]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/kingst-la2016/protocol.c
kingst-la2016: rephrase FPGA bitstream content zero padding
[libsigrok.git] / src / hardware / kingst-la2016 / protocol.c
index 157e9750a7699f5e3a67d0d8c5fd78932c46acf5..a0de3be70c0982ea5bc7525a49069dfdc13bab39 100644 (file)
  * CMD_FPGA_SPI requests. The FX2 MCU transparently handles the detail
  * of SPI transfers encoding the read (1) or write (0) direction in the
  * MSB of the address field. There are some 60 byte-wide FPGA registers.
+ *
+ * Unfortunately the FPGA registers change their meaning between the
+ * read and write directions of access, or exclusively provide one of
+ * these directions and not the other. This is an arbitrary vendor's
+ * choice, there is nothing which the sigrok driver could do about it.
+ * Values written to registers typically cannot get read back, neither
+ * verified after writing a configuration, nor queried upon startup for
+ * automatic detection of the current configuration. Neither appear to
+ * be there echo registers for presence and communication checks, nor
+ * version identifying registers, as far as we know.
  */
 #define REG_RUN                0x00    /* Read capture status, write start capture. */
 #define REG_PWM_EN     0x02    /* User PWM channels on/off. */
@@ -114,23 +124,92 @@ static int ctrl_out(const struct sr_dev_inst *sdi,
        return SR_OK;
 }
 
