1 /* 2 * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 */ 9 10 #include <common.h> 11 #include <dm.h> 12 #include <serial.h> 13 14 DECLARE_GLOBAL_DATA_PTR; 15 16 struct arc_serial_regs { 17 unsigned int id0; 18 unsigned int id1; 19 unsigned int id2; 20 unsigned int id3; 21 unsigned int data; 22 unsigned int status; 23 unsigned int baudl; 24 unsigned int baudh; 25 }; 26 27 28 struct arc_serial_platdata { 29 struct arc_serial_regs *reg; 30 unsigned int uartclk; 31 }; 32 33 /* Bit definitions of STATUS register */ 34 #define UART_RXEMPTY (1 << 5) 35 #define UART_OVERFLOW_ERR (1 << 1) 36 #define UART_TXEMPTY (1 << 7) 37 38 static int arc_serial_setbrg(struct udevice *dev, int baudrate) 39 { 40 struct arc_serial_platdata *plat = dev->platdata; 41 struct arc_serial_regs *const regs = plat->reg; 42 int arc_console_baud = gd->cpu_clk / (baudrate * 4) - 1; 43 44 writeb(arc_console_baud & 0xff, ®s->baudl); 45 writeb((arc_console_baud & 0xff00) >> 8, ®s->baudh); 46 47 return 0; 48 } 49 50 static int arc_serial_putc(struct udevice *dev, const char c) 51 { 52 struct arc_serial_platdata *plat = dev->platdata; 53 struct arc_serial_regs *const regs = plat->reg; 54 55 while (!(readb(®s->status) & UART_TXEMPTY)) 56 ; 57 58 writeb(c, ®s->data); 59 60 return 0; 61 } 62 63 static int arc_serial_tstc(struct arc_serial_regs *const regs) 64 { 65 return !(readb(®s->status) & UART_RXEMPTY); 66 } 67 68 static int arc_serial_pending(struct udevice *dev, bool input) 69 { 70 struct arc_serial_platdata *plat = dev->platdata; 71 struct arc_serial_regs *const regs = plat->reg; 72 uint32_t status = readb(®s->status); 73 74 if (input) 75 return status & UART_RXEMPTY ? 0 : 1; 76 else 77 return status & UART_TXEMPTY ? 0 : 1; 78 } 79 80 static int arc_serial_getc(struct udevice *dev) 81 { 82 struct arc_serial_platdata *plat = dev->platdata; 83 struct arc_serial_regs *const regs = plat->reg; 84 85 while (!arc_serial_tstc(regs)) 86 ; 87 88 /* Check for overflow errors */ 89 if (readb(®s->status) & UART_OVERFLOW_ERR) 90 return 0; 91 92 return readb(®s->data) & 0xFF; 93 } 94 95 static int arc_serial_probe(struct udevice *dev) 96 { 97 return 0; 98 } 99 100 static const struct dm_serial_ops arc_serial_ops = { 101 .putc = arc_serial_putc, 102 .pending = arc_serial_pending, 103 .getc = arc_serial_getc, 104 .setbrg = arc_serial_setbrg, 105 }; 106 107 static const struct udevice_id arc_serial_ids[] = { 108 { .compatible = "snps,arc-uart" }, 109 { } 110 }; 111 112 static int arc_serial_ofdata_to_platdata(struct udevice *dev) 113 { 114 struct arc_serial_platdata *plat = dev_get_platdata(dev); 115 DECLARE_GLOBAL_DATA_PTR; 116 117 plat->reg = (struct arc_serial_regs *)dev_get_addr(dev); 118 plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset, 119 "clock-frequency", 0); 120 121 return 0; 122 } 123 124 U_BOOT_DRIVER(serial_arc) = { 125 .name = "serial_arc", 126 .id = UCLASS_SERIAL, 127 .of_match = arc_serial_ids, 128 .ofdata_to_platdata = arc_serial_ofdata_to_platdata, 129 .probe = arc_serial_probe, 130 .ops = &arc_serial_ops, 131 .flags = DM_FLAG_PRE_RELOC, 132 }; 133