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