diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2017-03-13 08:16:44 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2017-03-13 08:16:44 +0100 |
commit | 4e11672653a4ad639ca2d2158b1266b258951f93 (patch) | |
tree | f414be44a08fa1bf479ced828a412102b0646785 /scripts | |
parent | 93c55ce0986a47f5b6774a81443e9b3a15fc727c (diff) | |
parent | 0482159e9ab9fcd23ab8db2e9d6f585c3929d447 (diff) | |
download | barebox-4e11672653a4ad639ca2d2158b1266b258951f93.tar.gz barebox-4e11672653a4ad639ca2d2158b1266b258951f93.tar.xz |
Merge branch 'for-next/imx'
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/Makefile | 5 | ||||
-rw-r--r-- | scripts/imx/Kconfig | 7 | ||||
-rw-r--r-- | scripts/imx/imx-usb-loader.c | 281 | ||||
-rw-r--r-- | scripts/imx/imx.h | 16 | ||||
-rw-r--r-- | scripts/mxs-usb-loader.c | 236 |
5 files changed, 289 insertions, 256 deletions
diff --git a/scripts/Makefile b/scripts/Makefile index 7f2527d1c2..8eda41e13b 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -22,9 +22,6 @@ hostprogs-$(CONFIG_ARCH_SOCFPGA) += socfpga_mkimage hostprogs-$(CONFIG_ARCH_MXS) += mxsimage mxsboot HOSTCFLAGS += -I$(srctree)/scripts/include/ HOSTLOADLIBES_mxsimage = `pkg-config --libs openssl` -HOSTCFLAGS_mxs-usb-loader.o = `pkg-config --cflags libusb-1.0` -HOSTLOADLIBES_mxs-usb-loader = `pkg-config --libs libusb-1.0` -hostprogs-$(CONFIG_ARCH_MXS_USBLOADER) += mxs-usb-loader HOSTCFLAGS_omap3-usb-loader.o = `pkg-config --cflags libusb-1.0` HOSTLOADLIBES_omap3-usb-loader = `pkg-config --libs libusb-1.0` hostprogs-$(CONFIG_OMAP3_USB_LOADER) += omap3-usb-loader @@ -33,7 +30,7 @@ HOSTLOADLIBES_omap4_usbboot = -lpthread `pkg-config --libs libusb-1.0` hostprogs-$(CONFIG_OMAP4_USBBOOT) += omap4_usbboot subdir-y += mod -subdir-$(CONFIG_ARCH_IMX) += imx +subdir-y += imx subdir-$(CONFIG_X86) += setupmbr subdir-$(CONFIG_DTC) += dtc subdir-$(CONFIG_ARCH_TEGRA) += tegra diff --git a/scripts/imx/Kconfig b/scripts/imx/Kconfig new file mode 100644 index 0000000000..fda9c639c1 --- /dev/null +++ b/scripts/imx/Kconfig @@ -0,0 +1,7 @@ +config ARCH_IMX_USBLOADER + depends on ARCH_MXS || ARCH_IMX + bool "compile imx-usb-loader" + help + imx-usb-loader is a tool to upload and start imximages to an i.MX SoC + in ROM boot mode. It requires libusb, so make sure you have the libusb + devel package installed on your machine. diff --git a/scripts/imx/imx-usb-loader.c b/scripts/imx/imx-usb-loader.c index 9de7bb3a8a..90ee3e09d5 100644 --- a/scripts/imx/imx-usb-loader.c +++ b/scripts/imx/imx-usb-loader.c @@ -45,6 +45,12 @@ #define FT_DCD 0xee #define FT_LOAD_ONLY 0x00 +/* + * comment from libusb: + * As per the USB 3.0 specs, the current maximum limit for the depth is 7. + */ +#define MAX_USB_PORTS 7 + int verbose; static struct libusb_device_handle *usb_dev_handle; static struct usb_id *usb_id; @@ -63,6 +69,9 @@ struct mach_id { #define HDR_MX53 2 unsigned char header_type; unsigned short max_transfer; +#define DEV_IMX 0 +#define DEV_MXS 1 + unsigned char dev_type; }; struct usb_work { @@ -81,7 +90,9 @@ static const struct mach_id imx_ids[] = { .vid = 0x066f, .pid = 0x3780, .name = "i.MX23", - .mode = MODE_BULK, + .mode = MODE_HID, + .max_transfer = 1024, + .dev_type = DEV_MXS, }, { .vid = 0x15a2, .pid = 0x0030, @@ -114,6 +125,8 @@ static const struct mach_id imx_ids[] = { .vid = 0x15a2, .pid = 0x004f, .name = "i.MX28", + .max_transfer = 1024, + .dev_type = DEV_MXS, }, { .vid = 0x15a2, .pid = 0x0052, @@ -181,6 +194,17 @@ struct sdp_command { uint8_t rsvd; } __attribute__((packed)); +#define MXS_CMD_FW_DOWNLOAD 0x02 +struct mxs_command { + uint32_t sign; /* Signature */ + uint32_t tag; /* Tag */ + uint32_t size; /* Payload size */ + uint8_t flags; /* Flags (host to device) */ + uint8_t rsvd[2]; /* Reserved */ + uint8_t cmd; /* Firmware download */ + uint32_t dw_size; /* Download size */ +} __attribute__((packed)); + static const struct mach_id *imx_device(unsigned short vid, unsigned short pid) { int i; @@ -197,9 +221,66 @@ static const struct mach_id *imx_device(unsigned short vid, unsigned short pid) return NULL; } -static libusb_device *find_imx_dev(libusb_device **devs, const struct mach_id **pp_id) +static int device_location_equal(libusb_device *device, const char *location) +{ + uint8_t port_path[MAX_USB_PORTS]; + uint8_t dev_bus; + int path_step, path_len; + int result = 0; + char *ptr, *loc; + + /* strtok need non const char */ + loc = strdup(location); + + path_len = libusb_get_port_numbers(device, port_path, MAX_USB_PORTS); + if (path_len == LIBUSB_ERROR_OVERFLOW) { + fprintf(stderr, "cannot determine path to usb device! (more than %i ports in path)\n", + MAX_USB_PORTS); + goto done; + } + + ptr = strtok(loc, "-"); + if (ptr == NULL) { + printf("no '-' in path\n"); + goto done; + } + + dev_bus = libusb_get_bus_number(device); + /* check bus mismatch */ + if (atoi(ptr) != dev_bus) + goto done; + + path_step = 0; + while (path_step < MAX_USB_PORTS) { + ptr = strtok(NULL, "."); + + /* no more tokens in path */ + if (ptr == NULL) + break; + + /* path mismatch at some step */ + if (path_step < path_len && atoi(ptr) != port_path[path_step]) + break; + + path_step++; + }; + + /* walked the full path, all elements match */ + if (path_step == path_len) + result = 1; + else + fprintf(stderr, " excluded by device path option\n"); + +done: + free(loc); + return result; +} + +static libusb_device *find_imx_dev(libusb_device **devs, const struct mach_id **pp_id, + const char *location) { int i = 0; + int err; const struct mach_id *p; for (;;) { @@ -217,10 +298,24 @@ static libusb_device *find_imx_dev(libusb_device **devs, const struct mach_id ** } p = imx_device(desc.idVendor, desc.idProduct); - if (p) { - *pp_id = p; - return dev; + if (!p) + continue; + + err = libusb_open(dev, &usb_dev_handle); + if (err) { + fprintf(stderr, "Could not open device vid=0x%x pid=0x%x err=%d\n", + p->vid, p->pid, err); + continue; + } + + if (location && !device_location_equal(dev, location)) { + libusb_close(usb_dev_handle); + usb_dev_handle = NULL; + continue; } + + *pp_id = p; + return dev; } *pp_id = NULL; @@ -798,6 +893,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 +1037,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"); @@ -1273,6 +1459,66 @@ static int write_mem(const struct config_data *data, uint32_t addr, return modify_memory(addr, val, width, set_bits, clear_bits); } +/* MXS section */ +static int mxs_load_file(libusb_device_handle *dev, uint8_t *data, int size) +{ + static struct mxs_command dl_command; + int last_trans, err; + void *p; + int cnt; + + dl_command.sign = htonl(0x424c5443); /* Signature: BLTC */ + dl_command.tag = htonl(0x1); + dl_command.size = htonl(size); + dl_command.flags = 0; + dl_command.rsvd[0] = 0; + dl_command.rsvd[1] = 0; + dl_command.cmd = MXS_CMD_FW_DOWNLOAD; + dl_command.dw_size = htonl(size); + + err = transfer(1, (unsigned char *) &dl_command, 20, &last_trans); + if (err) { + printf("transfer error at init step: err=%i, last_trans=%i\n", + err, last_trans); + return err; + } + + p = data; + cnt = size; + + while (1) { + int now = get_min(cnt, usb_id->mach_id->max_transfer); + + if (!now) + break; + + err = transfer(2, p, now, &now); + if (err) { + printf("dl_command err=%i, last_trans=%i\n", err, now); + return err; + } + + p += now; + cnt -= now; + } + + return err; +} + +static int mxs_work(struct usb_work *curr) +{ + unsigned fsize = 0; + unsigned char *buf = NULL; + int ret; + + ret = read_file(curr->filename, &buf, &fsize); + if (ret < 0) + return ret; + + return mxs_load_file(usb_dev_handle, buf, fsize); +} +/* end of mxs section */ + static int parse_initfile(const char *filename) { struct config_data data = { @@ -1287,6 +1533,7 @@ static void usage(const char *prgname) fprintf(stderr, "usage: %s [OPTIONS] [FILENAME]\n\n" "-c check correctness of flashed image\n" "-i <cfgfile> Specify custom SoC initialization file\n" + "-p <devpath> Specify device path: <bus>-<port>[.<port>]...\n" "-s skip DCD included in image\n" "-v verbose (give multiple times to increase)\n" "-h this help\n", prgname); @@ -1307,10 +1554,11 @@ int main(int argc, char *argv[]) struct usb_work w = {}; int opt; char *initfile = NULL; + char *devpath = NULL; w.do_dcd_once = 1; - while ((opt = getopt(argc, argv, "cvhi:s")) != -1) { + while ((opt = getopt(argc, argv, "cvhi:p:s")) != -1) { switch (opt) { case 'c': verify = 1; @@ -1323,6 +1571,9 @@ int main(int argc, char *argv[]) case 'i': initfile = optarg; break; + case 'p': + devpath = optarg; + break; case 's': w.do_dcd_once = 0; break; @@ -1350,19 +1601,12 @@ int main(int argc, char *argv[]) goto out; } - dev = find_imx_dev(devs, &mach); + dev = find_imx_dev(devs, &mach, devpath); if (!dev) { fprintf(stderr, "no supported device found\n"); goto out; } - err = libusb_open(dev, &usb_dev_handle); - if (err) { - fprintf(stderr, "Could not open device vid=0x%x pid=0x%x err=%d\n", - mach->vid, mach->pid, err); - goto out; - } - libusb_free_device_list(devs, 1); libusb_get_configuration(usb_dev_handle, &config); @@ -1384,6 +1628,11 @@ int main(int argc, char *argv[]) usb_id->mach_id = mach; + if (mach->dev_type == DEV_MXS) { + ret = mxs_work(&w); + goto out; + } + err = do_status(); if (err) { printf("status failed\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); diff --git a/scripts/mxs-usb-loader.c b/scripts/mxs-usb-loader.c deleted file mode 100644 index 8529274d6e..0000000000 --- a/scripts/mxs-usb-loader.c +++ /dev/null @@ -1,236 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <libusb.h> -#include <stdint.h> - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -void put32le(uint8_t * buf, uint32_t i) -{ - *buf++ = i & 0xff; - *buf++ = (i >> 8) & 0xff; - *buf++ = (i >> 16) & 0xff; - *buf++ = (i >> 24) & 0xff; -} - -void put32be(uint8_t * buf, uint32_t i) -{ - *buf++ = (i >> 24) & 0xff; - *buf++ = (i >> 16) & 0xff; - *buf++ = (i >> 8) & 0xff; - *buf++ = i & 0xff; -} - -enum dev_type_t { - HID_DEVICE, - RECOVERY_DEVICE, -}; - -struct dev_info_t { - uint16_t vendor_id; - uint16_t product_id; - unsigned xfer_size; - enum dev_type_t dev_type; -}; - -struct dev_info_t g_dev_info[] = { - {0x066f, 0x3780, 1024, HID_DEVICE}, /* i.MX233 / STMP3780 */ - {0x066f, 0x3770, 48, HID_DEVICE}, /* STMP3770 */ - {0x15A2, 0x004F, 1024, HID_DEVICE}, /* i.MX28 */ - {0x066f, 0x3600, 4096, RECOVERY_DEVICE}, /* STMP36xx */ -}; - -int send_hid(libusb_device_handle * dev, int xfer_size, uint8_t * data, - int size, int nr_xfers) -{ - int i; - - libusb_detach_kernel_driver(dev, 0); - libusb_detach_kernel_driver(dev, 4); - - libusb_claim_interface(dev, 0); - libusb_claim_interface(dev, 4); - - uint8_t *xfer_buf = malloc(1 + xfer_size); - uint8_t *p = xfer_buf; - - *p++ = 0x01; /* Report id */ - - /* Command block wrapper */ - *p++ = 'B'; /* Signature */ - *p++ = 'L'; - *p++ = 'T'; - *p++ = 'C'; - put32le(p, 0x1); /* Tag */ - p += 4; - put32le(p, size); /* Payload size */ - p += 4; - *p++ = 0; /* Flags (host to device) */ - p += 2; /* Reserved */ - - /* Command descriptor block */ - *p++ = 0x02; /* Firmware download */ - put32be(p, size); /* Download size */ - - int ret = libusb_control_transfer(dev, - LIBUSB_REQUEST_TYPE_CLASS | - LIBUSB_RECIPIENT_INTERFACE, 0x9, - 0x201, 0, - xfer_buf, xfer_size + 1, 1000); - if (ret < 0) { - printf("transfer error at init step\n"); - return 1; - } - - for (i = 0; i < nr_xfers; i++) { - xfer_buf[0] = 0x2; - memcpy(&xfer_buf[1], &data[i * xfer_size], xfer_size); - - ret = libusb_control_transfer(dev, - LIBUSB_REQUEST_TYPE_CLASS | - LIBUSB_RECIPIENT_INTERFACE, 0x9, - 0x202, 0, xfer_buf, xfer_size + 1, - 1000); - if (ret < 0) { - printf("transfer error at send step %d\n", i); - return 1; - } - } - - int recv_size; - ret = - libusb_interrupt_transfer(dev, 0x81, xfer_buf, xfer_size, - &recv_size, 1000); - if (ret < 0) { - printf("transfer error at final stage\n"); - return 1; - } - - return ret; -} - -int send_recovery(libusb_device_handle * dev, int xfer_size, uint8_t * data, - int size, int nr_xfers) -{ - (void)nr_xfers; - // there should be no kernel driver attached but in doubt... - libusb_detach_kernel_driver(dev, 0); - libusb_claim_interface(dev, 0); - - int sent = 0; - while (sent < size) { - int xfered; - int len = MIN(size - sent, xfer_size); - int ret = - libusb_bulk_transfer(dev, 1, data + sent, len, &xfered, - 1000); - if (ret < 0) { - printf("transfer error at send offset %d\n", sent); - return 1; - } - if (xfered == 0) { - printf("empty transfer at step offset %d\n", sent); - return 2; - } - sent += xfered; - } - return 0; -} - -int main(int argc, char **argv) -{ - if (argc != 3) { - printf("usage: %s <xfer size> <file>\n", argv[0]); - printf - ("If <xfer size> is set to zero, the preferred one is used.\n"); - return 1; - } - - char *end; - int xfer_size = strtol(argv[1], &end, 0); - if (end != (argv[1] + strlen(argv[1]))) { - printf("Invalid transfer size !\n"); - return 1; - } - - libusb_device_handle *dev; - - libusb_init(NULL); - - libusb_set_debug(NULL, 3); - - unsigned i; - for (i = 0; i < sizeof(g_dev_info) / sizeof(g_dev_info[0]); i++) { - dev = libusb_open_device_with_vid_pid(NULL, - g_dev_info[i].vendor_id, - g_dev_info[i].product_id); - if (dev == NULL) - continue; - if (xfer_size == 0) - xfer_size = g_dev_info[i].xfer_size; - printf("Found a match for %04x:%04x\n", - g_dev_info[i].vendor_id, g_dev_info[i].product_id); - break; - } - if (dev == NULL) { - printf("Cannot open device\n"); - return 1; - } - - FILE *f = fopen(argv[2], "r"); - if (f == NULL) { - perror("cannot open file"); - return 1; - } - fseek(f, 0, SEEK_END); - size_t size = ftell(f); - fseek(f, 0, SEEK_SET); - - printf("Transfer size: %d\n", xfer_size); - int nr_xfers = (size + xfer_size - 1) / xfer_size; - uint8_t *file_buf = malloc(nr_xfers * xfer_size); - memset(file_buf, 0xff, nr_xfers * xfer_size); // pad with 0xff - if (fread(file_buf, size, 1, f) != 1) { - perror("read error"); - fclose(f); - return 1; - } - fclose(f); - - switch (g_dev_info[i].dev_type) { - case HID_DEVICE: - send_hid(dev, xfer_size, file_buf, size, nr_xfers); - break; - case RECOVERY_DEVICE: - send_recovery(dev, xfer_size, file_buf, size, nr_xfers); - break; - default: - printf("unknown device type\n"); - break; - } - - return 0; -} |