+// SPDX-License-Identifier: GPL-2.0-or-later
+
/***************************************************************************
* Copyright (C) 2016-2017 by Nuvoton *
* Zale Yu <cyyu@nuvoton.com> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
/* project specific includes */
#include <helper/binarybuffer.h>
+#include <jtag/adapter.h>
#include <jtag/interface.h>
#include <jtag/hla/hla_layout.h>
#include <jtag/hla/hla_transport.h>
#include <hidapi.h>
-#define NULINK_READ_TIMEOUT 1000
+#include "libusb_helper.h"
+
+#define NULINK_READ_TIMEOUT LIBUSB_TIMEOUT_MS
#define NULINK_HID_MAX_SIZE (64)
+#define NULINK2_HID_MAX_SIZE (1024)
#define V6M_MAX_COMMAND_LENGTH (NULINK_HID_MAX_SIZE - 2)
+#define V7M_MAX_COMMAND_LENGTH (NULINK_HID_MAX_SIZE - 3)
+
+#define NULINK2_USB_PID1 (0x5200)
+#define NULINK2_USB_PID2 (0x5201)
struct nulink_usb_handle_s {
hid_device *dev_handle;
uint16_t max_packet_size;
uint8_t usbcmdidx;
uint8_t cmdidx;
- uint8_t cmdbuf[NULINK_HID_MAX_SIZE + 1];
- uint8_t tempbuf[NULINK_HID_MAX_SIZE];
- uint8_t databuf[NULINK_HID_MAX_SIZE];
+ uint8_t cmdsize;
+ uint8_t cmdbuf[NULINK2_HID_MAX_SIZE + 1];
+ uint8_t tempbuf[NULINK2_HID_MAX_SIZE];
+ uint8_t databuf[NULINK2_HID_MAX_SIZE];
uint32_t max_mem_packet;
uint16_t hardware_config; /* bit 0: 1:Nu-Link-Pro, 0:Nu-Link */
+
+ int (*xfer)(void *handle, uint8_t *buf, int size);
+ void (*init_buffer)(void *handle, uint32_t size);
};
/* ICE Command */
#define ARM_SRAM_BASE 0x20000000UL
#define HARDWARE_CONFIG_NULINKPRO 1
+#define HARDWARE_CONFIG_NULINK2 2
enum nulink_reset {
RESET_AUTO = 0,
return ERROR_OK;
}
-static int nulink_usb_xfer(void *handle, uint8_t *buf, int size)
+static int nulink1_usb_xfer(void *handle, uint8_t *buf, int size)
{
struct nulink_usb_handle_s *h = handle;
return err;
}
-static void nulink_usb_init_buffer(void *handle, uint32_t size)
+static int nulink2_usb_xfer(void *handle, uint8_t *buf, int size)
+{
+ struct nulink_usb_handle_s *h = handle;
+
+ assert(handle);
+
+ int err = nulink_usb_xfer_rw(h, h->tempbuf);
+
+ memcpy(buf, h->tempbuf + 3, V7M_MAX_COMMAND_LENGTH);
+
+ return err;
+}
+
+static void nulink1_usb_init_buffer(void *handle, uint32_t size)
{
struct nulink_usb_handle_s *h = handle;
h->cmdidx += 3;
}
+static void nulink2_usb_init_buffer(void *handle, uint32_t size)
+{
+ struct nulink_usb_handle_s *h = handle;
+
+ h->cmdidx = 0;
+
+ memset(h->cmdbuf, 0, h->max_packet_size + 1);
+ memset(h->tempbuf, 0, h->max_packet_size);
+ memset(h->databuf, 0, h->max_packet_size);
+
+ h->cmdbuf[0] = 0; /* report number */
+ h->cmdbuf[1] = ++h->usbcmdidx & 0x7F;
+ h_u16_to_le(h->cmdbuf + 2, size);
+ h->cmdidx += 4;
+}
+
+static inline int nulink_usb_xfer(void *handle, uint8_t *buf, int size)
+{
+ struct nulink_usb_handle_s *h = handle;
+
+ assert(handle);
+
+ return h->xfer(handle, buf, size);
+}
+
+static inline void nulink_usb_init_buffer(void *handle, uint32_t size)
+{
+ struct nulink_usb_handle_s *h = handle;
+
+ assert(handle);
+
+ h->init_buffer(handle, size);
+}
+
static int nulink_usb_version(void *handle)
{
struct nulink_usb_handle_s *h = handle;
h->cmdbuf[h->cmdidx + 4] = 0xA1; /* host_rev_num: 6561 */;
h->cmdbuf[h->cmdidx + 5] = 0x19;
- int res = nulink_usb_xfer(handle, h->databuf, 4 * 5);
+ int res = nulink_usb_xfer(handle, h->databuf, h->cmdsize);
if (res != ERROR_OK)
return res;
{
struct nulink_usb_handle_s *h = handle;
- LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 "0x%08" PRIX32, addr, val);
+ LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 " 0x%08" PRIX32, addr, val);
nulink_usb_init_buffer(handle, 8 + 12 * 1);
/* set command ID */
return res;
}
-static int nulink_usb_read_reg(void *handle, int num, uint32_t *val)
+static int nulink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
{
struct nulink_usb_handle_s *h = handle;
h->cmdbuf[h->cmdidx] = 0;
h->cmdidx += 1;
/* u32Addr */
- h_u32_to_le(h->cmdbuf + h->cmdidx, num);
+ h_u32_to_le(h->cmdbuf + h->cmdidx, regsel);
h->cmdidx += 4;
/* u32Data */
h_u32_to_le(h->cmdbuf + h->cmdidx, 0);
return res;
}
-static int nulink_usb_write_reg(void *handle, int num, uint32_t val)
+static int nulink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
{
struct nulink_usb_handle_s *h = handle;
h->cmdbuf[h->cmdidx] = 0;
h->cmdidx += 1;
/* u32Addr */
- h_u32_to_le(h->cmdbuf + h->cmdidx, num);
+ h_u32_to_le(h->cmdbuf + h->cmdidx, regsel);
h->cmdidx += 4;
/* u32Data */
h_u32_to_le(h->cmdbuf + h->cmdidx, val);
aligned_addr = aligned_addr * 4;
offset = addr - aligned_addr;
LOG_DEBUG("nulink_usb_read_mem8: unaligned address addr 0x%08" PRIx32
- "/aligned addr 0x%08" PRIx32 "offset %" PRIu32,
+ "/aligned addr 0x%08" PRIx32 " offset %" PRIu32,
addr, aligned_addr, offset);
addr = aligned_addr;
/* the nulink only supports 8/32bit memory read/writes
* honour 32bit, all others will be handled as 8bit access */
if (size == 4) {
- /* When in jtag mode the nulink uses the auto-increment functinality.
+ /* When in jtag mode the nulink uses the auto-increment functionality.
* However it expects us to pass the data correctly, this includes
* alignment and any page boundaries. We already do this as part of the
* adi_v5 implementation, but the nulink is a hla adapter and so this
- * needs implementiong manually.
+ * needs implementing manually.
* currently this only affects jtag mode, they do single
* access in SWD mode - but this may change and so we do it for both modes */
/* the nulink only supports 8/32bit memory read/writes
* honour 32bit, all others will be handled as 8bit access */
if (size == 4) {
- /* When in jtag mode the nulink uses the auto-increment functinality.
+ /* When in jtag mode the nulink uses the auto-increment functionality.
* However it expects us to pass the data correctly, this includes
* alignment and any page boundaries. We already do this as part of the
* adi_v5 implementation, but the nulink is a hla adapter and so this
- * needs implementiong manually.
+ * needs implementing manually.
* currently this only affects jtag mode, do single
* access in SWD mode - but this may change and so we do it for both modes */
goto error_open;
}
- if (param->serial) {
- size_t len = mbstowcs(NULL, param->serial, 0);
+ const char *serial = adapter_get_required_serial();
+ if (serial) {
+ size_t len = mbstowcs(NULL, serial, 0);
target_serial = calloc(len + 1, sizeof(wchar_t));
if (!target_serial) {
goto error_open;
}
- if (mbstowcs(target_serial, param->serial, len + 1) == (size_t)(-1)) {
+ if (mbstowcs(target_serial, serial, len + 1) == (size_t)(-1)) {
LOG_WARNING("unable to convert serial");
free(target_serial);
target_serial = NULL;
h->dev_handle = dev;
h->usbcmdidx = 0;
- h->hardware_config = 0;
- h->max_packet_size = NULINK_HID_MAX_SIZE;
+
+ switch (target_pid) {
+ case NULINK2_USB_PID1:
+ case NULINK2_USB_PID2:
+ h->hardware_config = HARDWARE_CONFIG_NULINK2;
+ h->max_packet_size = NULINK2_HID_MAX_SIZE;
+ h->init_buffer = nulink2_usb_init_buffer;
+ h->xfer = nulink2_usb_xfer;
+ break;
+ default:
+ h->hardware_config = 0;
+ h->max_packet_size = NULINK_HID_MAX_SIZE;
+ h->init_buffer = nulink1_usb_init_buffer;
+ h->xfer = nulink1_usb_xfer;
+ break;
+ }
/* get the device version */
+ h->cmdsize = 4 * 5;
int err = nulink_usb_version(h);
- if (err != ERROR_OK)
- goto error_open;
+ if (err != ERROR_OK) {
+ LOG_DEBUG("nulink_usb_version failed with cmdSize(4 * 5)");
+ h->cmdsize = 4 * 6;
+ err = nulink_usb_version(h);
+ if (err != ERROR_OK)
+ LOG_DEBUG("nulink_usb_version failed with cmdSize(4 * 6)");
+ }
/* SWD clock rate : 1MHz */
nulink_speed(h, 1000, false);