2022-06-26 23:06:45 +00:00
|
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
|
|
2013-11-03 16:31:44 +00:00
|
|
|
|
/*
|
|
|
|
|
* Driver for USB-JTAG, Altera USB-Blaster II and compatibles
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2013 Franck Jullien franck.jullien@gmail.com
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <jtag/interface.h>
|
|
|
|
|
#include <jtag/commands.h>
|
2021-04-19 20:04:30 +00:00
|
|
|
|
#include "helper/system.h"
|
2020-02-05 15:07:48 +00:00
|
|
|
|
#include <libusb_helper.h>
|
2013-11-03 16:31:44 +00:00
|
|
|
|
#include <target/image.h>
|
|
|
|
|
|
|
|
|
|
#include "ublast_access.h"
|
|
|
|
|
|
|
|
|
|
#define USBBLASTER_CTRL_READ_REV 0x94
|
|
|
|
|
#define USBBLASTER_CTRL_LOAD_FIRM 0xA0
|
|
|
|
|
#define USBBLASTER_EPOUT 4
|
|
|
|
|
#define USBBLASTER_EPIN 8
|
|
|
|
|
|
|
|
|
|
#define EZUSB_CPUCS 0xe600
|
|
|
|
|
#define CPU_RESET 1
|
|
|
|
|
|
|
|
|
|
/** Maximum size of a single firmware section. Entire EZ-USB code space = 16kB */
|
|
|
|
|
#define SECTION_BUFFERSIZE 16384
|
|
|
|
|
|
|
|
|
|
static int ublast2_libusb_read(struct ublast_lowlevel *low, uint8_t *buf,
|
|
|
|
|
unsigned size, uint32_t *bytes_read)
|
|
|
|
|
{
|
2018-07-05 11:42:14 +00:00
|
|
|
|
int ret, tmp = 0;
|
|
|
|
|
|
|
|
|
|
ret = jtag_libusb_bulk_read(low->libusb_dev,
|
2019-05-05 23:03:52 +00:00
|
|
|
|
USBBLASTER_EPIN |
|
2013-11-03 16:31:44 +00:00
|
|
|
|
LIBUSB_ENDPOINT_IN,
|
|
|
|
|
(char *)buf,
|
|
|
|
|
size,
|
2018-07-05 11:42:14 +00:00
|
|
|
|
100, &tmp);
|
|
|
|
|
*bytes_read = tmp;
|
|
|
|
|
|
|
|
|
|
return ret;
|
2013-11-03 16:31:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ublast2_libusb_write(struct ublast_lowlevel *low, uint8_t *buf,
|
|
|
|
|
int size, uint32_t *bytes_written)
|
|
|
|
|
{
|
2018-07-05 11:42:14 +00:00
|
|
|
|
int ret, tmp = 0;
|
|
|
|
|
|
|
|
|
|
ret = jtag_libusb_bulk_write(low->libusb_dev,
|
2019-05-05 23:03:52 +00:00
|
|
|
|
USBBLASTER_EPOUT |
|
2013-11-03 16:31:44 +00:00
|
|
|
|
LIBUSB_ENDPOINT_OUT,
|
|
|
|
|
(char *)buf,
|
|
|
|
|
size,
|
2018-07-05 11:42:14 +00:00
|
|
|
|
100, &tmp);
|
|
|
|
|
*bytes_written = tmp;
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
2013-11-03 16:31:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-05 14:50:31 +00:00
|
|
|
|
static int ublast2_write_firmware_section(struct libusb_device_handle *libusb_dev,
|
2013-11-03 16:31:44 +00:00
|
|
|
|
struct image *firmware_image, int section_index)
|
|
|
|
|
{
|
|
|
|
|
uint16_t chunk_size;
|
|
|
|
|
uint8_t data[SECTION_BUFFERSIZE];
|
|
|
|
|
uint8_t *data_ptr = data;
|
|
|
|
|
size_t size_read;
|
|
|
|
|
|
|
|
|
|
uint16_t size = (uint16_t)firmware_image->sections[section_index].size;
|
|
|
|
|
uint16_t addr = (uint16_t)firmware_image->sections[section_index].base_address;
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04x)", section_index, addr,
|
|
|
|
|
size);
|
|
|
|
|
|
|
|
|
|
/* Copy section contents to local buffer */
|
|
|
|
|
int ret = image_read_section(firmware_image, section_index, 0, size, data,
|
|
|
|
|
&size_read);
|
|
|
|
|
|
|
|
|
|
if ((ret != ERROR_OK) || (size_read != size)) {
|
|
|
|
|
/* Propagating the return code would return '0' (misleadingly indicating
|
|
|
|
|
* successful execution of the function) if only the size check fails. */
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t bytes_remaining = size;
|
|
|
|
|
|
|
|
|
|
/* Send section data in chunks of up to 64 bytes to ULINK */
|
|
|
|
|
while (bytes_remaining > 0) {
|
|
|
|
|
if (bytes_remaining > 64)
|
|
|
|
|
chunk_size = 64;
|
|
|
|
|
else
|
|
|
|
|
chunk_size = bytes_remaining;
|
|
|
|
|
|
|
|
|
|
jtag_libusb_control_transfer(libusb_dev,
|
2019-05-05 23:03:52 +00:00
|
|
|
|
LIBUSB_REQUEST_TYPE_VENDOR |
|
2013-11-03 16:31:44 +00:00
|
|
|
|
LIBUSB_ENDPOINT_OUT,
|
|
|
|
|
USBBLASTER_CTRL_LOAD_FIRM,
|
|
|
|
|
addr,
|
|
|
|
|
0,
|
|
|
|
|
(char *)data_ptr,
|
|
|
|
|
chunk_size,
|
|
|
|
|
100);
|
|
|
|
|
|
|
|
|
|
bytes_remaining -= chunk_size;
|
|
|
|
|
addr += chunk_size;
|
|
|
|
|
data_ptr += chunk_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-05 14:50:31 +00:00
|
|
|
|
static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev,
|
2013-11-03 16:31:44 +00:00
|
|
|
|
struct ublast_lowlevel *low)
|
|
|
|
|
{
|
|
|
|
|
struct image ublast2_firmware_image;
|
|
|
|
|
|
|
|
|
|
if (!low->firmware_path) {
|
|
|
|
|
LOG_ERROR("No firmware path specified");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-12 12:51:54 +00:00
|
|
|
|
if (libusb_claim_interface(libusb_dev, 0)) {
|
|
|
|
|
LOG_ERROR("unable to claim interface");
|
|
|
|
|
return ERROR_JTAG_INIT_FAILED;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-03 16:31:44 +00:00
|
|
|
|
ublast2_firmware_image.base_address = 0;
|
2020-11-03 15:11:48 +00:00
|
|
|
|
ublast2_firmware_image.base_address_set = false;
|
2013-11-03 16:31:44 +00:00
|
|
|
|
|
|
|
|
|
int ret = image_open(&ublast2_firmware_image, low->firmware_path, "ihex");
|
|
|
|
|
if (ret != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("Could not load firmware image");
|
2021-03-18 17:47:35 +00:00
|
|
|
|
goto error_release_usb;
|
2013-11-03 16:31:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** A host loader program must write 0x01 to the CPUCS register
|
|
|
|
|
* to put the CPU into RESET, load all or part of the EZUSB
|
|
|
|
|
* RAM with firmware, then reload the CPUCS register
|
|
|
|
|
* with ‘0’ to take the CPU out of RESET. The CPUCS register
|
|
|
|
|
* (at 0xE600) is the only EZ-USB register that can be written
|
|
|
|
|
* using the Firmware Download command.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char value = CPU_RESET;
|
|
|
|
|
jtag_libusb_control_transfer(libusb_dev,
|
2019-05-05 23:03:52 +00:00
|
|
|
|
LIBUSB_REQUEST_TYPE_VENDOR |
|
2013-11-03 16:31:44 +00:00
|
|
|
|
LIBUSB_ENDPOINT_OUT,
|
|
|
|
|
USBBLASTER_CTRL_LOAD_FIRM,
|
|
|
|
|
EZUSB_CPUCS,
|
|
|
|
|
0,
|
|
|
|
|
&value,
|
|
|
|
|
1,
|
|
|
|
|
100);
|
|
|
|
|
|
|
|
|
|
/* Download all sections in the image to ULINK */
|
2020-11-03 15:11:48 +00:00
|
|
|
|
for (unsigned int i = 0; i < ublast2_firmware_image.num_sections; i++) {
|
2013-11-03 16:31:44 +00:00
|
|
|
|
ret = ublast2_write_firmware_section(libusb_dev,
|
|
|
|
|
&ublast2_firmware_image, i);
|
|
|
|
|
if (ret != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("Error while downloading the firmware");
|
2021-03-18 17:47:35 +00:00
|
|
|
|
goto error_close_firmware;
|
2013-11-03 16:31:44 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = !CPU_RESET;
|
|
|
|
|
jtag_libusb_control_transfer(libusb_dev,
|
2019-05-05 23:03:52 +00:00
|
|
|
|
LIBUSB_REQUEST_TYPE_VENDOR |
|
2013-11-03 16:31:44 +00:00
|
|
|
|
LIBUSB_ENDPOINT_OUT,
|
|
|
|
|
USBBLASTER_CTRL_LOAD_FIRM,
|
|
|
|
|
EZUSB_CPUCS,
|
|
|
|
|
0,
|
|
|
|
|
&value,
|
|
|
|
|
1,
|
|
|
|
|
100);
|
|
|
|
|
|
2021-03-18 17:47:35 +00:00
|
|
|
|
error_close_firmware:
|
2013-11-03 16:31:44 +00:00
|
|
|
|
image_close(&ublast2_firmware_image);
|
|
|
|
|
|
2021-03-18 17:47:35 +00:00
|
|
|
|
error_release_usb:
|
2019-02-12 12:51:54 +00:00
|
|
|
|
/*
|
|
|
|
|
* Release claimed interface. Most probably it is already disconnected
|
|
|
|
|
* and re-enumerated as new devices after firmware upload, so we do
|
|
|
|
|
* not need to care about errors.
|
|
|
|
|
*/
|
|
|
|
|
libusb_release_interface(libusb_dev, 0);
|
|
|
|
|
|
2021-03-18 17:47:35 +00:00
|
|
|
|
return ret;
|
2013-11-03 16:31:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ublast2_libusb_init(struct ublast_lowlevel *low)
|
|
|
|
|
{
|
|
|
|
|
const uint16_t vids[] = { low->ublast_vid_uninit, 0 };
|
|
|
|
|
const uint16_t pids[] = { low->ublast_pid_uninit, 0 };
|
2020-02-05 14:50:31 +00:00
|
|
|
|
struct libusb_device_handle *temp;
|
2013-11-03 16:31:44 +00:00
|
|
|
|
bool renumeration = false;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2021-10-19 11:09:25 +00:00
|
|
|
|
if (jtag_libusb_open(vids, pids, &temp, NULL) == ERROR_OK) {
|
2013-11-03 16:31:44 +00:00
|
|
|
|
LOG_INFO("Altera USB-Blaster II (uninitialized) found");
|
|
|
|
|
LOG_INFO("Loading firmware...");
|
|
|
|
|
ret = load_usb_blaster_firmware(temp, low);
|
|
|
|
|
jtag_libusb_close(temp);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
renumeration = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const uint16_t vids_renum[] = { low->ublast_vid, 0 };
|
|
|
|
|
const uint16_t pids_renum[] = { low->ublast_pid, 0 };
|
|
|
|
|
|
|
|
|
|
if (renumeration == false) {
|
2021-10-19 11:09:25 +00:00
|
|
|
|
if (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK) {
|
2013-11-03 16:31:44 +00:00
|
|
|
|
LOG_ERROR("Altera USB-Blaster II not found");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
int retry = 10;
|
2021-10-19 11:09:25 +00:00
|
|
|
|
while (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK && retry--) {
|
2013-11-03 16:31:44 +00:00
|
|
|
|
usleep(1000000);
|
2020-07-12 21:40:41 +00:00
|
|
|
|
LOG_INFO("Waiting for reenumerate...");
|
2013-11-03 16:31:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!retry) {
|
|
|
|
|
LOG_ERROR("Altera USB-Blaster II not found");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-12 12:51:54 +00:00
|
|
|
|
if (libusb_claim_interface(low->libusb_dev, 0)) {
|
|
|
|
|
LOG_ERROR("unable to claim interface");
|
|
|
|
|
jtag_libusb_close(low->libusb_dev);
|
|
|
|
|
return ERROR_JTAG_INIT_FAILED;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-03 16:31:44 +00:00
|
|
|
|
char buffer[5];
|
|
|
|
|
jtag_libusb_control_transfer(low->libusb_dev,
|
2019-05-05 23:03:52 +00:00
|
|
|
|
LIBUSB_REQUEST_TYPE_VENDOR |
|
2013-11-03 16:31:44 +00:00
|
|
|
|
LIBUSB_ENDPOINT_IN,
|
|
|
|
|
USBBLASTER_CTRL_READ_REV,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
buffer,
|
|
|
|
|
5,
|
|
|
|
|
100);
|
|
|
|
|
|
|
|
|
|
LOG_INFO("Altera USB-Blaster II found (Firm. rev. = %s)", buffer);
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ublast2_libusb_quit(struct ublast_lowlevel *low)
|
|
|
|
|
{
|
2019-02-12 12:51:54 +00:00
|
|
|
|
if (libusb_release_interface(low->libusb_dev, 0))
|
|
|
|
|
LOG_ERROR("usb release interface failed");
|
|
|
|
|
|
2013-11-03 16:31:44 +00:00
|
|
|
|
jtag_libusb_close(low->libusb_dev);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct ublast_lowlevel low = {
|
|
|
|
|
.open = ublast2_libusb_init,
|
|
|
|
|
.close = ublast2_libusb_quit,
|
|
|
|
|
.read = ublast2_libusb_read,
|
|
|
|
|
.write = ublast2_libusb_write,
|
|
|
|
|
.flags = COPY_TDO_BUFFER,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ublast_lowlevel *ublast2_register_libusb(void)
|
|
|
|
|
{
|
|
|
|
|
return &low;
|
|
|
|
|
}
|