1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2004-2007 ARM Limited.
4  * Copyright (C) 2008 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
5  * Copyright (C) 2015 - 2016 Xilinx, Inc, Michal Simek
6  *
7  * As a special exception, if other files instantiate templates or use macros
8  * or inline functions from this file, or you compile this file and link it
9  * with other works to produce a work based on this file, this file does not
10  * by itself cause the resulting work to be covered by the GNU General Public
11  * License. However the source code for this file must still be made available
12  * in accordance with section (3) of the GNU General Public License.
13 
14  * This exception does not invalidate any other reasons why a work based on
15  * this file might be covered by the GNU General Public License.
16  */
17 
18 #include <common.h>
19 #include <dm.h>
20 #include <serial.h>
21 
22 #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V7A) || defined(CONFIG_CPU_V7R)
23 /*
24  * ARMV6 & ARMV7
25  */
26 #define DCC_RBIT	(1 << 30)
27 #define DCC_WBIT	(1 << 29)
28 
29 #define write_dcc(x)	\
30 		__asm__ volatile ("mcr p14, 0, %0, c0, c5, 0\n" : : "r" (x))
31 
32 #define read_dcc(x)	\
33 		__asm__ volatile ("mrc p14, 0, %0, c0, c5, 0\n" : "=r" (x))
34 
35 #define status_dcc(x)	\
36 		__asm__ volatile ("mrc p14, 0, %0, c0, c1, 0\n" : "=r" (x))
37 
38 #elif defined(CONFIG_CPU_XSCALE)
39 /*
40  * XSCALE
41  */
42 #define DCC_RBIT	(1 << 31)
43 #define DCC_WBIT	(1 << 28)
44 
45 #define write_dcc(x)	\
46 		__asm__ volatile ("mcr p14, 0, %0, c8, c0, 0\n" : : "r" (x))
47 
48 #define read_dcc(x)	\
49 		__asm__ volatile ("mrc p14, 0, %0, c9, c0, 0\n" : "=r" (x))
50 
51 #define status_dcc(x)	\
52 		__asm__ volatile ("mrc p14, 0, %0, c14, c0, 0\n" : "=r" (x))
53 
54 #elif defined(CONFIG_CPU_ARMV8)
55 /*
56  * ARMV8
57  */
58 #define DCC_RBIT	(1 << 30)
59 #define DCC_WBIT	(1 << 29)
60 
61 #define write_dcc(x)   \
62 		__asm__ volatile ("msr dbgdtrtx_el0, %0\n" : : "r" (x))
63 
64 #define read_dcc(x)    \
65 		__asm__ volatile ("mrs %0, dbgdtrrx_el0\n" : "=r" (x))
66 
67 #define status_dcc(x)  \
68 		__asm__ volatile ("mrs %0, mdccsr_el0\n" : "=r" (x))
69 
70 #else
71 #define DCC_RBIT	(1 << 0)
72 #define DCC_WBIT	(1 << 1)
73 
74 #define write_dcc(x)	\
75 		__asm__ volatile ("mcr p14, 0, %0, c1, c0, 0\n" : : "r" (x))
76 
77 #define read_dcc(x)	\
78 		__asm__ volatile ("mrc p14, 0, %0, c1, c0, 0\n" : "=r" (x))
79 
80 #define status_dcc(x)	\
81 		__asm__ volatile ("mrc p14, 0, %0, c0, c0, 0\n" : "=r" (x))
82 
83 #endif
84 
85 #define can_read_dcc(x)	do {	\
86 		status_dcc(x);	\
87 		x &= DCC_RBIT;	\
88 		} while (0);
89 
90 #define can_write_dcc(x) do {	\
91 		status_dcc(x);	\
92 		x &= DCC_WBIT;	\
93 		x = (x == 0);	\
94 		} while (0);
95 
96 #define TIMEOUT_COUNT 0x4000000
97 
arm_dcc_getc(struct udevice * dev)98 static int arm_dcc_getc(struct udevice *dev)
99 {
100 	int ch;
101 	register unsigned int reg;
102 
103 	do {
104 		can_read_dcc(reg);
105 	} while (!reg);
106 	read_dcc(ch);
107 
108 	return ch;
109 }
110 
arm_dcc_putc(struct udevice * dev,char ch)111 static int arm_dcc_putc(struct udevice *dev, char ch)
112 {
113 	register unsigned int reg;
114 	unsigned int timeout_count = TIMEOUT_COUNT;
115 
116 	while (--timeout_count) {
117 		can_write_dcc(reg);
118 		if (reg)
119 			break;
120 	}
121 	if (timeout_count == 0)
122 		return -EAGAIN;
123 	else
124 		write_dcc(ch);
125 
126 	return 0;
127 }
128 
arm_dcc_pending(struct udevice * dev,bool input)129 static int arm_dcc_pending(struct udevice *dev, bool input)
130 {
131 	register unsigned int reg;
132 
133 	if (input) {
134 		can_read_dcc(reg);
135 	} else {
136 		can_write_dcc(reg);
137 	}
138 
139 	return reg;
140 }
141 
142 static const struct dm_serial_ops arm_dcc_ops = {
143 	.putc = arm_dcc_putc,
144 	.pending = arm_dcc_pending,
145 	.getc = arm_dcc_getc,
146 };
147 
148 static const struct udevice_id arm_dcc_ids[] = {
149 	{ .compatible = "arm,dcc", },
150 	{ }
151 };
152 
153 U_BOOT_DRIVER(serial_dcc) = {
154 	.name	= "arm_dcc",
155 	.id	= UCLASS_SERIAL,
156 	.of_match = arm_dcc_ids,
157 	.ops	= &arm_dcc_ops,
158 };
159 
160 #ifdef CONFIG_DEBUG_UART_ARM_DCC
161 
162 #include <debug_uart.h>
163 
_debug_uart_init(void)164 static inline void _debug_uart_init(void)
165 {
166 }
167 
_debug_uart_putc(int ch)168 static inline void _debug_uart_putc(int ch)
169 {
170 	arm_dcc_putc(NULL, ch);
171 }
172 
173 DEBUG_UART_FUNCS
174 #endif
175