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> 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) */ 53c2e4eb43SAnton Rybakov #define USIZE 0xb8 /* UTS + sizeof(uint32_t) */ 548c4a5a9aSPeng Fan 558c4a5a9aSPeng Fan /* UART Control Register Bit Fields.*/ 568c4a5a9aSPeng Fan #define URXD_CHARRDY (1<<15) 578c4a5a9aSPeng Fan #define URXD_ERR (1<<14) 588c4a5a9aSPeng Fan #define URXD_OVRRUN (1<<13) 598c4a5a9aSPeng Fan #define URXD_FRMERR (1<<12) 608c4a5a9aSPeng Fan #define URXD_BRK (1<<11) 618c4a5a9aSPeng Fan #define URXD_PRERR (1<<10) 628c4a5a9aSPeng Fan #define URXD_RX_DATA (0xFF) 638c4a5a9aSPeng Fan #define UCR1_ADEN (1<<15) /* Auto dectect interrupt */ 648c4a5a9aSPeng Fan #define UCR1_ADBR (1<<14) /* Auto detect baud rate */ 658c4a5a9aSPeng Fan #define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ 668c4a5a9aSPeng Fan #define UCR1_IDEN (1<<12) /* Idle condition interrupt */ 678c4a5a9aSPeng Fan #define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ 688c4a5a9aSPeng Fan #define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ 698c4a5a9aSPeng Fan #define UCR1_IREN (1<<7) /* Infrared interface enable */ 708c4a5a9aSPeng Fan #define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ 718c4a5a9aSPeng Fan #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ 728c4a5a9aSPeng Fan #define UCR1_SNDBRK (1<<4) /* Send break */ 738c4a5a9aSPeng Fan #define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ 748c4a5a9aSPeng Fan #define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */ 758c4a5a9aSPeng Fan #define UCR1_DOZE (1<<1) /* Doze */ 768c4a5a9aSPeng Fan #define UCR1_UARTEN (1<<0) /* UART enabled */ 778c4a5a9aSPeng Fan 788c4a5a9aSPeng Fan #define UTS_FRCPERR (1<<13) /* Force parity error */ 798c4a5a9aSPeng Fan #define UTS_LOOP (1<<12) /* Loop tx and rx */ 808c4a5a9aSPeng Fan #define UTS_TXEMPTY (1<<6) /* TxFIFO empty */ 818c4a5a9aSPeng Fan #define UTS_RXEMPTY (1<<5) /* RxFIFO empty */ 828c4a5a9aSPeng Fan #define UTS_TXFULL (1<<4) /* TxFIFO full */ 838c4a5a9aSPeng Fan #define UTS_RXFULL (1<<3) /* RxFIFO full */ 848c4a5a9aSPeng Fan #define UTS_SOFTRST (1<<0) /* Software reset */ 858c4a5a9aSPeng Fan 8626267e82SJerome Forissier static vaddr_t chip_to_base(struct serial_chip *chip) 878c4a5a9aSPeng Fan { 8826267e82SJerome Forissier struct imx_uart_data *pd = 8926267e82SJerome Forissier container_of(chip, struct imx_uart_data, chip); 9026267e82SJerome Forissier 91c2e4eb43SAnton Rybakov return io_pa_or_va(&pd->base, USIZE); 928c4a5a9aSPeng Fan } 938c4a5a9aSPeng Fan 9426267e82SJerome Forissier static void imx_uart_flush(struct serial_chip *chip) 958c4a5a9aSPeng Fan { 9626267e82SJerome Forissier vaddr_t base = chip_to_base(chip); 9726267e82SJerome Forissier 9821145fe5SJordan Rhee 99918bb3a5SEtienne Carriere while (!(io_read32(base + UTS) & UTS_TXEMPTY)) 100918bb3a5SEtienne Carriere if (!(io_read32(base + UCR1) & UCR1_UARTEN)) 10121145fe5SJordan Rhee return; 1028c4a5a9aSPeng Fan } 1038c4a5a9aSPeng Fan 10426267e82SJerome Forissier static int imx_uart_getchar(struct serial_chip *chip) 1058c4a5a9aSPeng Fan { 10626267e82SJerome Forissier vaddr_t base = chip_to_base(chip); 10726267e82SJerome Forissier 108918bb3a5SEtienne Carriere while (io_read32(base + UTS) & UTS_RXEMPTY) 1098c4a5a9aSPeng Fan ; 1108c4a5a9aSPeng Fan 111918bb3a5SEtienne Carriere return (io_read32(base + URXD) & URXD_RX_DATA); 1128c4a5a9aSPeng Fan } 1138c4a5a9aSPeng Fan 11426267e82SJerome Forissier static void imx_uart_putc(struct serial_chip *chip, int ch) 1158c4a5a9aSPeng Fan { 11626267e82SJerome Forissier vaddr_t base = chip_to_base(chip); 1178c4a5a9aSPeng Fan 1184c85b2cfSJordan Rhee /* Wait until there's space in the TX FIFO */ 119918bb3a5SEtienne Carriere while (io_read32(base + UTS) & UTS_TXFULL) 120918bb3a5SEtienne Carriere if (!(io_read32(base + UCR1) & UCR1_UARTEN)) 12121145fe5SJordan Rhee return; 1224c85b2cfSJordan Rhee 123918bb3a5SEtienne Carriere io_write32(base + UTXD, ch); 1248c4a5a9aSPeng Fan } 12526267e82SJerome Forissier 12626267e82SJerome Forissier static const struct serial_ops imx_uart_ops = { 12726267e82SJerome Forissier .flush = imx_uart_flush, 12826267e82SJerome Forissier .getchar = imx_uart_getchar, 12926267e82SJerome Forissier .putc = imx_uart_putc, 13026267e82SJerome Forissier }; 1313639b55fSJerome Forissier DECLARE_KEEP_PAGER(imx_uart_ops); 13226267e82SJerome Forissier 13326267e82SJerome Forissier void imx_uart_init(struct imx_uart_data *pd, paddr_t base) 13426267e82SJerome Forissier { 13526267e82SJerome Forissier pd->base.pa = base; 13626267e82SJerome Forissier pd->chip.ops = &imx_uart_ops; 13726267e82SJerome Forissier 13826267e82SJerome Forissier /* 13926267e82SJerome Forissier * Do nothing, debug uart(uart0) share with normal world, 14026267e82SJerome Forissier * everything for uart0 initialization is done in bootloader. 14126267e82SJerome Forissier */ 14226267e82SJerome Forissier } 143f1c2959fSClement Faure 144f1c2959fSClement Faure #ifdef CFG_DT 145f1c2959fSClement Faure static struct serial_chip *imx_uart_dev_alloc(void) 146f1c2959fSClement Faure { 147f1c2959fSClement Faure struct imx_uart_data *pd = calloc(1, sizeof(*pd)); 148f1c2959fSClement Faure 149f1c2959fSClement Faure if (!pd) 150f1c2959fSClement Faure return NULL; 151f1c2959fSClement Faure 152f1c2959fSClement Faure return &pd->chip; 153f1c2959fSClement Faure } 154f1c2959fSClement Faure 155f1c2959fSClement Faure static int imx_uart_dev_init(struct serial_chip *chip, const void *fdt, 156f1c2959fSClement Faure int offs, const char *parms) 157f1c2959fSClement Faure { 158f1c2959fSClement Faure struct imx_uart_data *pd = 159f1c2959fSClement Faure container_of(chip, struct imx_uart_data, chip); 160f1c2959fSClement Faure vaddr_t vbase = 0; 161f1c2959fSClement Faure paddr_t pbase = 0; 162f1c2959fSClement Faure size_t size = 0; 163f1c2959fSClement Faure 164f1c2959fSClement Faure if (parms && parms[0]) 165f1c2959fSClement Faure IMSG("imx_uart: device parameters ignored (%s)", parms); 166f1c2959fSClement Faure 167*a5d5bbc8SVesa Jääskeläinen if (dt_map_dev(fdt, offs, &vbase, &size, DT_MAP_AUTO) < 0) 168f1c2959fSClement Faure return -1; 169f1c2959fSClement Faure 170f1c2959fSClement Faure pbase = virt_to_phys((void *)vbase); 171f1c2959fSClement Faure imx_uart_init(pd, pbase); 172f1c2959fSClement Faure 173f1c2959fSClement Faure return 0; 174f1c2959fSClement Faure } 175f1c2959fSClement Faure 176f1c2959fSClement Faure static void imx_uart_dev_free(struct serial_chip *chip) 177f1c2959fSClement Faure { 178f1c2959fSClement Faure struct imx_uart_data *pd = 179f1c2959fSClement Faure container_of(chip, struct imx_uart_data, chip); 180f1c2959fSClement Faure 181f1c2959fSClement Faure free(pd); 182f1c2959fSClement Faure } 183f1c2959fSClement Faure 184f1c2959fSClement Faure static const struct serial_driver imx_uart_driver = { 185f1c2959fSClement Faure .dev_alloc = imx_uart_dev_alloc, 186f1c2959fSClement Faure .dev_init = imx_uart_dev_init, 187f1c2959fSClement Faure .dev_free = imx_uart_dev_free, 188f1c2959fSClement Faure }; 189f1c2959fSClement Faure 190f1c2959fSClement Faure static const struct dt_device_match imx_match_table[] = { 191f1c2959fSClement Faure { .compatible = "fsl,imx6q-uart" }, 192f1c2959fSClement Faure { 0 } 193f1c2959fSClement Faure }; 194f1c2959fSClement Faure 19561bdedeaSJerome Forissier DEFINE_DT_DRIVER(imx_dt_driver) = { 196f1c2959fSClement Faure .name = "imx_uart", 1975e588771SClément Léger .type = DT_DRIVER_UART, 198f1c2959fSClement Faure .match_table = imx_match_table, 199f1c2959fSClement Faure .driver = &imx_uart_driver, 200f1c2959fSClement Faure }; 201f1c2959fSClement Faure 202f1c2959fSClement Faure #endif /* CFG_DT */ 203