]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/sysclk-lwla/lwla1034.c
Drop unneeded std_session_send_df_header() comments.
[libsigrok.git] / src / hardware / sysclk-lwla / lwla1034.c
index baf3d1e94b2621733cc99395c08a62dea51283b8..14692c38c618a58bac0f08b779cee3c2d5a93557 100644 (file)
@@ -39,7 +39,7 @@
 
 /* Capture memory read start address.
  */
-#define READ_START_ADDR                4
+#define READ_START_ADDR        4
 
 /* Number of device memory units (36 bit) to read at a time. Slices of 8
  * consecutive 36-bit words are mapped to 9 32-bit words each, so the chunk
  * a time. So far, it appears safe to increase this to 224 words (28 slices,
  * 1008 bytes), thus making the most of two 512 byte buffers.
  */
-#define READ_CHUNK_LEN36       (28 * 8)
+#define READ_CHUNK_LEN (28 * 8)
 
-/* Bit mask for the RLE repeat-count-follows flag. */
+/* Bit mask for the RLE repeat-count-follows flag.
+ */
 #define RLE_FLAG_LEN_FOLLOWS   (UINT64_C(1) << 35)
 
+/* Start index and count for bulk long register reads.
+ * The first five long registers do not return useful values when read,
+ * so skip over them to reduce the transfer size of status poll responses.
+ */
+#define READ_LREGS_START       LREG_MEM_FILL
+#define READ_LREGS_COUNT       (LREG_STATUS + 1 - READ_LREGS_START)
+
 /** LWLA1034 register addresses.
  */
 enum reg_addr {
@@ -185,8 +193,8 @@ static inline uint64_t bulk_long_get(const struct acquisition_state *acq,
 {
        uint64_t low, high;
 
-       low  = LWLA_TO_UINT32(acq->xfer_buf_in[2 * idx]);
-       high = LWLA_TO_UINT32(acq->xfer_buf_in[2 * idx + 1]);
+       low  = LWLA_TO_UINT32(acq->xfer_buf_in[2 * (idx - READ_LREGS_START)]);
+       high = LWLA_TO_UINT32(acq->xfer_buf_in[2 * (idx - READ_LREGS_START) + 1]);
 
        return (high << 32) | low;
 }
@@ -200,9 +208,7 @@ static void read_response(struct acquisition_state *acq)
        uint64_t sample, high_nibbles, word;
        uint32_t *slice;
        uint8_t *out_p;
-       unsigned int words_left;
-       unsigned int max_samples, run_samples;
-       unsigned int wi, ri, si;
+       unsigned int words_left, max_samples, run_samples, wi, ri, si;
 
        /* Number of 36-bit words remaining in the transfer buffer. */
        words_left = MIN(acq->mem_addr_next, acq->mem_addr_stop)
@@ -231,13 +237,13 @@ static void read_response(struct acquisition_state *acq)
                acq->samples_done += run_samples;
 
                if (run_samples == max_samples)
-                       break; /* packet full or sample limit reached */
+                       break; /* Packet full or sample limit reached. */
                if (wi >= words_left)
-                       break; /* done with current transfer */
+                       break; /* Done with current transfer. */
 
                /* Get the current slice of 8 packed 36-bit words. */
                slice = &acq->xfer_buf_in[(acq->in_index + wi) / 8 * 9];
-               si = (acq->in_index + wi) % 8; /* word index within slice */
+               si = (acq->in_index + wi) % 8; /* Word index within slice. */
 
                /* Extract the next 36-bit word. */
                high_nibbles = LWLA_TO_UINT32(slice[8]);
@@ -254,18 +260,70 @@ static void read_response(struct acquisition_state *acq)
                        acq->rle = RLE_STATE_DATA;
                }
        }
+
        acq->in_index += wi;
        acq->mem_addr_done += wi;
 }
 
