openocd: fix SPDX tag format for files .c
[fw/openocd] / src / jtag / drivers / versaloon / versaloon.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4  *   Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com>     *
5  ***************************************************************************/
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "versaloon_include.h"
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <libusb.h>
16
17 #include "versaloon.h"
18 #include "versaloon_internal.h"
19 #include "usbtoxxx/usbtoxxx.h"
20
21 uint8_t *versaloon_buf;
22 uint8_t *versaloon_cmd_buf;
23 uint16_t versaloon_buf_size;
24
25 struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
26 uint16_t versaloon_pending_idx;
27
28 struct libusb_device_handle *versaloon_usb_device_handle;
29 static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
30
31 static RESULT versaloon_init(void);
32 static RESULT versaloon_fini(void);
33 static RESULT versaloon_get_target_voltage(uint16_t *voltage);
34 static RESULT versaloon_set_target_voltage(uint16_t voltage);
35 static RESULT versaloon_delay_ms(uint16_t ms);
36 static RESULT versaloon_delay_us(uint16_t us);
37
38 struct versaloon_interface_t versaloon_interface = {
39         .init                           = versaloon_init,
40         .fini                           = versaloon_fini,
41         {       /* adaptors */
42                 {       /* target_voltage */
43                         .get            = versaloon_get_target_voltage,
44                         .set            = versaloon_set_target_voltage,
45                 },
46                 {       /* gpio */
47                         .init           = usbtogpio_init,
48                         .fini           = usbtogpio_fini,
49                         .config         = usbtogpio_config,
50                         .out            = usbtogpio_out,
51                         .in                     = usbtogpio_in,
52                 },
53                 {       /* delay */
54                         .delayms        = versaloon_delay_ms,
55                         .delayus        = versaloon_delay_us,
56                 },
57                 {       /* swd */
58                         .init           = usbtoswd_init,
59                         .fini           = usbtoswd_fini,
60                         .config         = usbtoswd_config,
61                         .seqout         = usbtoswd_seqout,
62                         .seqin          = usbtoswd_seqin,
63                         .transact       = usbtoswd_transact,
64                 },
65                 {       /* jtag_raw */
66                         .init           = usbtojtagraw_init,
67                         .fini           = usbtojtagraw_fini,
68                         .config         = usbtojtagraw_config,
69                         .execute        = usbtojtagraw_execute,
70                 },
71                 .peripheral_commit = usbtoxxx_execute_command,
72         },
73         {       /* usb_setting */
74                 .vid                    = VERSALOON_VID,
75                 .pid                    = VERSALOON_PID,
76                 .ep_out                 = VERSALOON_OUTP,
77                 .ep_in                  = VERSALOON_INP,
78                 .interface              = VERSALOON_IFACE,
79                 .buf_size               = 256,
80         }
81 };
82
83 /* programmer_cmd */
84 static uint32_t versaloon_pending_id;
85 static versaloon_callback_t versaloon_callback;
86 static void *versaloon_extra_data;
87 static struct versaloon_want_pos_t *versaloon_want_pos;
88
89 void versaloon_set_pending_id(uint32_t id)
90 {
91         versaloon_pending_id = id;
92 }
93 void versaloon_set_callback(versaloon_callback_t callback)
94 {
95         versaloon_callback = callback;
96 }
97 void versaloon_set_extra_data(void *p)
98 {
99         versaloon_extra_data = p;
100 }
101
102 void versaloon_free_want_pos(void)
103 {
104         uint16_t i;
105         struct versaloon_want_pos_t *tmp, *free_tmp;
106
107         tmp = versaloon_want_pos;
108         while (tmp) {
109                 free_tmp = tmp;
110                 tmp = tmp->next;
111                 free(free_tmp);
112         }
113         versaloon_want_pos = NULL;
114
115         for (i = 0; i < ARRAY_SIZE(versaloon_pending); i++) {
116                 tmp = versaloon_pending[i].pos;
117                 while (tmp) {
118                         free_tmp = tmp;
119                         tmp = tmp->next;
120                         free(free_tmp);
121                 }
122                 versaloon_pending[i].pos = NULL;
123         }
124 }
125
126 RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff)
127 {
128         struct versaloon_want_pos_t *new_pos = NULL;
129
130         new_pos = malloc(sizeof(*new_pos));
131         if (!new_pos) {
132                 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
133                 return ERRCODE_NOT_ENOUGH_MEMORY;
134         }
135         new_pos->offset = offset;
136         new_pos->size = size;
137         new_pos->buff = buff;
138         new_pos->next = NULL;
139
140         if (!versaloon_want_pos)
141                 versaloon_want_pos = new_pos;
142         else {
143                 struct versaloon_want_pos_t *tmp = versaloon_want_pos;
144
145                 while (tmp->next)
146                         tmp = tmp->next;
147                 tmp->next = new_pos;
148         }
149
150         return ERROR_OK;
151 }
152
153 RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie,
154         uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect)
155 {
156 #if PARAM_CHECK
157         if (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER) {
158                 LOG_BUG(ERRMSG_INVALID_INDEX, versaloon_pending_idx,
159                         "versaloon pending data");
160                 return ERROR_FAIL;
161         }
162 #endif
163
164         versaloon_pending[versaloon_pending_idx].type = type;
165         versaloon_pending[versaloon_pending_idx].cmd = cmd;
166         versaloon_pending[versaloon_pending_idx].actual_data_size = actual_szie;
167         versaloon_pending[versaloon_pending_idx].want_data_pos = want_pos;
168         versaloon_pending[versaloon_pending_idx].want_data_size = want_size;
169         versaloon_pending[versaloon_pending_idx].data_buffer = buffer;
170         versaloon_pending[versaloon_pending_idx].collect = collect;
171         versaloon_pending[versaloon_pending_idx].id = versaloon_pending_id;
172         versaloon_pending_id = 0;
173         versaloon_pending[versaloon_pending_idx].extra_data = versaloon_extra_data;
174         versaloon_extra_data = NULL;
175         versaloon_pending[versaloon_pending_idx].callback = versaloon_callback;
176         versaloon_callback = NULL;
177         versaloon_pending[versaloon_pending_idx].pos = versaloon_want_pos;
178         versaloon_want_pos = NULL;
179         versaloon_pending_idx++;
180
181         return ERROR_OK;
182 }
183
184 RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen)
185 {
186         int ret;
187         int transferred;
188
189 #if PARAM_CHECK
190         if (!versaloon_buf) {
191                 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
192                 return ERRCODE_INVALID_BUFFER;
193         }
194         if ((out_len == 0) || (out_len > versaloon_interface.usb_setting.buf_size)) {
195                 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
196                 return ERRCODE_INVALID_PARAMETER;
197         }
198 #endif
199
200         ret = libusb_bulk_transfer(versaloon_usb_device_handle,
201                         versaloon_interface.usb_setting.ep_out,
202                         versaloon_buf, out_len, &transferred, versaloon_usb_to);
203         if (ret != 0 || transferred != out_len) {
204                 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "send usb data");
205                 return ERRCODE_FAILURE_OPERATION;
206         }
207
208         if (inlen) {
209                 ret = libusb_bulk_transfer(versaloon_usb_device_handle,
210                         versaloon_interface.usb_setting.ep_in,
211                         versaloon_buf, versaloon_interface.usb_setting.buf_size,
212                         &transferred, versaloon_usb_to);
213                 if (ret == 0) {
214                         *inlen = (uint16_t)transferred;
215                         return ERROR_OK;
216                 } else {
217                         LOG_ERROR(ERRMSG_FAILURE_OPERATION, "receive usb data");
218                         return ERROR_FAIL;
219                 }
220         } else
221                 return ERROR_OK;
222 }
223
224 #define VERSALOON_RETRY_CNT 10
225 static RESULT versaloon_init(void)
226 {
227         uint16_t ret = 0;
228         uint8_t retry;
229         uint32_t timeout_tmp;
230
231         /* malloc temporary buffer */
232         versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size);
233         if (!versaloon_buf) {
234                 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
235                 return ERRCODE_NOT_ENOUGH_MEMORY;
236         }
237
238         /* connect to versaloon */
239         timeout_tmp = versaloon_usb_to;
240         /* not output error message when connecting */
241         /* 100ms delay when connect */
242         versaloon_usb_to = 100;
243         for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++) {
244                 versaloon_buf[0] = VERSALOON_GET_INFO;
245                 if ((versaloon_send_command(1, &ret) == ERROR_OK) && (ret >= 3))
246                         break;
247         }
248         versaloon_usb_to = timeout_tmp;
249         if (retry == VERSALOON_RETRY_CNT) {
250                 versaloon_fini();
251                 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
252                 return ERRCODE_FAILURE_OPERATION;
253         }
254
255         versaloon_buf[ret] = 0;
256         versaloon_buf_size = versaloon_buf[0] + (versaloon_buf[1] << 8);
257         versaloon_interface.usb_setting.buf_size = versaloon_buf_size;
258         LOG_INFO("%s", versaloon_buf + 2);
259
260         /* free temporary buffer */
261         free(versaloon_buf);
262         versaloon_buf = NULL;
263
264         versaloon_buf = malloc(versaloon_interface.usb_setting.buf_size);
265         if (!versaloon_buf) {
266                 versaloon_fini();
267                 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
268                 return ERRCODE_NOT_ENOUGH_MEMORY;
269         }
270         versaloon_cmd_buf = malloc(versaloon_interface.usb_setting.buf_size - 3);
271         if (!versaloon_cmd_buf) {
272                 versaloon_fini();
273                 LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
274                 return ERRCODE_NOT_ENOUGH_MEMORY;
275         }
276         if (usbtoxxx_init() != ERROR_OK) {
277                 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx");
278                 return ERROR_FAIL;
279         }
280         return versaloon_get_target_voltage(&ret);
281 }
282
283 static RESULT versaloon_fini(void)
284 {
285         if (versaloon_usb_device_handle) {
286                 usbtoxxx_fini();
287                 versaloon_free_want_pos();
288
289                 versaloon_usb_device_handle = NULL;
290
291                 free(versaloon_buf);
292                 versaloon_buf = NULL;
293
294                 free(versaloon_cmd_buf);
295                 versaloon_cmd_buf = NULL;
296         }
297
298         return ERROR_OK;
299 }
300
301 static RESULT versaloon_set_target_voltage(uint16_t voltage)
302 {
303         usbtopwr_init(0);
304         usbtopwr_config(0);
305         usbtopwr_output(0, voltage);
306         usbtopwr_fini(0);
307
308         return usbtoxxx_execute_command();
309 }
310
311 static RESULT versaloon_get_target_voltage(uint16_t *voltage)
312 {
313         uint16_t inlen;
314
315 #if PARAM_CHECK
316         if (!versaloon_buf) {
317                 LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
318                 return ERRCODE_INVALID_BUFFER;
319         }
320         if (!voltage) {
321                 LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__);
322                 return ERRCODE_INVALID_PARAMETER;
323         }
324 #endif
325
326         versaloon_buf[0] = VERSALOON_GET_TVCC;
327
328         if ((versaloon_send_command(1, &inlen) != ERROR_OK) || (inlen != 2)) {
329                 LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
330                 return ERRCODE_FAILURE_OPERATION;
331         } else {
332                 *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8);
333                 return ERROR_OK;
334         }
335 }
336
337 static RESULT versaloon_delay_ms(uint16_t ms)
338 {
339         return usbtodelay_delay(ms | 0x8000);
340 }
341
342 static RESULT versaloon_delay_us(uint16_t us)
343 {
344         return usbtodelay_delay(us & 0x7FFF);
345 }