jtag/hla, jtag/stlink: switch to command 'adapter serial'
[fw/openocd] / src / jtag / drivers / nulink_usb.c
index 3b0885b7a9709025a210d5a98943fee5e0c0ddcb..d4b8b53bc5eed382f70000c8cdb61a2a7ab3aeaa 100644 (file)
@@ -22,6 +22,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>
 #define NULINK_READ_TIMEOUT  1000
 
 #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 +75,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 +114,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 +127,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 +156,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 +204,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 +254,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 +412,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 +435,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 +451,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 +474,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 +504,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 +845,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 +910,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 +1055,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 +1065,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 +1113,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);