Home | History | Annotate | Download | only in serial
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2016 Stefan Roese <sr (at) denx.de>
      4  */
      5 
      6 #include <common.h>
      7 #include <dm.h>
      8 #include <serial.h>
      9 #include <asm/io.h>
     10 
     11 struct mvebu_platdata {
     12 	void __iomem *base;
     13 };
     14 
     15 /*
     16  * Register offset
     17  */
     18 #define UART_RX_REG		0x00
     19 #define UART_TX_REG		0x04
     20 #define UART_CTRL_REG		0x08
     21 #define UART_STATUS_REG		0x0c
     22 #define UART_BAUD_REG		0x10
     23 #define UART_POSSR_REG		0x14
     24 
     25 #define UART_STATUS_RX_RDY	0x10
     26 #define UART_STATUS_TXFIFO_FULL	0x800
     27 
     28 #define UART_CTRL_RXFIFO_RESET	0x4000
     29 #define UART_CTRL_TXFIFO_RESET	0x8000
     30 
     31 #define CONFIG_UART_BASE_CLOCK	25804800
     32 
     33 static int mvebu_serial_putc(struct udevice *dev, const char ch)
     34 {
     35 	struct mvebu_platdata *plat = dev_get_platdata(dev);
     36 	void __iomem *base = plat->base;
     37 
     38 	while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL)
     39 		;
     40 
     41 	writel(ch, base + UART_TX_REG);
     42 
     43 	return 0;
     44 }
     45 
     46 static int mvebu_serial_getc(struct udevice *dev)
     47 {
     48 	struct mvebu_platdata *plat = dev_get_platdata(dev);
     49 	void __iomem *base = plat->base;
     50 
     51 	while (!(readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY))
     52 		;
     53 
     54 	return readl(base + UART_RX_REG) & 0xff;
     55 }
     56 
     57 static int mvebu_serial_pending(struct udevice *dev, bool input)
     58 {
     59 	struct mvebu_platdata *plat = dev_get_platdata(dev);
     60 	void __iomem *base = plat->base;
     61 
     62 	if (readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY)
     63 		return 1;
     64 
     65 	return 0;
     66 }
     67 
     68 static int mvebu_serial_setbrg(struct udevice *dev, int baudrate)
     69 {
     70 	struct mvebu_platdata *plat = dev_get_platdata(dev);
     71 	void __iomem *base = plat->base;
     72 
     73 	/*
     74 	 * Calculate divider
     75 	 * baudrate = clock / 16 / divider
     76 	 */
     77 	writel(CONFIG_UART_BASE_CLOCK / baudrate / 16, base + UART_BAUD_REG);
     78 
     79 	/*
     80 	 * Set Programmable Oversampling Stack to 0,
     81 	 * UART defaults to 16x scheme
     82 	 */
     83 	writel(0, base + UART_POSSR_REG);
     84 
     85 	return 0;
     86 }
     87 
     88 static int mvebu_serial_probe(struct udevice *dev)
     89 {
     90 	struct mvebu_platdata *plat = dev_get_platdata(dev);
     91 	void __iomem *base = plat->base;
     92 
     93 	/* reset FIFOs */
     94 	writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
     95 	       base + UART_CTRL_REG);
     96 
     97 	/* No Parity, 1 Stop */
     98 	writel(0, base + UART_CTRL_REG);
     99 
    100 	return 0;
    101 }
    102 
    103 static int mvebu_serial_ofdata_to_platdata(struct udevice *dev)
    104 {
    105 	struct mvebu_platdata *plat = dev_get_platdata(dev);
    106 
    107 	plat->base = devfdt_get_addr_ptr(dev);
    108 
    109 	return 0;
    110 }
    111 
    112 static const struct dm_serial_ops mvebu_serial_ops = {
    113 	.putc = mvebu_serial_putc,
    114 	.pending = mvebu_serial_pending,
    115 	.getc = mvebu_serial_getc,
    116 	.setbrg = mvebu_serial_setbrg,
    117 };
    118 
    119 static const struct udevice_id mvebu_serial_ids[] = {
    120 	{ .compatible = "marvell,armada-3700-uart" },
    121 	{ }
    122 };
    123 
    124 U_BOOT_DRIVER(serial_mvebu) = {
    125 	.name	= "serial_mvebu",
    126 	.id	= UCLASS_SERIAL,
    127 	.of_match = mvebu_serial_ids,
    128 	.ofdata_to_platdata = mvebu_serial_ofdata_to_platdata,
    129 	.platdata_auto_alloc_size = sizeof(struct mvebu_platdata),
    130 	.probe	= mvebu_serial_probe,
    131 	.ops	= &mvebu_serial_ops,
    132 	.flags	= DM_FLAG_PRE_RELOC,
    133 };
    134 
    135 #ifdef CONFIG_DEBUG_MVEBU_A3700_UART
    136 
    137 #include <debug_uart.h>
    138 
    139 static inline void _debug_uart_init(void)
    140 {
    141 	void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
    142 
    143 	/* reset FIFOs */
    144 	writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
    145 	       base + UART_CTRL_REG);
    146 
    147 	/* No Parity, 1 Stop */
    148 	writel(0, base + UART_CTRL_REG);
    149 
    150 	/*
    151 	 * Calculate divider
    152 	 * baudrate = clock / 16 / divider
    153 	 */
    154 	writel(CONFIG_UART_BASE_CLOCK / 115200 / 16, base + UART_BAUD_REG);
    155 
    156 	/*
    157 	 * Set Programmable Oversampling Stack to 0,
    158 	 * UART defaults to 16x scheme
    159 	 */
    160 	writel(0, base + UART_POSSR_REG);
    161 }
    162 
    163 static inline void _debug_uart_putc(int ch)
    164 {
    165 	void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
    166 
    167 	while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL)
    168 		;
    169 
    170 	writel(ch, base + UART_TX_REG);
    171 }
    172 
    173 DEBUG_UART_FUNCS
    174 #endif
    175