1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2016 Stefan Roese <sr@denx.de> 4 * Copyright (C) 2021 Pali Roh��r <pali@kernel.org> 5 */ 6 7#include <common.h> 8#include <clk.h> 9#include <dm.h> 10#include <serial.h> 11#include <asm/io.h> 12#include <asm/arch/cpu.h> 13#include <mach/soc.h> 14 15struct mvebu_plat { 16 void __iomem *base; 17 ulong tbg_rate; 18 u8 tbg_idx; 19}; 20 21/* 22 * Register offset 23 */ 24#define UART_RX_REG 0x00 25#define UART_TX_REG 0x04 26#define UART_CTRL_REG 0x08 27#define UART_STATUS_REG 0x0c 28#define UART_BAUD_REG 0x10 29#define UART_POSSR_REG 0x14 30 31#define UART_STATUS_RX_RDY 0x10 32#define UART_STATUS_TX_EMPTY 0x40 33#define UART_STATUS_TXFIFO_FULL 0x800 34 35#define UART_CTRL_RXFIFO_RESET 0x4000 36#define UART_CTRL_TXFIFO_RESET 0x8000 37 38static int mvebu_serial_putc(struct udevice *dev, const char ch) 39{ 40 struct mvebu_plat *plat = dev_get_plat(dev); 41 void __iomem *base = plat->base; 42 43 if (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL) 44 return -EAGAIN; 45 46 writel(ch, base + UART_TX_REG); 47 48 return 0; 49} 50 51static int mvebu_serial_getc(struct udevice *dev) 52{ 53 struct mvebu_plat *plat = dev_get_plat(dev); 54 void __iomem *base = plat->base; 55 56 if (!(readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY)) 57 return -EAGAIN; 58 59 return readl(base + UART_RX_REG) & 0xff; 60} 61 62static int mvebu_serial_pending(struct udevice *dev, bool input) 63{ 64 struct mvebu_plat *plat = dev_get_plat(dev); 65 void __iomem *base = plat->base; 66 67 if (input) { 68 if (readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY) 69 return 1; 70 } else { 71 if (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY)) 72 return 1; 73 } 74 75 return 0; 76} 77 78static int mvebu_serial_setbrg(struct udevice *dev, int baudrate) 79{ 80 struct mvebu_plat *plat = dev_get_plat(dev); 81 void __iomem *base = plat->base; 82 u32 divider, d1, d2; 83 u32 oversampling; 84 85 /* 86 * Calculate divider 87 * baudrate = clock / 16 / divider 88 */ 89 d1 = d2 = 1; 90 divider = DIV_ROUND_CLOSEST(plat->tbg_rate, baudrate * 16 * d1 * d2); 91 92 /* 93 * Set Programmable Oversampling Stack to 0, 94 * UART defaults to 16x scheme 95 */ 96 oversampling = 0; 97 98 if (divider < 1) 99 divider = 1; 100 else if (divider > 1023) { 101 /* 102 * If divider is too high for selected baudrate then set 103 * divider d1 to the maximal value 6. 104 */ 105 d1 = 6; 106 divider = DIV_ROUND_CLOSEST(plat->tbg_rate, 107 baudrate * 16 * d1 * d2); 108 if (divider < 1) 109 divider = 1; 110 else if (divider > 1023) { 111 /* 112 * If divider is still too high then set also divider 113 * d2 to the maximal value 6. 114 */ 115 d2 = 6; 116 divider = DIV_ROUND_CLOSEST(plat->tbg_rate, 117 baudrate * 16 * d1 * d2); 118 if (divider < 1) 119 divider = 1; 120 else if (divider > 1023) { 121 /* 122 * And if divider is still to high then 123 * use oversampling with maximal factor 63. 124 */ 125 oversampling = (63 << 0) | (63 << 8) | 126 (63 << 16) | (63 << 24); 127 divider = DIV_ROUND_CLOSEST(plat->tbg_rate, 128 baudrate * 63 * d1 * d2); 129 if (divider < 1) 130 divider = 1; 131 else if (divider > 1023) 132 divider = 1023; 133 } 134 } 135 } 136 137 divider |= BIT(19); /* Do not use XTAL as a base clock */ 138 divider |= d1 << 15; /* Set d1 divider */ 139 divider |= d2 << 12; /* Set d2 divider */ 140 divider |= plat->tbg_idx << 10; /* Use selected TBG as a base clock */ 141 142 while (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY)) 143 ; 144 writel(divider, base + UART_BAUD_REG); 145 writel(oversampling, base + UART_POSSR_REG); 146 147 return 0; 148} 149 150static int mvebu_serial_probe(struct udevice *dev) 151{ 152 struct mvebu_plat *plat = dev_get_plat(dev); 153 void __iomem *base = plat->base; 154 struct udevice *nb_clk; 155 ofnode nb_clk_node; 156 int i, res; 157 158 nb_clk_node = ofnode_by_compatible(ofnode_null(), 159 "marvell,armada-3700-periph-clock-nb"); 160 if (!ofnode_valid(nb_clk_node)) { 161 printf("%s: NB periph clock node not available\n", __func__); 162 return -ENODEV; 163 } 164 165 res = device_get_global_by_ofnode(nb_clk_node, &nb_clk); 166 if (res) { 167 printf("%s: Cannot get NB periph clock\n", __func__); 168 return res; 169 } 170 171 /* 172 * Choose the TBG clock with lowest frequency which allows to configure 173 * UART also at lower baudrates. 174 */ 175 for (i = 0; i < 4; i++) { 176 struct clk clk; 177 ulong rate; 178 179 res = clk_get_by_index_nodev(nb_clk_node, i, &clk); 180 if (res) { 181 printf("%s: Cannot get TBG clock %i: %i\n", __func__, 182 i, res); 183 return -ENODEV; 184 } 185 186 rate = clk_get_rate(&clk); 187 if (!rate || IS_ERR_VALUE(rate)) { 188 printf("%s: Cannot get rate for TBG clock %i\n", 189 __func__, i); 190 return -EINVAL; 191 } 192 193 if (!i || plat->tbg_rate > rate) { 194 plat->tbg_rate = rate; 195 plat->tbg_idx = i; 196 } 197 } 198 199 /* reset FIFOs */ 200 writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET, 201 base + UART_CTRL_REG); 202 203 /* No Parity, 1 Stop */ 204 writel(0, base + UART_CTRL_REG); 205 206 return 0; 207} 208 209static int mvebu_serial_remove(struct udevice *dev) 210{ 211 struct mvebu_plat *plat = dev_get_plat(dev); 212 void __iomem *base = plat->base; 213 ulong new_parent_rate, parent_rate; 214 u32 new_divider, divider; 215 u32 new_oversampling; 216 u32 oversampling; 217 u32 d1, d2; 218 u32 nb_rst; 219 220 /* 221 * Switch UART base clock back to XTAL because older Linux kernel 222 * expects it. Otherwise it does not calculate UART divisor correctly 223 * and therefore UART does not work in kernel. 224 */ 225 divider = readl(base + UART_BAUD_REG); 226 if (!(divider & BIT(19))) /* UART already uses XTAL */ 227 return 0; 228 229 /* Read current divisors settings */ 230 d1 = (divider >> 15) & 7; 231 d2 = (divider >> 12) & 7; 232 parent_rate = plat->tbg_rate; 233 divider &= 1023; 234 oversampling = readl(base + UART_POSSR_REG) & 63; 235 if (!oversampling) 236 oversampling = 16; 237 238 /* Calculate new divisor against XTAL clock without changing baudrate */ 239 new_oversampling = 0; 240 new_parent_rate = get_ref_clk() * 1000000; 241 new_divider = DIV_ROUND_CLOSEST(new_parent_rate * divider * d1 * d2 * 242 oversampling, parent_rate * 16); 243 244 /* 245 * UART does not work reliably when XTAL divisor is smaller than 4. 246 * In this case we do not switch UART parent to XTAL. User either 247 * configured unsupported settings or has newer kernel with patches 248 * which allow usage of non-XTAL clock as a parent clock. 249 */ 250 if (new_divider < 4) 251 return 0; 252 253 /* 254 * If new divisor is larger than maximal supported, try to switch 255 * from default x16 scheme to oversampling with maximal factor 63. 256 */ 257 if (new_divider > 1023) { 258 new_oversampling = 63; 259 new_divider = DIV_ROUND_CLOSEST(new_parent_rate * divider * d1 * 260 d2 * oversampling, 261 parent_rate * new_oversampling); 262 if (new_divider < 4 || new_divider > 1023) 263 return 0; 264 } 265 266 /* wait until TX empty */ 267 while (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY)) 268 ; 269 270 /* external reset of UART via North Bridge Peripheral */ 271 nb_rst = readl(MVEBU_REGISTER(0x12400)); 272 writel(nb_rst & ~BIT(3), MVEBU_REGISTER(0x12400)); 273 writel(nb_rst | BIT(3), MVEBU_REGISTER(0x12400)); 274 275 /* set baudrate and oversampling */ 276 writel(new_divider, base + UART_BAUD_REG); 277 writel(new_oversampling, base + UART_POSSR_REG); 278 279 /* No Parity, 1 Stop */ 280 writel(0, base + UART_CTRL_REG); 281 282 return 0; 283} 284 285static int mvebu_serial_of_to_plat(struct udevice *dev) 286{ 287 struct mvebu_plat *plat = dev_get_plat(dev); 288 289 plat->base = dev_read_addr_ptr(dev); 290 291 return 0; 292} 293 294static const struct dm_serial_ops mvebu_serial_ops = { 295 .putc = mvebu_serial_putc, 296 .pending = mvebu_serial_pending, 297 .getc = mvebu_serial_getc, 298 .setbrg = mvebu_serial_setbrg, 299}; 300 301static const struct udevice_id mvebu_serial_ids[] = { 302 { .compatible = "marvell,armada-3700-uart" }, 303 { } 304}; 305 306U_BOOT_DRIVER(serial_mvebu) = { 307 .name = "serial_mvebu", 308 .id = UCLASS_SERIAL, 309 .of_match = mvebu_serial_ids, 310 .of_to_plat = mvebu_serial_of_to_plat, 311 .plat_auto = sizeof(struct mvebu_plat), 312 .probe = mvebu_serial_probe, 313 .remove = mvebu_serial_remove, 314 .flags = DM_FLAG_OS_PREPARE, 315 .ops = &mvebu_serial_ops, 316}; 317 318#ifdef CONFIG_DEBUG_MVEBU_A3700_UART 319 320#include <debug_uart.h> 321 322static inline void _debug_uart_init(void) 323{ 324 void __iomem *base = (void __iomem *)CONFIG_VAL(DEBUG_UART_BASE); 325 u32 parent_rate, divider; 326 327 /* reset FIFOs */ 328 writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET, 329 base + UART_CTRL_REG); 330 331 /* No Parity, 1 Stop */ 332 writel(0, base + UART_CTRL_REG); 333 334 /* 335 * Calculate divider 336 * baudrate = clock / 16 / divider 337 */ 338 parent_rate = (readl(MVEBU_REGISTER(0x13808)) & BIT(9)) ? 339 40000000 : 25000000; 340 divider = DIV_ROUND_CLOSEST(parent_rate, CONFIG_BAUDRATE * 16); 341 writel(divider, base + UART_BAUD_REG); 342 343 /* 344 * Set Programmable Oversampling Stack to 0, 345 * UART defaults to 16x scheme 346 */ 347 writel(0, base + UART_POSSR_REG); 348} 349 350static inline void _debug_uart_putc(int ch) 351{ 352 void __iomem *base = (void __iomem *)CONFIG_VAL(DEBUG_UART_BASE); 353 354 while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL) 355 ; 356 357 writel(ch, base + UART_TX_REG); 358} 359 360DEBUG_UART_FUNCS 361#endif 362