+/*
+ * Check the necessity for FPGA bitstream upload, because another upload
+ * would take some 600ms which is undesirable after program startup. Try
+ * to access some FPGA registers and check the values' plausibility. The
+ * check should fail on the safe side, request another upload when in
+ * doubt. A positive response (the request to continue operation with the
+ * currently active bitstream) should be conservative. Accessing multiple
+ * registers is considered cheap compared to the cost of bitstream upload.
+ *
+ * It helps though that both the vendor software and the sigrok driver
+ * use the same bundle of MCU firmware and FPGA bitstream for any of the
+ * supported models. We don't expect to successfully communicate to the
+ * device yet disagree on its protocol. Ideally we would access version
+ * identifying registers for improved robustness, but are not aware of
+ * any. A bitstream reload can always be forced by a power cycle.
+ */
+static int check_fpga_bitstream(const struct sr_dev_inst *sdi)
+{
+       uint8_t init_rsp;
+       int ret;
+       uint16_t run_state;
+       uint8_t pwm_en;
+       size_t read_len;
+       uint8_t buff[sizeof(run_state)];
+       const uint8_t *rdptr;
+
+       sr_dbg("Checking operation of the FPGA bitstream.");
+
+       init_rsp = 0xff;
+       ret = ctrl_in(sdi, CMD_FPGA_INIT, 0x00, 0, &init_rsp, sizeof(init_rsp));
+       if (ret != SR_OK || init_rsp != 0) {
+               sr_dbg("FPGA init query failed, or unexpected response.");
+               return SR_ERR_IO;
+       }
+
+       read_len = sizeof(run_state);
+       ret = ctrl_in(sdi, CMD_FPGA_SPI, REG_RUN, 0, buff, read_len);
+       if (ret != SR_OK) {
+               sr_dbg("FPGA register access failed (run state).");
+               return SR_ERR_IO;
+       }
+       rdptr = buff;
+       run_state = read_u16le_inc(&rdptr);
+       sr_spew("FPGA register: run state 0x%04x.", run_state);
+       if (run_state && (run_state & 0x3) != 0x1) {
+               sr_dbg("Unexpected FPGA register content (run state).");
+               return SR_ERR_DATA;
+       }
+       if (run_state && (run_state & ~0xf) != 0x85e0) {
+               sr_dbg("Unexpected FPGA register content (run state).");
+               return SR_ERR_DATA;
+       }
+
+       read_len = sizeof(pwm_en);
+       ret = ctrl_in(sdi, CMD_FPGA_SPI, REG_PWM_EN, 0, buff, read_len);
+       if (ret != SR_OK) {
+               sr_dbg("FPGA register access failed (PWM enable).");
+               return SR_ERR_IO;
+       }
+       rdptr = buff;
+       pwm_en = read_u8_inc(&rdptr);
+       sr_spew("FPGA register: PWM enable 0x%02x.", pwm_en);
+       if ((pwm_en & 0x3) != 0x0) {
+               sr_dbg("Unexpected FPGA register content (PWM enable).");
+               return SR_ERR_DATA;
+       }
+
+       sr_info("Could re-use current FPGA bitstream. No upload required.");
+       return SR_OK;
+}
+
 static int upload_fpga_bitstream(const struct sr_dev_inst *sdi,
        const char *bitstream_fname)
 {
-       struct dev_context *devc;
        struct drv_context *drvc;
        struct sr_usb_dev_inst *usb;
        struct sr_resource bitstream;
+       uint32_t bitstream_size;
        uint8_t buffer[sizeof(uint32_t)];
        uint8_t *wrptr;
-       uint8_t cmd_resp;
        uint8_t block[4096];
        int len, act_len;
        unsigned int pos;
        int ret;
-       unsigned int zero_pad_to = 0x2c000;
+       unsigned int zero_pad_to;
 
-       devc = sdi->priv;
        drvc = sdi->driver->context;
        usb = sdi->conn;
 
@@ -142,14 +221,18 @@ static int upload_fpga_bitstream(const struct sr_dev_inst *sdi,
                return ret;
        }
 
-       devc->bitstream_size = (uint32_t)bitstream.size;
+       bitstream_size = (uint32_t)bitstream.size;
        wrptr = buffer;
-       write_u32le_inc(&wrptr, devc->bitstream_size);
+       write_u32le_inc(&wrptr, bitstream_size);
        if ((ret = ctrl_out(sdi, CMD_FPGA_INIT, 0x00, 0, buffer, wrptr - buffer)) != SR_OK) {
                sr_err("Cannot initiate FPGA bitstream upload.");
                sr_resource_close(drvc->sr_ctx, &bitstream);
                return ret;
        }
+       zero_pad_to = bitstream_size;
+       zero_pad_to += LA2016_EP2_PADDING - 1;
+       zero_pad_to /= LA2016_EP2_PADDING;
+       zero_pad_to *= LA2016_EP2_PADDING;
 
        pos = 0;
        while (1) {
@@ -192,6 +275,14 @@ static int upload_fpga_bitstream(const struct sr_dev_inst *sdi,
        sr_info("FPGA bitstream upload (%" PRIu64 " bytes) done.",
                bitstream.size);
 
+       return SR_OK;
+}
+
+static int enable_fpga_bitstream(const struct sr_dev_inst *sdi)
+{
+       int ret;
+       uint8_t cmd_resp;
+
        if ((ret = ctrl_in(sdi, CMD_FPGA_INIT, 0x00, 0, &cmd_resp, sizeof(cmd_resp))) != SR_OK) {
                sr_err("Cannot read response after FPGA bitstream upload.");
                return ret;
@@ -201,15 +292,14 @@ static int upload_fpga_bitstream(const struct sr_dev_inst *sdi,
                        cmd_resp);
                return SR_ERR;
        }
-
        g_usleep(30000);
 
        if ((ret = ctrl_out(sdi, CMD_FPGA_ENABLE, 0x01, 0, NULL, 0)) != SR_OK) {
                sr_err("Cannot enable FPGA after bitstream upload.");
                return ret;
        }
-
        g_usleep(40000);
+
        return SR_OK;
 }
 
@@ -974,6 +1064,7 @@ SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi)
        uint8_t buf[8];
        int16_t purchase_date_bcd[2];
        uint8_t magic;
+       const char *bitstream_fn;
        int ret;
 
        devc = sdi->priv;
@@ -1053,28 +1144,40 @@ SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi)
        /* Select the FPGA bitstream depending on the model. */
        switch (magic) {
        case 2:
-               ret = upload_fpga_bitstream(sdi, FPGA_FW_LA2016);
+               bitstream_fn = FPGA_FW_LA2016;
                devc->max_samplerate = MAX_SAMPLE_RATE_LA2016;
                break;
        case 3:
-               ret = upload_fpga_bitstream(sdi, FPGA_FW_LA1016);
+               bitstream_fn = FPGA_FW_LA1016;
                devc->max_samplerate = MAX_SAMPLE_RATE_LA1016;
                break;
        case 8:
-               ret = upload_fpga_bitstream(sdi, FPGA_FW_LA2016A);
+               bitstream_fn = FPGA_FW_LA2016A;
                devc->max_samplerate = MAX_SAMPLE_RATE_LA2016;
                break;
        case 9:
-               ret = upload_fpga_bitstream(sdi, FPGA_FW_LA1016A);
+               bitstream_fn = FPGA_FW_LA1016A;
                devc->max_samplerate = MAX_SAMPLE_RATE_LA1016;
                break;
        default:
+               bitstream_fn = NULL;
+               break;
+       }
+       if (!bitstream_fn || !*bitstream_fn) {
                sr_err("Cannot identify as one of the supported models.");
                return SR_ERR;
        }
 
+       if (check_fpga_bitstream(sdi) != SR_OK) {
+               ret = upload_fpga_bitstream(sdi, bitstream_fn);
+               if (ret != SR_OK) {
+                       sr_err("Cannot upload FPGA bitstream.");
+                       return ret;
+               }
+       }
+       ret = enable_fpga_bitstream(sdi);
        if (ret != SR_OK) {
-               sr_err("Cannot upload FPGA bitstream.");
+               sr_err("Cannot enable FPGA bitstream after upload.");
                return ret;
        }