scripts: Add imx-usb-loader tool
This adds host tools for i.MX to generate the i.MX internal flash header format and a tool to upload these images to an i.MX SoC via USB. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
2307901376
commit
134a788ac5
|
@ -256,6 +256,15 @@ ifeq ($(machine-y),zynq)
|
|||
KBUILD_IMAGE := barebox.zynq
|
||||
endif
|
||||
|
||||
CFG_barebox.imx := $(src)/arch/arm/boards/$(board-y)/flash-header.imxcfg
|
||||
barebox.imx: $(KBUILD_BINARY) FORCE
|
||||
$(call if_changed,imx_image)
|
||||
|
||||
ifeq ($(CONFIG_ARCH_IMX_INTERNAL_BOOT_USE_IMXIMAGE),y)
|
||||
KBUILD_TARGET := barebox.imx
|
||||
KBUILD_IMAGE := barebox.imx
|
||||
endif
|
||||
|
||||
pbl := arch/arm/pbl
|
||||
$(pbl)/zbarebox.S $(pbl)/zbarebox.bin $(pbl)/zbarebox: barebox.bin
|
||||
$(Q)$(MAKE) $(build)=$(pbl) $@
|
||||
|
|
|
@ -66,6 +66,7 @@ config BOARDINFO
|
|||
|
||||
choice
|
||||
prompt "Select boot mode"
|
||||
depends on !ARCH_IMX_INTERNAL_BOOT_USE_IMXIMAGE
|
||||
help
|
||||
i.MX processors support two different boot modes. With the internal
|
||||
boot mode the boot medium contains a header describing the image to
|
||||
|
@ -93,6 +94,21 @@ config ARCH_IMX_EXTERNAL_BOOT
|
|||
|
||||
endchoice
|
||||
|
||||
config ARCH_IMX_IMXIMAGE
|
||||
bool
|
||||
help
|
||||
if enabled the imx-image tool is compiled
|
||||
|
||||
config ARCH_IMX_INTERNAL_BOOT_USE_IMXIMAGE
|
||||
select ARCH_IMX_IMXIMAGE
|
||||
bool
|
||||
help
|
||||
Traditionally the i.MX specific format for internal bootmode
|
||||
was generated using C structs inside the binary. Now there is
|
||||
a tool available to generate the imx-image format. Boards using
|
||||
this tool must select this option. This is recommended for new
|
||||
boards.
|
||||
|
||||
choice
|
||||
depends on ARCH_IMX_INTERNAL_BOOT
|
||||
prompt "Internal boot source"
|
||||
|
@ -596,6 +612,13 @@ 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 && !ARCH_IMX21
|
||||
|
|
|
@ -13,6 +13,7 @@ hostprogs-$(CONFIG_ARCH_OMAP) += omap_signGP mk-am35xx-spi-image
|
|||
hostprogs-$(CONFIG_ARCH_S5PCxx) += s5p_cksum
|
||||
hostprogs-$(CONFIG_ARCH_DAVINCI) += mkublheader
|
||||
hostprogs-$(CONFIG_ARCH_ZYNQ) += zynq_mkimage
|
||||
subdir-$(CONFIG_ARCH_IMX) += imx
|
||||
|
||||
HOSTLOADLIBES_omap4_usbboot = -lpthread
|
||||
omap4_usbboot-objs := usb_linux.o omap4_usbboot.o
|
||||
|
|
|
@ -308,3 +308,28 @@ quiet_cmd_check_file_size = CHKSIZE $@
|
|||
echo "$@ size $$size > of the maximum size $$max_size" >&2; \
|
||||
exit 1 ; \
|
||||
fi;
|
||||
|
||||
quiet_cmd_imximage__S_dcd= DCD_S $@
|
||||
cmd_imximage_S_dcd= \
|
||||
( \
|
||||
echo '\#include <asm-generic/barebox.lds.h>'; \
|
||||
echo '.balign STRUCT_ALIGNMENT'; \
|
||||
echo '.global $(subst -,_,$(*F))_start'; \
|
||||
echo '$(subst -,_,$(*F))_start:'; \
|
||||
echo '.incbin "$<" '; \
|
||||
echo '$(subst -,_,$(*F))_end:'; \
|
||||
echo '.global $(subst -,_,$(*F))_end'; \
|
||||
echo '.balign STRUCT_ALIGNMENT'; \
|
||||
) > $@
|
||||
|
||||
quiet_cmd_dcd = DCD $@
|
||||
cmd_dcd = $(objtree)/scripts/imx/imx-image -d -o $@ -c $<
|
||||
|
||||
$(obj)/%.dcd: $(obj)/%.imxcfg FORCE
|
||||
$(call if_changed,dcd)
|
||||
|
||||
$(obj)/%.S: $(obj)/%.dcd
|
||||
$(call cmd,imximage_S_dcd)
|
||||
|
||||
quiet_cmd_imx_image = IMX-IMG $@
|
||||
cmd_imx_image = $(obj)/scripts/imx/imx-image -b -c $(CFG_$(@F)) -f $< -o $@
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
imx-usb-loader
|
||||
imx-image
|
|
@ -0,0 +1,10 @@
|
|||
hostprogs-$(CONFIG_ARCH_IMX_IMXIMAGE) += imx-image
|
||||
hostprogs-$(CONFIG_ARCH_IMX_USBLOADER) += imx-usb-loader
|
||||
|
||||
always := $(hostprogs-y)
|
||||
|
||||
HOSTCFLAGS_imx-usb-loader.o = `pkg-config --cflags libusb-1.0`
|
||||
HOSTLOADLIBES_imx-usb-loader = `pkg-config --libs libusb-1.0`
|
||||
|
||||
imx-usb-loader-objs := imx-usb-loader.o
|
||||
imx-image-objs := imx-image.o
|
|
@ -0,0 +1,89 @@
|
|||
imx-usb-loader Tools
|
||||
|
||||
The Freescale i.MX SoCs support bootstrapping from USB. These are host
|
||||
side utilities handling this bootstrap process.
|
||||
|
||||
The imx-usb-loader tool is used to upload and start i.MX images. These
|
||||
are images containing a DCD (Device Configuration Data) table. To generate
|
||||
these images from raw binaries use the imx-image tool.
|
||||
|
||||
imx-image
|
||||
---------
|
||||
|
||||
The imx-image tool can be used to generate imximages from raw binaries.
|
||||
It requires an configuration file describing how to setup the SDRAM on
|
||||
a particular board. This mainly consists of a poke table. The recognized
|
||||
options in this file are:
|
||||
|
||||
soc <soctype> soctype can be one of imx35, imx51, imx53, imx6
|
||||
loadaddr <adr> The address the binary is uploaded to
|
||||
dcdofs <ofs> The offset of the image header in the image. This should be:
|
||||
0x400 - MMC/SD, NAND, serial ROM, PATA, SATA
|
||||
0x1000 - NOR Flash
|
||||
0x100 - OneNAND
|
||||
wm 8 <adr> <value> do a byte memory write
|
||||
wm 16 <adr> <value> do a short memory write
|
||||
wm 32 <adr> <value> do a word memory write
|
||||
check <width> <cond> <addr> <mask> Poll until condition becomes true.
|
||||
with <cond> being one of:
|
||||
while_all_bits_clear,
|
||||
while_all_bits_set,
|
||||
while_any_bit_clear,
|
||||
while_any_bit_set
|
||||
|
||||
the i.MX SoCs support a wide range of fancy things doing with the flash header.
|
||||
We limit ourselves to a very simple case, that is the flash header has a fixed
|
||||
size of 0x1000 bytes. The application is expected right thereafter, so if you
|
||||
specify a loadaddr of 0x80000000 in the config file, the first 0x1000 bytes
|
||||
are occupied by the flash header. The raw image inside the imximage will then
|
||||
end up at 0x80001000 from where it is then executed.
|
||||
|
||||
Example config file, suitable for an Eukra cpuimx35:
|
||||
|
||||
soc imx35
|
||||
dcdofs 0x400
|
||||
loadaddr 0x80000000
|
||||
wm 32 0x53F80004 0x00821000
|
||||
wm 32 0x53F80004 0x00821000
|
||||
wm 32 0xb8001010 0x00000004
|
||||
wm 32 0xB8001010 0x0000000C
|
||||
wm 32 0xb8001004 0x0009572B
|
||||
wm 32 0xb8001000 0x92220000
|
||||
wm 8 0x80000400 0xda
|
||||
wm 32 0xb8001000 0xa2220000
|
||||
wm 32 0x80000000 0x12344321
|
||||
wm 32 0x80000000 0x12344321
|
||||
wm 32 0xb8001000 0xb2220000
|
||||
wm 8 0x80000033 0xda
|
||||
wm 8 0x82000000 0xda
|
||||
wm 32 0xb8001000 0x82224080
|
||||
wm 32 0xb8001010 0x00000004
|
||||
|
||||
example call:
|
||||
|
||||
imx-image -c cpuimx35.cfg -f raw.bin -o imximage.bin
|
||||
|
||||
imx-usb-loader
|
||||
--------------
|
||||
|
||||
This utility is used to upload an imximage to a board. Some bootloaders directly
|
||||
generate this file format, with others you can generate such an image with the
|
||||
imx-image tool. The only required argument is the image file to upload. imx-usb-loader
|
||||
will then look for a supported device, upload the file and execute it.
|
||||
|
||||
example usage:
|
||||
|
||||
imx-usb-loader imximage.bin
|
||||
|
||||
Some technical notes: The i.MX SoCs USB ROM boot mode supports doing register writes
|
||||
and file uploads. The files are usually uploaded to SDRAM. For this to work the SDRAM
|
||||
has to be initialized first. The information necessary to do this is contained in the
|
||||
imximage itself, more exactly in the DCD table. The imx-usb-loader parses this table
|
||||
and translates the DCD into register writes, basically it resembles what the i.MX would
|
||||
do in ROM code when the same image would be loaded from another bootsource like SD/MMC
|
||||
cards. Still the i.MX needs the DCD table to be uploaded. The i.MX would execute the DCD
|
||||
data again, which would result in corrupting the just configured SDRAM. The imx-usb-loader
|
||||
prevents this by setting the DCD length to 0x0 before uploading the image.
|
||||
The i.MX Boot ROM supports different types of images to upload. The imx-usb-loader currently
|
||||
only handles the simple case of uploading a single image which is executed right after
|
||||
downloading.
|
|
@ -0,0 +1,744 @@
|
|||
/*
|
||||
* (C) Copyright 2013 Sascha Hauer, Pengutronix
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <endian.h>
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
|
||||
|
||||
#define MAX_DCD 1024
|
||||
|
||||
static uint32_t image_load_addr;
|
||||
static uint32_t image_dcd_offset;
|
||||
static uint32_t dcdtable[MAX_DCD];
|
||||
static int curdcd;
|
||||
static int header_version;
|
||||
static int add_barebox_header;
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* i.MX flash header v1 handling. Found on i.MX35 and i.MX51
|
||||
* ============================================================================
|
||||
*/
|
||||
struct imx_flash_header {
|
||||
uint32_t app_code_jump_vector;
|
||||
uint32_t app_code_barker;
|
||||
uint32_t app_code_csf;
|
||||
uint32_t dcd_ptr_ptr;
|
||||
uint32_t super_root_key;
|
||||
uint32_t dcd;
|
||||
uint32_t app_dest;
|
||||
uint32_t dcd_barker;
|
||||
uint32_t dcd_block_len;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define FLASH_HEADER_OFFSET 0x400
|
||||
#define DCD_BARKER 0xb17219e9
|
||||
|
||||
static uint32_t bb_header[] = {
|
||||
0xea0003fe, /* b 0x1000 */
|
||||
0xeafffffe, /* 1: b 1b */
|
||||
0xeafffffe, /* 1: b 1b */
|
||||
0xeafffffe, /* 1: b 1b */
|
||||
0xeafffffe, /* 1: b 1b */
|
||||
0xeafffffe, /* 1: b 1b */
|
||||
0xeafffffe, /* 1: b 1b */
|
||||
0xeafffffe, /* 1: b 1b */
|
||||
0x65726162, /* 'bare' */
|
||||
0x00786f62, /* 'box\0' */
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x55555555,
|
||||
0x55555555,
|
||||
0x55555555,
|
||||
0x55555555,
|
||||
0x55555555,
|
||||
0x55555555,
|
||||
0x55555555,
|
||||
0x55555555,
|
||||
};
|
||||
|
||||
static int add_header_v1(void *buf, int offset, uint32_t loadaddr, uint32_t imagesize)
|
||||
{
|
||||
struct imx_flash_header *hdr;
|
||||
int dcdsize = curdcd * sizeof(uint32_t);
|
||||
|
||||
if (add_barebox_header)
|
||||
memcpy(buf, bb_header, sizeof(bb_header));
|
||||
|
||||
buf += offset;
|
||||
hdr = buf;
|
||||
|
||||
hdr->app_code_jump_vector = loadaddr + 0x1000;
|
||||
hdr->app_code_barker = 0x000000b1;
|
||||
hdr->app_code_csf = 0x0;
|
||||
hdr->dcd_ptr_ptr = loadaddr + offset + offsetof(struct imx_flash_header, dcd);
|
||||
hdr->super_root_key = 0x0;
|
||||
hdr->dcd = loadaddr + offset + offsetof(struct imx_flash_header, dcd_barker);
|
||||
hdr->app_dest = loadaddr;
|
||||
hdr->dcd_barker = DCD_BARKER;
|
||||
hdr->dcd_block_len = dcdsize;
|
||||
|
||||
buf += sizeof(struct imx_flash_header);
|
||||
|
||||
memcpy(buf, dcdtable, dcdsize);
|
||||
|
||||
buf += dcdsize;
|
||||
|
||||
*(uint32_t *)buf = imagesize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_mem_v1(uint32_t addr, uint32_t val, int width)
|
||||
{
|
||||
if (curdcd > MAX_DCD - 3) {
|
||||
fprintf(stderr, "At maximum %d dcd entried are allowed\n", MAX_DCD);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dcdtable[curdcd++] = width;
|
||||
dcdtable[curdcd++] = addr;
|
||||
dcdtable[curdcd++] = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* i.MX flash header v2 handling. Found on i.MX53 and i.MX6
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
struct imx_boot_data {
|
||||
uint32_t start;
|
||||
uint32_t size;
|
||||
uint32_t plugin;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define TAG_IVT_HEADER 0xd1
|
||||
#define IVT_VERSION 0x40
|
||||
#define TAG_DCD_HEADER 0xd2
|
||||
#define DCD_VERSION 0x40
|
||||
#define TAG_WRITE 0xcc
|
||||
#define TAG_CHECK 0xcf
|
||||
|
||||
struct imx_ivt_header {
|
||||
uint8_t tag;
|
||||
uint16_t length;
|
||||
uint8_t version;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct imx_flash_header_v2 {
|
||||
struct imx_ivt_header header;
|
||||
|
||||
uint32_t entry;
|
||||
uint32_t reserved1;
|
||||
uint32_t dcd_ptr;
|
||||
uint32_t boot_data_ptr;
|
||||
uint32_t self;
|
||||
uint32_t csf;
|
||||
uint32_t reserved2;
|
||||
|
||||
struct imx_boot_data boot_data;
|
||||
struct imx_ivt_header dcd_header;
|
||||
} __attribute__((packed));
|
||||
|
||||
static int add_header_v2(void *buf, int offset, uint32_t loadaddr, uint32_t imagesize)
|
||||
{
|
||||
struct imx_flash_header_v2 *hdr;
|
||||
int dcdsize = curdcd * sizeof(uint32_t);
|
||||
|
||||
if (add_barebox_header)
|
||||
memcpy(buf, bb_header, sizeof(bb_header));
|
||||
|
||||
buf += offset;
|
||||
hdr = buf;
|
||||
|
||||
hdr->header.tag = TAG_IVT_HEADER;
|
||||
hdr->header.length = htobe16(32);
|
||||
hdr->header.version = IVT_VERSION;
|
||||
|
||||
hdr->entry = loadaddr + 0x1000;
|
||||
hdr->dcd_ptr = loadaddr + 0x400 + offsetof(struct imx_flash_header_v2, dcd_header);
|
||||
hdr->boot_data_ptr = loadaddr + 0x400 + offsetof(struct imx_flash_header_v2, boot_data);
|
||||
hdr->self = loadaddr + 0x400;
|
||||
|
||||
hdr->boot_data.start = loadaddr;
|
||||
hdr->boot_data.size = imagesize;
|
||||
|
||||
hdr->dcd_header.tag = TAG_DCD_HEADER;
|
||||
hdr->dcd_header.length = htobe16(sizeof(uint32_t) + dcdsize);
|
||||
hdr->dcd_header.version = DCD_VERSION;
|
||||
|
||||
buf += sizeof(*hdr);
|
||||
|
||||
memcpy(buf, dcdtable, dcdsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage(const char *prgname)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [OPTIONS]\n\n"
|
||||
"-c <config> specify configuration file\n"
|
||||
"-f <input> input image file\n"
|
||||
"-o <output> output file\n"
|
||||
"-b add barebox header to image. If used, barebox recognizes\n"
|
||||
" the image as regular barebox image which can be used as\n"
|
||||
" second stage image\n"
|
||||
"-h this help\n", prgname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#define MAXARGS 5
|
||||
|
||||
static int parse_line(char *line, char *argv[])
|
||||
{
|
||||
int nargs = 0;
|
||||
|
||||
while (nargs < MAXARGS) {
|
||||
|
||||
/* skip any white space */
|
||||
while ((*line == ' ') || (*line == '\t'))
|
||||
++line;
|
||||
|
||||
if (*line == '\0') /* end of line, no more args */
|
||||
argv[nargs] = NULL;
|
||||
|
||||
if (*line == '\0') { /* end of line, no more args */
|
||||
argv[nargs] = NULL;
|
||||
return nargs;
|
||||
}
|
||||
|
||||
argv[nargs++] = line; /* begin of argument string */
|
||||
|
||||
/* find end of string */
|
||||
while (*line && (*line != ' ') && (*line != '\t'))
|
||||
++line;
|
||||
|
||||
if (*line == '\0') { /* end of line, no more args */
|
||||
argv[nargs] = NULL;
|
||||
return nargs;
|
||||
}
|
||||
|
||||
*line++ = '\0'; /* terminate current arg */
|
||||
}
|
||||
|
||||
printf("** Too many args (max. %d) **\n", MAXARGS);
|
||||
|
||||
return nargs;
|
||||
}
|
||||
|
||||
struct command {
|
||||
const char *name;
|
||||
int (*parse)(int argc, char *argv[]);
|
||||
};
|
||||
|
||||
static uint32_t last_cmd;
|
||||
static int last_cmd_len;
|
||||
static uint32_t *last_dcd;
|
||||
|
||||
static void check_last_dcd(uint32_t cmd)
|
||||
{
|
||||
if (last_dcd) {
|
||||
if (last_cmd == cmd) {
|
||||
return;
|
||||
} else {
|
||||
uint32_t l = be32toh(*last_dcd);
|
||||
|
||||
l |= last_cmd_len << 8;
|
||||
|
||||
*last_dcd = htobe32(l);
|
||||
|
||||
last_dcd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cmd)
|
||||
return;
|
||||
|
||||
if (!last_dcd) {
|
||||
last_dcd = &dcdtable[curdcd++];
|
||||
*last_dcd = htobe32(cmd);
|
||||
last_cmd_len = sizeof(uint32_t);
|
||||
last_cmd = cmd;
|
||||
}
|
||||
}
|
||||
|
||||
static int write_mem_v2(uint32_t addr, uint32_t val, int width)
|
||||
{
|
||||
uint32_t cmd;
|
||||
|
||||
cmd = (TAG_WRITE << 24) | width;
|
||||
|
||||
if (curdcd > MAX_DCD - 3) {
|
||||
fprintf(stderr, "At maximum %d dcd entried are allowed\n", MAX_DCD);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
check_last_dcd(cmd);
|
||||
|
||||
last_cmd_len += sizeof(uint32_t) * 2;
|
||||
dcdtable[curdcd++] = htobe32(addr);
|
||||
dcdtable[curdcd++] = htobe32(val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *check_cmds[] = {
|
||||
"while_all_bits_clear", /* while ((*address & mask) == 0); */
|
||||
"while_all_bits_set" , /* while ((*address & mask) == mask); */
|
||||
"while_any_bit_clear", /* while ((*address & mask) != mask); */
|
||||
"while_any_bit_set", /* while ((*address & mask) != 0); */
|
||||
};
|
||||
|
||||
static void do_cmd_check_usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: check <width> <cmd> <addr> <mask>\n"
|
||||
"<width> access width in bytes [1|2|4]\n"
|
||||
"with <cmd> one of:\n"
|
||||
"while_all_bits_clear: while ((*addr & mask) == 0)\n"
|
||||
"while_all_bits_set: while ((*addr & mask) == mask)\n"
|
||||
"while_any_bit_clear: while ((*addr & mask) != mask)\n"
|
||||
"while_any_bit_set: while ((*addr & mask) != 0)\n");
|
||||
}
|
||||
|
||||
static int do_cmd_check(int argc, char *argv[])
|
||||
{
|
||||
uint32_t addr, mask, cmd;
|
||||
int i, width;
|
||||
const char *scmd;
|
||||
|
||||
if (argc < 5) {
|
||||
do_cmd_check_usage();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
width = strtoul(argv[1], NULL, 0) >> 3;
|
||||
scmd = argv[2];
|
||||
addr = strtoul(argv[3], NULL, 0);
|
||||
mask = strtoul(argv[4], NULL, 0);
|
||||
|
||||
switch (width) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "illegal width %d\n", width);
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
if (curdcd > MAX_DCD - 3) {
|
||||
fprintf(stderr, "At maximum %d dcd entried are allowed\n", MAX_DCD);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(check_cmds); i++) {
|
||||
if (!strcmp(scmd, check_cmds[i]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(check_cmds)) {
|
||||
do_cmd_check_usage();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd = (TAG_CHECK << 24) | (i << 3) | width;
|
||||
|
||||
check_last_dcd(cmd);
|
||||
|
||||
last_cmd_len += sizeof(uint32_t) * 2;
|
||||
dcdtable[curdcd++] = htobe32(addr);
|
||||
dcdtable[curdcd++] = htobe32(mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_cmd_write_mem(int argc, char *argv[])
|
||||
{
|
||||
uint32_t addr, val, width;
|
||||
|
||||
if (argc != 4) {
|
||||
fprintf(stderr, "usage: wm [8|16|32] <addr> <val>\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
width = strtoul(argv[1], NULL, 0);
|
||||
addr = strtoul(argv[2], NULL, 0);
|
||||
val = strtoul(argv[3], NULL, 0);
|
||||
|
||||
width >>= 3;
|
||||
|
||||
switch (width) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "illegal width %d\n", width);
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
switch (header_version) {
|
||||
case 1:
|
||||
return write_mem_v1(addr, val, width);
|
||||
case 2:
|
||||
return write_mem_v2(addr, val, width);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_loadaddr(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
return -EINVAL;
|
||||
|
||||
image_load_addr = strtoul(argv[1], NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_dcd_offset(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
return -EINVAL;
|
||||
|
||||
image_dcd_offset = strtoul(argv[1], NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct soc_type {
|
||||
char *name;
|
||||
int header_version;
|
||||
};
|
||||
|
||||
static struct soc_type socs[] = {
|
||||
{ .name = "imx35", .header_version = 1, },
|
||||
{ .name = "imx51", .header_version = 1, },
|
||||
{ .name = "imx53", .header_version = 2, },
|
||||
{ .name = "imx6", .header_version = 2, },
|
||||
};
|
||||
|
||||
static int do_soc(int argc, char *argv[])
|
||||
{
|
||||
char *soc;
|
||||
int i;
|
||||
|
||||
if (argc < 2)
|
||||
return -EINVAL;
|
||||
|
||||
soc = argv[1];
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(socs); i++) {
|
||||
if (!strcmp(socs[i].name, soc)) {
|
||||
header_version = socs[i].header_version;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "unkown SoC type \"%s\". Known SoCs are:\n", soc);
|
||||
for (i = 0; i < ARRAY_SIZE(socs); i++)
|
||||
fprintf(stderr, "%s ", socs[i].name);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct command cmds[] = {
|
||||
{
|
||||
.name = "wm",
|
||||
.parse = do_cmd_write_mem,
|
||||
}, {
|
||||
.name = "check",
|
||||
.parse = do_cmd_check,
|
||||
}, {
|
||||
.name = "loadaddr",
|
||||
.parse = do_loadaddr,
|
||||
}, {
|
||||
.name = "dcdofs",
|
||||
.parse = do_dcd_offset,
|
||||
}, {
|
||||
.name = "soc",
|
||||
.parse = do_soc,
|
||||
},
|
||||
};
|
||||
|
||||
static int parse_config(const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
int lineno = 0;
|
||||
char *line = NULL, *tmp;
|
||||
size_t len;
|
||||
char *argv[MAXARGS];
|
||||
int nargs, i, ret;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (!f) {
|
||||
fprintf(stderr, "Error: %s - Can't open DCD file\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((getline(&line, &len, f)) > 0) {
|
||||
lineno++;
|
||||
|
||||
tmp = strchr(line, '#');
|
||||
if (tmp)
|
||||
*tmp = 0;
|
||||
tmp = strrchr(line, '\n');
|
||||
if (tmp)
|
||||
*tmp = 0;
|
||||
|
||||
nargs = parse_line(line, argv);
|
||||
if (!nargs)
|
||||
continue;
|
||||
|
||||
ret = -ENOENT;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cmds); i++) {
|
||||
if (!strcmp(cmds[i].name, argv[0])) {
|
||||
ret = cmds[i].parse(nargs, argv);
|
||||
if (ret) {
|
||||
fprintf(stderr, "error in line %d: %s\n",
|
||||
lineno, strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == -ENOENT) {
|
||||
fprintf(stderr, "no such command: %s\n", argv[0]);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xread(int fd, void *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (len) {
|
||||
ret = read(fd, buf, len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!ret)
|
||||
return EOF;
|
||||
buf += ret;
|
||||
len -= ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xwrite(int fd, void *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (len) {
|
||||
ret = write(fd, buf, len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
buf += ret;
|
||||
len -= ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_dcd(const char *outfile)
|
||||
{
|
||||
int outfd, ret;
|
||||
int dcdsize = curdcd * sizeof(uint32_t);
|
||||
|
||||
outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
if (outfd < 0) {
|
||||
perror("open");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = xwrite(outfd, dcdtable, dcdsize);
|
||||
if (ret < 0) {
|
||||
perror("write");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt, ret;
|
||||
char *configfile = NULL;
|
||||
char *imagename = NULL;
|
||||
char *outfile = NULL;
|
||||
void *buf;
|
||||
size_t image_size = 0;
|
||||
struct stat s;
|
||||
int infd, outfd;
|
||||
int dcd_only = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "c:hf:o:bd")) != -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
configfile = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
imagename = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
outfile = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
add_barebox_header = 1;
|
||||
break;
|
||||
case 'd':
|
||||
dcd_only = 1;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
default:
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!imagename && !dcd_only) {
|
||||
fprintf(stderr, "image name not given\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!configfile) {
|
||||
fprintf(stderr, "config file not given\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!outfile) {
|
||||
fprintf(stderr, "output file not given\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!dcd_only) {
|
||||
ret = stat(imagename, &s);
|
||||
if (ret) {
|
||||
perror("stat");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
image_size = s.st_size;
|
||||
}
|
||||
|
||||
ret = parse_config(configfile);
|
||||
if (ret)
|
||||
exit(1);
|
||||
|
||||
buf = calloc(4096, 1);
|
||||
if (!buf)
|
||||
exit(1);
|
||||
|
||||
if (!image_dcd_offset) {
|
||||
fprintf(stderr, "no dcd offset given ('dcdofs'). Defaulting to 0x400\n");
|
||||
image_dcd_offset = 0x400;
|
||||
}
|
||||
|
||||
if (!header_version) {
|
||||
fprintf(stderr, "no SoC given. (missing 'soc' in config)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (header_version == 2)
|
||||
check_last_dcd(0);
|
||||
|
||||
if (dcd_only) {
|
||||
ret = write_dcd(outfile);
|
||||
if (ret)
|
||||
exit(1);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
switch (header_version) {
|
||||
case 1:
|
||||
add_header_v1(buf, image_dcd_offset, image_load_addr, image_size + 0x1000);
|
||||
break;
|
||||
case 2:
|
||||
add_header_v2(buf, image_dcd_offset, image_load_addr, image_size + 0x1000);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Congratulations! You're welcome to implement header version %d\n",
|
||||
header_version);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
if (outfd < 0) {
|
||||
perror("open");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = xwrite(outfd, buf, 4096);
|
||||
if (ret < 0) {
|
||||
perror("write");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
infd = open(imagename, O_RDONLY);
|
||||
if (infd < 0) {
|
||||
perror("open");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (image_size) {
|
||||
int now = image_size < 4096 ? image_size : 4096;
|
||||
|
||||
ret = xread(infd, buf, now);
|
||||
if (ret) {
|
||||
perror("read");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = xwrite(outfd, buf, now);
|
||||
if (ret) {
|
||||
perror("write");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
image_size -= now;
|
||||
}
|
||||
|
||||
ret = close(outfd);
|
||||
if (ret) {
|
||||
perror("close");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue