9
0
Fork 0

Merge branch 'for-next/imx'

This commit is contained in:
Sascha Hauer 2017-03-13 08:16:44 +01:00
commit 4e11672653
14 changed files with 321 additions and 308 deletions

View File

@ -268,6 +268,7 @@ source arch/arm/mach-ep93xx/Kconfig
source arch/arm/mach-highbank/Kconfig
source arch/arm/mach-imx/Kconfig
source arch/arm/mach-mxs/Kconfig
source scripts/imx/Kconfig
source arch/arm/mach-mvebu/Kconfig
source arch/arm/mach-netx/Kconfig
source arch/arm/mach-nomadik/Kconfig

View File

@ -122,7 +122,6 @@ PHYTEC_ENTRY_MLO(start_am33xx_phytec_phycore_sram_128mb, am335x_phytec_phycore_s
PHYTEC_ENTRY_MLO(start_am33xx_phytec_phycore_sram_256mb, am335x_phytec_phycore_som_mlo, PHYCORE_MT41J128M16125IT_256MB);
PHYTEC_ENTRY_MLO(start_am33xx_phytec_phycore_sram_512mb, am335x_phytec_phycore_som_mlo, PHYCORE_MT41J256M16HA15EIT_512MB);
PHYTEC_ENTRY_MLO(start_am33xx_phytec_phycore_sram_2x512mb, am335x_phytec_phycore_som_mlo, PHYCORE_MT41J512M8125IT_2x512MB);
PHYTEC_ENTRY_MLO(start_am33xx_phytec_phycore_sram_1024mb, am335x_phytec_phycore_som_mlo, PHYCORE_IM8G16D3FBBG15EI_1024MB);
PHYTEC_ENTRY_MLO(start_am33xx_phytec_phycore_r2_sram_512mb, am335x_phytec_phycore_som_mlo, PHYCORE_R2_MT41K256M16TW107IT_512MB);
PHYTEC_ENTRY_MLO(start_am33xx_phytec_phycore_r2_sram_256mb, am335x_phytec_phycore_som_mlo, PHYCORE_R2_MT41K128M16JT_256MB);
PHYTEC_ENTRY_MLO(start_am33xx_phytec_phycore_r2_sram_1024mb, am335x_phytec_phycore_som_mlo, PHYCORE_R2_MT41K512M16HA125IT_1024MB);

View File

@ -29,7 +29,6 @@ enum {
PHYCORE_MT41J64M1615IT_128MB,
PHYCORE_MT41J256M16HA15EIT_512MB,
PHYCORE_MT41J512M8125IT_2x512MB,
PHYCORE_IM8G16D3FBBG15EI_1024MB,
PHYCORE_R2_MT41K256M16TW107IT_512MB,
PHYCORE_R2_MT41K128M16JT_256MB,
PHYCORE_R2_MT41K512M16HA125IT_1024MB,
@ -162,26 +161,6 @@ struct am335x_sdram_timings physom_timings[] = {
},
},
/* 1024MB */
[PHYCORE_IM8G16D3FBBG15EI_1024MB] = {
.regs = {
.emif_read_latency = 0x7,
.emif_tim1 = 0x0AAAE4DB,
.emif_tim2 = 0x268F7FDA,
.emif_tim3 = 0x501F88BF,
.ocp_config = 0x003d3d3d,
.sdram_config = 0x61C053B2,
.zq_config = 0x50074BE4,
.sdram_ref_ctrl = 0x00000C30
},
.data = {
.rd_slave_ratio0 = 0x33,
.wr_dqs_slave_ratio0 = 0x4a,
.fifo_we_slave_ratio0 = 0xa4,
.wr_slave_ratio0 = 0x85,
},
},
/* 256MB */
[PHYCARD_NT5CB128M16BP_256MB] = {
.regs = {

View File

@ -309,7 +309,6 @@ config MACH_TX6X
config MACH_SABRELITE
bool "Freescale i.MX6 Sabre Lite"
select ARCH_IMX6
select HAVE_PBL_MULTI_IMAGES
config MACH_SABRESD
bool "Freescale i.MX6 SabreSD"
@ -657,13 +656,6 @@ endmenu
menu "i.MX specific settings"
config ARCH_IMX_USBLOADER
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.
config IMX_IIM
tristate "IIM fusebox device"
depends on !ARCH_IMX21

View File

@ -62,6 +62,7 @@ struct iim_priv {
struct imx_iim_drvdata {
void (*supply)(int enable);
char nregs[8];
};
static struct iim_priv *imx_iim;
@ -314,7 +315,7 @@ static struct regmap_bus imx_iim_regmap_bus = {
.reg_read = imx_iim_reg_read,
};
static int imx_iim_add_bank(struct iim_priv *iim, int num)
static int imx_iim_add_bank(struct iim_priv *iim, int num, int nregs)
{
struct iim_bank *bank;
char *name;
@ -331,7 +332,7 @@ static int imx_iim_add_bank(struct iim_priv *iim, int num)
bank->map_config.reg_bits = 8,
bank->map_config.val_bits = 8,
bank->map_config.reg_stride = 1,
bank->map_config.max_register = 31,
bank->map_config.max_register = (nregs - 1),
bank->map_config.name = xasprintf("bank%d", num);
bank->map = regmap_init(&iim->dev, &imx_iim_regmap_bus, bank, &bank->map_config);
@ -459,6 +460,7 @@ static int imx_iim_probe(struct device_d *dev)
struct iim_priv *iim;
int i, ret;
struct imx_iim_drvdata *drvdata = NULL;
char *nregs = NULL;
if (imx_iim)
return -EBUSY;
@ -486,8 +488,16 @@ static int imx_iim_probe(struct device_d *dev)
return PTR_ERR(iores);
iim->base = IOMEM(iores->start);
if (drvdata && drvdata->nregs[0])
nregs = drvdata->nregs;
for (i = 0; i < IIM_NUM_BANKS; i++) {
ret = imx_iim_add_bank(iim, i);
int n = nregs ? nregs[i] : 32;
if (!n)
continue;
ret = imx_iim_add_bank(iim, i, n);
if (ret)
return ret;
}
@ -529,14 +539,21 @@ static void imx53_iim_supply(int enable)
}
static struct imx_iim_drvdata imx27_drvdata = {
.nregs = { 32, 32 },
};
static struct imx_iim_drvdata imx25_imx31_imx35_drvdata = {
.nregs = { 32, 32, 32 },
};
static struct imx_iim_drvdata imx51_drvdata = {
.supply = imx51_iim_supply,
.nregs = { 32, 32, 32, 32 },
};
static struct imx_iim_drvdata imx53_drvdata = {
.supply = imx53_iim_supply,
.nregs = { 32, 32, 32, 32, 16 },
};
static __maybe_unused struct of_device_id imx_iim_dt_ids[] = {
@ -546,9 +563,18 @@ static __maybe_unused struct of_device_id imx_iim_dt_ids[] = {
}, {
.compatible = "fsl,imx51-iim",
.data = &imx51_drvdata,
}, {
.compatible = "fsl,imx35-iim",
.data = &imx25_imx31_imx35_drvdata,
}, {
.compatible = "fsl,imx31-iim",
.data = &imx25_imx31_imx35_drvdata,
}, {
.compatible = "fsl,imx27-iim",
.data = &imx27_drvdata,
}, {
.compatible = "fsl,imx25-iim",
.data = &imx25_imx31_imx35_drvdata,
}, {
/* sentinel */
}

View File

@ -143,11 +143,4 @@ endif
endmenu
config ARCH_MXS_USBLOADER
bool "compile mxs-usb-loader"
help
mxs-usb-loader is a tool to upload and start mxs bootstream images 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.
endif

View File

@ -494,10 +494,7 @@ static int imx6_ccm_probe(struct device_d *dev)
writel(0xffffffff, ccm_base + CCGR0);
writel(0xf0ffffff, ccm_base + CCGR1); /* gate GPU3D, GPU2D */
writel(0xffffffff, ccm_base + CCGR2);
if (IS_ENABLED(CONFIG_DRIVER_VIDEO_IMX_IPUV3))
writel(0x3fffffff, ccm_base + CCGR3); /* gate OpenVG */
else
writel(0x3fff0000, ccm_base + CCGR3); /* gate OpenVG, LDB, IPU1, IPU2 */
writel(0x3fffffff, ccm_base + CCGR3); /* gate OpenVG */
if (IS_ENABLED(CONFIG_PCI_IMX6))
writel(0xffffffff, ccm_base + CCGR4);
else

View File

@ -91,6 +91,7 @@ static int imx6_ccm_probe(struct device_d *dev)
int i;
struct device_node *ccm_node = dev->device_node;
anatop_base = IOMEM(MX6_ANATOP_BASE_ADDR);
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores))
return PTR_ERR(iores);
@ -100,8 +101,6 @@ static int imx6_ccm_probe(struct device_d *dev)
clks[IMX6UL_CLK_DUMMY] = clk_fixed("dummy", 0);
base = IOMEM(MX6_ANATOP_BASE_ADDR);
clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
clks[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
clks[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));

View File

@ -77,12 +77,6 @@ FILE_barebox-am33xx-phytec-phycore-mlo-2x512mb.spi.img = start_am33xx_phytec_phy
am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-2x512mb.img
am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-2x512mb.spi.img
pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_sram_1024mb
FILE_barebox-am33xx-phytec-phycore-mlo-1024mb.img = start_am33xx_phytec_phycore_sram_1024mb.pblx.mlo
FILE_barebox-am33xx-phytec-phycore-mlo-1024mb.spi.img = start_am33xx_phytec_phycore_sram_1024mb.pblx.mlospi
am33xx-mlo-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-1024mb.img
am33xx-mlospi-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += barebox-am33xx-phytec-phycore-mlo-1024mb.spi.img
pblx-$(CONFIG_MACH_PHYTEC_SOM_AM335X) += start_am33xx_phytec_phycore_r2_sram_1024mb
FILE_barebox-am33xx-phytec-phycore-r2-mlo-1024mb.img = start_am33xx_phytec_phycore_r2_sram_1024mb.pblx.mlo
FILE_barebox-am33xx-phytec-phycore-r2-mlo-1024mb.spi.img = start_am33xx_phytec_phycore_r2_sram_1024mb.pblx.mlospi

View File

@ -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

7
scripts/imx/Kconfig Normal file
View File

@ -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.

View File

@ -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");

View File

@ -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);

View File

@ -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;
}