jtag/drivers/bcm2835gpio: fix bcm2835_peri_base output format
[openocd.git] / src / jtag / drivers / nulink_usb.c
index 3b0885b7a9709025a210d5a98943fee5e0c0ddcb..4fdb85782787d3a9b80dd5d963bde94fdbafa9ad 100644 (file)
@@ -1,19 +1,8 @@
+// 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
@@ -22,6 +11,7 @@
 
 /* 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 */
@@ -65,6 +66,7 @@ struct nulink_usb_handle_s {
 #define ARM_SRAM_BASE                          0x20000000UL
 
 #define HARDWARE_CONFIG_NULINKPRO      1
+#define HARDWARE_CONFIG_NULINK2                2
 
 enum nulink_reset {
        RESET_AUTO = 0,
@@ -103,7 +105,7 @@ static int nulink_usb_xfer_rw(void *handle, uint8_t *buf)
        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;
 
@@ -116,7 +118,20 @@ static int nulink_usb_xfer(void *handle, uint8_t *buf, int size)
        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;
 
@@ -132,6 +147,40 @@ static void nulink_usb_init_buffer(void *handle, uint32_t size)
        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;
@@ -146,7 +195,7 @@ static int nulink_usb_version(void *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;
 
@@ -196,7 +245,7 @@ static int nulink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
 {
        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 */
@@ -354,7 +403,7 @@ static int nulink_usb_step(void *handle)
        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;
 
@@ -377,7 +426,7 @@ static int nulink_usb_read_reg(void *handle, int num, uint32_t *val)
        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);
@@ -393,7 +442,7 @@ static int nulink_usb_read_reg(void *handle, int num, uint32_t *val)
        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;
 
@@ -416,7 +465,7 @@ static int nulink_usb_write_reg(void *handle, int num, uint32_t val)
        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);
@@ -446,7 +495,7 @@ static int nulink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
                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;
@@ -787,11 +836,11 @@ static int nulink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
                /* 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 */
 
@@ -852,11 +901,11 @@ static int nulink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
                /* 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 */
 
@@ -997,8 +1046,9 @@ static int nulink_usb_open(struct hl_interface_param_s *param, void **fd)
                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) {
@@ -1006,7 +1056,7 @@ static int nulink_usb_open(struct hl_interface_param_s *param, void **fd)
                        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;
@@ -1054,13 +1104,33 @@ static int nulink_usb_open(struct hl_interface_param_s *param, void **fd)
 
        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);

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)