1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2016 Stefan Roese <sr@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