ULINK driver: Implement variable TCK frequency in OpenULINK firmware
[openocd.git] / src / jtag / drivers / OpenULINK / src / protocol.c
1 /***************************************************************************
2 * Copyright (C) 2011 by Martin Schmoelzer *
3 * <martin.schmoelzer@student.tuwien.ac.at> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #include "protocol.h"
22 #include "jtag.h"
23 #include "delay.h"
24 #include "usb.h"
25 #include "io.h"
26 #include "msgtypes.h"
27
28 #include "reg_ezusb.h"
29
30 /**
31 * @file Implementation of the OpenULINK communication protocol.
32 *
33 * The OpenULINK protocol uses one OUT and one IN endpoint. These two endpoints
34 * are configured to use the maximum packet size for full-speed transfers,
35 * 64 bytes. Commands always start with a command ID (see msgtypes.h for
36 * command ID definitions) and contain zero or more payload data bytes in both
37 * transfer directions (IN and OUT). The payload
38 *
39 * Almost all commands contain a fixed number of payload data bytes. The number
40 * of payload data bytes for the IN and OUT direction does not need to be the
41 * same.
42 *
43 * Multiple commands may be sent in one EP2 Bulk-OUT packet. Because the
44 * OpenULINK firmware does not perform bounds checking for EP2 Bulk-IN packets,
45 * the host MUST ensure that the commands sent in the OUT packet require a
46 * maximum of 64 bytes of IN data.
47 */
48
49 /** Index in EP2 Bulk-OUT data buffer that contains the current command ID */
50 volatile u8 cmd_id_index;
51
52 /** Number of data bytes already in EP2 Bulk-IN buffer */
53 volatile u8 payload_index_in;
54
55 /**
56 * Execute a SET_LEDS command.
57 */
58 void execute_set_led_command(void)
59 {
60 u8 led_state = OUT2BUF[cmd_id_index + 1];
61
62 if (led_state & RUN_LED_ON) {
63 SET_RUN_LED();
64 }
65
66 if (led_state & COM_LED_ON) {
67 SET_COM_LED();
68 }
69
70 if (led_state & RUN_LED_OFF) {
71 CLEAR_RUN_LED();
72 }
73
74 if (led_state & COM_LED_OFF) {
75 CLEAR_COM_LED();
76 }
77 }
78
79 /**
80 * Executes one command and updates global command indexes.
81 *
82 * @param index the index of the Bulk EP2-OUT data buffer at which the
83 * command ID is stored.
84 * @return true if this command was the last command.
85 * @return false if there are more commands within the current contents of the
86 * Bulk EP2-OUT data buffer.
87 */
88 bool execute_command(void)
89 {
90 u8 usb_out_bytecount, usb_in_bytecount;
91 u16 signal_state;
92 u16 count;
93
94 /* Most commands do not transfer IN data. To save code space, we write 0 to
95 * usb_in_bytecount here, then modify it in the switch statement below where
96 * neccessary */
97 usb_in_bytecount = 0;
98
99 switch (OUT2BUF[cmd_id_index] /* Command ID */) {
100 case CMD_SCAN_IN:
101 usb_out_bytecount = 5;
102 usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
103 jtag_scan_in(cmd_id_index + 1, payload_index_in);
104 break;
105 case CMD_SCAN_OUT:
106 usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
107 jtag_scan_out(cmd_id_index + 1);
108 break;
109 case CMD_SCAN_IO:
110 usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
111 usb_out_bytecount = usb_in_bytecount + 5;
112 jtag_scan_io(cmd_id_index + 1, payload_index_in);
113 break;
114 case CMD_CLOCK_TMS:
115 usb_out_bytecount = 2;
116 jtag_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
117 break;
118 case CMD_CLOCK_TCK:
119 usb_out_bytecount = 2;
120 count = (u16)OUT2BUF[cmd_id_index + 1];
121 count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
122 jtag_clock_tck(count);
123 break;
124 case CMD_SLOW_SCAN_IN:
125 usb_out_bytecount = 5;
126 usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
127 jtag_slow_scan_in(cmd_id_index + 1, payload_index_in);
128 break;
129 case CMD_SLOW_SCAN_OUT:
130 usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
131 jtag_slow_scan_out(cmd_id_index + 1);
132 break;
133 case CMD_SLOW_SCAN_IO:
134 usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
135 usb_out_bytecount = usb_in_bytecount + 5;
136 jtag_slow_scan_io(cmd_id_index + 1, payload_index_in);
137 break;
138 case CMD_SLOW_CLOCK_TMS:
139 usb_out_bytecount = 2;
140 jtag_slow_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
141 break;
142 case CMD_SLOW_CLOCK_TCK:
143 usb_out_bytecount = 2;
144 count = (u16)OUT2BUF[cmd_id_index + 1];
145 count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
146 jtag_slow_clock_tck(count);
147 break;
148 case CMD_SLEEP_US:
149 usb_out_bytecount = 2;
150 count = (u16)OUT2BUF[cmd_id_index + 1];
151 count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
152 delay_us(count);
153 break;
154 case CMD_SLEEP_MS:
155 usb_out_bytecount = 2;
156 count = (u16)OUT2BUF[cmd_id_index + 1];
157 count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
158 delay_ms(count);
159 break;
160 case CMD_GET_SIGNALS:
161 usb_out_bytecount = 0;
162 usb_in_bytecount = 2;
163 signal_state = jtag_get_signals();
164 IN2BUF[payload_index_in] = (signal_state >> 8) & 0x00FF;
165 IN2BUF[payload_index_in + 1] = signal_state & 0x00FF;
166 break;
167 case CMD_SET_SIGNALS:
168 usb_out_bytecount = 2;
169 jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
170 break;
171 case CMD_CONFIGURE_TCK_FREQ:
172 usb_out_bytecount = 5;
173 jtag_configure_tck_delay(
174 OUT2BUF[cmd_id_index + 1], /* scan_in */
175 OUT2BUF[cmd_id_index + 2], /* scan_out */
176 OUT2BUF[cmd_id_index + 3], /* scan_io */
177 OUT2BUF[cmd_id_index + 4], /* clock_tck */
178 OUT2BUF[cmd_id_index + 5]); /* clock_tms */
179 break;
180 case CMD_SET_LEDS:
181 usb_out_bytecount = 1;
182 execute_set_led_command();
183 break;
184 case CMD_TEST:
185 usb_out_bytecount = 1;
186 /* Do nothing... This command is only used to test if the device is ready
187 * to accept new commands */
188 break;
189 default:
190 /* Should never be reached */
191 usb_out_bytecount = 0;
192 break;
193 }
194
195 /* Update EP2 Bulk-IN data byte count */
196 payload_index_in += usb_in_bytecount;
197
198 /* Determine if this was the last command */
199 if ((cmd_id_index + usb_out_bytecount + 1) >= OUT2BC) {
200 return true;
201 }
202 else {
203 /* Not the last command, update cmd_id_index */
204 cmd_id_index += (usb_out_bytecount + 1);
205 return false;
206 }
207 }
208
209 /**
210 * Forever wait for commands and execute them as they arrive.
211 */
212 void command_loop(void)
213 {
214 bool last_command;
215
216 while (1) {
217 cmd_id_index = 0;
218 payload_index_in = 0;
219
220 /* Wait until host sends EP2 Bulk-OUT packet */
221 while (!EP2_out);
222 EP2_out = 0;
223
224 /* Turn on COM LED to indicate command execution */
225 SET_COM_LED();
226
227 /* Execute the commands */
228 last_command = false;
229 while (last_command == false) {
230 last_command = execute_command();
231 }
232
233 CLEAR_COM_LED();
234
235 /* Send back EP2 Bulk-IN packet if required */
236 if (payload_index_in > 0) {
237 IN2BC = payload_index_in;
238 while (!EP2_in);
239 EP2_in = 0;
240 }
241
242 /* Re-arm EP2-OUT after command execution */
243 OUT2BC = 0;
244 }
245 }