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