]>
Commit | Line | Data |
---|---|---|
36ea8e9a MF |
1 | /* |
2 | * jtag-console.c - console driver over Blackfin JTAG | |
3 | * | |
5079d8bb | 4 | * Copyright (c) 2008-2010 Analog Devices Inc. |
36ea8e9a MF |
5 | * |
6 | * Licensed under the GPL-2 or later. | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
b990c7bd | 10 | #include <malloc.h> |
52cb4d4f | 11 | #include <stdio_dev.h> |
36ea8e9a MF |
12 | #include <asm/blackfin.h> |
13 | ||
4fff5ac2 MF |
14 | #ifdef DEBUG |
15 | # define dprintf(...) serial_printf(__VA_ARGS__) | |
16 | #else | |
17 | # define dprintf(...) do { if (0) printf(__VA_ARGS__); } while (0) | |
18 | #endif | |
19 | ||
20 | static inline void dprintf_decode(const char *s, uint32_t len) | |
21 | { | |
22 | uint32_t i; | |
23 | for (i = 0; i < len; ++i) | |
24 | if (s[i] < 0x20 || s[i] >= 0x7f) | |
25 | dprintf("\\%o", s[i]); | |
26 | else | |
27 | dprintf("%c", s[i]); | |
28 | } | |
29 | ||
5079d8bb MF |
30 | static inline uint32_t bfin_write_emudat(uint32_t emudat) |
31 | { | |
32 | __asm__ __volatile__("emudat = %0;" : : "d"(emudat)); | |
33 | return emudat; | |
34 | } | |
35 | ||
36 | static inline uint32_t bfin_read_emudat(void) | |
37 | { | |
38 | uint32_t emudat; | |
39 | __asm__ __volatile__("%0 = emudat;" : "=d"(emudat)); | |
40 | return emudat; | |
41 | } | |
42 | ||
36ea8e9a | 43 | #ifndef CONFIG_JTAG_CONSOLE_TIMEOUT |
63cb0f4e | 44 | # define CONFIG_JTAG_CONSOLE_TIMEOUT 500 |
36ea8e9a MF |
45 | #endif |
46 | ||
47 | /* The Blackfin tends to be much much faster than the JTAG hardware. */ | |
5079d8bb | 48 | static bool jtag_write_emudat(uint32_t emudat) |
36ea8e9a MF |
49 | { |
50 | static bool overflowed = false; | |
d8940a65 | 51 | ulong timeout = get_timer(0); |
36ea8e9a MF |
52 | while (bfin_read_DBGSTAT() & 0x1) { |
53 | if (overflowed) | |
5079d8bb | 54 | return overflowed; |
d8940a65 | 55 | if (get_timer(timeout) > CONFIG_JTAG_CONSOLE_TIMEOUT) |
36ea8e9a MF |
56 | overflowed = true; |
57 | } | |
58 | overflowed = false; | |
5079d8bb MF |
59 | bfin_write_emudat(emudat); |
60 | return overflowed; | |
36ea8e9a MF |
61 | } |
62 | /* Transmit a buffer. The format is: | |
63 | * [32bit length][actual data] | |
64 | */ | |
b990c7bd | 65 | static void jtag_send(const char *raw_str, uint32_t len) |
36ea8e9a | 66 | { |
b990c7bd MF |
67 | const char *cooked_str; |
68 | uint32_t i, ex; | |
36ea8e9a MF |
69 | |
70 | if (len == 0) | |
71 | return; | |
72 | ||
b990c7bd MF |
73 | /* Ugh, need to output \r after \n */ |
74 | ex = 0; | |
75 | for (i = 0; i < len; ++i) | |
76 | if (raw_str[i] == '\n') | |
77 | ++ex; | |
78 | if (ex) { | |
79 | char *c = malloc(len + ex); | |
80 | cooked_str = c; | |
81 | for (i = 0; i < len; ++i) { | |
82 | *c++ = raw_str[i]; | |
83 | if (raw_str[i] == '\n') | |
84 | *c++ = '\r'; | |
85 | } | |
86 | len += ex; | |
87 | } else | |
88 | cooked_str = raw_str; | |
89 | ||
4fff5ac2 | 90 | dprintf("%s(\"", __func__); |
b990c7bd | 91 | dprintf_decode(cooked_str, len); |
4fff5ac2 MF |
92 | dprintf("\", %i)\n", len); |
93 | ||
36ea8e9a | 94 | /* First send the length */ |
5079d8bb | 95 | if (jtag_write_emudat(len)) |
b990c7bd | 96 | goto done; |
36ea8e9a MF |
97 | |
98 | /* Then send the data */ | |
5079d8bb MF |
99 | for (i = 0; i < len; i += 4) { |
100 | uint32_t emudat = | |
b990c7bd MF |
101 | (cooked_str[i + 0] << 0) | |
102 | (cooked_str[i + 1] << 8) | | |
103 | (cooked_str[i + 2] << 16) | | |
104 | (cooked_str[i + 3] << 24); | |
5079d8bb MF |
105 | if (jtag_write_emudat(emudat)) { |
106 | bfin_write_emudat(0); | |
b990c7bd | 107 | goto done; |
5079d8bb MF |
108 | } |
109 | } | |
b990c7bd MF |
110 | |
111 | done: | |
112 | if (cooked_str != raw_str) | |
113 | free((char *)cooked_str); | |
36ea8e9a | 114 | } |
709ea543 | 115 | static void jtag_putc(struct stdio_dev *dev, const char c) |
36ea8e9a MF |
116 | { |
117 | jtag_send(&c, 1); | |
118 | } | |
709ea543 | 119 | static void jtag_puts(struct stdio_dev *dev, const char *s) |
36ea8e9a MF |
120 | { |
121 | jtag_send(s, strlen(s)); | |
122 | } | |
123 | ||
e82b762f MF |
124 | static size_t inbound_len, leftovers_len; |
125 | ||
126 | /* Lower layers want to know when jtag has data */ | |
127 | static int jtag_tstc_dbg(void) | |
36ea8e9a | 128 | { |
4fff5ac2 MF |
129 | int ret = (bfin_read_DBGSTAT() & 0x2); |
130 | if (ret) | |
131 | dprintf("%s: ret:%i\n", __func__, ret); | |
132 | return ret; | |
36ea8e9a MF |
133 | } |
134 | ||
e82b762f | 135 | /* Higher layers want to know when any data is available */ |
709ea543 | 136 | static int jtag_tstc(struct stdio_dev *dev) |
e82b762f MF |
137 | { |
138 | return jtag_tstc_dbg() || leftovers_len; | |
139 | } | |
140 | ||
36ea8e9a MF |
141 | /* Receive a buffer. The format is: |
142 | * [32bit length][actual data] | |
143 | */ | |
36ea8e9a | 144 | static uint32_t leftovers; |
709ea543 | 145 | static int jtag_getc(struct stdio_dev *dev) |
36ea8e9a MF |
146 | { |
147 | int ret; | |
148 | uint32_t emudat; | |
149 | ||
4fff5ac2 MF |
150 | dprintf("%s: inlen:%zu leftlen:%zu left:%x\n", __func__, |
151 | inbound_len, leftovers_len, leftovers); | |
152 | ||
36ea8e9a MF |
153 | /* see if any data is left over */ |
154 | if (leftovers_len) { | |
155 | --leftovers_len; | |
156 | ret = leftovers & 0xff; | |
157 | leftovers >>= 8; | |
158 | return ret; | |
159 | } | |
160 | ||
161 | /* wait for new data ! */ | |
e82b762f | 162 | while (!jtag_tstc_dbg()) |
36ea8e9a | 163 | continue; |
5079d8bb | 164 | emudat = bfin_read_emudat(); |
36ea8e9a MF |
165 | |
166 | if (inbound_len == 0) { | |
167 | /* grab the length */ | |
168 | inbound_len = emudat; | |
169 | } else { | |
170 | /* store the bytes */ | |
171 | leftovers_len = min(4, inbound_len); | |
172 | inbound_len -= leftovers_len; | |
173 | leftovers = emudat; | |
174 | } | |
175 | ||
709ea543 | 176 | return jtag_getc(dev); |
36ea8e9a MF |
177 | } |
178 | ||
179 | int drv_jtag_console_init(void) | |
180 | { | |
52cb4d4f | 181 | struct stdio_dev dev; |
36ea8e9a MF |
182 | int ret; |
183 | ||
184 | memset(&dev, 0x00, sizeof(dev)); | |
185 | strcpy(dev.name, "jtag"); | |
186 | dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; | |
187 | dev.putc = jtag_putc; | |
188 | dev.puts = jtag_puts; | |
189 | dev.tstc = jtag_tstc; | |
190 | dev.getc = jtag_getc; | |
191 | ||
52cb4d4f | 192 | ret = stdio_register(&dev); |
36ea8e9a MF |
193 | return (ret == 0 ? 1 : ret); |
194 | } | |
195 | ||
196 | #ifdef CONFIG_UART_CONSOLE_IS_JTAG | |
41651cab | 197 | #include <serial.h> |
36ea8e9a | 198 | /* Since the JTAG is always available (at power on), allow it to fake a UART */ |
41651cab MV |
199 | void jtag_serial_setbrg(void) |
200 | { | |
201 | } | |
202 | ||
203 | int jtag_serial_init(void) | |
204 | { | |
205 | return 0; | |
206 | } | |
207 | ||
208 | static struct serial_device serial_jtag_drv = { | |
209 | .name = "jtag", | |
210 | .start = jtag_serial_init, | |
211 | .stop = NULL, | |
212 | .setbrg = jtag_serial_setbrg, | |
213 | .putc = jtag_putc, | |
214 | .puts = jtag_puts, | |
215 | .tstc = jtag_tstc, | |
216 | .getc = jtag_getc, | |
217 | }; | |
218 | ||
219 | void bfin_jtag_initialize(void) | |
220 | { | |
221 | serial_register(&serial_jtag_drv); | |
222 | } | |
223 | ||
224 | struct serial_device *default_serial_console(void) | |
225 | { | |
226 | return &serial_jtag_drv; | |
227 | } | |
36ea8e9a | 228 | #endif |