blob: 24531628ade6b8801cc12a5ca3ef4f5810673b88 [file] [log] [blame]
Miklós Márton324929c2019-08-01 19:14:10 +02001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2019 Miklós Márton martonmiklosqdev@gmail.com
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18/*
19 * Driver for programming SPI flash chips using the SPI port
20 * of the STMicroelectronics's STLINK-V3 programmer/debugger.
21 *
22 * The implementation is inspired by the ST's STLINK-V3-BRIDGE C++ API:
23 * https://www.st.com/en/development-tools/stlink-v3-bridge.html
24 */
25
26#include "flash.h"
27#include "programmer.h"
28#include "spi.h"
29
30#include <libusb.h>
31#include <limits.h>
32#include <stdint.h>
33#include <stdlib.h>
34#include <string.h>
35
36enum fw_version_check_result {
37 FW_VERSION_OK,
38 FW_VERSION_OLD,
39};
40
41enum spi_prescaler {
42 SPI_BAUDRATEPRESCALER_2 = 0,
43 SPI_BAUDRATEPRESCALER_4 = 1,
44 SPI_BAUDRATEPRESCALER_8 = 2,
45 SPI_BAUDRATEPRESCALER_16 = 3,
46 SPI_BAUDRATEPRESCALER_32 = 4,
47 SPI_BAUDRATEPRESCALER_64 = 5,
48 SPI_BAUDRATEPRESCALER_128 = 6,
49 SPI_BAUDRATEPRESCALER_256 = 7
50};
51
52enum spi_dir {
53 SPI_DIRECTION_2LINES_FULLDUPLEX = 0,
54 SPI_DIRECTION_2LINES_RXONLY = 1,
55 SPI_DIRECTION_1LINE_RX = 2,
56 SPI_DIRECTION_1LINE_TX = 3
57};
58
59enum spi_mode {
60 SPI_MODE_SLAVE = 0,
61 SPI_MODE_MASTER = 1
62};
63
64enum spi_datasize {
65 SPI_DATASIZE_16B = 0,
66 SPI_DATASIZE_8B = 1
67};
68
69enum spi_cpol {
70 SPI_CPOL_LOW = 0,
71 SPI_CPOL_HIGH = 1
72};
73
74enum spi_cpha {
75 SPI_CPHA_1EDGE = 0,
76 SPI_CPHA_2EDGE = 1
77};
78
79enum spi_firstbit {
80 SPI_FIRSTBIT_LSB = 0,
81 SPI_FIRSTBIT_MSB = 1
82};
83
84// ST calls the Chip select (CS) NSS == Negated Slave Select
85enum spi_nss {
86 SPI_NSS_SOFT = 0,
87 SPI_NSS_HARD = 1
88};
89
90enum spi_nss_level {
91 SPI_NSS_LOW = 0,
92 SPI_NSS_HIGH = 1
93};
94
95#define ST_GETVERSION_EXT 0xFB
96
97#define STLINK_BRIDGE_COMMAND 0xFC
98#define STLINK_BRIDGE_CLOSE 0x01
99#define STLINK_BRIDGE_GET_RWCMD_STATUS 0x02
100#define STLINK_BRIDGE_GET_CLOCK 0x03
101#define STLINK_BRIDGE_INIT_SPI 0x20
102#define STLINK_BRIDGE_WRITE_SPI 0x21
103#define STLINK_BRIDGE_READ_SPI 0x22
104#define STLINK_BRIDGE_CS_SPI 0x23
105
106#define STLINK_BRIDGE_SPI_ERROR 0x02
107
108#define STLINK_SPI_COM 0x02
109
110#define STLINK_EP_OUT 0x06
111#define STLINK_EP_IN 0x86
112
113#define FIRST_COMPATIBLE_BRIDGE_FW_VERSION 3
114
115#define USB_TIMEOUT_IN_MS 5000
116
117const struct dev_entry devs_stlinkv3_spi[] = {
118 {0x0483, 0x374F, OK, "STMicroelectronics", "STLINK-V3"},
119 {0}
120};
121
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000122struct stlinkv3_spi_data {
123 struct libusb_context *usb_ctx;
Anastasia Klimchukdaa86b52021-05-19 13:35:59 +1000124 libusb_device_handle *handle;
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000125};
Miklós Márton324929c2019-08-01 19:14:10 +0200126
127static int stlinkv3_command(uint8_t *command, size_t command_length,
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000128 uint8_t *answer, size_t answer_length, const char *command_name,
129 libusb_device_handle *stlinkv3_handle)
Miklós Márton324929c2019-08-01 19:14:10 +0200130{
131 int actual_length = 0;
132 int rc = libusb_bulk_transfer(stlinkv3_handle, STLINK_EP_OUT,
133 command, command_length,
134 &actual_length, USB_TIMEOUT_IN_MS);
135 if (rc != LIBUSB_TRANSFER_COMPLETED || (size_t)actual_length != command_length) {
136 msg_perr("Failed to issue the %s command: '%s'\n",
137 command_name,
138 libusb_error_name(rc));
139 return -1;
140 }
141
142 rc = libusb_bulk_transfer(stlinkv3_handle, STLINK_EP_IN,
143 answer, answer_length,
144 &actual_length, USB_TIMEOUT_IN_MS);
145 if (rc != LIBUSB_TRANSFER_COMPLETED || (size_t)actual_length != answer_length) {
146 msg_perr("Failed to get %s answer: '%s'\n",
147 command_name,
148 libusb_error_name(rc));
149 return -1;
150 }
151 return 0;
152}
153
154/**
155 * @param[out] bridge_input_clk Current input frequency in kHz of the given com.
156 */
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000157static int stlinkv3_get_clk(uint32_t *bridge_input_clk, libusb_device_handle *stlinkv3_handle)
Miklós Márton324929c2019-08-01 19:14:10 +0200158{
159 uint8_t command[16];
160 uint8_t answer[12];
161
162 if (bridge_input_clk == NULL)
163 return -1;
164
165 memset(command, 0, sizeof(command));
166
167 command[0] = STLINK_BRIDGE_COMMAND;
168 command[1] = STLINK_BRIDGE_GET_CLOCK;
169 command[2] = STLINK_SPI_COM;
170
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000171 if (stlinkv3_command(command, sizeof(command),
172 answer, sizeof(answer),
173 "STLINK_BRIDGE_GET_CLOCK",
174 stlinkv3_handle) != 0)
Miklós Márton324929c2019-08-01 19:14:10 +0200175 return -1;
176
177 *bridge_input_clk = (uint32_t)answer[4]
178 | (uint32_t)answer[5]<<8
179 | (uint32_t)answer[6]<<16
180 | (uint32_t)answer[7]<<24;
181 return 0;
182
183}
184
185static int stlinkv3_spi_calc_prescaler(uint16_t reqested_freq_in_kHz,
186 enum spi_prescaler *prescaler,
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000187 uint16_t *calculated_freq_in_kHz,
188 libusb_device_handle *stlinkv3_handle)
Miklós Márton324929c2019-08-01 19:14:10 +0200189{
190 uint32_t bridge_clk_in_kHz;
191 uint32_t calculated_prescaler = 1;
192 uint16_t prescaler_value;
193
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000194 if (stlinkv3_get_clk(&bridge_clk_in_kHz, stlinkv3_handle))
Miklós Márton324929c2019-08-01 19:14:10 +0200195 return -1;
196
197 calculated_prescaler = bridge_clk_in_kHz/reqested_freq_in_kHz;
198 // Apply a smaller frequency if not exact
199 if (calculated_prescaler <= 2) {
200 *prescaler = SPI_BAUDRATEPRESCALER_2;
201 prescaler_value = 2;
202 } else if (calculated_prescaler <= 4) {
203 *prescaler = SPI_BAUDRATEPRESCALER_4;
204 prescaler_value = 4;
205 } else if (calculated_prescaler <= 8) {
206 *prescaler = SPI_BAUDRATEPRESCALER_8;
207 prescaler_value = 8;
208 } else if (calculated_prescaler <= 16) {
209 *prescaler = SPI_BAUDRATEPRESCALER_16;
210 prescaler_value = 16;
211 } else if (calculated_prescaler <= 32) {
212 *prescaler = SPI_BAUDRATEPRESCALER_32;
213 prescaler_value = 32;
214 } else if (calculated_prescaler <= 64) {
215 *prescaler = SPI_BAUDRATEPRESCALER_64;
216 prescaler_value = 64;
217 } else if (calculated_prescaler <= 128) {
218 *prescaler = SPI_BAUDRATEPRESCALER_128;
219 prescaler_value = 128;
220 } else if (calculated_prescaler <= 256) {
221 *prescaler = SPI_BAUDRATEPRESCALER_256;
222 prescaler_value = 256;
223 } else {
224 // smaller frequency not possible
225 *prescaler = SPI_BAUDRATEPRESCALER_256;
226 prescaler_value = 256;
227 }
228
229 *calculated_freq_in_kHz = bridge_clk_in_kHz / prescaler_value;
230
231 return 0;
232}
233
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000234static int stlinkv3_check_version(enum fw_version_check_result *result, libusb_device_handle *stlinkv3_handle)
Miklós Márton324929c2019-08-01 19:14:10 +0200235{
236 uint8_t answer[12];
237 uint8_t command[16];
238
239 memset(command, 0, sizeof(command));
240
241 command[0] = ST_GETVERSION_EXT;
242 command[1] = 0x80;
243
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000244 if (stlinkv3_command(command, sizeof(command),
245 answer, sizeof(answer),
246 "ST_GETVERSION_EXT",
247 stlinkv3_handle) != 0)
Miklós Márton324929c2019-08-01 19:14:10 +0200248 return -1;
249
250 msg_pinfo("Connected to STLink V3 with bridge FW version: %d\n", answer[4]);
251 *result = answer[4] >= FIRST_COMPATIBLE_BRIDGE_FW_VERSION
252 ? FW_VERSION_OK
253 : FW_VERSION_OLD;
254 return 0;
255}
256
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000257static int stlinkv3_spi_open(uint16_t reqested_freq_in_kHz, libusb_device_handle *stlinkv3_handle)
Miklós Márton324929c2019-08-01 19:14:10 +0200258{
259 uint8_t command[16];
260 uint8_t answer[2];
261 uint16_t SCK_freq_in_kHz;
262 enum spi_prescaler prescaler;
263 enum fw_version_check_result fw_check_result;
264
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000265 if (stlinkv3_check_version(&fw_check_result, stlinkv3_handle)) {
Miklós Márton47143bc2020-07-26 10:40:46 +0200266 msg_perr("Failed to query FW version\n");
Miklós Márton324929c2019-08-01 19:14:10 +0200267 return -1;
268 }
269
270 if (fw_check_result != FW_VERSION_OK) {
Miklós Márton47143bc2020-07-26 10:40:46 +0200271 msg_pinfo("Your STLink V3 has a too old version of the bridge interface\n"
272 "Please update the firmware to version 2.33.25 or newer of the STSW-LINK007\n"
273 "which can be downloaded from here:\n"
274 "https://www.st.com/en/development-tools/stsw-link007.html\n");
Miklós Márton324929c2019-08-01 19:14:10 +0200275 return -1;
276 }
277
278 if (stlinkv3_spi_calc_prescaler(reqested_freq_in_kHz,
279 &prescaler,
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000280 &SCK_freq_in_kHz,
281 stlinkv3_handle)) {
Miklós Márton47143bc2020-07-26 10:40:46 +0200282 msg_perr("Failed to calculate SPI clock prescaler\n");
Miklós Márton324929c2019-08-01 19:14:10 +0200283 return -1;
284 }
285 msg_pinfo("SCK frequency set to %d kHz\n", SCK_freq_in_kHz);
286
287 memset(command, 0, sizeof(command));
288
289 command[0] = STLINK_BRIDGE_COMMAND;
290 command[1] = STLINK_BRIDGE_INIT_SPI;
291 command[2] = SPI_DIRECTION_2LINES_FULLDUPLEX;
292 command[3] = (SPI_MODE_MASTER
293 | (SPI_CPHA_1EDGE << 1)
294 | (SPI_CPOL_LOW << 2)
295 | (SPI_FIRSTBIT_MSB << 3));
296 command[4] = SPI_DATASIZE_8B;
297 command[5] = SPI_NSS_SOFT;
298 command[6] = (uint8_t)prescaler;
299
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000300 return stlinkv3_command(command, sizeof(command),
301 answer, sizeof(answer),
302 "STLINK_BRIDGE_INIT_SPI",
303 stlinkv3_handle);
Miklós Márton324929c2019-08-01 19:14:10 +0200304}
305
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000306static int stlinkv3_get_last_readwrite_status(uint32_t *status, libusb_device_handle *stlinkv3_handle)
Miklós Márton324929c2019-08-01 19:14:10 +0200307{
308 uint8_t command[16];
309 uint16_t answer[4];
310
311 memset(command, 0, sizeof(command));
312
313 command[0] = STLINK_BRIDGE_COMMAND;
314 command[1] = STLINK_BRIDGE_GET_RWCMD_STATUS;
315
316 if (stlinkv3_command(command, sizeof(command),
317 (uint8_t *)answer, sizeof(answer),
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000318 "STLINK_BRIDGE_GET_RWCMD_STATUS",
319 stlinkv3_handle) != 0)
Miklós Márton324929c2019-08-01 19:14:10 +0200320 return -1;
321
322 *status = (uint32_t)answer[2] | (uint32_t)answer[3]<<16;
323 return 0;
324}
325
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000326static int stlinkv3_spi_set_SPI_NSS(enum spi_nss_level nss_level, libusb_device_handle *stlinkv3_handle)
Miklós Márton324929c2019-08-01 19:14:10 +0200327{
328 uint8_t command[16];
329 uint8_t answer[2];
330
331 memset(command, 0, sizeof(command));
332
333 command[0] = STLINK_BRIDGE_COMMAND;
334 command[1] = STLINK_BRIDGE_CS_SPI;
335 command[2] = (uint8_t) (nss_level);
336
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000337 if (stlinkv3_command(command, sizeof(command),
338 answer, sizeof(answer),
339 "STLINK_BRIDGE_CS_SPI",
340 stlinkv3_handle) != 0)
Miklós Márton324929c2019-08-01 19:14:10 +0200341 return -1;
342 return 0;
343}
344
Edward O'Callaghane4ddc362020-04-12 17:27:53 +1000345static int stlinkv3_spi_transmit(const struct flashctx *flash,
Miklós Márton324929c2019-08-01 19:14:10 +0200346 unsigned int write_cnt,
347 unsigned int read_cnt,
348 const unsigned char *write_arr,
349 unsigned char *read_arr)
350{
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000351 struct stlinkv3_spi_data *stlinkv3_data = flash->mst->spi.data;
Anastasia Klimchukdaa86b52021-05-19 13:35:59 +1000352 libusb_device_handle *stlinkv3_handle = stlinkv3_data->handle;
Miklós Márton324929c2019-08-01 19:14:10 +0200353 uint8_t command[16];
354 int rc = 0;
355 int actual_length = 0;
356 uint32_t rw_status = 0;
Nico Huber370a9f32019-12-31 18:22:02 +0100357 unsigned int i;
Miklós Márton324929c2019-08-01 19:14:10 +0200358
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000359 if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_LOW, stlinkv3_handle)) {
Miklós Márton324929c2019-08-01 19:14:10 +0200360 msg_perr("Failed to set the NSS pin to low\n");
361 return -1;
362 }
363
364 memset(command, 0, sizeof(command));
365
366 command[0] = STLINK_BRIDGE_COMMAND;
367 command[1] = STLINK_BRIDGE_WRITE_SPI;
368 command[2] = (uint8_t)write_cnt;
369 command[3] = (uint8_t)(write_cnt >> 8);
370
Nico Huber370a9f32019-12-31 18:22:02 +0100371 for (i = 0; (i < 8) && (i < write_cnt); i++)
Miklós Márton324929c2019-08-01 19:14:10 +0200372 command[4+i] = write_arr[i];
373
374 rc = libusb_bulk_transfer(stlinkv3_handle, STLINK_EP_OUT,
375 command, sizeof(command),
376 &actual_length, USB_TIMEOUT_IN_MS);
377 if (rc != LIBUSB_TRANSFER_COMPLETED || actual_length != sizeof(command)) {
378 msg_perr("Failed to issue the STLINK_BRIDGE_WRITE_SPI command: '%s'\n",
379 libusb_error_name(rc));
380 goto transmit_err;
381 }
382
383 if (write_cnt > 8) {
384 rc = libusb_bulk_transfer(stlinkv3_handle,
385 STLINK_EP_OUT,
386 (unsigned char *)&write_arr[8],
387 (unsigned int)(write_cnt - 8),
388 &actual_length,
389 USB_TIMEOUT_IN_MS);
390 if (rc != LIBUSB_TRANSFER_COMPLETED || (unsigned int)actual_length != (write_cnt - 8)) {
391 msg_perr("Failed to send the data after the STLINK_BRIDGE_WRITE_SPI command: '%s'\n",
392 libusb_error_name(rc));
393 goto transmit_err;
394 }
395 }
396
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000397 if (stlinkv3_get_last_readwrite_status(&rw_status, stlinkv3_handle))
Miklós Márton324929c2019-08-01 19:14:10 +0200398 return -1;
399
400 if (rw_status != 0) {
401 msg_perr("SPI read/write failure: %d\n", rw_status);
402 goto transmit_err;
403 }
404
405 if (read_cnt) {
406 command[1] = STLINK_BRIDGE_READ_SPI;
407 command[2] = (uint8_t)read_cnt;
408 command[3] = (uint8_t)(read_cnt >> 8);
409
410 rc = libusb_bulk_transfer(stlinkv3_handle, STLINK_EP_OUT,
411 command, sizeof(command),
412 &actual_length, USB_TIMEOUT_IN_MS);
413 if (rc != LIBUSB_TRANSFER_COMPLETED || (unsigned int)actual_length != sizeof(command)) {
414 msg_perr("Failed to issue the STLINK_BRIDGE_READ_SPI command: '%s'\n",
415 libusb_error_name(rc));
416 goto transmit_err;
417 }
418
419 rc = libusb_bulk_transfer(stlinkv3_handle,
420 STLINK_EP_IN,
421 (unsigned char *)read_arr,
422 (int)read_cnt,
423 &actual_length,
424 USB_TIMEOUT_IN_MS);
425 if (rc != LIBUSB_TRANSFER_COMPLETED || (unsigned int)actual_length != read_cnt) {
426 msg_perr("Failed to retrive the STLINK_BRIDGE_READ_SPI answer: '%s'\n",
427 libusb_error_name(rc));
428 goto transmit_err;
429 }
430 }
431
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000432 if (stlinkv3_get_last_readwrite_status(&rw_status, stlinkv3_handle))
Miklós Márton324929c2019-08-01 19:14:10 +0200433 goto transmit_err;
434
435 if (rw_status != 0) {
436 msg_perr("SPI read/write failure: %d\n", rw_status);
437 goto transmit_err;
438 }
439
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000440 if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_HIGH, stlinkv3_handle)) {
Miklós Márton324929c2019-08-01 19:14:10 +0200441 msg_perr("Failed to set the NSS pin to high\n");
442 return -1;
443 }
444 return 0;
445
446transmit_err:
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000447 if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_HIGH, stlinkv3_handle))
Miklós Márton324929c2019-08-01 19:14:10 +0200448 msg_perr("Failed to set the NSS pin to high\n");
449 return -1;
450}
451
452static int stlinkv3_spi_shutdown(void *data)
453{
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000454 struct stlinkv3_spi_data *stlinkv3_data = data;
Miklós Márton324929c2019-08-01 19:14:10 +0200455 uint8_t command[16];
456 uint8_t answer[2];
457
458 memset(command, 0, sizeof(command));
459
460 command[0] = STLINK_BRIDGE_COMMAND;
461 command[1] = STLINK_BRIDGE_CLOSE;
462 command[2] = STLINK_SPI_COM;
463
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000464 stlinkv3_command(command, sizeof(command),
465 answer, sizeof(answer),
466 "STLINK_BRIDGE_CLOSE",
Anastasia Klimchukdaa86b52021-05-19 13:35:59 +1000467 stlinkv3_data->handle);
Miklós Márton324929c2019-08-01 19:14:10 +0200468
Anastasia Klimchukdaa86b52021-05-19 13:35:59 +1000469 libusb_close(stlinkv3_data->handle);
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000470 libusb_exit(stlinkv3_data->usb_ctx);
Miklós Márton324929c2019-08-01 19:14:10 +0200471
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000472 free(data);
Miklós Márton324929c2019-08-01 19:14:10 +0200473 return 0;
474}
475
476static const struct spi_master spi_programmer_stlinkv3 = {
477 .max_data_read = UINT16_MAX,
478 .max_data_write = UINT16_MAX,
479 .command = stlinkv3_spi_transmit,
480 .multicommand = default_spi_send_multicommand,
481 .read = default_spi_read,
482 .write_256 = default_spi_write_256,
483 .write_aai = default_spi_write_aai,
484};
485
486int stlinkv3_spi_init(void)
487{
488 uint16_t sck_freq_kHz = 1000; // selecting 1 MHz SCK is a good bet
489 char *speed_str = NULL;
490 char *serialno = NULL;
491 char *endptr = NULL;
Anastasia Klimchukcee470e2021-05-14 14:01:34 +1000492 int ret = 1;
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000493 struct libusb_context *usb_ctx;
494 libusb_device_handle *stlinkv3_handle;
495 struct stlinkv3_spi_data *stlinkv3_data;
Miklós Márton324929c2019-08-01 19:14:10 +0200496
497 libusb_init(&usb_ctx);
498 if (!usb_ctx) {
499 msg_perr("Could not initialize libusb!\n");
500 return 1;
501 }
502
503 serialno = extract_programmer_param("serial");
504 if (serialno)
505 msg_pdbg("Opening STLINK-V3 with serial: %s\n", serialno);
506 stlinkv3_handle = usb_dev_get_by_vid_pid_serial(usb_ctx,
507 devs_stlinkv3_spi[0].vendor_id,
508 devs_stlinkv3_spi[0].device_id,
509 serialno);
510
511 if (!stlinkv3_handle) {
512 if (serialno)
513 msg_perr("No STLINK-V3 seems to be connected with serial %s\n", serialno);
514 else
515 msg_perr("Could not find any connected STLINK-V3\n");
516 free(serialno);
Anastasia Klimchukcee470e2021-05-14 14:01:34 +1000517 goto init_err_exit;
Miklós Márton324929c2019-08-01 19:14:10 +0200518 }
519 free(serialno);
520
521 speed_str = extract_programmer_param("spispeed");
522 if (speed_str) {
523 sck_freq_kHz = strtoul(speed_str, &endptr, 0);
Patrick Georgi552e60e2020-04-23 09:36:12 +0200524 if (*endptr || sck_freq_kHz == 0) {
Miklós Márton324929c2019-08-01 19:14:10 +0200525 msg_perr("The spispeed parameter passed with invalid format: %s\n",
526 speed_str);
Patrick Georgi552e60e2020-04-23 09:36:12 +0200527 msg_perr("Please pass the parameter "
528 "with a simple non-zero number in kHz\n");
Patrick Georgi969e1dd2020-04-23 09:35:06 +0200529 free(speed_str);
Anastasia Klimchukcee470e2021-05-14 14:01:34 +1000530 ret = -1;
531 goto init_err_exit;
Miklós Márton324929c2019-08-01 19:14:10 +0200532 }
533 free(speed_str);
534 }
535
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000536 if (stlinkv3_spi_open(sck_freq_kHz, stlinkv3_handle))
Anastasia Klimchukcee470e2021-05-14 14:01:34 +1000537 goto init_err_exit;
Miklós Márton324929c2019-08-01 19:14:10 +0200538
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000539 stlinkv3_data = calloc(1, sizeof(*stlinkv3_data));
540 if (!stlinkv3_data) {
541 msg_perr("Unable to allocate space for SPI master data\n");
542 goto init_err_exit;
543 }
544
545 stlinkv3_data->usb_ctx = usb_ctx;
Anastasia Klimchukdaa86b52021-05-19 13:35:59 +1000546 stlinkv3_data->handle = stlinkv3_handle;
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000547
548 if (register_shutdown(stlinkv3_spi_shutdown, stlinkv3_data))
Anastasia Klimchukcee470e2021-05-14 14:01:34 +1000549 goto init_err_cleanup_exit;
Miklós Márton324929c2019-08-01 19:14:10 +0200550
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000551 if (register_spi_master(&spi_programmer_stlinkv3, stlinkv3_data))
Anastasia Klimchukcee470e2021-05-14 14:01:34 +1000552 return 1; /* shutdown function does cleanup */
Miklós Márton324929c2019-08-01 19:14:10 +0200553
554 return 0;
555
Anastasia Klimchukcee470e2021-05-14 14:01:34 +1000556init_err_cleanup_exit:
Anastasia Klimchuk7becf172021-05-19 14:32:04 +1000557 stlinkv3_spi_shutdown(stlinkv3_data);
Miklós Márton324929c2019-08-01 19:14:10 +0200558 return 1;
Anastasia Klimchukcee470e2021-05-14 14:01:34 +1000559
560init_err_exit:
561 if (stlinkv3_handle)
562 libusb_close(stlinkv3_handle);
563 libusb_exit(usb_ctx);
564 return ret;
Miklós Márton324929c2019-08-01 19:14:10 +0200565}