summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/imx/imx-usb-loader.c95
-rw-r--r--scripts/imx/imx.h16
2 files changed, 109 insertions, 2 deletions
diff --git a/scripts/imx/imx-usb-loader.c b/scripts/imx/imx-usb-loader.c
index 9de7bb3a8a..4105adeda9 100644
--- a/scripts/imx/imx-usb-loader.c
+++ b/scripts/imx/imx-usb-loader.c
@@ -798,6 +798,98 @@ static int do_dcd_v2_cmd_write(const unsigned char *dcd)
return 0;
}
+static int do_dcd_v2_cmd_check(const unsigned char *dcd)
+{
+ uint32_t mask;
+ uint32_t poll_count = 0;
+ int bytes;
+ enum imx_dcd_v2_check_cond cond;
+ struct imx_dcd_v2_check *check = (struct imx_dcd_v2_check *) dcd;
+ switch (ntohs(check->length)) {
+ case 12:
+ /* poll indefinitely */
+ poll_count = 0xffffffff;
+ break;
+ case 16:
+ poll_count = ntohl(check->count);
+ if (poll_count == 0)
+ /* this command behaves as for NOP */
+ return 0;
+ break;
+ default:
+ fprintf(stderr, "Error: invalid DCD check length\n");
+ return -1;
+ }
+
+ switch (check->param & 7) {
+ case 1:
+ case 2:
+ case 4:
+ bytes = check->param & 7;
+ break;
+ default:
+ fprintf(stderr, "Error: invalid DCD check size\n");
+ return -1;
+ }
+
+ switch ((check->param & 0xf8) >> 3) {
+ case check_all_bits_clear:
+ case check_all_bits_set:
+ case check_any_bit_clear:
+ case check_any_bit_set:
+ cond = (check->param & 0xf8) >> 3;
+ break;
+ default:
+ fprintf(stderr, "Error: invalid DCD check condition\n");
+ return -1;
+ }
+
+ mask = ntohl(check->mask);
+
+ fprintf(stderr, "DCD check condition %i on address 0x%x\n",
+ cond, ntohl(check->addr));
+ /* Reduce the poll count to some arbitrary practical limit.
+ Polling via SRP commands will be much slower compared to
+ polling when DCD is interpreted by the SOC microcode.
+ */
+ if (poll_count > 1000)
+ poll_count = 1000;
+
+ while (poll_count > 0) {
+ uint32_t data = 0;
+ int ret = read_memory(ntohl(check->addr), &data, bytes);
+ if (ret < 0)
+ return ret;
+
+ data &= mask;
+
+ switch (cond) {
+ case check_all_bits_clear:
+ if (data != 0)
+ return 0;
+ break;
+ case check_all_bits_set:
+ if (data != mask)
+ return 0;
+ break;
+ case check_any_bit_clear:
+ if (data == mask)
+ return 0;
+ break;
+ case check_any_bit_set:
+ if (data == 0)
+ return 0;
+ break;
+ }
+ poll_count--;
+ }
+
+ fprintf(stderr, "Error: timeout waiting for DCD check condition %i "
+ "on address 0x%08x to match 0x%08x\n", cond,
+ ntohl(check->addr), ntohl(check->mask));
+ return -1;
+}
+
static int process_dcd_table_ivt(const struct imx_flash_header_v2 *hdr,
const unsigned char *file_start, unsigned cnt)
{
@@ -850,8 +942,7 @@ static int process_dcd_table_ivt(const struct imx_flash_header_v2 *hdr,
ret = do_dcd_v2_cmd_write(dcd);
break;
case TAG_CHECK:
- fprintf(stderr, "DCD check not implemented yet\n");
- usleep(50000);
+ ret = do_dcd_v2_cmd_check(dcd);
break;
case TAG_UNLOCK:
fprintf(stderr, "DCD unlock not implemented yet\n");
diff --git a/scripts/imx/imx.h b/scripts/imx/imx.h
index 57c7525369..f32ae52abf 100644
--- a/scripts/imx/imx.h
+++ b/scripts/imx/imx.h
@@ -95,4 +95,20 @@ struct imx_dcd_v2_write {
struct imx_dcd_v2_write_rec data[MAX_RECORDS_DCD_V2];
} __attribute__((packed));
+struct imx_dcd_v2_check {
+ uint8_t tag;
+ uint16_t length;
+ uint8_t param;
+ uint32_t addr;
+ uint32_t mask;
+ uint32_t count;
+} __attribute__((packed));
+
+enum imx_dcd_v2_check_cond {
+ check_all_bits_clear = 0,
+ check_all_bits_set = 1,
+ check_any_bit_clear = 2,
+ check_any_bit_set = 3,
+} __attribute__((packed));
+
int parse_config(struct config_data *data, const char *filename);