144bd24c5SJames Kung /* 244bd24c5SJames Kung * Copyright (c) 2015, Linaro Limited 344bd24c5SJames Kung * All rights reserved. 444bd24c5SJames Kung * 544bd24c5SJames Kung * Redistribution and use in source and binary forms, with or without 644bd24c5SJames Kung * modification, are permitted provided that the following conditions are met: 744bd24c5SJames Kung * 844bd24c5SJames Kung * 1. Redistributions of source code must retain the above copyright notice, 944bd24c5SJames Kung * this list of conditions and the following disclaimer. 1044bd24c5SJames Kung * 1144bd24c5SJames Kung * 2. Redistributions in binary form must reproduce the above copyright notice, 1244bd24c5SJames Kung * this list of conditions and the following disclaimer in the documentation 1344bd24c5SJames Kung * and/or other materials provided with the distribution. 1444bd24c5SJames Kung * 1544bd24c5SJames Kung * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1644bd24c5SJames Kung * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1744bd24c5SJames Kung * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1844bd24c5SJames Kung * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1944bd24c5SJames Kung * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2044bd24c5SJames Kung * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2144bd24c5SJames Kung * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2244bd24c5SJames Kung * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2344bd24c5SJames Kung * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2444bd24c5SJames Kung * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2544bd24c5SJames Kung * POSSIBILITY OF SUCH DAMAGE. 2644bd24c5SJames Kung */ 2744bd24c5SJames Kung 28d66fa083SJerome Forissier #include <compiler.h> 2944bd24c5SJames Kung #include <console.h> 30*8d94060aSEtienne Carriere #include <drivers/serial8250_uart.h> 3144bd24c5SJames Kung #include <io.h> 32*8d94060aSEtienne Carriere #include <keep.h> 33d66fa083SJerome Forissier #include <util.h> 3444bd24c5SJames Kung 3544bd24c5SJames Kung /* uart register defines */ 3644bd24c5SJames Kung #define UART_RHR 0x0 3744bd24c5SJames Kung #define UART_THR 0x0 3844bd24c5SJames Kung #define UART_IER 0x4 3944bd24c5SJames Kung #define UART_ISR 0x8 4044bd24c5SJames Kung #define UART_FCR 0x8 4144bd24c5SJames Kung #define UART_LCR 0xc 4244bd24c5SJames Kung #define UART_MCR 0x10 4344bd24c5SJames Kung #define UART_LSR 0x14 4444bd24c5SJames Kung #define UART_MSR 0x18 4544bd24c5SJames Kung #define UART_SPR 0x1c 4644bd24c5SJames Kung 4744bd24c5SJames Kung /* uart status register bits */ 4844bd24c5SJames Kung #define LSR_TEMT 0x40 /* Transmitter empty */ 4944bd24c5SJames Kung #define LSR_THRE 0x20 /* Transmit-hold-register empty */ 5044bd24c5SJames Kung #define LSR_EMPTY (LSR_TEMT | LSR_THRE) 5144bd24c5SJames Kung #define LSR_DR 0x01 /* DATA Ready */ 5244bd24c5SJames Kung 53d66fa083SJerome Forissier static vaddr_t chip_to_base(struct serial_chip *chip) 5444bd24c5SJames Kung { 55d66fa083SJerome Forissier struct serial8250_uart_data *pd = 56d66fa083SJerome Forissier container_of(chip, struct serial8250_uart_data, chip); 57d66fa083SJerome Forissier 58d66fa083SJerome Forissier return io_pa_or_va(&pd->base); 5944bd24c5SJames Kung } 6044bd24c5SJames Kung 61d66fa083SJerome Forissier static void serial8250_uart_flush(struct serial_chip *chip) 6244bd24c5SJames Kung { 63d66fa083SJerome Forissier vaddr_t base = chip_to_base(chip); 64d66fa083SJerome Forissier 6544bd24c5SJames Kung while (1) { 6644bd24c5SJames Kung uint8_t state = read8(base + UART_LSR); 6744bd24c5SJames Kung 68d66fa083SJerome Forissier /* Wait until transmit FIFO is empty */ 6944bd24c5SJames Kung if ((state & LSR_EMPTY) == LSR_EMPTY) 7044bd24c5SJames Kung break; 7144bd24c5SJames Kung } 7244bd24c5SJames Kung } 7344bd24c5SJames Kung 74d66fa083SJerome Forissier static bool serial8250_uart_have_rx_data(struct serial_chip *chip) 7544bd24c5SJames Kung { 76d66fa083SJerome Forissier vaddr_t base = chip_to_base(chip); 77d66fa083SJerome Forissier 7844bd24c5SJames Kung return (read32(base + UART_LSR) & LSR_DR); 7944bd24c5SJames Kung } 8044bd24c5SJames Kung 81d66fa083SJerome Forissier static int serial8250_uart_getchar(struct serial_chip *chip) 8244bd24c5SJames Kung { 83d66fa083SJerome Forissier vaddr_t base = chip_to_base(chip); 8444bd24c5SJames Kung 85d66fa083SJerome Forissier while (!serial8250_uart_have_rx_data(chip)) { 86d66fa083SJerome Forissier /* Transmit FIFO is empty, waiting again */ 8744bd24c5SJames Kung ; 8844bd24c5SJames Kung } 8944bd24c5SJames Kung return read8(base + UART_RHR); 9044bd24c5SJames Kung } 9144bd24c5SJames Kung 92d66fa083SJerome Forissier static void serial8250_uart_putc(struct serial_chip *chip, int ch) 93d66fa083SJerome Forissier { 94d66fa083SJerome Forissier vaddr_t base = chip_to_base(chip); 95d66fa083SJerome Forissier 96d66fa083SJerome Forissier serial8250_uart_flush(chip); 97d66fa083SJerome Forissier 98d66fa083SJerome Forissier /* Write out character to transmit FIFO */ 99d66fa083SJerome Forissier write8(ch, base + UART_THR); 100d66fa083SJerome Forissier } 101d66fa083SJerome Forissier 102d66fa083SJerome Forissier static const struct serial_ops serial8250_uart_ops = { 103d66fa083SJerome Forissier .flush = serial8250_uart_flush, 104d66fa083SJerome Forissier .getchar = serial8250_uart_getchar, 105d66fa083SJerome Forissier .have_rx_data = serial8250_uart_have_rx_data, 106d66fa083SJerome Forissier .putc = serial8250_uart_putc, 107d66fa083SJerome Forissier }; 108*8d94060aSEtienne Carriere KEEP_PAGER(serial8250_uart_ops); 109d66fa083SJerome Forissier 110d66fa083SJerome Forissier void serial8250_uart_init(struct serial8250_uart_data *pd, paddr_t base, 111d66fa083SJerome Forissier uint32_t __unused uart_clk, 112d66fa083SJerome Forissier uint32_t __unused baud_rate) 113d66fa083SJerome Forissier 114d66fa083SJerome Forissier { 115d66fa083SJerome Forissier pd->base.pa = base; 116d66fa083SJerome Forissier pd->chip.ops = &serial8250_uart_ops; 117d66fa083SJerome Forissier 118d66fa083SJerome Forissier /* 119d66fa083SJerome Forissier * do nothing, debug uart(uart0) share with normal world, 120d66fa083SJerome Forissier * everything for uart0 is ready now. 121d66fa083SJerome Forissier */ 122d66fa083SJerome Forissier } 123