openocd: src/jtag: replace the GPL-2.0-or-later license tag
[openocd.git] / src / jtag / drivers / OpenULINK / src / protocol.c
blob319785e66be0ac965e9328a15b4ff3e9f4cebae3
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2011 by Martin Schmoelzer *
5 * <martin.schmoelzer@student.tuwien.ac.at> *
6 ***************************************************************************/
8 #include "protocol.h"
9 #include "jtag.h"
10 #include "delay.h"
11 #include "usb.h"
12 #include "io.h"
13 #include "msgtypes.h"
15 #include "reg_ezusb.h"
17 /**
18 * @file
19 * Implementation of the OpenULINK communication protocol.
21 * The OpenULINK protocol uses one OUT and one IN endpoint. These two endpoints
22 * are configured to use the maximum packet size for full-speed transfers,
23 * 64 bytes. Commands always start with a command ID (see msgtypes.h for
24 * command ID definitions) and contain zero or more payload data bytes in both
25 * transfer directions (IN and OUT). The payload
27 * Almost all commands contain a fixed number of payload data bytes. The number
28 * of payload data bytes for the IN and OUT direction does not need to be the
29 * same.
31 * Multiple commands may be sent in one EP2 Bulk-OUT packet. Because the
32 * OpenULINK firmware does not perform bounds checking for EP2 Bulk-IN packets,
33 * the host MUST ensure that the commands sent in the OUT packet require a
34 * maximum of 64 bytes of IN data.
37 /** Index in EP2 Bulk-OUT data buffer that contains the current command ID */
38 volatile uint8_t cmd_id_index;
40 /** Number of data bytes already in EP2 Bulk-IN buffer */
41 volatile uint8_t payload_index_in;
43 /**
44 * Execute a SET_LEDS command.
46 void execute_set_led_command(void)
48 uint8_t led_state = OUT2BUF[cmd_id_index + 1];
50 if (led_state & RUN_LED_ON)
51 SET_RUN_LED();
53 if (led_state & COM_LED_ON)
54 SET_COM_LED();
56 if (led_state & RUN_LED_OFF)
57 CLEAR_RUN_LED();
59 if (led_state & COM_LED_OFF)
60 CLEAR_COM_LED();
63 /**
64 * Executes one command and updates global command indexes.
66 * @return true if this command was the last command.
67 * @return false if there are more commands within the current contents of the
68 * Bulk EP2-OUT data buffer.
70 bool execute_command(void)
72 uint8_t usb_out_bytecount, usb_in_bytecount;
73 uint16_t signal_state;
74 uint16_t count;
76 /* Most commands do not transfer IN data. To save code space, we write 0 to
77 * usb_in_bytecount here, then modify it in the switch statement below where
78 * necessary */
79 usb_in_bytecount = 0;
81 switch (OUT2BUF[cmd_id_index] /* Command ID */) {
82 case CMD_SCAN_IN:
83 usb_out_bytecount = 5;
84 usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
85 jtag_scan_in(cmd_id_index + 1, payload_index_in);
86 break;
87 case CMD_SCAN_OUT:
88 usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
89 jtag_scan_out(cmd_id_index + 1);
90 break;
91 case CMD_SCAN_IO:
92 usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
93 usb_out_bytecount = usb_in_bytecount + 5;
94 jtag_scan_io(cmd_id_index + 1, payload_index_in);
95 break;
96 case CMD_CLOCK_TMS:
97 usb_out_bytecount = 2;
98 jtag_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
99 break;
100 case CMD_CLOCK_TCK:
101 usb_out_bytecount = 2;
102 count = (uint16_t)OUT2BUF[cmd_id_index + 1];
103 count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
104 jtag_clock_tck(count);
105 break;
106 case CMD_SLOW_SCAN_IN:
107 usb_out_bytecount = 5;
108 usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
109 jtag_slow_scan_in(cmd_id_index + 1, payload_index_in);
110 break;
111 case CMD_SLOW_SCAN_OUT:
112 usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
113 jtag_slow_scan_out(cmd_id_index + 1);
114 break;
115 case CMD_SLOW_SCAN_IO:
116 usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
117 usb_out_bytecount = usb_in_bytecount + 5;
118 jtag_slow_scan_io(cmd_id_index + 1, payload_index_in);
119 break;
120 case CMD_SLOW_CLOCK_TMS:
121 usb_out_bytecount = 2;
122 jtag_slow_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
123 break;
124 case CMD_SLOW_CLOCK_TCK:
125 usb_out_bytecount = 2;
126 count = (uint16_t)OUT2BUF[cmd_id_index + 1];
127 count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
128 jtag_slow_clock_tck(count);
129 break;
130 case CMD_SLEEP_US:
131 usb_out_bytecount = 2;
132 count = (uint16_t)OUT2BUF[cmd_id_index + 1];
133 count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
134 delay_us(count);
135 break;
136 case CMD_SLEEP_MS:
137 usb_out_bytecount = 2;
138 count = (uint16_t)OUT2BUF[cmd_id_index + 1];
139 count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
140 delay_ms(count);
141 break;
142 case CMD_GET_SIGNALS:
143 usb_out_bytecount = 0;
144 usb_in_bytecount = 2;
145 signal_state = jtag_get_signals();
146 IN2BUF[payload_index_in] = (signal_state >> 8) & 0x00FF;
147 IN2BUF[payload_index_in + 1] = signal_state & 0x00FF;
148 break;
149 case CMD_SET_SIGNALS:
150 usb_out_bytecount = 2;
151 jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
152 break;
153 case CMD_CONFIGURE_TCK_FREQ:
154 usb_out_bytecount = 5;
155 jtag_configure_tck_delay(
156 OUT2BUF[cmd_id_index + 1], /* scan_in */
157 OUT2BUF[cmd_id_index + 2], /* scan_out */
158 OUT2BUF[cmd_id_index + 3], /* scan_io */
159 OUT2BUF[cmd_id_index + 4], /* clock_tck */
160 OUT2BUF[cmd_id_index + 5]); /* clock_tms */
161 break;
162 case CMD_SET_LEDS:
163 usb_out_bytecount = 1;
164 execute_set_led_command();
165 break;
166 case CMD_TEST:
167 usb_out_bytecount = 1;
168 /* Do nothing... This command is only used to test if the device is ready
169 * to accept new commands */
170 break;
171 default:
172 /* Should never be reached */
173 usb_out_bytecount = 0;
174 break;
177 /* Update EP2 Bulk-IN data byte count */
178 payload_index_in += usb_in_bytecount;
180 /* Determine if this was the last command */
181 if ((cmd_id_index + usb_out_bytecount + 1) >= OUT2BC)
182 return true;
183 else {
184 /* Not the last command, update cmd_id_index */
185 cmd_id_index += (usb_out_bytecount + 1);
186 return false;
191 * Forever wait for commands and execute them as they arrive.
193 void command_loop(void)
195 bool last_command;
197 while (1) {
198 cmd_id_index = 0;
199 payload_index_in = 0;
201 /* Wait until host sends EP2 Bulk-OUT packet */
202 while (!EP2_out)
204 EP2_out = 0;
206 /* Turn on COM LED to indicate command execution */
207 SET_COM_LED();
209 /* Execute the commands */
210 last_command = false;
211 while (last_command == false)
212 last_command = execute_command();
214 CLEAR_COM_LED();
216 /* Send back EP2 Bulk-IN packet if required */
217 if (payload_index_in > 0) {
218 IN2BC = payload_index_in;
219 while (!EP2_in)
221 EP2_in = 0;
224 /* Re-arm EP2-OUT after command execution */
225 OUT2BC = 0;