+/* Check whether we can receive responses of more than 64 bytes.
+ * The FX2 firmware of the LWLA1034 has a bug in the reset logic which
+ * sometimes causes the response endpoint to be limited to transfers of
+ * 64 bytes at a time, instead of the expected 2*512 bytes. The problem
+ * can be worked around by never requesting more than 64 bytes.
+ * This quirk manifests itself only under certain conditions, and some
+ * users seem to see it more frequently than others. Detect it here in
+ * order to avoid paying the penalty unnecessarily.
+ */
+static int detect_short_transfer_quirk(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_usb_dev_inst *usb;
+       int xfer_len, ret;
+       uint16_t command[3];
+       unsigned char buf[512];
+       const int lreg_count = 10;
+
+       devc = sdi->priv;
+       usb  = sdi->conn;
+
+       command[0] = LWLA_WORD(CMD_READ_LREGS);
+       command[1] = LWLA_WORD(0);
+       command[2] = LWLA_WORD(lreg_count);
+
+       ret = lwla_send_command(usb, command, ARRAY_SIZE(command));
+       if (ret != SR_OK)
+               return ret;
+
+       ret = lwla_receive_reply(usb, buf, sizeof(buf), &xfer_len);
+       if (ret != SR_OK)
+               return ret;
+
+       devc->short_transfer_quirk = (xfer_len == 64);
+
+       if (xfer_len == 8 * lreg_count)
+               return SR_OK;
+
+       if (xfer_len == 64) {
+               /* Drain the tailing portion of the split transfer. */
+               ret = lwla_receive_reply(usb, buf, sizeof(buf), &xfer_len);
+               if (ret != SR_OK)
+                       return ret;
+
+               if (xfer_len == 8 * lreg_count - 64)
+                       return SR_OK;
+       }
+       sr_err("Received response of unexpected length %d.", xfer_len);
+
+       return SR_ERR;
+}
+
 /* Select and transfer FPGA bitstream for the current configuration.
  */
 static int apply_fpga_config(const struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
        struct drv_context *drvc;
-       int config;
-       int ret;
+       int config, ret;
 
        devc = sdi->priv;
        drvc = sdi->driver->context;
@@ -280,7 +338,7 @@ static int apply_fpga_config(const struct sr_dev_inst *sdi)
                config = FPGA_EXTNEG;
 
        if (config == devc->active_fpga_config)
-               return SR_OK; /* no change */
+               return SR_OK; /* No change. */
 
        ret = lwla_send_bitstream(drvc->sr_ctx, sdi->conn,
                                  bitstream_map[config]);
@@ -296,9 +354,7 @@ static int device_init_check(const struct sr_dev_inst *sdi)
        uint64_t value;
        int ret;
 
-       ret = read_long_reg(sdi->conn, LREG_TEST_ID, &value);
-       if (ret != SR_OK)
-               return ret;
+       read_long_reg(sdi->conn, LREG_TEST_ID, &value);
 
        /* Ignore the value returned by the first read. */
        ret = read_long_reg(sdi->conn, LREG_TEST_ID, &value);
@@ -309,15 +365,24 @@ static int device_init_check(const struct sr_dev_inst *sdi)
                sr_err("Received invalid test word 0x%016" PRIX64 ".", value);
                return SR_ERR;
        }
