Add 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_SLEEP_US:
125 usb_out_bytecount = 2;
126 count = (u16)OUT2BUF[cmd_id_index + 1];
127 count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
128 delay_us(count);
129 break;
130 case CMD_SLEEP_MS:
131 usb_out_bytecount = 2;
132 count = (u16)OUT2BUF[cmd_id_index + 1];
133 count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
134 delay_ms(count);
135 break;
136 case CMD_GET_SIGNALS:
137 usb_out_bytecount = 0;
138 usb_in_bytecount = 2;
139 signal_state = jtag_get_signals();
140 IN2BUF[payload_index_in] = (signal_state >> 8) & 0x00FF;
141 IN2BUF[payload_index_in + 1] = signal_state & 0x00FF;
142 break;
143 case CMD_SET_SIGNALS:
144 usb_out_bytecount = 2;
145 jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
146 break;
147 case CMD_SET_LEDS:
148 usb_out_bytecount = 1;
149 execute_set_led_command();
150 break;
151 case CMD_TEST:
152 usb_out_bytecount = 1;
153 /* Do nothing... This command is only used to test if the device is ready
154 * to accept new commands */
155 break;
156 default:
157 /* Should never be reached */
158 usb_out_bytecount = 0;
159 break;
160 }
161
162 /* Update EP2 Bulk-IN data byte count */
163 payload_index_in += usb_in_bytecount;
164
165 /* Determine if this was the last command */
166 if ((cmd_id_index + usb_out_bytecount + 1) >= OUT2BC) {
167 return true;
168 }
169 else {
170 /* Not the last command, update cmd_id_index */
171 cmd_id_index += (usb_out_bytecount + 1);
172 return false;
173 }
174 }
175
176 /**
177 * Forever wait for commands and execute them as they arrive.
178 */
179 void command_loop(void)
180 {
181 bool last_command;
182
183 while (1) {
184 cmd_id_index = 0;
185 payload_index_in = 0;
186
187 /* Wait until host sends EP2 Bulk-OUT packet */
188 while (!EP2_out);
189 EP2_out = 0;
190
191 /* Turn on COM LED to indicate command execution */
192 SET_COM_LED();
193
194 /* Execute the commands */
195 last_command = false;
196 while (last_command == false) {
197 last_command = execute_command();
198 }
199
200 CLEAR_COM_LED();
201
202 /* Send back EP2 Bulk-IN packet if required */
203 if (payload_index_in > 0) {
204 IN2BC = payload_index_in;
205 while (!EP2_in);
206 EP2_in = 0;
207 }
208
209 /* Re-arm EP2-OUT after command execution */
210 OUT2BC = 0;
211 }
212 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)