11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
23481d2f6SSoren Brinkmann /*
33481d2f6SSoren Brinkmann * Copyright (c) 2016, Xilinx Inc.
43481d2f6SSoren Brinkmann * All rights reserved.
53481d2f6SSoren Brinkmann *
63481d2f6SSoren Brinkmann * Redistribution and use in source and binary forms, with or without
73481d2f6SSoren Brinkmann * modification, are permitted provided that the following conditions are met:
83481d2f6SSoren Brinkmann *
93481d2f6SSoren Brinkmann * 1. Redistributions of source code must retain the above copyright notice,
103481d2f6SSoren Brinkmann * this list of conditions and the following disclaimer.
113481d2f6SSoren Brinkmann *
123481d2f6SSoren Brinkmann * 2. Redistributions in binary form must reproduce the above copyright notice,
133481d2f6SSoren Brinkmann * this list of conditions and the following disclaimer in the documentation
143481d2f6SSoren Brinkmann * and/or other materials provided with the distribution.
153481d2f6SSoren Brinkmann *
163481d2f6SSoren Brinkmann * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
173481d2f6SSoren Brinkmann * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183481d2f6SSoren Brinkmann * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193481d2f6SSoren Brinkmann * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
203481d2f6SSoren Brinkmann * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
213481d2f6SSoren Brinkmann * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
223481d2f6SSoren Brinkmann * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
233481d2f6SSoren Brinkmann * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
243481d2f6SSoren Brinkmann * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
253481d2f6SSoren Brinkmann * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
263481d2f6SSoren Brinkmann * POSSIBILITY OF SUCH DAMAGE.
273481d2f6SSoren Brinkmann */
2862fff454SJerome Forissier #include <assert.h>
293481d2f6SSoren Brinkmann #include <drivers/cdns_uart.h>
303481d2f6SSoren Brinkmann #include <io.h>
318d94060aSEtienne Carriere #include <keep.h>
3262fff454SJerome Forissier #include <mm/core_mmu.h>
333481d2f6SSoren Brinkmann #include <util.h>
343481d2f6SSoren Brinkmann
353481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL 0
363481d2f6SSoren Brinkmann #define CDNS_UART_MODE 4
373481d2f6SSoren Brinkmann #define CDNS_UART_IEN 8
383481d2f6SSoren Brinkmann #define CDNS_UART_IRQ_STATUS 0x14
393481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS 0x2c
403481d2f6SSoren Brinkmann #define CDNS_UART_FIFO 0x30
41*c2e4eb43SAnton Rybakov #define CDNS_UART_SIZE 0x34
423481d2f6SSoren Brinkmann
433481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_RXRES BIT(0)
443481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_TXRES BIT(1)
453481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_RXEN BIT(2)
463481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_TXEN BIT(4)
473481d2f6SSoren Brinkmann
483481d2f6SSoren Brinkmann #define CDNS_UART_MODE_8BIT (0 << 1)
493481d2f6SSoren Brinkmann #define CDNS_UART_MODE_PARITY_NONE (0x4 << 3)
503481d2f6SSoren Brinkmann #define CDNS_UART_MODE_1STP (0 << 6)
513481d2f6SSoren Brinkmann
523481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS_TFUL BIT(4)
533481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS_TEMPTY BIT(3)
543481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS_REMPTY BIT(1)
553481d2f6SSoren Brinkmann
563481d2f6SSoren Brinkmann #define CDNS_UART_IRQ_RXTRIG BIT(0)
573481d2f6SSoren Brinkmann #define CDNS_UART_IRQ_RXTOUT BIT(8)
583481d2f6SSoren Brinkmann
chip_to_base(struct serial_chip * chip)5962fff454SJerome Forissier static vaddr_t chip_to_base(struct serial_chip *chip)
603481d2f6SSoren Brinkmann {
6162fff454SJerome Forissier struct cdns_uart_data *pd =
6262fff454SJerome Forissier container_of(chip, struct cdns_uart_data, chip);
6362fff454SJerome Forissier
64*c2e4eb43SAnton Rybakov return io_pa_or_va(&pd->base, CDNS_UART_SIZE);
6562fff454SJerome Forissier }
6662fff454SJerome Forissier
cdns_uart_flush(struct serial_chip * chip)6762fff454SJerome Forissier static void cdns_uart_flush(struct serial_chip *chip)
6862fff454SJerome Forissier {
6962fff454SJerome Forissier vaddr_t base = chip_to_base(chip);
7062fff454SJerome Forissier
71918bb3a5SEtienne Carriere while (!(io_read32(base + CDNS_UART_CHANNEL_STATUS) &
723481d2f6SSoren Brinkmann CDNS_UART_CHANNEL_STATUS_TEMPTY))
733481d2f6SSoren Brinkmann ;
743481d2f6SSoren Brinkmann }
753481d2f6SSoren Brinkmann
cdns_uart_have_rx_data(struct serial_chip * chip)7662fff454SJerome Forissier static bool cdns_uart_have_rx_data(struct serial_chip *chip)
773481d2f6SSoren Brinkmann {
7862fff454SJerome Forissier vaddr_t base = chip_to_base(chip);
793481d2f6SSoren Brinkmann
80918bb3a5SEtienne Carriere return !(io_read32(base + CDNS_UART_CHANNEL_STATUS) &
8162fff454SJerome Forissier CDNS_UART_CHANNEL_STATUS_REMPTY);
823481d2f6SSoren Brinkmann }
833481d2f6SSoren Brinkmann
cdns_uart_getchar(struct serial_chip * chip)8462fff454SJerome Forissier static int cdns_uart_getchar(struct serial_chip *chip)
853481d2f6SSoren Brinkmann {
8662fff454SJerome Forissier vaddr_t base = chip_to_base(chip);
8762fff454SJerome Forissier
8862fff454SJerome Forissier while (!cdns_uart_have_rx_data(chip))
8962fff454SJerome Forissier ;
90918bb3a5SEtienne Carriere return io_read32(base + CDNS_UART_FIFO) & 0xff;
9162fff454SJerome Forissier }
9262fff454SJerome Forissier
cdns_uart_putc(struct serial_chip * chip,int ch)9362fff454SJerome Forissier static void cdns_uart_putc(struct serial_chip *chip, int ch)
9462fff454SJerome Forissier {
9562fff454SJerome Forissier vaddr_t base = chip_to_base(chip);
9662fff454SJerome Forissier
973481d2f6SSoren Brinkmann /* Wait until there is space in the FIFO */
98918bb3a5SEtienne Carriere while (io_read32(base + CDNS_UART_CHANNEL_STATUS) &
993481d2f6SSoren Brinkmann CDNS_UART_CHANNEL_STATUS_TFUL)
1003481d2f6SSoren Brinkmann ;
1013481d2f6SSoren Brinkmann
1023481d2f6SSoren Brinkmann /* Send the character */
103918bb3a5SEtienne Carriere io_write32(base + CDNS_UART_FIFO, ch);
1043481d2f6SSoren Brinkmann }
1053481d2f6SSoren Brinkmann
1063481d2f6SSoren Brinkmann
10762fff454SJerome Forissier static const struct serial_ops cdns_uart_ops = {
10862fff454SJerome Forissier .flush = cdns_uart_flush,
10962fff454SJerome Forissier .getchar = cdns_uart_getchar,
11062fff454SJerome Forissier .have_rx_data = cdns_uart_have_rx_data,
11162fff454SJerome Forissier .putc = cdns_uart_putc,
11262fff454SJerome Forissier };
1133639b55fSJerome Forissier DECLARE_KEEP_PAGER(cdns_uart_ops);
11462fff454SJerome Forissier
11562fff454SJerome Forissier /*
11662fff454SJerome Forissier * we rely on the bootloader having set up the HW correctly, we just enable
11762fff454SJerome Forissier * transmitter/receiver here, just in case.
11862fff454SJerome Forissier */
cdns_uart_init(struct cdns_uart_data * pd,paddr_t base,uint32_t uart_clk,uint32_t baud_rate)11962fff454SJerome Forissier void cdns_uart_init(struct cdns_uart_data *pd, paddr_t base, uint32_t uart_clk,
12062fff454SJerome Forissier uint32_t baud_rate)
1213481d2f6SSoren Brinkmann {
12262fff454SJerome Forissier pd->base.pa = base;
12362fff454SJerome Forissier pd->chip.ops = &cdns_uart_ops;
12462fff454SJerome Forissier
12562fff454SJerome Forissier if (!uart_clk || !baud_rate)
12662fff454SJerome Forissier return;
12762fff454SJerome Forissier
12862fff454SJerome Forissier /* Enable UART and RX/TX */
129918bb3a5SEtienne Carriere io_write32(base + CDNS_UART_CONTROL,
130918bb3a5SEtienne Carriere CDNS_UART_CONTROL_RXEN | CDNS_UART_CONTROL_TXEN);
13162fff454SJerome Forissier
13262fff454SJerome Forissier cdns_uart_flush(&pd->chip);
1333481d2f6SSoren Brinkmann }
134