-       return SR_OK;
+
+       return detect_short_transfer_quirk(sdi);
 }
 
 /* Set up the device in preparation for an acquisition session.
  */
 static int setup_acquisition(const struct sr_dev_inst *sdi)
 {
-       uint64_t divider_count;
-       uint64_t trigger_mask;
+       static const struct regval capture_init[] = {
+               {REG_MEM_CTRL,    MEM_CTRL_CLR_IDX},
+               {REG_MEM_CTRL,    MEM_CTRL_WRITE},
+               {REG_LONG_ADDR,   LREG_CAP_CTRL},
+               {REG_LONG_LOW,    CAP_CTRL_CLR_TIMEBASE | CAP_CTRL_FLUSH_FIFO |
+                                 CAP_CTRL_CLR_FIFOFULL | CAP_CTRL_CLR_COUNTER},
+               {REG_LONG_HIGH,   0},
+               {REG_LONG_STROBE, 0},
+       };
+       uint64_t divider_count, trigger_mask;
        struct dev_context *devc;
        struct sr_usb_dev_inst *usb;
        struct acquisition_state *acq;
@@ -327,21 +392,11 @@ static int setup_acquisition(const struct sr_dev_inst *sdi)
        usb  = sdi->conn;
        acq  = devc->acquisition;
 
-       acq->reg_seq_pos = 0;
-       acq->reg_seq_len = 0;
-
-       lwla_queue_regval(acq, REG_MEM_CTRL, MEM_CTRL_CLR_IDX);
-       lwla_queue_regval(acq, REG_MEM_CTRL, MEM_CTRL_WRITE);
-
-       queue_long_regval(acq, LREG_CAP_CTRL,
-               CAP_CTRL_CLR_TIMEBASE | CAP_CTRL_FLUSH_FIFO |
-               CAP_CTRL_CLR_FIFOFULL | CAP_CTRL_CLR_COUNTER);
-
-       lwla_queue_regval(acq, REG_CLK_BOOST, acq->clock_boost);
-
-       ret = lwla_write_regs(usb, acq->reg_sequence, acq->reg_seq_len);
-       acq->reg_seq_len = 0;
+       ret = lwla_write_regs(usb, capture_init, ARRAY_SIZE(capture_init));
+       if (ret != SR_OK)
+               return ret;
 
+       ret = lwla_write_reg(usb, REG_CLK_BOOST, acq->clock_boost);
        if (ret != SR_OK)
                return ret;
 
@@ -396,7 +451,7 @@ static int prepare_request(const struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
        struct acquisition_state *acq;
-       unsigned int count;
+       unsigned int chunk_len, remaining, count;
 
        devc = sdi->priv;
        acq  = devc->acquisition;
@@ -423,17 +478,20 @@ static int prepare_request(const struct sr_dev_inst *sdi)
                break;
        case STATE_STATUS_REQUEST:
                acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_LREGS);
-               acq->xfer_buf_out[1] = LWLA_WORD(0);
-               acq->xfer_buf_out[2] = LWLA_WORD(LREG_STATUS + 1);
+               acq->xfer_buf_out[1] = LWLA_WORD(READ_LREGS_START);
+               acq->xfer_buf_out[2] = LWLA_WORD(READ_LREGS_COUNT);
                acq->xfer_out->length = 3 * sizeof(acq->xfer_buf_out[0]);
                break;
        case STATE_LENGTH_REQUEST:
                lwla_queue_regval(acq, REG_MEM_FILL, 0);
                break;
        case STATE_READ_REQUEST:
+               /* Limit reads to 8 device words (36 bytes) at a time if the
+                * device firmware has the short transfer quirk. */
+               chunk_len = (devc->short_transfer_quirk) ? 8 : READ_CHUNK_LEN;
                /* Always read a multiple of 8 device words. */
-               count = MIN(READ_CHUNK_LEN36, acq->mem_addr_stop
-                                       - acq->mem_addr_next + 7) / 8 * 8;
+               remaining = (acq->mem_addr_stop - acq->mem_addr_next + 7) / 8 * 8;
+               count = MIN(chunk_len, remaining);
 
                acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_MEM36);
                acq->xfer_buf_out[1] = LWLA_WORD_0(acq->mem_addr_next);
@@ -463,9 +521,9 @@ static int handle_response(const struct sr_dev_inst *sdi)
 
        switch (devc->state) {
        case STATE_STATUS_REQUEST:
-               if (acq->xfer_in->actual_length != (LREG_STATUS + 1) * 8) {
+               if (acq->xfer_in->actual_length != READ_LREGS_COUNT * 8) {
                        sr_err("Received size %d doesn't match expected size %d.",
-                              acq->xfer_in->actual_length, (LREG_STATUS + 1) * 8);
+                              acq->xfer_in->actual_length, READ_LREGS_COUNT * 8);
                        return SR_ERR;
                }
                acq->mem_addr_fill = bulk_long_get(acq, LREG_MEM_FILL) & 0xFFFFFFFF;