X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fsysclk-lwla%2Flwla1034.c;h=14692c38c618a58bac0f08b779cee3c2d5a93557;hb=76bc28c3f1cbd88f01eda7251e9f4f1d88c506f2;hp=baf3d1e94b2621733cc99395c08a62dea51283b8;hpb=7ed808179f5542c903a476266c4b175a6f2a18a7;p=libsigrok.git diff --git a/src/hardware/sysclk-lwla/lwla1034.c b/src/hardware/sysclk-lwla/lwla1034.c index baf3d1e9..14692c38 100644 --- a/src/hardware/sysclk-lwla/lwla1034.c +++ b/src/hardware/sysclk-lwla/lwla1034.c @@ -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 @@ -54,11 +54,19 @@ * 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;