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