ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/uboot/tools/.gitignore b/marvell/uboot/tools/.gitignore
new file mode 100644
index 0000000..cd2f041
--- /dev/null
+++ b/marvell/uboot/tools/.gitignore
@@ -0,0 +1,22 @@
+/bmp_logo
+/envcrc
+/gen_eth_addr
+/img2srec
+/kwboot
+/dumpimage
+/mkenvimage
+/mkimage
+/mpc86x_clk
+/mxsboot
+/ncb
+/proftool
+/relocate-rela
+/ubsha1
+/xway-swap-bytes
+/*.exe
+/easylogo/easylogo
+/env/crc32.c
+/env/fw_printenv
+/gdb/gdbcont
+/gdb/gdbsend
+/kernel-doc/docproc
diff --git a/marvell/uboot/tools/Makefile b/marvell/uboot/tools/Makefile
new file mode 100644
index 0000000..72f4ca6
--- /dev/null
+++ b/marvell/uboot/tools/Makefile
@@ -0,0 +1,332 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+TOOLSUBDIRS = kernel-doc
+
+#
+# Include this after HOSTOS HOSTARCH check
+# so that we can act intelligently.
+#
+include $(TOPDIR)/config.mk
+
+#
+# toolchains targeting win32 generate .exe files
+#
+ifneq (,$(findstring WIN32 ,$(shell $(HOSTCC) -E -dM -xc /dev/null)))
+SFX = .exe
+else
+SFX =
+endif
+
+# Enable all the config-independent tools
+ifneq ($(HOST_TOOLS_ALL),)
+CONFIG_LCD_LOGO = y
+CONFIG_CMD_LOADS = y
+CONFIG_CMD_NET = y
+CONFIG_XWAY_SWAP_BYTES = y
+CONFIG_NETCONSOLE = y
+CONFIG_SHA1_CHECK_UB_IMG = y
+endif
+
+# Merge all the different vars for envcrc into one
+ENVCRC-$(CONFIG_ENV_IS_EMBEDDED) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_DATAFLASH) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_EEPROM) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_FLASH) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_ONENAND) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_NAND) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_NVRAM) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_SPI_FLASH) = y
+CONFIG_BUILD_ENVCRC ?= $(ENVCRC-y)
+
+# Generated executable files
+BIN_FILES-$(CONFIG_LCD_LOGO) += bmp_logo$(SFX)
+BIN_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo$(SFX)
+BIN_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc$(SFX)
+BIN_FILES-$(CONFIG_CMD_NET) += gen_eth_addr$(SFX)
+BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX)
+BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX)
+BIN_FILES-y += dumpimage$(SFX)
+BIN_FILES-y += mkenvimage$(SFX)
+BIN_FILES-y += mkimage$(SFX)
+BIN_FILES-y += mbrgen$(SFX)
+BIN_FILES-$(CONFIG_EXYNOS5250) += mk$(BOARD)spl$(SFX)
+BIN_FILES-$(CONFIG_EXYNOS5420) += mk$(BOARD)spl$(SFX)
+BIN_FILES-$(CONFIG_MX23) += mxsboot$(SFX)
+BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX)
+BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
+BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
+BIN_FILES-$(CONFIG_KIRKWOOD) += kwboot$(SFX)
+BIN_FILES-y += proftool(SFX)
+BIN_FILES-$(CONFIG_STATIC_RELA) += relocate-rela$(SFX)
+
+# Source files which exist outside the tools directory
+EXT_OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += common/env_embedded.o
+EXT_OBJ_FILES-y += common/image.o
+EXT_OBJ_FILES-$(CONFIG_FIT) += common/image-fit.o
+EXT_OBJ_FILES-y += common/image-sig.o
+EXT_OBJ_FILES-y += lib/crc32.o
+EXT_OBJ_FILES-y += lib/md5.o
+EXT_OBJ_FILES-y += lib/sha1.o
+
+# Source files located in the tools directory
+NOPED_OBJ_FILES-y += aisimage.o
+NOPED_OBJ_FILES-y += default_image.o
+NOPED_OBJ_FILES-y += dumpimage.o
+NOPED_OBJ_FILES-y += fit_image.o
+NOPED_OBJ_FILES-y += image-host.o
+NOPED_OBJ_FILES-y += imximage.o
+NOPED_OBJ_FILES-y += kwbimage.o
+NOPED_OBJ_FILES-y += imagetool.o
+NOPED_OBJ_FILES-y += mkenvimage.o
+NOPED_OBJ_FILES-y += mkimage.o
+NOPED_OBJ_FILES-y += mxsimage.o
+NOPED_OBJ_FILES-y += mbrgen.o
+NOPED_OBJ_FILES-y += omapimage.o
+NOPED_OBJ_FILES-y += os_support.o
+NOPED_OBJ_FILES-y += pblimage.o
+NOPED_OBJ_FILES-y += proftool.o
+NOPED_OBJ_FILES-y += ublimage.o
+NOPED_OBJ_FILES-y += relocate-rela.o
+OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc.o
+OBJ_FILES-$(CONFIG_CMD_LOADS) += img2srec.o
+OBJ_FILES-$(CONFIG_CMD_NET) += gen_eth_addr.o
+OBJ_FILES-$(CONFIG_EXYNOS_SPL) += mkexynosspl.o
+OBJ_FILES-$(CONFIG_KIRKWOOD) += kwboot.o
+OBJ_FILES-$(CONFIG_LCD_LOGO) += bmp_logo.o
+OBJ_FILES-$(CONFIG_MX23) += mxsboot.o
+OBJ_FILES-$(CONFIG_MX28) += mxsboot.o
+OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o
+OBJ_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1.o
+OBJ_FILES-$(CONFIG_SMDK5250) += mkexynosspl.o
+OBJ_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo.o
+OBJ_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes.o
+
+# Don't build by default
+#ifeq ($(ARCH),ppc)
+#BIN_FILES-y += mpc86x_clk$(SFX)
+#OBJ_FILES-y += mpc86x_clk.o
+#endif
+
+# Flattened device tree objects
+LIBFDT_OBJ_FILES-y += fdt.o
+LIBFDT_OBJ_FILES-y += fdt_ro.o
+LIBFDT_OBJ_FILES-y += fdt_rw.o
+LIBFDT_OBJ_FILES-y += fdt_strerror.o
+LIBFDT_OBJ_FILES-y += fdt_wip.o
+
+# RSA objects
+RSA_OBJ_FILES-$(CONFIG_FIT_SIGNATURE) += rsa-sign.o
+
+# Generated LCD/video logo
+LOGO_H = $(OBJTREE)/include/bmp_logo.h
+LOGO_DATA_H = $(OBJTREE)/include/bmp_logo_data.h
+LOGO-$(CONFIG_LCD_LOGO) += $(LOGO_H)
+LOGO-$(CONFIG_LCD_LOGO) += $(LOGO_DATA_H)
+LOGO-$(CONFIG_VIDEO_LOGO) += $(LOGO_H)
+LOGO-$(CONFIG_VIDEO_LOGO) += $(LOGO_DATA_H)
+
+# Generic logo
+ifeq ($(LOGO_BMP),)
+LOGO_BMP= logos/denx.bmp
+
+# Use board logo and fallback to vendor
+ifneq ($(wildcard logos/$(BOARD).bmp),)
+LOGO_BMP= logos/$(BOARD).bmp
+else
+ifneq ($(wildcard logos/$(VENDOR).bmp),)
+LOGO_BMP= logos/$(VENDOR).bmp
+endif
+endif
+
+endif # !LOGO_BMP
+
+# now $(obj) is defined
+HOSTSRCS += $(addprefix $(SRCTREE)/,$(EXT_OBJ_FILES-y:.o=.c))
+HOSTSRCS += $(addprefix $(SRCTREE)/tools/,$(OBJ_FILES-y:.o=.c))
+HOSTSRCS += $(addprefix $(SRCTREE)/lib/libfdt/,$(LIBFDT_OBJ_FILES-y:.o=.c))
+HOSTSRCS += $(addprefix $(SRCTREE)/lib/rsa/,$(RSA_OBJ_FILES-y:.o=.c))
+BINS	:= $(addprefix $(obj),$(sort $(BIN_FILES-y)))
+LIBFDT_OBJS	:= $(addprefix $(obj),$(LIBFDT_OBJ_FILES-y))
+RSA_OBJS	:= $(addprefix $(obj),$(RSA_OBJ_FILES-y))
+
+# We cannot check CONFIG_FIT_SIGNATURE here since it is not set on the host
+FIT_SIG_OBJ_FILES	:= image-sig.o
+FIT_SIG_OBJS		:= $(addprefix $(obj),$(FIT_SIG_OBJ_FILES))
+
+HOSTOBJS := $(addprefix $(obj),$(OBJ_FILES-y))
+NOPEDOBJS := $(addprefix $(obj),$(NOPED_OBJ_FILES-y))
+
+#
+# Use native tools and options
+# Define __KERNEL_STRICT_NAMES to prevent typedef overlaps
+# Define _GNU_SOURCE to obtain the getline prototype from stdio.h
+#
+HOSTCPPFLAGS =	-include $(SRCTREE)/include/libfdt_env.h \
+		-idirafter $(SRCTREE)/include \
+		-idirafter $(SRCTREE)/arch/$(ARCH)/include \
+		-idirafter $(OBJTREE)/include \
+		-I $(SRCTREE)/lib/libfdt \
+		-I $(SRCTREE)/tools \
+		-DCONFIG_SYS_TEXT_BASE=$(CONFIG_SYS_TEXT_BASE) \
+		-DUSE_HOSTCC \
+		-D__KERNEL_STRICT_NAMES \
+		-D_GNU_SOURCE
+
+
+all:	$(obj).depend $(BINS) $(LOGO-y) subdirs
+
+$(obj)bin2header$(SFX): $(obj)bin2header.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)bmp_logo$(SFX):	$(obj)bmp_logo.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)proftool(SFX):	$(obj)proftool.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)envcrc$(SFX):	$(obj)crc32.o $(obj)env_embedded.o $(obj)envcrc.o $(obj)sha1.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+
+$(obj)gen_eth_addr$(SFX):	$(obj)gen_eth_addr.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)img2srec$(SFX):	$(obj)img2srec.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)xway-swap-bytes$(SFX):	$(obj)xway-swap-bytes.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)dumpimage$(SFX):	$(obj)aisimage.o \
+			$(FIT_SIG_OBJS) \
+			$(obj)crc32.o \
+			$(obj)default_image.o \
+			$(obj)fit_image.o \
+			$(obj)image-fit.o \
+			$(obj)image.o \
+			$(obj)image-host.o \
+			$(obj)imagetool.o \
+			$(obj)imximage.o \
+			$(obj)kwbimage.o \
+			$(obj)dumpimage.o \
+			$(obj)md5.o \
+			$(obj)mxsimage.o \
+			$(obj)omapimage.o \
+			$(obj)os_support.o \
+			$(obj)pblimage.o \
+			$(obj)sha1.o \
+			$(obj)ublimage.o \
+			$(LIBFDT_OBJS) \
+			$(RSA_OBJS)
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTLIBS)
+	$(HOSTSTRIP) $@
+
+$(obj)mkenvimage$(SFX):	$(obj)crc32.o $(obj)mkenvimage.o \
+	$(obj)os_support.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)mkimage$(SFX):	$(obj)aisimage.o \
+			$(FIT_SIG_OBJS) \
+			$(obj)crc32.o \
+			$(obj)default_image.o \
+			$(obj)fit_image.o \
+			$(obj)image-fit.o \
+			$(obj)image-host.o \
+			$(obj)image.o \
+			$(obj)imagetool.o \
+			$(obj)imximage.o \
+			$(obj)kwbimage.o \
+			$(obj)md5.o \
+			$(obj)mkimage.o \
+			$(obj)mxsimage.o \
+			$(obj)omapimage.o \
+			$(obj)os_support.o \
+			$(obj)pblimage.o \
+			$(obj)sha1.o \
+			$(obj)ublimage.o \
+			$(LIBFDT_OBJS) \
+			$(RSA_OBJS)
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTLIBS)
+	$(HOSTSTRIP) $@
+
+$(obj)mbrgen$(SFX):     $(obj)crc32.o $(obj)mbrgen.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)mk$(BOARD)spl$(SFX):	$(obj)mkexynosspl.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)mpc86x_clk$(SFX):	$(obj)mpc86x_clk.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)mxsboot$(SFX):	$(obj)mxsboot.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)ncb$(SFX):	$(obj)ncb.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)ubsha1$(SFX):	$(obj)os_support.o $(obj)sha1.o $(obj)ubsha1.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+
+$(obj)kwboot$(SFX): $(obj)kwboot.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+$(obj)relocate-rela$(SFX): $(obj)relocate-rela.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+# Some of the tool objects need to be accessed from outside the tools directory
+$(obj)%.o: $(SRCTREE)/common/%.c
+	$(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
+$(obj)%.o: $(SRCTREE)/lib/%.c
+	$(HOSTCC) -g $(HOSTCFLAGS) -c -o $@ $<
+
+$(obj)%.o: $(SRCTREE)/lib/libfdt/%.c
+	$(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
+$(obj)%.o: $(SRCTREE)/lib/rsa/%.c
+	$(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
+subdirs:
+ifeq ($(TOOLSUBDIRS),)
+	@:
+else
+	@for dir in $(TOOLSUBDIRS) ; do \
+	    $(MAKE) \
+		HOSTOS=$(HOSTOS) \
+		HOSTARCH=$(HOSTARCH) \
+		-C $$dir || exit 1 ; \
+	done
+endif
+
+$(LOGO_H):	$(obj)bmp_logo $(LOGO_BMP)
+	$(obj)./bmp_logo --gen-info $(LOGO_BMP) > $@
+
+$(LOGO_DATA_H):	$(obj)bmp_logo $(LOGO_BMP)
+	$(obj)./bmp_logo --gen-data $(LOGO_BMP) > $@
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/marvell/uboot/tools/aisimage.c b/marvell/uboot/tools/aisimage.c
new file mode 100644
index 0000000..8de370a
--- /dev/null
+++ b/marvell/uboot/tools/aisimage.c
@@ -0,0 +1,431 @@
+/*
+ * (C) Copyright 2011
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "imagetool.h"
+#include "aisimage.h"
+#include <image.h>
+
+#define IS_FNC_EXEC(c)	(cmd_table[c].AIS_cmd == AIS_CMD_FNLOAD)
+#define WORD_ALIGN0	4
+#define WORD_ALIGN(len) (((len)+WORD_ALIGN0-1) & ~(WORD_ALIGN0-1))
+#define MAX_CMD_BUFFER	4096
+
+static uint32_t ais_img_size;
+
+/*
+ * Supported commands for configuration file
+ */
+static table_entry_t aisimage_cmds[] = {
+	{CMD_DATA,		"DATA",		"Reg Write Data"},
+	{CMD_FILL,		"FILL",		"Fill range with pattern"},
+	{CMD_CRCON,		"CRCON",	"CRC Enable"},
+	{CMD_CRCOFF,		"CRCOFF",	"CRC Disable"},
+	{CMD_CRCCHECK,		"CRCCHECK",	"CRC Validate"},
+	{CMD_JMPCLOSE,		"JMPCLOSE",	"Jump & Close"},
+	{CMD_JMP,		"JMP",		"Jump"},
+	{CMD_SEQREAD,		"SEQREAD",	"Sequential read"},
+	{CMD_PLL0,		"PLL0",		"PLL0"},
+	{CMD_PLL1,		"PLL1",		"PLL1"},
+	{CMD_CLK,		"CLK",		"Clock configuration"},
+	{CMD_DDR2,		"DDR2",		"DDR2 Configuration"},
+	{CMD_EMIFA,		"EMIFA",	"EMIFA"},
+	{CMD_EMIFA_ASYNC,	"EMIFA_ASYNC",	"EMIFA Async"},
+	{CMD_PLL,		"PLL",		"PLL & Clock configuration"},
+	{CMD_PSC,		"PSC",		"PSC setup"},
+	{CMD_PINMUX,		"PINMUX",	"Pinmux setup"},
+	{CMD_BOOTTABLE,		"BOOT_TABLE",	"Boot table command"},
+	{-1,			"",		""},
+};
+
+static struct ais_func_exec {
+	uint32_t index;
+	uint32_t argcnt;
+} ais_func_table[] = {
+	[CMD_PLL0] = {0, 2},
+	[CMD_PLL1] = {1, 2},
+	[CMD_CLK] = {2, 1},
+	[CMD_DDR2] = {3, 8},
+	[CMD_EMIFA] = {4, 5},
+	[CMD_EMIFA_ASYNC] = {5, 5},
+	[CMD_PLL] = {6, 3},
+	[CMD_PSC] = {7, 1},
+	[CMD_PINMUX] = {8, 3}
+};
+
+static struct cmd_table_t {
+	uint32_t nargs;
+	uint32_t AIS_cmd;
+} cmd_table[] = {
+	[CMD_FILL]	 =	{	4,	AIS_CMD_FILL},
+	[CMD_CRCON]	=	{	0,	AIS_CMD_ENCRC},
+	[CMD_CRCOFF]	=	{	0,	AIS_CMD_DISCRC},
+	[CMD_CRCCHECK]	=	{	2,	AIS_CMD_ENCRC},
+	[CMD_JMPCLOSE]	=	{	1,	AIS_CMD_JMPCLOSE},
+	[CMD_JMP]	=	{	1,	AIS_CMD_JMP},
+	[CMD_SEQREAD]	=	{	0,	AIS_CMD_SEQREAD},
+	[CMD_PLL0]	=	{	2,	AIS_CMD_FNLOAD},
+	[CMD_PLL1]	=	{	2,	AIS_CMD_FNLOAD},
+	[CMD_CLK]	=	{	1,	AIS_CMD_FNLOAD},
+	[CMD_DDR2]	=	{	8,	AIS_CMD_FNLOAD},
+	[CMD_EMIFA]	=	{	5,	AIS_CMD_FNLOAD},
+	[CMD_EMIFA_ASYNC] =	{	5,	AIS_CMD_FNLOAD},
+	[CMD_PLL]	=	{	3,	AIS_CMD_FNLOAD},
+	[CMD_PSC]	=	{	1,	AIS_CMD_FNLOAD},
+	[CMD_PINMUX]	=	{	3,	AIS_CMD_FNLOAD},
+	[CMD_BOOTTABLE]	=	{	4,	AIS_CMD_BOOTTBL},
+};
+
+static uint32_t get_cfg_value(char *token, char *name,  int linenr)
+{
+	char *endptr;
+	uint32_t value;
+
+	errno = 0;
+	value = strtoul(token, &endptr, 16);
+	if (errno || (token == endptr)) {
+		fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n",
+			name,  linenr, token);
+		exit(EXIT_FAILURE);
+	}
+	return value;
+}
+
+static int get_ais_table_id(uint32_t *ptr)
+{
+
+	int i;
+	int func_no;
+
+	for (i = 0; i < ARRAY_SIZE(cmd_table); i++) {
+		if (*ptr == cmd_table[i].AIS_cmd) {
+			if (cmd_table[i].AIS_cmd != AIS_CMD_FNLOAD)
+				return i;
+
+			func_no = ((struct ais_cmd_func *)ptr)->func_args
+				& 0xFFFF;
+			if (func_no == ais_func_table[i].index)
+				return i;
+		}
+	}
+
+	return -1;
+}
+
+static void aisimage_print_header(const void *hdr)
+{
+	struct ais_header *ais_hdr = (struct ais_header *)hdr;
+	uint32_t *ptr;
+	struct ais_cmd_load *ais_load;
+	int id;
+
+	if (ais_hdr->magic != AIS_MAGIC_WORD) {
+		fprintf(stderr, "Error: - AIS Magic Number not found\n");
+		return;
+	}
+	fprintf(stdout, "Image Type:   TI Davinci AIS Boot Image\n");
+	fprintf(stdout, "AIS magic :   %08x\n", ais_hdr->magic);
+	ptr = (uint32_t *)&ais_hdr->magic;
+	ptr++;
+
+	while (*ptr != AIS_CMD_JMPCLOSE) {
+		/* Check if we find the image */
+		if (*ptr == AIS_CMD_LOAD) {
+			ais_load = (struct ais_cmd_load *)ptr;
+			fprintf(stdout, "Image at  :   0x%08x size 0x%08x\n",
+				ais_load->addr,
+				ais_load->size);
+			ptr = ais_load->data + ais_load->size / sizeof(*ptr);
+			continue;
+		}
+
+		id = get_ais_table_id(ptr);
+		if (id < 0) {
+			fprintf(stderr, "Error: -  AIS Image corrupted\n");
+			return;
+		}
+		fprintf(stdout, "AIS cmd   :   %s\n",
+			get_table_entry_name(aisimage_cmds, NULL, id));
+		ptr += cmd_table[id].nargs + IS_FNC_EXEC(id) + 1;
+		if (((void *)ptr - hdr) > ais_img_size) {
+			fprintf(stderr,
+				"AIS Image not terminated by JMPCLOSE\n");
+			return;
+		}
+	}
+}
+
+static uint32_t *ais_insert_cmd_header(uint32_t cmd, uint32_t nargs,
+	uint32_t *parms, struct image_type_params *tparams,
+	uint32_t *ptr)
+{
+	int i;
+
+	*ptr++ = cmd_table[cmd].AIS_cmd;
+	if (IS_FNC_EXEC(cmd))
+		*ptr++ = ((nargs & 0xFFFF) << 16) + ais_func_table[cmd].index;
+
+	/* Copy parameters */
+	for (i = 0; i < nargs; i++)
+		*ptr++ = cpu_to_le32(parms[i]);
+
+	return ptr;
+
+}
+
+static uint32_t *ais_alloc_buffer(struct image_tool_params *params)
+{
+	int dfd;
+	struct stat sbuf;
+	char *datafile = params->datafile;
+	uint32_t *ptr;
+
+	dfd = open(datafile, O_RDONLY|O_BINARY);
+	if (dfd < 0) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			params->cmdname, datafile, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf(stderr, "%s: Can't stat %s: %s\n",
+			params->cmdname, datafile, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * Place for header is allocated. The size is taken from
+	 * the size of the datafile, that the ais_image_generate()
+	 * will copy into the header. Copying the datafile
+	 * is not left to the main program, because after the datafile
+	 * the header must be terminated with the Jump & Close command.
+	 */
+	ais_img_size = WORD_ALIGN(sbuf.st_size) + MAX_CMD_BUFFER;
+	ptr = (uint32_t *)malloc(WORD_ALIGN(sbuf.st_size) + MAX_CMD_BUFFER);
+	if (!ptr) {
+		fprintf(stderr, "%s: malloc return failure: %s\n",
+			params->cmdname, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	close(dfd);
+
+	return ptr;
+}
+
+static uint32_t *ais_copy_image(struct image_tool_params *params,
+	uint32_t *aisptr)
+
+{
+	int dfd;
+	struct stat sbuf;
+	char *datafile = params->datafile;
+	void *ptr;
+
+	dfd = open(datafile, O_RDONLY|O_BINARY);
+	if (dfd < 0) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			params->cmdname, datafile, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf(stderr, "%s: Can't stat %s: %s\n",
+			params->cmdname, datafile, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+	*aisptr++ = AIS_CMD_LOAD;
+	*aisptr++ = params->ep;
+	*aisptr++ = sbuf.st_size;
+	memcpy((void *)aisptr, ptr, sbuf.st_size);
+	aisptr += WORD_ALIGN(sbuf.st_size) / sizeof(uint32_t);
+
+	(void) munmap((void *)ptr, sbuf.st_size);
+	(void) close(dfd);
+
+	return aisptr;
+
+}
+
+static int aisimage_generate(struct image_tool_params *params,
+	struct image_type_params *tparams)
+{
+	FILE *fd = NULL;
+	char *line = NULL;
+	char *token, *saveptr1, *saveptr2;
+	int lineno = 0;
+	int fld;
+	size_t len;
+	int32_t cmd;
+	uint32_t nargs, cmd_parms[10];
+	uint32_t value, size;
+	char *name = params->imagename;
+	uint32_t *aishdr;
+
+	fd = fopen(name, "r");
+	if (fd == 0) {
+		fprintf(stderr,
+			"Error: %s - Can't open AIS configuration\n", name);
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * the size of the header is variable and is computed
+	 * scanning the configuration file.
+	 */
+	tparams->header_size = 0;
+
+	/*
+	 * Start allocating a buffer suitable for most command
+	 * The buffer is then reallocated if it is too small
+	 */
+	aishdr = ais_alloc_buffer(params);
+	tparams->hdr = aishdr;
+	*aishdr++ = AIS_MAGIC_WORD;
+
+	/* Very simple parsing, line starting with # are comments
+	 * and are dropped
+	 */
+	while ((getline(&line, &len, fd)) > 0) {
+		lineno++;
+
+		token = strtok_r(line, "\r\n", &saveptr1);
+		if (token == NULL)
+			continue;
+
+		/* Check inside the single line */
+		line = token;
+		fld = CFG_COMMAND;
+		cmd = CMD_INVALID;
+		nargs = 0;
+		while (token != NULL) {
+			token = strtok_r(line, " \t", &saveptr2);
+			if (token == NULL)
+				break;
+
+			/* Drop all text starting with '#' as comments */
+			if (token[0] == '#')
+				break;
+
+			switch (fld) {
+			case CFG_COMMAND:
+				cmd = get_table_entry_id(aisimage_cmds,
+					"aisimage commands", token);
+				if (cmd < 0) {
+					fprintf(stderr,
+					"Error: %s[%d] - Invalid command"
+					"(%s)\n", name, lineno, token);
+
+					exit(EXIT_FAILURE);
+				}
+				break;
+			case CFG_VALUE:
+				value = get_cfg_value(token, name, lineno);
+				cmd_parms[nargs++] = value;
+				if (nargs > cmd_table[cmd].nargs) {
+					fprintf(stderr,
+					 "Error: %s[%d] - too much arguments:"
+						"(%s) for command %s\n", name,
+						lineno, token,
+						aisimage_cmds[cmd].sname);
+					exit(EXIT_FAILURE);
+				}
+				break;
+			}
+			line = NULL;
+			fld = CFG_VALUE;
+		}
+		if (cmd != CMD_INVALID) {
+			/* Now insert the command into the header */
+			aishdr = ais_insert_cmd_header(cmd, nargs, cmd_parms,
+				tparams, aishdr);
+		}
+
+	}
+	fclose(fd);
+
+	aishdr = ais_copy_image(params, aishdr);
+
+	/* Add Jmp & Close */
+	*aishdr++ = AIS_CMD_JMPCLOSE;
+	*aishdr++ = params->ep;
+
+	size = (aishdr - (uint32_t *)tparams->hdr) * sizeof(uint32_t);
+	tparams->header_size = size;
+
+	return 0;
+}
+
+static int aisimage_check_image_types(uint8_t type)
+{
+	if (type == IH_TYPE_AISIMAGE)
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+}
+
+static int aisimage_verify_header(unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	struct ais_header *ais_hdr = (struct ais_header *)ptr;
+
+	if (ais_hdr->magic != AIS_MAGIC_WORD)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	/* Store the total size to remember in print_hdr */
+	ais_img_size = image_size;
+
+	return 0;
+}
+
+static void aisimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+}
+
+int aisimage_check_params(struct image_tool_params *params)
+{
+	if (!params)
+		return CFG_INVALID;
+	if (!strlen(params->imagename)) {
+		fprintf(stderr, "Error: %s - Configuration file not specified, "
+			"it is needed for aisimage generation\n",
+			params->cmdname);
+		return CFG_INVALID;
+	}
+	/*
+	 * Check parameters:
+	 * XIP is not allowed and verify that incompatible
+	 * parameters are not sent at the same time
+	 * For example, if list is required a data image must not be provided
+	 */
+	return	(params->dflag && (params->fflag || params->lflag)) ||
+		(params->fflag && (params->dflag || params->lflag)) ||
+		(params->lflag && (params->dflag || params->fflag)) ||
+		(params->xflag) || !(strlen(params->imagename));
+}
+
+/*
+ * aisimage parameters
+ */
+static struct image_type_params aisimage_params = {
+	.name		= "TI Davinci AIS Boot Image support",
+	.header_size	= 0,
+	.hdr		= NULL,
+	.check_image_type = aisimage_check_image_types,
+	.verify_header	= aisimage_verify_header,
+	.print_header	= aisimage_print_header,
+	.set_header	= aisimage_set_header,
+	.check_params	= aisimage_check_params,
+	.vrec_header	= aisimage_generate,
+};
+
+void init_ais_image_type(void)
+{
+	register_image_type(&aisimage_params);
+}
diff --git a/marvell/uboot/tools/aisimage.h b/marvell/uboot/tools/aisimage.h
new file mode 100644
index 0000000..e1aa3ef
--- /dev/null
+++ b/marvell/uboot/tools/aisimage.h
@@ -0,0 +1,81 @@
+/*
+ * (C) Copyright 2011
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _AISIMAGE_H_
+#define _AISIMAGE_H_
+
+/* all values are for little endian systems */
+#define AIS_MAGIC_WORD	0x41504954
+#define AIS_FCN_MAX	8
+
+enum {
+	AIS_CMD_LOAD	= 0x58535901,
+	AIS_CMD_VALCRC	= 0x58535902,
+	AIS_CMD_ENCRC	= 0x58535903,
+	AIS_CMD_DISCRC	= 0x58535904,
+	AIS_CMD_JMP	= 0x58535905,
+	AIS_CMD_JMPCLOSE = 0x58535906,
+	AIS_CMD_BOOTTBL	= 0x58535907,
+	AIS_CMD_FILL	= 0x5853590A,
+	AIS_CMD_FNLOAD	= 0x5853590D,
+	AIS_CMD_SEQREAD	= 0x58535963,
+};
+
+struct ais_cmd_load {
+	uint32_t cmd;
+	uint32_t addr;
+	uint32_t size;
+	uint32_t data[1];
+};
+
+struct ais_cmd_func {
+	uint32_t cmd;
+	uint32_t func_args;
+	uint32_t parms[AIS_FCN_MAX];
+};
+
+struct ais_cmd_jmpclose {
+	uint32_t cmd;
+	uint32_t addr;
+};
+
+#define CMD_DATA_STR	"DATA"
+
+enum ais_file_cmd {
+	CMD_INVALID,
+	CMD_FILL,
+	CMD_CRCON,
+	CMD_CRCOFF,
+	CMD_CRCCHECK,
+	CMD_JMPCLOSE,
+	CMD_JMP,
+	CMD_SEQREAD,
+	CMD_DATA,
+	CMD_PLL0,
+	CMD_PLL1,
+	CMD_CLK,
+	CMD_DDR2,
+	CMD_EMIFA,
+	CMD_EMIFA_ASYNC,
+	CMD_PLL,
+	CMD_PSC,
+	CMD_PINMUX,
+	CMD_BOOTTABLE
+};
+
+enum aisimage_fld_types {
+	CFG_INVALID = -1,
+	CFG_COMMAND,
+	CFG_VALUE,
+};
+
+struct ais_header {
+	uint32_t magic;
+	char data[1];
+};
+
+#endif /* _AISIMAGE_H_ */
diff --git a/marvell/uboot/tools/bddb/README b/marvell/uboot/tools/bddb/README
new file mode 100644
index 0000000..9bee59a
--- /dev/null
+++ b/marvell/uboot/tools/bddb/README
@@ -0,0 +1,116 @@
+Hymod Board Database
+
+(C) Copyright 2001
+Murray Jensen <Murray.Jensen@csiro.au>
+CSIRO Manufacturing Science and Technology, Preston Lab
+
+25-Jun-01
+
+This stuff is a set of PHP/MySQL scripts to implement a custom board
+database. It will need *extensive* hacking to modify it to keep the
+information about your custom boards that you want, however it is a good
+starting point.
+
+How it is used:
+
+	1. a board has gone through all the hardware testing etc and is
+	   ready to have the flash programmed for the first time - first you
+	   go to a web page and fill in information about the board in a form
+	   to register it in a database
+
+	2. the web stuff allocates a (unique) serial number and (optionally)
+	   a (locally administered) ethernet address and stores the information
+	   in a database using the serial number as the key (can do whole
+	   batches of boards in one go and/or use a previously registered board
+	   as defaults for the new board(s))
+
+	3. it then creates a file in the tftp area of a server somewhere
+	   containing the board information in a simple text format (one
+	   per serial number)
+
+	4. all hymod boards have an i2c eeprom, and when U-Boot sees that
+	   the eeprom is unitialised, it prompts for a serial number and
+	   ethernet address (if not set), then transfers the file created
+	   in step 3 from the server and initialises the eeprom from its
+	   contents
+
+What this means is you can't boot the board until you have allocated a serial
+number, but you don't have to type it all twice - you do it once on the web
+and the board then finds the info it needs to initialise its eeprom. The
+other side of the coin is the reading of the eeprom and how it gets passed
+to Linux (or another O/S).
+
+To see how this is all done for the hymod boards look at the code in the
+"board/hymod" directory and in the file "include/asm/hymod.h". Hymod boards
+can have a mezzanine card which also have an eeprom that needs allocating,
+the same process is used for these as well - just a different i2c address.
+
+Other forms provide the following functions:
+
+	- browsing the board database
+	- editing board information (one at a time)
+	- maintaining/browsing a (simple) per board event log
+
+You will need: MySQL (I use version 3.23.7-alpha), PHP4 (with MySQL
+support enabled) and a web server (I use Apache 1.3.x).
+
+I originally started by using phpMyBuilder (http://kyber.dk/phpMyBuilder)
+but it soon got far more complicated than that could handle (but I left
+the copyright messages in there anyway). Most of the code resides in the
+common defs.php file, which shouldn't need much alteration - all the work
+will be in shaping the front-end php files to your liking.
+
+Here's a quick summary of what needs doing to use it for your boards:
+
+1. get phpMyAdmin (http://phpwizard.net/projects/phpMyAdmin/) - it's an
+   invaluable tool for this sort of stuff (this step is optional of course)
+
+2. edit "bddb.css" to your taste, if you could be bothered - I have no
+   idea what is in there or what it does - I copied it from somewhere else
+   ("user.css" from the phpMyEdit (http://phpmyedit.sourcerforge.net) package,
+   I think) - I figure one day I'll see what sort of things I can change
+   in there.
+
+3. create a mysql database - call it whatever you like
+
+4. edit "create_tables.sql" and modify the "boards" table schema to
+   reflect the information you want to keep about your boards. It may or
+   may not be easier to do this and the next step in phpMyAdmin. Check out
+   the MySQL documentation at http://www.mysql.com/doc/ in particular the
+   column types at http://www.mysql.com/doc/C/o/Column_types.html - Note
+   there is only support for a few data types:
+
+	int		- presented as an html text input
+	char/text	- presented as an html text input
+	date		- presented as an html text input
+	enum		- presented as an html radio input
+
+   I also have what I call "enum_multi" which is a set of enums with the
+   same name, but suffixed with a number e.g. fred0, fred1, fred2. These
+   are presented as a number of html select's with a single label "fred"
+   this is useful for board characteristics that have multiple items of
+   the same type e.g. multiple banks of sdram.
+
+5. use the "create_tables.sql" file to create the "boards" table in the
+   database e.g. mysql dbname < create_tables.sql
+
+6. create a user and password for the web server to log into the MySQL
+   database with; give this user select, insert and update privileges
+   to the database created in 3 (and delete, if you want the "delete"
+   functions in the edit forms to work- I have this turned off). phpMyAdmin
+   helps in this step.
+
+7. edit "config.php" and set the variables: $mysql_user, $mysql_pw, $mysql_db,
+   $bddb_cfgdir and $bddb_label - keep the contents of this file secret - it
+   contains the web servers username and password (the three $mysql_* vars
+   are set from the previous step)
+
+8. edit "defs.php" and a. adjust the various enum value arrays and b. edit
+   the function "pg_foot()" to remove my email address :-)
+
+9. do major hacking on the following files: browse.php, doedit.php, donew.php,
+   edit.php and new.php to reflect your database schema - fortunately the
+   hacking is fairly straight-forward, but it is boring and time-consuming.
+
+These notes were written rather hastily - if you find any obvious problems
+please let me know.
diff --git a/marvell/uboot/tools/bddb/badsubmit.php b/marvell/uboot/tools/bddb/badsubmit.php
new file mode 100644
index 0000000..5092a31
--- /dev/null
+++ b/marvell/uboot/tools/bddb/badsubmit.php
@@ -0,0 +1,23 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	require("defs.php");
+	pg_head("$bddb_label - Unknown Submit Type");
+?>
+<center>
+  <font size="+4">
+    <b>
+      The <?php echo "$bddb_label"; ?> form was submitted with an
+      unknown SUBMIT type <?php echo "(value was '$submit')" ?>.
+      <br></br>
+      Perhaps you typed the URL in directly? Click here to go to the
+      home page of the <a href="index.php"><?php echo "$bddb_label"; ?></a>.
+    </b>
+  </font>
+</center>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/bddb.css b/marvell/uboot/tools/bddb/bddb.css
new file mode 100644
index 0000000..dee2b2e
--- /dev/null
+++ b/marvell/uboot/tools/bddb/bddb.css
@@ -0,0 +1,207 @@
+BODY {
+	background:	#e0ffff;
+	color:		#000000;
+	font-family:	Arial, Verdana,	Helvetica;
+}
+H1 {
+	font-family:	"Copperplate Gothic Bold";
+	background:	transparent;
+	color:		#993300;
+	text-align:	center;
+}
+H2, H3, H4, H5 {
+	background:	transparent;
+	color:		#993300;
+	margin-top:	4%;
+	text-align:	center;
+}
+Body.Plain Div.Abstract, Body.Plain P.Abstract {
+	background:	#cccc99;
+	color:		#333300;
+	border:		white;
+	padding:	3%;
+	font-family:	Times, Verdana;
+}
+TH.Nav {
+	background:	#0000cc;
+	color:		#ff9900;
+}
+TH.Menu	{
+	background:	#3366cc;
+	color:		#ff9900;
+}
+A:hover	{
+	color:		#ff6600;
+}
+A.Menu:hover {
+	color:		#ff6600;
+}
+A.HoMe:hover {
+	color:		#ff6600;
+}
+A.Menu {
+	background:	transparent;
+	color:		#ffcc33;
+	font-family:	Verdana, Helvetica, Arial;
+	font-size:	smaller;
+	text-decoration:	none;
+}
+A.Menu:visited {
+	background:	transparent;
+	color:		#ffcc99;
+}
+A.HoMe {
+	background:	transparent;
+	color:		#ffcc33;
+	font-family:	Verdana, Helvetica, Arial;
+	text-decoration:none;
+}
+A.HoMe:visited {
+	background:	transparent;
+	color:		#ffcc99;
+}
+TH.Xmp {
+	background:	#eeeeee;
+	color:		#330066;
+	font-family:	courier;
+	font-weight:	normal;
+}
+TH.LuT {
+	background:	#cccccc;
+	color:	#000000;
+}
+TD.LuT {
+	background:	#ffffcc;
+	color:		#000000;
+	font-size:	85%;
+}
+TH.Info, TD.Info {
+	background:	#ffffcc;
+	color:		#660000;
+	font-family:	"Comic Sans MS", Cursive, Verdana;
+	font-size:	smaller;
+}
+Div.Info, P.Info {
+	background:	#ffff99;
+	color:		#990033;
+	text-align:	left;
+	padding:	2%;
+	font-family:	"Comic Sans MS", Cursive, Verdana;
+	font-size:	85%;
+	}
+Div.Info A {
+	background:	transparent;
+	color:		#ff6600;
+}
+.HL {
+	background:	#ffff99;
+	color:		#000000;
+}
+TD.HL {
+	background:	#ccffff;
+	color:		#000000;
+}
+Div.Margins {
+	width:		512px;
+	text-align:	center;
+}
+TD.Plain {
+	background:	#ffffcc;
+	color:		#000033;
+}
+.Type {
+	background:	#cccccc;
+	color:		#660000;
+}
+.Name {
+	background:	#eeeeee;
+	color:		#660000;
+	vertical-align:	top;
+	text-align:	right;
+}
+.Value {
+	background:	#ffffee;
+	color:		#000066;
+}
+.Drop {
+	background:	#333366;
+	color:		#ffcc33;
+	font-family:	"Copperplate Gothic Light", Helvetica, Verdana, Arial;
+}
+A.Button:hover {
+	color:		#ff6600;
+}
+A.Button {
+	text-decoration:none;
+	color:		#003366;
+	background:	#ffcc66;
+}
+.Button {
+	font-size:	9pt;
+	text-align:	center;
+	text-decoration:none;
+	color:		#003366;
+	background:	#ffcc66;
+	margin-bottom:	2pt;
+	border-top:	2px solid #ffff99;
+	border-left:	2px solid #ffff99;
+	border-right:	2px solid #cc9933;
+	border-bottom:	2px solid #cc9933;
+	font-family:	Verdana, Arial, "Comic Sans MS";
+}
+.Banner	{
+	width:		468;
+	font-size:	12pt;
+	text-align:	center;
+	text-decoration:none;
+	color:		#003366;
+	background:	#ffcc66;
+	border-top:	4px solid #ffff99;
+	border-left:	4px solid #ffff99;
+	border-right:	4px solid #cc9933;
+	border-bottom:	4px solid #cc9933;
+	font-family:	Verdana, Arial, "Comic Sans MS";
+}
+TD.Nova, Body.Nova {
+	background:	#000000;
+	font-family:	"Times New Roman";
+	font-weight:	light;
+	color:		#ffcc00;
+}
+Body.Nova A.Button {
+	background:	gold;
+	color:		#003366;
+}
+Body.Nova A.Banner {
+	background:	transparent;
+	color:		#003366;
+}
+Body.Nova A {
+	background:	transparent;
+	text-decoration:none;
+	color:		#ffd766;
+}
+Body.Nova H1, Body.Nova H2, Body.Nova H3, Body.Nova H4 {
+	background:	transparent;
+	color:		white;
+	margin-top:	4%;
+	text-align:	center;
+	filter:		Blur(Add=1, Direction=0, Strength=8);
+}
+Body.Nova Div.Abstract {
+	background:	#000000;
+	color:		#ffffff;
+	font-family:	Times, Verdana;
+}
+Body.Nova A.Abstract {
+	background:	transparent;
+	color:		#ffeedd;
+}
+Body.Nova TH.LuT {
+	background:	black;
+	color:		#ffff99;
+}
+Body.Nova TD.LuT {
+	background:	navy;
+	color:		#ffff99;
+}
diff --git a/marvell/uboot/tools/bddb/brlog.php b/marvell/uboot/tools/bddb/brlog.php
new file mode 100644
index 0000000..fccfbd0
--- /dev/null
+++ b/marvell/uboot/tools/bddb/brlog.php
@@ -0,0 +1,109 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// list page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - Browse Board Log");
+
+	$serno=intval($serno);
+	if ($serno == 0)
+		die("serial number not specified or invalid!");
+
+	function print_cell($str) {
+		if ($str == '')
+			$str = '&nbsp;';
+		echo "\t<td>$str</td>\n";
+	}
+?>
+<table align=center border=1 cellpadding=10>
+<tr>
+<th>serno / edit</th>
+<th>ethaddr</th>
+<th>date</th>
+<th>batch</th>
+<th>type</th>
+<th>rev</th>
+<th>location</th>
+</tr>
+<?php
+	$r=mysql_query("select * from boards where serno=$serno");
+
+	while($row=mysql_fetch_array($r)){
+		foreach ($columns as $key) {
+			if (!key_in_array($key, $row))
+				$row[$key] = '';
+		}
+
+		echo "<tr>\n";
+		print_cell("<a href=\"edit.php?serno=$row[serno]\">$row[serno]</a>");
+		print_cell($row['ethaddr']);
+		print_cell($row['date']);
+		print_cell($row['batch']);
+		print_cell($row['type']);
+		print_cell($row['rev']);
+		print_cell($row['location']);
+		echo "</tr>\n";
+	}
+
+	mysql_free_result($r);
+?>
+</table>
+<hr></hr>
+<p></p>
+<?php
+	$limit=abs(isset($_REQUEST['limit'])?$_REQUEST['limit']:20);
+	$offset=abs(isset($_REQUEST['offset'])?$_REQUEST['offset']:0);
+	$lr=mysql_query("select count(*) as n from log where serno=$serno");
+	$lrow=mysql_fetch_array($lr);
+	if($lrow['n']>$limit){
+		$preoffset=max(0,$offset-$limit);
+		$postoffset=$offset+$limit;
+		echo "<table width=\"100%\">\n<tr align=center>\n";
+		printf("<td><%sa href=\"%s?submit=Log&serno=$serno&offset=%d\"><img border=0 alt=\"&lt;\" src=\"/icons/left.gif\"></a></td>\n", $offset>0?"":"no", $PHP_SELF, $preoffset);
+		printf("<td><%sa href=\"%s?submit=Log&serno=$serno&offset=%d\"><img border=0 alt=\"&gt;\" src=\"/icons/right.gif\"></a></td>\n", $postoffset<$lrow['n']?"":"no", $PHP_SELF, $postoffset);
+		echo "</tr>\n</table>\n";
+	}
+	mysql_free_result($lr);
+?>
+<table width="100%" border=1 cellpadding=10>
+<tr valign=top>
+<th>logno / edit</th>
+<th>date</th>
+<th>who</th>
+<th width="70%">details</th>
+</tr>
+<?php
+	$r=mysql_query("select * from log where serno=$serno order by logno limit $offset,$limit");
+
+	while($row=mysql_fetch_array($r)){
+		echo "<tr>\n";
+		print_cell("<a href=\"edlog.php?serno=$row[serno]&logno=$row[logno]\">$row[logno]</a>");
+		print_cell($row['date']);
+		print_cell($row['who']);
+		print_cell("<pre>" . urldecode($row['details']) . "</pre>");
+		echo "</tr>\n";
+	}
+
+	mysql_free_result($r);
+?>
+</table>
+<hr></hr>
+<p></p>
+<table width="100%">
+<tr>
+  <td align=center>
+    <a href="newlog.php?serno=<?php echo "$serno"; ?>">Add to Log</a>
+  </td>
+  <td align=center>
+    <a href="index.php">Back to Start</a>
+  </td>
+</tr>
+</table>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/browse.php b/marvell/uboot/tools/bddb/browse.php
new file mode 100644
index 0000000..675dfab
--- /dev/null
+++ b/marvell/uboot/tools/bddb/browse.php
@@ -0,0 +1,147 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// list page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	$serno=isset($_REQUEST['serno'])?$_REQUEST['serno']:'';
+
+	$verbose=isset($_REQUEST['verbose'])?intval($_REQUEST['verbose']):0;
+
+	pg_head("$bddb_label - Browse database" . ($verbose?" (verbose)":""));
+?>
+<p></p>
+<?php
+	$limit=isset($_REQUEST['limit'])?abs(intval($_REQUEST['limit'])):20;
+	$offset=isset($_REQUEST['offset'])?abs(intval($_REQUEST['offset'])):0;
+
+	if ($serno == '') {
+
+		$lr=mysql_query("select count(*) as n from boards");
+		$lrow=mysql_fetch_array($lr);
+
+		if($lrow['n']>$limit){
+			$preoffset=max(0,$offset-$limit);
+			$postoffset=$offset+$limit;
+			echo "<table width=\"100%\">\n<tr>\n";
+			printf("<td align=left><%sa href=\"%s?submit=Browse&offset=%d&verbose=%d\"><img border=0 alt=\"&lt;\" src=\"/icons/left.gif\"></a></td>\n", $offset>0?"":"no", $PHP_SELF, $preoffset, $verbose);
+			printf("<td align=right><%sa href=\"%s?submit=Browse&offset=%d&verbose=%d\"><img border=0 alt=\"&gt;\" src=\"/icons/right.gif\"></a></td>\n", $postoffset<$lrow['n']?"":"no", $PHP_SELF, $postoffset, $offset);
+			echo "</tr>\n</table>\n";
+		}
+
+		mysql_free_result($lr);
+	}
+?>
+<table align=center border=1 cellpadding=10>
+<tr>
+<th></th>
+<th>serno / edit</th>
+<th>ethaddr</th>
+<th>date</th>
+<th>batch</th>
+<th>type</th>
+<th>rev</th>
+<th>location</th>
+<?php
+	if ($verbose) {
+		echo "<th>comments</th>\n";
+		echo "<th>sdram</th>\n";
+		echo "<th>flash</th>\n";
+		echo "<th>zbt</th>\n";
+		echo "<th>xlxtyp</th>\n";
+		echo "<th>xlxspd</th>\n";
+		echo "<th>xlxtmp</th>\n";
+		echo "<th>xlxgrd</th>\n";
+		echo "<th>cputyp</th>\n";
+		echo "<th>cpuspd</th>\n";
+		echo "<th>cpmspd</th>\n";
+		echo "<th>busspd</th>\n";
+		echo "<th>hstype</th>\n";
+		echo "<th>hschin</th>\n";
+		echo "<th>hschout</th>\n";
+	}
+?>
+</tr>
+<?php
+	$query = "select * from boards";
+	if ($serno != '') {
+		$pre = " where ";
+		foreach (preg_split("/[\s,]+/", $serno) as $s) {
+			if (preg_match('/^[0-9]+$/',$s))
+				$query .= $pre . "serno=" . $s;
+			else if (preg_match('/^([0-9]+)-([0-9]+)$/',$s,$m)) {
+				$m1 = intval($m[1]); $m2 = intval($m[2]);
+				if ($m2 <= $m1)
+					die("bad serial number range ($s)");
+				$query .= $pre . "(serno>=$m[1] and serno<=$m[2])";
+			}
+			else
+				die("illegal serial number ($s)");
+			$pre = " or ";
+		}
+	}
+	$query .= " order by serno";
+	if ($serno == '')
+		$query .= " limit $offset,$limit";
+
+	$r = mysql_query($query);
+
+	function print_cell($str) {
+		if ($str == '')
+			$str = '&nbsp;';
+		echo "\t<td>$str</td>\n";
+	}
+
+	while($row=mysql_fetch_array($r)){
+		foreach ($columns as $key) {
+			if (!key_in_array($key, $row))
+				$row[$key] = '';
+		}
+
+		echo "<tr>\n";
+		print_cell("<a href=\"brlog.php?serno=$row[serno]\">Log</a>");
+		print_cell("<a href=\"edit.php?serno=$row[serno]\">$row[serno]</a>");
+		print_cell($row['ethaddr']);
+		print_cell($row['date']);
+		print_cell($row['batch']);
+		print_cell($row['type']);
+		print_cell($row['rev']);
+		print_cell($row['location']);
+		if ($verbose) {
+			print_cell("<pre>\n" . urldecode($row['comments']) .
+				"\n\t</pre>");
+			print_cell(gather_enum_multi_print("sdram", 4, $row));
+			print_cell(gather_enum_multi_print("flash", 4, $row));
+			print_cell(gather_enum_multi_print("zbt", 16, $row));
+			print_cell(gather_enum_multi_print("xlxtyp", 4, $row));
+			print_cell(gather_enum_multi_print("xlxspd", 4, $row));
+			print_cell(gather_enum_multi_print("xlxtmp", 4, $row));
+			print_cell(gather_enum_multi_print("xlxgrd", 4, $row));
+			print_cell($row['cputyp']);
+			print_cell($row['cpuspd']);
+			print_cell($row['cpmspd']);
+			print_cell($row['busspd']);
+			print_cell($row['hstype']);
+			print_cell($row['hschin']);
+			print_cell($row['hschout']);
+		}
+		echo "</tr>\n";
+	}
+?>
+</table>
+<p></p>
+<table width="100%">
+<tr>
+  <td align=center><?php
+	printf("<a href=\"%s?submit=Browse&offset=%d&verbose=%d%s\">%s Listing</a>\n", $PHP_SELF, $offset, $verbose?0:1, $serno!=''?"&serno=$serno":'', $verbose?"Terse":"Verbose");
+  ?></td>
+  <td align=center><a href="index.php">Back to Start</a></td>
+</tr>
+</table>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/config.php b/marvell/uboot/tools/bddb/config.php
new file mode 100644
index 0000000..6725757
--- /dev/null
+++ b/marvell/uboot/tools/bddb/config.php
@@ -0,0 +1,16 @@
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// mysql database access info
+	$mysql_user="fred";
+	$mysql_pw="apassword";
+	$mysql_db="mydbname";
+
+	// where to put the eeprom config files
+	$bddb_cfgdir = '/tftpboot/bddb';
+
+	// what this database is called
+	$bddb_label = 'Hymod Board Database';
+?>
diff --git a/marvell/uboot/tools/bddb/create_tables.sql b/marvell/uboot/tools/bddb/create_tables.sql
new file mode 100644
index 0000000..a2a5788
--- /dev/null
+++ b/marvell/uboot/tools/bddb/create_tables.sql
@@ -0,0 +1,90 @@
+# phpMyAdmin MySQL-Dump
+# http://phpwizard.net/phpMyAdmin/
+#
+# Host: localhost Database : hymod_bddb
+
+# (C) Copyright 2001
+# Murray Jensen <Murray.Jensen@csiro.au>
+# CSIRO Manufacturing and Infrastructure Technology, Preston Lab
+
+# --------------------------------------------------------
+#
+# Table structure for table 'boards'
+#
+
+DROP TABLE IF EXISTS boards;
+CREATE TABLE boards (
+   serno int(10) unsigned zerofill NOT NULL auto_increment,
+   ethaddr char(17),
+   date date NOT NULL,
+   batch char(32),
+   type enum('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY') NOT NULL,
+   rev tinyint(3) unsigned zerofill NOT NULL,
+   location char(64),
+   comments text,
+   sdram0 enum('32M','64M','128M','256M','512M','1G','2G','4G'),
+   sdram1 enum('32M','64M','128M','256M','512M','1G','2G','4G'),
+   sdram2 enum('32M','64M','128M','256M','512M','1G','2G','4G'),
+   sdram3 enum('32M','64M','128M','256M','512M','1G','2G','4G'),
+   flash0 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'),
+   flash1 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'),
+   flash2 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'),
+   flash3 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'),
+   zbt0 enum('512K','1M','2M','4M','8M','16M'),
+   zbt1 enum('512K','1M','2M','4M','8M','16M'),
+   zbt2 enum('512K','1M','2M','4M','8M','16M'),
+   zbt3 enum('512K','1M','2M','4M','8M','16M'),
+   zbt4 enum('512K','1M','2M','4M','8M','16M'),
+   zbt5 enum('512K','1M','2M','4M','8M','16M'),
+   zbt6 enum('512K','1M','2M','4M','8M','16M'),
+   zbt7 enum('512K','1M','2M','4M','8M','16M'),
+   zbt8 enum('512K','1M','2M','4M','8M','16M'),
+   zbt9 enum('512K','1M','2M','4M','8M','16M'),
+   zbta enum('512K','1M','2M','4M','8M','16M'),
+   zbtb enum('512K','1M','2M','4M','8M','16M'),
+   zbtc enum('512K','1M','2M','4M','8M','16M'),
+   zbtd enum('512K','1M','2M','4M','8M','16M'),
+   zbte enum('512K','1M','2M','4M','8M','16M'),
+   zbtf enum('512K','1M','2M','4M','8M','16M'),
+   xlxtyp0 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'),
+   xlxtyp1 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'),
+   xlxtyp2 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'),
+   xlxtyp3 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'),
+   xlxspd0 enum('6','7','8','4','5','9','10','11','12'),
+   xlxspd1 enum('6','7','8','4','5','9','10','11','12'),
+   xlxspd2 enum('6','7','8','4','5','9','10','11','12'),
+   xlxspd3 enum('6','7','8','4','5','9','10','11','12'),
+   xlxtmp0 enum('COM','IND'),
+   xlxtmp1 enum('COM','IND'),
+   xlxtmp2 enum('COM','IND'),
+   xlxtmp3 enum('COM','IND'),
+   xlxgrd0 enum('NORMAL','ENGSAMP'),
+   xlxgrd1 enum('NORMAL','ENGSAMP'),
+   xlxgrd2 enum('NORMAL','ENGSAMP'),
+   xlxgrd3 enum('NORMAL','ENGSAMP'),
+   cputyp enum('MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)','MPC8560'),
+   cpuspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ'),
+   cpmspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ'),
+   busspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ'),
+   hstype enum('AMCC-S2064A','Xilinx-Rockets'),
+   hschin enum('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16'),
+   hschout enum('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16'),
+   PRIMARY KEY (serno),
+   KEY serno (serno),
+   UNIQUE serno_2 (serno)
+);
+
+#
+# Table structure for table 'log'
+#
+
+DROP TABLE IF EXISTS log;
+CREATE TABLE log (
+   logno int(10) unsigned zerofill NOT NULL auto_increment,
+   serno int(10) unsigned zerofill NOT NULL,
+   date date NOT NULL,
+   details text NOT NULL,
+   PRIMARY KEY (logno),
+   KEY logno (logno, serno, date),
+   UNIQUE logno_2 (logno)
+);
diff --git a/marvell/uboot/tools/bddb/defs.php b/marvell/uboot/tools/bddb/defs.php
new file mode 100644
index 0000000..0b50602
--- /dev/null
+++ b/marvell/uboot/tools/bddb/defs.php
@@ -0,0 +1,710 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// contains mysql user id and password - keep secret
+	require("config.php");
+
+	if (isset($_REQUEST['logout'])) {
+		Header("status: 401 Unauthorized");
+		Header("HTTP/1.0 401 Unauthorized");
+		Header("WWW-authenticate: basic realm=\"$bddb_label\"");
+
+		echo "<html><head><title>" .
+			"Access to '$bddb_label' Denied" .
+			"</title></head>\n";
+		echo "<body bgcolor=#ffffff><br></br><br></br><center><h1>" .
+			"You must be an Authorised User " .
+			"to access the '$bddb_label'" .
+			"</h1>\n</center></body></html>\n";
+		exit;
+	}
+
+	// contents of the various enumerated types - if first item is
+	// empty ('') then the enum is allowed to be null (ie "not null"
+	// is not set on the column)
+
+	// all column names in the database table
+	$columns = array(
+		'serno','ethaddr','date','batch',
+		'type','rev','location','comments',
+		'sdram0','sdram1','sdram2','sdram3',
+		'flash0','flash1','flash2','flash3',
+		'zbt0','zbt1','zbt2','zbt3','zbt4','zbt5','zbt6','zbt7',
+		'zbt8','zbt9','zbta','zbtb','zbtc','zbtd','zbte','zbtf',
+		'xlxtyp0','xlxtyp1','xlxtyp2','xlxtyp3',
+		'xlxspd0','xlxspd1','xlxspd2','xlxspd3',
+		'xlxtmp0','xlxtmp1','xlxtmp2','xlxtmp3',
+		'xlxgrd0','xlxgrd1','xlxgrd2','xlxgrd3',
+		'cputyp','cpuspd','cpmspd','busspd',
+		'hstype','hschin','hschout'
+	);
+
+	// board type
+	$type_vals = array('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY');
+
+	// Xilinx fpga types
+	$xlxtyp_vals = array('','XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140');
+
+	// Xilinx fpga speeds
+	$xlxspd_vals = array('','6','7','8','4','5','9','10','11','12');
+
+	// Xilinx fpga temperatures (commercial or industrial)
+	$xlxtmp_vals = array('','COM','IND');
+
+	// Xilinx fpga grades (normal or engineering sample)
+	$xlxgrd_vals = array('','NORMAL','ENGSAMP');
+
+	// CPU types
+	$cputyp_vals = array('','MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)','MPC8560');
+
+	// CPU/BUS/CPM clock speeds 
+	$clk_vals = array('','33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ');
+
+	// sdram sizes (nbits array is for eeprom config file)
+	$sdram_vals = array('','32M','64M','128M','256M','512M','1G','2G','4G');
+	$sdram_nbits = array(0,25,26,27,28,29,30,31,32);
+
+	// flash sizes (nbits array is for eeprom config file)
+	$flash_vals = array('','4M','8M','16M','32M','64M','128M','256M','512M','1G');
+	$flash_nbits = array(0,22,23,24,25,26,27,28,29,30);
+
+	// zbt ram sizes (nbits array is for write into eeprom config file)
+	$zbt_vals = array('','512K','1M','2M','4M','8M','16M');
+	$zbt_nbits = array(0,19,20,21,22,23,24);
+
+	// high-speed serial attributes
+	$hstype_vals = array('','AMCC-S2064A','Xilinx-Rockets');
+	$hschin_vals = array('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16');
+	$hschout_vals = array('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16');
+
+	// value filters - used when outputting html
+	function rev_filter($num) {
+		if ($num == 0)
+			return "001";
+		else
+			return sprintf("%03d", $num);
+	}
+
+	function text_filter($str) {
+		return urldecode($str);
+	}
+
+	mt_srand(time() | getmypid());
+
+	// set up MySQL connection
+	mysql_connect("", $mysql_user, $mysql_pw) || die("cannot connect");
+	mysql_select_db($mysql_db) || die("cannot select db");
+
+	// page header
+	function pg_head($title)
+	{
+		echo "<html>\n<head>\n";
+		echo "<link rel=stylesheet href=\"bddb.css\" type=\"text/css\" title=\"style sheet\"></link>\n";
+		echo "<title>$title</title>\n";
+		echo "</head>\n";
+		echo "<body>\n";
+		echo "<center><h1>$title</h1></center>\n";
+		echo "<hr></hr>\n";
+	}
+
+	// page footer
+	function pg_foot()
+	{
+		echo "<hr></hr>\n";
+		echo "<table width=\"100%\"><tr><td align=left>\n<address>" .
+			"If you have any problems, email " .
+			"<a href=\"mailto:Murray.Jensen@csiro.au\">" .
+			"Murray Jensen" .
+			"</a></address>\n" .
+			"</td><td align=right>\n" .
+			"<a href=\"index.php?logout=true\">logout</a>\n" .
+			"</td></tr></table>\n";
+		echo "<p><small><i>Made with " .
+		    "<a href=\"http://kyber.dk/phpMyBuilder/\">" .
+		    "Kyber phpMyBuilder</a></i></small></p>\n";
+		echo "</body>\n";
+		echo "</html>\n";
+	}
+
+	// some support functions
+
+	if (!function_exists('array_search')) {
+
+		function array_search($needle, $haystack, $strict = false) {
+
+			if (is_array($haystack) && count($haystack)) {
+
+				$ntype = gettype($needle);
+
+				foreach ($haystack as $key => $value) {
+
+					if ($value == $needle && (!$strict ||
+					    gettype($value) == $ntype))
+						return $key;
+				}
+			}
+
+			return false;
+		}
+	}
+
+	if (!function_exists('in_array')) {
+
+		function in_array($needle, $haystack, $strict = false) {
+
+			if (is_array($haystack) && count($haystack)) {
+
+				$ntype = gettype($needle);
+
+				foreach ($haystack as $key => $value) {
+
+					if ($value == $needle && (!$strict ||
+					    gettype($value) == $ntype))
+						return true;
+				}
+			}
+
+			return false;
+		}
+	}
+
+	function key_in_array($key, $array) {
+		return in_array($key, array_keys($array), true);
+	}
+
+	function enum_to_index($name, $vals) {
+		$index = array_search($GLOBALS[$name], $vals);
+		if ($vals[0] != '')
+			$index++;
+		return $index;
+	}
+
+	// fetch a value from an array - return empty string is not present
+	function get_key_value($key, $array) {
+		if (key_in_array($key, $array))
+			return $array[$key];
+		else
+			return '';
+	}
+
+	function fprintf() {
+		$n = func_num_args();
+		if ($n < 2)
+			return FALSE;
+		$a = func_get_args();
+		$fp = array_shift($a);
+		$x = "\$s = sprintf";
+		$sep = '(';
+		foreach ($a as $z) {
+			$x .= "$sep'$z'";
+			$sep = ',';
+		}
+		$x .= ');';
+		eval($x);
+		$l = strlen($s);
+		$r = fwrite($fp, $s, $l);
+		if ($r != $l)
+			return FALSE;
+		else
+			return TRUE;
+	}
+
+	// functions to display (print) a database table and its columns
+
+	function begin_table($ncols) {
+		global $table_ncols;
+		$table_ncols = $ncols;
+		echo "<table align=center width=\"100%\""
+			. " border=1 cellpadding=4 cols=$table_ncols>\n";
+	}
+
+	function begin_field($name, $span = 0) {
+		global $table_ncols;
+		echo "<tr valign=top>\n";
+		echo "\t<th align=center>$name</th>\n";
+		if ($span <= 0)
+			$span = $table_ncols - 1;
+		if ($span > 1)
+			echo "\t<td colspan=$span>\n";
+		else
+			echo "\t<td>\n";
+	}
+
+	function cont_field($span = 1) {
+		echo "\t</td>\n";
+		if ($span > 1)
+			echo "\t<td colspan=$span>\n";
+		else
+			echo "\t<td>\n";
+	}
+
+	function end_field() {
+		echo "\t</td>\n";
+		echo "</tr>\n";
+	}
+
+	function end_table() {
+		echo "</table>\n";
+	}
+
+	function print_field($name, $array, $size = 0, $filt='') {
+
+		begin_field($name);
+
+		if (key_in_array($name, $array))
+			$value = $array[$name];
+		else
+			$value = '';
+
+		if ($filt != '')
+			$value = $filt($value);
+
+		echo "\t\t<input name=$name value=\"$value\"";
+		if ($size > 0)
+			echo " size=$size maxlength=$size";
+		echo "></input>\n";
+
+		end_field();
+	}
+
+	function print_field_multiline($name, $array, $cols, $rows, $filt='') {
+
+		begin_field($name);
+
+		if (key_in_array($name, $array))
+			$value = $array[$name];
+		else
+			$value = '';
+
+		if ($filt != '')
+			$value = $filt($value);
+
+		echo "\t\t<textarea name=$name " .
+			"cols=$cols rows=$rows wrap=off>\n";
+		echo "$value";
+		echo "</textarea>\n";
+
+		end_field();
+	}
+
+	// print a mysql ENUM as an html RADIO INPUT
+	function print_enum($name, $array, $vals, $def = -1) {
+
+		begin_field($name);
+
+		if (key_in_array($name, $array))
+			$chk = array_search($array[$name], $vals, FALSE);
+		else
+			$chk = $def;
+
+		$nval = count($vals);
+
+		for ($i = 0; $i < $nval; $i++) {
+
+			$val = $vals[$i];
+			if ($val == '')
+				$pval = "none";
+			else
+				$pval = "$val";
+
+			printf("\t\t<input type=radio name=$name"
+				. " value=\"$val\"%s>$pval</input>\n",
+				$i == $chk ? " checked" : "");
+		}
+
+		end_field();
+	}
+
+	// print a mysql ENUM as an html SELECT INPUT
+	function print_enum_select($name, $array, $vals, $def = -1) {
+
+		begin_field($name);
+
+		echo "\t\t<select name=$name>\n";
+
+		if (key_in_array($name, $array))
+			$chk = array_search($array[$name], $vals, FALSE);
+		else
+			$chk = $def;
+
+		$nval = count($vals);
+
+		for ($i = 0; $i < $nval; $i++) {
+
+			$val = $vals[$i];
+			if ($val == '')
+				$pval = "none";
+			else
+				$pval = "$val";
+
+			printf("\t\t\t<option " .
+				"value=\"%s\"%s>%s</option>\n",
+				$val, $i == $chk ? " selected" : "", $pval);
+		}
+
+		echo "\t\t</select>\n";
+
+		end_field();
+	}
+
+	// print a group of mysql ENUMs (e.g. name0,name1,...) as an html SELECT
+	function print_enum_multi($base, $array, $vals, $cnt, $defs, $grp = 0) {
+
+		global $table_ncols;
+
+		if ($grp <= 0)
+			$grp = $cnt;
+		$ncell = $cnt / $grp;
+		$span = ($table_ncols - 1) / $ncell;
+
+		begin_field($base, $span);
+
+		$nval = count($vals);
+
+		for ($i = 0; $i < $cnt; $i++) {
+
+			if ($i > 0 && ($i % $grp) == 0)
+				cont_field($span);
+
+			$name = sprintf("%s%x", $base, $i);
+
+			echo "\t\t<select name=$name>\n";
+
+			if (key_in_array($name, $array))
+				$ai = array_search($array[$name], $vals, FALSE);
+			else {
+				if (key_in_array($i, $defs))
+					$ai = $defs[$i];
+				else
+					$ai = 0;
+			}
+
+			for ($j = 0; $j < $nval; $j++) {
+
+				$val = $vals[$j];
+				if ($val == '')
+					$pval = "&nbsp;";
+				else
+					$pval = "$val";
+
+				printf("\t\t\t<option " .
+					"value=\"%s\"%s>%s</option>\n",
+					$val,
+					$j == $ai ? " selected" : "",
+					$pval);
+			}
+
+			echo "\t\t</select>\n";
+		}
+
+		end_field();
+	}
+
+	// functions to handle the form input
+
+	// fetch all the parts of an "enum_multi" into a string suitable
+	// for a MySQL query
+	function gather_enum_multi_query($base, $cnt) {
+
+		$retval = '';
+
+		for ($i = 0; $i < $cnt; $i++) {
+
+			$name = sprintf("%s%x", $base, $i);
+
+			if (isset($_REQUEST[$name])) {
+				$retval .= sprintf(", %s='%s'",
+					$name, $_REQUEST[$name]);
+			}
+		}
+
+		return $retval;
+	}
+
+	// fetch all the parts of an "enum_multi" into a string suitable
+	// for a display e.g. in an html table cell
+	function gather_enum_multi_print($base, $cnt, $array) {
+
+		$retval = '';
+
+		for ($i = 0; $i < $cnt; $i++) {
+
+			$name = sprintf("%s%x", $base, $i);
+
+			if ($array[$name] != '') {
+				if ($retval != '')
+					$retval .= ',';
+				$retval .= $array[$name];
+			}
+		}
+
+		return $retval;
+	}
+
+	// fetch all the parts of an "enum_multi" into a string suitable
+	// for writing to the eeprom data file
+	function gather_enum_multi_write($base, $cnt, $vals, $xfrm = array()) {
+
+		$retval = '';
+
+		for ($i = 0; $i < $cnt; $i++) {
+
+			$name = sprintf("%s%x", $base, $i);
+
+			if ($GLOBALS[$name] != '') {
+				if ($retval != '')
+					$retval .= ',';
+				$index = enum_to_index($name, $vals);
+				if ($xfrm != array())
+					$retval .= $xfrm[$index];
+				else
+					$retval .= $index;
+			}
+		}
+
+		return $retval;
+	}
+
+	// count how many parts of an "enum_multi" are actually set
+	function count_enum_multi($base, $cnt) {
+
+		$retval = 0;
+
+		for ($i = 0; $i < $cnt; $i++) {
+
+			$name = sprintf("%s%x", $base, $i);
+
+			if (isset($_REQUEST[$name]))
+				$retval++;
+		}
+
+		return $retval;
+	}
+
+	// ethernet address functions
+
+	// generate a (possibly not unique) random vendor ethernet address
+	// (setting bit 6 in the ethernet address - motorola wise i.e. bit 0
+	// is the most significant bit - means it is not an assigned ethernet
+	// address - it is a "locally administered" address). Also, make sure
+	// it is NOT a multicast ethernet address (by setting bit 7 to 0).
+	// e.g. the first byte of all ethernet addresses generated here will
+	// have 2 in the bottom two bits (incidentally, these are the first
+	// two bits transmitted on the wire, since the octets in ethernet
+	// addresses are transmitted LSB first).
+
+	function gen_eth_addr($serno) {
+
+		$ethaddr_hgh = (mt_rand(0, 65535) & 0xfeff) | 0x0200;
+		$ethaddr_mid = mt_rand(0, 65535);
+		$ethaddr_low = mt_rand(0, 65535);
+
+		return sprintf("%02lx:%02lx:%02lx:%02lx:%02lx:%02lx",
+			$ethaddr_hgh >> 8, $ethaddr_hgh & 0xff,
+			$ethaddr_mid >> 8, $ethaddr_mid & 0xff,
+			$ethaddr_low >> 8, $ethaddr_low & 0xff);
+	}
+
+	// check that an ethernet address is valid
+	function eth_addr_is_valid($ethaddr) {
+
+		$ethbytes = split(':', $ethaddr);
+
+		if (count($ethbytes) != 6)
+			return FALSE;
+
+		for ($i = 0; $i < 6; $i++) {
+			$ethbyte = $ethbytes[$i];
+			if (!ereg('^[0-9a-f][0-9a-f]$', $ethbyte))
+				return FALSE;
+		}
+
+		return TRUE;
+	}
+
+	// write a simple eeprom configuration file
+	function write_eeprom_cfg_file() {
+
+		global $sernos, $nsernos, $bddb_cfgdir, $numerrs, $cfgerrs;
+		global $date, $batch, $type_vals, $rev;
+		global $sdram_vals, $sdram_nbits;
+		global $flash_vals, $flash_nbits;
+		global $zbt_vals, $zbt_nbits;
+		global $xlxtyp_vals, $xlxspd_vals, $xlxtmp_vals, $xlxgrd_vals;
+		global $cputyp, $cputyp_vals, $clk_vals;
+		global $hstype, $hstype_vals, $hschin, $hschout;
+
+		$numerrs = 0;
+		$cfgerrs = array();
+
+		for ($i = 0; $i < $nsernos; $i++) {
+
+			$serno = sprintf("%010d", $sernos[$i]);
+
+			$wfp = @fopen($bddb_cfgdir . "/$serno.cfg", "w");
+			if (!$wfp) {
+				$cfgerrs[$i] = 'file create fail';
+				$numerrs++;
+				continue;
+			}
+			set_file_buffer($wfp, 0);
+
+			if (!fprintf($wfp, "serno=%d\n", $sernos[$i])) {
+				$cfgerrs[$i] = 'cfg wr fail (serno)';
+				fclose($wfp);
+				$numerrs++;
+				continue;
+			}
+
+			if (!fprintf($wfp, "date=%s\n", $date)) {
+				$cfgerrs[$i] = 'cfg wr fail (date)';
+				fclose($wfp);
+				$numerrs++;
+				continue;
+			}
+
+			if ($batch != '') {
+				if (!fprintf($wfp, "batch=%s\n", $batch)) {
+					$cfgerrs[$i] = 'cfg wr fail (batch)';
+					fclose($wfp);
+					$numerrs++;
+					continue;
+				}
+			}
+
+			$typei = enum_to_index("type", $type_vals);
+			if (!fprintf($wfp, "type=%d\n", $typei)) {
+				$cfgerrs[$i] = 'cfg wr fail (type)';
+				fclose($wfp);
+				$numerrs++;
+				continue;
+			}
+
+			if (!fprintf($wfp, "rev=%d\n", $rev)) {
+				$cfgerrs[$i] = 'cfg wr fail (rev)';
+				fclose($wfp);
+				$numerrs++;
+				continue;
+			}
+
+			$s = gather_enum_multi_write("sdram", 4,
+				$sdram_vals, $sdram_nbits);
+			if ($s != '') {
+				$b = fprintf($wfp, "sdram=%s\n", $s);
+				if (!$b) {
+					$cfgerrs[$i] = 'cfg wr fail (sdram)';
+					fclose($wfp);
+					$numerrs++;
+					continue;
+				}
+			}
+
+			$s = gather_enum_multi_write("flash", 4,
+				$flash_vals, $flash_nbits);
+			if ($s != '') {
+				$b = fprintf($wfp, "flash=%s\n", $s);
+				if (!$b) {
+					$cfgerrs[$i] = 'cfg wr fail (flash)';
+					fclose($wfp);
+					$numerrs++;
+					continue;
+				}
+			}
+
+			$s = gather_enum_multi_write("zbt", 16,
+				$zbt_vals, $zbt_nbits);
+			if ($s != '') {
+				$b = fprintf($wfp, "zbt=%s\n", $s);
+				if (!$b) {
+					$cfgerrs[$i] = 'cfg wr fail (zbt)';
+					fclose($wfp);
+					$numerrs++;
+					continue;
+				}
+			}
+
+			$s = gather_enum_multi_write("xlxtyp", 4, $xlxtyp_vals);
+			if ($s != '') {
+				$b = fprintf($wfp, "xlxtyp=%s\n", $s);
+				if (!$b) {
+					$cfgerrs[$i] = 'cfg wr fail (xlxtyp)';
+					fclose($wfp);
+					$numerrs++;
+					continue;
+				}
+			}
+
+			$s = gather_enum_multi_write("xlxspd", 4, $xlxspd_vals);
+			if ($s != '') {
+				$b = fprintf($wfp, "xlxspd=%s\n", $s);
+				if (!$b) {
+					$cfgerrs[$i] = 'cfg wr fail (xlxspd)';
+					fclose($wfp);
+					$numerrs++;
+					continue;
+				}
+			}
+
+			$s = gather_enum_multi_write("xlxtmp", 4, $xlxtmp_vals);
+			if ($s != '') {
+				$b = fprintf($wfp, "xlxtmp=%s\n", $s);
+				if (!$b) {
+					$cfgerrs[$i] = 'cfg wr fail (xlxtmp)';
+					fclose($wfp);
+					$numerrs++;
+					continue;
+				}
+			}
+
+			$s = gather_enum_multi_write("xlxgrd", 4, $xlxgrd_vals);
+			if ($s != '') {
+				$b = fprintf($wfp, "xlxgrd=%s\n", $s);
+				if (!$b) {
+					$cfgerrs[$i] = 'cfg wr fail (xlxgrd)';
+					fclose($wfp);
+					$numerrs++;
+					continue;
+				}
+			}
+
+			if ($cputyp != '') {
+				$cputypi = enum_to_index("cputyp",$cputyp_vals);
+				$cpuspdi = enum_to_index("cpuspd", $clk_vals);
+				$busspdi = enum_to_index("busspd", $clk_vals);
+				$cpmspdi = enum_to_index("cpmspd", $clk_vals);
+				$b = fprintf($wfp, "cputyp=%d\ncpuspd=%d\n" .
+					"busspd=%d\ncpmspd=%d\n",
+					$cputypi, $cpuspdi, $busspdi, $cpmspdi);
+				if (!$b) {
+					$cfgerrs[$i] = 'cfg wr fail (cputyp)';
+					fclose($wfp);
+					$numerrs++;
+					continue;
+				}
+			}
+
+			if ($hstype != '') {
+				$hstypei = enum_to_index("hstype",$hstype_vals);
+				$b = fprintf($wfp, "hstype=%d\n" .
+					"hschin=%s\nhschout=%s\n",
+					$hstypei, $hschin, $hschout);
+				if (!$b) {
+					$cfgerrs[$i] = 'cfg wr fail (hstype)';
+					fclose($wfp);
+					$numerrs++;
+					continue;
+				}
+			}
+
+			if (!fclose($wfp)) {
+				$cfgerrs[$i] = 'file cls fail';
+				$numerrs++;
+			}
+		}
+
+		return $numerrs;
+	}
+?>
diff --git a/marvell/uboot/tools/bddb/dodelete.php b/marvell/uboot/tools/bddb/dodelete.php
new file mode 100644
index 0000000..4839e36
--- /dev/null
+++ b/marvell/uboot/tools/bddb/dodelete.php
@@ -0,0 +1,65 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// dodelete page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - Delete Board Results");
+
+	if (!isset($_REQUEST['serno']))
+		die("the board serial number was not specified");
+	$serno=intval($_REQUEST['serno']);
+
+	mysql_query("delete from boards where serno=$serno");
+
+	if(mysql_errno()) {
+		$errstr = mysql_error();
+		echo "\t<font size=+4>\n";
+		echo "\t\t<p>\n";
+		echo "\t\t\tThe following error was encountered:\n";
+		echo "\t\t</p>\n";
+		echo "\t\t<center>\n";
+		printf("\t\t\t<b>%s</b>\n", $errstr);
+		echo "\t\t</center>\n";
+		echo "\t</font>\n";
+	}
+	else {
+		echo "\t<font size=+2>\n";
+		echo "\t\t<p>\n";
+		echo "\t\t\tThe board with serial number <b>$serno</b> was"
+			. " successfully deleted\n";
+		mysql_query("delete from log where serno=$serno");
+		if (mysql_errno()) {
+			$errstr = mysql_error();
+			echo "\t\t\t<font size=+4>\n";
+			echo "\t\t\t\t<p>\n";
+			echo "\t\t\t\t\tBut the following error occurred " .
+				"when deleting the log entries:\n";
+			echo "\t\t\t\t</p>\n";
+			echo "\t\t\t\t<center>\n";
+			printf("\t\t\t\t\t<b>%s</b>\n", $errstr);
+			echo "\t\t\t\t</center>\n";
+			echo "\t\t\t</font>\n";
+		}
+		echo "\t\t</p>\n";
+		echo "\t</font>\n";
+	}
+?>
+<p>
+<table width="100%">
+<tr>
+  <td align=center>
+    <a href="browse.php">Back to Browse</a>
+  </td>
+  <td align=center>
+    <a href="index.php">Back to Start</a>
+  </td>
+</tr>
+</table>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/dodellog.php b/marvell/uboot/tools/bddb/dodellog.php
new file mode 100644
index 0000000..9dd78c1
--- /dev/null
+++ b/marvell/uboot/tools/bddb/dodellog.php
@@ -0,0 +1,57 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// dodelete page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - Delete Log Entry Results");
+
+	if (!isset($_REQUEST['serno']))
+		die("the board serial number was not specified");
+	$serno=intval($_REQUEST['serno']);
+
+	if (!isset($_REQUEST['logno']) || $_REQUEST['logno'] == 0)
+		die("the log entry number not specified!");
+	$logno=$_REQUEST['logno'];
+
+	mysql_query("delete from log where serno=$serno and logno=$logno");
+
+	if(mysql_errno()) {
+		$errstr = mysql_error();
+		echo "\t<font size=+4>\n";
+		echo "\t\t<p>\n";
+		echo "\t\t\tThe following error was encountered:\n";
+		echo "\t\t</p>\n";
+		echo "\t\t<center>\n";
+		printf("\t\t\t<b>%s</b>\n", $errstr);
+		echo "\t\t</center>\n";
+		echo "\t</font>\n";
+	}
+	else {
+		echo "\t<font size=+2>\n";
+		echo "\t\t<p>\n";
+		echo "\t\t\tThe log entry with log number <b>$logno</b>\n";
+		echo "\t\t\tand serial number <b>$serno</b> ";
+		echo "was successfully deleted\n";
+		echo "\t\t</p>\n";
+		echo "\t</font>\n";
+	}
+?>
+<p>
+<table width="100%">
+<tr>
+  <td align=center>
+    <a href="brlog.php?serno=<?php echo "$serno"; ?>">Back to Log</a>
+  </td>
+  <td align=center>
+    <a href="index.php">Back to Start</a>
+  </td>
+</tr>
+</table>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/doedit.php b/marvell/uboot/tools/bddb/doedit.php
new file mode 100644
index 0000000..13fbb69
--- /dev/null
+++ b/marvell/uboot/tools/bddb/doedit.php
@@ -0,0 +1,186 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// doedit page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - Edit Board Results");
+
+	if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '')
+		die("the board serial number was not specified");
+	$serno=intval($_REQUEST['serno']);
+
+	$query="update boards set";
+
+	if (isset($_REQUEST['ethaddr'])) {
+		$ethaddr=$_REQUEST['ethaddr'];
+		if (!eth_addr_is_valid($ethaddr))
+			die("ethaddr is invalid ('$ethaddr')");
+		$query.=" ethaddr='$ethaddr',";
+	}
+
+	if (isset($_REQUEST['date'])) {
+		$date=$_REQUEST['date'];
+		list($y, $m, $d) = split("-", $date);
+		if (!checkdate($m, $d, $y) || $y < 1999)
+			die("date is invalid (input '$date', " .
+				"yyyy-mm-dd '$y-$m-$d')");
+		$query.=" date='$date'";
+	}
+
+	if (isset($_REQUEST['batch'])) {
+		$batch=$_REQUEST['batch'];
+		if (strlen($batch) > 32)
+			die("batch field too long (>32)");
+		$query.=", batch='$batch'";
+	}
+
+	if (isset($_REQUEST['type'])) {
+		$type=$_REQUEST['type'];
+		if (!in_array($type, $type_vals))
+			die("Invalid type ($type) specified");
+		$query.=", type='$type'";
+	}
+
+	if (isset($_REQUEST['rev'])) {
+		$rev=$_REQUEST['rev'];
+		if (($rev = intval($rev)) <= 0 || $rev > 255)
+			die("Revision number is invalid ($rev)");
+		$query.=sprintf(", rev=%d", $rev);
+	}
+
+	if (isset($_REQUEST['location'])) {
+		$location=$_REQUEST['location'];
+		if (strlen($location) > 64)
+			die("location field too long (>64)");
+		$query.=", location='$location'";
+	}
+
+	if (isset($_REQUEST['comments']))
+		$comments=$_REQUEST['comments'];
+		$query.=", comments='" . rawurlencode($comments) . "'";
+
+	$query.=gather_enum_multi_query("sdram", 4);
+
+	$query.=gather_enum_multi_query("flash", 4);
+
+	$query.=gather_enum_multi_query("zbt", 16);
+
+	$query.=gather_enum_multi_query("xlxtyp", 4);
+	$nxlx = count_enum_multi("xlxtyp", 4);
+
+	$query.=gather_enum_multi_query("xlxspd", 4);
+	if (count_enum_multi("xlxspd", 4) != $nxlx)
+		die("number of xilinx speeds not same as number of types");
+
+	$query.=gather_enum_multi_query("xlxtmp", 4);
+	if (count_enum_multi("xlxtmp", 4) != $nxlx)
+		die("number of xilinx temps. not same as number of types");
+
+	$query.=gather_enum_multi_query("xlxgrd", 4);
+	if (count_enum_multi("xlxgrd", 4) != $nxlx)
+		die("number of xilinx grades not same as number of types");
+
+	if (isset($_REQUEST['cputyp'])) {
+		$cputyp=$_REQUEST['cputyp'];
+		$query.=", cputyp='$cputyp'";
+		if (!isset($_REQUEST['cpuspd']) || $_REQUEST['cpuspd'] == '')
+			die("must specify cpu speed if cpu type is defined");
+		$cpuspd=$_REQUEST['cpuspd'];
+		$query.=", cpuspd='$cpuspd'";
+		if (!isset($_REQUEST['cpmspd']) || $_REQUEST['cpmspd'] == '')
+			die("must specify cpm speed if cpu type is defined");
+		$cpmspd=$_REQUEST['cpmspd'];
+		$query.=", cpmspd='$cpmspd'";
+		if (!isset($_REQUEST['busspd']) || $_REQUEST['busspd'] == '')
+			die("must specify bus speed if cpu type is defined");
+		$busspd=$_REQUEST['busspd'];
+		$query.=", busspd='$busspd'";
+	}
+	else {
+		if (isset($_REQUEST['cpuspd']))
+			die("can't specify cpu speed if there is no cpu");
+		if (isset($_REQUEST['cpmspd']))
+			die("can't specify cpm speed if there is no cpu");
+		if (isset($_REQUEST['busspd']))
+			die("can't specify bus speed if there is no cpu");
+	}
+
+	if (isset($_REQUEST['hschin'])) {
+		$hschin=$_REQUEST['hschin'];
+		if (($hschin = intval($hschin)) < 0 || $hschin > 4)
+			die("Invalid number of hs input chans ($hschin)");
+	}
+	else
+		$hschin = 0;
+	if (isset($_REQUEST['hschout'])) {
+		$hschout=$_REQUEST['hschout'];
+		if (($hschout = intval($hschout)) < 0 || $hschout > 4)
+			die("Invalid number of hs output chans ($hschout)");
+	}
+	else
+		$hschout = 0;
+	if (isset($_REQUEST['hstype'])) {
+		$hstype=$_REQUEST['hstype'];
+		$query.=", hstype='$hstype'";
+	}
+	else {
+		if ($_REQUEST['hschin'] != 0)
+			die("number of high-speed input channels must be zero"
+				. " if high-speed chip is not present");
+		if ($_REQUEST['hschout'] != 0)
+			die("number of high-speed output channels must be zero"
+				. " if high-speed chip is not present");
+	}
+	$query.=", hschin='$hschin'";
+	$query.=", hschout='$hschout'";
+
+	$query.=" where serno=$serno";
+
+	mysql_query($query);
+	if(mysql_errno()) {
+		$errstr = mysql_error();
+		echo "\t<font size=+4>\n";
+		echo "\t\t<p>\n";
+		echo "\t\t\tThe following error was encountered:\n";
+		echo "\t\t</p>\n";
+		echo "\t\t<center>\n";
+		printf("\t\t\t<b>%s</b>\n", $errstr);
+		echo "\t\t</center>\n";
+		echo "\t</font>\n";
+	}
+	else {
+		$sernos = array($serno);
+		$nsernos = 1;
+
+		write_eeprom_cfg_file();
+
+		echo "\t<font size=+2>\n";
+		echo "\t\t<p>\n";
+		echo "\t\t\tThe board with serial number <b>$serno</b> was"
+			. " successfully updated";
+		if ($numerrs > 0) {
+			$errstr = $cfgerrs[0];
+			echo "<br>\n\t\t\t";
+			echo "(but the cfg file update failed: $errstr)";
+		}
+		echo "\n";
+		echo "\t\t</p>\n";
+		echo "\t</font>\n";
+	}
+
+?>
+<p>
+<table align=center width="100%">
+<tr>
+  <td align=center><a href="browse.php">Back to Browse</a></td>
+  <td align=center><a href="index.php">Back to Start</a></td>
+</tr>
+</table>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/doedlog.php b/marvell/uboot/tools/bddb/doedlog.php
new file mode 100644
index 0000000..7009aa7
--- /dev/null
+++ b/marvell/uboot/tools/bddb/doedlog.php
@@ -0,0 +1,76 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// doedit page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - Edit Log Entry Results");
+
+	if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '')
+		die("the board serial number was not specified");
+	$serno=intval($_REQUEST['serno']);
+
+	if (!isset($_REQUEST['logno']) || $_REQUEST['logno'] == '')
+		die("log number not specified!");
+	$logno=intval($_REQUEST['logno']);
+
+	$query="update log set";
+
+	if (isset($_REQUEST['date'])) {
+		$date=$_REQUEST['date'];
+		list($y, $m, $d) = split("-", $date);
+		if (!checkdate($m, $d, $y) || $y < 1999)
+			die("date is invalid (input '$date', " .
+				"yyyy-mm-dd '$y-$m-$d')");
+		$query.=" date='$date'";
+	}
+
+	if (isset($_REQUEST['who'])) {
+		$who=$_REQUEST['who'];
+		$query.=", who='" . $who . "'";
+	}
+
+	if (isset($_REQUEST['details'])) {
+		$details=$_REQUEST['details'];
+		$query.=", details='" . rawurlencode($details) . "'";
+	}
+
+	$query.=" where serno=$serno and logno=$logno";
+
+	mysql_query($query);
+	if(mysql_errno()) {
+		$errstr = mysql_error();
+		echo "\t<font size=+4>\n";
+		echo "\t\t<p>\n";
+		echo "\t\t\tThe following error was encountered:\n";
+		echo "\t\t</p>\n";
+		echo "\t\t<center>\n";
+		printf("\t\t\t<b>%s</b>\n", $errstr);
+		echo "\t\t</center>\n";
+		echo "\t</font>\n";
+	}
+	else {
+		echo "\t<font size=+2>\n";
+		echo "\t\t<p>\n";
+		echo "\t\t\tThe log entry with log number <b>$logno</b> and\n";
+		echo "\t\t\tserial number <b>$serno</b> ";
+		echo "was successfully updated\n";
+		echo "\t\t</p>\n";
+		echo "\t</font>\n";
+	}
+
+?>
+<p>
+<table align=center width="100%">
+<tr>
+  <td align=center><a href="brlog.php?serno=<?php echo "$serno"; ?>">Back to Log</a></td>
+  <td align=center><a href="index.php">Back to Start</a></td>
+</tr>
+</table>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/donew.php b/marvell/uboot/tools/bddb/donew.php
new file mode 100644
index 0000000..39b2c78
--- /dev/null
+++ b/marvell/uboot/tools/bddb/donew.php
@@ -0,0 +1,230 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// doedit page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - Board Registration Results");
+
+	if (isset($_REQUEST['serno'])) {
+		$serno=$_REQUEST['serno'];
+		die("serial number must not be set ($serno) when Creating!");
+	}
+
+	$query="update boards set";
+
+	list($y, $m, $d) = split("-", $date);
+	if (!checkdate($m, $d, $y) || $y < 1999)
+		die("date is invalid (input '$date', yyyy-mm-dd '$y-$m-$d')");
+	$query.=" date='$date'";
+
+	if ($batch != '') {
+		if (strlen($batch) > 32)
+			die("batch field too long (>32)");
+		$query.=", batch='$batch'";
+	}
+
+	if (!in_array($type, $type_vals))
+		die("Invalid type ($type) specified");
+	$query.=", type='$type'";
+
+	if (($rev = intval($rev)) <= 0 || $rev > 255)
+		die("Revision number is invalid ($rev)");
+	$query.=sprintf(", rev=%d", $rev);
+
+	$query.=gather_enum_multi_query("sdram", 4);
+
+	$query.=gather_enum_multi_query("flash", 4);
+
+	$query.=gather_enum_multi_query("zbt", 16);
+
+	$query.=gather_enum_multi_query("xlxtyp", 4);
+	$nxlx = count_enum_multi("xlxtyp", 4);
+
+	$query.=gather_enum_multi_query("xlxspd", 4);
+	if (count_enum_multi("xlxspd", 4) != $nxlx)
+		die("number of xilinx speeds not same as number of types");
+
+	$query.=gather_enum_multi_query("xlxtmp", 4);
+	if (count_enum_multi("xlxtmp", 4) != $nxlx)
+		die("number of xilinx temps. not same as number of types");
+
+	$query.=gather_enum_multi_query("xlxgrd", 4);
+	if (count_enum_multi("xlxgrd", 4) != $nxlx)
+		die("number of xilinx grades not same as number of types");
+
+	if ($cputyp == '') {
+		if ($cpuspd != '')
+			die("can't specify cpu speed if there is no cpu");
+		if ($cpmspd != '')
+			die("can't specify cpm speed if there is no cpu");
+		if ($busspd != '')
+			die("can't specify bus speed if there is no cpu");
+	}
+	else {
+		$query.=", cputyp='$cputyp'";
+		if ($cpuspd == '')
+			die("must specify cpu speed if cpu type is defined");
+		$query.=", cpuspd='$cpuspd'";
+		if ($cpmspd == '')
+			die("must specify cpm speed if cpu type is defined");
+		$query.=", cpmspd='$cpmspd'";
+		if ($busspd == '')
+			die("must specify bus speed if cpu type is defined");
+		$query.=", busspd='$busspd'";
+	}
+
+	if (($hschin = intval($hschin)) < 0 || $hschin > 4)
+		die("Invalid number of hs input chans ($hschin)");
+	if (($hschout = intval($hschout)) < 0 || $hschout > 4)
+		die("Invalid number of hs output chans ($hschout)");
+	if ($hstype == '') {
+		if ($hschin != 0)
+			die("number of high-speed input channels must be zero"
+				. " if high-speed chip is not present");
+		if ($hschout != 0)
+			die("number of high-speed output channels must be zero"
+				. " if high-speed chip is not present");
+	}
+	else
+		$query.=", hstype='$hstype'";
+	$query.=", hschin='$hschin'";
+	$query.=", hschout='$hschout'";
+
+	// echo "final query = '$query'<br>\n";
+
+	$quant = intval($quant);
+	if ($quant <= 0) $quant = 1;
+
+	$sernos = array();
+	if ($geneths)
+		$ethaddrs = array();
+
+	$sqlerr = '';
+
+	while ($quant-- > 0) {
+
+		mysql_query("insert into boards (serno) values (null)");
+		if (mysql_errno()) {
+			$sqlerr = mysql_error();
+			break;
+		}
+
+		$serno = mysql_insert_id();
+		if (!$serno) {
+			$sqlerr = "couldn't allocate new serial number";
+			break;
+		}
+
+		mysql_query($query . " where serno=$serno");
+		if (mysql_errno()) {
+			$sqlerr = mysql_error();
+			break;
+		}
+
+		array_push($sernos, $serno);
+
+		if ($geneths) {
+
+			$ethaddr = gen_eth_addr($serno);
+
+			mysql_query("update boards set ethaddr='$ethaddr'" .
+			    " where serno=$serno");
+			if (mysql_errno()) {
+				$sqlerr = mysql_error();
+
+				array_push($ethaddrs,
+					"<font color=#ff0000><b>" .
+					"db save fail" .
+					"</b></font>");
+				break;
+			}
+
+			array_push($ethaddrs, $ethaddr);
+		}
+	}
+
+	$nsernos = count($sernos);
+
+	if ($nsernos > 0) {
+
+		write_eeprom_cfg_file();
+
+		echo "<font size=+2>\n";
+		echo "\t<p>\n";
+		echo "\t\tThe following board serial numbers were"
+			. " successfully allocated";
+		if ($numerrs > 0)
+			echo " (but with $numerrs cfg file error" .
+				($numerrs > 1 ? "s" : "") . ")";
+		echo ":\n";
+		echo "\t</p>\n";
+
+		echo "</font>\n";
+
+		echo "<table align=center width=\"100%\">\n";
+		echo "<tr>\n";
+		echo "\t<th>Serial Number</th>\n";
+		if ($numerrs > 0)
+			echo "\t<th>Cfg File Errs</th>\n";
+		if ($geneths)
+			echo "\t<th>Ethernet Address</th>\n";
+		echo "</tr>\n";
+
+		for ($i = 0; $i < $nsernos; $i++) {
+
+			$serno = sprintf("%010d", $sernos[$i]);
+
+			echo "<tr>\n";
+
+			echo "\t<td align=center><font size=+2>" .
+				"<b>$serno</b></font></td>\n";
+
+			if ($numerrs > 0) {
+				if (($errstr = $cfgerrs[$i]) == '')
+					$errstr = '&nbsp;';
+				echo "\t<td align=center>" .
+					"<font size=+2 color=#ff0000><b>" .
+					$errstr .
+					"</b></font></td>\n";
+			}
+
+			if ($geneths) {
+				echo "\t<td align=center>" .
+					"<font size=+2 color=#00ff00><b>" .
+					$ethaddrs[$i] .
+					"</b></font></td>\n";
+			}
+
+			echo "</tr>\n";
+		}
+
+		echo "</table>\n";
+	}
+
+	if ($sqlerr != '') {
+		echo "\t<font size=+4>\n";
+		echo "\t\t<p>\n";
+		echo "\t\t\tThe following SQL error was encountered:\n";
+		echo "\t\t</p>\n";
+		echo "\t\t<center>\n";
+		printf("\t\t\t<b>%s</b>\n", $sqlerr);
+		echo "\t\t</center>\n";
+		echo "\t</font>\n";
+	}
+
+?>
+<p>
+<table align=center width="100%">
+<tr>
+  <td align=center><a href="browse.php">Go to Browse</a></td>
+  <td align=center><a href="index.php">Back to Start</a></td>
+</tr>
+</table>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/donewlog.php b/marvell/uboot/tools/bddb/donewlog.php
new file mode 100644
index 0000000..7635d29
--- /dev/null
+++ b/marvell/uboot/tools/bddb/donewlog.php
@@ -0,0 +1,86 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// doedit page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - Add Log Entry Results");
+
+	if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '')
+		die("serial number not specified!");
+	$serno=intval($_REQUEST['serno']);
+
+	if (isset($_REQUEST['logno'])) {
+		$logno=$_REQUEST['logno'];
+		die("log number must not be set ($logno) when Creating!");
+	}
+
+	$query="update log set serno=$serno";
+
+	list($y, $m, $d) = split("-", $date);
+	if (!checkdate($m, $d, $y) || $y < 1999)
+		die("date is invalid (input '$date', yyyy-mm-dd '$y-$m-$d')");
+	$query.=", date='$date'";
+
+	if (isset($_REQUEST['who'])) {
+		$who=$_REQUEST['who'];
+		$query.=", who='" . $who . "'";
+	}
+
+	if (isset($_REQUEST['details'])) {
+		$details=$_REQUEST['details'];
+		$query.=", details='" . rawurlencode($details) . "'";
+	}
+
+	// echo "final query = '$query'<br>\n";
+
+	$sqlerr = '';
+
+	mysql_query("insert into log (logno) values (null)");
+	if (mysql_errno())
+		$sqlerr = mysql_error();
+	else {
+		$logno = mysql_insert_id();
+		if (!$logno)
+			$sqlerr = "couldn't allocate new serial number";
+		else {
+			mysql_query($query . " where logno=$logno");
+			if (mysql_errno())
+				$sqlerr = mysql_error();
+		}
+	}
+
+	if ($sqlerr == '') {
+		echo "<font size=+2>\n";
+		echo "\t<p>\n";
+		echo "\t\tA log entry with log number '$logno' was " .
+			"added to the board with serial number '$serno'\n";
+		echo "\t</p>\n";
+		echo "</font>\n";
+	}
+	else {
+		echo "\t<font size=+4>\n";
+		echo "\t\t<p>\n";
+		echo "\t\t\tThe following SQL error was encountered:\n";
+		echo "\t\t</p>\n";
+		echo "\t\t<center>\n";
+		printf("\t\t\t<b>%s</b>\n", $sqlerr);
+		echo "\t\t</center>\n";
+		echo "\t</font>\n";
+	}
+
+?>
+<p></p>
+<table width="100%">
+<tr>
+  <td align=center><a href="brlog.php?serno=<?php echo "$serno"; ?>">Go to Browse</a></td>
+  <td align=center><a href="index.php">Back to Start</a></td>
+</tr>
+</table>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/edit.php b/marvell/uboot/tools/bddb/edit.php
new file mode 100644
index 0000000..dd8c26c
--- /dev/null
+++ b/marvell/uboot/tools/bddb/edit.php
@@ -0,0 +1,131 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// edit page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - Edit Board Registration");
+
+	if ($serno == 0)
+		die("serial number not specified or invalid!");
+
+	$pserno = sprintf("%010d", $serno);
+
+	echo "<center><b><font size=+2>";
+	echo "Board Serial Number: $pserno";
+	echo "</font></b></center>\n";
+
+?>
+<p>
+<form action=doedit.php method=POST>
+<?php
+	echo "<input type=hidden name=serno value=$serno>\n";
+
+	$r=mysql_query("select * from boards where serno=$serno");
+	$row=mysql_fetch_array($r);
+	if(!$row) die("no record of serial number '$serno' in database");
+
+	begin_table(5);
+
+	// ethaddr char(17)
+	print_field("ethaddr", $row, 17);
+
+	// date date
+	print_field("date", $row);
+
+	// batch char(32)
+	print_field("batch", $row, 32);
+
+	// type enum('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY')
+	print_enum("type", $row, $type_vals);
+
+	// rev tinyint(3) unsigned zerofill
+	print_field("rev", $row, 3, 'rev_filter');
+
+	// location char(64)
+	print_field("location", $row, 64);
+
+	// comments text
+	print_field_multiline("comments", $row, 60, 10, 'text_filter');
+
+	// sdram[0-3] enum('32M','64M','128M','256M')
+	print_enum_multi("sdram", $row, $sdram_vals, 4, array());
+
+	// flash[0-3] enum('4M','8M','16M','32M','64M')
+	print_enum_multi("flash", $row, $flash_vals, 4, array());
+
+	// zbt[0-f] enum('512K','1M','2M','4M')
+	print_enum_multi("zbt", $row, $zbt_vals, 16, array());
+
+	// xlxtyp[0-3] enum('XCV300E','XCV400E','XCV600E')
+	print_enum_multi("xlxtyp", $row, $xlxtyp_vals, 4, array(), 1);
+
+	// xlxspd[0-3] enum('6','7','8')
+	print_enum_multi("xlxspd", $row, $xlxspd_vals, 4, array(), 1);
+
+	// xlxtmp[0-3] enum('COM','IND')
+	print_enum_multi("xlxtmp", $row, $xlxtmp_vals, 4, array(), 1);
+
+	// xlxgrd[0-3] enum('NORMAL','ENGSAMP')
+	print_enum_multi("xlxgrd", $row, $xlxgrd_vals, 4, array(), 1);
+
+	// cputyp enum('MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)')
+	print_enum("cputyp", $row, $cputyp_vals);
+
+	// cpuspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+	print_enum_select("cpuspd", $row, $clk_vals);
+
+	// cpmspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+	print_enum_select("cpmspd", $row, $clk_vals);
+
+	// busspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+	print_enum_select("busspd", $row, $clk_vals);
+
+	// hstype enum('AMCC-S2064A')
+	print_enum("hstype", $row, $hstype_vals);
+
+	// hschin enum('0','1','2','3','4')
+	print_enum("hschin", $row, $hschin_vals);
+
+	// hschout enum('0','1','2','3','4')
+	print_enum("hschout", $row, $hschout_vals);
+
+	end_table();
+
+	echo "<p>\n";
+	echo "<center><b>";
+	echo "<font color=#ff0000>WARNING: NO UNDO ON DELETE!</font>";
+	echo "<br></br>\n";
+	echo "<tt>[ <a href=\"dodelete.php?serno=$serno\">delete</a> ]</tt>";
+	echo "</b></center>\n";
+	echo "</p>\n";
+?>
+<p>
+<table align=center width="100%">
+<tr>
+  <td align=center>
+    <input type=submit value=Edit>
+  </td>
+  <td>
+    &nbsp;
+  </td>
+  <td align=center>
+    <input type=reset value=Reset>
+  </td>
+  <td>
+    &nbsp;
+  </td>
+  <td align=center>
+    <a href="index.php">Back to Start</a>
+  </td>
+</tr>
+</table>
+</p>
+</form>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/edlog.php b/marvell/uboot/tools/bddb/edlog.php
new file mode 100644
index 0000000..8befd35
--- /dev/null
+++ b/marvell/uboot/tools/bddb/edlog.php
@@ -0,0 +1,86 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// edit page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - Edit Board Log Entry");
+
+	if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '')
+		die("serial number not specified!");
+	$serno=intval($_REQUEST['serno']);
+
+	if (!isset($_REQUEST['logno']) || $_REQUEST['logno'] == '')
+		die("log number not specified!");
+	$logno=intval($_REQUEST['logno']);
+
+	$pserno = sprintf("%010d", $serno);
+	$plogno = sprintf("%010d", $logno);
+
+	echo "<center><b><font size=+2>";
+	echo "Board Serial Number: $pserno, Log Number: $plogno";
+	echo "</font></b></center>\n";
+
+?>
+<p>
+<form action=doedlog.php method=POST>
+<?php
+	echo "<input type=hidden name=serno value=$serno>\n";
+	echo "<input type=hidden name=logno value=$logno>\n";
+
+	$r=mysql_query("select * from log where serno=$serno and logno=$logno");
+	$row=mysql_fetch_array($r);
+	if(!$row)
+		die("no record of log entry with serial number '$serno' " .
+			"and log number '$logno' in database");
+
+	begin_table(3);
+
+	// date date
+	print_field("date", $row);
+
+	// who char(20)
+	print_field("who", $row);
+
+	// details text
+	print_field_multiline("details", $row, 60, 10, 'text_filter');
+
+	end_table();
+
+	echo "<p>\n";
+	echo "<center><b>";
+	echo "<font color=#ff0000>WARNING: NO UNDO ON DELETE!</font>";
+	echo "<br></br>\n";
+	echo "<tt>[ <a href=\"dodellog.php?serno=$serno&logno=$logno\">delete</a> ]</tt>";
+	echo "</b></center>\n";
+	echo "</p>\n";
+?>
+<p>
+<table align=center width="100%">
+<tr>
+  <td align=center>
+    <input type=submit value=Edit>
+  </td>
+  <td>
+    &nbsp;
+  </td>
+  <td align=center>
+    <input type=reset value=Reset>
+  </td>
+  <td>
+    &nbsp;
+  </td>
+  <td align=center>
+    <a href="index.php">Back to Start</a>
+  </td>
+</tr>
+</table>
+</p>
+</form>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/execute.php b/marvell/uboot/tools/bddb/execute.php
new file mode 100644
index 0000000..0b62882
--- /dev/null
+++ b/marvell/uboot/tools/bddb/execute.php
@@ -0,0 +1,33 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	$serno=isset($_REQUEST['serno'])?$_REQUEST['serno']:'';
+
+	$submit=isset($_REQUEST['submit'])?$_REQUEST['submit']:"[NOT SET]";
+
+	switch ($submit) {
+
+	case "New":
+		require("new.php");
+		break;
+
+	case "Edit":
+		require("edit.php");
+		break;
+
+	case "Browse":
+		require("browse.php");
+		break;
+
+	case "Log":
+		require("brlog.php");
+		break;
+
+	default:
+		require("badsubmit.php");
+		break;
+	}
+?>
diff --git a/marvell/uboot/tools/bddb/index.php b/marvell/uboot/tools/bddb/index.php
new file mode 100644
index 0000000..842aed5
--- /dev/null
+++ b/marvell/uboot/tools/bddb/index.php
@@ -0,0 +1,38 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	require("defs.php");
+	pg_head("$bddb_label");
+?>
+<font size="+4">
+  <form action=execute.php method=POST>
+    <table width="100%" cellspacing=10 cellpadding=10>
+      <tr>
+	<td align=center>
+	  <input type=submit name=submit value="New"></input>
+	</td>
+	<td align=center>
+	  <input type=submit name=submit value="Edit"></input>
+	</td>
+	<td align=center>
+	  <input type=submit name=submit value="Browse"></input>
+	</td>
+	<td align=center>
+	  <input type=submit name=submit value="Log"></input>
+	</td>
+      </tr>
+      <tr>
+	<td align=center colspan=4>
+	  <b>Serial Number:</b>
+	  <input type=text name=serno size=10 maxsize=10 value=""></input>
+	</td>
+      </tr>
+    </table>
+  </form>
+</font>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/new.php b/marvell/uboot/tools/bddb/new.php
new file mode 100644
index 0000000..30323ff
--- /dev/null
+++ b/marvell/uboot/tools/bddb/new.php
@@ -0,0 +1,120 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// edit page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - New Board Registration");
+?>
+<form action=donew.php method=POST>
+<p></p>
+<?php
+	$serno=intval($serno);
+	// if a serial number was supplied, fetch the record
+	// and use its contents as defaults
+	if ($serno != 0) {
+		$r=mysql_query("select * from boards where serno=$serno");
+		$row=mysql_fetch_array($r);
+		if(!$row)die("no record of serial number '$serno' in database");
+	}
+	else
+		$row = array();
+
+	begin_table(5);
+
+	// date date
+	print_field("date", array('date' => date("Y-m-d")));
+
+	// batch char(32)
+	print_field("batch", $row, 32);
+
+	// type enum('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY')
+	print_enum("type", $row, $type_vals, 0);
+
+	// rev tinyint(3) unsigned zerofill
+	print_field("rev", $row, 3, 'rev_filter');
+
+	// sdram[0-3] enum('32M','64M','128M','256M')
+	print_enum_multi("sdram", $row, $sdram_vals, 4, array(2));
+
+	// flash[0-3] enum('4M','8M','16M','32M','64M')
+	print_enum_multi("flash", $row, $flash_vals, 4, array(2));
+
+	// zbt[0-f] enum('512K','1M','2M','4M')
+	print_enum_multi("zbt", $row, $zbt_vals, 16, array(2, 2));
+
+	// xlxtyp[0-3] enum('XCV300E','XCV400E','XCV600E')
+	print_enum_multi("xlxtyp", $row, $xlxtyp_vals, 4, array(1), 1);
+
+	// xlxspd[0-3] enum('6','7','8')
+	print_enum_multi("xlxspd", $row, $xlxspd_vals, 4, array(1), 1);
+
+	// xlxtmp[0-3] enum('COM','IND')
+	print_enum_multi("xlxtmp", $row, $xlxtmp_vals, 4, array(1), 1);
+
+	// xlxgrd[0-3] enum('NORMAL','ENGSAMP')
+	print_enum_multi("xlxgrd", $row, $xlxgrd_vals, 4, array(1), 1);
+
+	// cputyp enum('MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)')
+	print_enum("cputyp", $row, $cputyp_vals, 1);
+
+	// cpuspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+	print_enum_select("cpuspd", $row, $clk_vals, 4);
+
+	// cpmspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+	print_enum_select("cpmspd", $row, $clk_vals, 4);
+
+	// busspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+	print_enum_select("busspd", $row, $clk_vals, 2);
+
+	// hstype enum('AMCC-S2064A')
+	print_enum("hstype", $row, $hstype_vals, 1);
+
+	// hschin enum('0','1','2','3','4')
+	print_enum("hschin", $row, $hschin_vals, 4);
+
+	// hschout enum('0','1','2','3','4')
+	print_enum("hschout", $row, $hschout_vals, 4);
+
+	end_table();
+?>
+<p></p>
+<table width="100%">
+<tr>
+  <td align=center colspan=3>
+    Allocate
+    <input type=text name=quant size=2 maxlength=2 value=" 1">
+    board serial number(s)
+  </td>
+</tr>
+<tr>
+  <td align=center colspan=3>
+    <input type=checkbox name=geneths checked>
+    Generate Ethernet Address(es)
+  </td>
+</tr>
+<tr>
+  <td colspan=3>
+    &nbsp;
+  </td>
+</tr>
+<tr>
+  <td align=center>
+    <input type=submit value="Register Board">
+  </td>
+  <td>
+    &nbsp;
+  </td>
+  <td align=center>
+    <input type=reset value="Reset Form Contents">
+  </td>
+</tr>
+</table>
+</form>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bddb/newlog.php b/marvell/uboot/tools/bddb/newlog.php
new file mode 100644
index 0000000..609bb85
--- /dev/null
+++ b/marvell/uboot/tools/bddb/newlog.php
@@ -0,0 +1,54 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+	// (C) Copyright 2001
+	// Murray Jensen <Murray.Jensen@csiro.au>
+	// CSIRO Manufacturing Science and Technology, Preston Lab
+
+	// edit page (hymod_bddb / boards)
+
+	require("defs.php");
+
+	pg_head("$bddb_label - New Log Entry");
+
+	if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '')
+		die("serial number not specified or invalid!");
+	$serno=intval($_REQUEST['serno']);
+
+	if (isset($_REQUEST['logno'])) {
+		$logno=$_REQUEST['logno'];
+		die("log number must not be specified when adding! ($logno)");
+	}
+?>
+<form action=donewlog.php method=POST>
+<p></p>
+<?php
+	echo "<input type=hidden name=serno value=$serno>\n";
+
+	begin_table(3);
+
+	// date date
+	print_field("date", array('date' => date("Y-m-d")));
+
+	// who char(20)
+	print_field("who", array());
+
+	// details text
+	print_field_multiline("details", array(), 60, 10, 'text_filter');
+
+	end_table();
+?>
+<p></p>
+<table width="100%">
+<tr>
+  <td align=center>
+    <input type=submit value="Add Log Entry">
+  </td>
+  <td align=center>
+    <input type=reset value="Reset Form Contents">
+  </td>
+</tr>
+</table>
+</form>
+<?php
+	pg_foot();
+?>
diff --git a/marvell/uboot/tools/bin2header.c b/marvell/uboot/tools/bin2header.c
new file mode 100644
index 0000000..27a5b6a
--- /dev/null
+++ b/marvell/uboot/tools/bin2header.c
@@ -0,0 +1,40 @@
+/* bin2header.c - program to convert binary file into a C structure
+ * definition to be included in a header file.
+ *
+ * (C) Copyright 2008 by Harald Welte <laforge@openmoko.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	if (argc < 2) {
+		fprintf(stderr, "%s needs one argument: the structure name\n",
+			argv[0]);
+		exit(1);
+	}
+
+	printf("/* bin2header output - automatically generated */\n");
+	printf("unsigned char %s[] = {\n", argv[1]);
+
+	while (1) {
+		int i, nread;
+		unsigned char buf[10];
+		nread = read(0, buf, sizeof(buf));
+		if (nread <= 0)
+			break;
+
+		printf("\t");
+		for (i = 0; i < nread - 1; i++)
+			printf("0x%02x, ", buf[i]);
+
+		printf("0x%02x,\n", buf[nread-1]);
+	}
+
+	printf("};\n");
+
+	exit(0);
+}
diff --git a/marvell/uboot/tools/bmp_logo.c b/marvell/uboot/tools/bmp_logo.c
new file mode 100644
index 0000000..2247adc
--- /dev/null
+++ b/marvell/uboot/tools/bmp_logo.c
@@ -0,0 +1,203 @@
+#include "compiler.h"
+
+enum {
+	MODE_GEN_INFO,
+	MODE_GEN_DATA
+};
+
+typedef struct bitmap_s {		/* bitmap description */
+	uint16_t width;
+	uint16_t height;
+	uint8_t	palette[256*3];
+	uint8_t	*data;
+} bitmap_t;
+
+#define DEFAULT_CMAP_SIZE	16	/* size of default color map	*/
+
+void usage(const char *prog)
+{
+	fprintf(stderr, "Usage: %s [--gen-info|--gen-data] file\n", prog);
+}
+
+/*
+ * Neutralize little endians.
+ */
+uint16_t le_short(uint16_t x)
+{
+    uint16_t val;
+    uint8_t *p = (uint8_t *)(&x);
+
+    val =  (*p++ & 0xff) << 0;
+    val |= (*p & 0xff) << 8;
+
+    return val;
+}
+
+void skip_bytes (FILE *fp, int n)
+{
+	while (n-- > 0)
+		fgetc (fp);
+}
+
+__attribute__ ((__noreturn__))
+int error (char * msg, FILE *fp)
+{
+	fprintf (stderr, "ERROR: %s\n", msg);
+
+	fclose (fp);
+
+	exit (EXIT_FAILURE);
+}
+
+void gen_info(bitmap_t *b, uint16_t n_colors)
+{
+	printf("/*\n"
+		" * Automatically generated by \"tools/bmp_logo\"\n"
+		" *\n"
+		" * DO NOT EDIT\n"
+		" *\n"
+		" */\n\n\n"
+		"#ifndef __BMP_LOGO_H__\n"
+		"#define __BMP_LOGO_H__\n\n"
+		"#define BMP_LOGO_WIDTH\t\t%d\n"
+		"#define BMP_LOGO_HEIGHT\t\t%d\n"
+		"#define BMP_LOGO_COLORS\t\t%d\n"
+		"#define BMP_LOGO_OFFSET\t\t%d\n\n"
+		"extern unsigned short bmp_logo_palette[];\n"
+		"extern unsigned char bmp_logo_bitmap[];\n\n"
+		"#endif /* __BMP_LOGO_H__ */\n",
+		b->width, b->height, n_colors,
+		DEFAULT_CMAP_SIZE);
+}
+
+int main (int argc, char *argv[])
+{
+	int	mode, i, x;
+	FILE	*fp;
+	bitmap_t bmp;
+	bitmap_t *b = &bmp;
+	uint16_t data_offset, n_colors;
+
+	if (argc < 3) {
+		usage(argv[0]);
+		exit (EXIT_FAILURE);
+	}
+
+	if (!strcmp(argv[1], "--gen-info"))
+		mode = MODE_GEN_INFO;
+	else if (!strcmp(argv[1], "--gen-data"))
+		mode = MODE_GEN_DATA;
+	else {
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	fp = fopen(argv[2], "rb");
+	if (!fp) {
+		perror(argv[2]);
+		exit (EXIT_FAILURE);
+	}
+
+	if (fgetc (fp) != 'B' || fgetc (fp) != 'M')
+		error ("Input file is not a bitmap", fp);
+
+	/*
+	 * read width and height of the image, and the number of colors used;
+	 * ignore the rest
+	 */
+	skip_bytes (fp, 8);
+	if (fread (&data_offset, sizeof (uint16_t), 1, fp) != 1)
+		error ("Couldn't read bitmap data offset", fp);
+	skip_bytes (fp, 6);
+	if (fread (&b->width,   sizeof (uint16_t), 1, fp) != 1)
+		error ("Couldn't read bitmap width", fp);
+	skip_bytes (fp, 2);
+	if (fread (&b->height,  sizeof (uint16_t), 1, fp) != 1)
+		error ("Couldn't read bitmap height", fp);
+	skip_bytes (fp, 22);
+	if (fread (&n_colors, sizeof (uint16_t), 1, fp) != 1)
+		error ("Couldn't read bitmap colors", fp);
+	skip_bytes (fp, 6);
+
+	/*
+	 * Repair endianess.
+	 */
+	data_offset = le_short(data_offset);
+	b->width = le_short(b->width);
+	b->height = le_short(b->height);
+	n_colors = le_short(n_colors);
+
+	/* assume we are working with an 8-bit file */
+	if ((n_colors == 0) || (n_colors > 256 - DEFAULT_CMAP_SIZE)) {
+		/* reserve DEFAULT_CMAP_SIZE color map entries for default map */
+		n_colors = 256 - DEFAULT_CMAP_SIZE;
+	}
+
+	if (mode == MODE_GEN_INFO) {
+		gen_info(b, n_colors);
+		goto out;
+	}
+
+	printf("/*\n"
+		" * Automatically generated by \"tools/bmp_logo\"\n"
+		" *\n"
+		" * DO NOT EDIT\n"
+		" *\n"
+		" */\n\n\n"
+		"#ifndef __BMP_LOGO_DATA_H__\n"
+		"#define __BMP_LOGO_DATA_H__\n\n");
+
+	/* allocate memory */
+	if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL)
+		error ("Error allocating memory for file", fp);
+
+	/* read and print the palette information */
+	printf("unsigned short bmp_logo_palette[] = {\n");
+
+	for (i=0; i<n_colors; ++i) {
+		b->palette[(int)(i*3+2)] = fgetc(fp);
+		b->palette[(int)(i*3+1)] = fgetc(fp);
+		b->palette[(int)(i*3+0)] = fgetc(fp);
+		x=fgetc(fp);
+
+		printf ("%s0x0%X%X%X,%s",
+			((i%8) == 0) ? "\t" : "  ",
+			(b->palette[(int)(i*3+0)] >> 4) & 0x0F,
+			(b->palette[(int)(i*3+1)] >> 4) & 0x0F,
+			(b->palette[(int)(i*3+2)] >> 4) & 0x0F,
+			((i%8) == 7) ? "\n" : ""
+		);
+	}
+
+	/* seek to offset indicated by file header */
+	fseek(fp, (long)data_offset, SEEK_SET);
+
+	/* read the bitmap; leave room for default color map */
+	printf ("\n");
+	printf ("};\n");
+	printf ("\n");
+	printf("unsigned char bmp_logo_bitmap[] = {\n");
+	for (i=(b->height-1)*b->width; i>=0; i-=b->width) {
+		for (x = 0; x < b->width; x++) {
+			b->data[i + x] = (uint8_t) fgetc(fp)
+						+ DEFAULT_CMAP_SIZE;
+		}
+	}
+
+	for (i=0; i<(b->height*b->width); ++i) {
+		if ((i%8) == 0)
+			putchar ('\t');
+		printf ("0x%02X,%c",
+			b->data[i],
+			((i%8) == 7) ? '\n' : ' '
+		);
+	}
+	printf ("\n"
+		"};\n\n"
+		"#endif /* __BMP_LOGO_DATA_H__ */\n"
+	);
+
+out:
+	fclose(fp);
+	return 0;
+}
diff --git a/marvell/uboot/tools/buildman/.gitignore b/marvell/uboot/tools/buildman/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/marvell/uboot/tools/buildman/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/marvell/uboot/tools/buildman/README b/marvell/uboot/tools/buildman/README
new file mode 100644
index 0000000..c30c1d4
--- /dev/null
+++ b/marvell/uboot/tools/buildman/README
@@ -0,0 +1,690 @@
+# Copyright (c) 2013 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+What is this?
+=============
+
+This tool handles building U-Boot to check that you have not broken it
+with your patch series. It can build each individual commit and report
+which boards fail on which commits, and which errors come up. It aims
+to make full use of multi-processor machines.
+
+A key feature of buildman is its output summary, which allows warnings,
+errors or image size increases in a particular commit or board to be
+quickly identified and the offending commit pinpointed. This can be a big
+help for anyone working with >10 patches at a time.
+
+
+Caveats
+=======
+
+Buildman is still in its infancy. It is already a very useful tool, but
+expect to find problems and send patches.
+
+Buildman can be stopped and restarted, in which case it will continue
+where it left off. This should happen cleanly and without side-effects.
+If not, it is a bug, for which a patch would be welcome.
+
+Buildman gets so tied up in its work that it can ignore the outside world.
+You may need to press Ctrl-C several times to quit it. Also it will print
+out various exceptions when stopped.
+
+
+Theory of Operation
+===================
+
+(please read this section in full twice or you will be perpetually confused)
+
+Buildman is a builder. It is not make, although it runs make. It does not
+produce any useful output on the terminal while building, except for
+progress information. All the output (errors, warnings and binaries if you
+are ask for them) is stored in output directories, which you can look at
+while the build is progressing, or when it is finished.
+
+Buildman produces a concise summary of which boards succeeded and failed.
+It shows which commit introduced which board failure using a simple
+red/green colour coding. Full error information can be requested, in which
+case it is de-duped and displayed against the commit that introduced the
+error. An example workflow is below.
+
+Buildman stores image size information and can report changes in image size
+from commit to commit. An example of this is below.
+
+Buildman starts multiple threads, and each thread builds for one board at
+a time. A thread starts at the first commit, configures the source for your
+board and builds it. Then it checks out the next commit and does an
+incremental build. Eventually the thread reaches the last commit and stops.
+If errors or warnings are found along the way, the thread will reconfigure
+after every commit, and your build will be very slow. This is because a
+file that produces just a warning would not normally be rebuilt in an
+incremental build.
+
+Buildman works in an entirely separate place from your U-Boot repository.
+It creates a separate working directory for each thread, and puts the
+output files in the working directory, organised by commit name and board
+name, in a two-level hierarchy.
+
+Buildman is invoked in your U-Boot directory, the one with the .git
+directory. It clones this repository into a copy for each thread, and the
+threads do not affect the state of your git repository. Any checkouts done
+by the thread affect only the working directory for that thread.
+
+Buildman automatically selects the correct toolchain for each board. You
+must supply suitable toolchains, but buildman takes care of selecting the
+right one.
+
+Buildman always builds a branch, and always builds the upstream commit as
+well, for comparison. It cannot build individual commits at present, unless
+(maybe) you point it at an empty branch. Put all your commits in a branch,
+set the branch's upstream to a valid value, and all will be well. Otherwise
+buildman will perform random actions. Use -n to check what the random
+actions might be.
+
+Buildman is optimised for building many commits at once, for many boards.
+On multi-core machines, Buildman is fast because it uses most of the
+available CPU power. When it gets to the end, or if you are building just
+a few commits or boards, it will be pretty slow. As a tip, if you don't
+plan to use your machine for anything else, you can use -T to increase the
+number of threads beyond the default.
+
+Buildman lets you build all boards, or a subset. Specify the subset by passing
+command-line arguments that list the desired board name, architecture name,
+SOC name, or anything else in the boards.cfg file. Multiple arguments are
+allowed. Each argument will be interpreted as a regular expression, so
+behaviour is a superset of exact or substring matching. Examples are:
+
+* 'tegra20'      All boards with a Tegra20 SoC
+* 'tegra'        All boards with any Tegra Soc (Tegra20, Tegra30, Tegra114...)
+* '^tegra[23]0$' All boards with either Tegra20 or Tegra30 SoC
+* 'powerpc'      All PowerPC boards
+
+Buildman does not store intermediate object files. It optionally copies
+the binary output into a directory when a build is successful. Size
+information is always recorded. It needs a fair bit of disk space to work,
+typically 250MB per thread.
+
+
+Setting up
+==========
+
+1. Get the U-Boot source. You probably already have it, but if not these
+steps should get you started with a repo and some commits for testing.
+
+$ cd /path/to/u-boot
+$ git clone git://git.denx.de/u-boot.git .
+$ git checkout -b my-branch origin/master
+$ # Add some commits to the branch, reading for testing
+
+2. Create ~/.buildman to tell buildman where to find tool chains. As an
+example:
+
+# Buildman settings file
+
+[toolchain]
+root: /
+rest: /toolchains/*
+eldk: /opt/eldk-4.2
+
+[toolchain-alias]
+x86: i386
+blackfin: bfin
+sh: sh4
+nds32: nds32le
+openrisc: or32
+
+
+This selects the available toolchain paths. Add the base directory for
+each of your toolchains here. Buildman will search inside these directories
+and also in any '/usr' and '/usr/bin' subdirectories.
+
+Make sure the tags (here root: rest: and eldk:) are unique.
+
+The toolchain-alias section indicates that the i386 toolchain should be used
+to build x86 commits.
+
+
+2. Check the available toolchains
+
+Run this check to make sure that you have a toolchain for every architecture.
+
+$ ./tools/buildman/buildman --list-tool-chains
+Scanning for tool chains
+   - scanning path '/'
+      - looking in '/.'
+      - looking in '/bin'
+      - looking in '/usr/bin'
+         - found '/usr/bin/gcc'
+Tool chain test:  OK
+         - found '/usr/bin/c89-gcc'
+Tool chain test:  OK
+         - found '/usr/bin/c99-gcc'
+Tool chain test:  OK
+         - found '/usr/bin/x86_64-linux-gnu-gcc'
+Tool chain test:  OK
+   - scanning path '/toolchains/powerpc-linux'
+      - looking in '/toolchains/powerpc-linux/.'
+      - looking in '/toolchains/powerpc-linux/bin'
+         - found '/toolchains/powerpc-linux/bin/powerpc-linux-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/powerpc-linux/usr/bin'
+   - scanning path '/toolchains/nds32le-linux-glibc-v1f'
+      - looking in '/toolchains/nds32le-linux-glibc-v1f/.'
+      - looking in '/toolchains/nds32le-linux-glibc-v1f/bin'
+         - found '/toolchains/nds32le-linux-glibc-v1f/bin/nds32le-linux-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/nds32le-linux-glibc-v1f/usr/bin'
+   - scanning path '/toolchains/nios2'
+      - looking in '/toolchains/nios2/.'
+      - looking in '/toolchains/nios2/bin'
+         - found '/toolchains/nios2/bin/nios2-linux-gcc'
+Tool chain test:  OK
+         - found '/toolchains/nios2/bin/nios2-linux-uclibc-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/nios2/usr/bin'
+         - found '/toolchains/nios2/usr/bin/nios2-linux-gcc'
+Tool chain test:  OK
+         - found '/toolchains/nios2/usr/bin/nios2-linux-uclibc-gcc'
+Tool chain test:  OK
+   - scanning path '/toolchains/microblaze-unknown-linux-gnu'
+      - looking in '/toolchains/microblaze-unknown-linux-gnu/.'
+      - looking in '/toolchains/microblaze-unknown-linux-gnu/bin'
+         - found '/toolchains/microblaze-unknown-linux-gnu/bin/microblaze-unknown-linux-gnu-gcc'
+Tool chain test:  OK
+         - found '/toolchains/microblaze-unknown-linux-gnu/bin/mb-linux-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/microblaze-unknown-linux-gnu/usr/bin'
+   - scanning path '/toolchains/mips-linux'
+      - looking in '/toolchains/mips-linux/.'
+      - looking in '/toolchains/mips-linux/bin'
+         - found '/toolchains/mips-linux/bin/mips-linux-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/mips-linux/usr/bin'
+   - scanning path '/toolchains/old'
+      - looking in '/toolchains/old/.'
+      - looking in '/toolchains/old/bin'
+      - looking in '/toolchains/old/usr/bin'
+   - scanning path '/toolchains/i386-linux'
+      - looking in '/toolchains/i386-linux/.'
+      - looking in '/toolchains/i386-linux/bin'
+         - found '/toolchains/i386-linux/bin/i386-linux-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/i386-linux/usr/bin'
+   - scanning path '/toolchains/bfin-uclinux'
+      - looking in '/toolchains/bfin-uclinux/.'
+      - looking in '/toolchains/bfin-uclinux/bin'
+         - found '/toolchains/bfin-uclinux/bin/bfin-uclinux-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/bfin-uclinux/usr/bin'
+   - scanning path '/toolchains/sparc-elf'
+      - looking in '/toolchains/sparc-elf/.'
+      - looking in '/toolchains/sparc-elf/bin'
+         - found '/toolchains/sparc-elf/bin/sparc-elf-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/sparc-elf/usr/bin'
+   - scanning path '/toolchains/arm-2010q1'
+      - looking in '/toolchains/arm-2010q1/.'
+      - looking in '/toolchains/arm-2010q1/bin'
+         - found '/toolchains/arm-2010q1/bin/arm-none-linux-gnueabi-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/arm-2010q1/usr/bin'
+   - scanning path '/toolchains/from'
+      - looking in '/toolchains/from/.'
+      - looking in '/toolchains/from/bin'
+      - looking in '/toolchains/from/usr/bin'
+   - scanning path '/toolchains/sh4-gentoo-linux-gnu'
+      - looking in '/toolchains/sh4-gentoo-linux-gnu/.'
+      - looking in '/toolchains/sh4-gentoo-linux-gnu/bin'
+         - found '/toolchains/sh4-gentoo-linux-gnu/bin/sh4-gentoo-linux-gnu-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/sh4-gentoo-linux-gnu/usr/bin'
+   - scanning path '/toolchains/avr32-linux'
+      - looking in '/toolchains/avr32-linux/.'
+      - looking in '/toolchains/avr32-linux/bin'
+         - found '/toolchains/avr32-linux/bin/avr32-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/avr32-linux/usr/bin'
+   - scanning path '/toolchains/m68k-linux'
+      - looking in '/toolchains/m68k-linux/.'
+      - looking in '/toolchains/m68k-linux/bin'
+         - found '/toolchains/m68k-linux/bin/m68k-linux-gcc'
+Tool chain test:  OK
+      - looking in '/toolchains/m68k-linux/usr/bin'
+List of available toolchains (17):
+arm       : /toolchains/arm-2010q1/bin/arm-none-linux-gnueabi-gcc
+avr32     : /toolchains/avr32-linux/bin/avr32-gcc
+bfin      : /toolchains/bfin-uclinux/bin/bfin-uclinux-gcc
+c89       : /usr/bin/c89-gcc
+c99       : /usr/bin/c99-gcc
+i386      : /toolchains/i386-linux/bin/i386-linux-gcc
+m68k      : /toolchains/m68k-linux/bin/m68k-linux-gcc
+mb        : /toolchains/microblaze-unknown-linux-gnu/bin/mb-linux-gcc
+microblaze: /toolchains/microblaze-unknown-linux-gnu/bin/microblaze-unknown-linux-gnu-gcc
+mips      : /toolchains/mips-linux/bin/mips-linux-gcc
+nds32le   : /toolchains/nds32le-linux-glibc-v1f/bin/nds32le-linux-gcc
+nios2     : /toolchains/nios2/bin/nios2-linux-gcc
+powerpc   : /toolchains/powerpc-linux/bin/powerpc-linux-gcc
+sandbox   : /usr/bin/gcc
+sh4       : /toolchains/sh4-gentoo-linux-gnu/bin/sh4-gentoo-linux-gnu-gcc
+sparc     : /toolchains/sparc-elf/bin/sparc-elf-gcc
+x86_64    : /usr/bin/x86_64-linux-gnu-gcc
+
+
+You can see that everything is covered, even some strange ones that won't
+be used (c88 and c99). This is a feature.
+
+
+How to run it
+=============
+
+First do a dry run using the -n flag: (replace <branch> with a real, local
+branch with a valid upstream)
+
+$ ./tools/buildman/buildman -b <branch> -n
+
+If it can't detect the upstream branch, try checking out the branch, and
+doing something like 'git branch --set-upstream <branch> upstream/master'
+or something similar.
+
+As an exmmple:
+
+Dry run, so not doing much. But I would do this:
+
+Building 18 commits for 1059 boards (4 threads, 1 job per thread)
+Build directory: ../lcd9b
+    5bb3505 Merge branch 'master' of git://git.denx.de/u-boot-arm
+    c18f1b4 tegra: Use const for pinmux_config_pingroup/table()
+    2f043ae tegra: Add display support to funcmux
+    e349900 tegra: fdt: Add pwm binding and node
+    424a5f0 tegra: fdt: Add LCD definitions for Tegra
+    0636ccf tegra: Add support for PWM
+    a994fe7 tegra: Add SOC support for display/lcd
+    fcd7350 tegra: Add LCD driver
+    4d46e9d tegra: Add LCD support to Nvidia boards
+    991bd48 arm: Add control over cachability of memory regions
+    54e8019 lcd: Add CONFIG_LCD_ALIGNMENT to select frame buffer alignment
+    d92aff7 lcd: Add support for flushing LCD fb from dcache after update
+    dbd0677 tegra: Align LCD frame buffer to section boundary
+    0cff9b8 tegra: Support control of cache settings for LCD
+    9c56900 tegra: fdt: Add LCD definitions for Seaboard
+    5cc29db lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console
+    cac5a23 tegra: Enable display/lcd support on Seaboard
+    49ff541 wip
+
+Total boards to build for each commit: 1059
+
+This shows that it will build all 1059 boards, using 4 threads (because
+we have a 4-core CPU). Each thread will run with -j1, meaning that each
+make job will use a single CPU. The list of commits to be built helps you
+confirm that things look about right. Notice that buildman has chosen a
+'base' directory for you, immediately above your source tree.
+
+Buildman works entirely inside the base directory, here ../lcd9b,
+creating a working directory for each thread, and creating output
+directories for each commit and board.
+
+
+Suggested Workflow
+==================
+
+To run the build for real, take off the -n:
+
+$ ./tools/buildman/buildman -b <branch>
+
+Buildman will set up some working directories, and get started. After a
+minute or so it will settle down to a steady pace, with a display like this:
+
+Building 18 commits for 1059 boards (4 threads, 1 job per thread)
+  528   36  124 /19062  1:13:30  : SIMPC8313_SP
+
+This means that it is building 19062 board/commit combinations. So far it
+has managed to succesfully build 528. Another 36 have built with warnings,
+and 124 more didn't build at all. Buildman expects to complete the process
+in an hour and 15 minutes. Use this time to buy a faster computer.
+
+
+To find out how the build went, ask for a summary with -s. You can do this
+either before the build completes (presumably in another terminal) or or
+afterwards. Let's work through an example of how this is used:
+
+$ ./tools/buildman/buildman -b lcd9b -s
+...
+01: Merge branch 'master' of git://git.denx.de/u-boot-arm
+   powerpc:   + galaxy5200_LOWBOOT
+02: tegra: Use const for pinmux_config_pingroup/table()
+03: tegra: Add display support to funcmux
+04: tegra: fdt: Add pwm binding and node
+05: tegra: fdt: Add LCD definitions for Tegra
+06: tegra: Add support for PWM
+07: tegra: Add SOC support for display/lcd
+08: tegra: Add LCD driver
+09: tegra: Add LCD support to Nvidia boards
+10: arm: Add control over cachability of memory regions
+11: lcd: Add CONFIG_LCD_ALIGNMENT to select frame buffer alignment
+12: lcd: Add support for flushing LCD fb from dcache after update
+       arm:   + lubbock
+13: tegra: Align LCD frame buffer to section boundary
+14: tegra: Support control of cache settings for LCD
+15: tegra: fdt: Add LCD definitions for Seaboard
+16: lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console
+17: tegra: Enable display/lcd support on Seaboard
+18: wip
+
+This shows which commits have succeeded and which have failed. In this case
+the build is still in progress so many boards are not built yet (use -u to
+see which ones). But still we can see a few failures. The galaxy5200_LOWBOOT
+never builds correctly. This could be a problem with our toolchain, or it
+could be a bug in the upstream. The good news is that we probably don't need
+to blame our commits. The bad news is it isn't tested on that board.
+
+Commit 12 broke lubbock. That's what the '+ lubbock' means. The failure
+is never fixed by a later commit, or you would see lubbock again, in green,
+without the +.
+
+To see the actual error:
+
+$ ./tools/buildman/buildman -b <branch> -se lubbock
+...
+12: lcd: Add support for flushing LCD fb from dcache after update
+       arm:   + lubbock
++common/libcommon.o: In function `lcd_sync':
++/u-boot/lcd9b/.bm-work/00/common/lcd.c:120: undefined reference to `flush_dcache_range'
++arm-none-linux-gnueabi-ld: BFD (Sourcery G++ Lite 2010q1-202) 2.19.51.20090709 assertion fail /scratch/julian/2010q1-release-linux-lite/obj/binutils-src-2010q1-202-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:12572
++make: *** [/u-boot/lcd9b/.bm-work/00/build/u-boot] Error 139
+13: tegra: Align LCD frame buffer to section boundary
+14: tegra: Support control of cache settings for LCD
+15: tegra: fdt: Add LCD definitions for Seaboard
+16: lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console
+-/u-boot/lcd9b/.bm-work/00/common/lcd.c:120: undefined reference to `flush_dcache_range'
++/u-boot/lcd9b/.bm-work/00/common/lcd.c:125: undefined reference to `flush_dcache_range'
+17: tegra: Enable display/lcd support on Seaboard
+18: wip
+
+So the problem is in lcd.c, due to missing cache operations. This information
+should be enough to work out what that commit is doing to break these
+boards. (In this case pxa did not have cache operations defined).
+
+If you see error lines marked with - that means that the errors were fixed
+by that commit. Sometimes commits can be in the wrong order, so that a
+breakage is introduced for a few commits and fixed by later commits. This
+shows up clearly with buildman. You can then reorder the commits and try
+again.
+
+At commit 16, the error moves - you can see that the old error at line 120
+is fixed, but there is a new one at line 126. This is probably only because
+we added some code and moved the broken line futher down the file.
+
+If many boards have the same error, then -e will display the error only
+once. This makes the output as concise as possible.
+
+The full build output in this case is available in:
+
+../lcd9b/12_of_18_gd92aff7_lcd--Add-support-for/lubbock/
+
+   done: Indicates the build was done, and holds the return code from make.
+         This is 0 for a good build, typically 2 for a failure.
+
+   err:  Output from stderr, if any. Errors and warnings appear here.
+
+   log:  Output from stdout. Normally there isn't any since buildman runs
+         in silent mode for now.
+
+   toolchain: Shows information about the toolchain used for the build.
+
+   sizes: Shows image size information.
+
+It is possible to get the build output there also. Use the -k option for
+this. In that case you will also see some output files, like:
+
+   System.map  toolchain  u-boot  u-boot.bin  u-boot.map  autoconf.mk
+   (also SPL versions u-boot-spl and u-boot-spl.bin if available)
+
+
+Checking Image Sizes
+====================
+
+A key requirement for U-Boot is that you keep code/data size to a minimum.
+Where a new feature increases this noticeably it should normally be put
+behind a CONFIG flag so that boards can leave it off and keep the image
+size more or less the same with each new release.
+
+To check the impact of your commits on image size, use -S. For example:
+
+$ ./tools/buildman/buildman -b us-x86 -sS
+Summary of 10 commits for 1066 boards (4 threads, 1 job per thread)
+01: MAKEALL: add support for per architecture toolchains
+02: x86: Add function to get top of usable ram
+       x86: (for 1/3 boards)  text -272.0  rodata +41.0
+03: x86: Add basic cache operations
+04: x86: Permit bootstage and timer data to be used prior to relocation
+       x86: (for 1/3 boards)  data +16.0
+05: x86: Add an __end symbol to signal the end of the U-Boot binary
+       x86: (for 1/3 boards)  text +76.0
+06: x86: Rearrange the output input to remove BSS
+       x86: (for 1/3 boards)  bss -2140.0
+07: x86: Support relocation of FDT on start-up
+       x86: +   coreboot-x86
+08: x86: Add error checking to x86 relocation code
+09: x86: Adjust link device tree include file
+10: x86: Enable CONFIG_OF_CONTROL on coreboot
+
+
+You can see that image size only changed on x86, which is good because this
+series is not supposed to change any other board. From commit 7 onwards the
+build fails so we don't get code size numbers. The numbers are fractional
+because they are an average of all boards for that architecture. The
+intention is to allow you to quickly find image size problems introduced by
+your commits.
+
+Note that the 'text' region and 'rodata' are split out. You should add the
+two together to get the total read-only size (reported as the first column
+in the output from binutil's 'size' utility).
+
+A useful option is --step which lets you skip some commits. For example
+--step 2 will show the image sizes for only every 2nd commit (so it will
+compare the image sizes of the 1st, 3rd, 5th... commits). You can also use
+--step 0 which will compare only the first and last commits. This is useful
+for an overview of how your entire series affects code size.
+
+You can also use -d to see a detailed size breakdown for each board. This
+list is sorted in order from largest growth to largest reduction.
+
+It is possible to go a little further with the -B option (--bloat). This
+shows where U-Boot has bloted, breaking the size change down to the function
+level. Example output is below:
+
+$ ./tools/buildman/buildman -b us-mem4 -sSdB
+...
+19: Roll crc32 into hash infrastructure
+       arm: (for 10/10 boards)  all -143.4  bss +1.2  data -4.8  rodata -48.2 text -91.6
+            paz00          :  all +23  bss -4  rodata -29  text +56
+               u-boot: add: 1/0, grow: 3/-2 bytes: 168/-104 (64)
+                 function                                   old     new   delta
+                 hash_command                                80     160     +80
+                 crc32_wd_buf                                 -      56     +56
+                 ext4fs_read_file                           540     568     +28
+                 insert_var_value_sub                       688     692      +4
+                 run_list_real                             1996    1992      -4
+                 do_mem_crc                                 168      68    -100
+            trimslice      :  all -9  bss +16  rodata -29  text +4
+               u-boot: add: 1/0, grow: 1/-3 bytes: 136/-124 (12)
+                 function                                   old     new   delta
+                 hash_command                                80     160     +80
+                 crc32_wd_buf                                 -      56     +56
+                 ext4fs_iterate_dir                         672     668      -4
+                 ext4fs_read_file                           568     548     -20
+                 do_mem_crc                                 168      68    -100
+            whistler       :  all -9  bss +16  rodata -29  text +4
+               u-boot: add: 1/0, grow: 1/-3 bytes: 136/-124 (12)
+                 function                                   old     new   delta
+                 hash_command                                80     160     +80
+                 crc32_wd_buf                                 -      56     +56
+                 ext4fs_iterate_dir                         672     668      -4
+                 ext4fs_read_file                           568     548     -20
+                 do_mem_crc                                 168      68    -100
+            seaboard       :  all -9  bss -28  rodata -29  text +48
+               u-boot: add: 1/0, grow: 3/-2 bytes: 160/-104 (56)
+                 function                                   old     new   delta
+                 hash_command                                80     160     +80
+                 crc32_wd_buf                                 -      56     +56
+                 ext4fs_read_file                           548     568     +20
+                 run_list_real                             1996    2000      +4
+                 do_nandboot                                760     756      -4
+                 do_mem_crc                                 168      68    -100
+            colibri_t20_iris:  all -9  rodata -29  text +20
+               u-boot: add: 1/0, grow: 2/-3 bytes: 140/-112 (28)
+                 function                                   old     new   delta
+                 hash_command                                80     160     +80
+                 crc32_wd_buf                                 -      56     +56
+                 read_abs_bbt                               204     208      +4
+                 do_nandboot                                760     756      -4
+                 ext4fs_read_file                           576     568      -8
+                 do_mem_crc                                 168      68    -100
+            ventana        :  all -37  bss -12  rodata -29  text +4
+               u-boot: add: 1/0, grow: 1/-3 bytes: 136/-124 (12)
+                 function                                   old     new   delta
+                 hash_command                                80     160     +80
+                 crc32_wd_buf                                 -      56     +56
+                 ext4fs_iterate_dir                         672     668      -4
+                 ext4fs_read_file                           568     548     -20
+                 do_mem_crc                                 168      68    -100
+            harmony        :  all -37  bss -16  rodata -29  text +8
+               u-boot: add: 1/0, grow: 2/-3 bytes: 140/-124 (16)
+                 function                                   old     new   delta
+                 hash_command                                80     160     +80
+                 crc32_wd_buf                                 -      56     +56
+                 nand_write_oob_syndrome                    428     432      +4
+                 ext4fs_iterate_dir                         672     668      -4
+                 ext4fs_read_file                           568     548     -20
+                 do_mem_crc                                 168      68    -100
+            medcom-wide    :  all -417  bss +28  data -16  rodata -93  text -336
+               u-boot: add: 1/-1, grow: 1/-2 bytes: 88/-376 (-288)
+                 function                                   old     new   delta
+                 crc32_wd_buf                                 -      56     +56
+                 do_fat_read_at                            2872    2904     +32
+                 hash_algo                                   16       -     -16
+                 do_mem_crc                                 168      68    -100
+                 hash_command                               420     160    -260
+            tec            :  all -449  bss -4  data -16  rodata -93  text -336
+               u-boot: add: 1/-1, grow: 1/-2 bytes: 88/-376 (-288)
+                 function                                   old     new   delta
+                 crc32_wd_buf                                 -      56     +56
+                 do_fat_read_at                            2872    2904     +32
+                 hash_algo                                   16       -     -16
+                 do_mem_crc                                 168      68    -100
+                 hash_command                               420     160    -260
+            plutux         :  all -481  bss +16  data -16  rodata -93  text -388
+               u-boot: add: 1/-1, grow: 1/-3 bytes: 68/-408 (-340)
+                 function                                   old     new   delta
+                 crc32_wd_buf                                 -      56     +56
+                 do_load_serial_bin                        1688    1700     +12
+                 hash_algo                                   16       -     -16
+                 do_fat_read_at                            2904    2872     -32
+                 do_mem_crc                                 168      68    -100
+                 hash_command                               420     160    -260
+   powerpc: (for 5/5 boards)  all +37.4  data -3.2  rodata -41.8  text +82.4
+            MPC8610HPCD    :  all +55  rodata -29  text +84
+               u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80)
+                 function                                   old     new   delta
+                 hash_command                                 -     176    +176
+                 do_mem_crc                                 184      88     -96
+            MPC8641HPCN    :  all +55  rodata -29  text +84
+               u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80)
+                 function                                   old     new   delta
+                 hash_command                                 -     176    +176
+                 do_mem_crc                                 184      88     -96
+            MPC8641HPCN_36BIT:  all +55  rodata -29  text +84
+               u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80)
+                 function                                   old     new   delta
+                 hash_command                                 -     176    +176
+                 do_mem_crc                                 184      88     -96
+            sbc8641d       :  all +55  rodata -29  text +84
+               u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80)
+                 function                                   old     new   delta
+                 hash_command                                 -     176    +176
+                 do_mem_crc                                 184      88     -96
+            xpedite517x    :  all -33  data -16  rodata -93  text +76
+               u-boot: add: 1/-1, grow: 0/-1 bytes: 176/-112 (64)
+                 function                                   old     new   delta
+                 hash_command                                 -     176    +176
+                 hash_algo                                   16       -     -16
+                 do_mem_crc                                 184      88     -96
+...
+
+
+This shows that commit 19 has increased text size for arm (although only one
+board was built) and by 96 bytes for powerpc. This increase was offset in both
+cases by reductions in rodata and data/bss.
+
+Shown below the summary lines is the sizes for each board. Below each board
+is the sizes for each function. This information starts with:
+
+   add - number of functions added / removed
+   grow - number of functions which grew / shrunk
+   bytes - number of bytes of code added to / removed from all functions,
+            plus the total byte change in brackets
+
+The change seems to be that hash_command() has increased by more than the
+do_mem_crc() function has decreased. The function sizes typically add up to
+roughly the text area size, but note that every read-only section except
+rodata is included in 'text', so the function total does not exactly
+correspond.
+
+It is common when refactoring code for the rodata to decrease as the text size
+increases, and vice versa.
+
+
+Providing 'make' flags
+======================
+
+U-Boot's build system supports a few flags (such as BUILD_TAG) which affect
+the build product. These flags can be specified in the buildman settings
+file. They can also be useful when building U-Boot against other open source
+software.
+
+[make-flags]
+at91-boards=ENABLE_AT91_TEST=1
+snapper9260=${at91-boards} BUILD_TAG=442
+snapper9g45=${at91-boards} BUILD_TAG=443
+
+This will use 'make ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
+and 'make ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. A special
+variable ${target} is available to access the target name (snapper9260 and
+snapper9g20 in this case). Variables are resolved recursively.
+
+It is expected that any variables added are dealt with in U-Boot's
+config.mk file and documented in the README.
+
+
+Other options
+=============
+
+Buildman has various other command line options. Try --help to see them.
+
+
+TODO
+====
+
+This has mostly be written in my spare time as a response to my difficulties
+in testing large series of patches. Apart from tidying up there is quite a
+bit of scope for improvement. Things like better error diffs, easier access
+to log files, error display while building. Also it would be nice it buildman
+could 'hunt' for problems, perhaps by building a few boards for each arch,
+or checking commits for changed files and building only boards which use
+those files.
+
+
+Credits
+=======
+
+Thanks to Grant Grundler <grundler@chromium.org> for his ideas for improving
+the build speed by building all commits for a board instead of the other
+way around.
+
+
+Simon Glass
+sjg@chromium.org
+Halloween 2012
+Updated 12-12-12
+Updated 23-02-13
diff --git a/marvell/uboot/tools/buildman/board.py b/marvell/uboot/tools/buildman/board.py
new file mode 100644
index 0000000..5172a47
--- /dev/null
+++ b/marvell/uboot/tools/buildman/board.py
@@ -0,0 +1,164 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import re
+
+class Board:
+    """A particular board that we can build"""
+    def __init__(self, status, arch, cpu, soc, vendor, board_name, target, options):
+        """Create a new board type.
+
+        Args:
+            status: define whether the board is 'Active' or 'Orphaned'
+            arch: Architecture name (e.g. arm)
+            cpu: Cpu name (e.g. arm1136)
+            soc: Name of SOC, or '' if none (e.g. mx31)
+            vendor: Name of vendor (e.g. armltd)
+            board_name: Name of board (e.g. integrator)
+            target: Target name (use make <target>_config to configure)
+            options: board-specific options (e.g. integratorcp:CM1136)
+        """
+        self.target = target
+        self.arch = arch
+        self.cpu = cpu
+        self.board_name = board_name
+        self.vendor = vendor
+        self.soc = soc
+        self.props = [self.target, self.arch, self.cpu, self.board_name,
+                      self.vendor, self.soc]
+        self.options = options
+        self.build_it = False
+
+
+class Boards:
+    """Manage a list of boards."""
+    def __init__(self):
+        # Use a simple list here, sinc OrderedDict requires Python 2.7
+        self._boards = []
+
+    def AddBoard(self, board):
+        """Add a new board to the list.
+
+        The board's target member must not already exist in the board list.
+
+        Args:
+            board: board to add
+        """
+        self._boards.append(board)
+
+    def ReadBoards(self, fname):
+        """Read a list of boards from a board file.
+
+        Create a board object for each and add it to our _boards list.
+
+        Args:
+            fname: Filename of boards.cfg file
+        """
+        with open(fname, 'r') as fd:
+            for line in fd:
+                if line[0] == '#':
+                    continue
+                fields = line.split()
+                if not fields:
+                    continue
+                for upto in range(len(fields)):
+                    if fields[upto] == '-':
+                        fields[upto] = ''
+                while len(fields) < 8:
+                    fields.append('')
+                if len(fields) > 8:
+                    fields = fields[:8]
+
+                board = Board(*fields)
+                self.AddBoard(board)
+
+
+    def GetList(self):
+        """Return a list of available boards.
+
+        Returns:
+            List of Board objects
+        """
+        return self._boards
+
+    def GetDict(self):
+        """Build a dictionary containing all the boards.
+
+        Returns:
+            Dictionary:
+                key is board.target
+                value is board
+        """
+        board_dict = {}
+        for board in self._boards:
+            board_dict[board.target] = board
+        return board_dict
+
+    def GetSelectedDict(self):
+        """Return a dictionary containing the selected boards
+
+        Returns:
+            List of Board objects that are marked selected
+        """
+        board_dict = {}
+        for board in self._boards:
+            if board.build_it:
+                board_dict[board.target] = board
+        return board_dict
+
+    def GetSelected(self):
+        """Return a list of selected boards
+
+        Returns:
+            List of Board objects that are marked selected
+        """
+        return [board for board in self._boards if board.build_it]
+
+    def GetSelectedNames(self):
+        """Return a list of selected boards
+
+        Returns:
+            List of board names that are marked selected
+        """
+        return [board.target for board in self._boards if board.build_it]
+
+    def SelectBoards(self, args):
+        """Mark boards selected based on args
+
+        Args:
+            List of strings specifying boards to include, either named, or
+            by their target, architecture, cpu, vendor or soc. If empty, all
+            boards are selected.
+
+        Returns:
+            Dictionary which holds the number of boards which were selected
+            due to each argument, arranged by argument.
+        """
+        result = {}
+        argres = {}
+        for arg in args:
+            result[arg] = 0
+            argres[arg] = re.compile(arg)
+        result['all'] = 0
+
+        for board in self._boards:
+            if args:
+                for arg in args:
+                    argre = argres[arg]
+                    match = False
+                    for prop in board.props:
+                        match = argre.match(prop)
+                        if match:
+                            break
+                    if match:
+                        if not board.build_it:
+                            board.build_it = True
+                            result[arg] += 1
+                            result['all'] += 1
+            else:
+                board.build_it = True
+                result['all'] += 1
+
+        return result
diff --git a/marvell/uboot/tools/buildman/bsettings.py b/marvell/uboot/tools/buildman/bsettings.py
new file mode 100644
index 0000000..9164798
--- /dev/null
+++ b/marvell/uboot/tools/buildman/bsettings.py
@@ -0,0 +1,41 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import ConfigParser
+import os
+
+
+def Setup(fname=''):
+    """Set up the buildman settings module by reading config files
+
+    Args:
+        config_fname:   Config filename to read ('' for default)
+    """
+    global settings
+    global config_fname
+
+    settings = ConfigParser.SafeConfigParser()
+    config_fname = fname
+    if config_fname == '':
+        config_fname = '%s/.buildman' % os.getenv('HOME')
+    if config_fname:
+        settings.read(config_fname)
+
+def GetItems(section):
+    """Get the items from a section of the config.
+
+    Args:
+        section: name of section to retrieve
+
+    Returns:
+        List of (name, value) tuples for the section
+    """
+    try:
+        return settings.items(section)
+    except ConfigParser.NoSectionError as e:
+        print e
+        return []
+    except:
+        raise
diff --git a/marvell/uboot/tools/buildman/builder.py b/marvell/uboot/tools/buildman/builder.py
new file mode 100644
index 0000000..4a2d753
--- /dev/null
+++ b/marvell/uboot/tools/buildman/builder.py
@@ -0,0 +1,1430 @@
+# Copyright (c) 2013 The Chromium OS Authors.
+#
+# Bloat-o-meter code used here Copyright 2004 Matt Mackall <mpm@selenic.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import collections
+import errno
+from datetime import datetime, timedelta
+import glob
+import os
+import re
+import Queue
+import shutil
+import string
+import sys
+import threading
+import time
+
+import command
+import gitutil
+import terminal
+import toolchain
+
+
+"""
+Theory of Operation
+
+Please see README for user documentation, and you should be familiar with
+that before trying to make sense of this.
+
+Buildman works by keeping the machine as busy as possible, building different
+commits for different boards on multiple CPUs at once.
+
+The source repo (self.git_dir) contains all the commits to be built. Each
+thread works on a single board at a time. It checks out the first commit,
+configures it for that board, then builds it. Then it checks out the next
+commit and builds it (typically without re-configuring). When it runs out
+of commits, it gets another job from the builder and starts again with that
+board.
+
+Clearly the builder threads could work either way - they could check out a
+commit and then built it for all boards. Using separate directories for each
+commit/board pair they could leave their build product around afterwards
+also.
+
+The intent behind building a single board for multiple commits, is to make
+use of incremental builds. Since each commit is built incrementally from
+the previous one, builds are faster. Reconfiguring for a different board
+removes all intermediate object files.
+
+Many threads can be working at once, but each has its own working directory.
+When a thread finishes a build, it puts the output files into a result
+directory.
+
+The base directory used by buildman is normally '../<branch>', i.e.
+a directory higher than the source repository and named after the branch
+being built.
+
+Within the base directory, we have one subdirectory for each commit. Within
+that is one subdirectory for each board. Within that is the build output for
+that commit/board combination.
+
+Buildman also create working directories for each thread, in a .bm-work/
+subdirectory in the base dir.
+
+As an example, say we are building branch 'us-net' for boards 'sandbox' and
+'seaboard', and say that us-net has two commits. We will have directories
+like this:
+
+us-net/             base directory
+    01_of_02_g4ed4ebc_net--Add-tftp-speed-/
+        sandbox/
+            u-boot.bin
+        seaboard/
+            u-boot.bin
+    02_of_02_g4ed4ebc_net--Check-tftp-comp/
+        sandbox/
+            u-boot.bin
+        seaboard/
+            u-boot.bin
+    .bm-work/
+        00/         working directory for thread 0 (contains source checkout)
+            build/  build output
+        01/         working directory for thread 1
+            build/  build output
+        ...
+u-boot/             source directory
+    .git/           repository
+"""
+
+# Possible build outcomes
+OUTCOME_OK, OUTCOME_WARNING, OUTCOME_ERROR, OUTCOME_UNKNOWN = range(4)
+
+# Translate a commit subject into a valid filename
+trans_valid_chars = string.maketrans("/: ", "---")
+
+
+def Mkdir(dirname):
+    """Make a directory if it doesn't already exist.
+
+    Args:
+        dirname: Directory to create
+    """
+    try:
+        os.mkdir(dirname)
+    except OSError as err:
+        if err.errno == errno.EEXIST:
+            pass
+        else:
+            raise
+
+class BuilderJob:
+    """Holds information about a job to be performed by a thread
+
+    Members:
+        board: Board object to build
+        commits: List of commit options to build.
+    """
+    def __init__(self):
+        self.board = None
+        self.commits = []
+
+
+class ResultThread(threading.Thread):
+    """This thread processes results from builder threads.
+
+    It simply passes the results on to the builder. There is only one
+    result thread, and this helps to serialise the build output.
+    """
+    def __init__(self, builder):
+        """Set up a new result thread
+
+        Args:
+            builder: Builder which will be sent each result
+        """
+        threading.Thread.__init__(self)
+        self.builder = builder
+
+    def run(self):
+        """Called to start up the result thread.
+
+        We collect the next result job and pass it on to the build.
+        """
+        while True:
+            result = self.builder.out_queue.get()
+            self.builder.ProcessResult(result)
+            self.builder.out_queue.task_done()
+
+
+class BuilderThread(threading.Thread):
+    """This thread builds U-Boot for a particular board.
+
+    An input queue provides each new job. We run 'make' to build U-Boot
+    and then pass the results on to the output queue.
+
+    Members:
+        builder: The builder which contains information we might need
+        thread_num: Our thread number (0-n-1), used to decide on a
+                temporary directory
+    """
+    def __init__(self, builder, thread_num):
+        """Set up a new builder thread"""
+        threading.Thread.__init__(self)
+        self.builder = builder
+        self.thread_num = thread_num
+
+    def Make(self, commit, brd, stage, cwd, *args, **kwargs):
+        """Run 'make' on a particular commit and board.
+
+        The source code will already be checked out, so the 'commit'
+        argument is only for information.
+
+        Args:
+            commit: Commit object that is being built
+            brd: Board object that is being built
+            stage: Stage of the build. Valid stages are:
+                        distclean - can be called to clean source
+                        config - called to configure for a board
+                        build - the main make invocation - it does the build
+            args: A list of arguments to pass to 'make'
+            kwargs: A list of keyword arguments to pass to command.RunPipe()
+
+        Returns:
+            CommandResult object
+        """
+        return self.builder.do_make(commit, brd, stage, cwd, *args,
+                **kwargs)
+
+    def RunCommit(self, commit_upto, brd, work_dir, do_config, force_build):
+        """Build a particular commit.
+
+        If the build is already done, and we are not forcing a build, we skip
+        the build and just return the previously-saved results.
+
+        Args:
+            commit_upto: Commit number to build (0...n-1)
+            brd: Board object to build
+            work_dir: Directory to which the source will be checked out
+            do_config: True to run a make <board>_config on the source
+            force_build: Force a build even if one was previously done
+
+        Returns:
+            tuple containing:
+                - CommandResult object containing the results of the build
+                - boolean indicating whether 'make config' is still needed
+        """
+        # Create a default result - it will be overwritte by the call to
+        # self.Make() below, in the event that we do a build.
+        result = command.CommandResult()
+        result.return_code = 0
+        out_dir = os.path.join(work_dir, 'build')
+
+        # Check if the job was already completed last time
+        done_file = self.builder.GetDoneFile(commit_upto, brd.target)
+        result.already_done = os.path.exists(done_file)
+        if result.already_done and not force_build:
+            # Get the return code from that build and use it
+            with open(done_file, 'r') as fd:
+                result.return_code = int(fd.readline())
+            err_file = self.builder.GetErrFile(commit_upto, brd.target)
+            if os.path.exists(err_file) and os.stat(err_file).st_size:
+                result.stderr = 'bad'
+        else:
+            # We are going to have to build it. First, get a toolchain
+            if not self.toolchain:
+                try:
+                    self.toolchain = self.builder.toolchains.Select(brd.arch)
+                except ValueError as err:
+                    result.return_code = 10
+                    result.stdout = ''
+                    result.stderr = str(err)
+                    # TODO(sjg@chromium.org): This gets swallowed, but needs
+                    # to be reported.
+
+            if self.toolchain:
+                # Checkout the right commit
+                if commit_upto is not None:
+                    commit = self.builder.commits[commit_upto]
+                    if self.builder.checkout:
+                        git_dir = os.path.join(work_dir, '.git')
+                        gitutil.Checkout(commit.hash, git_dir, work_dir,
+                                         force=True)
+                else:
+                    commit = self.builder.commit # Ick, fix this for BuildCommits()
+
+                # Set up the environment and command line
+                env = self.toolchain.MakeEnvironment()
+                Mkdir(out_dir)
+                args = ['O=build', '-s']
+                if self.builder.num_jobs is not None:
+                    args.extend(['-j', str(self.builder.num_jobs)])
+                config_args = ['%s_config' % brd.target]
+                config_out = ''
+                args.extend(self.builder.toolchains.GetMakeArguments(brd))
+
+                # If we need to reconfigure, do that now
+                if do_config:
+                    result = self.Make(commit, brd, 'distclean', work_dir,
+                            'distclean', *args, env=env)
+                    result = self.Make(commit, brd, 'config', work_dir,
+                            *(args + config_args), env=env)
+                    config_out = result.combined
+                    do_config = False   # No need to configure next time
+                if result.return_code == 0:
+                    result = self.Make(commit, brd, 'build', work_dir, *args,
+                            env=env)
+                    result.stdout = config_out + result.stdout
+            else:
+                result.return_code = 1
+                result.stderr = 'No tool chain for %s\n' % brd.arch
+            result.already_done = False
+
+        result.toolchain = self.toolchain
+        result.brd = brd
+        result.commit_upto = commit_upto
+        result.out_dir = out_dir
+        return result, do_config
+
+    def _WriteResult(self, result, keep_outputs):
+        """Write a built result to the output directory.
+
+        Args:
+            result: CommandResult object containing result to write
+            keep_outputs: True to store the output binaries, False
+                to delete them
+        """
+        # Fatal error
+        if result.return_code < 0:
+            return
+
+        # Aborted?
+        if result.stderr and 'No child processes' in result.stderr:
+            return
+
+        if result.already_done:
+            return
+
+        # Write the output and stderr
+        output_dir = self.builder._GetOutputDir(result.commit_upto)
+        Mkdir(output_dir)
+        build_dir = self.builder.GetBuildDir(result.commit_upto,
+                result.brd.target)
+        Mkdir(build_dir)
+
+        outfile = os.path.join(build_dir, 'log')
+        with open(outfile, 'w') as fd:
+            if result.stdout:
+                fd.write(result.stdout)
+
+        errfile = self.builder.GetErrFile(result.commit_upto,
+                result.brd.target)
+        if result.stderr:
+            with open(errfile, 'w') as fd:
+                fd.write(result.stderr)
+        elif os.path.exists(errfile):
+            os.remove(errfile)
+
+        if result.toolchain:
+            # Write the build result and toolchain information.
+            done_file = self.builder.GetDoneFile(result.commit_upto,
+                    result.brd.target)
+            with open(done_file, 'w') as fd:
+                fd.write('%s' % result.return_code)
+            with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
+                print >>fd, 'gcc', result.toolchain.gcc
+                print >>fd, 'path', result.toolchain.path
+                print >>fd, 'cross', result.toolchain.cross
+                print >>fd, 'arch', result.toolchain.arch
+                fd.write('%s' % result.return_code)
+
+            with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
+                print >>fd, 'gcc', result.toolchain.gcc
+                print >>fd, 'path', result.toolchain.path
+
+            # Write out the image and function size information and an objdump
+            env = result.toolchain.MakeEnvironment()
+            lines = []
+            for fname in ['u-boot', 'spl/u-boot-spl']:
+                cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
+                nm_result = command.RunPipe([cmd], capture=True,
+                        capture_stderr=True, cwd=result.out_dir,
+                        raise_on_error=False, env=env)
+                if nm_result.stdout:
+                    nm = self.builder.GetFuncSizesFile(result.commit_upto,
+                                    result.brd.target, fname)
+                    with open(nm, 'w') as fd:
+                        print >>fd, nm_result.stdout,
+
+                cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname]
+                dump_result = command.RunPipe([cmd], capture=True,
+                        capture_stderr=True, cwd=result.out_dir,
+                        raise_on_error=False, env=env)
+                rodata_size = ''
+                if dump_result.stdout:
+                    objdump = self.builder.GetObjdumpFile(result.commit_upto,
+                                    result.brd.target, fname)
+                    with open(objdump, 'w') as fd:
+                        print >>fd, dump_result.stdout,
+                    for line in dump_result.stdout.splitlines():
+                        fields = line.split()
+                        if len(fields) > 5 and fields[1] == '.rodata':
+                            rodata_size = fields[2]
+
+                cmd = ['%ssize' % self.toolchain.cross, fname]
+                size_result = command.RunPipe([cmd], capture=True,
+                        capture_stderr=True, cwd=result.out_dir,
+                        raise_on_error=False, env=env)
+                if size_result.stdout:
+                    lines.append(size_result.stdout.splitlines()[1] + ' ' +
+                                 rodata_size)
+
+            # Write out the image sizes file. This is similar to the output
+            # of binutil's 'size' utility, but it omits the header line and
+            # adds an additional hex value at the end of each line for the
+            # rodata size
+            if len(lines):
+                sizes = self.builder.GetSizesFile(result.commit_upto,
+                                result.brd.target)
+                with open(sizes, 'w') as fd:
+                    print >>fd, '\n'.join(lines)
+
+        # Now write the actual build output
+        if keep_outputs:
+            patterns = ['u-boot', '*.bin', 'u-boot.dtb', '*.map',
+                        'include/autoconf.mk', 'spl/u-boot-spl',
+                        'spl/u-boot-spl.bin']
+            for pattern in patterns:
+                file_list = glob.glob(os.path.join(result.out_dir, pattern))
+                for fname in file_list:
+                    shutil.copy(fname, build_dir)
+
+
+    def RunJob(self, job):
+        """Run a single job
+
+        A job consists of a building a list of commits for a particular board.
+
+        Args:
+            job: Job to build
+        """
+        brd = job.board
+        work_dir = self.builder.GetThreadDir(self.thread_num)
+        self.toolchain = None
+        if job.commits:
+            # Run 'make board_config' on the first commit
+            do_config = True
+            commit_upto  = 0
+            force_build = False
+            for commit_upto in range(0, len(job.commits), job.step):
+                result, request_config = self.RunCommit(commit_upto, brd,
+                        work_dir, do_config,
+                        force_build or self.builder.force_build)
+                failed = result.return_code or result.stderr
+                if failed and not do_config:
+                    # If our incremental build failed, try building again
+                    # with a reconfig.
+                    if self.builder.force_config_on_failure:
+                        result, request_config = self.RunCommit(commit_upto,
+                            brd, work_dir, True, True)
+                do_config = request_config
+
+                # If we built that commit, then config is done. But if we got
+                # an warning, reconfig next time to force it to build the same
+                # files that created warnings this time. Otherwise an
+                # incremental build may not build the same file, and we will
+                # think that the warning has gone away.
+                # We could avoid this by using -Werror everywhere...
+                # For errors, the problem doesn't happen, since presumably
+                # the build stopped and didn't generate output, so will retry
+                # that file next time. So we could detect warnings and deal
+                # with them specially here. For now, we just reconfigure if
+                # anything goes work.
+                # Of course this is substantially slower if there are build
+                # errors/warnings (e.g. 2-3x slower even if only 10% of builds
+                # have problems).
+                if (failed and not result.already_done and not do_config and
+                        self.builder.force_config_on_failure):
+                    # If this build failed, try the next one with a
+                    # reconfigure.
+                    # Sometimes if the board_config.h file changes it can mess
+                    # with dependencies, and we get:
+                    # make: *** No rule to make target `include/autoconf.mk',
+                    #     needed by `depend'.
+                    do_config = True
+                    force_build = True
+                else:
+                    force_build = False
+                    if self.builder.force_config_on_failure:
+                        if failed:
+                            do_config = True
+                    result.commit_upto = commit_upto
+                    if result.return_code < 0:
+                        raise ValueError('Interrupt')
+
+                # We have the build results, so output the result
+                self._WriteResult(result, job.keep_outputs)
+                self.builder.out_queue.put(result)
+        else:
+            # Just build the currently checked-out build
+            result = self.RunCommit(None, True)
+            result.commit_upto = self.builder.upto
+            self.builder.out_queue.put(result)
+
+    def run(self):
+        """Our thread's run function
+
+        This thread picks a job from the queue, runs it, and then goes to the
+        next job.
+        """
+        alive = True
+        while True:
+            job = self.builder.queue.get()
+            try:
+                if self.builder.active and alive:
+                    self.RunJob(job)
+            except Exception as err:
+                alive = False
+                print err
+            self.builder.queue.task_done()
+
+
+class Builder:
+    """Class for building U-Boot for a particular commit.
+
+    Public members: (many should ->private)
+        active: True if the builder is active and has not been stopped
+        already_done: Number of builds already completed
+        base_dir: Base directory to use for builder
+        checkout: True to check out source, False to skip that step.
+            This is used for testing.
+        col: terminal.Color() object
+        count: Number of commits to build
+        do_make: Method to call to invoke Make
+        fail: Number of builds that failed due to error
+        force_build: Force building even if a build already exists
+        force_config_on_failure: If a commit fails for a board, disable
+            incremental building for the next commit we build for that
+            board, so that we will see all warnings/errors again.
+        git_dir: Git directory containing source repository
+        last_line_len: Length of the last line we printed (used for erasing
+            it with new progress information)
+        num_jobs: Number of jobs to run at once (passed to make as -j)
+        num_threads: Number of builder threads to run
+        out_queue: Queue of results to process
+        re_make_err: Compiled regular expression for ignore_lines
+        queue: Queue of jobs to run
+        threads: List of active threads
+        toolchains: Toolchains object to use for building
+        upto: Current commit number we are building (0.count-1)
+        warned: Number of builds that produced at least one warning
+
+    Private members:
+        _base_board_dict: Last-summarised Dict of boards
+        _base_err_lines: Last-summarised list of errors
+        _build_period_us: Time taken for a single build (float object).
+        _complete_delay: Expected delay until completion (timedelta)
+        _next_delay_update: Next time we plan to display a progress update
+                (datatime)
+        _show_unknown: Show unknown boards (those not built) in summary
+        _timestamps: List of timestamps for the completion of the last
+            last _timestamp_count builds. Each is a datetime object.
+        _timestamp_count: Number of timestamps to keep in our list.
+        _working_dir: Base working directory containing all threads
+    """
+    class Outcome:
+        """Records a build outcome for a single make invocation
+
+        Public Members:
+            rc: Outcome value (OUTCOME_...)
+            err_lines: List of error lines or [] if none
+            sizes: Dictionary of image size information, keyed by filename
+                - Each value is itself a dictionary containing
+                    values for 'text', 'data' and 'bss', being the integer
+                    size in bytes of each section.
+            func_sizes: Dictionary keyed by filename - e.g. 'u-boot'. Each
+                    value is itself a dictionary:
+                        key: function name
+                        value: Size of function in bytes
+        """
+        def __init__(self, rc, err_lines, sizes, func_sizes):
+            self.rc = rc
+            self.err_lines = err_lines
+            self.sizes = sizes
+            self.func_sizes = func_sizes
+
+    def __init__(self, toolchains, base_dir, git_dir, num_threads, num_jobs,
+                 checkout=True, show_unknown=True, step=1):
+        """Create a new Builder object
+
+        Args:
+            toolchains: Toolchains object to use for building
+            base_dir: Base directory to use for builder
+            git_dir: Git directory containing source repository
+            num_threads: Number of builder threads to run
+            num_jobs: Number of jobs to run at once (passed to make as -j)
+            checkout: True to check out source, False to skip that step.
+                This is used for testing.
+            show_unknown: Show unknown boards (those not built) in summary
+            step: 1 to process every commit, n to process every nth commit
+        """
+        self.toolchains = toolchains
+        self.base_dir = base_dir
+        self._working_dir = os.path.join(base_dir, '.bm-work')
+        self.threads = []
+        self.active = True
+        self.do_make = self.Make
+        self.checkout = checkout
+        self.num_threads = num_threads
+        self.num_jobs = num_jobs
+        self.already_done = 0
+        self.force_build = False
+        self.git_dir = git_dir
+        self._show_unknown = show_unknown
+        self._timestamp_count = 10
+        self._build_period_us = None
+        self._complete_delay = None
+        self._next_delay_update = datetime.now()
+        self.force_config_on_failure = True
+        self._step = step
+
+        self.col = terminal.Color()
+
+        self.queue = Queue.Queue()
+        self.out_queue = Queue.Queue()
+        for i in range(self.num_threads):
+            t = BuilderThread(self, i)
+            t.setDaemon(True)
+            t.start()
+            self.threads.append(t)
+
+        self.last_line_len = 0
+        t = ResultThread(self)
+        t.setDaemon(True)
+        t.start()
+        self.threads.append(t)
+
+        ignore_lines = ['(make.*Waiting for unfinished)', '(Segmentation fault)']
+        self.re_make_err = re.compile('|'.join(ignore_lines))
+
+    def __del__(self):
+        """Get rid of all threads created by the builder"""
+        for t in self.threads:
+            del t
+
+    def _AddTimestamp(self):
+        """Add a new timestamp to the list and record the build period.
+
+        The build period is the length of time taken to perform a single
+        build (one board, one commit).
+        """
+        now = datetime.now()
+        self._timestamps.append(now)
+        count = len(self._timestamps)
+        delta = self._timestamps[-1] - self._timestamps[0]
+        seconds = delta.total_seconds()
+
+        # If we have enough data, estimate build period (time taken for a
+        # single build) and therefore completion time.
+        if count > 1 and self._next_delay_update < now:
+            self._next_delay_update = now + timedelta(seconds=2)
+            if seconds > 0:
+                self._build_period = float(seconds) / count
+                todo = self.count - self.upto
+                self._complete_delay = timedelta(microseconds=
+                        self._build_period * todo * 1000000)
+                # Round it
+                self._complete_delay -= timedelta(
+                        microseconds=self._complete_delay.microseconds)
+
+        if seconds > 60:
+            self._timestamps.popleft()
+            count -= 1
+
+    def ClearLine(self, length):
+        """Clear any characters on the current line
+
+        Make way for a new line of length 'length', by outputting enough
+        spaces to clear out the old line. Then remember the new length for
+        next time.
+
+        Args:
+            length: Length of new line, in characters
+        """
+        if length < self.last_line_len:
+            print ' ' * (self.last_line_len - length),
+            print '\r',
+        self.last_line_len = length
+        sys.stdout.flush()
+
+    def SelectCommit(self, commit, checkout=True):
+        """Checkout the selected commit for this build
+        """
+        self.commit = commit
+        if checkout and self.checkout:
+            gitutil.Checkout(commit.hash)
+
+    def Make(self, commit, brd, stage, cwd, *args, **kwargs):
+        """Run make
+
+        Args:
+            commit: Commit object that is being built
+            brd: Board object that is being built
+            stage: Stage that we are at (distclean, config, build)
+            cwd: Directory where make should be run
+            args: Arguments to pass to make
+            kwargs: Arguments to pass to command.RunPipe()
+        """
+        cmd = ['make'] + list(args)
+        result = command.RunPipe([cmd], capture=True, capture_stderr=True,
+                cwd=cwd, raise_on_error=False, **kwargs)
+        return result
+
+    def ProcessResult(self, result):
+        """Process the result of a build, showing progress information
+
+        Args:
+            result: A CommandResult object
+        """
+        col = terminal.Color()
+        if result:
+            target = result.brd.target
+
+            if result.return_code < 0:
+                self.active = False
+                command.StopAll()
+                return
+
+            self.upto += 1
+            if result.return_code != 0:
+                self.fail += 1
+            elif result.stderr:
+                self.warned += 1
+            if result.already_done:
+                self.already_done += 1
+        else:
+            target = '(starting)'
+
+        # Display separate counts for ok, warned and fail
+        ok = self.upto - self.warned - self.fail
+        line = '\r' + self.col.Color(self.col.GREEN, '%5d' % ok)
+        line += self.col.Color(self.col.YELLOW, '%5d' % self.warned)
+        line += self.col.Color(self.col.RED, '%5d' % self.fail)
+
+        name = ' /%-5d  ' % self.count
+
+        # Add our current completion time estimate
+        self._AddTimestamp()
+        if self._complete_delay:
+            name += '%s  : ' % self._complete_delay
+        # When building all boards for a commit, we can print a commit
+        # progress message.
+        if result and result.commit_upto is None:
+            name += 'commit %2d/%-3d' % (self.commit_upto + 1,
+                    self.commit_count)
+
+        name += target
+        print line + name,
+        length = 13 + len(name)
+        self.ClearLine(length)
+
+    def _GetOutputDir(self, commit_upto):
+        """Get the name of the output directory for a commit number
+
+        The output directory is typically .../<branch>/<commit>.
+
+        Args:
+            commit_upto: Commit number to use (0..self.count-1)
+        """
+        commit = self.commits[commit_upto]
+        subject = commit.subject.translate(trans_valid_chars)
+        commit_dir = ('%02d_of_%02d_g%s_%s' % (commit_upto + 1,
+                self.commit_count, commit.hash, subject[:20]))
+        output_dir = os.path.join(self.base_dir, commit_dir)
+        return output_dir
+
+    def GetBuildDir(self, commit_upto, target):
+        """Get the name of the build directory for a commit number
+
+        The build directory is typically .../<branch>/<commit>/<target>.
+
+        Args:
+            commit_upto: Commit number to use (0..self.count-1)
+            target: Target name
+        """
+        output_dir = self._GetOutputDir(commit_upto)
+        return os.path.join(output_dir, target)
+
+    def GetDoneFile(self, commit_upto, target):
+        """Get the name of the done file for a commit number
+
+        Args:
+            commit_upto: Commit number to use (0..self.count-1)
+            target: Target name
+        """
+        return os.path.join(self.GetBuildDir(commit_upto, target), 'done')
+
+    def GetSizesFile(self, commit_upto, target):
+        """Get the name of the sizes file for a commit number
+
+        Args:
+            commit_upto: Commit number to use (0..self.count-1)
+            target: Target name
+        """
+        return os.path.join(self.GetBuildDir(commit_upto, target), 'sizes')
+
+    def GetFuncSizesFile(self, commit_upto, target, elf_fname):
+        """Get the name of the funcsizes file for a commit number and ELF file
+
+        Args:
+            commit_upto: Commit number to use (0..self.count-1)
+            target: Target name
+            elf_fname: Filename of elf image
+        """
+        return os.path.join(self.GetBuildDir(commit_upto, target),
+                            '%s.sizes' % elf_fname.replace('/', '-'))
+
+    def GetObjdumpFile(self, commit_upto, target, elf_fname):
+        """Get the name of the objdump file for a commit number and ELF file
+
+        Args:
+            commit_upto: Commit number to use (0..self.count-1)
+            target: Target name
+            elf_fname: Filename of elf image
+        """
+        return os.path.join(self.GetBuildDir(commit_upto, target),
+                            '%s.objdump' % elf_fname.replace('/', '-'))
+
+    def GetErrFile(self, commit_upto, target):
+        """Get the name of the err file for a commit number
+
+        Args:
+            commit_upto: Commit number to use (0..self.count-1)
+            target: Target name
+        """
+        output_dir = self.GetBuildDir(commit_upto, target)
+        return os.path.join(output_dir, 'err')
+
+    def FilterErrors(self, lines):
+        """Filter out errors in which we have no interest
+
+        We should probably use map().
+
+        Args:
+            lines: List of error lines, each a string
+        Returns:
+            New list with only interesting lines included
+        """
+        out_lines = []
+        for line in lines:
+            if not self.re_make_err.search(line):
+                out_lines.append(line)
+        return out_lines
+
+    def ReadFuncSizes(self, fname, fd):
+        """Read function sizes from the output of 'nm'
+
+        Args:
+            fd: File containing data to read
+            fname: Filename we are reading from (just for errors)
+
+        Returns:
+            Dictionary containing size of each function in bytes, indexed by
+            function name.
+        """
+        sym = {}
+        for line in fd.readlines():
+            try:
+                size, type, name = line[:-1].split()
+            except:
+                print "Invalid line in file '%s': '%s'" % (fname, line[:-1])
+                continue
+            if type in 'tTdDbB':
+                # function names begin with '.' on 64-bit powerpc
+                if '.' in name[1:]:
+                    name = 'static.' + name.split('.')[0]
+                sym[name] = sym.get(name, 0) + int(size, 16)
+        return sym
+
+    def GetBuildOutcome(self, commit_upto, target, read_func_sizes):
+        """Work out the outcome of a build.
+
+        Args:
+            commit_upto: Commit number to check (0..n-1)
+            target: Target board to check
+            read_func_sizes: True to read function size information
+
+        Returns:
+            Outcome object
+        """
+        done_file = self.GetDoneFile(commit_upto, target)
+        sizes_file = self.GetSizesFile(commit_upto, target)
+        sizes = {}
+        func_sizes = {}
+        if os.path.exists(done_file):
+            with open(done_file, 'r') as fd:
+                return_code = int(fd.readline())
+                err_lines = []
+                err_file = self.GetErrFile(commit_upto, target)
+                if os.path.exists(err_file):
+                    with open(err_file, 'r') as fd:
+                        err_lines = self.FilterErrors(fd.readlines())
+
+                # Decide whether the build was ok, failed or created warnings
+                if return_code:
+                    rc = OUTCOME_ERROR
+                elif len(err_lines):
+                    rc = OUTCOME_WARNING
+                else:
+                    rc = OUTCOME_OK
+
+                # Convert size information to our simple format
+                if os.path.exists(sizes_file):
+                    with open(sizes_file, 'r') as fd:
+                        for line in fd.readlines():
+                            values = line.split()
+                            rodata = 0
+                            if len(values) > 6:
+                                rodata = int(values[6], 16)
+                            size_dict = {
+                                'all' : int(values[0]) + int(values[1]) +
+                                        int(values[2]),
+                                'text' : int(values[0]) - rodata,
+                                'data' : int(values[1]),
+                                'bss' : int(values[2]),
+                                'rodata' : rodata,
+                            }
+                            sizes[values[5]] = size_dict
+
+            if read_func_sizes:
+                pattern = self.GetFuncSizesFile(commit_upto, target, '*')
+                for fname in glob.glob(pattern):
+                    with open(fname, 'r') as fd:
+                        dict_name = os.path.basename(fname).replace('.sizes',
+                                                                    '')
+                        func_sizes[dict_name] = self.ReadFuncSizes(fname, fd)
+
+            return Builder.Outcome(rc, err_lines, sizes, func_sizes)
+
+        return Builder.Outcome(OUTCOME_UNKNOWN, [], {}, {})
+
+    def GetResultSummary(self, boards_selected, commit_upto, read_func_sizes):
+        """Calculate a summary of the results of building a commit.
+
+        Args:
+            board_selected: Dict containing boards to summarise
+            commit_upto: Commit number to summarize (0..self.count-1)
+            read_func_sizes: True to read function size information
+
+        Returns:
+            Tuple:
+                Dict containing boards which passed building this commit.
+                    keyed by board.target
+                List containing a summary of error/warning lines
+        """
+        board_dict = {}
+        err_lines_summary = []
+
+        for board in boards_selected.itervalues():
+            outcome = self.GetBuildOutcome(commit_upto, board.target,
+                                           read_func_sizes)
+            board_dict[board.target] = outcome
+            for err in outcome.err_lines:
+                if err and not err.rstrip() in err_lines_summary:
+                    err_lines_summary.append(err.rstrip())
+        return board_dict, err_lines_summary
+
+    def AddOutcome(self, board_dict, arch_list, changes, char, color):
+        """Add an output to our list of outcomes for each architecture
+
+        This simple function adds failing boards (changes) to the
+        relevant architecture string, so we can print the results out
+        sorted by architecture.
+
+        Args:
+             board_dict: Dict containing all boards
+             arch_list: Dict keyed by arch name. Value is a string containing
+                    a list of board names which failed for that arch.
+             changes: List of boards to add to arch_list
+             color: terminal.Colour object
+        """
+        done_arch = {}
+        for target in changes:
+            if target in board_dict:
+                arch = board_dict[target].arch
+            else:
+                arch = 'unknown'
+            str = self.col.Color(color, ' ' + target)
+            if not arch in done_arch:
+                str = self.col.Color(color, char) + '  ' + str
+                done_arch[arch] = True
+            if not arch in arch_list:
+                arch_list[arch] = str
+            else:
+                arch_list[arch] += str
+
+
+    def ColourNum(self, num):
+        color = self.col.RED if num > 0 else self.col.GREEN
+        if num == 0:
+            return '0'
+        return self.col.Color(color, str(num))
+
+    def ResetResultSummary(self, board_selected):
+        """Reset the results summary ready for use.
+
+        Set up the base board list to be all those selected, and set the
+        error lines to empty.
+
+        Following this, calls to PrintResultSummary() will use this
+        information to work out what has changed.
+
+        Args:
+            board_selected: Dict containing boards to summarise, keyed by
+                board.target
+        """
+        self._base_board_dict = {}
+        for board in board_selected:
+            self._base_board_dict[board] = Builder.Outcome(0, [], [], {})
+        self._base_err_lines = []
+
+    def PrintFuncSizeDetail(self, fname, old, new):
+        grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
+        delta, common = [], {}
+
+        for a in old:
+            if a in new:
+                common[a] = 1
+
+        for name in old:
+            if name not in common:
+                remove += 1
+                down += old[name]
+                delta.append([-old[name], name])
+
+        for name in new:
+            if name not in common:
+                add += 1
+                up += new[name]
+                delta.append([new[name], name])
+
+        for name in common:
+                diff = new.get(name, 0) - old.get(name, 0)
+                if diff > 0:
+                    grow, up = grow + 1, up + diff
+                elif diff < 0:
+                    shrink, down = shrink + 1, down - diff
+                delta.append([diff, name])
+
+        delta.sort()
+        delta.reverse()
+
+        args = [add, -remove, grow, -shrink, up, -down, up - down]
+        if max(args) == 0:
+            return
+        args = [self.ColourNum(x) for x in args]
+        indent = ' ' * 15
+        print ('%s%s: add: %s/%s, grow: %s/%s bytes: %s/%s (%s)' %
+               tuple([indent, self.col.Color(self.col.YELLOW, fname)] + args))
+        print '%s  %-38s %7s %7s %+7s' % (indent, 'function', 'old', 'new',
+                                        'delta')
+        for diff, name in delta:
+            if diff:
+                color = self.col.RED if diff > 0 else self.col.GREEN
+                msg = '%s  %-38s %7s %7s %+7d' % (indent, name,
+                        old.get(name, '-'), new.get(name,'-'), diff)
+                print self.col.Color(color, msg)
+
+
+    def PrintSizeDetail(self, target_list, show_bloat):
+        """Show details size information for each board
+
+        Args:
+            target_list: List of targets, each a dict containing:
+                    'target': Target name
+                    'total_diff': Total difference in bytes across all areas
+                    <part_name>: Difference for that part
+            show_bloat: Show detail for each function
+        """
+        targets_by_diff = sorted(target_list, reverse=True,
+        key=lambda x: x['_total_diff'])
+        for result in targets_by_diff:
+            printed_target = False
+            for name in sorted(result):
+                diff = result[name]
+                if name.startswith('_'):
+                    continue
+                if diff != 0:
+                    color = self.col.RED if diff > 0 else self.col.GREEN
+                msg = ' %s %+d' % (name, diff)
+                if not printed_target:
+                    print '%10s  %-15s:' % ('', result['_target']),
+                    printed_target = True
+                print self.col.Color(color, msg),
+            if printed_target:
+                print
+                if show_bloat:
+                    target = result['_target']
+                    outcome = result['_outcome']
+                    base_outcome = self._base_board_dict[target]
+                    for fname in outcome.func_sizes:
+                        self.PrintFuncSizeDetail(fname,
+                                                 base_outcome.func_sizes[fname],
+                                                 outcome.func_sizes[fname])
+
+
+    def PrintSizeSummary(self, board_selected, board_dict, show_detail,
+                         show_bloat):
+        """Print a summary of image sizes broken down by section.
+
+        The summary takes the form of one line per architecture. The
+        line contains deltas for each of the sections (+ means the section
+        got bigger, - means smaller). The nunmbers are the average number
+        of bytes that a board in this section increased by.
+
+        For example:
+           powerpc: (622 boards)   text -0.0
+          arm: (285 boards)   text -0.0
+          nds32: (3 boards)   text -8.0
+
+        Args:
+            board_selected: Dict containing boards to summarise, keyed by
+                board.target
+            board_dict: Dict containing boards for which we built this
+                commit, keyed by board.target. The value is an Outcome object.
+            show_detail: Show detail for each board
+            show_bloat: Show detail for each function
+        """
+        arch_list = {}
+        arch_count = {}
+
+        # Calculate changes in size for different image parts
+        # The previous sizes are in Board.sizes, for each board
+        for target in board_dict:
+            if target not in board_selected:
+                continue
+            base_sizes = self._base_board_dict[target].sizes
+            outcome = board_dict[target]
+            sizes = outcome.sizes
+
+            # Loop through the list of images, creating a dict of size
+            # changes for each image/part. We end up with something like
+            # {'target' : 'snapper9g45, 'data' : 5, 'u-boot-spl:text' : -4}
+            # which means that U-Boot data increased by 5 bytes and SPL
+            # text decreased by 4.
+            err = {'_target' : target}
+            for image in sizes:
+                if image in base_sizes:
+                    base_image = base_sizes[image]
+                    # Loop through the text, data, bss parts
+                    for part in sorted(sizes[image]):
+                        diff = sizes[image][part] - base_image[part]
+                        col = None
+                        if diff:
+                            if image == 'u-boot':
+                                name = part
+                            else:
+                                name = image + ':' + part
+                            err[name] = diff
+            arch = board_selected[target].arch
+            if not arch in arch_count:
+                arch_count[arch] = 1
+            else:
+                arch_count[arch] += 1
+            if not sizes:
+                pass    # Only add to our list when we have some stats
+            elif not arch in arch_list:
+                arch_list[arch] = [err]
+            else:
+                arch_list[arch].append(err)
+
+        # We now have a list of image size changes sorted by arch
+        # Print out a summary of these
+        for arch, target_list in arch_list.iteritems():
+            # Get total difference for each type
+            totals = {}
+            for result in target_list:
+                total = 0
+                for name, diff in result.iteritems():
+                    if name.startswith('_'):
+                        continue
+                    total += diff
+                    if name in totals:
+                        totals[name] += diff
+                    else:
+                        totals[name] = diff
+                result['_total_diff'] = total
+                result['_outcome'] = board_dict[result['_target']]
+
+            count = len(target_list)
+            printed_arch = False
+            for name in sorted(totals):
+                diff = totals[name]
+                if diff:
+                    # Display the average difference in this name for this
+                    # architecture
+                    avg_diff = float(diff) / count
+                    color = self.col.RED if avg_diff > 0 else self.col.GREEN
+                    msg = ' %s %+1.1f' % (name, avg_diff)
+                    if not printed_arch:
+                        print '%10s: (for %d/%d boards)' % (arch, count,
+                                arch_count[arch]),
+                        printed_arch = True
+                    print self.col.Color(color, msg),
+
+            if printed_arch:
+                print
+                if show_detail:
+                    self.PrintSizeDetail(target_list, show_bloat)
+
+
+    def PrintResultSummary(self, board_selected, board_dict, err_lines,
+                           show_sizes, show_detail, show_bloat):
+        """Compare results with the base results and display delta.
+
+        Only boards mentioned in board_selected will be considered. This
+        function is intended to be called repeatedly with the results of
+        each commit. It therefore shows a 'diff' between what it saw in
+        the last call and what it sees now.
+
+        Args:
+            board_selected: Dict containing boards to summarise, keyed by
+                board.target
+            board_dict: Dict containing boards for which we built this
+                commit, keyed by board.target. The value is an Outcome object.
+            err_lines: A list of errors for this commit, or [] if there is
+                none, or we don't want to print errors
+            show_sizes: Show image size deltas
+            show_detail: Show detail for each board
+            show_bloat: Show detail for each function
+        """
+        better = []     # List of boards fixed since last commit
+        worse = []      # List of new broken boards since last commit
+        new = []        # List of boards that didn't exist last time
+        unknown = []    # List of boards that were not built
+
+        for target in board_dict:
+            if target not in board_selected:
+                continue
+
+            # If the board was built last time, add its outcome to a list
+            if target in self._base_board_dict:
+                base_outcome = self._base_board_dict[target].rc
+                outcome = board_dict[target]
+                if outcome.rc == OUTCOME_UNKNOWN:
+                    unknown.append(target)
+                elif outcome.rc < base_outcome:
+                    better.append(target)
+                elif outcome.rc > base_outcome:
+                    worse.append(target)
+            else:
+                new.append(target)
+
+        # Get a list of errors that have appeared, and disappeared
+        better_err = []
+        worse_err = []
+        for line in err_lines:
+            if line not in self._base_err_lines:
+                worse_err.append('+' + line)
+        for line in self._base_err_lines:
+            if line not in err_lines:
+                better_err.append('-' + line)
+
+        # Display results by arch
+        if better or worse or unknown or new or worse_err or better_err:
+            arch_list = {}
+            self.AddOutcome(board_selected, arch_list, better, '',
+                    self.col.GREEN)
+            self.AddOutcome(board_selected, arch_list, worse, '+',
+                    self.col.RED)
+            self.AddOutcome(board_selected, arch_list, new, '*', self.col.BLUE)
+            if self._show_unknown:
+                self.AddOutcome(board_selected, arch_list, unknown, '?',
+                        self.col.MAGENTA)
+            for arch, target_list in arch_list.iteritems():
+                print '%10s: %s' % (arch, target_list)
+            if better_err:
+                print self.col.Color(self.col.GREEN, '\n'.join(better_err))
+            if worse_err:
+                print self.col.Color(self.col.RED, '\n'.join(worse_err))
+
+        if show_sizes:
+            self.PrintSizeSummary(board_selected, board_dict, show_detail,
+                                  show_bloat)
+
+        # Save our updated information for the next call to this function
+        self._base_board_dict = board_dict
+        self._base_err_lines = err_lines
+
+        # Get a list of boards that did not get built, if needed
+        not_built = []
+        for board in board_selected:
+            if not board in board_dict:
+                not_built.append(board)
+        if not_built:
+            print "Boards not built (%d): %s" % (len(not_built),
+                    ', '.join(not_built))
+
+
+    def ShowSummary(self, commits, board_selected, show_errors, show_sizes,
+                    show_detail, show_bloat):
+        """Show a build summary for U-Boot for a given board list.
+
+        Reset the result summary, then repeatedly call GetResultSummary on
+        each commit's results, then display the differences we see.
+
+        Args:
+            commit: Commit objects to summarise
+            board_selected: Dict containing boards to summarise
+            show_errors: Show errors that occured
+            show_sizes: Show size deltas
+            show_detail: Show detail for each board
+            show_bloat: Show detail for each function
+        """
+        self.commit_count = len(commits)
+        self.commits = commits
+        self.ResetResultSummary(board_selected)
+
+        for commit_upto in range(0, self.commit_count, self._step):
+            board_dict, err_lines = self.GetResultSummary(board_selected,
+                    commit_upto, read_func_sizes=show_bloat)
+            msg = '%02d: %s' % (commit_upto + 1, commits[commit_upto].subject)
+            print self.col.Color(self.col.BLUE, msg)
+            self.PrintResultSummary(board_selected, board_dict,
+                    err_lines if show_errors else [], show_sizes, show_detail,
+                    show_bloat)
+
+
+    def SetupBuild(self, board_selected, commits):
+        """Set up ready to start a build.
+
+        Args:
+            board_selected: Selected boards to build
+            commits: Selected commits to build
+        """
+        # First work out how many commits we will build
+        count = (len(commits) + self._step - 1) / self._step
+        self.count = len(board_selected) * count
+        self.upto = self.warned = self.fail = 0
+        self._timestamps = collections.deque()
+
+    def BuildBoardsForCommit(self, board_selected, keep_outputs):
+        """Build all boards for a single commit"""
+        self.SetupBuild(board_selected)
+        self.count = len(board_selected)
+        for brd in board_selected.itervalues():
+            job = BuilderJob()
+            job.board = brd
+            job.commits = None
+            job.keep_outputs = keep_outputs
+            self.queue.put(brd)
+
+        self.queue.join()
+        self.out_queue.join()
+        print
+        self.ClearLine(0)
+
+    def BuildCommits(self, commits, board_selected, show_errors, keep_outputs):
+        """Build all boards for all commits (non-incremental)"""
+        self.commit_count = len(commits)
+
+        self.ResetResultSummary(board_selected)
+        for self.commit_upto in range(self.commit_count):
+            self.SelectCommit(commits[self.commit_upto])
+            self.SelectOutputDir()
+            Mkdir(self.output_dir)
+
+            self.BuildBoardsForCommit(board_selected, keep_outputs)
+            board_dict, err_lines = self.GetResultSummary()
+            self.PrintResultSummary(board_selected, board_dict,
+                err_lines if show_errors else [])
+
+        if self.already_done:
+            print '%d builds already done' % self.already_done
+
+    def GetThreadDir(self, thread_num):
+        """Get the directory path to the working dir for a thread.
+
+        Args:
+            thread_num: Number of thread to check.
+        """
+        return os.path.join(self._working_dir, '%02d' % thread_num)
+
+    def _PrepareThread(self, thread_num):
+        """Prepare the working directory for a thread.
+
+        This clones or fetches the repo into the thread's work directory.
+
+        Args:
+            thread_num: Thread number (0, 1, ...)
+        """
+        thread_dir = self.GetThreadDir(thread_num)
+        Mkdir(thread_dir)
+        git_dir = os.path.join(thread_dir, '.git')
+
+        # Clone the repo if it doesn't already exist
+        # TODO(sjg@chromium): Perhaps some git hackery to symlink instead, so
+        # we have a private index but uses the origin repo's contents?
+        if self.git_dir:
+            src_dir = os.path.abspath(self.git_dir)
+            if os.path.exists(git_dir):
+                gitutil.Fetch(git_dir, thread_dir)
+            else:
+                print 'Cloning repo for thread %d' % thread_num
+                gitutil.Clone(src_dir, thread_dir)
+
+    def _PrepareWorkingSpace(self, max_threads):
+        """Prepare the working directory for use.
+
+        Set up the git repo for each thread.
+
+        Args:
+            max_threads: Maximum number of threads we expect to need.
+        """
+        Mkdir(self._working_dir)
+        for thread in range(max_threads):
+            self._PrepareThread(thread)
+
+    def _PrepareOutputSpace(self):
+        """Get the output directories ready to receive files.
+
+        We delete any output directories which look like ones we need to
+        create. Having left over directories is confusing when the user wants
+        to check the output manually.
+        """
+        dir_list = []
+        for commit_upto in range(self.commit_count):
+            dir_list.append(self._GetOutputDir(commit_upto))
+
+        for dirname in glob.glob(os.path.join(self.base_dir, '*')):
+            if dirname not in dir_list:
+                shutil.rmtree(dirname)
+
+    def BuildBoards(self, commits, board_selected, show_errors, keep_outputs):
+        """Build all commits for a list of boards
+
+        Args:
+            commits: List of commits to be build, each a Commit object
+            boards_selected: Dict of selected boards, key is target name,
+                    value is Board object
+            show_errors: True to show summarised error/warning info
+            keep_outputs: True to save build output files
+        """
+        self.commit_count = len(commits)
+        self.commits = commits
+
+        self.ResetResultSummary(board_selected)
+        Mkdir(self.base_dir)
+        self._PrepareWorkingSpace(min(self.num_threads, len(board_selected)))
+        self._PrepareOutputSpace()
+        self.SetupBuild(board_selected, commits)
+        self.ProcessResult(None)
+
+        # Create jobs to build all commits for each board
+        for brd in board_selected.itervalues():
+            job = BuilderJob()
+            job.board = brd
+            job.commits = commits
+            job.keep_outputs = keep_outputs
+            job.step = self._step
+            self.queue.put(job)
+
+        # Wait until all jobs are started
+        self.queue.join()
+
+        # Wait until we have processed all output
+        self.out_queue.join()
+        print
+        self.ClearLine(0)
diff --git a/marvell/uboot/tools/buildman/buildman b/marvell/uboot/tools/buildman/buildman
new file mode 120000
index 0000000..e4fba2d
--- /dev/null
+++ b/marvell/uboot/tools/buildman/buildman
@@ -0,0 +1 @@
+buildman.py
\ No newline at end of file
diff --git a/marvell/uboot/tools/buildman/buildman.py b/marvell/uboot/tools/buildman/buildman.py
new file mode 100755
index 0000000..8822efe
--- /dev/null
+++ b/marvell/uboot/tools/buildman/buildman.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+"""See README for more information"""
+
+import multiprocessing
+from optparse import OptionParser
+import os
+import re
+import sys
+import unittest
+
+# Bring in the patman libraries
+our_path = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(our_path, '../patman'))
+
+# Our modules
+import board
+import builder
+import checkpatch
+import command
+import control
+import doctest
+import gitutil
+import patchstream
+import terminal
+import toolchain
+
+def RunTests():
+    import test
+    import doctest
+
+    result = unittest.TestResult()
+    for module in ['toolchain']:
+        suite = doctest.DocTestSuite(module)
+        suite.run(result)
+
+    # TODO: Surely we can just 'print' result?
+    print result
+    for test, err in result.errors:
+        print err
+    for test, err in result.failures:
+        print err
+
+    sys.argv = [sys.argv[0]]
+    suite = unittest.TestLoader().loadTestsFromTestCase(test.TestBuild)
+    result = unittest.TestResult()
+    suite.run(result)
+
+    # TODO: Surely we can just 'print' result?
+    print result
+    for test, err in result.errors:
+        print err
+    for test, err in result.failures:
+        print err
+
+
+parser = OptionParser()
+parser.add_option('-b', '--branch', type='string',
+       help='Branch name to build')
+parser.add_option('-B', '--bloat', dest='show_bloat',
+       action='store_true', default=False,
+       help='Show changes in function code size for each board')
+parser.add_option('-c', '--count', dest='count', type='int',
+       default=-1, help='Run build on the top n commits')
+parser.add_option('-e', '--show_errors', action='store_true',
+       default=False, help='Show errors and warnings')
+parser.add_option('-f', '--force-build', dest='force_build',
+       action='store_true', default=False,
+       help='Force build of boards even if already built')
+parser.add_option('-d', '--detail', dest='show_detail',
+       action='store_true', default=False,
+       help='Show detailed information for each board in summary')
+parser.add_option('-g', '--git', type='string',
+       help='Git repo containing branch to build', default='.')
+parser.add_option('-H', '--full-help', action='store_true', dest='full_help',
+       default=False, help='Display the README file')
+parser.add_option('-j', '--jobs', dest='jobs', type='int',
+       default=None, help='Number of jobs to run at once (passed to make)')
+parser.add_option('-k', '--keep-outputs', action='store_true',
+       default=False, help='Keep all build output files (e.g. binaries)')
+parser.add_option('--list-tool-chains', action='store_true', default=False,
+       help='List available tool chains')
+parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
+       default=False, help="Do a try run (describe actions, but no nothing)")
+parser.add_option('-Q', '--quick', action='store_true',
+       default=False, help='Do a rough build, with limited warning resolution')
+parser.add_option('-s', '--summary', action='store_true',
+       default=False, help='Show a build summary')
+parser.add_option('-S', '--show-sizes', action='store_true',
+       default=False, help='Show image size variation in summary')
+parser.add_option('--step', type='int',
+       default=1, help='Only build every n commits (0=just first and last)')
+parser.add_option('-t', '--test', action='store_true', dest='test',
+                  default=False, help='run tests')
+parser.add_option('-T', '--threads', type='int',
+       default=None, help='Number of builder threads to use')
+parser.add_option('-u', '--show_unknown', action='store_true',
+       default=False, help='Show boards with unknown build result')
+
+parser.usage = """buildman -b <branch> [options]
+
+Build U-Boot for all commits in a branch. Use -n to do a dry run"""
+
+(options, args) = parser.parse_args()
+
+# Run our meagre tests
+if options.test:
+    RunTests()
+elif options.full_help:
+    pager = os.getenv('PAGER')
+    if not pager:
+        pager = 'more'
+    fname = os.path.join(os.path.dirname(sys.argv[0]), 'README')
+    command.Run(pager, fname)
+
+# Build selected commits for selected boards
+else:
+    control.DoBuildman(options, args)
diff --git a/marvell/uboot/tools/buildman/control.py b/marvell/uboot/tools/buildman/control.py
new file mode 100644
index 0000000..8e6a08f
--- /dev/null
+++ b/marvell/uboot/tools/buildman/control.py
@@ -0,0 +1,174 @@
+# Copyright (c) 2013 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import multiprocessing
+import os
+import sys
+
+import board
+import bsettings
+from builder import Builder
+import gitutil
+import patchstream
+import terminal
+import toolchain
+
+def GetPlural(count):
+    """Returns a plural 's' if count is not 1"""
+    return 's' if count != 1 else ''
+
+def GetActionSummary(is_summary, count, selected, options):
+    """Return a string summarising the intended action.
+
+    Returns:
+        Summary string.
+    """
+    count = (count + options.step - 1) / options.step
+    str = '%s %d commit%s for %d boards' % (
+        'Summary of' if is_summary else 'Building', count, GetPlural(count),
+        len(selected))
+    str += ' (%d thread%s, %d job%s per thread)' % (options.threads,
+            GetPlural(options.threads), options.jobs, GetPlural(options.jobs))
+    return str
+
+def ShowActions(series, why_selected, boards_selected, builder, options):
+    """Display a list of actions that we would take, if not a dry run.
+
+    Args:
+        series: Series object
+        why_selected: Dictionary where each key is a buildman argument
+                provided by the user, and the value is the boards brought
+                in by that argument. For example, 'arm' might bring in
+                400 boards, so in this case the key would be 'arm' and
+                the value would be a list of board names.
+        boards_selected: Dict of selected boards, key is target name,
+                value is Board object
+        builder: The builder that will be used to build the commits
+        options: Command line options object
+    """
+    col = terminal.Color()
+    print 'Dry run, so not doing much. But I would do this:'
+    print
+    print GetActionSummary(False, len(series.commits), boards_selected,
+            options)
+    print 'Build directory: %s' % builder.base_dir
+    for upto in range(0, len(series.commits), options.step):
+        commit = series.commits[upto]
+        print '   ', col.Color(col.YELLOW, commit.hash, bright=False),
+        print commit.subject
+    print
+    for arg in why_selected:
+        if arg != 'all':
+            print arg, ': %d boards' % why_selected[arg]
+    print ('Total boards to build for each commit: %d\n' %
+            why_selected['all'])
+
+def DoBuildman(options, args):
+    """The main control code for buildman
+
+    Args:
+        options: Command line options object
+        args: Command line arguments (list of strings)
+    """
+    gitutil.Setup()
+
+    bsettings.Setup()
+    options.git_dir = os.path.join(options.git, '.git')
+
+    toolchains = toolchain.Toolchains()
+    toolchains.Scan(options.list_tool_chains)
+    if options.list_tool_chains:
+        toolchains.List()
+        print
+        return
+
+    # Work out how many commits to build. We want to build everything on the
+    # branch. We also build the upstream commit as a control so we can see
+    # problems introduced by the first commit on the branch.
+    col = terminal.Color()
+    count = options.count
+    if count == -1:
+        if not options.branch:
+            str = 'Please use -b to specify a branch to build'
+            print col.Color(col.RED, str)
+            sys.exit(1)
+        count = gitutil.CountCommitsInBranch(options.git_dir, options.branch)
+        if count is None:
+            str = "Branch '%s' not found or has no upstream" % options.branch
+            print col.Color(col.RED, str)
+            sys.exit(1)
+        count += 1   # Build upstream commit also
+
+    if not count:
+        str = ("No commits found to process in branch '%s': "
+               "set branch's upstream or use -c flag" % options.branch)
+        print col.Color(col.RED, str)
+        sys.exit(1)
+
+    # Work out what subset of the boards we are building
+    boards = board.Boards()
+    boards.ReadBoards(os.path.join(options.git, 'boards.cfg'))
+    why_selected = boards.SelectBoards(args)
+    selected = boards.GetSelected()
+    if not len(selected):
+        print col.Color(col.RED, 'No matching boards found')
+        sys.exit(1)
+
+    # Read the metadata from the commits. First look at the upstream commit,
+    # then the ones in the branch. We would like to do something like
+    # upstream/master~..branch but that isn't possible if upstream/master is
+    # a merge commit (it will list all the commits that form part of the
+    # merge)
+    range_expr = gitutil.GetRangeInBranch(options.git_dir, options.branch)
+    upstream_commit = gitutil.GetUpstream(options.git_dir, options.branch)
+    series = patchstream.GetMetaDataForList(upstream_commit, options.git_dir,
+            1)
+    # Conflicting tags are not a problem for buildman, since it does not use
+    # them. For example, Series-version is not useful for buildman. On the
+    # other hand conflicting tags will cause an error. So allow later tags
+    # to overwrite earlier ones.
+    series.allow_overwrite = True
+    series = patchstream.GetMetaDataForList(range_expr, options.git_dir, None,
+            series)
+
+    # By default we have one thread per CPU. But if there are not enough jobs
+    # we can have fewer threads and use a high '-j' value for make.
+    if not options.threads:
+        options.threads = min(multiprocessing.cpu_count(), len(selected))
+    if not options.jobs:
+        options.jobs = max(1, (multiprocessing.cpu_count() +
+                len(selected) - 1) / len(selected))
+
+    if not options.step:
+        options.step = len(series.commits) - 1
+
+    # Create a new builder with the selected options
+    output_dir = os.path.join('..', options.branch)
+    builder = Builder(toolchains, output_dir, options.git_dir,
+            options.threads, options.jobs, checkout=True,
+            show_unknown=options.show_unknown, step=options.step)
+    builder.force_config_on_failure = not options.quick
+
+    # For a dry run, just show our actions as a sanity check
+    if options.dry_run:
+        ShowActions(series, why_selected, selected, builder, options)
+    else:
+        builder.force_build = options.force_build
+
+        # Work out which boards to build
+        board_selected = boards.GetSelectedDict()
+
+        print GetActionSummary(options.summary, count, board_selected, options)
+
+        if options.summary:
+            # We can't show function sizes without board details at present
+            if options.show_bloat:
+                options.show_detail = True
+            builder.ShowSummary(series.commits, board_selected,
+                    options.show_errors, options.show_sizes,
+                    options.show_detail, options.show_bloat)
+        else:
+            builder.BuildBoards(series.commits, board_selected,
+                    options.show_errors, options.keep_outputs)
diff --git a/marvell/uboot/tools/buildman/test.py b/marvell/uboot/tools/buildman/test.py
new file mode 100644
index 0000000..068784a
--- /dev/null
+++ b/marvell/uboot/tools/buildman/test.py
@@ -0,0 +1,169 @@
+#
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import os
+import shutil
+import sys
+import tempfile
+import time
+import unittest
+
+# Bring in the patman libraries
+our_path = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(our_path, '../patman'))
+
+import board
+import bsettings
+import builder
+import control
+import command
+import commit
+import toolchain
+
+errors = [
+    '''main.c: In function 'main_loop':
+main.c:260:6: warning: unused variable 'joe' [-Wunused-variable]
+''',
+    '''main.c: In function 'main_loop':
+main.c:295:2: error: 'fred' undeclared (first use in this function)
+main.c:295:2: note: each undeclared identifier is reported only once for each function it appears in
+make[1]: *** [main.o] Error 1
+make: *** [common/libcommon.o] Error 2
+Make failed
+''',
+    '''main.c: In function 'main_loop':
+main.c:280:6: warning: unused variable 'mary' [-Wunused-variable]
+''',
+    '''powerpc-linux-ld: warning: dot moved backwards before `.bss'
+powerpc-linux-ld: warning: dot moved backwards before `.bss'
+powerpc-linux-ld: u-boot: section .text lma 0xfffc0000 overlaps previous sections
+powerpc-linux-ld: u-boot: section .rodata lma 0xfffef3ec overlaps previous sections
+powerpc-linux-ld: u-boot: section .reloc lma 0xffffa400 overlaps previous sections
+powerpc-linux-ld: u-boot: section .data lma 0xffffcd38 overlaps previous sections
+powerpc-linux-ld: u-boot: section .u_boot_cmd lma 0xffffeb40 overlaps previous sections
+powerpc-linux-ld: u-boot: section .bootpg lma 0xfffff198 overlaps previous sections
+'''
+]
+
+
+# hash, subject, return code, list of errors/warnings
+commits = [
+    ['1234', 'upstream/master, ok', 0, []],
+    ['5678', 'Second commit, a warning', 0, errors[0:1]],
+    ['9012', 'Third commit, error', 1, errors[0:2]],
+    ['3456', 'Fourth commit, warning', 0, [errors[0], errors[2]]],
+    ['7890', 'Fifth commit, link errors', 1, [errors[0], errors[3]]],
+    ['abcd', 'Sixth commit, fixes all errors', 0, []]
+]
+
+boards = [
+    ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 1', 'board0',  ''],
+    ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 2', 'board1', ''],
+    ['Active', 'powerpc', 'powerpc', '', 'Tester', 'PowerPC board 1', 'board2', ''],
+    ['Active', 'powerpc', 'mpc5xx', '', 'Tester', 'PowerPC board 2', 'board3', ''],
+    ['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''],
+]
+
+class Options:
+    """Class that holds build options"""
+    pass
+
+class TestBuild(unittest.TestCase):
+    """Test buildman
+
+    TODO: Write tests for the rest of the functionality
+    """
+    def setUp(self):
+        # Set up commits to build
+        self.commits = []
+        sequence = 0
+        for commit_info in commits:
+            comm = commit.Commit(commit_info[0])
+            comm.subject = commit_info[1]
+            comm.return_code = commit_info[2]
+            comm.error_list = commit_info[3]
+            comm.sequence = sequence
+            sequence += 1
+            self.commits.append(comm)
+
+        # Set up boards to build
+        self.boards = board.Boards()
+        for brd in boards:
+            self.boards.AddBoard(board.Board(*brd))
+        self.boards.SelectBoards([])
+
+        # Set up the toolchains
+        bsettings.Setup()
+        self.toolchains = toolchain.Toolchains()
+        self.toolchains.Add('arm-linux-gcc', test=False)
+        self.toolchains.Add('sparc-linux-gcc', test=False)
+        self.toolchains.Add('powerpc-linux-gcc', test=False)
+        self.toolchains.Add('gcc', test=False)
+
+    def Make(self, commit, brd, stage, *args, **kwargs):
+        result = command.CommandResult()
+        boardnum = int(brd.target[-1])
+        result.return_code = 0
+        result.stderr = ''
+        result.stdout = ('This is the test output for board %s, commit %s' %
+                (brd.target, commit.hash))
+        if boardnum >= 1 and boardnum >= commit.sequence:
+            result.return_code = commit.return_code
+            result.stderr = ''.join(commit.error_list)
+        if stage == 'build':
+            target_dir = None
+            for arg in args:
+                if arg.startswith('O='):
+                    target_dir = arg[2:]
+
+            if not os.path.isdir(target_dir):
+                os.mkdir(target_dir)
+            #time.sleep(.2 + boardnum * .2)
+
+        result.combined = result.stdout + result.stderr
+        return result
+
+    def testBasic(self):
+        """Test basic builder operation"""
+        output_dir = tempfile.mkdtemp()
+        if not os.path.isdir(output_dir):
+            os.mkdir(output_dir)
+        build = builder.Builder(self.toolchains, output_dir, None, 1, 2,
+                                checkout=False, show_unknown=False)
+        build.do_make = self.Make
+        board_selected = self.boards.GetSelectedDict()
+
+        #build.BuildCommits(self.commits, board_selected, False)
+        build.BuildBoards(self.commits, board_selected, False, False)
+        build.ShowSummary(self.commits, board_selected, True, False,
+                          False, False)
+
+    def _testGit(self):
+        """Test basic builder operation by building a branch"""
+        base_dir = tempfile.mkdtemp()
+        if not os.path.isdir(base_dir):
+            os.mkdir(base_dir)
+        options = Options()
+        options.git = os.getcwd()
+        options.summary = False
+        options.jobs = None
+        options.dry_run = False
+        #options.git = os.path.join(base_dir, 'repo')
+        options.branch = 'test-buildman'
+        options.force_build = False
+        options.list_tool_chains = False
+        options.count = -1
+        options.git_dir = None
+        options.threads = None
+        options.show_unknown = False
+        options.quick = False
+        options.show_errors = False
+        options.keep_outputs = False
+        args = ['tegra20']
+        control.DoBuildman(options, args)
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/marvell/uboot/tools/buildman/toolchain.py b/marvell/uboot/tools/buildman/toolchain.py
new file mode 100644
index 0000000..b643386
--- /dev/null
+++ b/marvell/uboot/tools/buildman/toolchain.py
@@ -0,0 +1,247 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import re
+import glob
+import os
+
+import bsettings
+import command
+
+class Toolchain:
+    """A single toolchain
+
+    Public members:
+        gcc: Full path to C compiler
+        path: Directory path containing C compiler
+        cross: Cross compile string, e.g. 'arm-linux-'
+        arch: Architecture of toolchain as determined from the first
+                component of the filename. E.g. arm-linux-gcc becomes arm
+    """
+
+    def __init__(self, fname, test, verbose=False):
+        """Create a new toolchain object.
+
+        Args:
+            fname: Filename of the gcc component
+            test: True to run the toolchain to test it
+        """
+        self.gcc = fname
+        self.path = os.path.dirname(fname)
+        self.cross = os.path.basename(fname)[:-3]
+        pos = self.cross.find('-')
+        self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
+
+        env = self.MakeEnvironment()
+
+        # As a basic sanity check, run the C compiler with --version
+        cmd = [fname, '--version']
+        if test:
+            result = command.RunPipe([cmd], capture=True, env=env,
+                                     raise_on_error=False)
+            self.ok = result.return_code == 0
+            if verbose:
+                print 'Tool chain test: ',
+                if self.ok:
+                    print 'OK'
+                else:
+                    print 'BAD'
+                    print 'Command: ', cmd
+                    print result.stdout
+                    print result.stderr
+        else:
+            self.ok = True
+        self.priority = self.GetPriority(fname)
+
+    def GetPriority(self, fname):
+        """Return the priority of the toolchain.
+
+        Toolchains are ranked according to their suitability by their
+        filename prefix.
+
+        Args:
+            fname: Filename of toolchain
+        Returns:
+            Priority of toolchain, 0=highest, 20=lowest.
+        """
+        priority_list = ['-elf', '-unknown-linux-gnu', '-linux', '-elf',
+            '-none-linux-gnueabi', '-uclinux', '-none-eabi',
+            '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux']
+        for prio in range(len(priority_list)):
+            if priority_list[prio] in fname:
+                return prio
+        return prio
+
+    def MakeEnvironment(self):
+        """Returns an environment for using the toolchain.
+
+        Thie takes the current environment, adds CROSS_COMPILE and
+        augments PATH so that the toolchain will operate correctly.
+        """
+        env = dict(os.environ)
+        env['CROSS_COMPILE'] = self.cross
+        env['PATH'] += (':' + self.path)
+        return env
+
+
+class Toolchains:
+    """Manage a list of toolchains for building U-Boot
+
+    We select one toolchain for each architecture type
+
+    Public members:
+        toolchains: Dict of Toolchain objects, keyed by architecture name
+        paths: List of paths to check for toolchains (may contain wildcards)
+    """
+
+    def __init__(self):
+        self.toolchains = {}
+        self.paths = []
+        toolchains = bsettings.GetItems('toolchain')
+        if not toolchains:
+            print ("Warning: No tool chains - please add a [toolchain] section"
+                 " to your buildman config file %s. See README for details" %
+                 config_fname)
+
+        for name, value in toolchains:
+            if '*' in value:
+                self.paths += glob.glob(value)
+            else:
+                self.paths.append(value)
+        self._make_flags = dict(bsettings.GetItems('make-flags'))
+
+    def Add(self, fname, test=True, verbose=False):
+        """Add a toolchain to our list
+
+        We select the given toolchain as our preferred one for its
+        architecture if it is a higher priority than the others.
+
+        Args:
+            fname: Filename of toolchain's gcc driver
+            test: True to run the toolchain to test it
+        """
+        toolchain = Toolchain(fname, test, verbose)
+        add_it = toolchain.ok
+        if toolchain.arch in self.toolchains:
+            add_it = (toolchain.priority <
+                        self.toolchains[toolchain.arch].priority)
+        if add_it:
+            self.toolchains[toolchain.arch] = toolchain
+
+    def Scan(self, verbose):
+        """Scan for available toolchains and select the best for each arch.
+
+        We look for all the toolchains we can file, figure out the
+        architecture for each, and whether it works. Then we select the
+        highest priority toolchain for each arch.
+
+        Args:
+            verbose: True to print out progress information
+        """
+        if verbose: print 'Scanning for tool chains'
+        for path in self.paths:
+            if verbose: print "   - scanning path '%s'" % path
+            for subdir in ['.', 'bin', 'usr/bin']:
+                dirname = os.path.join(path, subdir)
+                if verbose: print "      - looking in '%s'" % dirname
+                for fname in glob.glob(dirname + '/*gcc'):
+                    if verbose: print "         - found '%s'" % fname
+                    self.Add(fname, True, verbose)
+
+    def List(self):
+        """List out the selected toolchains for each architecture"""
+        print 'List of available toolchains (%d):' % len(self.toolchains)
+        if len(self.toolchains):
+            for key, value in sorted(self.toolchains.iteritems()):
+                print '%-10s: %s' % (key, value.gcc)
+        else:
+            print 'None'
+
+    def Select(self, arch):
+        """Returns the toolchain for a given architecture
+
+        Args:
+            args: Name of architecture (e.g. 'arm', 'ppc_8xx')
+
+        returns:
+            toolchain object, or None if none found
+        """
+        for name, value in bsettings.GetItems('toolchain-alias'):
+            if arch == name:
+                arch = value
+
+        if not arch in self.toolchains:
+            raise ValueError, ("No tool chain found for arch '%s'" % arch)
+        return self.toolchains[arch]
+
+    def ResolveReferences(self, var_dict, args):
+        """Resolve variable references in a string
+
+        This converts ${blah} within the string to the value of blah.
+        This function works recursively.
+
+        Args:
+            var_dict: Dictionary containing variables and their values
+            args: String containing make arguments
+        Returns:
+            Resolved string
+
+        >>> bsettings.Setup()
+        >>> tcs = Toolchains()
+        >>> tcs.Add('fred', False)
+        >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \
+                        'second' : '2nd'}
+        >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set')
+        'this=OBLIQUE_set'
+        >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd')
+        'this=OBLIQUE_setfi2ndrstnd'
+        """
+        re_var = re.compile('(\$\{[a-z0-9A-Z]{1,}\})')
+
+        while True:
+            m = re_var.search(args)
+            if not m:
+                break
+            lookup = m.group(0)[2:-1]
+            value = var_dict.get(lookup, '')
+            args = args[:m.start(0)] + value + args[m.end(0):]
+        return args
+
+    def GetMakeArguments(self, board):
+        """Returns 'make' arguments for a given board
+
+        The flags are in a section called 'make-flags'. Flags are named
+        after the target they represent, for example snapper9260=TESTING=1
+        will pass TESTING=1 to make when building the snapper9260 board.
+
+        References to other boards can be added in the string also. For
+        example:
+
+        [make-flags]
+        at91-boards=ENABLE_AT91_TEST=1
+        snapper9260=${at91-boards} BUILD_TAG=442
+        snapper9g45=${at91-boards} BUILD_TAG=443
+
+        This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
+        and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45.
+
+        A special 'target' variable is set to the board target.
+
+        Args:
+            board: Board object for the board to check.
+        Returns:
+            'make' flags for that board, or '' if none
+        """
+        self._make_flags['target'] = board.target
+        arg_str = self.ResolveReferences(self._make_flags,
+                           self._make_flags.get(board.target, ''))
+        args = arg_str.split(' ')
+        i = 0
+        while i < len(args):
+            if not args[i]:
+                del args[i]
+            else:
+                i += 1
+        return args
diff --git a/marvell/uboot/tools/default_image.c b/marvell/uboot/tools/default_image.c
new file mode 100644
index 0000000..0a0792e
--- /dev/null
+++ b/marvell/uboot/tools/default_image.c
@@ -0,0 +1,194 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2004
+ * DENX Software Engineering
+ * Wolfgang Denk, wd@denx.de
+ *
+ * Updated-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *		default_image specific code abstracted from mkimage.c
+ *		some functions added to address abstraction
+ *
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "imagetool.h"
+#include <image.h>
+#include <u-boot/crc.h>
+
+static image_header_t header;
+
+static int image_check_image_types(uint8_t type)
+{
+	if (((type > IH_TYPE_INVALID) && (type < IH_TYPE_FLATDT)) ||
+	    (type == IH_TYPE_KERNEL_NOLOAD))
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+}
+
+static int image_check_params(struct image_tool_params *params)
+{
+	return	((params->dflag && (params->fflag || params->lflag)) ||
+		(params->fflag && (params->dflag || params->lflag)) ||
+		(params->lflag && (params->dflag || params->fflag)));
+}
+
+static int image_verify_header(unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	uint32_t len;
+	const unsigned char *data;
+	uint32_t checksum;
+	image_header_t header;
+	image_header_t *hdr = &header;
+
+	/*
+	 * create copy of header so that we can blank out the
+	 * checksum field for checking - this can't be done
+	 * on the PROT_READ mapped data.
+	 */
+	memcpy(hdr, ptr, sizeof(image_header_t));
+
+	if (be32_to_cpu(hdr->ih_magic) != IH_MAGIC) {
+		fprintf(stderr,
+			"%s: Bad Magic Number: \"%s\" is no valid image\n",
+			params->cmdname, params->imagefile);
+		return -FDT_ERR_BADMAGIC;
+	}
+
+	data = (const unsigned char *)hdr;
+	len  = sizeof(image_header_t);
+
+	checksum = be32_to_cpu(hdr->ih_hcrc);
+	hdr->ih_hcrc = cpu_to_be32(0);	/* clear for re-calculation */
+
+	if (crc32(0, data, len) != checksum) {
+		fprintf(stderr,
+			"%s: ERROR: \"%s\" has bad header checksum!\n",
+			params->cmdname, params->imagefile);
+		return -FDT_ERR_BADSTATE;
+	}
+
+	data = (const unsigned char *)ptr + sizeof(image_header_t);
+	len  = image_size - sizeof(image_header_t) ;
+
+	checksum = be32_to_cpu(hdr->ih_dcrc);
+	if (crc32(0, data, len) != checksum) {
+		fprintf(stderr,
+			"%s: ERROR: \"%s\" has corrupted data!\n",
+			params->cmdname, params->imagefile);
+		return -FDT_ERR_BADSTRUCTURE;
+	}
+	return 0;
+}
+
+static void image_set_header(void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+	uint32_t checksum;
+
+	image_header_t * hdr = (image_header_t *)ptr;
+
+	checksum = crc32(0,
+			(const unsigned char *)(ptr +
+				sizeof(image_header_t)),
+			sbuf->st_size - sizeof(image_header_t));
+
+	/* Build new header */
+	image_set_magic(hdr, IH_MAGIC);
+	image_set_time(hdr, sbuf->st_mtime);
+	image_set_size(hdr, sbuf->st_size - sizeof(image_header_t));
+	image_set_load(hdr, params->addr);
+	image_set_ep(hdr, params->ep);
+	image_set_dcrc(hdr, checksum);
+	image_set_os(hdr, params->os);
+	image_set_arch(hdr, params->arch);
+	image_set_type(hdr, params->type);
+	image_set_comp(hdr, params->comp);
+
+	image_set_name(hdr, params->imagename);
+
+	checksum = crc32(0, (const unsigned char *)hdr,
+				sizeof(image_header_t));
+
+	image_set_hcrc(hdr, checksum);
+}
+
+static int image_save_datafile(struct image_tool_params *params,
+			       ulong file_data, ulong file_len)
+{
+	int dfd;
+	const char *datafile = params->outfile;
+
+	dfd = open(datafile, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+		   S_IRUSR | S_IWUSR);
+	if (dfd < 0) {
+		fprintf(stderr, "%s: Can't open \"%s\": %s\n",
+			params->cmdname, datafile, strerror(errno));
+		return -1;
+	}
+
+	if (write(dfd, (void *)file_data, file_len) != (ssize_t)file_len) {
+		fprintf(stderr, "%s: Write error on \"%s\": %s\n",
+			params->cmdname, datafile, strerror(errno));
+		close(dfd);
+		return -1;
+	}
+
+	close(dfd);
+
+	return 0;
+}
+
+static int image_extract_datafile(void *ptr, struct image_tool_params *params)
+{
+	const image_header_t *hdr = (const image_header_t *)ptr;
+	ulong file_data;
+	ulong file_len;
+
+	if (image_check_type(hdr, IH_TYPE_MULTI)) {
+		ulong idx = params->pflag;
+		ulong count;
+
+		/* get the number of data files present in the image */
+		count = image_multi_count(hdr);
+
+		/* retrieve the "data file" at the idx position */
+		image_multi_getimg(hdr, idx, &file_data, &file_len);
+
+		if ((file_len == 0) || (idx >= count)) {
+			fprintf(stderr, "%s: No such data file %ld in \"%s\"\n",
+				params->cmdname, idx, params->imagefile);
+			return -1;
+		}
+	} else {
+		file_data = image_get_data(hdr);
+		file_len = image_get_size(hdr);
+	}
+
+	/* save the "data file" into the file system */
+	return image_save_datafile(params, file_data, file_len);
+}
+
+/*
+ * Default image type parameters definition
+ */
+static struct image_type_params defimage_params = {
+	.name = "Default Image support",
+	.header_size = sizeof(image_header_t),
+	.hdr = (void*)&header,
+	.check_image_type = image_check_image_types,
+	.verify_header = image_verify_header,
+	.print_header = image_print_contents,
+	.set_header = image_set_header,
+	.extract_datafile = image_extract_datafile,
+	.check_params = image_check_params,
+};
+
+void init_default_image_type(void)
+{
+	register_image_type(&defimage_params);
+}
diff --git a/marvell/uboot/tools/dumpimage.c b/marvell/uboot/tools/dumpimage.c
new file mode 100644
index 0000000..542ee28
--- /dev/null
+++ b/marvell/uboot/tools/dumpimage.c
@@ -0,0 +1,305 @@
+/*
+ * Based on mkimage.c.
+ *
+ * Written by Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "dumpimage.h"
+#include <image.h>
+#include <version.h>
+
+static void usage(void);
+
+/* image_type_params linked list to maintain registered image types supports */
+static struct image_type_params *dumpimage_tparams;
+
+/* parameters initialized by core will be used by the image type code */
+static struct image_tool_params params = {
+	.type = IH_TYPE_KERNEL,
+};
+
+/**
+ * dumpimage_register() - register respective image generation/list support
+ *
+ * the input struct image_type_params is checked and appended to the link
+ * list, if the input structure is already registered, issue an error
+ *
+ * @tparams: Image type parameters
+ */
+static void dumpimage_register(struct image_type_params *tparams)
+{
+	struct image_type_params **tp;
+
+	if (!tparams) {
+		fprintf(stderr, "%s: %s: Null input\n", params.cmdname,
+			__func__);
+		exit(EXIT_FAILURE);
+	}
+
+	/* scan the linked list, check for registry and point the last one */
+	for (tp = &dumpimage_tparams; *tp != NULL; tp = &(*tp)->next) {
+		if (!strcmp((*tp)->name, tparams->name)) {
+			fprintf(stderr, "%s: %s already registered\n",
+				params.cmdname, tparams->name);
+			return;
+		}
+	}
+
+	/* add input struct entry at the end of link list */
+	*tp = tparams;
+	/* mark input entry as last entry in the link list */
+	tparams->next = NULL;
+
+	debug("Registered %s\n", tparams->name);
+}
+
+/**
+ * dumpimage_get_type() - find the image type params for a given image type
+ *
+ * Scan all registered image types and check the input type_id for each
+ * supported image type
+ *
+ * @return respective image_type_params pointer. If the input type is not
+ * supported by any of registered image types, returns NULL
+ */
+static struct image_type_params *dumpimage_get_type(int type)
+{
+	struct image_type_params *curr;
+
+	for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) {
+		if (curr->check_image_type) {
+			if (!curr->check_image_type(type))
+				return curr;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * dumpimage_verify_print_header() - verifies the image header
+ *
+ * Scan registered image types and verify the image_header for each
+ * supported image type. If verification is successful, this prints
+ * the respective header.
+ *
+ * @return 0 on success, negative if input image format does not match with
+ * any of supported image types
+ */
+static int dumpimage_verify_print_header(void *ptr, struct stat *sbuf)
+{
+	int retval = -1;
+	struct image_type_params *curr;
+
+	for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) {
+		if (curr->verify_header) {
+			retval = curr->verify_header((unsigned char *)ptr,
+						     sbuf->st_size, &params);
+			if (retval != 0)
+				continue;
+			/*
+			 * Print the image information  if verify is
+			 * successful
+			 */
+			if (curr->print_header) {
+				curr->print_header(ptr);
+			} else {
+				fprintf(stderr,
+					"%s: print_header undefined for %s\n",
+					params.cmdname, curr->name);
+			}
+			break;
+		}
+	}
+
+	return retval;
+}
+
+/*
+ * dumpimage_extract_datafile -
+ *
+ * It scans all registered image types,
+ * verifies image_header for each supported image type
+ * if verification is successful, it extracts the desired file,
+ * indexed by pflag, from the image
+ *
+ * returns negative if input image format does not match with any of
+ * supported image types
+ */
+static int dumpimage_extract_datafile(void *ptr, struct stat *sbuf)
+{
+	int retval = -1;
+	struct image_type_params *curr;
+
+	for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) {
+		if (curr->verify_header) {
+			retval = curr->verify_header((unsigned char *)ptr,
+						     sbuf->st_size, &params);
+			if (retval != 0)
+				continue;
+			/*
+			 * Extract the file from the image
+			 * if verify is successful
+			 */
+			if (curr->extract_datafile) {
+				curr->extract_datafile(ptr, &params);
+			} else {
+				fprintf(stderr,
+					"%s: extract_datafile undefined for %s\n",
+					params.cmdname, curr->name);
+			break;
+			}
+		}
+	}
+
+	return retval;
+}
+
+int main(int argc, char **argv)
+{
+	int opt;
+	int ifd = -1;
+	struct stat sbuf;
+	char *ptr;
+	int retval = 0;
+	struct image_type_params *tparams = NULL;
+
+	/* Init all image generation/list support */
+	register_image_tool(dumpimage_register);
+
+	params.cmdname = *argv;
+
+	while ((opt = getopt(argc, argv, "li:o:p:V")) != -1) {
+		switch (opt) {
+		case 'l':
+			params.lflag = 1;
+			break;
+		case 'i':
+			params.imagefile = optarg;
+			params.iflag = 1;
+			break;
+		case 'o':
+			params.outfile = optarg;
+			break;
+		case 'p':
+			params.pflag = strtoul(optarg, &ptr, 10);
+			if (*ptr) {
+				fprintf(stderr,
+					"%s: invalid file position %s\n",
+					params.cmdname, *argv);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'V':
+			printf("dumpimage version %s\n", PLAIN_VERSION);
+			exit(EXIT_SUCCESS);
+		default:
+			usage();
+		}
+	}
+
+	if (optind >= argc)
+		usage();
+
+	/* set tparams as per input type_id */
+	tparams = dumpimage_get_type(params.type);
+	if (tparams == NULL) {
+		fprintf(stderr, "%s: unsupported type %s\n",
+			params.cmdname, genimg_get_type_name(params.type));
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * check the passed arguments parameters meets the requirements
+	 * as per image type to be generated/listed
+	 */
+	if (tparams->check_params) {
+		if (tparams->check_params(&params))
+			usage();
+	}
+
+	if (params.iflag)
+		params.datafile = argv[optind];
+	else
+		params.imagefile = argv[optind];
+	if (!params.outfile)
+		params.outfile = params.datafile;
+
+	ifd = open(params.imagefile, O_RDONLY|O_BINARY);
+	if (ifd < 0) {
+		fprintf(stderr, "%s: Can't open \"%s\": %s\n",
+			params.cmdname, params.imagefile,
+			strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (params.lflag || params.iflag) {
+		if (fstat(ifd, &sbuf) < 0) {
+			fprintf(stderr, "%s: Can't stat \"%s\": %s\n",
+				params.cmdname, params.imagefile,
+				strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+
+		if ((unsigned)sbuf.st_size < tparams->header_size) {
+			fprintf(stderr,
+				"%s: Bad size: \"%s\" is not valid image\n",
+				params.cmdname, params.imagefile);
+			exit(EXIT_FAILURE);
+		}
+
+		ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
+		if (ptr == MAP_FAILED) {
+			fprintf(stderr, "%s: Can't read \"%s\": %s\n",
+				params.cmdname, params.imagefile,
+				strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+
+		/*
+		 * Both calls bellow scan through dumpimage registry for all
+		 * supported image types and verify the input image file
+		 * header for match
+		 */
+		if (params.iflag) {
+			/*
+			 * Extract the data files from within the matched
+			 * image type. Returns the error code if not matched
+			 */
+			retval = dumpimage_extract_datafile(ptr, &sbuf);
+		} else {
+			/*
+			 * Print the image information for matched image type
+			 * Returns the error code if not matched
+			 */
+			retval = dumpimage_verify_print_header(ptr, &sbuf);
+		}
+
+		(void)munmap((void *)ptr, sbuf.st_size);
+		(void)close(ifd);
+
+		return retval;
+	}
+
+	(void)close(ifd);
+
+	return EXIT_SUCCESS;
+}
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: %s -l image\n"
+		"          -l ==> list image header information\n",
+		params.cmdname);
+	fprintf(stderr,
+		"       %s -i image [-p position] [-o outfile] data_file\n"
+		"          -i ==> extract from the 'image' a specific 'data_file'"
+		", indexed by 'position' (starting at 0)\n",
+		params.cmdname);
+	fprintf(stderr,
+		"       %s -V ==> print version information and exit\n",
+		params.cmdname);
+
+	exit(EXIT_FAILURE);
+}
diff --git a/marvell/uboot/tools/dumpimage.h b/marvell/uboot/tools/dumpimage.h
new file mode 100644
index 0000000..d78523d
--- /dev/null
+++ b/marvell/uboot/tools/dumpimage.h
@@ -0,0 +1,33 @@
+/*
+ * Based on mkimage.c.
+ *
+ * Written by Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DUMPIMAGE_H_
+#define _DUMPIMAGE_H_
+
+#include "os_support.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <sha1.h>
+#include "fdt_host.h"
+#include "imagetool.h"
+
+#undef DUMPIMAGE_DEBUG
+
+#ifdef DUMPIMAGE_DEBUG
+#define debug(fmt, args...)	printf(fmt, ##args)
+#else
+#define debug(fmt, args...)
+#endif /* DUMPIMAGE_DEBUG */
+
+#endif /* _DUMPIMAGE_H_ */
diff --git a/marvell/uboot/tools/easylogo/Makefile b/marvell/uboot/tools/easylogo/Makefile
new file mode 100644
index 0000000..d8e28b0
--- /dev/null
+++ b/marvell/uboot/tools/easylogo/Makefile
@@ -0,0 +1,11 @@
+include $(TOPDIR)/config.mk
+
+all: $(obj)easylogo
+
+$(obj)easylogo: $(SRCTREE)/tools/easylogo/easylogo.c
+	$(HOSTCC) $(HOSTCFLAGS_NOPED) $(HOSTLDFLAGS) -o $@ $^
+
+clean:
+	rm -f $(obj)easylogo
+
+.PHONY: all clean
diff --git a/marvell/uboot/tools/easylogo/easylogo.c b/marvell/uboot/tools/easylogo/easylogo.c
new file mode 100644
index 0000000..4ba86bf
--- /dev/null
+++ b/marvell/uboot/tools/easylogo/easylogo.c
@@ -0,0 +1,610 @@
+/*
+** Easylogo TGA->header converter
+** ==============================
+** (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
+** AIRVENT SAM s.p.a - RIMINI(ITALY)
+** (C) 2007-2008 Mike Frysinger <vapier@gentoo.org>
+**
+** This is still under construction!
+*/
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#pragma pack(1)
+
+/*#define ENABLE_ASCII_BANNERS */
+
+typedef struct {
+	unsigned char id;
+	unsigned char ColorMapType;
+	unsigned char ImageTypeCode;
+	unsigned short ColorMapOrigin;
+	unsigned short ColorMapLenght;
+	unsigned char ColorMapEntrySize;
+	unsigned short ImageXOrigin;
+	unsigned short ImageYOrigin;
+	unsigned short ImageWidth;
+	unsigned short ImageHeight;
+	unsigned char ImagePixelSize;
+	unsigned char ImageDescriptorByte;
+} tga_header_t;
+
+typedef struct {
+	unsigned char r, g, b;
+} rgb_t;
+
+typedef struct {
+	unsigned char b, g, r;
+} bgr_t;
+
+typedef struct {
+	unsigned char Cb, y1, Cr, y2;
+} yuyv_t;
+
+typedef struct {
+	void *data, *palette;
+	int width, height, pixels, bpp, pixel_size, size, palette_size, yuyv;
+} image_t;
+
+void *xmalloc (size_t size)
+{
+	void *ret = malloc (size);
+	if (!ret) {
+		fprintf (stderr, "\nerror: malloc(%zu) failed: %s",
+			size, strerror(errno));
+		exit (1);
+	}
+	return ret;
+}
+
+void StringUpperCase (char *str)
+{
+	int count = strlen (str);
+	char c;
+
+	while (count--) {
+		c = *str;
+		if ((c >= 'a') && (c <= 'z'))
+			*str = 'A' + (c - 'a');
+		str++;
+	}
+}
+
+void StringLowerCase (char *str)
+{
+	int count = strlen (str);
+	char c;
+
+	while (count--) {
+		c = *str;
+		if ((c >= 'A') && (c <= 'Z'))
+			*str = 'a' + (c - 'A');
+		str++;
+	}
+}
+void pixel_rgb_to_yuyv (rgb_t * rgb_pixel, yuyv_t * yuyv_pixel)
+{
+	unsigned int pR, pG, pB;
+
+	/* Transform (0-255) components to (0-100) */
+	pR = rgb_pixel->r * 100 / 255;
+	pG = rgb_pixel->g * 100 / 255;
+	pB = rgb_pixel->b * 100 / 255;
+
+	/* Calculate YUV values (0-255) from RGB beetween 0-100 */
+	yuyv_pixel->y1 = yuyv_pixel->y2 = 209 * (pR + pG + pB) / 300 + 16;
+	yuyv_pixel->Cb = pB - (pR / 4) - (pG * 3 / 4) + 128;
+	yuyv_pixel->Cr = pR - (pG * 3 / 4) - (pB / 4) + 128;
+
+	return;
+}
+
+void printlogo_rgb (rgb_t * data, int w, int h)
+{
+	int x, y;
+
+	for (y = 0; y < h; y++) {
+		for (x = 0; x < w; x++, data++)
+			if ((data->r <
+			     30) /*&&(data->g == 0)&&(data->b == 0) */ )
+				printf (" ");
+			else
+				printf ("X");
+		printf ("\n");
+	}
+}
+
+void printlogo_yuyv (unsigned short *data, int w, int h)
+{
+	int x, y;
+
+	for (y = 0; y < h; y++) {
+		for (x = 0; x < w; x++, data++)
+			if (*data == 0x1080)	/* Because of inverted on i386! */
+				printf (" ");
+			else
+				printf ("X");
+		printf ("\n");
+	}
+}
+
+static inline unsigned short le16_to_cpu (unsigned short val)
+{
+	union {
+		unsigned char pval[2];
+		unsigned short val;
+	} swapped;
+
+	swapped.val = val;
+	return (swapped.pval[1] << 8) + swapped.pval[0];
+}
+
+int image_load_tga (image_t * image, char *filename)
+{
+	FILE *file;
+	tga_header_t header;
+	int i;
+	unsigned char app;
+	rgb_t *p;
+
+	if ((file = fopen (filename, "rb")) == NULL)
+		return -1;
+
+	fread (&header, sizeof (header), 1, file);
+
+	/* byte swap: tga is little endian, host is ??? */
+	header.ColorMapOrigin = le16_to_cpu (header.ColorMapOrigin);
+	header.ColorMapLenght = le16_to_cpu (header.ColorMapLenght);
+	header.ImageXOrigin = le16_to_cpu (header.ImageXOrigin);
+	header.ImageYOrigin = le16_to_cpu (header.ImageYOrigin);
+	header.ImageWidth = le16_to_cpu (header.ImageWidth);
+	header.ImageHeight = le16_to_cpu (header.ImageHeight);
+
+	image->width = header.ImageWidth;
+	image->height = header.ImageHeight;
+
+	switch (header.ImageTypeCode) {
+	case 2:		/* Uncompressed RGB */
+		image->yuyv = 0;
+		image->palette_size = 0;
+		image->palette = NULL;
+		break;
+
+	default:
+		printf ("Format not supported!\n");
+		return -1;
+	}
+
+	image->bpp = header.ImagePixelSize;
+	image->pixel_size = ((image->bpp - 1) / 8) + 1;
+	image->pixels = image->width * image->height;
+	image->size = image->pixels * image->pixel_size;
+	image->data = xmalloc (image->size);
+
+	if (image->bpp != 24) {
+		printf ("Bpp not supported: %d!\n", image->bpp);
+		return -1;
+	}
+
+	fread (image->data, image->size, 1, file);
+
+/* Swapping R and B values */
+
+	p = image->data;
+	for (i = 0; i < image->pixels; i++, p++) {
+		app = p->r;
+		p->r = p->b;
+		p->b = app;
+	}
+
+/* Swapping image */
+
+	if (!(header.ImageDescriptorByte & 0x20)) {
+		unsigned char *temp = xmalloc (image->size);
+		int linesize = image->pixel_size * image->width;
+		void *dest = image->data,
+			*source = temp + image->size - linesize;
+
+		printf ("S");
+		if (temp == NULL) {
+			printf ("Cannot alloc temp buffer!\n");
+			return -1;
+		}
+
+		memcpy (temp, image->data, image->size);
+		for (i = 0; i < image->height;
+		     i++, dest += linesize, source -= linesize)
+			memcpy (dest, source, linesize);
+
+		free (temp);
+	}
+#ifdef ENABLE_ASCII_BANNERS
+	printlogo_rgb (image->data, image->width, image->height);
+#endif
+
+	fclose (file);
+	return 0;
+}
+
+void image_free (image_t * image)
+{
+	free (image->data);
+	free (image->palette);
+}
+
+int image_rgb_to_yuyv (image_t * rgb_image, image_t * yuyv_image)
+{
+	rgb_t *rgb_ptr = (rgb_t *) rgb_image->data;
+	yuyv_t yuyv;
+	unsigned short *dest;
+	int count = 0;
+
+	yuyv_image->pixel_size = 2;
+	yuyv_image->bpp = 16;
+	yuyv_image->yuyv = 1;
+	yuyv_image->width = rgb_image->width;
+	yuyv_image->height = rgb_image->height;
+	yuyv_image->pixels = yuyv_image->width * yuyv_image->height;
+	yuyv_image->size = yuyv_image->pixels * yuyv_image->pixel_size;
+	dest = (unsigned short *) (yuyv_image->data =
+				   xmalloc (yuyv_image->size));
+	yuyv_image->palette = 0;
+	yuyv_image->palette_size = 0;
+
+	while ((count++) < rgb_image->pixels) {
+		pixel_rgb_to_yuyv (rgb_ptr++, &yuyv);
+
+		if ((count & 1) == 0)	/* Was == 0 */
+			memcpy (dest, ((void *) &yuyv) + 2, sizeof (short));
+		else
+			memcpy (dest, (void *) &yuyv, sizeof (short));
+
+		dest++;
+	}
+
+#ifdef ENABLE_ASCII_BANNERS
+	printlogo_yuyv (yuyv_image->data, yuyv_image->width,
+			yuyv_image->height);
+#endif
+	return 0;
+}
+
+int image_rgb888_to_rgb565(image_t *rgb888_image, image_t *rgb565_image)
+{
+	rgb_t *rgb_ptr = (rgb_t *) rgb888_image->data;
+	unsigned short *dest;
+	int count = 0;
+
+	rgb565_image->pixel_size = 2;
+	rgb565_image->bpp = 16;
+	rgb565_image->yuyv = 0;
+	rgb565_image->width = rgb888_image->width;
+	rgb565_image->height = rgb888_image->height;
+	rgb565_image->pixels = rgb565_image->width * rgb565_image->height;
+	rgb565_image->size = rgb565_image->pixels * rgb565_image->pixel_size;
+	dest = (unsigned short *) (rgb565_image->data =
+				   xmalloc(rgb565_image->size));
+	rgb565_image->palette = 0;
+	rgb565_image->palette_size = 0;
+
+	while ((count++) < rgb888_image->pixels) {
+
+		*dest++ = ((rgb_ptr->b & 0xF8) << 8) |
+			((rgb_ptr->g & 0xFC) << 3) |
+			(rgb_ptr->r >> 3);
+		rgb_ptr++;
+	}
+
+	return 0;
+}
+
+enum comp_t {
+	COMP_NONE,
+	COMP_GZIP,
+	COMP_LZMA,
+};
+static enum comp_t compression = COMP_NONE;
+static bool bss_storage = false;
+
+int image_save_header (image_t * image, char *filename, char *varname)
+{
+	FILE *file = fopen (filename, "w");
+	char app[256], str[256] = "", def_name[64];
+	int count = image->size, col = 0;
+	unsigned char *dataptr = image->data;
+
+	if (file == NULL)
+		return -1;
+
+	/*  Author information */
+	fprintf (file,
+		 "/*\n * Generated by EasyLogo, (C) 2000 by Paolo Scaffardi\n *\n");
+	fprintf (file,
+		 " * To use this, include it and call: easylogo_plot(screen,&%s, width,x,y)\n *\n",
+		 varname);
+	fprintf (file,
+		 " * Where:\t'screen'\tis the pointer to the frame buffer\n");
+	fprintf (file, " *\t\t'width'\tis the screen width\n");
+	fprintf (file, " *\t\t'x'\t\tis the horizontal position\n");
+	fprintf (file, " *\t\t'y'\t\tis the vertical position\n */\n\n");
+
+	/* image compress */
+	if (compression != COMP_NONE) {
+		const char *errstr = NULL;
+		unsigned char *compressed;
+		const char *comp_name;
+		struct stat st;
+		FILE *compfp;
+		size_t filename_len = strlen(filename);
+		char *compfilename = xmalloc(filename_len + 20);
+		char *compcmd = xmalloc(filename_len + 50);
+
+		sprintf(compfilename, "%s.bin", filename);
+		switch (compression) {
+		case COMP_GZIP:
+			strcpy(compcmd, "gzip");
+			comp_name = "GZIP";
+			break;
+		case COMP_LZMA:
+			strcpy(compcmd, "lzma");
+			comp_name = "LZMA";
+			break;
+		default:
+			errstr = "\nerror: unknown compression method";
+			goto done;
+		}
+		strcat(compcmd, " > ");
+		strcat(compcmd, compfilename);
+		compfp = popen(compcmd, "w");
+		if (!compfp) {
+			errstr = "\nerror: popen() failed";
+			goto done;
+		}
+		if (fwrite(image->data, image->size, 1, compfp) != 1) {
+			errstr = "\nerror: writing data to gzip failed";
+			goto done;
+		}
+		if (pclose(compfp)) {
+			errstr = "\nerror: gzip process failed";
+			goto done;
+		}
+
+		compfp = fopen(compfilename, "r");
+		if (!compfp) {
+			errstr = "\nerror: open() on gzip data failed";
+			goto done;
+		}
+		if (stat(compfilename, &st)) {
+			errstr = "\nerror: stat() on gzip file failed";
+			goto done;
+		}
+		compressed = xmalloc(st.st_size);
+		if (fread(compressed, st.st_size, 1, compfp) != 1) {
+			errstr = "\nerror: reading gzip data failed";
+			goto done;
+		}
+		fclose(compfp);
+
+		unlink(compfilename);
+
+		dataptr = compressed;
+		count = st.st_size;
+		fprintf(file, "#define EASYLOGO_ENABLE_%s %i\n\n", comp_name, count);
+		if (bss_storage)
+			fprintf (file, "static unsigned char EASYLOGO_DECOMP_BUFFER[%i];\n\n", image->size);
+
+ done:
+		free(compfilename);
+		free(compcmd);
+
+		if (errstr) {
+			perror (errstr);
+			return -1;
+		}
+	}
+
+	/*	Headers */
+	fprintf (file, "#include <video_easylogo.h>\n\n");
+	/*	Macros */
+	strcpy (def_name, varname);
+	StringUpperCase (def_name);
+	fprintf (file, "#define	DEF_%s_WIDTH\t\t%d\n", def_name,
+		 image->width);
+	fprintf (file, "#define	DEF_%s_HEIGHT\t\t%d\n", def_name,
+		 image->height);
+	fprintf (file, "#define	DEF_%s_PIXELS\t\t%d\n", def_name,
+		 image->pixels);
+	fprintf (file, "#define	DEF_%s_BPP\t\t%d\n", def_name, image->bpp);
+	fprintf (file, "#define	DEF_%s_PIXEL_SIZE\t%d\n", def_name,
+		 image->pixel_size);
+	fprintf (file, "#define	DEF_%s_SIZE\t\t%d\n\n", def_name,
+		 image->size);
+	/*  Declaration */
+	fprintf (file, "unsigned char DEF_%s_DATA[] = {\n",
+		 def_name);
+
+	/*	Data */
+	while (count)
+		switch (col) {
+		case 0:
+			sprintf (str, " 0x%02x", *dataptr++);
+			col++;
+			count--;
+			break;
+
+		case 16:
+			fprintf (file, "%s", str);
+			if (count > 0)
+				fprintf (file, ",");
+			fprintf (file, "\n");
+
+			col = 0;
+			break;
+
+		default:
+			strcpy (app, str);
+			sprintf (str, "%s, 0x%02x", app, *dataptr++);
+			col++;
+			count--;
+			break;
+		}
+
+	if (col)
+		fprintf (file, "%s\n", str);
+
+	/*	End of declaration */
+	fprintf (file, "};\n\n");
+	/*	Variable */
+	fprintf (file, "fastimage_t %s = {\n", varname);
+	fprintf (file, "		DEF_%s_DATA,\n", def_name);
+	fprintf (file, "		DEF_%s_WIDTH,\n", def_name);
+	fprintf (file, "		DEF_%s_HEIGHT,\n", def_name);
+	fprintf (file, "		DEF_%s_BPP,\n", def_name);
+	fprintf (file, "		DEF_%s_PIXEL_SIZE,\n", def_name);
+	fprintf (file, "		DEF_%s_SIZE\n};\n", def_name);
+
+	fclose (file);
+
+	return 0;
+}
+
+#define DEF_FILELEN	256
+
+static void usage (int exit_status)
+{
+	puts (
+		"EasyLogo 1.0 (C) 2000 by Paolo Scaffardi\n"
+		"\n"
+		"Syntax:	easylogo [options] inputfile [outputvar [outputfile]]\n"
+		"\n"
+		"Options:\n"
+		"  -r     Output RGB888 instead of YUYV\n"
+		"  -s     Output RGB565 instead of YUYV\n"
+		"  -g     Compress with gzip\n"
+		"  -l     Compress with lzma\n"
+		"  -b     Preallocate space in bss for decompressing image\n"
+		"  -h     Help output\n"
+		"\n"
+		"Where: 'inputfile'   is the TGA image to load\n"
+		"       'outputvar'   is the variable name to create\n"
+		"       'outputfile'  is the output header file (default is 'inputfile.h')"
+	);
+	exit (exit_status);
+}
+
+int main (int argc, char *argv[])
+{
+	int c;
+	bool use_rgb888 = false;
+	bool use_rgb565 = false;
+	char inputfile[DEF_FILELEN],
+		outputfile[DEF_FILELEN], varname[DEF_FILELEN];
+
+	image_t rgb888_logo, rgb565_logo, yuyv_logo;
+
+	while ((c = getopt(argc, argv, "hrsglb")) > 0) {
+		switch (c) {
+		case 'h':
+			usage (0);
+			break;
+		case 'r':
+			use_rgb888 = true;
+			puts("Using 24-bit RGB888 Output Fromat");
+			break;
+		case 's':
+			use_rgb565 = true;
+			puts("Using 16-bit RGB565 Output Fromat");
+			break;
+		case 'g':
+			compression = COMP_GZIP;
+			puts("Compressing with gzip");
+			break;
+		case 'l':
+			compression = COMP_LZMA;
+			puts("Compressing with lzma");
+			break;
+		case 'b':
+			bss_storage = true;
+			puts("Preallocating bss space for decompressing image");
+			break;
+		default:
+			usage (1);
+			break;
+		}
+	}
+
+	c = argc - optind;
+	if (c > 4 || c < 1)
+		usage (1);
+
+	strcpy (inputfile, argv[optind]);
+
+	if (c > 1)
+		strcpy (varname, argv[optind + 1]);
+	else {
+		/* transform "input.tga" to just "input" */
+		char *dot;
+		strcpy (varname, inputfile);
+		dot = strchr (varname, '.');
+		if (dot)
+			*dot = '\0';
+	}
+
+	if (c > 2)
+		strcpy (outputfile, argv[optind + 2]);
+	else {
+		/* just append ".h" to input file name */
+		strcpy (outputfile, inputfile);
+		strcat (outputfile, ".h");
+	}
+
+	/* Make sure the output is sent as soon as we printf() */
+	setbuf(stdout, NULL);
+
+	printf ("Doing '%s' (%s) from '%s'...",
+		outputfile, varname, inputfile);
+
+	/* Import TGA logo */
+
+	printf ("L");
+	if (image_load_tga(&rgb888_logo, inputfile) < 0) {
+		printf ("input file not found!\n");
+		exit (1);
+	}
+
+	/* Convert, save, and free the image */
+
+	if (!use_rgb888 && !use_rgb565) {
+		printf ("C");
+		image_rgb_to_yuyv(&rgb888_logo, &yuyv_logo);
+
+		printf("S");
+		image_save_header(&yuyv_logo, outputfile, varname);
+		image_free(&yuyv_logo);
+	} else if (use_rgb565) {
+		printf("C");
+		image_rgb888_to_rgb565(&rgb888_logo, &rgb565_logo);
+
+		printf("S");
+		image_save_header(&rgb565_logo, outputfile, varname);
+		image_free(&rgb565_logo);
+	} else {
+		printf("S");
+		image_save_header(&rgb888_logo, outputfile, varname);
+	}
+
+	/* Free original image and copy */
+
+	image_free(&rgb888_logo);
+
+	printf ("\n");
+
+	return 0;
+}
diff --git a/marvell/uboot/tools/easylogo/linux_blackfin.tga b/marvell/uboot/tools/easylogo/linux_blackfin.tga
new file mode 100644
index 0000000..e2bb17b
--- /dev/null
+++ b/marvell/uboot/tools/easylogo/linux_blackfin.tga
Binary files differ
diff --git a/marvell/uboot/tools/easylogo/linux_logo.tga b/marvell/uboot/tools/easylogo/linux_logo.tga
new file mode 100644
index 0000000..ac53def
--- /dev/null
+++ b/marvell/uboot/tools/easylogo/linux_logo.tga
Binary files differ
diff --git a/marvell/uboot/tools/easylogo/runme.sh b/marvell/uboot/tools/easylogo/runme.sh
new file mode 100644
index 0000000..625ebaa
--- /dev/null
+++ b/marvell/uboot/tools/easylogo/runme.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+make
+./easylogo linux_logo.tga u_boot_logo video_logo.h
+mv video_logo.h ../../include
diff --git a/marvell/uboot/tools/env/Makefile b/marvell/uboot/tools/env/Makefile
new file mode 100644
index 0000000..27892f7
--- /dev/null
+++ b/marvell/uboot/tools/env/Makefile
@@ -0,0 +1,43 @@
+#
+# (C) Copyright 2002-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+HOSTSRCS := $(SRCTREE)/lib/crc32.c  fw_env.c  fw_env_main.c
+HOSTSRCS += $(SRCTREE)/lib/ctype.c $(SRCTREE)/lib/linux_string.c
+HOSTSRCS += $(SRCTREE)/common/env_attr.c $(SRCTREE)/common/env_flags.c
+HEADERS	:= fw_env.h $(OBJTREE)/include/config.h
+
+# Compile for a hosted environment on the target
+HOSTCPPFLAGS  = -idirafter $(SRCTREE)/include \
+		-idirafter $(SRCTREE)/arch/$(ARCH)/include \
+		-idirafter $(OBJTREE)/include \
+		-idirafter $(SRCTREE)/tools/env \
+		-DUSE_HOSTCC \
+		-DTEXT_BASE=$(TEXT_BASE)
+
+ifeq ($(MTD_VERSION),old)
+HOSTCPPFLAGS += -DMTD_OLD
+endif
+
+all:	$(obj)fw_printenv
+
+# Some files complain if compiled with -pedantic, use HOSTCFLAGS_NOPED
+$(obj)fw_printenv:	$(HOSTSRCS) $(HEADERS)
+	$(HOSTCC) $(HOSTCFLAGS_NOPED) $(HOSTLDFLAGS) -o $@ $(HOSTSRCS)
+	$(HOSTSTRIP) $@
+
+clean:
+	rm -f $(obj)fw_printenv
+
+#########################################################################
+
+include $(TOPDIR)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/marvell/uboot/tools/env/README b/marvell/uboot/tools/env/README
new file mode 100644
index 0000000..1020b57
--- /dev/null
+++ b/marvell/uboot/tools/env/README
@@ -0,0 +1,61 @@
+
+This is a demo implementation of a Linux command line tool to access
+the U-Boot's environment variables.
+
+In the current version, there is an issue in cross-compilation.
+In order to cross-compile fw_printenv, run
+    make HOSTCC=<your CC cross-compiler> env
+in the root directory of the U-Boot distribution. For example,
+    make HOSTCC=arm-linux-gcc env
+
+For the run-time utility configuration uncomment the line
+#define CONFIG_FILE  "/etc/fw_env.config"
+in fw_env.h.
+
+For building against older versions of the MTD headers (meaning before
+v2.6.8-rc1) it is required to pass the argument "MTD_VERSION=old" to
+make.
+
+See comments in the fw_env.config file for definitions for the
+particular board.
+
+Configuration can also be done via #defines in the fw_env.h file. The
+following lines are relevant:
+
+#define HAVE_REDUND	/* For systems with 2 env sectors */
+#define DEVICE1_NAME	"/dev/mtd1"
+#define DEVICE2_NAME	"/dev/mtd2"
+#define DEVICE1_OFFSET    0x0000
+#define ENV1_SIZE         0x4000
+#define DEVICE1_ESIZE     0x4000
+#define DEVICE1_ENVSECTORS     2
+#define DEVICE2_OFFSET    0x0000
+#define ENV2_SIZE         0x4000
+#define DEVICE2_ESIZE     0x4000
+#define DEVICE2_ENVSECTORS     2
+
+Un-define HAVE_REDUND, if you want to use the utilities on a system
+that does not have support for redundant environment enabled.
+If HAVE_REDUND is undefined, DEVICE2_NAME is ignored,
+as is ENV2_SIZE and DEVICE2_ESIZE.
+
+The DEVICEx_NAME constants define which MTD character devices are to
+be used to access the environment.
+
+The DEVICEx_OFFSET constants define the environment offset within the
+MTD character device.
+
+ENVx_SIZE defines the size in bytes taken by the environment, which
+may be less then flash sector size, if the environment takes less
+then 1 sector.
+
+DEVICEx_ESIZE defines the size of the first sector in the flash
+partition where the environment resides.
+
+DEVICEx_ENVSECTORS defines the number of sectors that may be used for
+this environment instance. On NAND this is used to limit the range
+within which bad blocks are skipped, on NOR it is not used.
+
+To prevent losing changes to the environment and to prevent confusing the MTD
+drivers, a lock file at /var/lock/fw_printenv.lock is used to serialize access
+to the environment.
diff --git a/marvell/uboot/tools/env/fw_env.c b/marvell/uboot/tools/env/fw_env.c
new file mode 100644
index 0000000..577ce2d
--- /dev/null
+++ b/marvell/uboot/tools/env/fw_env.c
@@ -0,0 +1,1337 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2008
+ * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <errno.h>
+#include <env_flags.h>
+#include <fcntl.h>
+#include <linux/stringify.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef MTD_OLD
+# include <stdint.h>
+# include <linux/mtd/mtd.h>
+#else
+# define  __user	/* nothing */
+# include <mtd/mtd-user.h>
+#endif
+
+#include "fw_env.h"
+
+#define WHITESPACE(c) ((c == '\t') || (c == ' '))
+
+#define min(x, y) ({				\
+	typeof(x) _min1 = (x);			\
+	typeof(y) _min2 = (y);			\
+	(void) (&_min1 == &_min2);		\
+	_min1 < _min2 ? _min1 : _min2; })
+
+struct envdev_s {
+	char devname[16];		/* Device name */
+	ulong devoff;			/* Device offset */
+	ulong env_size;			/* environment size */
+	ulong erase_size;		/* device erase size */
+	ulong env_sectors;		/* number of environment sectors */
+	uint8_t mtd_type;		/* type of the MTD device */
+};
+
+static struct envdev_s envdevices[2] =
+{
+	{
+		.mtd_type = MTD_ABSENT,
+	}, {
+		.mtd_type = MTD_ABSENT,
+	},
+};
+static int dev_current;
+
+#define DEVNAME(i)    envdevices[(i)].devname
+#define DEVOFFSET(i)  envdevices[(i)].devoff
+#define ENVSIZE(i)    envdevices[(i)].env_size
+#define DEVESIZE(i)   envdevices[(i)].erase_size
+#define ENVSECTORS(i) envdevices[(i)].env_sectors
+#define DEVTYPE(i)    envdevices[(i)].mtd_type
+
+#define CUR_ENVSIZE ENVSIZE(dev_current)
+
+#define ENV_SIZE      getenvsize()
+
+struct env_image_single {
+	uint32_t	crc;	/* CRC32 over data bytes    */
+	char		data[];
+};
+
+struct env_image_redundant {
+	uint32_t	crc;	/* CRC32 over data bytes    */
+	unsigned char	flags;	/* active or obsolete */
+	char		data[];
+};
+
+enum flag_scheme {
+	FLAG_NONE,
+	FLAG_BOOLEAN,
+	FLAG_INCREMENTAL,
+};
+
+struct environment {
+	void			*image;
+	uint32_t		*crc;
+	unsigned char		*flags;
+	char			*data;
+	enum flag_scheme	flag_scheme;
+};
+
+static struct environment environment = {
+	.flag_scheme = FLAG_NONE,
+};
+
+static int HaveRedundEnv = 0;
+
+static unsigned char active_flag = 1;
+/* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */
+static unsigned char obsolete_flag = 0;
+
+#define DEFAULT_ENV_INSTANCE_STATIC
+#include <env_default.h>
+
+static int flash_io (int mode);
+static char *envmatch (char * s1, char * s2);
+static int parse_config (void);
+
+#if defined(CONFIG_FILE)
+static int get_config (char *);
+#endif
+static inline ulong getenvsize (void)
+{
+	ulong rc = CUR_ENVSIZE - sizeof(long);
+
+	if (HaveRedundEnv)
+		rc -= sizeof (char);
+	return rc;
+}
+
+static char *fw_string_blank(char *s, int noblank)
+{
+	int i;
+	int len = strlen(s);
+
+	for (i = 0; i < len; i++, s++) {
+		if ((noblank && !WHITESPACE(*s)) ||
+			(!noblank && WHITESPACE(*s)))
+			break;
+	}
+	if (i == len)
+		return NULL;
+
+	return s;
+}
+
+/*
+ * Search the environment for a variable.
+ * Return the value, if found, or NULL, if not found.
+ */
+char *fw_getenv (char *name)
+{
+	char *env, *nxt;
+
+	for (env = environment.data; *env; env = nxt + 1) {
+		char *val;
+
+		for (nxt = env; *nxt; ++nxt) {
+			if (nxt >= &environment.data[ENV_SIZE]) {
+				fprintf (stderr, "## Error: "
+					"environment not terminated\n");
+				return NULL;
+			}
+		}
+		val = envmatch (name, env);
+		if (!val)
+			continue;
+		return val;
+	}
+	return NULL;
+}
+
+/*
+ * Search the default environment for a variable.
+ * Return the value, if found, or NULL, if not found.
+ */
+char *fw_getdefenv(char *name)
+{
+	char *env, *nxt;
+
+	for (env = default_environment; *env; env = nxt + 1) {
+		char *val;
+
+		for (nxt = env; *nxt; ++nxt) {
+			if (nxt >= &default_environment[ENV_SIZE]) {
+				fprintf(stderr, "## Error: "
+					"default environment not terminated\n");
+				return NULL;
+			}
+		}
+		val = envmatch(name, env);
+		if (!val)
+			continue;
+		return val;
+	}
+	return NULL;
+}
+
+/*
+ * Print the current definition of one, or more, or all
+ * environment variables
+ */
+int fw_printenv (int argc, char *argv[])
+{
+	char *env, *nxt;
+	int i, n_flag;
+	int rc = 0;
+
+	if (fw_env_open())
+		return -1;
+
+	if (argc == 1) {		/* Print all env variables  */
+		for (env = environment.data; *env; env = nxt + 1) {
+			for (nxt = env; *nxt; ++nxt) {
+				if (nxt >= &environment.data[ENV_SIZE]) {
+					fprintf (stderr, "## Error: "
+						"environment not terminated\n");
+					return -1;
+				}
+			}
+
+			printf ("%s\n", env);
+		}
+		return 0;
+	}
+
+	if (strcmp (argv[1], "-n") == 0) {
+		n_flag = 1;
+		++argv;
+		--argc;
+		if (argc != 2) {
+			fprintf (stderr, "## Error: "
+				"`-n' option requires exactly one argument\n");
+			return -1;
+		}
+	} else {
+		n_flag = 0;
+	}
+
+	for (i = 1; i < argc; ++i) {	/* print single env variables   */
+		char *name = argv[i];
+		char *val = NULL;
+
+		for (env = environment.data; *env; env = nxt + 1) {
+
+			for (nxt = env; *nxt; ++nxt) {
+				if (nxt >= &environment.data[ENV_SIZE]) {
+					fprintf (stderr, "## Error: "
+						"environment not terminated\n");
+					return -1;
+				}
+			}
+			val = envmatch (name, env);
+			if (val) {
+				if (!n_flag) {
+					fputs (name, stdout);
+					putc ('=', stdout);
+				}
+				puts (val);
+				break;
+			}
+		}
+		if (!val) {
+			fprintf (stderr, "## Error: \"%s\" not defined\n", name);
+			rc = -1;
+		}
+	}
+
+	return rc;
+}
+
+int fw_env_close(void)
+{
+	/*
+	 * Update CRC
+	 */
+	*environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE);
+
+	/* write environment back to flash */
+	if (flash_io(O_RDWR)) {
+		fprintf(stderr,
+			"Error: can't write fw_env to flash\n");
+			return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Set/Clear a single variable in the environment.
+ * This is called in sequence to update the environment
+ * in RAM without updating the copy in flash after each set
+ */
+int fw_env_write(char *name, char *value)
+{
+	int len;
+	char *env, *nxt;
+	char *oldval = NULL;
+	int deleting, creating, overwriting;
+
+	/*
+	 * search if variable with this name already exists
+	 */
+	for (nxt = env = environment.data; *env; env = nxt + 1) {
+		for (nxt = env; *nxt; ++nxt) {
+			if (nxt >= &environment.data[ENV_SIZE]) {
+				fprintf(stderr, "## Error: "
+					"environment not terminated\n");
+				errno = EINVAL;
+				return -1;
+			}
+		}
+		if ((oldval = envmatch (name, env)) != NULL)
+			break;
+	}
+
+	deleting = (oldval && !(value && strlen(value)));
+	creating = (!oldval && (value && strlen(value)));
+	overwriting = (oldval && (value && strlen(value)));
+
+	/* check for permission */
+	if (deleting) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_DELETE)) {
+			printf("Can't delete \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		}
+	} else if (overwriting) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) {
+			printf("Can't overwrite \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		} else if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
+			const char *defval = fw_getdefenv(name);
+
+			if (defval == NULL)
+				defval = "";
+			if (strcmp(oldval, defval)
+			    != 0) {
+				printf("Can't overwrite \"%s\"\n", name);
+				errno = EROFS;
+				return -1;
+			}
+		}
+	} else if (creating) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_CREATE)) {
+			printf("Can't create \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		}
+	} else
+		/* Nothing to do */
+		return 0;
+
+	if (deleting || overwriting) {
+		if (*++nxt == '\0') {
+			*env = '\0';
+		} else {
+			for (;;) {
+				*env = *nxt++;
+				if ((*env == '\0') && (*nxt == '\0'))
+					break;
+				++env;
+			}
+		}
+		*++env = '\0';
+	}
+
+	/* Delete only ? */
+	if (!value || !strlen(value))
+		return 0;
+
+	/*
+	 * Append new definition at the end
+	 */
+	for (env = environment.data; *env || *(env + 1); ++env);
+	if (env > environment.data)
+		++env;
+	/*
+	 * Overflow when:
+	 * "name" + "=" + "val" +"\0\0"  > CUR_ENVSIZE - (env-environment)
+	 */
+	len = strlen (name) + 2;
+	/* add '=' for first arg, ' ' for all others */
+	len += strlen(value) + 1;
+
+	if (len > (&environment.data[ENV_SIZE] - env)) {
+		fprintf (stderr,
+			"Error: environment overflow, \"%s\" deleted\n",
+			name);
+		return -1;
+	}
+
+	while ((*env = *name++) != '\0')
+		env++;
+	*env = '=';
+	while ((*++env = *value++) != '\0')
+		;
+
+	/* end is marked with double '\0' */
+	*++env = '\0';
+
+	return 0;
+}
+
+/*
+ * Deletes or sets environment variables. Returns -1 and sets errno error codes:
+ * 0	  - OK
+ * EINVAL - need at least 1 argument
+ * EROFS  - certain variables ("ethaddr", "serial#") cannot be
+ *	    modified or deleted
+ *
+ */
+int fw_setenv(int argc, char *argv[])
+{
+	int i;
+	size_t len;
+	char *name;
+	char *value = NULL;
+
+	if (argc < 2) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (fw_env_open()) {
+		fprintf(stderr, "Error: environment not initialized\n");
+		return -1;
+	}
+
+	name = argv[1];
+
+	if (env_flags_validate_env_set_params(argc, argv) < 0)
+		return 1;
+
+	len = 0;
+	for (i = 2; i < argc; ++i) {
+		char *val = argv[i];
+		size_t val_len = strlen(val);
+
+		if (value)
+			value[len - 1] = ' ';
+		value = realloc(value, len + val_len + 1);
+		if (!value) {
+			fprintf(stderr,
+				"Cannot malloc %zu bytes: %s\n",
+				len, strerror(errno));
+			return -1;
+		}
+
+		memcpy(value + len, val, val_len);
+		len += val_len;
+		value[len++] = '\0';
+	}
+
+	fw_env_write(name, value);
+
+	free(value);
+
+	return fw_env_close();
+}
+
+/*
+ * Parse  a file  and configure the u-boot variables.
+ * The script file has a very simple format, as follows:
+ *
+ * Each line has a couple with name, value:
+ * <white spaces>variable_name<white spaces>variable_value
+ *
+ * Both variable_name and variable_value are interpreted as strings.
+ * Any character after <white spaces> and before ending \r\n is interpreted
+ * as variable's value (no comment allowed on these lines !)
+ *
+ * Comments are allowed if the first character in the line is #
+ *
+ * Returns -1 and sets errno error codes:
+ * 0	  - OK
+ * -1     - Error
+ */
+int fw_parse_script(char *fname)
+{
+	FILE *fp;
+	char dump[1024];	/* Maximum line length in the file */
+	char *name;
+	char *val;
+	int lineno = 0;
+	int len;
+	int ret = 0;
+
+	if (fw_env_open()) {
+		fprintf(stderr, "Error: environment not initialized\n");
+		return -1;
+	}
+
+	if (strcmp(fname, "-") == 0)
+		fp = stdin;
+	else {
+		fp = fopen(fname, "r");
+		if (fp == NULL) {
+			fprintf(stderr, "I cannot open %s for reading\n",
+				 fname);
+			return -1;
+		}
+	}
+
+	while (fgets(dump, sizeof(dump), fp)) {
+		lineno++;
+		len = strlen(dump);
+
+		/*
+		 * Read a whole line from the file. If the line is too long
+		 * or is not terminated, reports an error and exit.
+		 */
+		if (dump[len - 1] != '\n') {
+			fprintf(stderr,
+			"Line %d not corrected terminated or too long\n",
+				lineno);
+			ret = -1;
+			break;
+		}
+
+		/* Drop ending line feed / carriage return */
+		while (len > 0 && (dump[len - 1] == '\n' ||
+				dump[len - 1] == '\r')) {
+			dump[len - 1] = '\0';
+			len--;
+		}
+
+		/* Skip comment or empty lines */
+		if ((len == 0) || dump[0] == '#')
+			continue;
+
+		/*
+		 * Search for variable's name,
+		 * remove leading whitespaces
+		 */
+		name = fw_string_blank(dump, 1);
+		if (!name)
+			continue;
+
+		/* The first white space is the end of variable name */
+		val = fw_string_blank(name, 0);
+		len = strlen(name);
+		if (val) {
+			*val++ = '\0';
+			if ((val - name) < len)
+				val = fw_string_blank(val, 1);
+			else
+				val = NULL;
+		}
+
+#ifdef DEBUG
+		fprintf(stderr, "Setting %s : %s\n",
+			name, val ? val : " removed");
+#endif
+
+		if (env_flags_validate_type(name, val) < 0) {
+			ret = -1;
+			break;
+		}
+
+		/*
+		 * If there is an error setting a variable,
+		 * try to save the environment and returns an error
+		 */
+		if (fw_env_write(name, val)) {
+			fprintf(stderr,
+			"fw_env_write returns with error : %s\n",
+				strerror(errno));
+			ret = -1;
+			break;
+		}
+
+	}
+
+	/* Close file if not stdin */
+	if (strcmp(fname, "-") != 0)
+		fclose(fp);
+
+	ret |= fw_env_close();
+
+	return ret;
+
+}
+
+/*
+ * Test for bad block on NAND, just returns 0 on NOR, on NAND:
+ * 0	- block is good
+ * > 0	- block is bad
+ * < 0	- failed to test
+ */
+static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart)
+{
+	if (mtd_type == MTD_NANDFLASH) {
+		int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart);
+
+		if (badblock < 0) {
+			perror ("Cannot read bad block mark");
+			return badblock;
+		}
+
+		if (badblock) {
+#ifdef DEBUG
+			fprintf (stderr, "Bad block at 0x%llx, "
+				 "skipping\n", *blockstart);
+#endif
+			return badblock;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Read data from flash at an offset into a provided buffer. On NAND it skips
+ * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from
+ * the DEVOFFSET (dev) block. On NOR the loop is only run once.
+ */
+static int flash_read_buf (int dev, int fd, void *buf, size_t count,
+			   off_t offset, uint8_t mtd_type)
+{
+	size_t blocklen;	/* erase / write length - one block on NAND,
+				   0 on NOR */
+	size_t processed = 0;	/* progress counter */
+	size_t readlen = count;	/* current read length */
+	off_t top_of_range;	/* end of the last block we may use */
+	off_t block_seek;	/* offset inside the current block to the start
+				   of the data */
+	loff_t blockstart;	/* running start of the current block -
+				   MEMGETBADBLOCK needs 64 bits */
+	int rc;
+
+	blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev);
+
+	/* Offset inside a block */
+	block_seek = offset - blockstart;
+
+	if (mtd_type == MTD_NANDFLASH) {
+		/*
+		 * NAND: calculate which blocks we are reading. We have
+		 * to read one block at a time to skip bad blocks.
+		 */
+		blocklen = DEVESIZE (dev);
+
+		/*
+		 * To calculate the top of the range, we have to use the
+		 * global DEVOFFSET (dev), which can be different from offset
+		 */
+		top_of_range = ((DEVOFFSET(dev) / blocklen) +
+				ENVSECTORS (dev)) * blocklen;
+
+		/* Limit to one block for the first read */
+		if (readlen > blocklen - block_seek)
+			readlen = blocklen - block_seek;
+	} else {
+		blocklen = 0;
+		top_of_range = offset + count;
+	}
+
+	/* This only runs once on NOR flash */
+	while (processed < count) {
+		rc = flash_bad_block (fd, mtd_type, &blockstart);
+		if (rc < 0)		/* block test failed */
+			return -1;
+
+		if (blockstart + block_seek + readlen > top_of_range) {
+			/* End of range is reached */
+			fprintf (stderr,
+				 "Too few good blocks within range\n");
+			return -1;
+		}
+
+		if (rc) {		/* block is bad */
+			blockstart += blocklen;
+			continue;
+		}
+
+		/*
+		 * If a block is bad, we retry in the next block at the same
+		 * offset - see common/env_nand.c::writeenv()
+		 */
+		lseek (fd, blockstart + block_seek, SEEK_SET);
+
+		rc = read (fd, buf + processed, readlen);
+		if (rc != readlen) {
+			fprintf (stderr, "Read error on %s: %s\n",
+				 DEVNAME (dev), strerror (errno));
+			return -1;
+		}
+#ifdef DEBUG
+		fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
+			 rc, blockstart + block_seek, DEVNAME(dev));
+#endif
+		processed += readlen;
+		readlen = min (blocklen, count - processed);
+		block_seek = 0;
+		blockstart += blocklen;
+	}
+
+	return processed;
+}
+
+/*
+ * Write count bytes at offset, but stay within ENVSECTORS (dev) sectors of
+ * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we
+ * erase and write the whole data at once.
+ */
+static int flash_write_buf (int dev, int fd, void *buf, size_t count,
+			    off_t offset, uint8_t mtd_type)
+{
+	void *data;
+	struct erase_info_user erase;
+	size_t blocklen;	/* length of NAND block / NOR erase sector */
+	size_t erase_len;	/* whole area that can be erased - may include
+				   bad blocks */
+	size_t erasesize;	/* erase / write length - one block on NAND,
+				   whole area on NOR */
+	size_t processed = 0;	/* progress counter */
+	size_t write_total;	/* total size to actually write - excluding
+				   bad blocks */
+	off_t erase_offset;	/* offset to the first erase block (aligned)
+				   below offset */
+	off_t block_seek;	/* offset inside the erase block to the start
+				   of the data */
+	off_t top_of_range;	/* end of the last block we may use */
+	loff_t blockstart;	/* running start of the current block -
+				   MEMGETBADBLOCK needs 64 bits */
+	int rc;
+
+	/*
+	 * For mtd devices only offset and size of the environment do matter
+	 */
+	if (mtd_type == MTD_ABSENT) {
+		blocklen = count;
+		top_of_range = offset + count;
+		erase_len = blocklen;
+		blockstart = offset;
+		block_seek = 0;
+		write_total = blocklen;
+	} else {
+		blocklen = DEVESIZE(dev);
+
+		top_of_range = ((DEVOFFSET(dev) / blocklen) +
+					ENVSECTORS(dev)) * blocklen;
+
+		erase_offset = (offset / blocklen) * blocklen;
+
+		/* Maximum area we may use */
+		erase_len = top_of_range - erase_offset;
+
+		blockstart = erase_offset;
+		/* Offset inside a block */
+		block_seek = offset - erase_offset;
+
+		/*
+		 * Data size we actually write: from the start of the block
+		 * to the start of the data, then count bytes of data, and
+		 * to the end of the block
+		 */
+		write_total = ((block_seek + count + blocklen - 1) /
+							blocklen) * blocklen;
+	}
+
+	/*
+	 * Support data anywhere within erase sectors: read out the complete
+	 * area to be erased, replace the environment image, write the whole
+	 * block back again.
+	 */
+	if (write_total > count) {
+		data = malloc (erase_len);
+		if (!data) {
+			fprintf (stderr,
+				 "Cannot malloc %zu bytes: %s\n",
+				 erase_len, strerror (errno));
+			return -1;
+		}
+
+		rc = flash_read_buf (dev, fd, data, write_total, erase_offset,
+				     mtd_type);
+		if (write_total != rc)
+			return -1;
+
+#ifdef DEBUG
+		fprintf(stderr, "Preserving data ");
+		if (block_seek != 0)
+			fprintf(stderr, "0x%x - 0x%lx", 0, block_seek - 1);
+		if (block_seek + count != write_total) {
+			if (block_seek != 0)
+				fprintf(stderr, " and ");
+			fprintf(stderr, "0x%lx - 0x%x",
+				block_seek + count, write_total - 1);
+		}
+		fprintf(stderr, "\n");
+#endif
+		/* Overwrite the old environment */
+		memcpy (data + block_seek, buf, count);
+	} else {
+		/*
+		 * We get here, iff offset is block-aligned and count is a
+		 * multiple of blocklen - see write_total calculation above
+		 */
+		data = buf;
+	}
+
+	if (mtd_type == MTD_NANDFLASH) {
+		/*
+		 * NAND: calculate which blocks we are writing. We have
+		 * to write one block at a time to skip bad blocks.
+		 */
+		erasesize = blocklen;
+	} else {
+		erasesize = erase_len;
+	}
+
+	erase.length = erasesize;
+
+	/* This only runs once on NOR flash and SPI-dataflash */
+	while (processed < write_total) {
+		rc = flash_bad_block (fd, mtd_type, &blockstart);
+		if (rc < 0)		/* block test failed */
+			return rc;
+
+		if (blockstart + erasesize > top_of_range) {
+			fprintf (stderr, "End of range reached, aborting\n");
+			return -1;
+		}
+
+		if (rc) {		/* block is bad */
+			blockstart += blocklen;
+			continue;
+		}
+
+		if (mtd_type != MTD_ABSENT) {
+			erase.start = blockstart;
+			ioctl(fd, MEMUNLOCK, &erase);
+			/* These do not need an explicit erase cycle */
+			if (mtd_type != MTD_DATAFLASH)
+				if (ioctl(fd, MEMERASE, &erase) != 0) {
+					fprintf(stderr,
+						"MTD erase error on %s: %s\n",
+						DEVNAME(dev), strerror(errno));
+					return -1;
+				}
+		}
+
+		if (lseek (fd, blockstart, SEEK_SET) == -1) {
+			fprintf (stderr,
+				 "Seek error on %s: %s\n",
+				 DEVNAME (dev), strerror (errno));
+			return -1;
+		}
+
+#ifdef DEBUG
+		fprintf(stderr, "Write 0x%x bytes at 0x%llx\n", erasesize,
+			blockstart);
+#endif
+		if (write (fd, data + processed, erasesize) != erasesize) {
+			fprintf (stderr, "Write error on %s: %s\n",
+				 DEVNAME (dev), strerror (errno));
+			return -1;
+		}
+
+		if (mtd_type != MTD_ABSENT)
+			ioctl(fd, MEMLOCK, &erase);
+
+		processed  += blocklen;
+		block_seek = 0;
+		blockstart += blocklen;
+	}
+
+	if (write_total > count)
+		free (data);
+
+	return processed;
+}
+
+/*
+ * Set obsolete flag at offset - NOR flash only
+ */
+static int flash_flag_obsolete (int dev, int fd, off_t offset)
+{
+	int rc;
+	struct erase_info_user erase;
+
+	erase.start  = DEVOFFSET (dev);
+	erase.length = DEVESIZE (dev);
+	/* This relies on the fact, that obsolete_flag == 0 */
+	rc = lseek (fd, offset, SEEK_SET);
+	if (rc < 0) {
+		fprintf (stderr, "Cannot seek to set the flag on %s \n",
+			 DEVNAME (dev));
+		return rc;
+	}
+	ioctl (fd, MEMUNLOCK, &erase);
+	rc = write (fd, &obsolete_flag, sizeof (obsolete_flag));
+	ioctl (fd, MEMLOCK, &erase);
+	if (rc < 0)
+		perror ("Could not set obsolete flag");
+
+	return rc;
+}
+
+static int flash_write (int fd_current, int fd_target, int dev_target)
+{
+	int rc;
+
+	switch (environment.flag_scheme) {
+	case FLAG_NONE:
+		break;
+	case FLAG_INCREMENTAL:
+		(*environment.flags)++;
+		break;
+	case FLAG_BOOLEAN:
+		*environment.flags = active_flag;
+		break;
+	default:
+		fprintf (stderr, "Unimplemented flash scheme %u \n",
+			 environment.flag_scheme);
+		return -1;
+	}
+
+#ifdef DEBUG
+	fprintf(stderr, "Writing new environment at 0x%lx on %s\n",
+		DEVOFFSET (dev_target), DEVNAME (dev_target));
+#endif
+	rc = flash_write_buf(dev_target, fd_target, environment.image,
+			      CUR_ENVSIZE, DEVOFFSET(dev_target),
+			      DEVTYPE(dev_target));
+	if (rc < 0)
+		return rc;
+
+	if (environment.flag_scheme == FLAG_BOOLEAN) {
+		/* Have to set obsolete flag */
+		off_t offset = DEVOFFSET (dev_current) +
+			offsetof (struct env_image_redundant, flags);
+#ifdef DEBUG
+		fprintf(stderr,
+			"Setting obsolete flag in environment at 0x%lx on %s\n",
+			DEVOFFSET (dev_current), DEVNAME (dev_current));
+#endif
+		flash_flag_obsolete (dev_current, fd_current, offset);
+	}
+
+	return 0;
+}
+
+static int flash_read (int fd)
+{
+	struct mtd_info_user mtdinfo;
+	struct stat st;
+	int rc;
+
+	rc = fstat(fd, &st);
+	if (rc < 0) {
+		fprintf(stderr, "Cannot stat the file %s\n",
+			DEVNAME(dev_current));
+		return -1;
+	}
+
+	if (S_ISCHR(st.st_mode)) {
+		rc = ioctl(fd, MEMGETINFO, &mtdinfo);
+		if (rc < 0) {
+			fprintf(stderr, "Cannot get MTD information for %s\n",
+				DEVNAME(dev_current));
+			return -1;
+		}
+		if (mtdinfo.type != MTD_NORFLASH &&
+		    mtdinfo.type != MTD_NANDFLASH &&
+		    mtdinfo.type != MTD_DATAFLASH &&
+		    mtdinfo.type != MTD_UBIVOLUME) {
+			fprintf (stderr, "Unsupported flash type %u on %s\n",
+				 mtdinfo.type, DEVNAME(dev_current));
+			return -1;
+		}
+	} else {
+		memset(&mtdinfo, 0, sizeof(mtdinfo));
+		mtdinfo.type = MTD_ABSENT;
+	}
+
+	DEVTYPE(dev_current) = mtdinfo.type;
+
+	rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE,
+			     DEVOFFSET (dev_current), mtdinfo.type);
+
+	return (rc != CUR_ENVSIZE) ? -1 : 0;
+}
+
+static int flash_io (int mode)
+{
+	int fd_current, fd_target, rc, dev_target;
+
+	/* dev_current: fd_current, erase_current */
+	fd_current = open (DEVNAME (dev_current), mode);
+	if (fd_current < 0) {
+		fprintf (stderr,
+			 "Can't open %s: %s\n",
+			 DEVNAME (dev_current), strerror (errno));
+		return -1;
+	}
+
+	if (mode == O_RDWR) {
+		if (HaveRedundEnv) {
+			/* switch to next partition for writing */
+			dev_target = !dev_current;
+			/* dev_target: fd_target, erase_target */
+			fd_target = open (DEVNAME (dev_target), mode);
+			if (fd_target < 0) {
+				fprintf (stderr,
+					 "Can't open %s: %s\n",
+					 DEVNAME (dev_target),
+					 strerror (errno));
+				rc = -1;
+				goto exit;
+			}
+		} else {
+			dev_target = dev_current;
+			fd_target = fd_current;
+		}
+
+		rc = flash_write (fd_current, fd_target, dev_target);
+
+		if (HaveRedundEnv) {
+			if (close (fd_target)) {
+				fprintf (stderr,
+					"I/O error on %s: %s\n",
+					DEVNAME (dev_target),
+					strerror (errno));
+				rc = -1;
+			}
+		}
+	} else {
+		rc = flash_read (fd_current);
+	}
+
+exit:
+	if (close (fd_current)) {
+		fprintf (stderr,
+			 "I/O error on %s: %s\n",
+			 DEVNAME (dev_current), strerror (errno));
+		return -1;
+	}
+
+	return rc;
+}
+
+/*
+ * s1 is either a simple 'name', or a 'name=value' pair.
+ * s2 is a 'name=value' pair.
+ * If the names match, return the value of s2, else NULL.
+ */
+
+static char *envmatch (char * s1, char * s2)
+{
+	if (s1 == NULL || s2 == NULL)
+		return NULL;
+
+	while (*s1 == *s2++)
+		if (*s1++ == '=')
+			return s2;
+	if (*s1 == '\0' && *(s2 - 1) == '=')
+		return s2;
+	return NULL;
+}
+
+/*
+ * Prevent confusion if running from erased flash memory
+ */
+int fw_env_open(void)
+{
+	int crc0, crc0_ok;
+	unsigned char flag0;
+	void *addr0;
+
+	int crc1, crc1_ok;
+	unsigned char flag1;
+	void *addr1;
+
+	struct env_image_single *single;
+	struct env_image_redundant *redundant;
+
+	if (parse_config ())		/* should fill envdevices */
+		return -1;
+
+	addr0 = calloc(1, CUR_ENVSIZE);
+	if (addr0 == NULL) {
+		fprintf(stderr,
+			"Not enough memory for environment (%ld bytes)\n",
+			CUR_ENVSIZE);
+		return -1;
+	}
+
+	/* read environment from FLASH to local buffer */
+	environment.image = addr0;
+
+	if (HaveRedundEnv) {
+		redundant = addr0;
+		environment.crc		= &redundant->crc;
+		environment.flags	= &redundant->flags;
+		environment.data	= redundant->data;
+	} else {
+		single = addr0;
+		environment.crc		= &single->crc;
+		environment.flags	= NULL;
+		environment.data	= single->data;
+	}
+
+	dev_current = 0;
+	if (flash_io (O_RDONLY))
+		return -1;
+
+	crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
+	crc0_ok = (crc0 == *environment.crc);
+	if (!HaveRedundEnv) {
+		if (!crc0_ok) {
+			fprintf (stderr,
+				"Warning: Bad CRC, using default environment\n");
+			memcpy(environment.data, default_environment, sizeof default_environment);
+		}
+	} else {
+		flag0 = *environment.flags;
+
+		dev_current = 1;
+		addr1 = calloc(1, CUR_ENVSIZE);
+		if (addr1 == NULL) {
+			fprintf(stderr,
+				"Not enough memory for environment (%ld bytes)\n",
+				CUR_ENVSIZE);
+			return -1;
+		}
+		redundant = addr1;
+
+		/*
+		 * have to set environment.image for flash_read(), careful -
+		 * other pointers in environment still point inside addr0
+		 */
+		environment.image = addr1;
+		if (flash_io (O_RDONLY))
+			return -1;
+
+		/* Check flag scheme compatibility */
+		if (DEVTYPE(dev_current) == MTD_NORFLASH &&
+		    DEVTYPE(!dev_current) == MTD_NORFLASH) {
+			environment.flag_scheme = FLAG_BOOLEAN;
+		} else if (DEVTYPE(dev_current) == MTD_NANDFLASH &&
+			   DEVTYPE(!dev_current) == MTD_NANDFLASH) {
+			environment.flag_scheme = FLAG_INCREMENTAL;
+		} else if (DEVTYPE(dev_current) == MTD_DATAFLASH &&
+			   DEVTYPE(!dev_current) == MTD_DATAFLASH) {
+			environment.flag_scheme = FLAG_BOOLEAN;
+		} else if (DEVTYPE(dev_current) == MTD_UBIVOLUME &&
+			   DEVTYPE(!dev_current) == MTD_UBIVOLUME) {
+			environment.flag_scheme = FLAG_INCREMENTAL;
+		} else if (DEVTYPE(dev_current) == MTD_ABSENT &&
+			   DEVTYPE(!dev_current) == MTD_ABSENT) {
+			environment.flag_scheme = FLAG_INCREMENTAL;
+		} else {
+			fprintf (stderr, "Incompatible flash types!\n");
+			return -1;
+		}
+
+		crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
+		crc1_ok = (crc1 == redundant->crc);
+		flag1 = redundant->flags;
+
+		if (crc0_ok && !crc1_ok) {
+			dev_current = 0;
+		} else if (!crc0_ok && crc1_ok) {
+			dev_current = 1;
+		} else if (!crc0_ok && !crc1_ok) {
+			fprintf (stderr,
+				"Warning: Bad CRC, using default environment\n");
+			memcpy (environment.data, default_environment,
+				sizeof default_environment);
+			dev_current = 0;
+		} else {
+			switch (environment.flag_scheme) {
+			case FLAG_BOOLEAN:
+				if (flag0 == active_flag &&
+				    flag1 == obsolete_flag) {
+					dev_current = 0;
+				} else if (flag0 == obsolete_flag &&
+					   flag1 == active_flag) {
+					dev_current = 1;
+				} else if (flag0 == flag1) {
+					dev_current = 0;
+				} else if (flag0 == 0xFF) {
+					dev_current = 0;
+				} else if (flag1 == 0xFF) {
+					dev_current = 1;
+				} else {
+					dev_current = 0;
+				}
+				break;
+			case FLAG_INCREMENTAL:
+				if (flag0 == 255 && flag1 == 0)
+					dev_current = 1;
+				else if ((flag1 == 255 && flag0 == 0) ||
+					 flag0 >= flag1)
+					dev_current = 0;
+				else /* flag1 > flag0 */
+					dev_current = 1;
+				break;
+			default:
+				fprintf (stderr, "Unknown flag scheme %u \n",
+					 environment.flag_scheme);
+				return -1;
+			}
+		}
+
+		/*
+		 * If we are reading, we don't need the flag and the CRC any
+		 * more, if we are writing, we will re-calculate CRC and update
+		 * flags before writing out
+		 */
+		if (dev_current) {
+			environment.image	= addr1;
+			environment.crc		= &redundant->crc;
+			environment.flags	= &redundant->flags;
+			environment.data	= redundant->data;
+			free (addr0);
+		} else {
+			environment.image	= addr0;
+			/* Other pointers are already set */
+			free (addr1);
+		}
+#ifdef DEBUG
+		fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current));
+#endif
+	}
+	return 0;
+}
+
+
+static int parse_config ()
+{
+	struct stat st;
+
+#if defined(CONFIG_FILE)
+	/* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */
+	if (get_config (CONFIG_FILE)) {
+		fprintf (stderr,
+			"Cannot parse config file: %s\n", strerror (errno));
+		return -1;
+	}
+#else
+	strcpy (DEVNAME (0), DEVICE1_NAME);
+	DEVOFFSET (0) = DEVICE1_OFFSET;
+	ENVSIZE (0) = ENV1_SIZE;
+	/* Default values are: erase-size=env-size, #sectors=1 */
+	DEVESIZE (0) = ENVSIZE (0);
+	ENVSECTORS (0) = 1;
+#ifdef DEVICE1_ESIZE
+	DEVESIZE (0) = DEVICE1_ESIZE;
+#endif
+#ifdef DEVICE1_ENVSECTORS
+	ENVSECTORS (0) = DEVICE1_ENVSECTORS;
+#endif
+
+#ifdef HAVE_REDUND
+	strcpy (DEVNAME (1), DEVICE2_NAME);
+	DEVOFFSET (1) = DEVICE2_OFFSET;
+	ENVSIZE (1) = ENV2_SIZE;
+	/* Default values are: erase-size=env-size, #sectors=1 */
+	DEVESIZE (1) = ENVSIZE (1);
+	ENVSECTORS (1) = 1;
+#ifdef DEVICE2_ESIZE
+	DEVESIZE (1) = DEVICE2_ESIZE;
+#endif
+#ifdef DEVICE2_ENVSECTORS
+	ENVSECTORS (1) = DEVICE2_ENVSECTORS;
+#endif
+	HaveRedundEnv = 1;
+#endif
+#endif
+	if (stat (DEVNAME (0), &st)) {
+		fprintf (stderr,
+			"Cannot access MTD device %s: %s\n",
+			DEVNAME (0), strerror (errno));
+		return -1;
+	}
+
+	if (HaveRedundEnv && stat (DEVNAME (1), &st)) {
+		fprintf (stderr,
+			"Cannot access MTD device %s: %s\n",
+			DEVNAME (1), strerror (errno));
+		return -1;
+	}
+	return 0;
+}
+
+#if defined(CONFIG_FILE)
+static int get_config (char *fname)
+{
+	FILE *fp;
+	int i = 0;
+	int rc;
+	char dump[128];
+
+	fp = fopen (fname, "r");
+	if (fp == NULL)
+		return -1;
+
+	while (i < 2 && fgets (dump, sizeof (dump), fp)) {
+		/* Skip incomplete conversions and comment strings */
+		if (dump[0] == '#')
+			continue;
+
+		rc = sscanf (dump, "%s %lx %lx %lx %lx",
+			     DEVNAME (i),
+			     &DEVOFFSET (i),
+			     &ENVSIZE (i),
+			     &DEVESIZE (i),
+			     &ENVSECTORS (i));
+
+		if (rc < 3)
+			continue;
+
+		if (rc < 4)
+			/* Assume the erase size is the same as the env-size */
+			DEVESIZE(i) = ENVSIZE(i);
+
+		if (rc < 5)
+			/* Default - 1 sector */
+			ENVSECTORS (i) = 1;
+
+		i++;
+	}
+	fclose (fp);
+
+	HaveRedundEnv = i - 1;
+	if (!i) {			/* No valid entries found */
+		errno = EINVAL;
+		return -1;
+	} else
+		return 0;
+}
+#endif
diff --git a/marvell/uboot/tools/env/fw_env.config b/marvell/uboot/tools/env/fw_env.config
new file mode 100644
index 0000000..90e499d
--- /dev/null
+++ b/marvell/uboot/tools/env/fw_env.config
@@ -0,0 +1,22 @@
+# Configuration file for fw_(printenv/setenv) utility.
+# Up to two entries are valid, in this case the redundant
+# environment sector is assumed present.
+# Notice, that the "Number of sectors" is ignored on NOR and SPI-dataflash.
+# Futhermore, if the Flash sector size is ommitted, this value is assumed to
+# be the same as the Environment size, which is valid for NOR and SPI-dataflash
+
+# NOR example
+# MTD device name	Device offset	Env. size	Flash sector size	Number of sectors
+/dev/mtd1		0x0000		0x4000		0x4000
+/dev/mtd2		0x0000		0x4000		0x4000
+
+# MTD SPI-dataflash example
+# MTD device name	Device offset	Env. size	Flash sector size	Number of sectors
+#/dev/mtd5		0x4200		0x4200
+#/dev/mtd6		0x4200		0x4200
+
+# NAND example
+#/dev/mtd0		0x4000		0x4000		0x20000			2
+
+# Block device example
+#/dev/mmcblk0		0xc0000		0x20000
diff --git a/marvell/uboot/tools/env/fw_env.h b/marvell/uboot/tools/env/fw_env.h
new file mode 100644
index 0000000..aff471b
--- /dev/null
+++ b/marvell/uboot/tools/env/fw_env.h
@@ -0,0 +1,63 @@
+/*
+ * (C) Copyright 2002-2008
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* Pull in the current config to define the default environment */
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__ /* get only #defines from config.h */
+#include <config.h>
+#undef	__ASSEMBLY__
+#else
+#include <config.h>
+#endif
+
+/*
+ * To build the utility with the static configuration
+ * comment out the next line.
+ * See included "fw_env.config" sample file
+ * for notes on configuration.
+ */
+#define CONFIG_FILE     "/etc/fw_env.config"
+
+#ifndef CONFIG_FILE
+#define HAVE_REDUND /* For systems with 2 env sectors */
+#define DEVICE1_NAME      "/dev/mtd1"
+#define DEVICE2_NAME      "/dev/mtd2"
+#define DEVICE1_OFFSET    0x0000
+#define ENV1_SIZE         0x4000
+#define DEVICE1_ESIZE     0x4000
+#define DEVICE1_ENVSECTORS     2
+#define DEVICE2_OFFSET    0x0000
+#define ENV2_SIZE         0x4000
+#define DEVICE2_ESIZE     0x4000
+#define DEVICE2_ENVSECTORS     2
+#endif
+
+#ifndef CONFIG_BAUDRATE
+#define CONFIG_BAUDRATE		115200
+#endif
+
+#ifndef CONFIG_BOOTDELAY
+#define CONFIG_BOOTDELAY	5	/* autoboot after 5 seconds	*/
+#endif
+
+#ifndef CONFIG_BOOTCOMMAND
+#define CONFIG_BOOTCOMMAND							\
+	"bootp; "								\
+	"setenv bootargs root=/dev/nfs nfsroot=${serverip}:${rootpath} "	\
+	"ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off; "	\
+	"bootm"
+#endif
+
+extern int   fw_printenv(int argc, char *argv[]);
+extern char *fw_getenv  (char *name);
+extern int fw_setenv  (int argc, char *argv[]);
+extern int fw_parse_script(char *fname);
+extern int fw_env_open(void);
+extern int fw_env_write(char *name, char *value);
+extern int fw_env_close(void);
+
+extern unsigned	long  crc32	 (unsigned long, const unsigned char *, unsigned);
diff --git a/marvell/uboot/tools/env/fw_env_main.c b/marvell/uboot/tools/env/fw_env_main.c
new file mode 100644
index 0000000..2b85d78
--- /dev/null
+++ b/marvell/uboot/tools/env/fw_env_main.c
@@ -0,0 +1,140 @@
+/*
+ * (C) Copyright 2000-2008
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Command line user interface to firmware (=U-Boot) environment.
+ *
+ * Implements:
+ *	fw_printenv [[ -n name ] | [ name ... ]]
+ *              - prints the value of a single environment variable
+ *                "name", the ``name=value'' pairs of one or more
+ *                environment variables "name", or the whole
+ *                environment if no names are specified.
+ *	fw_setenv name [ value ... ]
+ *		- If a name without any values is given, the variable
+ *		  with this name is deleted from the environment;
+ *		  otherwise, all "value" arguments are concatenated,
+ *		  separated by single blank characters, and the
+ *		  resulting string is assigned to the environment
+ *		  variable "name"
+ */
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <unistd.h>
+#include "fw_env.h"
+
+#define	CMD_PRINTENV	"fw_printenv"
+#define CMD_SETENV	"fw_setenv"
+
+static struct option long_options[] = {
+	{"script", required_argument, NULL, 's'},
+	{"help", no_argument, NULL, 'h'},
+	{NULL, 0, NULL, 0}
+};
+
+void usage(void)
+{
+
+	fprintf(stderr, "fw_printenv/fw_setenv, "
+		"a command line interface to U-Boot environment\n\n"
+		"usage:\tfw_printenv [-n] [variable name]\n"
+		"\tfw_setenv [variable name] [variable value]\n"
+		"\tfw_setenv -s [ file ]\n"
+		"\tfw_setenv -s - < [ file ]\n\n"
+		"The file passed as argument contains only pairs "
+		"name / value\n"
+		"Example:\n"
+		"# Any line starting with # is treated as comment\n"
+		"\n"
+		"\t      netdev         eth0\n"
+		"\t      kernel_addr    400000\n"
+		"\t      var1\n"
+		"\t      var2          The quick brown fox jumps over the "
+		"lazy dog\n"
+		"\n"
+		"A variable without value will be dropped. It is possible\n"
+		"to put any number of spaces between the fields, but any\n"
+		"space inside the value is treated as part of the value "
+		"itself.\n\n"
+	);
+}
+
+int main(int argc, char *argv[])
+{
+	char *p;
+	char *cmdname = *argv;
+	char *script_file = NULL;
+	int c;
+	const char *lockname = "/var/lock/" CMD_PRINTENV ".lock";
+	int lockfd = -1;
+	int retval = EXIT_SUCCESS;
+
+	lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+	if (-1 == lockfd) {
+		fprintf(stderr, "Error opening lock file %s\n", lockname);
+		return EXIT_FAILURE;
+	}
+
+	if (-1 == flock(lockfd, LOCK_EX)) {
+		fprintf(stderr, "Error locking file %s\n", lockname);
+		close(lockfd);
+		return EXIT_FAILURE;
+	}
+
+	if ((p = strrchr (cmdname, '/')) != NULL) {
+		cmdname = p + 1;
+	}
+
+	while ((c = getopt_long (argc, argv, "ns:h",
+		long_options, NULL)) != EOF) {
+		switch (c) {
+		case 'n':
+			/* handled in fw_printenv */
+			break;
+		case 's':
+			script_file = optarg;
+			break;
+		case 'h':
+			usage();
+			goto exit;
+		default: /* '?' */
+			fprintf(stderr, "Try `%s --help' for more information."
+				"\n", cmdname);
+			retval = EXIT_FAILURE;
+			goto exit;
+		}
+	}
+
+	if (strcmp(cmdname, CMD_PRINTENV) == 0) {
+		if (fw_printenv(argc, argv) != 0)
+			retval = EXIT_FAILURE;
+	} else if (strcmp(cmdname, CMD_SETENV) == 0) {
+		if (!script_file) {
+			if (fw_setenv(argc, argv) != 0)
+				retval = EXIT_FAILURE;
+		} else {
+			if (fw_parse_script(script_file) != 0)
+				retval = EXIT_FAILURE;
+		}
+	} else {
+		fprintf(stderr,
+			"Identity crisis - may be called as `" CMD_PRINTENV
+			"' or as `" CMD_SETENV "' but not as `%s'\n",
+			cmdname);
+		retval = EXIT_FAILURE;
+	}
+
+exit:
+	flock(lockfd, LOCK_UN);
+	close(lockfd);
+	return retval;
+}
diff --git a/marvell/uboot/tools/envcrc.c b/marvell/uboot/tools/envcrc.c
new file mode 100644
index 0000000..a9d9b48
--- /dev/null
+++ b/marvell/uboot/tools/envcrc.c
@@ -0,0 +1,129 @@
+/*
+ * (C) Copyright 2001
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef __ASSEMBLY__
+#define	__ASSEMBLY__			/* Dirty trick to get only #defines	*/
+#endif
+#define	__ASM_STUB_PROCESSOR_H__	/* don't include asm/processor.		*/
+#include <config.h>
+#undef	__ASSEMBLY__
+
+#if defined(CONFIG_ENV_IS_IN_FLASH)
+# ifndef  CONFIG_ENV_ADDR
+#  define CONFIG_ENV_ADDR	(CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
+# endif
+# ifndef  CONFIG_ENV_OFFSET
+#  define CONFIG_ENV_OFFSET (CONFIG_ENV_ADDR - CONFIG_SYS_FLASH_BASE)
+# endif
+# if !defined(CONFIG_ENV_ADDR_REDUND) && defined(CONFIG_ENV_OFFSET_REDUND)
+#  define CONFIG_ENV_ADDR_REDUND	(CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET_REDUND)
+# endif
+# ifndef  CONFIG_ENV_SIZE
+#  define CONFIG_ENV_SIZE	CONFIG_ENV_SECT_SIZE
+# endif
+# if defined(CONFIG_ENV_ADDR_REDUND) && !defined(CONFIG_ENV_SIZE_REDUND)
+#  define CONFIG_ENV_SIZE_REDUND	CONFIG_ENV_SIZE
+# endif
+# if (CONFIG_ENV_ADDR >= CONFIG_SYS_MONITOR_BASE) && \
+     ((CONFIG_ENV_ADDR + CONFIG_ENV_SIZE) <= (CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN))
+#  define ENV_IS_EMBEDDED
+# endif
+# if defined(CONFIG_ENV_ADDR_REDUND) || defined(CONFIG_ENV_OFFSET_REDUND)
+#  define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+# endif
+#endif	/* CONFIG_ENV_IS_IN_FLASH */
+
+#if defined(ENV_IS_EMBEDDED) && !defined(CONFIG_BUILD_ENVCRC)
+# define CONFIG_BUILD_ENVCRC
+#endif
+
+#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
+# define ENV_HEADER_SIZE	(sizeof(uint32_t) + 1)
+#else
+# define ENV_HEADER_SIZE	(sizeof(uint32_t))
+#endif
+
+#define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE)
+
+
+#ifdef CONFIG_BUILD_ENVCRC
+# include <environment.h>
+extern unsigned int env_size;
+extern env_t environment;
+#endif	/* CONFIG_BUILD_ENVCRC */
+
+extern uint32_t crc32 (uint32_t, const unsigned char *, unsigned int);
+
+int main (int argc, char **argv)
+{
+#ifdef CONFIG_BUILD_ENVCRC
+	unsigned char pad = 0x00;
+	uint32_t crc;
+	unsigned char *envptr = (unsigned char *)&environment,
+		*dataptr = envptr + ENV_HEADER_SIZE;
+	unsigned int datasize = ENV_SIZE;
+	unsigned int eoe;
+
+	if (argv[1] && !strncmp(argv[1], "--binary", 8)) {
+		int ipad = 0xff;
+		if (argv[1][8] == '=')
+			sscanf(argv[1] + 9, "%i", &ipad);
+		pad = ipad;
+	}
+
+	if (pad) {
+		/* find the end of env */
+		for (eoe = 0; eoe < datasize - 1; ++eoe)
+			if (!dataptr[eoe] && !dataptr[eoe+1]) {
+				eoe += 2;
+				break;
+			}
+		if (eoe < datasize - 1)
+			memset(dataptr + eoe, pad, datasize - eoe);
+	}
+
+	crc = crc32 (0, dataptr, datasize);
+
+	/* Check if verbose mode is activated passing a parameter to the program */
+	if (argc > 1) {
+		if (!strncmp(argv[1], "--binary", 8)) {
+			int le = (argc > 2 ? !strcmp(argv[2], "le") : 1);
+			size_t i, start, end, step;
+			if (le) {
+				start = 0;
+				end = ENV_HEADER_SIZE;
+				step = 1;
+			} else {
+				start = ENV_HEADER_SIZE - 1;
+				end = -1;
+				step = -1;
+			}
+			for (i = start; i != end; i += step)
+				printf("%c", (crc & (0xFF << (i * 8))) >> (i * 8));
+			if (fwrite(dataptr, 1, datasize, stdout) != datasize)
+				fprintf(stderr, "fwrite() failed: %s\n", strerror(errno));
+		} else {
+			printf("CRC32 from offset %08X to %08X of environment = %08X\n",
+				(unsigned int) (dataptr - envptr),
+				(unsigned int) (dataptr - envptr) + datasize,
+				crc);
+		}
+	} else {
+		printf ("0x%08X\n", crc);
+	}
+#else
+	printf ("0\n");
+#endif
+	return EXIT_SUCCESS;
+}
diff --git a/marvell/uboot/tools/fdt_host.h b/marvell/uboot/tools/fdt_host.h
new file mode 100644
index 0000000..c2b23c6
--- /dev/null
+++ b/marvell/uboot/tools/fdt_host.h
@@ -0,0 +1,14 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __FDT_HOST_H__
+#define __FDT_HOST_H__
+
+/* Make sure to include u-boot version of libfdt include files */
+#include "../include/libfdt.h"
+#include "../include/fdt_support.h"
+
+#endif /* __FDT_HOST_H__ */
diff --git a/marvell/uboot/tools/fit_image.c b/marvell/uboot/tools/fit_image.c
new file mode 100644
index 0000000..1466164
--- /dev/null
+++ b/marvell/uboot/tools/fit_image.c
@@ -0,0 +1,210 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2004
+ * DENX Software Engineering
+ * Wolfgang Denk, wd@denx.de
+ *
+ * Updated-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *		FIT image specific code abstracted from mkimage.c
+ *		some functions added to address abstraction
+ *
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "imagetool.h"
+#include "mkimage.h"
+#include <image.h>
+#include <u-boot/crc.h>
+
+static image_header_t header;
+
+static int fit_verify_header (unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	return fdt_check_header(ptr);
+}
+
+static int fit_check_image_types (uint8_t type)
+{
+	if (type == IH_TYPE_FLATDT)
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+}
+
+int mmap_fdt(struct image_tool_params *params, const char *fname, void **blobp,
+		struct stat *sbuf)
+{
+	void *ptr;
+	int fd;
+
+	/* Load FIT blob into memory (we need to write hashes/signatures) */
+	fd = open(fname, O_RDWR | O_BINARY);
+
+	if (fd < 0) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			params->cmdname, fname, strerror(errno));
+		unlink(fname);
+		return -1;
+	}
+
+	if (fstat(fd, sbuf) < 0) {
+		fprintf(stderr, "%s: Can't stat %s: %s\n",
+			params->cmdname, fname, strerror(errno));
+		unlink(fname);
+		return -1;
+	}
+
+	ptr = mmap(0, sbuf->st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "%s: Can't read %s: %s\n",
+			params->cmdname, fname, strerror(errno));
+		unlink(fname);
+		return -1;
+	}
+
+	/* check if ptr has a valid blob */
+	if (fdt_check_header(ptr)) {
+		fprintf(stderr, "%s: Invalid FIT blob\n", params->cmdname);
+		unlink(fname);
+		return -1;
+	}
+
+	*blobp = ptr;
+	return fd;
+}
+
+/**
+ * fit_handle_file - main FIT file processing function
+ *
+ * fit_handle_file() runs dtc to convert .its to .itb, includes
+ * binary data, updates timestamp property and calculates hashes.
+ *
+ * datafile  - .its file
+ * imagefile - .itb file
+ *
+ * returns:
+ *     only on success, otherwise calls exit (EXIT_FAILURE);
+ */
+static int fit_handle_file(struct image_tool_params *params)
+{
+	char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
+	char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
+	int tfd, destfd = 0;
+	void *dest_blob = NULL;
+	struct stat sbuf;
+	void *ptr;
+	off_t destfd_size = 0;
+
+	/* Flattened Image Tree (FIT) format  handling */
+	debug ("FIT format handling\n");
+
+	/* call dtc to include binary properties into the tmp file */
+	if (strlen (params->imagefile) +
+		strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > sizeof (tmpfile)) {
+		fprintf (stderr, "%s: Image file name (%s) too long, "
+				"can't create tmpfile",
+				params->imagefile, params->cmdname);
+		return (EXIT_FAILURE);
+	}
+	sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);
+
+	/* We either compile the source file, or use the existing FIT image */
+	if (params->datafile) {
+		/* dtc -I dts -O dtb -p 500 datafile > tmpfile */
+		snprintf(cmd, sizeof(cmd), "%s %s %s > %s",
+			 MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
+		debug("Trying to execute \"%s\"\n", cmd);
+	} else {
+		snprintf(cmd, sizeof(cmd), "cp %s %s",
+			 params->imagefile, tmpfile);
+	}
+	if (system (cmd) == -1) {
+		fprintf (stderr, "%s: system(%s) failed: %s\n",
+				params->cmdname, cmd, strerror(errno));
+		goto err_system;
+	}
+
+	if (params->keydest) {
+		destfd = mmap_fdt(params, params->keydest, &dest_blob, &sbuf);
+		if (destfd < 0)
+			goto err_keydest;
+		destfd_size = sbuf.st_size;
+	}
+
+	tfd = mmap_fdt(params, tmpfile, &ptr, &sbuf);
+	if (tfd < 0)
+		goto err_mmap;
+
+	/* set hashes for images in the blob */
+	if (fit_add_verification_data(params->keydir,
+				      dest_blob, ptr, params->comment,
+				      params->require_keys)) {
+		fprintf(stderr, "%s Can't add hashes to FIT blob\n",
+			params->cmdname);
+		goto err_add_hashes;
+	}
+
+	/* for first image creation, add a timestamp at offset 0 i.e., root  */
+	if (params->datafile && fit_set_timestamp(ptr, 0, sbuf.st_mtime)) {
+		fprintf (stderr, "%s: Can't add image timestamp\n",
+				params->cmdname);
+		goto err_add_timestamp;
+	}
+	debug ("Added timestamp successfully\n");
+
+	munmap ((void *)ptr, sbuf.st_size);
+	close (tfd);
+	if (dest_blob) {
+		munmap(dest_blob, destfd_size);
+		close(destfd);
+	}
+
+	if (rename (tmpfile, params->imagefile) == -1) {
+		fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
+				params->cmdname, tmpfile, params->imagefile,
+				strerror (errno));
+		unlink (tmpfile);
+		unlink (params->imagefile);
+		return (EXIT_FAILURE);
+	}
+	return (EXIT_SUCCESS);
+
+err_add_timestamp:
+err_add_hashes:
+	munmap(ptr, sbuf.st_size);
+err_mmap:
+	if (dest_blob)
+		munmap(dest_blob, destfd_size);
+err_keydest:
+err_system:
+	unlink(tmpfile);
+	return -1;
+}
+
+static int fit_check_params(struct image_tool_params *params)
+{
+	return	((params->dflag && (params->fflag || params->lflag)) ||
+		(params->fflag && (params->dflag || params->lflag)) ||
+		(params->lflag && (params->dflag || params->fflag)));
+}
+
+static struct image_type_params fitimage_params = {
+	.name = "FIT Image support",
+	.header_size = sizeof(image_header_t),
+	.hdr = (void*)&header,
+	.verify_header = fit_verify_header,
+	.print_header = fit_print_contents,
+	.check_image_type = fit_check_image_types,
+	.fflag_handle = fit_handle_file,
+	.set_header = NULL,	/* FIT images use DTB header */
+	.check_params = fit_check_params,
+};
+
+void init_fit_image_type (void)
+{
+	register_image_type(&fitimage_params);
+}
diff --git a/marvell/uboot/tools/gdb/Makefile b/marvell/uboot/tools/gdb/Makefile
new file mode 100644
index 0000000..dd98fb6
--- /dev/null
+++ b/marvell/uboot/tools/gdb/Makefile
@@ -0,0 +1,56 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2000
+# Murray Jensen <Murray.Jensen@csiro.au>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+BINS	= gdbsend gdbcont
+
+COBJS	= gdbsend.o gdbcont.o error.o remote.o serial.o
+
+HOSTOBJS := $(addprefix $(obj),$(COBJS))
+HOSTSRCS := $(COBJS:.o=.c)
+BINS	:= $(addprefix $(obj),$(BINS))
+
+#
+# Use native tools and options
+#
+HOSTCPPFLAGS = -I$(BFD_ROOT_DIR)/include
+
+ifeq ($(HOSTOS),cygwin)
+
+all:
+$(obj).depend:
+
+else	# ! CYGWIN
+
+all:	$(obj).depend $(BINS)
+
+$(obj)gdbsend:	$(obj)gdbsend.o $(obj)error.o $(obj)remote.o $(obj)serial.o
+		$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+
+$(obj)gdbcont:	$(obj)gdbcont.o $(obj)error.o $(obj)remote.o $(obj)serial.o
+		$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+
+clean:
+	rm -f $(HOSTOBJS)
+
+distclean:	clean
+	rm -f $(BINS) $(obj)core $(obj)*.bak $(obj).depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
+
+endif	# cygwin
diff --git a/marvell/uboot/tools/gdb/error.c b/marvell/uboot/tools/gdb/error.c
new file mode 100644
index 0000000..4c32ce5
--- /dev/null
+++ b/marvell/uboot/tools/gdb/error.c
@@ -0,0 +1,65 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "error.h"
+
+char *pname;
+
+void
+Warning(char *fmt, ...)
+{
+    va_list args;
+
+    fprintf(stderr, "%s: WARNING: ", pname);
+
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+
+    fprintf(stderr, "\n");
+}
+
+void
+Error(char *fmt, ...)
+{
+    va_list args;
+
+    fprintf(stderr, "%s: ERROR: ", pname);
+
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+
+    fprintf(stderr, "\n");
+
+    exit(1);
+}
+
+void
+Perror(char *fmt, ...)
+{
+    va_list args;
+    int e = errno;
+    char *p;
+
+    fprintf(stderr, "%s: ERROR: ", pname);
+
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+
+    if ((p = strerror(e)) == NULL || *p == '\0')
+	fprintf(stderr, ": Unknown Error (%d)\n", e);
+    else
+	fprintf(stderr, ": %s\n", p);
+
+    exit(1);
+}
diff --git a/marvell/uboot/tools/gdb/error.h b/marvell/uboot/tools/gdb/error.h
new file mode 100644
index 0000000..fdadaac
--- /dev/null
+++ b/marvell/uboot/tools/gdb/error.h
@@ -0,0 +1,14 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <stdarg.h>
+
+extern char *pname;
+
+extern void Warning(char *, ...);
+extern void Error(char *, ...);
+extern void Perror(char *, ...);
diff --git a/marvell/uboot/tools/gdb/gdbcont.c b/marvell/uboot/tools/gdb/gdbcont.c
new file mode 100644
index 0000000..761bdb0
--- /dev/null
+++ b/marvell/uboot/tools/gdb/gdbcont.c
@@ -0,0 +1,71 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "serial.h"
+#include "error.h"
+#include "remote.h"
+
+char *serialdev = "/dev/term/b";
+speed_t speed = B230400;
+int verbose = 0;
+
+int
+main(int ac, char **av)
+{
+    int c, sfd;
+
+    if ((pname = strrchr(av[0], '/')) == NULL)
+	pname = av[0];
+    else
+	pname++;
+
+    while ((c = getopt(ac, av, "b:p:v")) != EOF)
+	switch (c) {
+
+	case 'b':
+	    if ((speed = cvtspeed(optarg)) == B0)
+		Error("can't decode baud rate specified in -b option");
+	    break;
+
+	case 'p':
+	    serialdev = optarg;
+	    break;
+
+	case 'v':
+	    verbose = 1;
+	    break;
+
+	default:
+	usage:
+	    fprintf(stderr, "Usage: %s [-b bps] [-p dev] [-v]\n", pname);
+	    exit(1);
+	}
+    if (optind != ac)
+	goto usage;
+
+    if (verbose)
+	fprintf(stderr, "Opening serial port and sending continue...\n");
+
+    if ((sfd = serialopen(serialdev, speed)) < 0)
+	Perror("open of serial device '%s' failed", serialdev);
+
+    remote_desc = sfd;
+    remote_reset();
+    remote_continue();
+
+    if (serialclose(sfd) < 0)
+	Perror("close of serial device '%s' failed", serialdev);
+
+    if (verbose)
+	fprintf(stderr, "Done.\n");
+
+    return (0);
+}
diff --git a/marvell/uboot/tools/gdb/gdbsend.c b/marvell/uboot/tools/gdb/gdbsend.c
new file mode 100644
index 0000000..bb28c72
--- /dev/null
+++ b/marvell/uboot/tools/gdb/gdbsend.c
@@ -0,0 +1,121 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "serial.h"
+#include "error.h"
+#include "remote.h"
+
+char *serialdev = "/dev/term/b";
+speed_t speed = B230400;
+int verbose = 0, docont = 0;
+unsigned long addr = 0x10000UL;
+
+int
+main(int ac, char **av)
+{
+    int c, sfd, ifd;
+    char *ifn, *image;
+    struct stat ist;
+
+    if ((pname = strrchr(av[0], '/')) == NULL)
+	pname = av[0];
+    else
+	pname++;
+
+    while ((c = getopt(ac, av, "a:b:cp:v")) != EOF)
+	switch (c) {
+
+	case 'a': {
+	    char *ep;
+
+	    addr = strtol(optarg, &ep, 0);
+	    if (ep == optarg || *ep != '\0')
+		Error("can't decode address specified in -a option");
+	    break;
+	}
+
+	case 'b':
+	    if ((speed = cvtspeed(optarg)) == B0)
+		Error("can't decode baud rate specified in -b option");
+	    break;
+
+	case 'c':
+	    docont = 1;
+	    break;
+
+	case 'p':
+	    serialdev = optarg;
+	    break;
+
+	case 'v':
+	    verbose = 1;
+	    break;
+
+	default:
+	usage:
+	    fprintf(stderr,
+		"Usage: %s [-a addr] [-b bps] [-c] [-p dev] [-v] imagefile\n",
+		pname);
+	    exit(1);
+	}
+
+    if (optind != ac - 1)
+	goto usage;
+    ifn = av[optind++];
+
+    if (verbose)
+	fprintf(stderr, "Opening file and reading image...\n");
+
+    if ((ifd = open(ifn, O_RDONLY)) < 0)
+	Perror("can't open kernel image file '%s'", ifn);
+
+    if (fstat(ifd, &ist) < 0)
+	Perror("fstat '%s' failed", ifn);
+
+    if ((image = (char *)malloc(ist.st_size)) == NULL)
+	Perror("can't allocate %ld bytes for image", ist.st_size);
+
+    if ((c = read(ifd, image, ist.st_size)) < 0)
+	Perror("read of %d bytes from '%s' failed", ist.st_size, ifn);
+
+    if (c != ist.st_size)
+	Error("read of %ld bytes from '%s' failed (%d)", ist.st_size, ifn, c);
+
+    if (close(ifd) < 0)
+	Perror("close of '%s' failed", ifn);
+
+    if (verbose)
+	fprintf(stderr, "Opening serial port and sending image...\n");
+
+    if ((sfd = serialopen(serialdev, speed)) < 0)
+	Perror("open of serial device '%s' failed", serialdev);
+
+    remote_desc = sfd;
+    remote_reset();
+    remote_write_bytes(addr, image, ist.st_size);
+
+    if (docont) {
+	if (verbose)
+	    fprintf(stderr, "[continue]");
+	remote_continue();
+    }
+
+    if (serialclose(sfd) < 0)
+	Perror("close of serial device '%s' failed", serialdev);
+
+    if (verbose)
+	fprintf(stderr, "Done.\n");
+
+    return (0);
+}
diff --git a/marvell/uboot/tools/gdb/remote.c b/marvell/uboot/tools/gdb/remote.c
new file mode 100644
index 0000000..f368104
--- /dev/null
+++ b/marvell/uboot/tools/gdb/remote.c
@@ -0,0 +1,916 @@
+/*
+ * taken from gdb/remote.c
+ *
+ * I am only interested in the write to memory stuff - everything else
+ * has been ripped out
+ *
+ * all the copyright notices etc have been left in
+ */
+
+/* enough so that it will compile */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/*nicked from gcc..*/
+
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not GNU C.  */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
+#include <alloca.h>
+#else /* not sparc */
+#if defined (MSDOS) && !defined (__TURBOC__)
+#include <malloc.h>
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+#include <malloc.h>
+ #pragma alloca
+#else /* not MSDOS, __TURBOC__, or _AIX */
+#ifdef __hpux
+#endif /* __hpux */
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc.  */
+#endif /* not GNU C.  */
+#ifdef __cplusplus
+extern "C" {
+#endif
+    void* alloca(size_t);
+#ifdef __cplusplus
+}
+#endif
+#endif /* alloca not defined.  */
+
+
+#include "serial.h"
+#include "error.h"
+#include "remote.h"
+#define REGISTER_BYTES 0
+#define fprintf_unfiltered fprintf
+#define fprintf_filtered fprintf
+#define fputs_unfiltered fputs
+#define fputs_filtered fputs
+#define fputc_unfiltered fputc
+#define fputc_filtered fputc
+#define printf_unfiltered printf
+#define printf_filtered printf
+#define puts_unfiltered puts
+#define puts_filtered puts
+#define putchar_unfiltered putchar
+#define putchar_filtered putchar
+#define fputstr_unfiltered(a,b,c) fputs((a), (c))
+#define gdb_stdlog stderr
+#define SERIAL_READCHAR(fd,timo)	serialreadchar((fd), (timo))
+#define SERIAL_WRITE(fd, addr, len)	serialwrite((fd), (addr), (len))
+#define error Error
+#define perror_with_name Perror
+#define gdb_flush fflush
+#define max(a,b) (((a)>(b))?(a):(b))
+#define min(a,b) (((a)<(b))?(a):(b))
+#define target_mourn_inferior() {}
+#define ULONGEST unsigned long
+#define CORE_ADDR unsigned long
+
+static int putpkt (char *);
+static int putpkt_binary(char *, int);
+static void getpkt (char *, int);
+
+static int remote_debug = 0, remote_register_buf_size = 0, watchdog = 0;
+
+int remote_desc = -1, remote_timeout = 10;
+
+static void
+fputstrn_unfiltered(char *s, int n, int x, FILE *fp)
+{
+    while (n-- > 0)
+	fputc(*s++, fp);
+}
+
+void
+remote_reset(void)
+{
+    SERIAL_WRITE(remote_desc, "+", 1);
+}
+
+void
+remote_continue(void)
+{
+    putpkt("c");
+}
+
+/* Remote target communications for serial-line targets in custom GDB protocol
+   Copyright 1988, 91, 92, 93, 94, 95, 96, 97, 98, 1999
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+/* *INDENT-OFF* */
+/* Remote communication protocol.
+
+   A debug packet whose contents are <data>
+   is encapsulated for transmission in the form:
+
+	$ <data> # CSUM1 CSUM2
+
+	<data> must be ASCII alphanumeric and cannot include characters
+	'$' or '#'.  If <data> starts with two characters followed by
+	':', then the existing stubs interpret this as a sequence number.
+
+	CSUM1 and CSUM2 are ascii hex representation of an 8-bit
+	checksum of <data>, the most significant nibble is sent first.
+	the hex digits 0-9,a-f are used.
+
+   Receiver responds with:
+
+	+	- if CSUM is correct and ready for next packet
+	-	- if CSUM is incorrect
+
+   <data> is as follows:
+   Most values are encoded in ascii hex digits.  Signal numbers are according
+   to the numbering in target.h.
+
+	Request		Packet
+
+	set thread	Hct...		Set thread for subsequent operations.
+					c = 'c' for thread used in step and
+					continue; t... can be -1 for all
+					threads.
+					c = 'g' for thread used in other
+					operations.  If zero, pick a thread,
+					any thread.
+	reply		OK		for success
+			ENN		for an error.
+
+	read registers  g
+	reply		XX....X		Each byte of register data
+					is described by two hex digits.
+					Registers are in the internal order
+					for GDB, and the bytes in a register
+					are in the same order the machine uses.
+			or ENN		for an error.
+
+	write regs	GXX..XX		Each byte of register data
+					is described by two hex digits.
+	reply		OK		for success
+			ENN		for an error
+
+	write reg	Pn...=r...	Write register n... with value r...,
+					which contains two hex digits for each
+					byte in the register (target byte
+					order).
+	reply		OK		for success
+			ENN		for an error
+	(not supported by all stubs).
+
+	read mem	mAA..AA,LLLL	AA..AA is address, LLLL is length.
+	reply		XX..XX		XX..XX is mem contents
+					Can be fewer bytes than requested
+					if able to read only part of the data.
+			or ENN		NN is errno
+
+	write mem	MAA..AA,LLLL:XX..XX
+					AA..AA is address,
+					LLLL is number of bytes,
+					XX..XX is data
+	reply		OK		for success
+			ENN		for an error (this includes the case
+					where only part of the data was
+					written).
+
+	write mem       XAA..AA,LLLL:XX..XX
+	 (binary)                       AA..AA is address,
+					LLLL is number of bytes,
+					XX..XX is binary data
+	reply           OK              for success
+			ENN             for an error
+
+	continue	cAA..AA		AA..AA is address to resume
+					If AA..AA is omitted,
+					resume at same address.
+
+	step		sAA..AA		AA..AA is address to resume
+					If AA..AA is omitted,
+					resume at same address.
+
+	continue with	Csig;AA..AA	Continue with signal sig (hex signal
+	signal				number).  If ;AA..AA is omitted,
+					resume at same address.
+
+	step with	Ssig;AA..AA	Like 'C' but step not continue.
+	signal
+
+	last signal     ?               Reply the current reason for stopping.
+					This is the same reply as is generated
+					for step or cont : SAA where AA is the
+					signal number.
+
+	detach          D               Reply OK.
+
+	There is no immediate reply to step or cont.
+	The reply comes when the machine stops.
+	It is		SAA		AA is the signal number.
+
+	or...		TAAn...:r...;n...:r...;n...:r...;
+					AA = signal number
+					n... = register number (hex)
+					  r... = register contents
+					n... = `thread'
+					  r... = thread process ID.  This is
+						 a hex integer.
+					n... = other string not starting
+					    with valid hex digit.
+					  gdb should ignore this n,r pair
+					  and go on to the next.  This way
+					  we can extend the protocol.
+	or...		WAA		The process exited, and AA is
+					the exit status.  This is only
+					applicable for certains sorts of
+					targets.
+	or...		XAA		The process terminated with signal
+					AA.
+	or (obsolete)	NAA;tttttttt;dddddddd;bbbbbbbb
+					AA = signal number
+					tttttttt = address of symbol "_start"
+					dddddddd = base of data section
+					bbbbbbbb = base of bss  section.
+					Note: only used by Cisco Systems
+					targets.  The difference between this
+					reply and the "qOffsets" query is that
+					the 'N' packet may arrive spontaneously
+					whereas the 'qOffsets' is a query
+					initiated by the host debugger.
+	or...           OXX..XX	XX..XX  is hex encoding of ASCII data. This
+					can happen at any time while the
+					program is running and the debugger
+					should continue to wait for
+					'W', 'T', etc.
+
+	thread alive	TXX		Find out if the thread XX is alive.
+	reply		OK		thread is still alive
+			ENN		thread is dead
+
+	remote restart	RXX		Restart the remote server
+
+	extended ops	!		Use the extended remote protocol.
+					Sticky -- only needs to be set once.
+
+	kill request	k
+
+	toggle debug	d		toggle debug flag (see 386 & 68k stubs)
+	reset		r		reset -- see sparc stub.
+	reserved	<other>		On other requests, the stub should
+					ignore the request and send an empty
+					response ($#<checksum>).  This way
+					we can extend the protocol and GDB
+					can tell whether the stub it is
+					talking to uses the old or the new.
+	search		tAA:PP,MM	Search backwards starting at address
+					AA for a match with pattern PP and
+					mask MM.  PP and MM are 4 bytes.
+					Not supported by all stubs.
+
+	general query	qXXXX		Request info about XXXX.
+	general set	QXXXX=yyyy	Set value of XXXX to yyyy.
+	query sect offs	qOffsets	Get section offsets.  Reply is
+					Text=xxx;Data=yyy;Bss=zzz
+
+	Responses can be run-length encoded to save space.  A '*' means that
+	the next character is an ASCII encoding giving a repeat count which
+	stands for that many repititions of the character preceding the '*'.
+	The encoding is n+29, yielding a printable character where n >=3
+	(which is where rle starts to win).  Don't use an n > 126.
+
+	So
+	"0* " means the same as "0000".  */
+/* *INDENT-ON* */
+
+/* This variable (available to the user via "set remotebinarydownload")
+   dictates whether downloads are sent in binary (via the 'X' packet).
+   We assume that the stub can, and attempt to do it. This will be cleared if
+   the stub does not understand it. This switch is still needed, though
+   in cases when the packet is supported in the stub, but the connection
+   does not allow it (i.e., 7-bit serial connection only). */
+static int remote_binary_download = 1;
+
+/* Have we already checked whether binary downloads work? */
+static int remote_binary_checked;
+
+/* Maximum number of bytes to read/write at once.  The value here
+   is chosen to fill up a packet (the headers account for the 32).  */
+#define MAXBUFBYTES(N) (((N)-32)/2)
+
+/* Having this larger than 400 causes us to be incompatible with m68k-stub.c
+   and i386-stub.c.  Normally, no one would notice because it only matters
+   for writing large chunks of memory (e.g. in downloads).  Also, this needs
+   to be more than 400 if required to hold the registers (see below, where
+   we round it up based on REGISTER_BYTES).  */
+/* Round up PBUFSIZ to hold all the registers, at least.  */
+#define	PBUFSIZ ((REGISTER_BYTES > MAXBUFBYTES (400)) \
+		 ? (REGISTER_BYTES * 2 + 32) \
+		 : 400)
+
+
+/* This variable sets the number of bytes to be written to the target
+   in a single packet.  Normally PBUFSIZ is satisfactory, but some
+   targets need smaller values (perhaps because the receiving end
+   is slow).  */
+
+static int remote_write_size = 0x7fffffff;
+
+/* This variable sets the number of bits in an address that are to be
+   sent in a memory ("M" or "m") packet.  Normally, after stripping
+   leading zeros, the entire address would be sent. This variable
+   restricts the address to REMOTE_ADDRESS_SIZE bits.  HISTORY: The
+   initial implementation of remote.c restricted the address sent in
+   memory packets to ``host::sizeof long'' bytes - (typically 32
+   bits).  Consequently, for 64 bit targets, the upper 32 bits of an
+   address was never sent.  Since fixing this bug may cause a break in
+   some remote targets this variable is principly provided to
+   facilitate backward compatibility. */
+
+static int remote_address_size;
+
+/* Convert hex digit A to a number.  */
+
+static int
+fromhex (int a)
+{
+  if (a >= '0' && a <= '9')
+    return a - '0';
+  else if (a >= 'a' && a <= 'f')
+    return a - 'a' + 10;
+  else if (a >= 'A' && a <= 'F')
+    return a - 'A' + 10;
+  else {
+    error ("Reply contains invalid hex digit %d", a);
+    return -1;
+  }
+}
+
+/* Convert number NIB to a hex digit.  */
+
+static int
+tohex (int nib)
+{
+  if (nib < 10)
+    return '0' + nib;
+  else
+    return 'a' + nib - 10;
+}
+
+/* Return the number of hex digits in num.  */
+
+static int
+hexnumlen (ULONGEST num)
+{
+  int i;
+
+  for (i = 0; num != 0; i++)
+    num >>= 4;
+
+  return max (i, 1);
+}
+
+/* Set BUF to the hex digits representing NUM.  */
+
+static int
+hexnumstr (char *buf, ULONGEST num)
+{
+  int i;
+  int len = hexnumlen (num);
+
+  buf[len] = '\0';
+
+  for (i = len - 1; i >= 0; i--)
+    {
+      buf[i] = "0123456789abcdef"[(num & 0xf)];
+      num >>= 4;
+    }
+
+  return len;
+}
+
+/* Mask all but the least significant REMOTE_ADDRESS_SIZE bits. */
+
+static CORE_ADDR
+remote_address_masked (CORE_ADDR addr)
+{
+  if (remote_address_size > 0
+      && remote_address_size < (sizeof (ULONGEST) * 8))
+    {
+      /* Only create a mask when that mask can safely be constructed
+	 in a ULONGEST variable. */
+      ULONGEST mask = 1;
+      mask = (mask << remote_address_size) - 1;
+      addr &= mask;
+    }
+  return addr;
+}
+
+/* Determine whether the remote target supports binary downloading.
+   This is accomplished by sending a no-op memory write of zero length
+   to the target at the specified address. It does not suffice to send
+   the whole packet, since many stubs strip the eighth bit and subsequently
+   compute a wrong checksum, which causes real havoc with remote_write_bytes.
+
+   NOTE: This can still lose if the serial line is not eight-bit clean. In
+   cases like this, the user should clear "remotebinarydownload". */
+static void
+check_binary_download (CORE_ADDR addr)
+{
+  if (remote_binary_download && !remote_binary_checked)
+    {
+      char *buf = alloca (PBUFSIZ);
+      char *p;
+      remote_binary_checked = 1;
+
+      p = buf;
+      *p++ = 'X';
+      p += hexnumstr (p, (ULONGEST) addr);
+      *p++ = ',';
+      p += hexnumstr (p, (ULONGEST) 0);
+      *p++ = ':';
+      *p = '\0';
+
+      putpkt_binary (buf, (int) (p - buf));
+      getpkt (buf, 0);
+
+      if (buf[0] == '\0')
+	remote_binary_download = 0;
+    }
+
+  if (remote_debug)
+    {
+      if (remote_binary_download)
+	fprintf_unfiltered (gdb_stdlog,
+			    "binary downloading suppported by target\n");
+      else
+	fprintf_unfiltered (gdb_stdlog,
+			    "binary downloading NOT suppported by target\n");
+    }
+}
+
+/* Write memory data directly to the remote machine.
+   This does not inform the data cache; the data cache uses this.
+   MEMADDR is the address in the remote memory space.
+   MYADDR is the address of the buffer in our space.
+   LEN is the number of bytes.
+
+   Returns number of bytes transferred, or 0 for error.  */
+
+int
+remote_write_bytes (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  unsigned char *buf = alloca (PBUFSIZ);
+  int max_buf_size;		/* Max size of packet output buffer */
+  int origlen;
+  extern int verbose;
+
+  /* Verify that the target can support a binary download */
+  check_binary_download (memaddr);
+
+  /* Chop the transfer down if necessary */
+
+  max_buf_size = min (remote_write_size, PBUFSIZ);
+  if (remote_register_buf_size != 0)
+    max_buf_size = min (max_buf_size, remote_register_buf_size);
+
+  /* Subtract header overhead from max payload size -  $M<memaddr>,<len>:#nn */
+  max_buf_size -= 2 + hexnumlen (memaddr + len - 1) + 1 + hexnumlen (len) + 4;
+
+  origlen = len;
+  while (len > 0)
+    {
+      unsigned char *p, *plen;
+      int todo;
+      int i;
+
+      /* construct "M"<memaddr>","<len>":" */
+      /* sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo); */
+      memaddr = remote_address_masked (memaddr);
+      p = buf;
+      if (remote_binary_download)
+	{
+	  *p++ = 'X';
+	  todo = min (len, max_buf_size);
+	}
+      else
+	{
+	  *p++ = 'M';
+	  todo = min (len, max_buf_size / 2);	/* num bytes that will fit */
+	}
+
+      p += hexnumstr ((char *)p, (ULONGEST) memaddr);
+      *p++ = ',';
+
+      plen = p;			/* remember where len field goes */
+      p += hexnumstr ((char *)p, (ULONGEST) todo);
+      *p++ = ':';
+      *p = '\0';
+
+      /* We send target system values byte by byte, in increasing byte
+	 addresses, each byte encoded as two hex characters (or one
+	 binary character).  */
+      if (remote_binary_download)
+	{
+	  int escaped = 0;
+	  for (i = 0;
+	       (i < todo) && (i + escaped) < (max_buf_size - 2);
+	       i++)
+	    {
+	      switch (myaddr[i] & 0xff)
+		{
+		case '$':
+		case '#':
+		case 0x7d:
+		  /* These must be escaped */
+		  escaped++;
+		  *p++ = 0x7d;
+		  *p++ = (myaddr[i] & 0xff) ^ 0x20;
+		  break;
+		default:
+		  *p++ = myaddr[i] & 0xff;
+		  break;
+		}
+	    }
+
+	  if (i < todo)
+	    {
+	      /* Escape chars have filled up the buffer prematurely,
+		 and we have actually sent fewer bytes than planned.
+		 Fix-up the length field of the packet.  */
+
+	      /* FIXME: will fail if new len is a shorter string than
+		 old len.  */
+
+	      plen += hexnumstr ((char *)plen, (ULONGEST) i);
+	      *plen++ = ':';
+	    }
+	}
+      else
+	{
+	  for (i = 0; i < todo; i++)
+	    {
+	      *p++ = tohex ((myaddr[i] >> 4) & 0xf);
+	      *p++ = tohex (myaddr[i] & 0xf);
+	    }
+	  *p = '\0';
+	}
+
+      putpkt_binary ((char *)buf, (int) (p - buf));
+      getpkt ((char *)buf, 0);
+
+      if (buf[0] == 'E')
+	{
+	  /* There is no correspondance between what the remote protocol uses
+	     for errors and errno codes.  We would like a cleaner way of
+	     representing errors (big enough to include errno codes, bfd_error
+	     codes, and others).  But for now just return EIO.  */
+	  errno = EIO;
+	  return 0;
+	}
+
+      /* Increment by i, not by todo, in case escape chars
+	 caused us to send fewer bytes than we'd planned.  */
+      myaddr += i;
+      memaddr += i;
+      len -= i;
+
+      if (verbose)
+	putc('.', stderr);
+    }
+  return origlen;
+}
+
+/* Stuff for dealing with the packets which are part of this protocol.
+   See comment at top of file for details.  */
+
+/* Read a single character from the remote end, masking it down to 7 bits. */
+
+static int
+readchar (int timeout)
+{
+  int ch;
+
+  ch = SERIAL_READCHAR (remote_desc, timeout);
+
+  switch (ch)
+    {
+    case SERIAL_EOF:
+      error ("Remote connection closed");
+    case SERIAL_ERROR:
+      perror_with_name ("Remote communication error");
+    case SERIAL_TIMEOUT:
+      return ch;
+    default:
+      return ch & 0x7f;
+    }
+}
+
+static int
+putpkt (buf)
+     char *buf;
+{
+  return putpkt_binary (buf, strlen (buf));
+}
+
+/* Send a packet to the remote machine, with error checking.  The data
+   of the packet is in BUF.  The string in BUF can be at most  PBUFSIZ - 5
+   to account for the $, # and checksum, and for a possible /0 if we are
+   debugging (remote_debug) and want to print the sent packet as a string */
+
+static int
+putpkt_binary (buf, cnt)
+     char *buf;
+     int cnt;
+{
+  int i;
+  unsigned char csum = 0;
+  char *buf2 = alloca (PBUFSIZ);
+  char *junkbuf = alloca (PBUFSIZ);
+
+  int ch;
+  int tcount = 0;
+  char *p;
+
+  /* Copy the packet into buffer BUF2, encapsulating it
+     and giving it a checksum.  */
+
+  if (cnt > BUFSIZ - 5)		/* Prosanity check */
+    abort ();
+
+  p = buf2;
+  *p++ = '$';
+
+  for (i = 0; i < cnt; i++)
+    {
+      csum += buf[i];
+      *p++ = buf[i];
+    }
+  *p++ = '#';
+  *p++ = tohex ((csum >> 4) & 0xf);
+  *p++ = tohex (csum & 0xf);
+
+  /* Send it over and over until we get a positive ack.  */
+
+  while (1)
+    {
+      int started_error_output = 0;
+
+      if (remote_debug)
+	{
+	  *p = '\0';
+	  fprintf_unfiltered (gdb_stdlog, "Sending packet: ");
+	  fputstrn_unfiltered (buf2, p - buf2, 0, gdb_stdlog);
+	  fprintf_unfiltered (gdb_stdlog, "...");
+	  gdb_flush (gdb_stdlog);
+	}
+      if (SERIAL_WRITE (remote_desc, buf2, p - buf2))
+	perror_with_name ("putpkt: write failed");
+
+      /* read until either a timeout occurs (-2) or '+' is read */
+      while (1)
+	{
+	  ch = readchar (remote_timeout);
+
+	  if (remote_debug)
+	    {
+	      switch (ch)
+		{
+		case '+':
+		case SERIAL_TIMEOUT:
+		case '$':
+		  if (started_error_output)
+		    {
+		      putchar_unfiltered ('\n');
+		      started_error_output = 0;
+		    }
+		}
+	    }
+
+	  switch (ch)
+	    {
+	    case '+':
+	      if (remote_debug)
+		fprintf_unfiltered (gdb_stdlog, "Ack\n");
+	      return 1;
+	    case SERIAL_TIMEOUT:
+	      tcount++;
+	      if (tcount > 3)
+		return 0;
+	      break;		/* Retransmit buffer */
+	    case '$':
+	      {
+		/* It's probably an old response, and we're out of sync.
+		   Just gobble up the packet and ignore it.  */
+		getpkt (junkbuf, 0);
+		continue;	/* Now, go look for + */
+	      }
+	    default:
+	      if (remote_debug)
+		{
+		  if (!started_error_output)
+		    {
+		      started_error_output = 1;
+		      fprintf_unfiltered (gdb_stdlog, "putpkt: Junk: ");
+		    }
+		  fputc_unfiltered (ch & 0177, gdb_stdlog);
+		}
+	      continue;
+	    }
+	  break;		/* Here to retransmit */
+	}
+
+#if 0
+      /* This is wrong.  If doing a long backtrace, the user should be
+	 able to get out next time we call QUIT, without anything as
+	 violent as interrupt_query.  If we want to provide a way out of
+	 here without getting to the next QUIT, it should be based on
+	 hitting ^C twice as in remote_wait.  */
+      if (quit_flag)
+	{
+	  quit_flag = 0;
+	  interrupt_query ();
+	}
+#endif
+    }
+}
+
+/* Come here after finding the start of the frame.  Collect the rest
+   into BUF, verifying the checksum, length, and handling run-length
+   compression.  Returns 0 on any error, 1 on success.  */
+
+static int
+read_frame (char *buf)
+{
+  unsigned char csum;
+  char *bp;
+  int c;
+
+  csum = 0;
+  bp = buf;
+
+  while (1)
+    {
+      c = readchar (remote_timeout);
+
+      switch (c)
+	{
+	case SERIAL_TIMEOUT:
+	  if (remote_debug)
+	    fputs_filtered ("Timeout in mid-packet, retrying\n", gdb_stdlog);
+	  return 0;
+	case '$':
+	  if (remote_debug)
+	    fputs_filtered ("Saw new packet start in middle of old one\n",
+			    gdb_stdlog);
+	  return 0;		/* Start a new packet, count retries */
+	case '#':
+	  {
+	    unsigned char pktcsum;
+
+	    *bp = '\000';
+
+	    pktcsum = fromhex (readchar (remote_timeout)) << 4;
+	    pktcsum |= fromhex (readchar (remote_timeout));
+
+	    if (csum == pktcsum)
+	      {
+		return 1;
+	      }
+
+	    if (remote_debug)
+	      {
+		fprintf_filtered (gdb_stdlog,
+			      "Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+				  pktcsum, csum);
+		fputs_filtered (buf, gdb_stdlog);
+		fputs_filtered ("\n", gdb_stdlog);
+	      }
+	    return 0;
+	  }
+	case '*':		/* Run length encoding */
+	  csum += c;
+	  c = readchar (remote_timeout);
+	  csum += c;
+	  c = c - ' ' + 3;	/* Compute repeat count */
+
+	  if (c > 0 && c < 255 && bp + c - 1 < buf + PBUFSIZ - 1)
+	    {
+	      memset (bp, *(bp - 1), c);
+	      bp += c;
+	      continue;
+	    }
+
+	  *bp = '\0';
+	  printf_filtered ("Repeat count %d too large for buffer: ", c);
+	  puts_filtered (buf);
+	  puts_filtered ("\n");
+	  return 0;
+	default:
+	  if (bp < buf + PBUFSIZ - 1)
+	    {
+	      *bp++ = c;
+	      csum += c;
+	      continue;
+	    }
+
+	  *bp = '\0';
+	  puts_filtered ("Remote packet too long: ");
+	  puts_filtered (buf);
+	  puts_filtered ("\n");
+
+	  return 0;
+	}
+    }
+}
+
+/* Read a packet from the remote machine, with error checking, and
+   store it in BUF.  BUF is expected to be of size PBUFSIZ.  If
+   FOREVER, wait forever rather than timing out; this is used while
+   the target is executing user code.  */
+
+static void
+getpkt (buf, forever)
+     char *buf;
+     int forever;
+{
+  int c;
+  int tries;
+  int timeout;
+  int val;
+
+  strcpy (buf, "timeout");
+
+  if (forever)
+    {
+      timeout = watchdog > 0 ? watchdog : -1;
+    }
+
+  else
+    timeout = remote_timeout;
+
+#define MAX_TRIES 3
+
+  for (tries = 1; tries <= MAX_TRIES; tries++)
+    {
+      /* This can loop forever if the remote side sends us characters
+	 continuously, but if it pauses, we'll get a zero from readchar
+	 because of timeout.  Then we'll count that as a retry.  */
+
+      /* Note that we will only wait forever prior to the start of a packet.
+	 After that, we expect characters to arrive at a brisk pace.  They
+	 should show up within remote_timeout intervals.  */
+
+      do
+	{
+	  c = readchar (timeout);
+
+	  if (c == SERIAL_TIMEOUT)
+	    {
+	      if (forever)	/* Watchdog went off.  Kill the target. */
+		{
+		  target_mourn_inferior ();
+		  error ("Watchdog has expired.  Target detached.\n");
+		}
+	      if (remote_debug)
+		fputs_filtered ("Timed out.\n", gdb_stdlog);
+	      goto retry;
+	    }
+	}
+      while (c != '$');
+
+      /* We've found the start of a packet, now collect the data.  */
+
+      val = read_frame (buf);
+
+      if (val == 1)
+	{
+	  if (remote_debug)
+	    {
+	      fprintf_unfiltered (gdb_stdlog, "Packet received: ");
+	      fputstr_unfiltered (buf, 0, gdb_stdlog);
+	      fprintf_unfiltered (gdb_stdlog, "\n");
+	    }
+	  SERIAL_WRITE (remote_desc, "+", 1);
+	  return;
+	}
+
+      /* Try the whole thing again.  */
+    retry:
+      SERIAL_WRITE (remote_desc, "-", 1);
+    }
+
+  /* We have tried hard enough, and just can't receive the packet.  Give up. */
+
+  printf_unfiltered ("Ignoring packet error, continuing...\n");
+  SERIAL_WRITE (remote_desc, "+", 1);
+}
diff --git a/marvell/uboot/tools/gdb/remote.h b/marvell/uboot/tools/gdb/remote.h
new file mode 100644
index 0000000..df6b069
--- /dev/null
+++ b/marvell/uboot/tools/gdb/remote.h
@@ -0,0 +1,12 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+extern int remote_desc, remote_timeout;
+
+extern void remote_reset(void);
+extern void remote_continue(void);
+extern int remote_write_bytes(unsigned long, char *, int);
diff --git a/marvell/uboot/tools/gdb/serial.c b/marvell/uboot/tools/gdb/serial.c
new file mode 100644
index 0000000..709f8ce
--- /dev/null
+++ b/marvell/uboot/tools/gdb/serial.c
@@ -0,0 +1,133 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include "serial.h"
+
+#if defined(__sun__)	 || \
+    defined(__OpenBSD__) || \
+    defined(__FreeBSD__) || \
+    defined(__NetBSD__)	 || \
+    defined(__APPLE__)
+static struct termios tios = { BRKINT, 0, B115200|CS8|CREAD, 0, { 0 } };
+#else
+static struct termios tios = { BRKINT, 0, B115200|CS8|CREAD, 0,   0   };
+#endif
+
+static struct speedmap {
+    char *str;
+    speed_t val;
+} speedmap[] = {
+    { "50", B50 },		{ "75", B75 },		{ "110", B110 },
+    { "134", B134 },		{ "150", B150 },	{ "200", B200 },
+    { "300", B300 },		{ "600", B600 },	{ "1200", B1200 },
+    { "1800", B1800 },		{ "2400", B2400 },	{ "4800", B4800 },
+    { "9600", B9600 },		{ "19200", B19200 },	{ "38400", B38400 },
+    { "57600", B57600 },
+#ifdef	B76800
+    { "76800", B76800 },
+#endif
+    { "115200", B115200 },
+#ifdef	B153600
+    { "153600", B153600 },
+#endif
+    { "230400", B230400 },
+#ifdef	B307200
+    { "307200", B307200 },
+#endif
+#ifdef B460800
+    { "460800", B460800 }
+#endif
+};
+static int nspeeds = sizeof speedmap / sizeof speedmap[0];
+
+speed_t
+cvtspeed(char *str)
+{
+    struct speedmap *smp = speedmap, *esmp = &speedmap[nspeeds];
+
+    while (smp < esmp) {
+	if (strcmp(str, smp->str) == 0)
+	    return (smp->val);
+	smp++;
+    }
+    return B0;
+}
+
+int
+serialopen(char *device, speed_t speed)
+{
+    int fd;
+
+    if (cfsetospeed(&tios, speed) < 0)
+	return -1;
+
+    if ((fd = open(device, O_RDWR)) < 0)
+	return -1;
+
+    if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
+	(void)close(fd);
+	return -1;
+    }
+
+    return fd;
+}
+
+int
+serialreadchar(int fd, int timeout)
+{
+    fd_set fds;
+    struct timeval tv;
+    int n;
+    char ch;
+
+    tv.tv_sec = timeout;
+    tv.tv_usec = 0;
+
+    FD_ZERO(&fds);
+    FD_SET(fd, &fds);
+
+    /* this is a fucking horrible quick hack - fix this */
+
+    if ((n = select(fd + 1, &fds, 0, 0, &tv)) < 0)
+	return SERIAL_ERROR;
+
+    if (n == 0)
+	return SERIAL_TIMEOUT;
+
+    if ((n = read(fd, &ch, 1)) < 0)
+	return SERIAL_ERROR;
+
+    if (n == 0)
+	return SERIAL_EOF;
+
+    return ch;
+}
+
+int
+serialwrite(int fd, char *buf, int len)
+{
+    int n;
+
+    do {
+	n = write(fd, buf, len);
+	if (n < 0)
+	    return 1;
+	len -= n;
+	buf += n;
+    } while (len > 0);
+    return 0;
+}
+
+int
+serialclose(int fd)
+{
+    return close(fd);
+}
diff --git a/marvell/uboot/tools/gdb/serial.h b/marvell/uboot/tools/gdb/serial.h
new file mode 100644
index 0000000..dc9d6b7
--- /dev/null
+++ b/marvell/uboot/tools/gdb/serial.h
@@ -0,0 +1,18 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <termios.h>
+
+#define SERIAL_ERROR	-1	/* General error, see errno for details */
+#define SERIAL_TIMEOUT	-2
+#define SERIAL_EOF	-3
+
+extern speed_t cvtspeed(char *);
+extern int serialopen(char *, speed_t);
+extern int serialreadchar(int, int);
+extern int serialwrite(int, char *, int);
+extern int serialclose(int);
diff --git a/marvell/uboot/tools/gen_eth_addr.c b/marvell/uboot/tools/gen_eth_addr.c
new file mode 100644
index 0000000..bf9d935
--- /dev/null
+++ b/marvell/uboot/tools/gen_eth_addr.c
@@ -0,0 +1,34 @@
+/*
+ * (C) Copyright 2001
+ * Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+
+int
+main(int argc, char *argv[])
+{
+    unsigned long ethaddr_low, ethaddr_high;
+
+    srand(time(0) | getpid());
+
+    /*
+     * setting the 2nd LSB in the most significant byte of
+     * the address makes it a locally administered ethernet
+     * address
+     */
+    ethaddr_high = (rand() & 0xfeff) | 0x0200;
+    ethaddr_low = rand();
+
+    printf("%02lx:%02lx:%02lx:%02lx:%02lx:%02lx\n",
+	ethaddr_high >> 8, ethaddr_high & 0xff,
+	ethaddr_low >> 24, (ethaddr_low >> 16) & 0xff,
+	(ethaddr_low >> 8) & 0xff, ethaddr_low & 0xff);
+
+    return (0);
+}
diff --git a/marvell/uboot/tools/getline.c b/marvell/uboot/tools/getline.c
new file mode 100644
index 0000000..f7dbcc9
--- /dev/null
+++ b/marvell/uboot/tools/getline.c
@@ -0,0 +1,90 @@
+/* getline.c -- Replacement for GNU C library function getline
+ *
+ * Copyright (C) 1993, 1996, 2001, 2002 Free Software Foundation, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* Written by Jan Brittenson, bson@gnu.ai.mit.edu.  */
+
+#include <assert.h>
+#include <stdio.h>
+
+/* Always add at least this many bytes when extending the buffer.  */
+#define MIN_CHUNK 64
+
+/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
+   + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
+   malloc (or NULL), pointing to *N characters of space.  It is realloc'd
+   as necessary.  Return the number of characters read (not including the
+   null terminator), or -1 on error or EOF.
+   NOTE: There is another getstr() function declared in <curses.h>.  */
+static int getstr(char **lineptr, size_t *n, FILE *stream,
+		  char terminator, size_t offset)
+{
+	int nchars_avail;	/* Allocated but unused chars in *LINEPTR.  */
+	char *read_pos;		/* Where we're reading into *LINEPTR. */
+	int ret;
+
+	if (!lineptr || !n || !stream)
+		return -1;
+
+	if (!*lineptr) {
+		*n = MIN_CHUNK;
+		*lineptr = malloc(*n);
+		if (!*lineptr)
+			return -1;
+	}
+
+	nchars_avail = *n - offset;
+	read_pos = *lineptr + offset;
+
+	for (;;) {
+		register int c = getc(stream);
+
+		/* We always want at least one char left in the buffer, since we
+		   always (unless we get an error while reading the first char)
+		   NUL-terminate the line buffer.  */
+
+		assert(*n - nchars_avail == read_pos - *lineptr);
+		if (nchars_avail < 2) {
+			if (*n > MIN_CHUNK)
+				*n *= 2;
+			else
+				*n += MIN_CHUNK;
+
+			nchars_avail = *n + *lineptr - read_pos;
+			*lineptr = realloc(*lineptr, *n);
+			if (!*lineptr)
+				return -1;
+			read_pos = *n - nchars_avail + *lineptr;
+			assert(*n - nchars_avail == read_pos - *lineptr);
+		}
+
+		if (c == EOF || ferror (stream)) {
+			/* Return partial line, if any.  */
+			if (read_pos == *lineptr)
+				return -1;
+			else
+				break;
+		}
+
+		*read_pos++ = c;
+		nchars_avail--;
+
+		if (c == terminator)
+			/* Return the line.  */
+			break;
+	}
+
+	/* Done - NUL terminate and return the number of chars read.  */
+	*read_pos = '\0';
+
+	ret = read_pos - (*lineptr + offset);
+	return ret;
+}
+
+int getline (char **lineptr, size_t *n, FILE *stream)
+{
+	return getstr(lineptr, n, stream, '\n', 0);
+}
diff --git a/marvell/uboot/tools/getline.h b/marvell/uboot/tools/getline.h
new file mode 100644
index 0000000..a2f35b9
--- /dev/null
+++ b/marvell/uboot/tools/getline.h
@@ -0,0 +1 @@
+int getline(char **lineptr, size_t *n, FILE *stream);
diff --git a/marvell/uboot/tools/image-host.c b/marvell/uboot/tools/image-host.c
new file mode 100644
index 0000000..0d5c88c
--- /dev/null
+++ b/marvell/uboot/tools/image-host.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "mkimage.h"
+#include <image.h>
+#include <version.h>
+
+/**
+ * fit_set_hash_value - set hash value in requested has node
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @value: hash value to be set
+ * @value_len: hash value length
+ *
+ * fit_set_hash_value() attempts to set hash value in a node at offset
+ * given and returns operation status to the caller.
+ *
+ * returns
+ *     0, on success
+ *     -1, on failure
+ */
+static int fit_set_hash_value(void *fit, int noffset, uint8_t *value,
+				int value_len)
+{
+	int ret;
+
+	ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
+	if (ret) {
+		printf("Can't set hash '%s' property for '%s' node(%s)\n",
+		       FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL),
+		       fdt_strerror(ret));
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * fit_image_process_hash - Process a single subnode of the images/ node
+ *
+ * Check each subnode and process accordingly. For hash nodes we generate
+ * a hash of the supplised data and store it in the node.
+ *
+ * @fit:	pointer to the FIT format image header
+ * @image_name:	name of image being processes (used to display errors)
+ * @noffset:	subnode offset
+ * @data:	data to process
+ * @size:	size of data in bytes
+ * @return 0 if ok, -1 on error
+ */
+static int fit_image_process_hash(void *fit, const char *image_name,
+		int noffset, const void *data, size_t size)
+{
+	uint8_t value[FIT_MAX_HASH_LEN];
+	const char *node_name;
+	int value_len;
+	char *algo;
+
+	node_name = fit_get_name(fit, noffset, NULL);
+
+	if (fit_image_hash_get_algo(fit, noffset, &algo)) {
+		printf("Can't get hash algo property for '%s' hash node in '%s' image node\n",
+		       node_name, image_name);
+		return -1;
+	}
+
+	if (calculate_hash(data, size, algo, value, &value_len)) {
+		printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n",
+		       algo, node_name, image_name);
+		return -1;
+	}
+
+	if (fit_set_hash_value(fit, noffset, value, value_len)) {
+		printf("Can't set hash value for '%s' hash node in '%s' image node\n",
+		       node_name, image_name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * fit_image_write_sig() - write the signature to a FIT
+ *
+ * This writes the signature and signer data to the FIT.
+ *
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @value: signature value to be set
+ * @value_len: signature value length
+ * @comment: Text comment to write (NULL for none)
+ *
+ * returns
+ *     0, on success
+ *     -FDT_ERR_..., on failure
+ */
+static int fit_image_write_sig(void *fit, int noffset, uint8_t *value,
+		int value_len, const char *comment, const char *region_prop,
+		int region_proplen)
+{
+	int string_size;
+	int ret;
+
+	/*
+	 * Get the current string size, before we update the FIT and add
+	 * more
+	 */
+	string_size = fdt_size_dt_strings(fit);
+
+	ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
+	if (!ret) {
+		ret = fdt_setprop_string(fit, noffset, "signer-name",
+					 "mkimage");
+	}
+	if (!ret) {
+		ret = fdt_setprop_string(fit, noffset, "signer-version",
+				  PLAIN_VERSION);
+	}
+	if (comment && !ret)
+		ret = fdt_setprop_string(fit, noffset, "comment", comment);
+	if (!ret)
+		ret = fit_set_timestamp(fit, noffset, time(NULL));
+	if (region_prop && !ret) {
+		uint32_t strdata[2];
+
+		ret = fdt_setprop(fit, noffset, "hashed-nodes",
+				   region_prop, region_proplen);
+		strdata[0] = 0;
+		strdata[1] = cpu_to_fdt32(string_size);
+		if (!ret) {
+			ret = fdt_setprop(fit, noffset, "hashed-strings",
+					  strdata, sizeof(strdata));
+		}
+	}
+
+	return ret;
+}
+
+static int fit_image_setup_sig(struct image_sign_info *info,
+		const char *keydir, void *fit, const char *image_name,
+		int noffset, const char *require_keys)
+{
+	const char *node_name;
+	char *algo_name;
+
+	node_name = fit_get_name(fit, noffset, NULL);
+	if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
+		printf("Can't get algo property for '%s' signature node in '%s' image node\n",
+		       node_name, image_name);
+		return -1;
+	}
+
+	memset(info, '\0', sizeof(*info));
+	info->keydir = keydir;
+	info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+	info->fit = fit;
+	info->node_offset = noffset;
+	info->algo = image_get_sig_algo(algo_name);
+	info->require_keys = require_keys;
+	if (!info->algo) {
+		printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n",
+		       algo_name, node_name, image_name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * fit_image_process_sig- Process a single subnode of the images/ node
+ *
+ * Check each subnode and process accordingly. For signature nodes we
+ * generate a signed hash of the supplised data and store it in the node.
+ *
+ * @keydir:	Directory containing keys to use for signing
+ * @keydest:	Destination FDT blob to write public keys into
+ * @fit:	pointer to the FIT format image header
+ * @image_name:	name of image being processes (used to display errors)
+ * @noffset:	subnode offset
+ * @data:	data to process
+ * @size:	size of data in bytes
+ * @comment:	Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
+ * @return 0 if ok, -1 on error
+ */
+static int fit_image_process_sig(const char *keydir, void *keydest,
+		void *fit, const char *image_name,
+		int noffset, const void *data, size_t size,
+		const char *comment, int require_keys)
+{
+	struct image_sign_info info;
+	struct image_region region;
+	const char *node_name;
+	uint8_t *value;
+	uint value_len;
+	int ret;
+
+	if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset,
+				require_keys ? "image" : NULL))
+		return -1;
+
+	node_name = fit_get_name(fit, noffset, NULL);
+	region.data = data;
+	region.size = size;
+	ret = info.algo->sign(&info, &region, 1, &value, &value_len);
+	if (ret) {
+		printf("Failed to sign '%s' signature node in '%s' image node: %d\n",
+		       node_name, image_name, ret);
+
+		/* We allow keys to be missing */
+		if (ret == -ENOENT)
+			return 0;
+		return -1;
+	}
+
+	ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
+			NULL, 0);
+	if (ret) {
+		printf("Can't write signature for '%s' signature node in '%s' image node: %s\n",
+		       node_name, image_name, fdt_strerror(ret));
+		return -1;
+	}
+	free(value);
+
+	/* Get keyname again, as FDT has changed and invalidated our pointer */
+	info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+
+	/* Write the public key into the supplied FDT file */
+	if (keydest && info.algo->add_verify_data(&info, keydest)) {
+		printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
+		       node_name, image_name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * fit_image_add_verification_data() - calculate/set verig. data for image node
+ *
+ * This adds hash and signature values for an component image node.
+ *
+ * All existing hash subnodes are checked, if algorithm property is set to
+ * one of the supported hash algorithms, hash value is computed and
+ * corresponding hash node property is set, for example:
+ *
+ * Input component image node structure:
+ *
+ * o image@1 (at image_noffset)
+ *   | - data = [binary data]
+ *   o hash@1
+ *     |- algo = "sha1"
+ *
+ * Output component image node structure:
+ *
+ * o image@1 (at image_noffset)
+ *   | - data = [binary data]
+ *   o hash@1
+ *     |- algo = "sha1"
+ *     |- value = sha1(data)
+ *
+ * For signature details, please see doc/uImage.FIT/signature.txt
+ *
+ * @keydir	Directory containing *.key and *.crt files (or NULL)
+ * @keydest	FDT Blob to write public keys into (NULL if none)
+ * @fit:	Pointer to the FIT format image header
+ * @image_noffset: Requested component image node
+ * @comment:	Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
+ * @return: 0 on success, <0 on failure
+ */
+int fit_image_add_verification_data(const char *keydir, void *keydest,
+		void *fit, int image_noffset, const char *comment,
+		int require_keys)
+{
+	const char *image_name;
+	const void *data;
+	size_t size;
+	int noffset;
+
+	/* Get image data and data length */
+	if (fit_image_get_data(fit, image_noffset, &data, &size)) {
+		printf("Can't get image data/size\n");
+		return -1;
+	}
+
+	image_name = fit_get_name(fit, image_noffset, NULL);
+
+	/* Process all hash subnodes of the component image node */
+	for (noffset = fdt_first_subnode(fit, image_noffset);
+	     noffset >= 0;
+	     noffset = fdt_next_subnode(fit, noffset)) {
+		const char *node_name;
+		int ret = 0;
+
+		/*
+		 * Check subnode name, must be equal to "hash" or "signature".
+		 * Multiple hash nodes require unique unit node
+		 * names, e.g. hash@1, hash@2, signature@1, etc.
+		 */
+		node_name = fit_get_name(fit, noffset, NULL);
+		if (!strncmp(node_name, FIT_HASH_NODENAME,
+			     strlen(FIT_HASH_NODENAME))) {
+			ret = fit_image_process_hash(fit, image_name, noffset,
+						data, size);
+		} else if (IMAGE_ENABLE_SIGN && keydir &&
+			   !strncmp(node_name, FIT_SIG_NODENAME,
+				strlen(FIT_SIG_NODENAME))) {
+			ret = fit_image_process_sig(keydir, keydest,
+				fit, image_name, noffset, data, size,
+				comment, require_keys);
+		}
+		if (ret)
+			return -1;
+	}
+
+	return 0;
+}
+
+struct strlist {
+	int count;
+	char **strings;
+};
+
+static void strlist_init(struct strlist *list)
+{
+	memset(list, '\0', sizeof(*list));
+}
+
+static void strlist_free(struct strlist *list)
+{
+	int i;
+
+	for (i = 0; i < list->count; i++)
+		free(list->strings[i]);
+	free(list->strings);
+}
+
+static int strlist_add(struct strlist *list, const char *str)
+{
+	char *dup;
+
+	dup = strdup(str);
+	list->strings = realloc(list->strings,
+				(list->count + 1) * sizeof(char *));
+	if (!list || !str)
+		return -1;
+	list->strings[list->count++] = dup;
+
+	return 0;
+}
+
+static const char *fit_config_get_image_list(void *fit, int noffset,
+		int *lenp, int *allow_missingp)
+{
+	static const char default_list[] = FIT_KERNEL_PROP "\0"
+			FIT_FDT_PROP;
+	const char *prop;
+
+	/* If there is an "image" property, use that */
+	prop = fdt_getprop(fit, noffset, "sign-images", lenp);
+	if (prop) {
+		*allow_missingp = 0;
+		return *lenp ? prop : NULL;
+	}
+
+	/* Default image list */
+	*allow_missingp = 1;
+	*lenp = sizeof(default_list);
+
+	return default_list;
+}
+
+static int fit_config_get_hash_list(void *fit, int conf_noffset,
+				    int sig_offset, struct strlist *node_inc)
+{
+	int allow_missing;
+	const char *prop, *iname, *end;
+	const char *conf_name, *sig_name;
+	char name[200], path[200];
+	int image_count;
+	int ret, len;
+
+	conf_name = fit_get_name(fit, conf_noffset, NULL);
+	sig_name = fit_get_name(fit, sig_offset, NULL);
+
+	/*
+	 * Build a list of nodes we need to hash. We always need the root
+	 * node and the configuration.
+	 */
+	strlist_init(node_inc);
+	snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name);
+	if (strlist_add(node_inc, "/") ||
+	    strlist_add(node_inc, name))
+		goto err_mem;
+
+	/* Get a list of images that we intend to sign */
+	prop = fit_config_get_image_list(fit, conf_noffset, &len,
+					&allow_missing);
+	if (!prop)
+		return 0;
+
+	/* Locate the images */
+	end = prop + len;
+	image_count = 0;
+	for (iname = prop; iname < end; iname += strlen(iname) + 1) {
+		int noffset;
+		int image_noffset;
+		int hash_count;
+
+		image_noffset = fit_conf_get_prop_node(fit, conf_noffset,
+						       iname);
+		if (image_noffset < 0) {
+			printf("Failed to find image '%s' in  configuration '%s/%s'\n",
+			       iname, conf_name, sig_name);
+			if (allow_missing)
+				continue;
+
+			return -ENOENT;
+		}
+
+		ret = fdt_get_path(fit, image_noffset, path, sizeof(path));
+		if (ret < 0)
+			goto err_path;
+		if (strlist_add(node_inc, path))
+			goto err_mem;
+
+		snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH,
+			 conf_name);
+
+		/* Add all this image's hashes */
+		hash_count = 0;
+		for (noffset = fdt_first_subnode(fit, image_noffset);
+		     noffset >= 0;
+		     noffset = fdt_next_subnode(fit, noffset)) {
+			const char *name = fit_get_name(fit, noffset, NULL);
+
+			if (strncmp(name, FIT_HASH_NODENAME,
+				    strlen(FIT_HASH_NODENAME)))
+				continue;
+			ret = fdt_get_path(fit, noffset, path, sizeof(path));
+			if (ret < 0)
+				goto err_path;
+			if (strlist_add(node_inc, path))
+				goto err_mem;
+			hash_count++;
+		}
+
+		if (!hash_count) {
+			printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n",
+			       conf_name, sig_name, iname);
+			return -ENOMSG;
+		}
+
+		image_count++;
+	}
+
+	if (!image_count) {
+		printf("Failed to find any images for configuration '%s/%s'\n",
+		       conf_name, sig_name);
+		return -ENOMSG;
+	}
+
+	return 0;
+
+err_mem:
+	printf("Out of memory processing configuration '%s/%s'\n", conf_name,
+	       sig_name);
+	return -ENOMEM;
+
+err_path:
+	printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n",
+	       iname, conf_name, sig_name, fdt_strerror(ret));
+	return -ENOENT;
+}
+
+static int fit_config_get_data(void *fit, int conf_noffset, int noffset,
+		struct image_region **regionp, int *region_countp,
+		char **region_propp, int *region_proplen)
+{
+	char * const exc_prop[] = {"data"};
+	struct strlist node_inc;
+	struct image_region *region;
+	struct fdt_region fdt_regions[100];
+	const char *conf_name, *sig_name;
+	char path[200];
+	int count, i;
+	char *region_prop;
+	int ret, len;
+
+	conf_name = fit_get_name(fit, conf_noffset, NULL);
+	sig_name = fit_get_name(fit, conf_noffset, NULL);
+	debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name);
+
+	/* Get a list of nodes we want to hash */
+	ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc);
+	if (ret)
+		return ret;
+
+	/* Get a list of regions to hash */
+	count = fdt_find_regions(fit, node_inc.strings, node_inc.count,
+			exc_prop, ARRAY_SIZE(exc_prop),
+			fdt_regions, ARRAY_SIZE(fdt_regions),
+			path, sizeof(path), 1);
+	if (count < 0) {
+		printf("Failed to hash configuration '%s/%s': %s\n", conf_name,
+		       sig_name, fdt_strerror(ret));
+		return -EIO;
+	}
+	if (count == 0) {
+		printf("No data to hash for configuration '%s/%s': %s\n",
+		       conf_name, sig_name, fdt_strerror(ret));
+		return -EINVAL;
+	}
+
+	/* Build our list of data blocks */
+	region = fit_region_make_list(fit, fdt_regions, count, NULL);
+	if (!region) {
+		printf("Out of memory hashing configuration '%s/%s'\n",
+		       conf_name, sig_name);
+		return -ENOMEM;
+	}
+
+	/* Create a list of all hashed properties */
+	debug("Hash nodes:\n");
+	for (i = len = 0; i < node_inc.count; i++) {
+		debug("   %s\n", node_inc.strings[i]);
+		len += strlen(node_inc.strings[i]) + 1;
+	}
+	region_prop = malloc(len);
+	if (!region_prop) {
+		printf("Out of memory setting up regions for configuration '%s/%s'\n",
+		       conf_name, sig_name);
+		return -ENOMEM;
+	}
+	for (i = len = 0; i < node_inc.count;
+	     len += strlen(node_inc.strings[i]) + 1, i++)
+		strcpy(region_prop + len, node_inc.strings[i]);
+	strlist_free(&node_inc);
+
+	*region_countp = count;
+	*regionp = region;
+	*region_propp = region_prop;
+	*region_proplen = len;
+
+	return 0;
+}
+
+static int fit_config_process_sig(const char *keydir, void *keydest,
+		void *fit, const char *conf_name, int conf_noffset,
+		int noffset, const char *comment, int require_keys)
+{
+	struct image_sign_info info;
+	const char *node_name;
+	struct image_region *region;
+	char *region_prop;
+	int region_proplen;
+	int region_count;
+	uint8_t *value;
+	uint value_len;
+	int ret;
+
+	node_name = fit_get_name(fit, noffset, NULL);
+	if (fit_config_get_data(fit, conf_noffset, noffset, &region,
+				&region_count, &region_prop, &region_proplen))
+		return -1;
+
+	if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset,
+				require_keys ? "conf" : NULL))
+		return -1;
+
+	ret = info.algo->sign(&info, region, region_count, &value, &value_len);
+	free(region);
+	if (ret) {
+		printf("Failed to sign '%s' signature node in '%s' conf node\n",
+		       node_name, conf_name);
+
+		/* We allow keys to be missing */
+		if (ret == -ENOENT)
+			return 0;
+		return -1;
+	}
+
+	if (fit_image_write_sig(fit, noffset, value, value_len, comment,
+				region_prop, region_proplen)) {
+		printf("Can't write signature for '%s' signature node in '%s' conf node\n",
+		       node_name, conf_name);
+		return -1;
+	}
+	free(value);
+	free(region_prop);
+
+	/* Get keyname again, as FDT has changed and invalidated our pointer */
+	info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+
+	/* Write the public key into the supplied FDT file */
+	if (keydest && info.algo->add_verify_data(&info, keydest)) {
+		printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
+		       node_name, conf_name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int fit_config_add_verification_data(const char *keydir, void *keydest,
+		void *fit, int conf_noffset, const char *comment,
+		int require_keys)
+{
+	const char *conf_name;
+	int noffset;
+
+	conf_name = fit_get_name(fit, conf_noffset, NULL);
+
+	/* Process all hash subnodes of the configuration node */
+	for (noffset = fdt_first_subnode(fit, conf_noffset);
+	     noffset >= 0;
+	     noffset = fdt_next_subnode(fit, noffset)) {
+		const char *node_name;
+		int ret = 0;
+
+		node_name = fit_get_name(fit, noffset, NULL);
+		if (!strncmp(node_name, FIT_SIG_NODENAME,
+			     strlen(FIT_SIG_NODENAME))) {
+			ret = fit_config_process_sig(keydir, keydest,
+				fit, conf_name, conf_noffset, noffset, comment,
+				require_keys);
+		}
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
+			      const char *comment, int require_keys)
+{
+	int images_noffset, confs_noffset;
+	int noffset;
+	int ret;
+
+	/* Find images parent node offset */
+	images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+	if (images_noffset < 0) {
+		printf("Can't find images parent node '%s' (%s)\n",
+		       FIT_IMAGES_PATH, fdt_strerror(images_noffset));
+		return images_noffset;
+	}
+
+	/* Process its subnodes, print out component images details */
+	for (noffset = fdt_first_subnode(fit, images_noffset);
+	     noffset >= 0;
+	     noffset = fdt_next_subnode(fit, noffset)) {
+		/*
+		 * Direct child node of the images parent node,
+		 * i.e. component image node.
+		 */
+		ret = fit_image_add_verification_data(keydir, keydest,
+				fit, noffset, comment, require_keys);
+		if (ret)
+			return ret;
+	}
+
+	/* If there are no keys, we can't sign configurations */
+	if (!IMAGE_ENABLE_SIGN || !keydir)
+		return 0;
+
+	/* Find configurations parent node offset */
+	confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
+	if (confs_noffset < 0) {
+		printf("Can't find images parent node '%s' (%s)\n",
+		       FIT_IMAGES_PATH, fdt_strerror(confs_noffset));
+		return -ENOENT;
+	}
+
+	/* Process its subnodes, print out component images details */
+	for (noffset = fdt_first_subnode(fit, confs_noffset);
+	     noffset >= 0;
+	     noffset = fdt_next_subnode(fit, noffset)) {
+		ret = fit_config_add_verification_data(keydir, keydest,
+						       fit, noffset, comment,
+						       require_keys);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
diff --git a/marvell/uboot/tools/imagetool.c b/marvell/uboot/tools/imagetool.c
new file mode 100644
index 0000000..29d2189
--- /dev/null
+++ b/marvell/uboot/tools/imagetool.c
@@ -0,0 +1,58 @@
+/*
+ * (C) Copyright 2013
+ *
+ * Written by Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "imagetool.h"
+
+/*
+ * Callback function to register a image type within a tool
+ */
+static imagetool_register_t register_func;
+
+/*
+ * register_image_tool -
+ *
+ * The tool provides its own registration function in order to all image
+ * types initialize themselves.
+ */
+void register_image_tool(imagetool_register_t image_register)
+{
+	/*
+	 * Save the image tool callback function. It will be used to register
+	 * image types within that tool
+	 */
+	register_func = image_register;
+
+	/* Init Freescale PBL Boot image generation/list support */
+	init_pbl_image_type();
+	/* Init Kirkwood Boot image generation/list support */
+	init_kwb_image_type();
+	/* Init Freescale imx Boot image generation/list support */
+	init_imx_image_type();
+	/* Init Freescale mxs Boot image generation/list support */
+	init_mxs_image_type();
+	/* Init FIT image generation/list support */
+	init_fit_image_type();
+	/* Init TI OMAP Boot image generation/list support */
+	init_omap_image_type();
+	/* Init Default image generation/list support */
+	init_default_image_type();
+	/* Init Davinci UBL support */
+	init_ubl_image_type();
+	/* Init Davinci AIS support */
+	init_ais_image_type();
+}
+
+/*
+ * register_image_type -
+ *
+ * Register a image type within a tool
+ */
+void register_image_type(struct image_type_params *tparams)
+{
+	register_func(tparams);
+}
diff --git a/marvell/uboot/tools/imagetool.h b/marvell/uboot/tools/imagetool.h
new file mode 100644
index 0000000..c2c9aea
--- /dev/null
+++ b/marvell/uboot/tools/imagetool.h
@@ -0,0 +1,173 @@
+/*
+ * (C) Copyright 2013
+ *
+ * Written by Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _IMAGETOOL_H_
+#define _IMAGETOOL_H_
+
+#include "os_support.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <sha1.h>
+#include "fdt_host.h"
+
+#define ARRAY_SIZE(x)		(sizeof(x) / sizeof((x)[0]))
+
+#define IH_ARCH_DEFAULT		IH_ARCH_INVALID
+
+/*
+ * This structure defines all such variables those are initialized by
+ * mkimage and dumpimage main core and need to be referred by image
+ * type specific functions
+ */
+struct image_tool_params {
+	int dflag;
+	int eflag;
+	int fflag;
+	int iflag;
+	int lflag;
+	int pflag;
+	int vflag;
+	int xflag;
+	int skipcpy;
+	int os;
+	int arch;
+	int type;
+	int comp;
+	char *dtc;
+	unsigned int addr;
+	unsigned int ep;
+	char *imagename;
+	char *imagename2;
+	char *datafile;
+	char *imagefile;
+	char *cmdname;
+	const char *outfile;	/* Output filename */
+	const char *keydir;	/* Directory holding private keys */
+	const char *keydest;	/* Destination .dtb for public key */
+	const char *comment;	/* Comment to add to signature node */
+	int require_keys;	/* 1 to mark signing keys as 'required' */
+};
+
+/*
+ * image type specific variables and callback functions
+ */
+struct image_type_params {
+	/* name is an identification tag string for added support */
+	char *name;
+	/*
+	 * header size is local to the specific image type to be supported,
+	 * mkimage core treats this as number of bytes
+	 */
+	uint32_t header_size;
+	/* Image type header pointer */
+	void *hdr;
+	/*
+	 * There are several arguments that are passed on the command line
+	 * and are registered as flags in image_tool_params structure.
+	 * This callback function can be used to check the passed arguments
+	 * are in-lined with the image type to be supported
+	 *
+	 * Returns 1 if parameter check is successful
+	 */
+	int (*check_params) (struct image_tool_params *);
+	/*
+	 * This function is used by list command (i.e. mkimage -l <filename>)
+	 * image type verification code must be put here
+	 *
+	 * Returns 0 if image header verification is successful
+	 * otherwise, returns respective negative error codes
+	 */
+	int (*verify_header) (unsigned char *, int, struct image_tool_params *);
+	/* Prints image information abstracting from image header */
+	void (*print_header) (const void *);
+	/*
+	 * The header or image contents need to be set as per image type to
+	 * be generated using this callback function.
+	 * further output file post processing (for ex. checksum calculation,
+	 * padding bytes etc..) can also be done in this callback function.
+	 */
+	void (*set_header) (void *, struct stat *, int,
+					struct image_tool_params *);
+	/*
+	 * This function is used by the command to retrieve a data file from
+	 * the image (i.e. dumpimage -i <image> -p <position> <data_file>).
+	 * Thus the code to extract a file from an image must be put here.
+	 *
+	 * Returns 0 if the file was successfully retrieved from the image,
+	 * or a negative value on error.
+	 */
+	int (*extract_datafile) (void *, struct image_tool_params *);
+	/*
+	 * Some image generation support for ex (default image type) supports
+	 * more than one type_ids, this callback function is used to check
+	 * whether input (-T <image_type>) is supported by registered image
+	 * generation/list low level code
+	 */
+	int (*check_image_type) (uint8_t);
+	/* This callback function will be executed if fflag is defined */
+	int (*fflag_handle) (struct image_tool_params *);
+	/*
+	 * This callback function will be executed for variable size record
+	 * It is expected to build this header in memory and return its length
+	 * and a pointer to it by using image_type_params.header_size and
+	 * image_type_params.hdr. The return value shall indicate if an
+	 * additional padding should be used when copying the data image
+	 * by returning the padding length.
+	 */
+	int (*vrec_header) (struct image_tool_params *,
+		struct image_type_params *);
+	/* pointer to the next registered entry in linked list */
+	struct image_type_params *next;
+};
+
+/*
+ * Tool registration function.
+ */
+typedef void (*imagetool_register_t)(struct image_type_params *);
+
+/*
+ * Initializes all image types with the given registration callback
+ * function.
+ * An image tool uses this function to initialize all image types.
+ */
+void register_image_tool(imagetool_register_t image_register);
+
+/*
+ * Register a image type within a tool.
+ * An image type uses this function to register itself within
+ * all tools.
+ */
+void register_image_type(struct image_type_params *tparams);
+
+/*
+ * There is a c file associated with supported image type low level code
+ * for ex. default_image.c, fit_image.c
+ * init_xxx_type() is the only function referred by image tool core to avoid
+ * a single lined header file, you can define them here
+ *
+ * Supported image types init functions
+ */
+void init_default_image_type(void);
+void init_pbl_image_type(void);
+void init_ais_image_type(void);
+void init_kwb_image_type(void);
+void init_imx_image_type(void);
+void init_mxs_image_type(void);
+void init_fit_image_type(void);
+void init_ubl_image_type(void);
+void init_omap_image_type(void);
+
+void pbl_load_uboot(int fd, struct image_tool_params *mparams);
+
+#endif /* _IMAGETOOL_H_ */
diff --git a/marvell/uboot/tools/img2brec.sh b/marvell/uboot/tools/img2brec.sh
new file mode 100755
index 0000000..0fcdba2
--- /dev/null
+++ b/marvell/uboot/tools/img2brec.sh
Binary files differ
diff --git a/marvell/uboot/tools/img2srec.c b/marvell/uboot/tools/img2srec.c
new file mode 100644
index 0000000..ec76964
--- /dev/null
+++ b/marvell/uboot/tools/img2srec.c
@@ -0,0 +1,372 @@
+/*************************************************************************
+|  COPYRIGHT (c) 2000 BY ABATRON AG
+|*************************************************************************
+|
+|  PROJECT NAME: Linux Image to S-record Conversion Utility
+|  FILENAME    : img2srec.c
+|
+|  COMPILER    : GCC
+|
+|  TARGET OS   : LINUX / UNIX
+|  TARGET HW   : -
+|
+|  PROGRAMMER  : Abatron / RD
+|  CREATION    : 07.07.00
+|
+|*************************************************************************
+|
+|  DESCRIPTION :
+|
+|  Utility to convert a Linux Boot Image to S-record:
+|  ==================================================
+|
+|  This command line utility can be used to convert a Linux boot image
+|  (zimage.initrd) to S-Record format used for flash programming.
+|  This conversion takes care of the special sections "IMAGE" and INITRD".
+|
+|  img2srec [-o offset] image > image.srec
+|
+|
+|  Build the utility:
+|  ==================
+|
+|  To build the utility use GCC as follows:
+|
+|  gcc img2srec.c -o img2srec
+|
+|
+|*************************************************************************
+|
+|
+|  UPDATES     :
+|
+|  DATE      NAME  CHANGES
+|  -----------------------------------------------------------
+|  Latest update
+|
+|  07.07.00  aba   Initial release
+|
+|*************************************************************************/
+
+/*************************************************************************
+|  INCLUDES
+|*************************************************************************/
+
+#include "os_support.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <elf.h>
+#include <unistd.h>
+#include <errno.h>
+
+/*************************************************************************
+|  FUNCTIONS
+|*************************************************************************/
+
+static char* ExtractHex (uint32_t* value,  char* getPtr)
+{
+  uint32_t num;
+  uint32_t digit;
+  uint8_t  c;
+
+  while (*getPtr == ' ') getPtr++;
+  num = 0;
+  for (;;) {
+    c = *getPtr;
+    if      ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
+    else if ((c >= 'A') && (c <= 'F')) digit = (uint32_t)(c - 'A' + 10);
+    else if ((c >= 'a') && (c <= 'f')) digit = (uint32_t)(c - 'a' + 10);
+    else break;
+    num <<= 4;
+    num += digit;
+    getPtr++;
+  } /* for */
+  *value = num;
+  return getPtr;
+} /* ExtractHex */
+
+static char* ExtractDecimal (uint32_t* value,  char* getPtr)
+{
+  uint32_t num;
+  uint32_t digit;
+  uint8_t  c;
+
+  while (*getPtr == ' ') getPtr++;
+  num = 0;
+  for (;;) {
+    c = *getPtr;
+    if      ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
+    else break;
+    num *= 10;
+    num += digit;
+    getPtr++;
+  } /* for */
+  *value = num;
+  return getPtr;
+} /* ExtractDecimal */
+
+
+static void ExtractNumber (uint32_t* value,  char* getPtr)
+{
+  bool  neg = false;;
+
+  while (*getPtr == ' ') getPtr++;
+  if (*getPtr == '-') {
+    neg = true;
+    getPtr++;
+  } /* if */
+  if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) {
+    getPtr +=2;
+    (void)ExtractHex(value, getPtr);
+  } /* if */
+  else {
+    (void)ExtractDecimal(value, getPtr);
+  } /* else */
+  if (neg) *value = -(*value);
+} /* ExtractNumber */
+
+
+static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer)
+{
+  uint16_t x;
+  x = (uint16_t)*buffer++;
+  x = (x<<8) + (uint16_t)*buffer++;
+  *value = x;
+  return buffer;
+} /* ExtractWord */
+
+
+static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer)
+{
+  uint32_t x;
+  x = (uint32_t)*buffer++;
+  x = (x<<8) + (uint32_t)*buffer++;
+  x = (x<<8) + (uint32_t)*buffer++;
+  x = (x<<8) + (uint32_t)*buffer++;
+  *value = x;
+  return buffer;
+} /* ExtractLong */
+
+
+static uint8_t* ExtractBlock(uint16_t count, uint8_t* data, uint8_t* buffer)
+{
+  while (count--) *data++ = *buffer++;
+  return buffer;
+} /* ExtractBlock */
+
+
+static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum)
+{
+  uint16_t  temp;
+
+  static  char ByteToHex[] = "0123456789ABCDEF";
+
+  *pCheckSum += value;
+  temp  = value / 16;
+  *pa++ = ByteToHex[temp];
+  temp  = value % 16;
+  *pa++ = ByteToHex[temp];
+  return pa;
+}
+
+
+static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr,
+			  const uint8_t* data, int nCount)
+{
+  uint16_t  addrLen;
+  uint16_t  sRLen;
+  uint16_t  checkSum;
+  uint16_t  i;
+
+  switch (sType) {
+  case 0:
+  case 1:
+  case 9:
+    addrLen = 2;
+    break;
+  case 2:
+  case 8:
+    addrLen = 3;
+    break;
+  case 3:
+  case 7:
+    addrLen = 4;
+    break;
+  default:
+    return pa;
+  } /* switch */
+
+  *pa++ = 'S';
+  *pa++ = (char)(sType + '0');
+  sRLen = addrLen + nCount + 1;
+  checkSum = 0;
+  pa = WriteHex(pa, (uint8_t)sRLen, &checkSum);
+
+  /* Write address field */
+  for (i = 1; i <= addrLen; i++) {
+    pa = WriteHex(pa, (uint8_t)(addr >> (8 * (addrLen - i))), &checkSum);
+  } /* for */
+
+  /* Write code/data fields */
+  for (i = 0; i < nCount; i++) {
+    pa = WriteHex(pa, *data++, &checkSum);
+  } /* for */
+
+  /* Write checksum field */
+  checkSum = ~checkSum;
+  pa = WriteHex(pa, (uint8_t)checkSum, &checkSum);
+  *pa++ = '\0';
+  return pa;
+}
+
+
+static void ConvertELF(char* fileName, uint32_t loadOffset)
+{
+  FILE*         file;
+  int           i;
+  int           rxCount;
+  uint8_t          rxBlock[1024];
+  uint32_t         loadSize;
+  uint32_t         firstAddr;
+  uint32_t         loadAddr;
+  uint32_t         loadDiff = 0;
+  Elf32_Ehdr    elfHeader;
+  Elf32_Shdr    sectHeader[32];
+  uint8_t*         getPtr;
+  char          srecLine[128];
+  char		*hdr_name;
+
+
+  /* open file */
+  if ((file = fopen(fileName,"rb")) == NULL) {
+    fprintf (stderr, "Can't open %s: %s\n", fileName, strerror(errno));
+    return;
+  } /* if */
+
+  /* read ELF header */
+  rxCount = fread(rxBlock, 1, sizeof elfHeader, file);
+  getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock);
+  getPtr = ExtractWord(&elfHeader.e_type, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_machine, getPtr);
+  getPtr = ExtractLong((uint32_t *)&elfHeader.e_version, getPtr);
+  getPtr = ExtractLong((uint32_t *)&elfHeader.e_entry, getPtr);
+  getPtr = ExtractLong((uint32_t *)&elfHeader.e_phoff, getPtr);
+  getPtr = ExtractLong((uint32_t *)&elfHeader.e_shoff, getPtr);
+  getPtr = ExtractLong((uint32_t *)&elfHeader.e_flags, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_phnum, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_shnum, getPtr);
+  getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr);
+  if (    (rxCount              != sizeof elfHeader)
+       || (elfHeader.e_ident[0] != ELFMAG0)
+       || (elfHeader.e_ident[1] != ELFMAG1)
+       || (elfHeader.e_ident[2] != ELFMAG2)
+       || (elfHeader.e_ident[3] != ELFMAG3)
+       || (elfHeader.e_type     != ET_EXEC)
+     ) {
+    fclose(file);
+    fprintf (stderr, "*** illegal file format\n");
+    return;
+  } /* if */
+
+  /* read all section headers */
+  fseek(file, elfHeader.e_shoff, SEEK_SET);
+  for (i = 0; i < elfHeader.e_shnum; i++) {
+    rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file);
+    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_name, rxBlock);
+    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_type, getPtr);
+    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_flags, getPtr);
+    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addr, getPtr);
+    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_offset, getPtr);
+    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_size, getPtr);
+    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_link, getPtr);
+    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_info, getPtr);
+    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addralign, getPtr);
+    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_entsize, getPtr);
+    if (rxCount != sizeof sectHeader[0]) {
+      fclose(file);
+      fprintf (stderr, "*** illegal file format\n");
+      return;
+    } /* if */
+  } /* for */
+
+  if ((hdr_name = strrchr(fileName, '/')) == NULL) {
+    hdr_name = fileName;
+  } else {
+    ++hdr_name;
+  }
+  /* write start record */
+  (void)BuildSRecord(srecLine, 0, 0, (uint8_t *)hdr_name, strlen(hdr_name));
+  printf("%s\r\n",srecLine);
+
+  /* write data records */
+  firstAddr = ~0;
+  loadAddr  =  0;
+  for (i = 0; i < elfHeader.e_shnum; i++) {
+    if (    (sectHeader[i].sh_type == SHT_PROGBITS)
+	 && (sectHeader[i].sh_size != 0)
+	 ) {
+      loadSize = sectHeader[i].sh_size;
+      if (sectHeader[i].sh_flags != 0) {
+	loadAddr = sectHeader[i].sh_addr;
+	loadDiff = loadAddr - sectHeader[i].sh_offset;
+      } /* if */
+      else {
+	loadAddr = sectHeader[i].sh_offset + loadDiff;
+      } /* else */
+
+      if (loadAddr < firstAddr)
+	firstAddr = loadAddr;
+
+      /* build s-records */
+      loadSize = sectHeader[i].sh_size;
+      fseek(file, sectHeader[i].sh_offset, SEEK_SET);
+      while (loadSize) {
+	rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file);
+	if (rxCount < 0) {
+	  fclose(file);
+	  fprintf (stderr, "*** illegal file format\n");
+	return;
+	} /* if */
+	(void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount);
+	loadSize -= rxCount;
+	loadAddr += rxCount;
+	printf("%s\r\n",srecLine);
+      } /* while */
+    } /* if */
+  } /* for */
+
+  /* add end record */
+  (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0);
+  printf("%s\r\n",srecLine);
+  fclose(file);
+} /* ConvertELF */
+
+
+/*************************************************************************
+|  MAIN
+|*************************************************************************/
+
+int main( int argc, char *argv[ ])
+{
+  uint32_t offset;
+
+  if (argc == 2) {
+    ConvertELF(argv[1], 0);
+  } /* if */
+  else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) {
+    ExtractNumber(&offset, argv[2]);
+    ConvertELF(argv[3], offset);
+  } /* if */
+  else {
+    fprintf (stderr, "Usage: img2srec [-o offset] <image>\n");
+  } /* if */
+
+  return 0;
+} /* main */
diff --git a/marvell/uboot/tools/imximage.c b/marvell/uboot/tools/imximage.c
new file mode 100644
index 0000000..18dc051
--- /dev/null
+++ b/marvell/uboot/tools/imximage.c
@@ -0,0 +1,705 @@
+/*
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "imagetool.h"
+#include <image.h>
+#include "imximage.h"
+
+#define UNDEFINED 0xFFFFFFFF
+
+/*
+ * Supported commands for configuration file
+ */
+static table_entry_t imximage_cmds[] = {
+	{CMD_BOOT_FROM,         "BOOT_FROM",            "boot command",	  },
+	{CMD_BOOT_OFFSET,       "BOOT_OFFSET",          "Boot offset",	  },
+	{CMD_DATA,              "DATA",                 "Reg Write Data", },
+	{CMD_CSF,               "CSF",           "Command Sequence File", },
+	{CMD_IMAGE_VERSION,     "IMAGE_VERSION",        "image version",  },
+	{-1,                    "",                     "",	          },
+};
+
+/*
+ * Supported Boot options for configuration file
+ * this is needed to set the correct flash offset
+ */
+static table_entry_t imximage_boot_offset[] = {
+	{FLASH_OFFSET_ONENAND,	"onenand",	"OneNAND Flash",},
+	{FLASH_OFFSET_NAND,	"nand",		"NAND Flash",	},
+	{FLASH_OFFSET_NOR,	"nor",		"NOR Flash",	},
+	{FLASH_OFFSET_SATA,	"sata",		"SATA Disk",	},
+	{FLASH_OFFSET_SD,	"sd",		"SD Card",	},
+	{FLASH_OFFSET_SPI,	"spi",		"SPI Flash",	},
+	{-1,			"",		"Invalid",	},
+};
+
+/*
+ * Supported Boot options for configuration file
+ * this is needed to determine the initial load size
+ */
+static table_entry_t imximage_boot_loadsize[] = {
+	{FLASH_LOADSIZE_ONENAND,	"onenand",	"OneNAND Flash",},
+	{FLASH_LOADSIZE_NAND,		"nand",		"NAND Flash",	},
+	{FLASH_LOADSIZE_NOR,		"nor",		"NOR Flash",	},
+	{FLASH_LOADSIZE_SATA,		"sata",		"SATA Disk",	},
+	{FLASH_LOADSIZE_SD,		"sd",		"SD Card",	},
+	{FLASH_LOADSIZE_SPI,		"spi",		"SPI Flash",	},
+	{-1,				"",		"Invalid",	},
+};
+
+/*
+ * IMXIMAGE version definition for i.MX chips
+ */
+static table_entry_t imximage_versions[] = {
+	{IMXIMAGE_V1,	"",	" (i.MX25/35/51 compatible)", },
+	{IMXIMAGE_V2,	"",	" (i.MX53/6 compatible)",     },
+	{-1,            "",     " (Invalid)",                 },
+};
+
+static struct imx_header imximage_header;
+static uint32_t imximage_version;
+/*
+ * Image Vector Table Offset
+ * Initialized to a wrong not 4-bytes aligned address to
+ * check if it is was set by the cfg file.
+ */
+static uint32_t imximage_ivt_offset = UNDEFINED;
+static uint32_t imximage_csf_size = UNDEFINED;
+/* Initial Load Region Size */
+static uint32_t imximage_init_loadsize;
+
+static set_dcd_val_t set_dcd_val;
+static set_dcd_rst_t set_dcd_rst;
+static set_imx_hdr_t set_imx_hdr;
+static uint32_t max_dcd_entries;
+static uint32_t *header_size_ptr;
+static uint32_t *csf_ptr;
+
+static uint32_t get_cfg_value(char *token, char *name,  int linenr)
+{
+	char *endptr;
+	uint32_t value;
+
+	errno = 0;
+	value = strtoul(token, &endptr, 16);
+	if (errno || (token == endptr)) {
+		fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n",
+			name,  linenr, token);
+		exit(EXIT_FAILURE);
+	}
+	return value;
+}
+
+static uint32_t detect_imximage_version(struct imx_header *imx_hdr)
+{
+	imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1;
+	imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2;
+	flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr;
+	flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr;
+
+	/* Try to detect V1 */
+	if ((fhdr_v1->app_code_barker == APP_CODE_BARKER) &&
+		(hdr_v1->dcd_table.preamble.barker == DCD_BARKER))
+		return IMXIMAGE_V1;
+
+	/* Try to detect V2 */
+	if ((fhdr_v2->header.tag == IVT_HEADER_TAG) &&
+		(hdr_v2->dcd_table.header.tag == DCD_HEADER_TAG))
+		return IMXIMAGE_V2;
+
+	return IMXIMAGE_VER_INVALID;
+}
+
+static void err_imximage_version(int version)
+{
+	fprintf(stderr,
+		"Error: Unsupported imximage version:%d\n", version);
+
+	exit(EXIT_FAILURE);
+}
+
+static void set_dcd_val_v1(struct imx_header *imxhdr, char *name, int lineno,
+					int fld, uint32_t value, uint32_t off)
+{
+	dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table;
+
+	switch (fld) {
+	case CFG_REG_SIZE:
+		/* Byte, halfword, word */
+		if ((value != 1) && (value != 2) && (value != 4)) {
+			fprintf(stderr, "Error: %s[%d] - "
+				"Invalid register size " "(%d)\n",
+				name, lineno, value);
+			exit(EXIT_FAILURE);
+		}
+		dcd_v1->addr_data[off].type = value;
+		break;
+	case CFG_REG_ADDRESS:
+		dcd_v1->addr_data[off].addr = value;
+		break;
+	case CFG_REG_VALUE:
+		dcd_v1->addr_data[off].value = value;
+		break;
+	default:
+		break;
+
+	}
+}
+
+static void set_dcd_val_v2(struct imx_header *imxhdr, char *name, int lineno,
+					int fld, uint32_t value, uint32_t off)
+{
+	dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table;
+
+	switch (fld) {
+	case CFG_REG_ADDRESS:
+		dcd_v2->addr_data[off].addr = cpu_to_be32(value);
+		break;
+	case CFG_REG_VALUE:
+		dcd_v2->addr_data[off].value = cpu_to_be32(value);
+		break;
+	default:
+		break;
+
+	}
+}
+
+/*
+ * Complete setting up the rest field of DCD of V1
+ * such as barker code and DCD data length.
+ */
+static void set_dcd_rst_v1(struct imx_header *imxhdr, uint32_t dcd_len,
+						char *name, int lineno)
+{
+	dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table;
+
+	dcd_v1->preamble.barker = DCD_BARKER;
+	dcd_v1->preamble.length = dcd_len * sizeof(dcd_type_addr_data_t);
+}
+
+/*
+ * Complete setting up the reset field of DCD of V2
+ * such as DCD tag, version, length, etc.
+ */
+static void set_dcd_rst_v2(struct imx_header *imxhdr, uint32_t dcd_len,
+						char *name, int lineno)
+{
+	dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table;
+
+	dcd_v2->header.tag = DCD_HEADER_TAG;
+	dcd_v2->header.length = cpu_to_be16(
+			dcd_len * sizeof(dcd_addr_data_t) + 8);
+	dcd_v2->header.version = DCD_VERSION;
+	dcd_v2->write_dcd_command.tag = DCD_COMMAND_TAG;
+	dcd_v2->write_dcd_command.length = cpu_to_be16(
+			dcd_len * sizeof(dcd_addr_data_t) + 4);
+	dcd_v2->write_dcd_command.param = DCD_COMMAND_PARAM;
+}
+
+static void set_imx_hdr_v1(struct imx_header *imxhdr, uint32_t dcd_len,
+		uint32_t entry_point, uint32_t flash_offset)
+{
+	imx_header_v1_t *hdr_v1 = &imxhdr->header.hdr_v1;
+	flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr;
+	dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table;
+	uint32_t hdr_base;
+	uint32_t header_length = (((char *)&dcd_v1->addr_data[dcd_len].addr)
+			- ((char *)imxhdr));
+
+	/* Set magic number */
+	fhdr_v1->app_code_barker = APP_CODE_BARKER;
+
+	/* TODO: check i.MX image V1 handling, for now use 'old' style */
+	hdr_base = entry_point - 4096;
+	fhdr_v1->app_dest_ptr = hdr_base - flash_offset;
+	fhdr_v1->app_code_jump_vector = entry_point;
+
+	fhdr_v1->dcd_ptr_ptr = hdr_base + offsetof(flash_header_v1_t, dcd_ptr);
+	fhdr_v1->dcd_ptr = hdr_base + offsetof(imx_header_v1_t, dcd_table);
+
+	/* Security feature are not supported */
+	fhdr_v1->app_code_csf = 0;
+	fhdr_v1->super_root_key = 0;
+	header_size_ptr = (uint32_t *)(((char *)imxhdr) + header_length - 4);
+}
+
+static void set_imx_hdr_v2(struct imx_header *imxhdr, uint32_t dcd_len,
+		uint32_t entry_point, uint32_t flash_offset)
+{
+	imx_header_v2_t *hdr_v2 = &imxhdr->header.hdr_v2;
+	flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr;
+	uint32_t hdr_base;
+
+	/* Set magic number */
+	fhdr_v2->header.tag = IVT_HEADER_TAG; /* 0xD1 */
+	fhdr_v2->header.length = cpu_to_be16(sizeof(flash_header_v2_t));
+	fhdr_v2->header.version = IVT_VERSION; /* 0x40 */
+
+	fhdr_v2->entry = entry_point;
+	fhdr_v2->reserved1 = fhdr_v2->reserved2 = 0;
+	hdr_base = entry_point - imximage_init_loadsize +
+		flash_offset;
+	fhdr_v2->self = hdr_base;
+	fhdr_v2->dcd_ptr = hdr_base + offsetof(imx_header_v2_t, dcd_table);
+	fhdr_v2->boot_data_ptr = hdr_base
+			+ offsetof(imx_header_v2_t, boot_data);
+	hdr_v2->boot_data.start = entry_point - imximage_init_loadsize;
+
+	fhdr_v2->csf = 0;
+
+	header_size_ptr = &hdr_v2->boot_data.size;
+	csf_ptr = &fhdr_v2->csf;
+}
+
+static void set_hdr_func(void)
+{
+	switch (imximage_version) {
+	case IMXIMAGE_V1:
+		set_dcd_val = set_dcd_val_v1;
+		set_dcd_rst = set_dcd_rst_v1;
+		set_imx_hdr = set_imx_hdr_v1;
+		max_dcd_entries = MAX_HW_CFG_SIZE_V1;
+		break;
+	case IMXIMAGE_V2:
+		set_dcd_val = set_dcd_val_v2;
+		set_dcd_rst = set_dcd_rst_v2;
+		set_imx_hdr = set_imx_hdr_v2;
+		max_dcd_entries = MAX_HW_CFG_SIZE_V2;
+		break;
+	default:
+		err_imximage_version(imximage_version);
+		break;
+	}
+}
+
+static void print_hdr_v1(struct imx_header *imx_hdr)
+{
+	imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1;
+	flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr;
+	dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table;
+	uint32_t size, length, ver;
+
+	size = dcd_v1->preamble.length;
+	if (size > (MAX_HW_CFG_SIZE_V1 * sizeof(dcd_type_addr_data_t))) {
+		fprintf(stderr,
+			"Error: Image corrupt DCD size %d exceed maximum %d\n",
+			(uint32_t)(size / sizeof(dcd_type_addr_data_t)),
+			MAX_HW_CFG_SIZE_V1);
+		exit(EXIT_FAILURE);
+	}
+
+	length = dcd_v1->preamble.length / sizeof(dcd_type_addr_data_t);
+	ver = detect_imximage_version(imx_hdr);
+
+	printf("Image Type:   Freescale IMX Boot Image\n");
+	printf("Image Ver:    %x", ver);
+	printf("%s\n", get_table_entry_name(imximage_versions, NULL, ver));
+	printf("Data Size:    ");
+	genimg_print_size(dcd_v1->addr_data[length].type);
+	printf("Load Address: %08x\n", (uint32_t)fhdr_v1->app_dest_ptr);
+	printf("Entry Point:  %08x\n", (uint32_t)fhdr_v1->app_code_jump_vector);
+}
+
+static void print_hdr_v2(struct imx_header *imx_hdr)
+{
+	imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2;
+	flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr;
+	dcd_v2_t *dcd_v2 = &hdr_v2->dcd_table;
+	uint32_t size, version;
+
+	size = be16_to_cpu(dcd_v2->header.length) - 8;
+	if (size > (MAX_HW_CFG_SIZE_V2 * sizeof(dcd_addr_data_t))) {
+		fprintf(stderr,
+			"Error: Image corrupt DCD size %d exceed maximum %d\n",
+			(uint32_t)(size / sizeof(dcd_addr_data_t)),
+			MAX_HW_CFG_SIZE_V2);
+		exit(EXIT_FAILURE);
+	}
+
+	version = detect_imximage_version(imx_hdr);
+
+	printf("Image Type:   Freescale IMX Boot Image\n");
+	printf("Image Ver:    %x", version);
+	printf("%s\n", get_table_entry_name(imximage_versions, NULL, version));
+	printf("Data Size:    ");
+	genimg_print_size(hdr_v2->boot_data.size);
+	printf("Load Address: %08x\n", (uint32_t)fhdr_v2->boot_data_ptr);
+	printf("Entry Point:  %08x\n", (uint32_t)fhdr_v2->entry);
+	if (fhdr_v2->csf && (imximage_ivt_offset != UNDEFINED) &&
+	    (imximage_csf_size != UNDEFINED)) {
+		printf("HAB Blocks:   %08x %08x %08x\n",
+		       (uint32_t)fhdr_v2->self, 0,
+		       hdr_v2->boot_data.size - imximage_ivt_offset -
+		       imximage_csf_size);
+	}
+}
+
+static void parse_cfg_cmd(struct imx_header *imxhdr, int32_t cmd, char *token,
+				char *name, int lineno, int fld, int dcd_len)
+{
+	int value;
+	static int cmd_ver_first = ~0;
+
+	switch (cmd) {
+	case CMD_IMAGE_VERSION:
+		imximage_version = get_cfg_value(token, name, lineno);
+		if (cmd_ver_first == 0) {
+			fprintf(stderr, "Error: %s[%d] - IMAGE_VERSION "
+				"command need be the first before other "
+				"valid command in the file\n", name, lineno);
+			exit(EXIT_FAILURE);
+		}
+		cmd_ver_first = 1;
+		set_hdr_func();
+		break;
+	case CMD_BOOT_FROM:
+		imximage_ivt_offset = get_table_entry_id(imximage_boot_offset,
+					"imximage boot option", token);
+		if (imximage_ivt_offset == -1) {
+			fprintf(stderr, "Error: %s[%d] -Invalid boot device"
+				"(%s)\n", name, lineno, token);
+			exit(EXIT_FAILURE);
+		}
+
+		imximage_init_loadsize =
+			get_table_entry_id(imximage_boot_loadsize,
+					   "imximage boot option", token);
+
+		if (imximage_init_loadsize == -1) {
+			fprintf(stderr,
+				"Error: %s[%d] -Invalid boot device(%s)\n",
+				name, lineno, token);
+			exit(EXIT_FAILURE);
+		}
+
+		/*
+		 * The SOC loads from the storage starting at address 0
+		 * then ensures that the load size contains the offset
+		 */
+		if (imximage_init_loadsize < imximage_ivt_offset)
+			imximage_init_loadsize = imximage_ivt_offset;
+		if (unlikely(cmd_ver_first != 1))
+			cmd_ver_first = 0;
+		break;
+	case CMD_BOOT_OFFSET:
+		imximage_ivt_offset = get_cfg_value(token, name, lineno);
+		if (unlikely(cmd_ver_first != 1))
+			cmd_ver_first = 0;
+		break;
+	case CMD_DATA:
+		value = get_cfg_value(token, name, lineno);
+		(*set_dcd_val)(imxhdr, name, lineno, fld, value, dcd_len);
+		if (unlikely(cmd_ver_first != 1))
+			cmd_ver_first = 0;
+		break;
+	case CMD_CSF:
+		if (imximage_version != 2) {
+			fprintf(stderr,
+				"Error: %s[%d] - CSF only supported for VERSION 2(%s)\n",
+				name, lineno, token);
+			exit(EXIT_FAILURE);
+		}
+		imximage_csf_size = get_cfg_value(token, name, lineno);
+		if (unlikely(cmd_ver_first != 1))
+			cmd_ver_first = 0;
+		break;
+	}
+}
+
+static void parse_cfg_fld(struct imx_header *imxhdr, int32_t *cmd,
+		char *token, char *name, int lineno, int fld, int *dcd_len)
+{
+	int value;
+
+	switch (fld) {
+	case CFG_COMMAND:
+		*cmd = get_table_entry_id(imximage_cmds,
+			"imximage commands", token);
+		if (*cmd < 0) {
+			fprintf(stderr, "Error: %s[%d] - Invalid command"
+			"(%s)\n", name, lineno, token);
+			exit(EXIT_FAILURE);
+		}
+		break;
+	case CFG_REG_SIZE:
+		parse_cfg_cmd(imxhdr, *cmd, token, name, lineno, fld, *dcd_len);
+		break;
+	case CFG_REG_ADDRESS:
+	case CFG_REG_VALUE:
+		if (*cmd != CMD_DATA)
+			return;
+
+		value = get_cfg_value(token, name, lineno);
+		(*set_dcd_val)(imxhdr, name, lineno, fld, value, *dcd_len);
+
+		if (fld == CFG_REG_VALUE) {
+			(*dcd_len)++;
+			if (*dcd_len > max_dcd_entries) {
+				fprintf(stderr, "Error: %s[%d] -"
+					"DCD table exceeds maximum size(%d)\n",
+					name, lineno, max_dcd_entries);
+				exit(EXIT_FAILURE);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+}
+static uint32_t parse_cfg_file(struct imx_header *imxhdr, char *name)
+{
+	FILE *fd = NULL;
+	char *line = NULL;
+	char *token, *saveptr1, *saveptr2;
+	int lineno = 0;
+	int fld;
+	size_t len;
+	int dcd_len = 0;
+	int32_t cmd;
+
+	fd = fopen(name, "r");
+	if (fd == 0) {
+		fprintf(stderr, "Error: %s - Can't open DCD file\n", name);
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * Very simple parsing, line starting with # are comments
+	 * and are dropped
+	 */
+	while ((getline(&line, &len, fd)) > 0) {
+		lineno++;
+
+		token = strtok_r(line, "\r\n", &saveptr1);
+		if (token == NULL)
+			continue;
+
+		/* Check inside the single line */
+		for (fld = CFG_COMMAND, cmd = CMD_INVALID,
+				line = token; ; line = NULL, fld++) {
+			token = strtok_r(line, " \t", &saveptr2);
+			if (token == NULL)
+				break;
+
+			/* Drop all text starting with '#' as comments */
+			if (token[0] == '#')
+				break;
+
+			parse_cfg_fld(imxhdr, &cmd, token, name,
+					lineno, fld, &dcd_len);
+		}
+
+	}
+
+	(*set_dcd_rst)(imxhdr, dcd_len, name, lineno);
+	fclose(fd);
+
+	/* Exit if there is no BOOT_FROM field specifying the flash_offset */
+	if (imximage_ivt_offset == FLASH_OFFSET_UNDEFINED) {
+		fprintf(stderr, "Error: No BOOT_FROM tag in %s\n", name);
+		exit(EXIT_FAILURE);
+	}
+	return dcd_len;
+}
+
+
+static int imximage_check_image_types(uint8_t type)
+{
+	if (type == IH_TYPE_IMXIMAGE)
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+}
+
+static int imximage_verify_header(unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	struct imx_header *imx_hdr = (struct imx_header *) ptr;
+
+	if (detect_imximage_version(imx_hdr) == IMXIMAGE_VER_INVALID)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	return 0;
+}
+
+static void imximage_print_header(const void *ptr)
+{
+	struct imx_header *imx_hdr = (struct imx_header *) ptr;
+	uint32_t version = detect_imximage_version(imx_hdr);
+
+	switch (version) {
+	case IMXIMAGE_V1:
+		print_hdr_v1(imx_hdr);
+		break;
+	case IMXIMAGE_V2:
+		print_hdr_v2(imx_hdr);
+		break;
+	default:
+		err_imximage_version(version);
+		break;
+	}
+}
+
+static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+	struct imx_header *imxhdr = (struct imx_header *)ptr;
+	uint32_t dcd_len;
+
+	/*
+	 * In order to not change the old imx cfg file
+	 * by adding VERSION command into it, here need
+	 * set up function ptr group to V1 by default.
+	 */
+	imximage_version = IMXIMAGE_V1;
+	/* Be able to detect if the cfg file has no BOOT_FROM tag */
+	imximage_ivt_offset = FLASH_OFFSET_UNDEFINED;
+	imximage_csf_size = 0;
+	set_hdr_func();
+
+	/* Parse dcd configuration file */
+	dcd_len = parse_cfg_file(imxhdr, params->imagename);
+
+	/* Set the imx header */
+	(*set_imx_hdr)(imxhdr, dcd_len, params->ep, imximage_ivt_offset);
+
+	/*
+	 * ROM bug alert
+	 *
+	 * MX53 only loads 512 byte multiples in case of SD boot.
+	 * MX53 only loads NAND page multiples in case of NAND boot and
+	 * supports up to 4096 byte large pages, thus align to 4096.
+	 *
+	 * The remaining fraction of a block bytes would not be loaded!
+	 */
+	*header_size_ptr = ROUND(sbuf->st_size, 4096);
+
+	if (csf_ptr && imximage_csf_size) {
+		*csf_ptr = params->ep - imximage_init_loadsize +
+			*header_size_ptr;
+		*header_size_ptr += imximage_csf_size;
+	}
+}
+
+int imximage_check_params(struct image_tool_params *params)
+{
+	if (!params)
+		return CFG_INVALID;
+	if (!strlen(params->imagename)) {
+		fprintf(stderr, "Error: %s - Configuration file not specified, "
+			"it is needed for imximage generation\n",
+			params->cmdname);
+		return CFG_INVALID;
+	}
+	/*
+	 * Check parameters:
+	 * XIP is not allowed and verify that incompatible
+	 * parameters are not sent at the same time
+	 * For example, if list is required a data image must not be provided
+	 */
+	return	(params->dflag && (params->fflag || params->lflag)) ||
+		(params->fflag && (params->dflag || params->lflag)) ||
+		(params->lflag && (params->dflag || params->fflag)) ||
+		(params->xflag) || !(strlen(params->imagename));
+}
+
+static int imximage_generate(struct image_tool_params *params,
+	struct image_type_params *tparams)
+{
+	struct imx_header *imxhdr;
+	size_t alloc_len;
+	struct stat sbuf;
+	char *datafile = params->datafile;
+	uint32_t pad_len;
+
+	memset(&imximage_header, 0, sizeof(imximage_header));
+
+	/*
+	 * In order to not change the old imx cfg file
+	 * by adding VERSION command into it, here need
+	 * set up function ptr group to V1 by default.
+	 */
+	imximage_version = IMXIMAGE_V1;
+	/* Be able to detect if the cfg file has no BOOT_FROM tag */
+	imximage_ivt_offset = FLASH_OFFSET_UNDEFINED;
+	imximage_csf_size = 0;
+	set_hdr_func();
+
+	/* Parse dcd configuration file */
+	parse_cfg_file(&imximage_header, params->imagename);
+
+	/* TODO: check i.MX image V1 handling, for now use 'old' style */
+	if (imximage_version == IMXIMAGE_V1) {
+		alloc_len = 4096;
+	} else {
+		if (imximage_init_loadsize < imximage_ivt_offset +
+			sizeof(imx_header_v2_t))
+				imximage_init_loadsize = imximage_ivt_offset +
+					sizeof(imx_header_v2_t);
+		alloc_len = imximage_init_loadsize - imximage_ivt_offset;
+	}
+
+	if (alloc_len < sizeof(struct imx_header)) {
+		fprintf(stderr, "%s: header error\n",
+			params->cmdname);
+		exit(EXIT_FAILURE);
+	}
+
+	imxhdr = malloc(alloc_len);
+
+	if (!imxhdr) {
+		fprintf(stderr, "%s: malloc return failure: %s\n",
+			params->cmdname, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	memset(imxhdr, 0, alloc_len);
+
+	tparams->header_size = alloc_len;
+	tparams->hdr         = imxhdr;
+
+	/* determine data image file length */
+
+	if (stat(datafile, &sbuf) < 0) {
+		fprintf(stderr, "%s: Can't stat %s: %s\n",
+			params->cmdname, datafile, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	pad_len = ROUND(sbuf.st_size, 4096) - sbuf.st_size;
+
+	/* TODO: check i.MX image V1 handling, for now use 'old' style */
+	if (imximage_version == IMXIMAGE_V1)
+		return 0;
+	else
+		return pad_len;
+}
+
+
+/*
+ * imximage parameters
+ */
+static struct image_type_params imximage_params = {
+	.name		= "Freescale i.MX Boot Image support",
+	.header_size	= 0,
+	.hdr		= NULL,
+	.check_image_type = imximage_check_image_types,
+	.verify_header	= imximage_verify_header,
+	.print_header	= imximage_print_header,
+	.set_header	= imximage_set_header,
+	.check_params	= imximage_check_params,
+	.vrec_header	= imximage_generate,
+};
+
+void init_imx_image_type(void)
+{
+	register_image_type(&imximage_params);
+}
diff --git a/marvell/uboot/tools/imximage.h b/marvell/uboot/tools/imximage.h
new file mode 100644
index 0000000..01f861e
--- /dev/null
+++ b/marvell/uboot/tools/imximage.h
@@ -0,0 +1,175 @@
+/*
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _IMXIMAGE_H_
+#define _IMXIMAGE_H_
+
+#define MAX_HW_CFG_SIZE_V2 121 /* Max number of registers imx can set for v2 */
+#define MAX_HW_CFG_SIZE_V1 60  /* Max number of registers imx can set for v1 */
+#define APP_CODE_BARKER	0xB1
+#define DCD_BARKER	0xB17219E9
+
+/*
+ * NOTE: This file must be kept in sync with arch/arm/include/asm/\
+ *       imx-common/imximage.cfg because tools/imximage.c can not
+ *       cross-include headers from arch/arm/ and vice-versa.
+ */
+#define CMD_DATA_STR	"DATA"
+
+/* Initial Vector Table Offset */
+#define FLASH_OFFSET_UNDEFINED	0xFFFFFFFF
+#define FLASH_OFFSET_STANDARD	0x400
+#define FLASH_OFFSET_NAND	FLASH_OFFSET_STANDARD
+#define FLASH_OFFSET_SD		FLASH_OFFSET_STANDARD
+#define FLASH_OFFSET_SPI	FLASH_OFFSET_STANDARD
+#define FLASH_OFFSET_ONENAND	0x100
+#define FLASH_OFFSET_NOR	0x1000
+#define FLASH_OFFSET_SATA	FLASH_OFFSET_STANDARD
+
+/* Initial Load Region Size */
+#define FLASH_LOADSIZE_UNDEFINED	0xFFFFFFFF
+#define FLASH_LOADSIZE_STANDARD		0x1000
+#define FLASH_LOADSIZE_NAND		FLASH_LOADSIZE_STANDARD
+#define FLASH_LOADSIZE_SD		FLASH_LOADSIZE_STANDARD
+#define FLASH_LOADSIZE_SPI		FLASH_LOADSIZE_STANDARD
+#define FLASH_LOADSIZE_ONENAND		0x400
+#define FLASH_LOADSIZE_NOR		0x0 /* entire image */
+#define FLASH_LOADSIZE_SATA		FLASH_LOADSIZE_STANDARD
+
+#define IVT_HEADER_TAG 0xD1
+#define IVT_VERSION 0x40
+#define DCD_HEADER_TAG 0xD2
+#define DCD_COMMAND_TAG 0xCC
+#define DCD_VERSION 0x40
+#define DCD_COMMAND_PARAM 0x4
+
+enum imximage_cmd {
+	CMD_INVALID,
+	CMD_IMAGE_VERSION,
+	CMD_BOOT_FROM,
+	CMD_BOOT_OFFSET,
+	CMD_DATA,
+	CMD_CSF,
+};
+
+enum imximage_fld_types {
+	CFG_INVALID = -1,
+	CFG_COMMAND,
+	CFG_REG_SIZE,
+	CFG_REG_ADDRESS,
+	CFG_REG_VALUE
+};
+
+enum imximage_version {
+	IMXIMAGE_VER_INVALID = -1,
+	IMXIMAGE_V1 = 1,
+	IMXIMAGE_V2
+};
+
+typedef struct {
+	uint32_t type; /* Type of pointer (byte, halfword, word, wait/read) */
+	uint32_t addr; /* Address to write to */
+	uint32_t value; /* Data to write */
+} dcd_type_addr_data_t;
+
+typedef struct {
+	uint32_t barker; /* Barker for sanity check */
+	uint32_t length; /* Device configuration length (without preamble) */
+} dcd_preamble_t;
+
+typedef struct {
+	dcd_preamble_t preamble;
+	dcd_type_addr_data_t addr_data[MAX_HW_CFG_SIZE_V1];
+} dcd_v1_t;
+
+typedef struct {
+	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_ptr;
+	uint32_t app_dest_ptr;
+} flash_header_v1_t;
+
+typedef struct {
+	uint32_t length; 	/* Length of data to be read from flash */
+} flash_cfg_parms_t;
+
+typedef struct {
+	flash_header_v1_t fhdr;
+	dcd_v1_t dcd_table;
+	flash_cfg_parms_t ext_header;
+} imx_header_v1_t;
+
+typedef struct {
+	uint32_t addr;
+	uint32_t value;
+} dcd_addr_data_t;
+
+typedef struct {
+	uint8_t tag;
+	uint16_t length;
+	uint8_t version;
+} __attribute__((packed)) ivt_header_t;
+
+typedef struct {
+	uint8_t tag;
+	uint16_t length;
+	uint8_t param;
+} __attribute__((packed)) write_dcd_command_t;
+
+typedef struct {
+	ivt_header_t header;
+	write_dcd_command_t write_dcd_command;
+	dcd_addr_data_t addr_data[MAX_HW_CFG_SIZE_V2];
+} dcd_v2_t;
+
+typedef struct {
+	uint32_t start;
+	uint32_t size;
+	uint32_t plugin;
+} boot_data_t;
+
+typedef struct {
+	ivt_header_t 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;
+} flash_header_v2_t;
+
+typedef struct {
+	flash_header_v2_t fhdr;
+	boot_data_t boot_data;
+	dcd_v2_t dcd_table;
+} imx_header_v2_t;
+
+/* The header must be aligned to 4k on MX53 for NAND boot */
+struct imx_header {
+	union {
+		imx_header_v1_t hdr_v1;
+		imx_header_v2_t hdr_v2;
+	} header;
+};
+
+typedef void (*set_dcd_val_t)(struct imx_header *imxhdr,
+					char *name, int lineno,
+					int fld, uint32_t value,
+					uint32_t off);
+
+typedef void (*set_dcd_rst_t)(struct imx_header *imxhdr,
+					uint32_t dcd_len,
+					char *name, int lineno);
+
+typedef void (*set_imx_hdr_t)(struct imx_header *imxhdr, uint32_t dcd_len,
+		uint32_t entry_point, uint32_t flash_offset);
+
+#endif /* _IMXIMAGE_H_ */
diff --git a/marvell/uboot/tools/jtagconsole b/marvell/uboot/tools/jtagconsole
new file mode 100755
index 0000000..d404fac
--- /dev/null
+++ b/marvell/uboot/tools/jtagconsole
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+usage() {
+	(
+	echo "Usage: $0 [board IP] [board port]"
+	echo ""
+	echo "If IP is not specified, 'localhost' will be used"
+	echo "If port is not specified, '2001' will be used"
+	[ -z "$*" ] && exit 0
+	echo ""
+	echo "ERROR: $*"
+	exit 1
+	) 1>&2
+	exit $?
+}
+
+while [ -n "$1" ] ; do
+	case $1 in
+		-h|--help) usage;;
+		--)        break;;
+		-*)        usage "Invalid option $1";;
+		*)         break;;
+	esac
+	shift
+done
+
+ip=${1:-localhost}
+port=${2:-2001}
+
+if [ -z "${ip}" ] || [ -n "$3" ] ; then
+	usage "Invalid number of arguments"
+fi
+
+trap "stty icanon echo opost intr ^C" 0 2 3 5 10 13 15
+echo "NOTE: the interrupt signal (normally ^C) has been remapped to ^T"
+
+stty -icanon -echo -opost intr ^T
+nc ${ip} ${port}
+exit 0
diff --git a/marvell/uboot/tools/kernel-doc/Makefile b/marvell/uboot/tools/kernel-doc/Makefile
new file mode 100644
index 0000000..eb56e2e
--- /dev/null
+++ b/marvell/uboot/tools/kernel-doc/Makefile
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2012 Marek Vasut <marex@denx.de>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+all:	$(obj)docproc
+
+$(obj)docproc:	docproc.c
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
+clean:
+	rm -rf docproc
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/marvell/uboot/tools/kernel-doc/docproc.c b/marvell/uboot/tools/kernel-doc/docproc.c
new file mode 100644
index 0000000..a9b49c5
--- /dev/null
+++ b/marvell/uboot/tools/kernel-doc/docproc.c
@@ -0,0 +1,576 @@
+/*
+ *	docproc is a simple preprocessor for the template files
+ *      used as placeholders for the kernel internal documentation.
+ *	docproc is used for documentation-frontend and
+ *      dependency-generator.
+ *	The two usages have in common that they require
+ *	some knowledge of the .tmpl syntax, therefore they
+ *	are kept together.
+ *
+ *	documentation-frontend
+ *		Scans the template file and call kernel-doc for
+ *		all occurrences of ![EIF]file
+ *		Beforehand each referenced file is scanned for
+ *		any symbols that are exported via these macros:
+ *			EXPORT_SYMBOL(), EXPORT_SYMBOL_GPL(), &
+ *			EXPORT_SYMBOL_GPL_FUTURE()
+ *		This is used to create proper -function and
+ *		-nofunction arguments in calls to kernel-doc.
+ *		Usage: docproc doc file.tmpl
+ *
+ *	dependency-generator:
+ *		Scans the template file and list all files
+ *		referenced in a format recognized by make.
+ *		Usage:	docproc depend file.tmpl
+ *		Writes dependency information to stdout
+ *		in the following format:
+ *		file.tmpl src.c	src2.c
+ *		The filenames are obtained from the following constructs:
+ *		!Efilename
+ *		!Ifilename
+ *		!Dfilename
+ *		!Ffilename
+ *		!Pfilename
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* exitstatus is used to keep track of any failing calls to kernel-doc,
+ * but execution continues. */
+int exitstatus = 0;
+
+typedef void DFL(char *);
+DFL *defaultline;
+
+typedef void FILEONLY(char * file);
+FILEONLY *internalfunctions;
+FILEONLY *externalfunctions;
+FILEONLY *symbolsonly;
+FILEONLY *findall;
+
+typedef void FILELINE(char * file, char * line);
+FILELINE * singlefunctions;
+FILELINE * entity_system;
+FILELINE * docsection;
+
+#define MAXLINESZ     2048
+#define MAXFILES      250
+#define KERNELDOCPATH "tools/kernel-doc/"
+#define KERNELDOC     "kernel-doc"
+#define DOCBOOK       "-docbook"
+#define LIST          "-list"
+#define FUNCTION      "-function"
+#define NOFUNCTION    "-nofunction"
+#define NODOCSECTIONS "-no-doc-sections"
+
+static char *srctree, *kernsrctree;
+
+static char **all_list = NULL;
+static int all_list_len = 0;
+
+static void consume_symbol(const char *sym)
+{
+	int i;
+
+	for (i = 0; i < all_list_len; i++) {
+		if (!all_list[i])
+			continue;
+		if (strcmp(sym, all_list[i]))
+			continue;
+		all_list[i] = NULL;
+		break;
+	}
+}
+
+static void usage (void)
+{
+	fprintf(stderr, "Usage: docproc {doc|depend} file\n");
+	fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
+	fprintf(stderr, "doc: frontend when generating kernel documentation\n");
+	fprintf(stderr, "depend: generate list of files referenced within file\n");
+	fprintf(stderr, "Environment variable SRCTREE: absolute path to sources.\n");
+	fprintf(stderr, "                     KBUILD_SRC: absolute path to kernel source tree.\n");
+}
+
+/*
+ * Execute kernel-doc with parameters given in svec
+ */
+static void exec_kernel_doc(char **svec)
+{
+	pid_t pid;
+	int ret;
+	char real_filename[PATH_MAX + 1];
+	/* Make sure output generated so far are flushed */
+	fflush(stdout);
+	switch (pid=fork()) {
+		case -1:
+			perror("fork");
+			exit(1);
+		case  0:
+			memset(real_filename, 0, sizeof(real_filename));
+			strncat(real_filename, kernsrctree, PATH_MAX);
+			strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
+					PATH_MAX - strlen(real_filename));
+			execvp(real_filename, svec);
+			fprintf(stderr, "exec ");
+			perror(real_filename);
+			exit(1);
+		default:
+			waitpid(pid, &ret ,0);
+	}
+	if (WIFEXITED(ret))
+		exitstatus |= WEXITSTATUS(ret);
+	else
+		exitstatus = 0xff;
+}
+
+/* Types used to create list of all exported symbols in a number of files */
+struct symbols
+{
+	char *name;
+};
+
+struct symfile
+{
+	char *filename;
+	struct symbols *symbollist;
+	int symbolcnt;
+};
+
+struct symfile symfilelist[MAXFILES];
+int symfilecnt = 0;
+
+static void add_new_symbol(struct symfile *sym, char * symname)
+{
+	sym->symbollist =
+	  realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
+	sym->symbollist[sym->symbolcnt++].name = strdup(symname);
+}
+
+/* Add a filename to the list */
+static struct symfile * add_new_file(char * filename)
+{
+	symfilelist[symfilecnt++].filename = strdup(filename);
+	return &symfilelist[symfilecnt - 1];
+}
+
+/* Check if file already are present in the list */
+static struct symfile * filename_exist(char * filename)
+{
+	int i;
+	for (i=0; i < symfilecnt; i++)
+		if (strcmp(symfilelist[i].filename, filename) == 0)
+			return &symfilelist[i];
+	return NULL;
+}
+
+/*
+ * List all files referenced within the template file.
+ * Files are separated by tabs.
+ */
+static void adddep(char * file)		   { printf("\t%s", file); }
+static void adddep2(char * file, char * line)     { line = line; adddep(file); }
+static void noaction(char * line)		   { line = line; }
+static void noaction2(char * file, char * line)   { file = file; line = line; }
+
+/* Echo the line without further action */
+static void printline(char * line)               { printf("%s", line); }
+
+/*
+ * Find all symbols in filename that are exported with EXPORT_SYMBOL &
+ * EXPORT_SYMBOL_GPL (& EXPORT_SYMBOL_GPL_FUTURE implicitly).
+ * All symbols located are stored in symfilelist.
+ */
+static void find_export_symbols(char * filename)
+{
+	FILE * fp;
+	struct symfile *sym;
+	char line[MAXLINESZ];
+	if (filename_exist(filename) == NULL) {
+		char real_filename[PATH_MAX + 1];
+		memset(real_filename, 0, sizeof(real_filename));
+		strncat(real_filename, srctree, PATH_MAX);
+		strncat(real_filename, "/", PATH_MAX - strlen(real_filename));
+		strncat(real_filename, filename,
+				PATH_MAX - strlen(real_filename));
+		sym = add_new_file(filename);
+		fp = fopen(real_filename, "r");
+		if (fp == NULL)	{
+			fprintf(stderr, "docproc: ");
+			perror(real_filename);
+			exit(1);
+		}
+		while (fgets(line, MAXLINESZ, fp)) {
+			char *p;
+			char *e;
+			if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != NULL) ||
+			    ((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) {
+				/* Skip EXPORT_SYMBOL{_GPL} */
+				while (isalnum(*p) || *p == '_')
+					p++;
+				/* Remove parentheses & additional whitespace */
+				while (isspace(*p))
+					p++;
+				if (*p != '(')
+					continue; /* Syntax error? */
+				else
+					p++;
+				while (isspace(*p))
+					p++;
+				e = p;
+				while (isalnum(*e) || *e == '_')
+					e++;
+				*e = '\0';
+				add_new_symbol(sym, p);
+			}
+		}
+		fclose(fp);
+	}
+}
+
+/*
+ * Document all external or internal functions in a file.
+ * Call kernel-doc with following parameters:
+ * kernel-doc -docbook -nofunction function_name1 filename
+ * Function names are obtained from all the src files
+ * by find_export_symbols.
+ * intfunc uses -nofunction
+ * extfunc uses -function
+ */
+static void docfunctions(char * filename, char * type)
+{
+	int i,j;
+	int symcnt = 0;
+	int idx = 0;
+	char **vec;
+
+	for (i=0; i <= symfilecnt; i++)
+		symcnt += symfilelist[i].symbolcnt;
+	vec = malloc((2 + 2 * symcnt + 3) * sizeof(char *));
+	if (vec == NULL) {
+		perror("docproc: ");
+		exit(1);
+	}
+	vec[idx++] = KERNELDOC;
+	vec[idx++] = DOCBOOK;
+	vec[idx++] = NODOCSECTIONS;
+	for (i=0; i < symfilecnt; i++) {
+		struct symfile * sym = &symfilelist[i];
+		for (j=0; j < sym->symbolcnt; j++) {
+			vec[idx++]     = type;
+			consume_symbol(sym->symbollist[j].name);
+			vec[idx++] = sym->symbollist[j].name;
+		}
+	}
+	vec[idx++]     = filename;
+	vec[idx] = NULL;
+	printf("<!-- %s -->\n", filename);
+	exec_kernel_doc(vec);
+	fflush(stdout);
+	free(vec);
+}
+static void intfunc(char * filename) {	docfunctions(filename, NOFUNCTION); }
+static void extfunc(char * filename) { docfunctions(filename, FUNCTION);   }
+
+/*
+ * Document specific function(s) in a file.
+ * Call kernel-doc with the following parameters:
+ * kernel-doc -docbook -function function1 [-function function2]
+ */
+static void singfunc(char * filename, char * line)
+{
+	char *vec[200]; /* Enough for specific functions */
+	int i, idx = 0;
+	int startofsym = 1;
+	vec[idx++] = KERNELDOC;
+	vec[idx++] = DOCBOOK;
+
+	/* Split line up in individual parameters preceded by FUNCTION */
+	for (i=0; line[i]; i++) {
+		if (isspace(line[i])) {
+			line[i] = '\0';
+			startofsym = 1;
+			continue;
+		}
+		if (startofsym) {
+			startofsym = 0;
+			vec[idx++] = FUNCTION;
+			vec[idx++] = &line[i];
+		}
+	}
+	for (i = 0; i < idx; i++) {
+		if (strcmp(vec[i], FUNCTION))
+			continue;
+		consume_symbol(vec[i + 1]);
+	}
+	vec[idx++] = filename;
+	vec[idx] = NULL;
+	exec_kernel_doc(vec);
+}
+
+/*
+ * Insert specific documentation section from a file.
+ * Call kernel-doc with the following parameters:
+ * kernel-doc -docbook -function "doc section" filename
+ */
+static void docsect(char *filename, char *line)
+{
+	char *vec[6]; /* kerneldoc -docbook -function "section" file NULL */
+	char *s;
+
+	for (s = line; *s; s++)
+		if (*s == '\n')
+			*s = '\0';
+
+	if (asprintf(&s, "DOC: %s", line) < 0) {
+		perror("asprintf");
+		exit(1);
+	}
+	consume_symbol(s);
+	free(s);
+
+	vec[0] = KERNELDOC;
+	vec[1] = DOCBOOK;
+	vec[2] = FUNCTION;
+	vec[3] = line;
+	vec[4] = filename;
+	vec[5] = NULL;
+	exec_kernel_doc(vec);
+}
+
+static void find_all_symbols(char *filename)
+{
+	char *vec[4]; /* kerneldoc -list file NULL */
+	pid_t pid;
+	int ret, i, count, start;
+	char real_filename[PATH_MAX + 1];
+	int pipefd[2];
+	char *data, *str;
+	size_t data_len = 0;
+
+	vec[0] = KERNELDOC;
+	vec[1] = LIST;
+	vec[2] = filename;
+	vec[3] = NULL;
+
+	if (pipe(pipefd)) {
+		perror("pipe");
+		exit(1);
+	}
+
+	switch (pid=fork()) {
+		case -1:
+			perror("fork");
+			exit(1);
+		case  0:
+			close(pipefd[0]);
+			dup2(pipefd[1], 1);
+			memset(real_filename, 0, sizeof(real_filename));
+			strncat(real_filename, kernsrctree, PATH_MAX);
+			strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
+					PATH_MAX - strlen(real_filename));
+			execvp(real_filename, vec);
+			fprintf(stderr, "exec ");
+			perror(real_filename);
+			exit(1);
+		default:
+			close(pipefd[1]);
+			data = malloc(4096);
+			do {
+				while ((ret = read(pipefd[0],
+						   data + data_len,
+						   4096)) > 0) {
+					data_len += ret;
+					data = realloc(data, data_len + 4096);
+				}
+			} while (ret == -EAGAIN);
+			if (ret != 0) {
+				perror("read");
+				exit(1);
+			}
+			waitpid(pid, &ret ,0);
+	}
+	if (WIFEXITED(ret))
+		exitstatus |= WEXITSTATUS(ret);
+	else
+		exitstatus = 0xff;
+
+	count = 0;
+	/* poor man's strtok, but with counting */
+	for (i = 0; i < data_len; i++) {
+		if (data[i] == '\n') {
+			count++;
+			data[i] = '\0';
+		}
+	}
+	start = all_list_len;
+	all_list_len += count;
+	all_list = realloc(all_list, sizeof(char *) * all_list_len);
+	str = data;
+	for (i = 0; i < data_len && start != all_list_len; i++) {
+		if (data[i] == '\0') {
+			all_list[start] = str;
+			str = data + i + 1;
+			start++;
+		}
+	}
+}
+
+/*
+ * Parse file, calling action specific functions for:
+ * 1) Lines containing !E
+ * 2) Lines containing !I
+ * 3) Lines containing !D
+ * 4) Lines containing !F
+ * 5) Lines containing !P
+ * 6) Lines containing !C
+ * 7) Default lines - lines not matching the above
+ */
+static void parse_file(FILE *infile)
+{
+	char line[MAXLINESZ];
+	char * s;
+	while (fgets(line, MAXLINESZ, infile)) {
+		if (line[0] == '!') {
+			s = line + 2;
+			switch (line[1]) {
+				case 'E':
+					while (*s && !isspace(*s)) s++;
+					*s = '\0';
+					externalfunctions(line+2);
+					break;
+				case 'I':
+					while (*s && !isspace(*s)) s++;
+					*s = '\0';
+					internalfunctions(line+2);
+					break;
+				case 'D':
+					while (*s && !isspace(*s)) s++;
+					*s = '\0';
+					symbolsonly(line+2);
+					break;
+				case 'F':
+					/* filename */
+					while (*s && !isspace(*s)) s++;
+					*s++ = '\0';
+					/* function names */
+					while (isspace(*s))
+						s++;
+					singlefunctions(line +2, s);
+					break;
+				case 'P':
+					/* filename */
+					while (*s && !isspace(*s)) s++;
+					*s++ = '\0';
+					/* DOC: section name */
+					while (isspace(*s))
+						s++;
+					docsection(line + 2, s);
+					break;
+				case 'C':
+					while (*s && !isspace(*s)) s++;
+					*s = '\0';
+					if (findall)
+						findall(line+2);
+					break;
+				default:
+					defaultline(line);
+			}
+		} else {
+			defaultline(line);
+		}
+	}
+	fflush(stdout);
+}
+
+
+int main(int argc, char *argv[])
+{
+	FILE * infile;
+	int i;
+
+	srctree = getenv("SRCTREE");
+	if (!srctree)
+		srctree = getcwd(NULL, 0);
+	kernsrctree = getenv("KBUILD_SRC");
+	if (!kernsrctree || !*kernsrctree)
+		kernsrctree = srctree;
+	if (argc != 3) {
+		usage();
+		exit(1);
+	}
+	/* Open file, exit on error */
+	infile = fopen(argv[2], "r");
+	if (infile == NULL) {
+		fprintf(stderr, "docproc: ");
+		perror(argv[2]);
+		exit(2);
+	}
+
+	if (strcmp("doc", argv[1]) == 0) {
+		/* Need to do this in two passes.
+		 * First pass is used to collect all symbols exported
+		 * in the various files;
+		 * Second pass generate the documentation.
+		 * This is required because some functions are declared
+		 * and exported in different files :-((
+		 */
+		/* Collect symbols */
+		defaultline       = noaction;
+		internalfunctions = find_export_symbols;
+		externalfunctions = find_export_symbols;
+		symbolsonly       = find_export_symbols;
+		singlefunctions   = noaction2;
+		docsection        = noaction2;
+		findall           = find_all_symbols;
+		parse_file(infile);
+
+		/* Rewind to start from beginning of file again */
+		fseek(infile, 0, SEEK_SET);
+		defaultline       = printline;
+		internalfunctions = intfunc;
+		externalfunctions = extfunc;
+		symbolsonly       = printline;
+		singlefunctions   = singfunc;
+		docsection        = docsect;
+		findall           = NULL;
+
+		parse_file(infile);
+
+		for (i = 0; i < all_list_len; i++) {
+			if (!all_list[i])
+				continue;
+			fprintf(stderr, "Warning: didn't use docs for %s\n",
+				all_list[i]);
+		}
+	} else if (strcmp("depend", argv[1]) == 0) {
+		/* Create first part of dependency chain
+		 * file.tmpl */
+		printf("%s\t", argv[2]);
+		defaultline       = noaction;
+		internalfunctions = adddep;
+		externalfunctions = adddep;
+		symbolsonly       = adddep;
+		singlefunctions   = adddep2;
+		docsection        = adddep2;
+		findall           = adddep;
+		parse_file(infile);
+		printf("\n");
+	} else {
+		fprintf(stderr, "Unknown option: %s\n", argv[1]);
+		exit(1);
+	}
+	fclose(infile);
+	fflush(stdout);
+	return exitstatus;
+}
diff --git a/marvell/uboot/tools/kernel-doc/kernel-doc b/marvell/uboot/tools/kernel-doc/kernel-doc
new file mode 100755
index 0000000..cbbf34c
--- /dev/null
+++ b/marvell/uboot/tools/kernel-doc/kernel-doc
@@ -0,0 +1,2557 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
+## Copyright (C) 2000, 1  Tim Waugh <twaugh@redhat.com>          ##
+## Copyright (C) 2001  Simon Huggins                             ##
+## Copyright (C) 2005-2012  Randy Dunlap                         ##
+## Copyright (C) 2012  Dan Luedtke                               ##
+## 								 ##
+## #define enhancements by Armin Kuster <akuster@mvista.com>	 ##
+## Copyright (c) 2000 MontaVista Software, Inc.			 ##
+## 								 ##
+## This software falls under the GNU General Public License.     ##
+## Please read the COPYING file for more information             ##
+
+# 18/01/2001 - 	Cleanups
+# 		Functions prototyped as foo(void) same as foo()
+# 		Stop eval'ing where we don't need to.
+# -- huggie@earth.li
+
+# 27/06/2001 -  Allowed whitespace after initial "/**" and
+#               allowed comments before function declarations.
+# -- Christian Kreibich <ck@whoop.org>
+
+# Still to do:
+# 	- add perldoc documentation
+# 	- Look more closely at some of the scarier bits :)
+
+# 26/05/2001 - 	Support for separate source and object trees.
+#		Return error code.
+# 		Keith Owens <kaos@ocs.com.au>
+
+# 23/09/2001 - Added support for typedefs, structs, enums and unions
+#              Support for Context section; can be terminated using empty line
+#              Small fixes (like spaces vs. \s in regex)
+# -- Tim Jansen <tim@tjansen.de>
+
+# 25/07/2012 - Added support for HTML5
+# -- Dan Luedtke <mail@danrl.de>
+
+#
+# This will read a 'c' file and scan for embedded comments in the
+# style of gnome comments (+minor extensions - see below).
+#
+
+# Note: This only supports 'c'.
+
+# usage:
+# kernel-doc [ -docbook | -html | -html5 | -text | -man | -list ]
+#            [ -no-doc-sections ]
+#            [ -function funcname [ -function funcname ...] ]
+#            c file(s)s > outputfile
+# or
+#            [ -nofunction funcname [ -function funcname ...] ]
+#            c file(s)s > outputfile
+#
+#  Set output format using one of -docbook -html -html5 -text or -man.
+#  Default is man.
+#  The -list format is for internal use by docproc.
+#
+#  -no-doc-sections
+#	Do not output DOC: sections
+#
+#  -function funcname
+#	If set, then only generate documentation for the given function(s) or
+#	DOC: section titles.  All other functions and DOC: sections are ignored.
+#
+#  -nofunction funcname
+#	If set, then only generate documentation for the other function(s)/DOC:
+#	sections. Cannot be used together with -function (yes, that's a bug --
+#	perl hackers can fix it 8))
+#
+#  c files - list of 'c' files to process
+#
+#  All output goes to stdout, with errors to stderr.
+
+#
+# format of comments.
+# In the following table, (...)? signifies optional structure.
+#                         (...)* signifies 0 or more structure elements
+# /**
+#  * function_name(:)? (- short description)?
+# (* @parameterx: (description of parameter x)?)*
+# (* a blank line)?
+#  * (Description:)? (Description of function)?
+#  * (section header: (section description)? )*
+#  (*)?*/
+#
+# So .. the trivial example would be:
+#
+# /**
+#  * my_function
+#  */
+#
+# If the Description: header tag is omitted, then there must be a blank line
+# after the last parameter specification.
+# e.g.
+# /**
+#  * my_function - does my stuff
+#  * @my_arg: its mine damnit
+#  *
+#  * Does my stuff explained.
+#  */
+#
+#  or, could also use:
+# /**
+#  * my_function - does my stuff
+#  * @my_arg: its mine damnit
+#  * Description: Does my stuff explained.
+#  */
+# etc.
+#
+# Besides functions you can also write documentation for structs, unions,
+# enums and typedefs. Instead of the function name you must write the name
+# of the declaration;  the struct/union/enum/typedef must always precede
+# the name. Nesting of declarations is not supported.
+# Use the argument mechanism to document members or constants.
+# e.g.
+# /**
+#  * struct my_struct - short description
+#  * @a: first member
+#  * @b: second member
+#  *
+#  * Longer description
+#  */
+# struct my_struct {
+#     int a;
+#     int b;
+# /* private: */
+#     int c;
+# };
+#
+# All descriptions can be multiline, except the short function description.
+#
+# You can also add additional sections. When documenting kernel functions you
+# should document the "Context:" of the function, e.g. whether the functions
+# can be called form interrupts. Unlike other sections you can end it with an
+# empty line.
+# Example-sections should contain the string EXAMPLE so that they are marked
+# appropriately in DocBook.
+#
+# Example:
+# /**
+#  * user_function - function that can only be called in user context
+#  * @a: some argument
+#  * Context: !in_interrupt()
+#  *
+#  * Some description
+#  * Example:
+#  *    user_function(22);
+#  */
+# ...
+#
+#
+# All descriptive text is further processed, scanning for the following special
+# patterns, which are highlighted appropriately.
+#
+# 'funcname()' - function
+# '$ENVVAR' - environmental variable
+# '&struct_name' - name of a structure (up to two words including 'struct')
+# '@parameter' - name of a parameter
+# '%CONST' - name of a constant.
+
+## init lots of data
+
+my $errors = 0;
+my $warnings = 0;
+my $anon_struct_union = 0;
+
+# match expressions used to find embedded type information
+my $type_constant = '\%([-_\w]+)';
+my $type_func = '(\w+)\(\)';
+my $type_param = '\@(\w+)';
+my $type_struct = '\&((struct\s*)*[_\w]+)';
+my $type_struct_xml = '\\&amp;((struct\s*)*[_\w]+)';
+my $type_env = '(\$\w+)';
+
+# Output conversion substitutions.
+#  One for each output format
+
+# these work fairly well
+my %highlights_html = ( $type_constant, "<i>\$1</i>",
+			$type_func, "<b>\$1</b>",
+			$type_struct_xml, "<i>\$1</i>",
+			$type_env, "<b><i>\$1</i></b>",
+			$type_param, "<tt><b>\$1</b></tt>" );
+my $local_lt = "\\\\\\\\lt:";
+my $local_gt = "\\\\\\\\gt:";
+my $blankline_html = $local_lt . "p" . $local_gt;	# was "<p>"
+
+# html version 5
+my %highlights_html5 = ( $type_constant, "<span class=\"const\">\$1</span>",
+			$type_func, "<span class=\"func\">\$1</span>",
+			$type_struct_xml, "<span class=\"struct\">\$1</span>",
+			$type_env, "<span class=\"env\">\$1</span>",
+			$type_param, "<span class=\"param\">\$1</span>" );
+my $blankline_html5 = $local_lt . "br /" . $local_gt;
+
+# XML, docbook format
+my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
+			$type_constant, "<constant>\$1</constant>",
+			$type_func, "<function>\$1</function>",
+			$type_struct_xml, "<structname>\$1</structname>",
+			$type_env, "<envar>\$1</envar>",
+			$type_param, "<parameter>\$1</parameter>" );
+my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n";
+
+# gnome, docbook format
+my %highlights_gnome = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
+			 $type_func, "<function>\$1</function>",
+			 $type_struct, "<structname>\$1</structname>",
+			 $type_env, "<envar>\$1</envar>",
+			 $type_param, "<parameter>\$1</parameter>" );
+my $blankline_gnome = "</para><para>\n";
+
+# these are pretty rough
+my %highlights_man = ( $type_constant, "\$1",
+		       $type_func, "\\\\fB\$1\\\\fP",
+		       $type_struct, "\\\\fI\$1\\\\fP",
+		       $type_param, "\\\\fI\$1\\\\fP" );
+my $blankline_man = "";
+
+# text-mode
+my %highlights_text = ( $type_constant, "\$1",
+			$type_func, "\$1",
+			$type_struct, "\$1",
+			$type_param, "\$1" );
+my $blankline_text = "";
+
+# list mode
+my %highlights_list = ( $type_constant, "\$1",
+			$type_func, "\$1",
+			$type_struct, "\$1",
+			$type_param, "\$1" );
+my $blankline_list = "";
+
+# read arguments
+if ($#ARGV == -1) {
+    usage();
+}
+
+my $kernelversion;
+my $dohighlight = "";
+
+my $verbose = 0;
+my $output_mode = "man";
+my $no_doc_sections = 0;
+my %highlights = %highlights_man;
+my $blankline = $blankline_man;
+my $modulename = "Bootloader API";
+my $function_only = 0;
+my $man_date = ('January', 'February', 'March', 'April', 'May', 'June',
+		'July', 'August', 'September', 'October',
+		'November', 'December')[(localtime)[4]] .
+  " " . ((localtime)[5]+1900);
+
+# Essentially these are globals.
+# They probably want to be tidied up, made more localised or something.
+# CAVEAT EMPTOR!  Some of the others I localised may not want to be, which
+# could cause "use of undefined value" or other bugs.
+my ($function, %function_table, %parametertypes, $declaration_purpose);
+my ($type, $declaration_name, $return_type);
+my ($newsection, $newcontents, $prototype, $brcount, %source_map);
+
+if (defined($ENV{'KBUILD_VERBOSE'})) {
+	$verbose = "$ENV{'KBUILD_VERBOSE'}";
+}
+
+# Generated docbook code is inserted in a template at a point where
+# docbook v3.1 requires a non-zero sequence of RefEntry's; see:
+# http://www.oasis-open.org/docbook/documentation/reference/html/refentry.html
+# We keep track of number of generated entries and generate a dummy
+# if needs be to ensure the expanded template can be postprocessed
+# into html.
+my $section_counter = 0;
+
+my $lineprefix="";
+
+# states
+# 0 - normal code
+# 1 - looking for function name
+# 2 - scanning field start.
+# 3 - scanning prototype.
+# 4 - documentation block
+my $state;
+my $in_doc_sect;
+
+#declaration types: can be
+# 'function', 'struct', 'union', 'enum', 'typedef'
+my $decl_type;
+
+my $doc_special = "\@\%\$\&";
+
+my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start.
+my $doc_end = '\*/';
+my $doc_com = '\s*\*\s*';
+my $doc_decl = $doc_com . '(\w+)';
+my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)';
+my $doc_content = $doc_com . '(.*)';
+my $doc_block = $doc_com . 'DOC:\s*(.*)?';
+
+my %constants;
+my %parameterdescs;
+my @parameterlist;
+my %sections;
+my @sectionlist;
+my $sectcheck;
+my $struct_actual;
+
+my $contents = "";
+my $section_default = "Description";	# default section
+my $section_intro = "Introduction";
+my $section = $section_default;
+my $section_context = "Context";
+
+my $undescribed = "-- undescribed --";
+
+reset_state();
+
+while ($ARGV[0] =~ m/^-(.*)/) {
+    my $cmd = shift @ARGV;
+    if ($cmd eq "-html") {
+	$output_mode = "html";
+	%highlights = %highlights_html;
+	$blankline = $blankline_html;
+    } elsif ($cmd eq "-html5") {
+	$output_mode = "html5";
+	%highlights = %highlights_html5;
+	$blankline = $blankline_html5;
+    } elsif ($cmd eq "-man") {
+	$output_mode = "man";
+	%highlights = %highlights_man;
+	$blankline = $blankline_man;
+    } elsif ($cmd eq "-text") {
+	$output_mode = "text";
+	%highlights = %highlights_text;
+	$blankline = $blankline_text;
+    } elsif ($cmd eq "-docbook") {
+	$output_mode = "xml";
+	%highlights = %highlights_xml;
+	$blankline = $blankline_xml;
+    } elsif ($cmd eq "-list") {
+	$output_mode = "list";
+	%highlights = %highlights_list;
+	$blankline = $blankline_list;
+    } elsif ($cmd eq "-gnome") {
+	$output_mode = "gnome";
+	%highlights = %highlights_gnome;
+	$blankline = $blankline_gnome;
+    } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document
+	$modulename = shift @ARGV;
+    } elsif ($cmd eq "-function") { # to only output specific functions
+	$function_only = 1;
+	$function = shift @ARGV;
+	$function_table{$function} = 1;
+    } elsif ($cmd eq "-nofunction") { # to only output specific functions
+	$function_only = 2;
+	$function = shift @ARGV;
+	$function_table{$function} = 1;
+    } elsif ($cmd eq "-v") {
+	$verbose = 1;
+    } elsif (($cmd eq "-h") || ($cmd eq "--help")) {
+	usage();
+    } elsif ($cmd eq '-no-doc-sections') {
+	    $no_doc_sections = 1;
+    }
+}
+
+# continue execution near EOF;
+
+sub usage {
+    print "Usage: $0 [ -docbook | -html | -html5 | -text | -man | -list ]\n";
+    print "         [ -no-doc-sections ]\n";
+    print "         [ -function funcname [ -function funcname ...] ]\n";
+    print "         [ -nofunction funcname [ -nofunction funcname ...] ]\n";
+    print "         [ -v ]\n";
+    print "         c source file(s) > outputfile\n";
+    print "         -v : verbose output, more warnings & other info listed\n";
+    exit 1;
+}
+
+# get kernel version from env
+sub get_kernel_version() {
+    my $version = 'unknown kernel version';
+
+    if (defined($ENV{'U_BOOT_VERSION'})) {
+	$version = $ENV{'U_BOOT_VERSION'};
+    }
+    return $version;
+}
+
+##
+# dumps section contents to arrays/hashes intended for that purpose.
+#
+sub dump_section {
+    my $file = shift;
+    my $name = shift;
+    my $contents = join "\n", @_;
+
+    if ($name =~ m/$type_constant/) {
+	$name = $1;
+#	print STDERR "constant section '$1' = '$contents'\n";
+	$constants{$name} = $contents;
+    } elsif ($name =~ m/$type_param/) {
+#	print STDERR "parameter def '$1' = '$contents'\n";
+	$name = $1;
+	$parameterdescs{$name} = $contents;
+	$sectcheck = $sectcheck . $name . " ";
+    } elsif ($name eq "@\.\.\.") {
+#	print STDERR "parameter def '...' = '$contents'\n";
+	$name = "...";
+	$parameterdescs{$name} = $contents;
+	$sectcheck = $sectcheck . $name . " ";
+    } else {
+#	print STDERR "other section '$name' = '$contents'\n";
+	if (defined($sections{$name}) && ($sections{$name} ne "")) {
+		print STDERR "Error(${file}:$.): duplicate section name '$name'\n";
+		++$errors;
+	}
+	$sections{$name} = $contents;
+	push @sectionlist, $name;
+    }
+}
+
+##
+# dump DOC: section after checking that it should go out
+#
+sub dump_doc_section {
+    my $file = shift;
+    my $name = shift;
+    my $contents = join "\n", @_;
+
+    if ($no_doc_sections) {
+	return;
+    }
+
+    if (($function_only == 0) ||
+	( $function_only == 1 && defined($function_table{$name})) ||
+	( $function_only == 2 && !defined($function_table{$name})))
+    {
+	dump_section($file, $name, $contents);
+	output_blockhead({'sectionlist' => \@sectionlist,
+			  'sections' => \%sections,
+			  'module' => $modulename,
+			  'content-only' => ($function_only != 0), });
+    }
+}
+
+##
+# output function
+#
+# parameterdescs, a hash.
+#  function => "function name"
+#  parameterlist => @list of parameters
+#  parameterdescs => %parameter descriptions
+#  sectionlist => @list of sections
+#  sections => %section descriptions
+#
+
+sub output_highlight {
+    my $contents = join "\n",@_;
+    my $line;
+
+#   DEBUG
+#   if (!defined $contents) {
+#	use Carp;
+#	confess "output_highlight got called with no args?\n";
+#   }
+
+    if ($output_mode eq "html" || $output_mode eq "html5" ||
+	$output_mode eq "xml") {
+	$contents = local_unescape($contents);
+	# convert data read & converted thru xml_escape() into &xyz; format:
+	$contents =~ s/\\\\\\/\&/g;
+    }
+#   print STDERR "contents b4:$contents\n";
+    eval $dohighlight;
+    die $@ if $@;
+#   print STDERR "contents af:$contents\n";
+
+#   strip whitespaces when generating html5
+    if ($output_mode eq "html5") {
+	$contents =~ s/^\s+//;
+	$contents =~ s/\s+$//;
+    }
+    foreach $line (split "\n", $contents) {
+	if ($line eq ""){
+	    print $lineprefix, local_unescape($blankline);
+	} else {
+	    $line =~ s/\\\\\\/\&/g;
+	    if ($output_mode eq "man" && substr($line, 0, 1) eq ".") {
+		print "\\&$line";
+	    } else {
+		print $lineprefix, $line;
+	    }
+	}
+	print "\n";
+    }
+}
+
+# output sections in html
+sub output_section_html(%) {
+    my %args = %{$_[0]};
+    my $section;
+
+    foreach $section (@{$args{'sectionlist'}}) {
+	print "<h3>$section</h3>\n";
+	print "<blockquote>\n";
+	output_highlight($args{'sections'}{$section});
+	print "</blockquote>\n";
+    }
+}
+
+# output enum in html
+sub output_enum_html(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    print "<h2>enum " . $args{'enum'} . "</h2>\n";
+
+    print "<b>enum " . $args{'enum'} . "</b> {<br>\n";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	print " <b>" . $parameter . "</b>";
+	if ($count != $#{$args{'parameterlist'}}) {
+	    $count++;
+	    print ",\n";
+	}
+	print "<br>";
+    }
+    print "};<br>\n";
+
+    print "<h3>Constants</h3>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	print "<dt><b>" . $parameter . "</b>\n";
+	print "<dd>";
+	output_highlight($args{'parameterdescs'}{$parameter});
+    }
+    print "</dl>\n";
+    output_section_html(@_);
+    print "<hr>\n";
+}
+
+# output typedef in html
+sub output_typedef_html(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    print "<h2>typedef " . $args{'typedef'} . "</h2>\n";
+
+    print "<b>typedef " . $args{'typedef'} . "</b>\n";
+    output_section_html(@_);
+    print "<hr>\n";
+}
+
+# output struct in html
+sub output_struct_html(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+
+    print "<h2>" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "</h2>\n";
+    print "<b>" . $args{'type'} . " " . $args{'struct'} . "</b> {<br>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	if ($parameter =~ /^#/) {
+		print "$parameter<br>\n";
+		next;
+	}
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print "&nbsp; &nbsp; <i>$1</i><b>$parameter</b>) <i>($2)</i>;<br>\n";
+	} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+	    # bitfield
+	    print "&nbsp; &nbsp; <i>$1</i> <b>$parameter</b>$2;<br>\n";
+	} else {
+	    print "&nbsp; &nbsp; <i>$type</i> <b>$parameter</b>;<br>\n";
+	}
+    }
+    print "};<br>\n";
+
+    print "<h3>Members</h3>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	($parameter =~ /^#/) && next;
+
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	print "<dt><b>" . $parameter . "</b>\n";
+	print "<dd>";
+	output_highlight($args{'parameterdescs'}{$parameter_name});
+    }
+    print "</dl>\n";
+    output_section_html(@_);
+    print "<hr>\n";
+}
+
+# output function in html
+sub output_function_html(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    print "<h2>" . $args{'function'} . " - " . $args{'purpose'} . "</h2>\n";
+    print "<i>" . $args{'functiontype'} . "</i>\n";
+    print "<b>" . $args{'function'} . "</b>\n";
+    print "(";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print "<i>$1</i><b>$parameter</b>) <i>($2)</i>";
+	} else {
+	    print "<i>" . $type . "</i> <b>" . $parameter . "</b>";
+	}
+	if ($count != $#{$args{'parameterlist'}}) {
+	    $count++;
+	    print ",\n";
+	}
+    }
+    print ")\n";
+
+    print "<h3>Arguments</h3>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	print "<dt><b>" . $parameter . "</b>\n";
+	print "<dd>";
+	output_highlight($args{'parameterdescs'}{$parameter_name});
+    }
+    print "</dl>\n";
+    output_section_html(@_);
+    print "<hr>\n";
+}
+
+# output DOC: block header in html
+sub output_blockhead_html(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    foreach $section (@{$args{'sectionlist'}}) {
+	print "<h3>$section</h3>\n";
+	print "<ul>\n";
+	output_highlight($args{'sections'}{$section});
+	print "</ul>\n";
+    }
+    print "<hr>\n";
+}
+
+# output sections in html5
+sub output_section_html5(%) {
+    my %args = %{$_[0]};
+    my $section;
+
+    foreach $section (@{$args{'sectionlist'}}) {
+	print "<section>\n";
+	print "<h1>$section</h1>\n";
+	print "<p>\n";
+	output_highlight($args{'sections'}{$section});
+	print "</p>\n";
+	print "</section>\n";
+    }
+}
+
+# output enum in html5
+sub output_enum_html5(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    my $html5id;
+
+    $html5id = $args{'enum'};
+    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+    print "<article class=\"enum\" id=\"enum:". $html5id . "\">";
+    print "<h1>enum " . $args{'enum'} . "</h1>\n";
+    print "<ol class=\"code\">\n";
+    print "<li>";
+    print "<span class=\"keyword\">enum</span> ";
+    print "<span class=\"identifier\">" . $args{'enum'} . "</span> {";
+    print "</li>\n";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	print "<li class=\"indent\">";
+	print "<span class=\"param\">" . $parameter . "</span>";
+	if ($count != $#{$args{'parameterlist'}}) {
+	    $count++;
+	    print ",";
+	}
+	print "</li>\n";
+    }
+    print "<li>};</li>\n";
+    print "</ol>\n";
+
+    print "<section>\n";
+    print "<h1>Constants</h1>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	print "<dt>" . $parameter . "</dt>\n";
+	print "<dd>";
+	output_highlight($args{'parameterdescs'}{$parameter});
+	print "</dd>\n";
+    }
+    print "</dl>\n";
+    print "</section>\n";
+    output_section_html5(@_);
+    print "</article>\n";
+}
+
+# output typedef in html5
+sub output_typedef_html5(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    my $html5id;
+
+    $html5id = $args{'typedef'};
+    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+    print "<article class=\"typedef\" id=\"typedef:" . $html5id . "\">\n";
+    print "<h1>typedef " . $args{'typedef'} . "</h1>\n";
+
+    print "<ol class=\"code\">\n";
+    print "<li>";
+    print "<span class=\"keyword\">typedef</span> ";
+    print "<span class=\"identifier\">" . $args{'typedef'} . "</span>";
+    print "</li>\n";
+    print "</ol>\n";
+    output_section_html5(@_);
+    print "</article>\n";
+}
+
+# output struct in html5
+sub output_struct_html5(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $html5id;
+
+    $html5id = $args{'struct'};
+    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+    print "<article class=\"struct\" id=\"struct:" . $html5id . "\">\n";
+    print "<hgroup>\n";
+    print "<h1>" . $args{'type'} . " " . $args{'struct'} . "</h1>";
+    print "<h2>". $args{'purpose'} . "</h2>\n";
+    print "</hgroup>\n";
+    print "<ol class=\"code\">\n";
+    print "<li>";
+    print "<span class=\"type\">" . $args{'type'} . "</span> ";
+    print "<span class=\"identifier\">" . $args{'struct'} . "</span> {";
+    print "</li>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	print "<li class=\"indent\">";
+	if ($parameter =~ /^#/) {
+		print "<span class=\"param\">" . $parameter ."</span>\n";
+		print "</li>\n";
+		next;
+	}
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print "<span class=\"type\">$1</span> ";
+	    print "<span class=\"param\">$parameter</span>";
+	    print "<span class=\"type\">)</span> ";
+	    print "(<span class=\"args\">$2</span>);";
+	} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+	    # bitfield
+	    print "<span class=\"type\">$1</span> ";
+	    print "<span class=\"param\">$parameter</span>";
+	    print "<span class=\"bits\">$2</span>;";
+	} else {
+	    print "<span class=\"type\">$type</span> ";
+	    print "<span class=\"param\">$parameter</span>;";
+	}
+	print "</li>\n";
+    }
+    print "<li>};</li>\n";
+    print "</ol>\n";
+
+    print "<section>\n";
+    print "<h1>Members</h1>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	($parameter =~ /^#/) && next;
+
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	print "<dt>" . $parameter . "</dt>\n";
+	print "<dd>";
+	output_highlight($args{'parameterdescs'}{$parameter_name});
+	print "</dd>\n";
+    }
+    print "</dl>\n";
+    print "</section>\n";
+    output_section_html5(@_);
+    print "</article>\n";
+}
+
+# output function in html5
+sub output_function_html5(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+    my $html5id;
+
+    $html5id = $args{'function'};
+    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+    print "<article class=\"function\" id=\"func:". $html5id . "\">\n";
+    print "<hgroup>\n";
+    print "<h1>" . $args{'function'} . "</h1>";
+    print "<h2>" . $args{'purpose'} . "</h2>\n";
+    print "</hgroup>\n";
+    print "<ol class=\"code\">\n";
+    print "<li>";
+    print "<span class=\"type\">" . $args{'functiontype'} . "</span> ";
+    print "<span class=\"identifier\">" . $args{'function'} . "</span> (";
+    print "</li>";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	print "<li class=\"indent\">";
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print "<span class=\"type\">$1</span> ";
+	    print "<span class=\"param\">$parameter</span>";
+	    print "<span class=\"type\">)</span> ";
+	    print "(<span class=\"args\">$2</span>)";
+	} else {
+	    print "<span class=\"type\">$type</span> ";
+	    print "<span class=\"param\">$parameter</span>";
+	}
+	if ($count != $#{$args{'parameterlist'}}) {
+	    $count++;
+	    print ",";
+	}
+	print "</li>\n";
+    }
+    print "<li>)</li>\n";
+    print "</ol>\n";
+
+    print "<section>\n";
+    print "<h1>Arguments</h1>\n";
+    print "<p>\n";
+    print "<dl>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	print "<dt>" . $parameter . "</dt>\n";
+	print "<dd>";
+	output_highlight($args{'parameterdescs'}{$parameter_name});
+	print "</dd>\n";
+    }
+    print "</dl>\n";
+    print "</section>\n";
+    output_section_html5(@_);
+    print "</article>\n";
+}
+
+# output DOC: block header in html5
+sub output_blockhead_html5(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+    my $html5id;
+
+    foreach $section (@{$args{'sectionlist'}}) {
+	$html5id = $section;
+	$html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+	print "<article class=\"doc\" id=\"doc:". $html5id . "\">\n";
+	print "<h1>$section</h1>\n";
+	print "<p>\n";
+	output_highlight($args{'sections'}{$section});
+	print "</p>\n";
+    }
+    print "</article>\n";
+}
+
+sub output_section_xml(%) {
+    my %args = %{$_[0]};
+    my $section;
+    # print out each section
+    $lineprefix="   ";
+    foreach $section (@{$args{'sectionlist'}}) {
+	print "<refsect1>\n";
+	print "<title>$section</title>\n";
+	if ($section =~ m/EXAMPLE/i) {
+	    print "<informalexample><programlisting>\n";
+	} else {
+	    print "<para>\n";
+	}
+	output_highlight($args{'sections'}{$section});
+	if ($section =~ m/EXAMPLE/i) {
+	    print "</programlisting></informalexample>\n";
+	} else {
+	    print "</para>\n";
+	}
+	print "</refsect1>\n";
+    }
+}
+
+# output function in XML DocBook
+sub output_function_xml(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+    my $id;
+
+    $id = "API-" . $args{'function'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    print "<refentry id=\"$id\">\n";
+    print "<refentryinfo>\n";
+    print " <title>U-BOOT</title>\n";
+    print " <productname>Bootloader Hackers Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
+    print "<refmeta>\n";
+    print " <refentrytitle><phrase>" . $args{'function'} . "</phrase></refentrytitle>\n";
+    print " <manvolnum>9</manvolnum>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
+    print "</refmeta>\n";
+    print "<refnamediv>\n";
+    print " <refname>" . $args{'function'} . "</refname>\n";
+    print " <refpurpose>\n";
+    print "  ";
+    output_highlight ($args{'purpose'});
+    print " </refpurpose>\n";
+    print "</refnamediv>\n";
+
+    print "<refsynopsisdiv>\n";
+    print " <title>Synopsis</title>\n";
+    print "  <funcsynopsis><funcprototype>\n";
+    print "   <funcdef>" . $args{'functiontype'} . " ";
+    print "<function>" . $args{'function'} . " </function></funcdef>\n";
+
+    $count = 0;
+    if ($#{$args{'parameterlist'}} >= 0) {
+	foreach $parameter (@{$args{'parameterlist'}}) {
+	    $type = $args{'parametertypes'}{$parameter};
+	    if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+		# pointer-to-function
+		print "   <paramdef>$1<parameter>$parameter</parameter>)\n";
+		print "     <funcparams>$2</funcparams></paramdef>\n";
+	    } else {
+		print "   <paramdef>" . $type;
+		print " <parameter>$parameter</parameter></paramdef>\n";
+	    }
+	}
+    } else {
+	print "  <void/>\n";
+    }
+    print "  </funcprototype></funcsynopsis>\n";
+    print "</refsynopsisdiv>\n";
+
+    # print parameters
+    print "<refsect1>\n <title>Arguments</title>\n";
+    if ($#{$args{'parameterlist'}} >= 0) {
+	print " <variablelist>\n";
+	foreach $parameter (@{$args{'parameterlist'}}) {
+	    my $parameter_name = $parameter;
+	    $parameter_name =~ s/\[.*//;
+
+	    print "  <varlistentry>\n   <term><parameter>$parameter</parameter></term>\n";
+	    print "   <listitem>\n    <para>\n";
+	    $lineprefix="     ";
+	    output_highlight($args{'parameterdescs'}{$parameter_name});
+	    print "    </para>\n   </listitem>\n  </varlistentry>\n";
+	}
+	print " </variablelist>\n";
+    } else {
+	print " <para>\n  None\n </para>\n";
+    }
+    print "</refsect1>\n";
+
+    output_section_xml(@_);
+    print "</refentry>\n\n";
+}
+
+# output struct in XML DocBook
+sub output_struct_xml(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $id;
+
+    $id = "API-struct-" . $args{'struct'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    print "<refentry id=\"$id\">\n";
+    print "<refentryinfo>\n";
+    print " <title>U-BOOT</title>\n";
+    print " <productname>Bootloader Hackers Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
+    print "<refmeta>\n";
+    print " <refentrytitle><phrase>" . $args{'type'} . " " . $args{'struct'} . "</phrase></refentrytitle>\n";
+    print " <manvolnum>9</manvolnum>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
+    print "</refmeta>\n";
+    print "<refnamediv>\n";
+    print " <refname>" . $args{'type'} . " " . $args{'struct'} . "</refname>\n";
+    print " <refpurpose>\n";
+    print "  ";
+    output_highlight ($args{'purpose'});
+    print " </refpurpose>\n";
+    print "</refnamediv>\n";
+
+    print "<refsynopsisdiv>\n";
+    print " <title>Synopsis</title>\n";
+    print "  <programlisting>\n";
+    print $args{'type'} . " " . $args{'struct'} . " {\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	if ($parameter =~ /^#/) {
+	    my $prm = $parameter;
+	    # convert data read & converted thru xml_escape() into &xyz; format:
+	    # This allows us to have #define macros interspersed in a struct.
+	    $prm =~ s/\\\\\\/\&/g;
+	    print "$prm\n";
+	    next;
+	}
+
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	defined($args{'parameterdescs'}{$parameter_name}) || next;
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print "  $1 $parameter) ($2);\n";
+	} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+	    # bitfield
+	    print "  $1 $parameter$2;\n";
+	} else {
+	    print "  " . $type . " " . $parameter . ";\n";
+	}
+    }
+    print "};";
+    print "  </programlisting>\n";
+    print "</refsynopsisdiv>\n";
+
+    print " <refsect1>\n";
+    print "  <title>Members</title>\n";
+
+    if ($#{$args{'parameterlist'}} >= 0) {
+    print "  <variablelist>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+      ($parameter =~ /^#/) && next;
+
+      my $parameter_name = $parameter;
+      $parameter_name =~ s/\[.*//;
+
+      defined($args{'parameterdescs'}{$parameter_name}) || next;
+      ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+      print "    <varlistentry>";
+      print "      <term>$parameter</term>\n";
+      print "      <listitem><para>\n";
+      output_highlight($args{'parameterdescs'}{$parameter_name});
+      print "      </para></listitem>\n";
+      print "    </varlistentry>\n";
+    }
+    print "  </variablelist>\n";
+    } else {
+	print " <para>\n  None\n </para>\n";
+    }
+    print " </refsect1>\n";
+
+    output_section_xml(@_);
+
+    print "</refentry>\n\n";
+}
+
+# output enum in XML DocBook
+sub output_enum_xml(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+    my $id;
+
+    $id = "API-enum-" . $args{'enum'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    print "<refentry id=\"$id\">\n";
+    print "<refentryinfo>\n";
+    print " <title>U-BOOT</title>\n";
+    print " <productname>Bootloader Hackers Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
+    print "<refmeta>\n";
+    print " <refentrytitle><phrase>enum " . $args{'enum'} . "</phrase></refentrytitle>\n";
+    print " <manvolnum>9</manvolnum>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
+    print "</refmeta>\n";
+    print "<refnamediv>\n";
+    print " <refname>enum " . $args{'enum'} . "</refname>\n";
+    print " <refpurpose>\n";
+    print "  ";
+    output_highlight ($args{'purpose'});
+    print " </refpurpose>\n";
+    print "</refnamediv>\n";
+
+    print "<refsynopsisdiv>\n";
+    print " <title>Synopsis</title>\n";
+    print "  <programlisting>\n";
+    print "enum " . $args{'enum'} . " {\n";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	print "  $parameter";
+	if ($count != $#{$args{'parameterlist'}}) {
+	    $count++;
+	    print ",";
+	}
+	print "\n";
+    }
+    print "};";
+    print "  </programlisting>\n";
+    print "</refsynopsisdiv>\n";
+
+    print "<refsect1>\n";
+    print " <title>Constants</title>\n";
+    print "  <variablelist>\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+      my $parameter_name = $parameter;
+      $parameter_name =~ s/\[.*//;
+
+      print "    <varlistentry>";
+      print "      <term>$parameter</term>\n";
+      print "      <listitem><para>\n";
+      output_highlight($args{'parameterdescs'}{$parameter_name});
+      print "      </para></listitem>\n";
+      print "    </varlistentry>\n";
+    }
+    print "  </variablelist>\n";
+    print "</refsect1>\n";
+
+    output_section_xml(@_);
+
+    print "</refentry>\n\n";
+}
+
+# output typedef in XML DocBook
+sub output_typedef_xml(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $id;
+
+    $id = "API-typedef-" . $args{'typedef'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    print "<refentry id=\"$id\">\n";
+    print "<refentryinfo>\n";
+    print " <title>U-BOOT</title>\n";
+    print " <productname>Bootloader Hackers Manual</productname>\n";
+    print " <date>$man_date</date>\n";
+    print "</refentryinfo>\n";
+    print "<refmeta>\n";
+    print " <refentrytitle><phrase>typedef " . $args{'typedef'} . "</phrase></refentrytitle>\n";
+    print " <manvolnum>9</manvolnum>\n";
+    print "</refmeta>\n";
+    print "<refnamediv>\n";
+    print " <refname>typedef " . $args{'typedef'} . "</refname>\n";
+    print " <refpurpose>\n";
+    print "  ";
+    output_highlight ($args{'purpose'});
+    print " </refpurpose>\n";
+    print "</refnamediv>\n";
+
+    print "<refsynopsisdiv>\n";
+    print " <title>Synopsis</title>\n";
+    print "  <synopsis>typedef " . $args{'typedef'} . ";</synopsis>\n";
+    print "</refsynopsisdiv>\n";
+
+    output_section_xml(@_);
+
+    print "</refentry>\n\n";
+}
+
+# output in XML DocBook
+sub output_blockhead_xml(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    my $id = $args{'module'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    # print out each section
+    $lineprefix="   ";
+    foreach $section (@{$args{'sectionlist'}}) {
+	if (!$args{'content-only'}) {
+		print "<refsect1>\n <title>$section</title>\n";
+	}
+	if ($section =~ m/EXAMPLE/i) {
+	    print "<example><para>\n";
+	} else {
+	    print "<para>\n";
+	}
+	output_highlight($args{'sections'}{$section});
+	if ($section =~ m/EXAMPLE/i) {
+	    print "</para></example>\n";
+	} else {
+	    print "</para>";
+	}
+	if (!$args{'content-only'}) {
+		print "\n</refsect1>\n";
+	}
+    }
+
+    print "\n\n";
+}
+
+# output in XML DocBook
+sub output_function_gnome {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+    my $id;
+
+    $id = $args{'module'} . "-" . $args{'function'};
+    $id =~ s/[^A-Za-z0-9]/-/g;
+
+    print "<sect2>\n";
+    print " <title id=\"$id\">" . $args{'function'} . "</title>\n";
+
+    print "  <funcsynopsis>\n";
+    print "   <funcdef>" . $args{'functiontype'} . " ";
+    print "<function>" . $args{'function'} . " ";
+    print "</function></funcdef>\n";
+
+    $count = 0;
+    if ($#{$args{'parameterlist'}} >= 0) {
+	foreach $parameter (@{$args{'parameterlist'}}) {
+	    $type = $args{'parametertypes'}{$parameter};
+	    if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+		# pointer-to-function
+		print "   <paramdef>$1 <parameter>$parameter</parameter>)\n";
+		print "     <funcparams>$2</funcparams></paramdef>\n";
+	    } else {
+		print "   <paramdef>" . $type;
+		print " <parameter>$parameter</parameter></paramdef>\n";
+	    }
+	}
+    } else {
+	print "  <void>\n";
+    }
+    print "  </funcsynopsis>\n";
+    if ($#{$args{'parameterlist'}} >= 0) {
+	print " <informaltable pgwide=\"1\" frame=\"none\" role=\"params\">\n";
+	print "<tgroup cols=\"2\">\n";
+	print "<colspec colwidth=\"2*\">\n";
+	print "<colspec colwidth=\"8*\">\n";
+	print "<tbody>\n";
+	foreach $parameter (@{$args{'parameterlist'}}) {
+	    my $parameter_name = $parameter;
+	    $parameter_name =~ s/\[.*//;
+
+	    print "  <row><entry align=\"right\"><parameter>$parameter</parameter></entry>\n";
+	    print "   <entry>\n";
+	    $lineprefix="     ";
+	    output_highlight($args{'parameterdescs'}{$parameter_name});
+	    print "    </entry></row>\n";
+	}
+	print " </tbody></tgroup></informaltable>\n";
+    } else {
+	print " <para>\n  None\n </para>\n";
+    }
+
+    # print out each section
+    $lineprefix="   ";
+    foreach $section (@{$args{'sectionlist'}}) {
+	print "<simplesect>\n <title>$section</title>\n";
+	if ($section =~ m/EXAMPLE/i) {
+	    print "<example><programlisting>\n";
+	} else {
+	}
+	print "<para>\n";
+	output_highlight($args{'sections'}{$section});
+	print "</para>\n";
+	if ($section =~ m/EXAMPLE/i) {
+	    print "</programlisting></example>\n";
+	} else {
+	}
+	print " </simplesect>\n";
+    }
+
+    print "</sect2>\n\n";
+}
+
+##
+# output function in man
+sub output_function_man(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Bootloader Hacker's Manual\" U-BOOT\n";
+
+    print ".SH NAME\n";
+    print $args{'function'} . " \\- " . $args{'purpose'} . "\n";
+
+    print ".SH SYNOPSIS\n";
+    if ($args{'functiontype'} ne "") {
+	print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n";
+    } else {
+	print ".B \"" . $args{'function'} . "\n";
+    }
+    $count = 0;
+    my $parenth = "(";
+    my $post = ",";
+    foreach my $parameter (@{$args{'parameterlist'}}) {
+	if ($count == $#{$args{'parameterlist'}}) {
+	    $post = ");";
+	}
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print ".BI \"" . $parenth . $1 . "\" " . $parameter . " \") (" . $2 . ")" . $post . "\"\n";
+	} else {
+	    $type =~ s/([^\*])$/$1 /;
+	    print ".BI \"" . $parenth . $type . "\" " . $parameter . " \"" . $post . "\"\n";
+	}
+	$count++;
+	$parenth = "";
+    }
+
+    print ".SH ARGUMENTS\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	print ".IP \"" . $parameter . "\" 12\n";
+	output_highlight($args{'parameterdescs'}{$parameter_name});
+    }
+    foreach $section (@{$args{'sectionlist'}}) {
+	print ".SH \"", uc $section, "\"\n";
+	output_highlight($args{'sections'}{$section});
+    }
+}
+
+##
+# output enum in man
+sub output_enum_man(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" U-BOOT\n";
+
+    print ".SH NAME\n";
+    print "enum " . $args{'enum'} . " \\- " . $args{'purpose'} . "\n";
+
+    print ".SH SYNOPSIS\n";
+    print "enum " . $args{'enum'} . " {\n";
+    $count = 0;
+    foreach my $parameter (@{$args{'parameterlist'}}) {
+	print ".br\n.BI \"    $parameter\"\n";
+	if ($count == $#{$args{'parameterlist'}}) {
+	    print "\n};\n";
+	    last;
+	}
+	else {
+	    print ", \n.br\n";
+	}
+	$count++;
+    }
+
+    print ".SH Constants\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	print ".IP \"" . $parameter . "\" 12\n";
+	output_highlight($args{'parameterdescs'}{$parameter_name});
+    }
+    foreach $section (@{$args{'sectionlist'}}) {
+	print ".SH \"$section\"\n";
+	output_highlight($args{'sections'}{$section});
+    }
+}
+
+##
+# output struct in man
+sub output_struct_man(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+
+    print ".TH \"$args{'module'}\" 9 \"" . $args{'type'} . " " . $args{'struct'} . "\" \"$man_date\" \"API Manual\" U-BOOT\n";
+
+    print ".SH NAME\n";
+    print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n";
+
+    print ".SH SYNOPSIS\n";
+    print $args{'type'} . " " . $args{'struct'} . " {\n.br\n";
+
+    foreach my $parameter (@{$args{'parameterlist'}}) {
+	if ($parameter =~ /^#/) {
+	    print ".BI \"$parameter\"\n.br\n";
+	    next;
+	}
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print ".BI \"    " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n";
+	} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+	    # bitfield
+	    print ".BI \"    " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n";
+	} else {
+	    $type =~ s/([^\*])$/$1 /;
+	    print ".BI \"    " . $type . "\" " . $parameter . " \"" . "\"\n;\n";
+	}
+	print "\n.br\n";
+    }
+    print "};\n.br\n";
+
+    print ".SH Members\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	($parameter =~ /^#/) && next;
+
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	print ".IP \"" . $parameter . "\" 12\n";
+	output_highlight($args{'parameterdescs'}{$parameter_name});
+    }
+    foreach $section (@{$args{'sectionlist'}}) {
+	print ".SH \"$section\"\n";
+	output_highlight($args{'sections'}{$section});
+    }
+}
+
+##
+# output typedef in man
+sub output_typedef_man(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+
+    print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" U-BOOT\n";
+
+    print ".SH NAME\n";
+    print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n";
+
+    foreach $section (@{$args{'sectionlist'}}) {
+	print ".SH \"$section\"\n";
+	output_highlight($args{'sections'}{$section});
+    }
+}
+
+sub output_blockhead_man(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $count;
+
+    print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API Manual\" U-BOOT\n";
+
+    foreach $section (@{$args{'sectionlist'}}) {
+	print ".SH \"$section\"\n";
+	output_highlight($args{'sections'}{$section});
+    }
+}
+
+##
+# output in text
+sub output_function_text(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+    my $start;
+
+    print "Name:\n\n";
+    print $args{'function'} . " - " . $args{'purpose'} . "\n";
+
+    print "\nSynopsis:\n\n";
+    if ($args{'functiontype'} ne "") {
+	$start = $args{'functiontype'} . " " . $args{'function'} . " (";
+    } else {
+	$start = $args{'function'} . " (";
+    }
+    print $start;
+
+    my $count = 0;
+    foreach my $parameter (@{$args{'parameterlist'}}) {
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print $1 . $parameter . ") (" . $2;
+	} else {
+	    print $type . " " . $parameter;
+	}
+	if ($count != $#{$args{'parameterlist'}}) {
+	    $count++;
+	    print ",\n";
+	    print " " x length($start);
+	} else {
+	    print ");\n\n";
+	}
+    }
+
+    print "Arguments:\n\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	print $parameter . "\n\t" . $args{'parameterdescs'}{$parameter_name} . "\n";
+    }
+    output_section_text(@_);
+}
+
+#output sections in text
+sub output_section_text(%) {
+    my %args = %{$_[0]};
+    my $section;
+
+    print "\n";
+    foreach $section (@{$args{'sectionlist'}}) {
+	print "$section:\n\n";
+	output_highlight($args{'sections'}{$section});
+    }
+    print "\n\n";
+}
+
+# output enum in text
+sub output_enum_text(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    print "Enum:\n\n";
+
+    print "enum " . $args{'enum'} . " - " . $args{'purpose'} . "\n\n";
+    print "enum " . $args{'enum'} . " {\n";
+    $count = 0;
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	print "\t$parameter";
+	if ($count != $#{$args{'parameterlist'}}) {
+	    $count++;
+	    print ",";
+	}
+	print "\n";
+    }
+    print "};\n\n";
+
+    print "Constants:\n\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	print "$parameter\n\t";
+	print $args{'parameterdescs'}{$parameter} . "\n";
+    }
+
+    output_section_text(@_);
+}
+
+# output typedef in text
+sub output_typedef_text(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+    my $count;
+    print "Typedef:\n\n";
+
+    print "typedef " . $args{'typedef'} . " - " . $args{'purpose'} . "\n";
+    output_section_text(@_);
+}
+
+# output struct as text
+sub output_struct_text(%) {
+    my %args = %{$_[0]};
+    my ($parameter);
+
+    print $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "\n\n";
+    print $args{'type'} . " " . $args{'struct'} . " {\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	if ($parameter =~ /^#/) {
+	    print "$parameter\n";
+	    next;
+	}
+
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	$type = $args{'parametertypes'}{$parameter};
+	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+	    # pointer-to-function
+	    print "\t$1 $parameter) ($2);\n";
+	} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+	    # bitfield
+	    print "\t$1 $parameter$2;\n";
+	} else {
+	    print "\t" . $type . " " . $parameter . ";\n";
+	}
+    }
+    print "};\n\n";
+
+    print "Members:\n\n";
+    foreach $parameter (@{$args{'parameterlist'}}) {
+	($parameter =~ /^#/) && next;
+
+	my $parameter_name = $parameter;
+	$parameter_name =~ s/\[.*//;
+
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	print "$parameter\n\t";
+	print $args{'parameterdescs'}{$parameter_name} . "\n";
+    }
+    print "\n";
+    output_section_text(@_);
+}
+
+sub output_blockhead_text(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+
+    foreach $section (@{$args{'sectionlist'}}) {
+	print " $section:\n";
+	print "    -> ";
+	output_highlight($args{'sections'}{$section});
+    }
+}
+
+## list mode output functions
+
+sub output_function_list(%) {
+    my %args = %{$_[0]};
+
+    print $args{'function'} . "\n";
+}
+
+# output enum in list
+sub output_enum_list(%) {
+    my %args = %{$_[0]};
+    print $args{'enum'} . "\n";
+}
+
+# output typedef in list
+sub output_typedef_list(%) {
+    my %args = %{$_[0]};
+    print $args{'typedef'} . "\n";
+}
+
+# output struct as list
+sub output_struct_list(%) {
+    my %args = %{$_[0]};
+
+    print $args{'struct'} . "\n";
+}
+
+sub output_blockhead_list(%) {
+    my %args = %{$_[0]};
+    my ($parameter, $section);
+
+    foreach $section (@{$args{'sectionlist'}}) {
+	print "DOC: $section\n";
+    }
+}
+
+##
+# generic output function for all types (function, struct/union, typedef, enum);
+# calls the generated, variable output_ function name based on
+# functype and output_mode
+sub output_declaration {
+    no strict 'refs';
+    my $name = shift;
+    my $functype = shift;
+    my $func = "output_${functype}_$output_mode";
+    if (($function_only==0) ||
+	( $function_only == 1 && defined($function_table{$name})) ||
+	( $function_only == 2 && !defined($function_table{$name})))
+    {
+	&$func(@_);
+	$section_counter++;
+    }
+}
+
+##
+# generic output function - calls the right one based on current output mode.
+sub output_blockhead {
+    no strict 'refs';
+    my $func = "output_blockhead_" . $output_mode;
+    &$func(@_);
+    $section_counter++;
+}
+
+##
+# takes a declaration (struct, union, enum, typedef) and
+# invokes the right handler. NOT called for functions.
+sub dump_declaration($$) {
+    no strict 'refs';
+    my ($prototype, $file) = @_;
+    my $func = "dump_" . $decl_type;
+    &$func(@_);
+}
+
+sub dump_union($$) {
+    dump_struct(@_);
+}
+
+sub dump_struct($$) {
+    my $x = shift;
+    my $file = shift;
+    my $nested;
+
+    if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
+	#my $decl_type = $1;
+	$declaration_name = $2;
+	my $members = $3;
+
+	# ignore embedded structs or unions
+	$members =~ s/({.*})//g;
+	$nested = $1;
+
+	# ignore members marked private:
+	$members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gos;
+	$members =~ s/\/\*\s*private:.*//gos;
+	# strip comments:
+	$members =~ s/\/\*.*?\*\///gos;
+	$nested =~ s/\/\*.*?\*\///gos;
+	# strip kmemcheck_bitfield_{begin,end}.*;
+	$members =~ s/kmemcheck_bitfield_.*?;//gos;
+	# strip attributes
+	$members =~ s/__aligned\s*\(\d+\)//gos;
+
+	create_parameterlist($members, ';', $file);
+	check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested);
+
+	output_declaration($declaration_name,
+			   'struct',
+			   {'struct' => $declaration_name,
+			    'module' => $modulename,
+			    'parameterlist' => \@parameterlist,
+			    'parameterdescs' => \%parameterdescs,
+			    'parametertypes' => \%parametertypes,
+			    'sectionlist' => \@sectionlist,
+			    'sections' => \%sections,
+			    'purpose' => $declaration_purpose,
+			    'type' => $decl_type
+			   });
+    }
+    else {
+	print STDERR "Error(${file}:$.): Cannot parse struct or union!\n";
+	++$errors;
+    }
+}
+
+sub dump_enum($$) {
+    my $x = shift;
+    my $file = shift;
+
+    $x =~ s@/\*.*?\*/@@gos;	# strip comments.
+    $x =~ s/^#\s*define\s+.*$//; # strip #define macros inside enums
+
+    if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
+	$declaration_name = $1;
+	my $members = $2;
+
+	foreach my $arg (split ',', $members) {
+	    $arg =~ s/^\s*(\w+).*/$1/;
+	    push @parameterlist, $arg;
+	    if (!$parameterdescs{$arg}) {
+		$parameterdescs{$arg} = $undescribed;
+		print STDERR "Warning(${file}:$.): Enum value '$arg' ".
+		    "not described in enum '$declaration_name'\n";
+	    }
+
+	}
+
+	output_declaration($declaration_name,
+			   'enum',
+			   {'enum' => $declaration_name,
+			    'module' => $modulename,
+			    'parameterlist' => \@parameterlist,
+			    'parameterdescs' => \%parameterdescs,
+			    'sectionlist' => \@sectionlist,
+			    'sections' => \%sections,
+			    'purpose' => $declaration_purpose
+			   });
+    }
+    else {
+	print STDERR "Error(${file}:$.): Cannot parse enum!\n";
+	++$errors;
+    }
+}
+
+sub dump_typedef($$) {
+    my $x = shift;
+    my $file = shift;
+
+    $x =~ s@/\*.*?\*/@@gos;	# strip comments.
+    while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) {
+	$x =~ s/\(*.\)\s*;$/;/;
+	$x =~ s/\[*.\]\s*;$/;/;
+    }
+
+    if ($x =~ /typedef.*\s+(\w+)\s*;/) {
+	$declaration_name = $1;
+
+	output_declaration($declaration_name,
+			   'typedef',
+			   {'typedef' => $declaration_name,
+			    'module' => $modulename,
+			    'sectionlist' => \@sectionlist,
+			    'sections' => \%sections,
+			    'purpose' => $declaration_purpose
+			   });
+    }
+    else {
+	print STDERR "Error(${file}:$.): Cannot parse typedef!\n";
+	++$errors;
+    }
+}
+
+sub save_struct_actual($) {
+    my $actual = shift;
+
+    # strip all spaces from the actual param so that it looks like one string item
+    $actual =~ s/\s*//g;
+    $struct_actual = $struct_actual . $actual . " ";
+}
+
+sub create_parameterlist($$$) {
+    my $args = shift;
+    my $splitter = shift;
+    my $file = shift;
+    my $type;
+    my $param;
+
+    # temporarily replace commas inside function pointer definition
+    while ($args =~ /(\([^\),]+),/) {
+	$args =~ s/(\([^\),]+),/$1#/g;
+    }
+
+    foreach my $arg (split($splitter, $args)) {
+	# strip comments
+	$arg =~ s/\/\*.*\*\///;
+	# strip leading/trailing spaces
+	$arg =~ s/^\s*//;
+	$arg =~ s/\s*$//;
+	$arg =~ s/\s+/ /;
+
+	if ($arg =~ /^#/) {
+	    # Treat preprocessor directive as a typeless variable just to fill
+	    # corresponding data structures "correctly". Catch it later in
+	    # output_* subs.
+	    push_parameter($arg, "", $file);
+	} elsif ($arg =~ m/\(.+\)\s*\(/) {
+	    # pointer-to-function
+	    $arg =~ tr/#/,/;
+	    $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/;
+	    $param = $1;
+	    $type = $arg;
+	    $type =~ s/([^\(]+\(\*?)\s*$param/$1/;
+	    save_struct_actual($param);
+	    push_parameter($param, $type, $file);
+	} elsif ($arg) {
+	    $arg =~ s/\s*:\s*/:/g;
+	    $arg =~ s/\s*\[/\[/g;
+
+	    my @args = split('\s*,\s*', $arg);
+	    if ($args[0] =~ m/\*/) {
+		$args[0] =~ s/(\*+)\s*/ $1/;
+	    }
+
+	    my @first_arg;
+	    if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) {
+		    shift @args;
+		    push(@first_arg, split('\s+', $1));
+		    push(@first_arg, $2);
+	    } else {
+		    @first_arg = split('\s+', shift @args);
+	    }
+
+	    unshift(@args, pop @first_arg);
+	    $type = join " ", @first_arg;
+
+	    foreach $param (@args) {
+		if ($param =~ m/^(\*+)\s*(.*)/) {
+		    save_struct_actual($2);
+		    push_parameter($2, "$type $1", $file);
+		}
+		elsif ($param =~ m/(.*?):(\d+)/) {
+		    if ($type ne "") { # skip unnamed bit-fields
+			save_struct_actual($1);
+			push_parameter($1, "$type:$2", $file)
+		    }
+		}
+		else {
+		    save_struct_actual($param);
+		    push_parameter($param, $type, $file);
+		}
+	    }
+	}
+    }
+}
+
+sub push_parameter($$$) {
+	my $param = shift;
+	my $type = shift;
+	my $file = shift;
+
+	if (($anon_struct_union == 1) && ($type eq "") &&
+	    ($param eq "}")) {
+		return;		# ignore the ending }; from anon. struct/union
+	}
+
+	$anon_struct_union = 0;
+	my $param_name = $param;
+	$param_name =~ s/\[.*//;
+
+	if ($type eq "" && $param =~ /\.\.\.$/)
+	{
+	    if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") {
+		$parameterdescs{$param} = "variable arguments";
+	    }
+	}
+	elsif ($type eq "" && ($param eq "" or $param eq "void"))
+	{
+	    $param="void";
+	    $parameterdescs{void} = "no arguments";
+	}
+	elsif ($type eq "" && ($param eq "struct" or $param eq "union"))
+	# handle unnamed (anonymous) union or struct:
+	{
+		$type = $param;
+		$param = "{unnamed_" . $param . "}";
+		$parameterdescs{$param} = "anonymous\n";
+		$anon_struct_union = 1;
+	}
+
+	# warn if parameter has no description
+	# (but ignore ones starting with # as these are not parameters
+	# but inline preprocessor statements);
+	# also ignore unnamed structs/unions;
+	if (!$anon_struct_union) {
+	if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) {
+
+	    $parameterdescs{$param_name} = $undescribed;
+
+	    if (($type eq 'function') || ($type eq 'enum')) {
+		print STDERR "Warning(${file}:$.): Function parameter ".
+		    "or member '$param' not " .
+		    "described in '$declaration_name'\n";
+	    }
+	    print STDERR "Warning(${file}:$.):" .
+			 " No description found for parameter '$param'\n";
+	    ++$warnings;
+	}
+	}
+
+	$param = xml_escape($param);
+
+	# strip spaces from $param so that it is one continuous string
+	# on @parameterlist;
+	# this fixes a problem where check_sections() cannot find
+	# a parameter like "addr[6 + 2]" because it actually appears
+	# as "addr[6", "+", "2]" on the parameter list;
+	# but it's better to maintain the param string unchanged for output,
+	# so just weaken the string compare in check_sections() to ignore
+	# "[blah" in a parameter string;
+	###$param =~ s/\s*//g;
+	push @parameterlist, $param;
+	$parametertypes{$param} = $type;
+}
+
+sub check_sections($$$$$$) {
+	my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_;
+	my @sects = split ' ', $sectcheck;
+	my @prms = split ' ', $prmscheck;
+	my $err;
+	my ($px, $sx);
+	my $prm_clean;		# strip trailing "[array size]" and/or beginning "*"
+
+	foreach $sx (0 .. $#sects) {
+		$err = 1;
+		foreach $px (0 .. $#prms) {
+			$prm_clean = $prms[$px];
+			$prm_clean =~ s/\[.*\]//;
+			$prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
+			# ignore array size in a parameter string;
+			# however, the original param string may contain
+			# spaces, e.g.:  addr[6 + 2]
+			# and this appears in @prms as "addr[6" since the
+			# parameter list is split at spaces;
+			# hence just ignore "[..." for the sections check;
+			$prm_clean =~ s/\[.*//;
+
+			##$prm_clean =~ s/^\**//;
+			if ($prm_clean eq $sects[$sx]) {
+				$err = 0;
+				last;
+			}
+		}
+		if ($err) {
+			if ($decl_type eq "function") {
+				print STDERR "Warning(${file}:$.): " .
+					"Excess function parameter " .
+					"'$sects[$sx]' " .
+					"description in '$decl_name'\n";
+				++$warnings;
+			} else {
+				if ($nested !~ m/\Q$sects[$sx]\E/) {
+				    print STDERR "Warning(${file}:$.): " .
+					"Excess struct/union/enum/typedef member " .
+					"'$sects[$sx]' " .
+					"description in '$decl_name'\n";
+				    ++$warnings;
+				}
+			}
+		}
+	}
+}
+
+##
+# takes a function prototype and the name of the current file being
+# processed and spits out all the details stored in the global
+# arrays/hashes.
+sub dump_function($$) {
+    my $prototype = shift;
+    my $file = shift;
+
+    $prototype =~ s/^static +//;
+    $prototype =~ s/^extern +//;
+    $prototype =~ s/^asmlinkage +//;
+    $prototype =~ s/^inline +//;
+    $prototype =~ s/^__inline__ +//;
+    $prototype =~ s/^__inline +//;
+    $prototype =~ s/^__always_inline +//;
+    $prototype =~ s/^noinline +//;
+    $prototype =~ s/__devinit +//;
+    $prototype =~ s/__init +//;
+    $prototype =~ s/__init_or_module +//;
+    $prototype =~ s/__must_check +//;
+    $prototype =~ s/__weak +//;
+    $prototype =~ s/^#\s*define\s+//; #ak added
+    $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//;
+
+    # Yes, this truly is vile.  We are looking for:
+    # 1. Return type (may be nothing if we're looking at a macro)
+    # 2. Function name
+    # 3. Function parameters.
+    #
+    # All the while we have to watch out for function pointer parameters
+    # (which IIRC is what the two sections are for), C types (these
+    # regexps don't even start to express all the possibilities), and
+    # so on.
+    #
+    # If you mess with these regexps, it's a good idea to check that
+    # the following functions' documentation still comes out right:
+    # - parport_register_device (function pointer parameters)
+    # - atomic_set (macro)
+    # - pci_match_device, __copy_to_user (long return type)
+
+    if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+	$prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+	$prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+	$prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+	$prototype =~ m/^(\w+\s+\w+\s*\*\s*\w+\s*\*\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/)  {
+	$return_type = $1;
+	$declaration_name = $2;
+	my $args = $3;
+
+	create_parameterlist($args, ',', $file);
+    } else {
+	print STDERR "Error(${file}:$.): cannot understand prototype: '$prototype'\n";
+	++$errors;
+	return;
+    }
+
+	my $prms = join " ", @parameterlist;
+	check_sections($file, $declaration_name, "function", $sectcheck, $prms, "");
+
+    output_declaration($declaration_name,
+		       'function',
+		       {'function' => $declaration_name,
+			'module' => $modulename,
+			'functiontype' => $return_type,
+			'parameterlist' => \@parameterlist,
+			'parameterdescs' => \%parameterdescs,
+			'parametertypes' => \%parametertypes,
+			'sectionlist' => \@sectionlist,
+			'sections' => \%sections,
+			'purpose' => $declaration_purpose
+		       });
+}
+
+sub reset_state {
+    $function = "";
+    %constants = ();
+    %parameterdescs = ();
+    %parametertypes = ();
+    @parameterlist = ();
+    %sections = ();
+    @sectionlist = ();
+    $sectcheck = "";
+    $struct_actual = "";
+    $prototype = "";
+
+    $state = 0;
+}
+
+sub tracepoint_munge($) {
+	my $file = shift;
+	my $tracepointname = 0;
+	my $tracepointargs = 0;
+
+	if ($prototype =~ m/TRACE_EVENT\((.*?),/) {
+		$tracepointname = $1;
+	}
+	if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) {
+		$tracepointname = $1;
+	}
+	if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) {
+		$tracepointname = $2;
+	}
+	$tracepointname =~ s/^\s+//; #strip leading whitespace
+	if ($prototype =~ m/TP_PROTO\((.*?)\)/) {
+		$tracepointargs = $1;
+	}
+	if (($tracepointname eq 0) || ($tracepointargs eq 0)) {
+		print STDERR "Warning(${file}:$.): Unrecognized tracepoint format: \n".
+			     "$prototype\n";
+	} else {
+		$prototype = "static inline void trace_$tracepointname($tracepointargs)";
+	}
+}
+
+sub syscall_munge() {
+	my $void = 0;
+
+	$prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs
+##	if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) {
+	if ($prototype =~ m/SYSCALL_DEFINE0/) {
+		$void = 1;
+##		$prototype = "long sys_$1(void)";
+	}
+
+	$prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name
+	if ($prototype =~ m/long (sys_.*?),/) {
+		$prototype =~ s/,/\(/;
+	} elsif ($void) {
+		$prototype =~ s/\)/\(void\)/;
+	}
+
+	# now delete all of the odd-number commas in $prototype
+	# so that arg types & arg names don't have a comma between them
+	my $count = 0;
+	my $len = length($prototype);
+	if ($void) {
+		$len = 0;	# skip the for-loop
+	}
+	for (my $ix = 0; $ix < $len; $ix++) {
+		if (substr($prototype, $ix, 1) eq ',') {
+			$count++;
+			if ($count % 2 == 1) {
+				substr($prototype, $ix, 1) = ' ';
+			}
+		}
+	}
+}
+
+sub process_state3_function($$) {
+    my $x = shift;
+    my $file = shift;
+
+    $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
+
+    if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) {
+	# do nothing
+    }
+    elsif ($x =~ /([^\{]*)/) {
+	$prototype .= $1;
+    }
+
+    if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) {
+	$prototype =~ s@/\*.*?\*/@@gos;	# strip comments.
+	$prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
+	$prototype =~ s@^\s+@@gos; # strip leading spaces
+	if ($prototype =~ /SYSCALL_DEFINE/) {
+		syscall_munge();
+	}
+	if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ ||
+	    $prototype =~ /DEFINE_SINGLE_EVENT/)
+	{
+		tracepoint_munge($file);
+	}
+	dump_function($prototype, $file);
+	reset_state();
+    }
+}
+
+sub process_state3_type($$) {
+    my $x = shift;
+    my $file = shift;
+
+    $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
+    $x =~ s@^\s+@@gos; # strip leading spaces
+    $x =~ s@\s+$@@gos; # strip trailing spaces
+    $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
+
+    if ($x =~ /^#/) {
+	# To distinguish preprocessor directive from regular declaration later.
+	$x .= ";";
+    }
+
+    while (1) {
+	if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
+	    $prototype .= $1 . $2;
+	    ($2 eq '{') && $brcount++;
+	    ($2 eq '}') && $brcount--;
+	    if (($2 eq ';') && ($brcount == 0)) {
+		dump_declaration($prototype, $file);
+		reset_state();
+		last;
+	    }
+	    $x = $3;
+	} else {
+	    $prototype .= $x;
+	    last;
+	}
+    }
+}
+
+# xml_escape: replace <, >, and & in the text stream;
+#
+# however, formatting controls that are generated internally/locally in the
+# kernel-doc script are not escaped here; instead, they begin life like
+# $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings
+# are converted to their mnemonic-expected output, without the 4 * '\' & ':',
+# just before actual output; (this is done by local_unescape())
+sub xml_escape($) {
+	my $text = shift;
+	if (($output_mode eq "text") || ($output_mode eq "man")) {
+		return $text;
+	}
+	$text =~ s/\&/\\\\\\amp;/g;
+	$text =~ s/\</\\\\\\lt;/g;
+	$text =~ s/\>/\\\\\\gt;/g;
+	return $text;
+}
+
+# convert local escape strings to html
+# local escape strings look like:  '\\\\menmonic:' (that's 4 backslashes)
+sub local_unescape($) {
+	my $text = shift;
+	if (($output_mode eq "text") || ($output_mode eq "man")) {
+		return $text;
+	}
+	$text =~ s/\\\\\\\\lt:/</g;
+	$text =~ s/\\\\\\\\gt:/>/g;
+	return $text;
+}
+
+sub process_file($) {
+    my $file;
+    my $identifier;
+    my $func;
+    my $descr;
+    my $in_purpose = 0;
+    my $initial_section_counter = $section_counter;
+
+    if (defined($ENV{'SRCTREE'})) {
+	$file = "$ENV{'SRCTREE'}" . "/" . "@_";
+    }
+    else {
+	$file = "@_";
+    }
+    if (defined($source_map{$file})) {
+	$file = $source_map{$file};
+    }
+
+    if (!open(IN,"<$file")) {
+	print STDERR "Error: Cannot open file $file\n";
+	++$errors;
+	return;
+    }
+
+    $. = 1;
+
+    $section_counter = 0;
+    while (<IN>) {
+	if ($state == 0) {
+	    if (/$doc_start/o) {
+		$state = 1;		# next line is always the function name
+		$in_doc_sect = 0;
+	    }
+	} elsif ($state == 1) {	# this line is the function name (always)
+	    if (/$doc_block/o) {
+		$state = 4;
+		$contents = "";
+		if ( $1 eq "" ) {
+			$section = $section_intro;
+		} else {
+			$section = $1;
+		}
+	    }
+	    elsif (/$doc_decl/o) {
+		$identifier = $1;
+		if (/\s*([\w\s]+?)\s*-/) {
+		    $identifier = $1;
+		}
+
+		$state = 2;
+		if (/-(.*)/) {
+		    # strip leading/trailing/multiple spaces
+		    $descr= $1;
+		    $descr =~ s/^\s*//;
+		    $descr =~ s/\s*$//;
+		    $descr =~ s/\s+/ /;
+		    $declaration_purpose = xml_escape($descr);
+		    $in_purpose = 1;
+		} else {
+		    $declaration_purpose = "";
+		}
+
+		if (($declaration_purpose eq "") && $verbose) {
+			print STDERR "Warning(${file}:$.): missing initial short description on line:\n";
+			print STDERR $_;
+			++$warnings;
+		}
+
+		if ($identifier =~ m/^struct/) {
+		    $decl_type = 'struct';
+		} elsif ($identifier =~ m/^union/) {
+		    $decl_type = 'union';
+		} elsif ($identifier =~ m/^enum/) {
+		    $decl_type = 'enum';
+		} elsif ($identifier =~ m/^typedef/) {
+		    $decl_type = 'typedef';
+		} else {
+		    $decl_type = 'function';
+		}
+
+		if ($verbose) {
+		    print STDERR "Info(${file}:$.): Scanning doc for $identifier\n";
+		}
+	    } else {
+		print STDERR "Warning(${file}:$.): Cannot understand $_ on line $.",
+		" - I thought it was a doc line\n";
+		++$warnings;
+		$state = 0;
+	    }
+	} elsif ($state == 2) {	# look for head: lines, and include content
+	    if (/$doc_sect/o) {
+		$newsection = $1;
+		$newcontents = $2;
+
+		if (($contents ne "") && ($contents ne "\n")) {
+		    if (!$in_doc_sect && $verbose) {
+			print STDERR "Warning(${file}:$.): contents before sections\n";
+			++$warnings;
+		    }
+		    dump_section($file, $section, xml_escape($contents));
+		    $section = $section_default;
+		}
+
+		$in_doc_sect = 1;
+		$in_purpose = 0;
+		$contents = $newcontents;
+		if ($contents ne "") {
+		    while ((substr($contents, 0, 1) eq " ") ||
+			substr($contents, 0, 1) eq "\t") {
+			    $contents = substr($contents, 1);
+		    }
+		    $contents .= "\n";
+		}
+		$section = $newsection;
+	    } elsif (/$doc_end/) {
+
+		if (($contents ne "") && ($contents ne "\n")) {
+		    dump_section($file, $section, xml_escape($contents));
+		    $section = $section_default;
+		    $contents = "";
+		}
+		# look for doc_com + <text> + doc_end:
+		if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') {
+		    print STDERR "Warning(${file}:$.): suspicious ending line: $_";
+		    ++$warnings;
+		}
+
+		$prototype = "";
+		$state = 3;
+		$brcount = 0;
+#		print STDERR "end of doc comment, looking for prototype\n";
+	    } elsif (/$doc_content/) {
+		# miguel-style comment kludge, look for blank lines after
+		# @parameter line to signify start of description
+		if ($1 eq "") {
+		    if ($section =~ m/^@/ || $section eq $section_context) {
+			dump_section($file, $section, xml_escape($contents));
+			$section = $section_default;
+			$contents = "";
+		    } else {
+			$contents .= "\n";
+		    }
+		    $in_purpose = 0;
+		} elsif ($in_purpose == 1) {
+		    # Continued declaration purpose
+		    chomp($declaration_purpose);
+		    $declaration_purpose .= " " . xml_escape($1);
+		} elsif ($section =~ m/^Example/) {
+		    $_ =~ s/^\s*\*//;
+		    $contents .= $_;
+		} else {
+		    $contents .= $1 . "\n";
+		}
+	    } else {
+		# i dont know - bad line?  ignore.
+		print STDERR "Warning(${file}:$.): bad line: $_";
+		++$warnings;
+	    }
+	} elsif ($state == 3) {	# scanning for function '{' (end of prototype)
+	    if ($decl_type eq 'function') {
+		process_state3_function($_, $file);
+	    } else {
+		process_state3_type($_, $file);
+	    }
+	} elsif ($state == 4) {
+		# Documentation block
+		if (/$doc_block/) {
+			dump_doc_section($file, $section, xml_escape($contents));
+			$contents = "";
+			$function = "";
+			%constants = ();
+			%parameterdescs = ();
+			%parametertypes = ();
+			@parameterlist = ();
+			%sections = ();
+			@sectionlist = ();
+			$prototype = "";
+			if ( $1 eq "" ) {
+				$section = $section_intro;
+			} else {
+				$section = $1;
+			}
+		}
+		elsif (/$doc_end/)
+		{
+			dump_doc_section($file, $section, xml_escape($contents));
+			$contents = "";
+			$function = "";
+			%constants = ();
+			%parameterdescs = ();
+			%parametertypes = ();
+			@parameterlist = ();
+			%sections = ();
+			@sectionlist = ();
+			$prototype = "";
+			$state = 0;
+		}
+		elsif (/$doc_content/)
+		{
+			if ( $1 eq "" )
+			{
+				$contents .= $blankline;
+			}
+			else
+			{
+				$contents .= $1 . "\n";
+			}
+		}
+	}
+    }
+    if ($initial_section_counter == $section_counter) {
+	print STDERR "Warning(${file}): no structured comments found\n";
+	if ($output_mode eq "xml") {
+	    # The template wants at least one RefEntry here; make one.
+	    print "<refentry>\n";
+	    print " <refnamediv>\n";
+	    print "  <refname>\n";
+	    print "   ${file}\n";
+	    print "  </refname>\n";
+	    print "  <refpurpose>\n";
+	    print "   Document generation inconsistency\n";
+	    print "  </refpurpose>\n";
+	    print " </refnamediv>\n";
+	    print " <refsect1>\n";
+	    print "  <title>\n";
+	    print "   Oops\n";
+	    print "  </title>\n";
+	    print "  <warning>\n";
+	    print "   <para>\n";
+	    print "    The template for this document tried to insert\n";
+	    print "    the structured comment from the file\n";
+	    print "    <filename>${file}</filename> at this point,\n";
+	    print "    but none was found.\n";
+	    print "    This dummy section is inserted to allow\n";
+	    print "    generation to continue.\n";
+	    print "   </para>\n";
+	    print "  </warning>\n";
+	    print " </refsect1>\n";
+	    print "</refentry>\n";
+	}
+    }
+}
+
+
+$kernelversion = get_kernel_version();
+
+# generate a sequence of code that will splice in highlighting information
+# using the s// operator.
+foreach my $pattern (keys %highlights) {
+#   print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n";
+    $dohighlight .=  "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n";
+}
+
+# Read the file that maps relative names to absolute names for
+# separate source and object directories and for shadow trees.
+if (open(SOURCE_MAP, "<.tmp_filelist.txt")) {
+	my ($relname, $absname);
+	while(<SOURCE_MAP>) {
+		chop();
+		($relname, $absname) = (split())[0..1];
+		$relname =~ s:^/+::;
+		$source_map{$relname} = $absname;
+	}
+	close(SOURCE_MAP);
+}
+
+foreach (@ARGV) {
+    chomp;
+    process_file($_);
+}
+if ($verbose && $errors) {
+  print STDERR "$errors errors\n";
+}
+if ($verbose && $warnings) {
+  print STDERR "$warnings warnings\n";
+}
+
+exit($errors);
diff --git a/marvell/uboot/tools/kwbimage.c b/marvell/uboot/tools/kwbimage.c
new file mode 100644
index 0000000..109d616
--- /dev/null
+++ b/marvell/uboot/tools/kwbimage.c
@@ -0,0 +1,386 @@
+/*
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "imagetool.h"
+#include <image.h>
+#include "kwbimage.h"
+
+/*
+ * Supported commands for configuration file
+ */
+static table_entry_t kwbimage_cmds[] = {
+	{CMD_BOOT_FROM,		"BOOT_FROM",		"boot command",	},
+	{CMD_NAND_ECC_MODE,	"NAND_ECC_MODE",	"NAND mode",	},
+	{CMD_NAND_PAGE_SIZE,	"NAND_PAGE_SIZE",	"NAND size",	},
+	{CMD_SATA_PIO_MODE,	"SATA_PIO_MODE",	"SATA mode",	},
+	{CMD_DDR_INIT_DELAY,	"DDR_INIT_DELAY",	"DDR init dly",	},
+	{CMD_DATA,		"DATA",			"Reg Write Data", },
+	{CMD_INVALID,		"",			"",	},
+};
+
+/*
+ * Supported Boot options for configuration file
+ */
+static table_entry_t kwbimage_bootops[] = {
+	{IBR_HDR_SPI_ID,	"spi",		"SPI Flash",	},
+	{IBR_HDR_NAND_ID,	"nand",		"NAND Flash",	},
+	{IBR_HDR_SATA_ID,	"sata",		"Sata port",	},
+	{IBR_HDR_PEX_ID,	"pex",		"PCIe port",	},
+	{IBR_HDR_UART_ID,	"uart",		"Serial port",	},
+	{-1,			"",		"Invalid",	},
+};
+
+/*
+ * Supported NAND ecc options configuration file
+ */
+static table_entry_t kwbimage_eccmodes[] = {
+	{IBR_HDR_ECC_DEFAULT,		"default",	"Default mode",	},
+	{IBR_HDR_ECC_FORCED_HAMMING,	"hamming",	"Hamming mode",	},
+	{IBR_HDR_ECC_FORCED_RS,		"rs",		"RS mode",	},
+	{IBR_HDR_ECC_DISABLED,		"disabled",	"ECC Disabled",	},
+	{-1,				"",		"",	},
+};
+
+static struct kwb_header kwbimage_header;
+static int datacmd_cnt = 0;
+static char * fname = "Unknown";
+static int lineno = -1;
+
+/*
+ * Report Error if xflag is set in addition to default
+ */
+static int kwbimage_check_params(struct image_tool_params *params)
+{
+	if (!strlen (params->imagename)) {
+		printf ("Error:%s - Configuration file not specified, "
+			"it is needed for kwbimage generation\n",
+			params->cmdname);
+		return CFG_INVALID;
+	}
+	return	((params->dflag && (params->fflag || params->lflag)) ||
+		(params->fflag && (params->dflag || params->lflag)) ||
+		(params->lflag && (params->dflag || params->fflag)) ||
+		(params->xflag) || !(strlen (params->imagename)));
+}
+
+static uint32_t check_get_hexval (char *token)
+{
+	uint32_t hexval;
+
+	if (!sscanf (token, "%x", &hexval)) {
+		printf ("Error:%s[%d] - Invalid hex data(%s)\n", fname,
+			lineno, token);
+		exit (EXIT_FAILURE);
+	}
+	return hexval;
+}
+
+/*
+ * Generates 8 bit checksum
+ */
+static uint8_t kwbimage_checksum8 (void *start, uint32_t len, uint8_t csum)
+{
+	register uint8_t sum = csum;
+	volatile uint8_t *p = (volatile uint8_t *)start;
+
+	/* check len and return zero checksum if invalid */
+	if (!len)
+		return 0;
+
+	do {
+		sum += *p;
+		p++;
+	} while (--len);
+	return (sum);
+}
+
+/*
+ * Generates 32 bit checksum
+ */
+static uint32_t kwbimage_checksum32 (uint32_t *start, uint32_t len, uint32_t csum)
+{
+	register uint32_t sum = csum;
+	volatile uint32_t *p = start;
+
+	/* check len and return zero checksum if invalid */
+	if (!len)
+		return 0;
+
+	if (len % sizeof(uint32_t)) {
+		printf ("Error:%s[%d] - length is not in multiple of %zu\n",
+			__FUNCTION__, len, sizeof(uint32_t));
+		return 0;
+	}
+
+	do {
+		sum += *p;
+		p++;
+		len -= sizeof(uint32_t);
+	} while (len > 0);
+	return (sum);
+}
+
+static void kwbimage_check_cfgdata (char *token, enum kwbimage_cmd cmdsw,
+					struct kwb_header *kwbhdr)
+{
+	bhr_t *mhdr = &kwbhdr->kwb_hdr;
+	extbhr_t *exthdr = &kwbhdr->kwb_exthdr;
+	int i;
+
+	switch (cmdsw) {
+	case CMD_BOOT_FROM:
+		i = get_table_entry_id (kwbimage_bootops,
+				"Kwbimage boot option", token);
+
+		if (i < 0)
+			goto INVL_DATA;
+
+		mhdr->blockid = i;
+		printf ("Preparing kirkwood boot image to boot "
+			"from %s\n", token);
+		break;
+	case CMD_NAND_ECC_MODE:
+		i = get_table_entry_id (kwbimage_eccmodes,
+			"NAND ecc mode", token);
+
+		if (i < 0)
+			goto INVL_DATA;
+
+		mhdr->nandeccmode = i;
+		printf ("Nand ECC mode = %s\n", token);
+		break;
+	case CMD_NAND_PAGE_SIZE:
+		mhdr->nandpagesize =
+			(uint16_t) check_get_hexval (token);
+		printf ("Nand page size = 0x%x\n", mhdr->nandpagesize);
+		break;
+	case CMD_SATA_PIO_MODE:
+		mhdr->satapiomode =
+			(uint8_t) check_get_hexval (token);
+		printf ("Sata PIO mode = 0x%x\n",
+				mhdr->satapiomode);
+		break;
+	case CMD_DDR_INIT_DELAY:
+		mhdr->ddrinitdelay =
+			(uint16_t) check_get_hexval (token);
+		printf ("DDR init delay = %d msec\n", mhdr->ddrinitdelay);
+		break;
+	case CMD_DATA:
+		exthdr->rcfg[datacmd_cnt].raddr =
+			check_get_hexval (token);
+
+		break;
+	case CMD_INVALID:
+		goto INVL_DATA;
+	default:
+		goto INVL_DATA;
+	}
+	return;
+
+INVL_DATA:
+	printf ("Error:%s[%d] - Invalid data\n", fname, lineno);
+	exit (EXIT_FAILURE);
+}
+
+/*
+ * this function sets the kwbimage header by-
+ * 	1. Abstracting input command line arguments data
+ *	2. parses the kwbimage configuration file and update extebded header data
+ *	3. calculates header, extended header and image checksums
+ */
+static void kwdimage_set_ext_header (struct kwb_header *kwbhdr, char* name) {
+	bhr_t *mhdr = &kwbhdr->kwb_hdr;
+	extbhr_t *exthdr = &kwbhdr->kwb_exthdr;
+	FILE *fd = NULL;
+	int j;
+	char *line = NULL;
+	char * token, *saveptr1, *saveptr2;
+	size_t len = 0;
+	enum kwbimage_cmd cmd;
+
+	fname = name;
+	/* set dram register offset */
+	exthdr->dramregsoffs = (intptr_t)&exthdr->rcfg - (intptr_t)mhdr;
+
+	if ((fd = fopen (name, "r")) == 0) {
+		printf ("Error:%s - Can't open\n", fname);
+		exit (EXIT_FAILURE);
+	}
+
+	/* Simple kwimage.cfg file parser */
+	lineno=0;
+	while ((getline (&line, &len, fd)) > 0) {
+		lineno++;
+		token = strtok_r (line, "\r\n", &saveptr1);
+		/* drop all lines with zero tokens (= empty lines) */
+		if (token == NULL)
+			continue;
+
+		for (j = 0, cmd = CMD_INVALID, line = token; ; line = NULL) {
+			token = strtok_r (line, " \t", &saveptr2);
+			if (token == NULL)
+			break;
+			/* Drop all text starting with '#' as comments */
+			if (token[0] == '#')
+				break;
+
+			/* Process rest as valid config command line */
+			switch (j) {
+			case CFG_COMMAND:
+				cmd = get_table_entry_id (kwbimage_cmds,
+						"Kwbimage command", token);
+
+				if (cmd == CMD_INVALID)
+					goto INVL_CMD;
+				break;
+
+			case CFG_DATA0:
+				kwbimage_check_cfgdata (token, cmd, kwbhdr);
+				break;
+
+			case CFG_DATA1:
+				if (cmd != CMD_DATA)
+					goto INVL_CMD;
+
+				exthdr->rcfg[datacmd_cnt].rdata =
+						check_get_hexval (token);
+
+				if (datacmd_cnt > KWBIMAGE_MAX_CONFIG ) {
+					printf ("Error:%s[%d] - Found more "
+						"than max(%zd) allowed "
+						"data configurations\n",
+						fname, lineno,
+						KWBIMAGE_MAX_CONFIG);
+				exit (EXIT_FAILURE);
+				} else
+					datacmd_cnt++;
+				break;
+
+			default:
+				goto INVL_CMD;
+			}
+			j++;
+		}
+	}
+	if (line)
+		free (line);
+
+	fclose (fd);
+	return;
+
+/*
+ * Invalid Command error reporring
+ *
+ * command CMD_DATA needs three strings on a line
+ * whereas other commands need only two.
+ *
+ * if more than two/three (as per command type) are observed,
+ * then error will be reported
+ */
+INVL_CMD:
+	printf ("Error:%s[%d] - Invalid command\n", fname, lineno);
+	exit (EXIT_FAILURE);
+}
+
+static void kwbimage_set_header (void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+	struct kwb_header *hdr = (struct kwb_header *)ptr;
+	bhr_t *mhdr = &hdr->kwb_hdr;
+	extbhr_t *exthdr = &hdr->kwb_exthdr;
+	uint32_t checksum;
+	int size;
+
+	/* Build and add image checksum header */
+	checksum = kwbimage_checksum32 ((uint32_t *)ptr, sbuf->st_size, 0);
+
+	size = write (ifd, &checksum, sizeof(uint32_t));
+	if (size != sizeof(uint32_t)) {
+		printf ("Error:%s - Checksum write %d bytes %s\n",
+			params->cmdname, size, params->imagefile);
+		exit (EXIT_FAILURE);
+	}
+
+	sbuf->st_size += sizeof(uint32_t);
+
+	mhdr->blocksize = sbuf->st_size - sizeof(struct kwb_header);
+	mhdr->srcaddr = sizeof(struct kwb_header);
+	mhdr->destaddr= params->addr;
+	mhdr->execaddr =params->ep;
+	mhdr->ext = 0x1; /* header extension appended */
+
+	kwdimage_set_ext_header (hdr, params->imagename);
+	/* calculate checksums */
+	mhdr->checkSum = kwbimage_checksum8 ((void *)mhdr, sizeof(bhr_t), 0);
+	exthdr->checkSum = kwbimage_checksum8 ((void *)exthdr,
+						sizeof(extbhr_t), 0);
+}
+
+static int kwbimage_verify_header (unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	struct kwb_header *hdr = (struct kwb_header *)ptr;
+	bhr_t *mhdr = &hdr->kwb_hdr;
+	extbhr_t *exthdr = &hdr->kwb_exthdr;
+	uint8_t calc_hdrcsum;
+	uint8_t calc_exthdrcsum;
+
+	calc_hdrcsum = kwbimage_checksum8 ((void *)mhdr,
+			sizeof(bhr_t) - sizeof(uint8_t), 0);
+	if (calc_hdrcsum != mhdr->checkSum)
+		return -FDT_ERR_BADSTRUCTURE;	/* mhdr csum not matched */
+
+	calc_exthdrcsum = kwbimage_checksum8 ((void *)exthdr,
+			sizeof(extbhr_t) - sizeof(uint8_t), 0);
+	if (calc_exthdrcsum != exthdr->checkSum)
+		return -FDT_ERR_BADSTRUCTURE; /* exthdr csum not matched */
+
+	return 0;
+}
+
+static void kwbimage_print_header (const void *ptr)
+{
+	struct kwb_header *hdr = (struct kwb_header *) ptr;
+	bhr_t *mhdr = &hdr->kwb_hdr;
+	char *name = get_table_entry_name (kwbimage_bootops,
+				"Kwbimage boot option",
+				(int) mhdr->blockid);
+
+	printf ("Image Type:   Kirkwood Boot from %s Image\n", name);
+	printf ("Data Size:    ");
+	genimg_print_size (mhdr->blocksize - sizeof(uint32_t));
+	printf ("Load Address: %08x\n", mhdr->destaddr);
+	printf ("Entry Point:  %08x\n", mhdr->execaddr);
+}
+
+static int kwbimage_check_image_types (uint8_t type)
+{
+	if (type == IH_TYPE_KWBIMAGE)
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+}
+
+/*
+ * kwbimage type parameters definition
+ */
+static struct image_type_params kwbimage_params = {
+	.name = "Kirkwood Boot Image support",
+	.header_size = sizeof(struct kwb_header),
+	.hdr = (void*)&kwbimage_header,
+	.check_image_type = kwbimage_check_image_types,
+	.verify_header = kwbimage_verify_header,
+	.print_header = kwbimage_print_header,
+	.set_header = kwbimage_set_header,
+	.check_params = kwbimage_check_params,
+};
+
+void init_kwb_image_type (void)
+{
+	register_image_type(&kwbimage_params);
+}
diff --git a/marvell/uboot/tools/kwbimage.h b/marvell/uboot/tools/kwbimage.h
new file mode 100644
index 0000000..8e4a4e2
--- /dev/null
+++ b/marvell/uboot/tools/kwbimage.h
@@ -0,0 +1,90 @@
+/*
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _KWBIMAGE_H_
+#define _KWBIMAGE_H_
+
+#include <stdint.h>
+
+#define KWBIMAGE_MAX_CONFIG	((0x1dc - 0x20)/sizeof(struct reg_config))
+#define MAX_TEMPBUF_LEN		32
+
+/* NAND ECC Mode */
+#define IBR_HDR_ECC_DEFAULT		0x00
+#define IBR_HDR_ECC_FORCED_HAMMING	0x01
+#define IBR_HDR_ECC_FORCED_RS  		0x02
+#define IBR_HDR_ECC_DISABLED  		0x03
+
+/* Boot Type - block ID */
+#define IBR_HDR_I2C_ID			0x4D
+#define IBR_HDR_SPI_ID			0x5A
+#define IBR_HDR_NAND_ID			0x8B
+#define IBR_HDR_SATA_ID			0x78
+#define IBR_HDR_PEX_ID			0x9C
+#define IBR_HDR_UART_ID			0x69
+#define IBR_DEF_ATTRIB	 		0x00
+
+enum kwbimage_cmd {
+	CMD_INVALID,
+	CMD_BOOT_FROM,
+	CMD_NAND_ECC_MODE,
+	CMD_NAND_PAGE_SIZE,
+	CMD_SATA_PIO_MODE,
+	CMD_DDR_INIT_DELAY,
+	CMD_DATA
+};
+
+enum kwbimage_cmd_types {
+	CFG_INVALID = -1,
+	CFG_COMMAND,
+	CFG_DATA0,
+	CFG_DATA1
+};
+
+/* typedefs */
+typedef struct bhr_t {
+	uint8_t blockid;		/*0     */
+	uint8_t nandeccmode;		/*1     */
+	uint16_t nandpagesize;		/*2-3   */
+	uint32_t blocksize;		/*4-7   */
+	uint32_t rsvd1;			/*8-11  */
+	uint32_t srcaddr;		/*12-15 */
+	uint32_t destaddr;		/*16-19 */
+	uint32_t execaddr;		/*20-23 */
+	uint8_t satapiomode;		/*24    */
+	uint8_t rsvd3;			/*25    */
+	uint16_t ddrinitdelay;		/*26-27 */
+	uint16_t rsvd2;			/*28-29 */
+	uint8_t ext;			/*30    */
+	uint8_t checkSum;		/*31    */
+} bhr_t, *pbhr_t;
+
+struct reg_config {
+	uint32_t raddr;
+	uint32_t rdata;
+};
+
+typedef struct extbhr_t {
+	uint32_t dramregsoffs;
+	uint8_t rsrvd1[0x20 - sizeof(uint32_t)];
+	struct reg_config rcfg[KWBIMAGE_MAX_CONFIG];
+	uint8_t rsrvd2[7];
+	uint8_t checkSum;
+} extbhr_t, *pextbhr_t;
+
+struct kwb_header {
+	bhr_t kwb_hdr;
+	extbhr_t kwb_exthdr;
+};
+
+/*
+ * functions
+ */
+void init_kwb_image_type (void);
+
+#endif /* _KWBIMAGE_H_ */
diff --git a/marvell/uboot/tools/kwboot.c b/marvell/uboot/tools/kwboot.c
new file mode 100644
index 0000000..e773f01
--- /dev/null
+++ b/marvell/uboot/tools/kwboot.c
@@ -0,0 +1,742 @@
+/*
+ * Boot a Marvell Kirkwood SoC, with Xmodem over UART0.
+ *
+ * (c) 2012 Daniel Stodden <daniel.stodden@gmail.com>
+ *
+ * References: marvell.com, "88F6180, 88F6190, 88F6192, and 88F6281
+ *   Integrated Controller: Functional Specifications" December 2,
+ *   2008. Chapter 24.2 "BootROM Firmware".
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "kwbimage.h"
+
+#ifdef __GNUC__
+#define PACKED __attribute((packed))
+#else
+#define PACKED
+#endif
+
+/*
+ * Marvell BootROM UART Sensing
+ */
+
+static unsigned char kwboot_msg_boot[] = {
+	0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
+};
+
+#define KWBOOT_MSG_REQ_DELAY	10 /* ms */
+#define KWBOOT_MSG_RSP_TIMEO	50 /* ms */
+
+/*
+ * Xmodem Transfers
+ */
+
+#define SOH	1	/* sender start of block header */
+#define EOT	4	/* sender end of block transfer */
+#define ACK	6	/* target block ack */
+#define NAK	21	/* target block negative ack */
+#define CAN	24	/* target/sender transfer cancellation */
+
+struct kwboot_block {
+	uint8_t soh;
+	uint8_t pnum;
+	uint8_t _pnum;
+	uint8_t data[128];
+	uint8_t csum;
+} PACKED;
+
+#define KWBOOT_BLK_RSP_TIMEO 1000 /* ms */
+
+static int kwboot_verbose;
+
+static void
+kwboot_printv(const char *fmt, ...)
+{
+	va_list ap;
+
+	if (kwboot_verbose) {
+		va_start(ap, fmt);
+		vprintf(fmt, ap);
+		va_end(ap);
+		fflush(stdout);
+	}
+}
+
+static void
+__spinner(void)
+{
+	const char seq[] = { '-', '\\', '|', '/' };
+	const int div = 8;
+	static int state, bs;
+
+	if (state % div == 0) {
+		fputc(bs, stdout);
+		fputc(seq[state / div % sizeof(seq)], stdout);
+		fflush(stdout);
+	}
+
+	bs = '\b';
+	state++;
+}
+
+static void
+kwboot_spinner(void)
+{
+	if (kwboot_verbose)
+		__spinner();
+}
+
+static void
+__progress(int pct, char c)
+{
+	const int width = 70;
+	static const char *nl = "";
+	static int pos;
+
+	if (pos % width == 0)
+		printf("%s%3d %% [", nl, pct);
+
+	fputc(c, stdout);
+
+	nl = "]\n";
+	pos++;
+
+	if (pct == 100) {
+		while (pos++ < width)
+			fputc(' ', stdout);
+		fputs(nl, stdout);
+	}
+
+	fflush(stdout);
+
+}
+
+static void
+kwboot_progress(int _pct, char c)
+{
+	static int pct;
+
+	if (_pct != -1)
+		pct = _pct;
+
+	if (kwboot_verbose)
+		__progress(pct, c);
+}
+
+static int
+kwboot_tty_recv(int fd, void *buf, size_t len, int timeo)
+{
+	int rc, nfds;
+	fd_set rfds;
+	struct timeval tv;
+	ssize_t n;
+
+	rc = -1;
+
+	FD_ZERO(&rfds);
+	FD_SET(fd, &rfds);
+
+	tv.tv_sec = 0;
+	tv.tv_usec = timeo * 1000;
+	if (tv.tv_usec > 1000000) {
+		tv.tv_sec += tv.tv_usec / 1000000;
+		tv.tv_usec %= 1000000;
+	}
+
+	do {
+		nfds = select(fd + 1, &rfds, NULL, NULL, &tv);
+		if (nfds < 0)
+			goto out;
+		if (!nfds) {
+			errno = ETIMEDOUT;
+			goto out;
+		}
+
+		n = read(fd, buf, len);
+		if (n < 0)
+			goto out;
+
+		buf = (char *)buf + n;
+		len -= n;
+	} while (len > 0);
+
+	rc = 0;
+out:
+	return rc;
+}
+
+static int
+kwboot_tty_send(int fd, const void *buf, size_t len)
+{
+	int rc;
+	ssize_t n;
+
+	rc = -1;
+
+	do {
+		n = write(fd, buf, len);
+		if (n < 0)
+			goto out;
+
+		buf = (char *)buf + n;
+		len -= n;
+	} while (len > 0);
+
+	rc = tcdrain(fd);
+out:
+	return rc;
+}
+
+static int
+kwboot_tty_send_char(int fd, unsigned char c)
+{
+	return kwboot_tty_send(fd, &c, 1);
+}
+
+static speed_t
+kwboot_tty_speed(int baudrate)
+{
+	switch (baudrate) {
+	case 115200:
+		return B115200;
+	case 57600:
+		return B57600;
+	case 38400:
+		return B38400;
+	case 19200:
+		return B19200;
+	case 9600:
+		return B9600;
+	}
+
+	return -1;
+}
+
+static int
+kwboot_open_tty(const char *path, speed_t speed)
+{
+	int rc, fd;
+	struct termios tio;
+
+	rc = -1;
+
+	fd = open(path, O_RDWR|O_NOCTTY|O_NDELAY);
+	if (fd < 0)
+		goto out;
+
+	memset(&tio, 0, sizeof(tio));
+
+	tio.c_iflag = 0;
+	tio.c_cflag = CREAD|CLOCAL|CS8;
+
+	tio.c_cc[VMIN] = 1;
+	tio.c_cc[VTIME] = 10;
+
+	cfsetospeed(&tio, speed);
+	cfsetispeed(&tio, speed);
+
+	rc = tcsetattr(fd, TCSANOW, &tio);
+	if (rc)
+		goto out;
+
+	rc = fd;
+out:
+	if (rc < 0) {
+		if (fd >= 0)
+			close(fd);
+	}
+
+	return rc;
+}
+
+static int
+kwboot_bootmsg(int tty, void *msg)
+{
+	int rc;
+	char c;
+
+	kwboot_printv("Sending boot message. Please reboot the target...");
+
+	do {
+		rc = tcflush(tty, TCIOFLUSH);
+		if (rc)
+			break;
+
+		rc = kwboot_tty_send(tty, msg, 8);
+		if (rc) {
+			usleep(KWBOOT_MSG_REQ_DELAY * 1000);
+			continue;
+		}
+
+		rc = kwboot_tty_recv(tty, &c, 1, KWBOOT_MSG_RSP_TIMEO);
+
+		kwboot_spinner();
+
+	} while (rc || c != NAK);
+
+	kwboot_printv("\n");
+
+	return rc;
+}
+
+static int
+kwboot_xm_makeblock(struct kwboot_block *block, const void *data,
+		    size_t size, int pnum)
+{
+	const size_t blksz = sizeof(block->data);
+	size_t n;
+	int i;
+
+	block->pnum = pnum;
+	block->_pnum = ~block->pnum;
+
+	n = size < blksz ? size : blksz;
+	memcpy(&block->data[0], data, n);
+	memset(&block->data[n], 0, blksz - n);
+
+	block->csum = 0;
+	for (i = 0; i < n; i++)
+		block->csum += block->data[i];
+
+	return n;
+}
+
+static int
+kwboot_xm_sendblock(int fd, struct kwboot_block *block)
+{
+	int rc, retries;
+	char c;
+
+	retries = 16;
+	do {
+		rc = kwboot_tty_send(fd, block, sizeof(*block));
+		if (rc)
+			break;
+
+		rc = kwboot_tty_recv(fd, &c, 1, KWBOOT_BLK_RSP_TIMEO);
+		if (rc)
+			break;
+
+		if (c != ACK)
+			kwboot_progress(-1, '+');
+
+	} while (c == NAK && retries-- > 0);
+
+	rc = -1;
+
+	switch (c) {
+	case ACK:
+		rc = 0;
+		break;
+	case NAK:
+		errno = EBADMSG;
+		break;
+	case CAN:
+		errno = ECANCELED;
+		break;
+	default:
+		errno = EPROTO;
+		break;
+	}
+
+	return rc;
+}
+
+static int
+kwboot_xmodem(int tty, const void *_data, size_t size)
+{
+	const uint8_t *data = _data;
+	int rc, pnum, N, err;
+
+	pnum = 1;
+	N = 0;
+
+	kwboot_printv("Sending boot image...\n");
+
+	do {
+		struct kwboot_block block;
+		int n;
+
+		n = kwboot_xm_makeblock(&block,
+					data + N, size - N,
+					pnum++);
+		if (n < 0)
+			goto can;
+
+		if (!n)
+			break;
+
+		rc = kwboot_xm_sendblock(tty, &block);
+		if (rc)
+			goto out;
+
+		N += n;
+		kwboot_progress(N * 100 / size, '.');
+	} while (1);
+
+	rc = kwboot_tty_send_char(tty, EOT);
+
+out:
+	return rc;
+
+can:
+	err = errno;
+	kwboot_tty_send_char(tty, CAN);
+	errno = err;
+	goto out;
+}
+
+static int
+kwboot_term_pipe(int in, int out, char *quit, int *s)
+{
+	ssize_t nin, nout;
+	char _buf[128], *buf = _buf;
+
+	nin = read(in, buf, sizeof(buf));
+	if (nin < 0)
+		return -1;
+
+	if (quit) {
+		int i;
+
+		for (i = 0; i < nin; i++) {
+			if (*buf == quit[*s]) {
+				(*s)++;
+				if (!quit[*s])
+					return 0;
+				buf++;
+				nin--;
+			} else
+				while (*s > 0) {
+					nout = write(out, quit, *s);
+					if (nout <= 0)
+						return -1;
+					(*s) -= nout;
+				}
+		}
+	}
+
+	while (nin > 0) {
+		nout = write(out, buf, nin);
+		if (nout <= 0)
+			return -1;
+		nin -= nout;
+	}
+
+	return 0;
+}
+
+static int
+kwboot_terminal(int tty)
+{
+	int rc, in, s;
+	char *quit = "\34c";
+	struct termios otio, tio;
+
+	rc = -1;
+
+	in = STDIN_FILENO;
+	if (isatty(in)) {
+		rc = tcgetattr(in, &otio);
+		if (!rc) {
+			tio = otio;
+			cfmakeraw(&tio);
+			rc = tcsetattr(in, TCSANOW, &tio);
+		}
+		if (rc) {
+			perror("tcsetattr");
+			goto out;
+		}
+
+		kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n",
+			      quit[0]|0100, quit[1]);
+	} else
+		in = -1;
+
+	rc = 0;
+	s = 0;
+
+	do {
+		fd_set rfds;
+		int nfds = 0;
+
+		FD_SET(tty, &rfds);
+		nfds = nfds < tty ? tty : nfds;
+
+		if (in >= 0) {
+			FD_SET(in, &rfds);
+			nfds = nfds < in ? in : nfds;
+		}
+
+		nfds = select(nfds + 1, &rfds, NULL, NULL, NULL);
+		if (nfds < 0)
+			break;
+
+		if (FD_ISSET(tty, &rfds)) {
+			rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL);
+			if (rc)
+				break;
+		}
+
+		if (FD_ISSET(in, &rfds)) {
+			rc = kwboot_term_pipe(in, tty, quit, &s);
+			if (rc)
+				break;
+		}
+	} while (quit[s] != 0);
+
+	tcsetattr(in, TCSANOW, &otio);
+out:
+	return rc;
+}
+
+static void *
+kwboot_mmap_image(const char *path, size_t *size, int prot)
+{
+	int rc, fd, flags;
+	struct stat st;
+	void *img;
+
+	rc = -1;
+	fd = -1;
+	img = NULL;
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		goto out;
+
+	rc = fstat(fd, &st);
+	if (rc)
+		goto out;
+
+	flags = (prot & PROT_WRITE) ? MAP_PRIVATE : MAP_SHARED;
+
+	img = mmap(NULL, st.st_size, prot, flags, fd, 0);
+	if (img == MAP_FAILED) {
+		img = NULL;
+		goto out;
+	}
+
+	rc = 0;
+	*size = st.st_size;
+out:
+	if (rc && img) {
+		munmap(img, st.st_size);
+		img = NULL;
+	}
+	if (fd >= 0)
+		close(fd);
+
+	return img;
+}
+
+static uint8_t
+kwboot_img_csum8(void *_data, size_t size)
+{
+	uint8_t *data = _data, csum;
+
+	for (csum = 0; size-- > 0; data++)
+		csum += *data;
+
+	return csum;
+}
+
+static int
+kwboot_img_patch_hdr(void *img, size_t size)
+{
+	int rc;
+	bhr_t *hdr;
+	uint8_t csum;
+	const size_t hdrsz = sizeof(*hdr);
+
+	rc = -1;
+	hdr = img;
+
+	if (size < hdrsz) {
+		errno = EINVAL;
+		goto out;
+	}
+
+	csum = kwboot_img_csum8(hdr, hdrsz) - hdr->checkSum;
+	if (csum != hdr->checkSum) {
+		errno = EINVAL;
+		goto out;
+	}
+
+	if (hdr->blockid == IBR_HDR_UART_ID) {
+		rc = 0;
+		goto out;
+	}
+
+	hdr->blockid = IBR_HDR_UART_ID;
+
+	hdr->nandeccmode = IBR_HDR_ECC_DISABLED;
+	hdr->nandpagesize = 0;
+
+	hdr->srcaddr = hdr->ext
+		? sizeof(struct kwb_header)
+		: sizeof(*hdr);
+
+	hdr->checkSum = kwboot_img_csum8(hdr, hdrsz) - csum;
+
+	rc = 0;
+out:
+	return rc;
+}
+
+static void
+kwboot_usage(FILE *stream, char *progname)
+{
+	fprintf(stream,
+		"Usage: %s -b <image> [ -p ] [ -t ] "
+		"[-B <baud> ] <TTY>\n", progname);
+	fprintf(stream, "\n");
+	fprintf(stream, "  -b <image>: boot <image>\n");
+	fprintf(stream, "  -p: patch <image> to type 0x69 (uart boot)\n");
+	fprintf(stream, "\n");
+	fprintf(stream, "  -t: mini terminal\n");
+	fprintf(stream, "\n");
+	fprintf(stream, "  -B <baud>: set baud rate\n");
+	fprintf(stream, "\n");
+}
+
+int
+main(int argc, char **argv)
+{
+	const char *ttypath, *imgpath;
+	int rv, rc, tty, term, prot, patch;
+	void *bootmsg;
+	void *img;
+	size_t size;
+	speed_t speed;
+
+	rv = 1;
+	tty = -1;
+	bootmsg = NULL;
+	imgpath = NULL;
+	img = NULL;
+	term = 0;
+	patch = 0;
+	size = 0;
+	speed = B115200;
+
+	kwboot_verbose = isatty(STDOUT_FILENO);
+
+	do {
+		int c = getopt(argc, argv, "hb:ptB:");
+		if (c < 0)
+			break;
+
+		switch (c) {
+		case 'b':
+			bootmsg = kwboot_msg_boot;
+			imgpath = optarg;
+			break;
+
+		case 'p':
+			patch = 1;
+			break;
+
+		case 't':
+			term = 1;
+			break;
+
+		case 'B':
+			speed = kwboot_tty_speed(atoi(optarg));
+			if (speed == -1)
+				goto usage;
+			break;
+
+		case 'h':
+			rv = 0;
+		default:
+			goto usage;
+		}
+	} while (1);
+
+	if (!bootmsg && !term)
+		goto usage;
+
+	if (patch && !imgpath)
+		goto usage;
+
+	if (argc - optind < 1)
+		goto usage;
+
+	ttypath = argv[optind++];
+
+	tty = kwboot_open_tty(ttypath, speed);
+	if (tty < 0) {
+		perror(ttypath);
+		goto out;
+	}
+
+	if (imgpath) {
+		prot = PROT_READ | (patch ? PROT_WRITE : 0);
+
+		img = kwboot_mmap_image(imgpath, &size, prot);
+		if (!img) {
+			perror(imgpath);
+			goto out;
+		}
+	}
+
+	if (patch) {
+		rc = kwboot_img_patch_hdr(img, size);
+		if (rc) {
+			fprintf(stderr, "%s: Invalid image.\n", imgpath);
+			goto out;
+		}
+	}
+
+	if (bootmsg) {
+		rc = kwboot_bootmsg(tty, bootmsg);
+		if (rc) {
+			perror("bootmsg");
+			goto out;
+		}
+	}
+
+	if (img) {
+		rc = kwboot_xmodem(tty, img, size);
+		if (rc) {
+			perror("xmodem");
+			goto out;
+		}
+	}
+
+	if (term) {
+		rc = kwboot_terminal(tty);
+		if (rc && !(errno == EINTR)) {
+			perror("terminal");
+			goto out;
+		}
+	}
+
+	rv = 0;
+out:
+	if (tty >= 0)
+		close(tty);
+
+	if (img)
+		munmap(img, size);
+
+	return rv;
+
+usage:
+	kwboot_usage(rv ? stderr : stdout, basename(argv[0]));
+	goto out;
+}
diff --git a/marvell/uboot/tools/logos/atmel.bmp b/marvell/uboot/tools/logos/atmel.bmp
new file mode 100644
index 0000000..5c659ce
--- /dev/null
+++ b/marvell/uboot/tools/logos/atmel.bmp
Binary files differ
diff --git a/marvell/uboot/tools/logos/denx.bmp b/marvell/uboot/tools/logos/denx.bmp
new file mode 100644
index 0000000..c4cde09
--- /dev/null
+++ b/marvell/uboot/tools/logos/denx.bmp
Binary files differ
diff --git a/marvell/uboot/tools/logos/esd.bmp b/marvell/uboot/tools/logos/esd.bmp
new file mode 100644
index 0000000..a6b4030
--- /dev/null
+++ b/marvell/uboot/tools/logos/esd.bmp
Binary files differ
diff --git a/marvell/uboot/tools/logos/freescale.bmp b/marvell/uboot/tools/logos/freescale.bmp
new file mode 100644
index 0000000..1589e80
--- /dev/null
+++ b/marvell/uboot/tools/logos/freescale.bmp
Binary files differ
diff --git a/marvell/uboot/tools/logos/intercontrol.bmp b/marvell/uboot/tools/logos/intercontrol.bmp
new file mode 100644
index 0000000..cf2a884
--- /dev/null
+++ b/marvell/uboot/tools/logos/intercontrol.bmp
Binary files differ
diff --git a/marvell/uboot/tools/logos/linux_logo_ttcontrol.bmp b/marvell/uboot/tools/logos/linux_logo_ttcontrol.bmp
new file mode 100644
index 0000000..031d3a4
--- /dev/null
+++ b/marvell/uboot/tools/logos/linux_logo_ttcontrol.bmp
Binary files differ
diff --git a/marvell/uboot/tools/logos/linux_logo_ttcontrol_palfin.bmp b/marvell/uboot/tools/logos/linux_logo_ttcontrol_palfin.bmp
new file mode 100644
index 0000000..e3e38d1
--- /dev/null
+++ b/marvell/uboot/tools/logos/linux_logo_ttcontrol_palfin.bmp
Binary files differ
diff --git a/marvell/uboot/tools/logos/ronetix.bmp b/marvell/uboot/tools/logos/ronetix.bmp
new file mode 100644
index 0000000..f956813
--- /dev/null
+++ b/marvell/uboot/tools/logos/ronetix.bmp
Binary files differ
diff --git a/marvell/uboot/tools/logos/siemens.bmp b/marvell/uboot/tools/logos/siemens.bmp
new file mode 100644
index 0000000..bff2b19
--- /dev/null
+++ b/marvell/uboot/tools/logos/siemens.bmp
Binary files differ
diff --git a/marvell/uboot/tools/logos/syteco.bmp b/marvell/uboot/tools/logos/syteco.bmp
new file mode 100644
index 0000000..9a994fe
--- /dev/null
+++ b/marvell/uboot/tools/logos/syteco.bmp
Binary files differ
diff --git a/marvell/uboot/tools/logos/wandboard.bmp b/marvell/uboot/tools/logos/wandboard.bmp
new file mode 100644
index 0000000..7f288a8
--- /dev/null
+++ b/marvell/uboot/tools/logos/wandboard.bmp
Binary files differ
diff --git a/marvell/uboot/tools/mbrgen.c b/marvell/uboot/tools/mbrgen.c
new file mode 100644
index 0000000..d0587db
--- /dev/null
+++ b/marvell/uboot/tools/mbrgen.c
@@ -0,0 +1,285 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <u-boot/crc.h>
+
+/* following part is used by part_efi.h */
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long long u64;
+#ifndef __packed
+#define __packed			__attribute__((packed))
+#endif
+
+#include <part_efi.h>
+
+#define DEFAULT_MBR_NAME1	"primary_gpt"
+#define DEFAULT_MBR_NAME2	"second_gpt"
+#define SECTOR_SIZE		512
+#define GPT_HEADER_SIZE		512
+#define MAX_PART_ENTRY		128
+#define MAX_NAME_SZ		36
+#define GPT_SIZE		128
+#define ENTRY_NUM		128
+#define FIRST_USABLE_LBA	34
+#define HEADER_SIZE		92
+
+#ifdef WIN32
+#define OUTPUT		"%I64x"
+#define OUTPUT_D	"%I64d"
+#define SEPERATOR       '\\'
+#else
+#define OUTPUT		"%llx"
+#define OUTPUT_D	"%lld"
+#define SEPERATOR       '/'
+#endif
+
+static void usage(void);
+static char mbrfile1[PATH_MAX + 1], mbrfile2[PATH_MAX + 1], *cmdname;
+static int show_content;
+static FILE *desp, *mbr;
+static void random_uuid(unsigned char *str)
+{
+	int i;
+	for (i = 0; i < 16; i++)
+		str[i] = (unsigned char) (256.0 * (rand() / (RAND_MAX + 1.0)));
+}
+
+static void reformat_part_size(u64 *start, u64 *end, int num)
+{
+	int i;
+	for (i = 0; i < num; i++) {
+		if (start[i] > end[i]) {
+			fprintf(stderr, "The %d entry's start "OUTPUT" exceed end "OUTPUT"\n",
+				i, start[i], end[i]);
+			exit(EXIT_FAILURE);
+		}
+		if (end[i] > start[i + 1]) {
+			fprintf(stderr,
+				"The %d entry's end "OUTPUT"exceed the next start "OUTPUT"\n",
+				i, end[i], start[i + 1]);
+			exit(EXIT_FAILURE);
+		}
+		if (start[i] == end[i])
+			end[i] = (start[i + 1] - SECTOR_SIZE);
+		start[i] /= SECTOR_SIZE;
+		end[i] /= SECTOR_SIZE;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	char oneline[100], filename[MAX_PART_ENTRY][36];
+	gpt_header pri_header, sec_header;
+	char gpt_header_pad[GPT_HEADER_SIZE - sizeof(gpt_header)] = {0};
+	legacy_mbr leg_mbr;
+	gpt_entry *entry;
+	unsigned long long start[MAX_PART_ENTRY + 1], end[MAX_PART_ENTRY + 1], dev_sz;
+	unsigned int i, j, num;
+	char *output = NULL;
+	int ret;
+	cmdname = argv[0];
+	while (--argc > 0 && **++argv == '-') {
+		while (*++*argv) {
+			switch (**argv) {
+			case 's':
+				show_content = 1;
+				break;
+			case 'o':
+				if (--argc <= 0)
+					usage();
+				output = *++argv;
+				goto NXTARG;
+			default:
+				usage();
+			}
+		}
+NXTARG:
+		;
+	}
+
+	if (output) {
+		num = strlen(output);
+		if (output[num - 1] == SEPERATOR)
+			output[num - 1] = 0;
+		ret = access(output, F_OK);
+		if (ret) {
+#ifndef __MINGW32__
+			ret = mkdir(output, S_IRWXU | S_IRWXG | S_IROTH);
+#else
+			ret = mkdir(output);
+#endif
+			if (ret)
+				perror("mkdir fail");
+		}
+	}
+	if (argc != 2) {
+		usage();
+		exit(EXIT_FAILURE);
+	}
+
+	if (sscanf(argv[1], "0%*[xX]%100s", oneline) == 1)
+		dev_sz = strtoull(oneline, 0, 16);
+	else
+		dev_sz = strtoull(argv[1], 0, 10);
+	desp = fopen(*argv, "r");
+	if (!desp) {
+		fprintf(stderr, "Can't open %s: %s\n", *argv, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	num = 0;
+	while (fgets(oneline, sizeof(oneline), desp) != NULL) {
+		switch (sscanf(oneline, "%s\t"OUTPUT"\t"OUTPUT"\n",
+			filename[num], &start[num], &end[num])) {
+		case 2:
+			end[num] = start[num];
+			break;
+		case 3:
+			end[num] -= SECTOR_SIZE;
+			break;
+		default:
+			fprintf(stderr, "desp file err\n");
+			fclose(desp);
+			exit(EXIT_FAILURE);
+		}
+		if (strlen(filename[num]) > MAX_NAME_SZ) {
+			fprintf(stderr, "The %dth entry name %s exceed max size of %x\n",
+				num, filename[num], MAX_NAME_SZ);
+			fclose(desp);
+			exit(EXIT_FAILURE);
+		}
+		num++;
+	}
+
+	fclose(desp);
+	if (num == 0)
+		return 0;
+	start[num] = dev_sz;
+	end[num] = dev_sz;
+	if (end[num - 1] > dev_sz) {
+		fprintf(stderr, "The last entry end 0x"OUTPUT"exceed device size 0x"OUTPUT"\n",
+			end[num - 1], dev_sz);
+		exit(EXIT_FAILURE);
+	}
+	reformat_part_size(start, end, num);
+
+	entry = malloc(sizeof(gpt_entry) * ENTRY_NUM);
+	if (!entry) {
+		fprintf(stderr, "malloc fail\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (output) {
+		sprintf(mbrfile1, "%s%c%s_"OUTPUT_D, output, SEPERATOR,
+			DEFAULT_MBR_NAME1, dev_sz);
+		sprintf(mbrfile2, "%s%c%s_"OUTPUT_D, output, SEPERATOR,
+			DEFAULT_MBR_NAME2, dev_sz);
+	} else {
+		sprintf(mbrfile1, "%s_"OUTPUT_D, DEFAULT_MBR_NAME1, dev_sz);
+		sprintf(mbrfile2, "%s_"OUTPUT_D, DEFAULT_MBR_NAME2, dev_sz);
+	}
+	memset(entry, 0, sizeof(gpt_entry) * ENTRY_NUM);
+	for (i = 0; i < num; i++) {
+		memcpy(&entry[i].partition_type_guid, &PARTITION_BASIC_DATA_GUID,
+		       sizeof(efi_guid_t));
+		random_uuid((unsigned char *)&entry[i].unique_partition_guid);
+		memcpy(&entry[i].starting_lba, &start[i], 8);
+		memcpy(&entry[i].ending_lba, &end[i], 8);
+		for (j = 0; j < strlen(filename[i]); j++)
+			entry[i].partition_name[j] = filename[i][j];
+	}
+
+	dev_sz /= SECTOR_SIZE;
+	memset(&pri_header, 0, sizeof(pri_header));
+	pri_header.signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
+	pri_header.revision = cpu_to_le32(GPT_HEADER_REVISION_V1);
+	pri_header.header_size = cpu_to_le32(HEADER_SIZE);
+	pri_header.my_lba = cpu_to_le64(1);
+	pri_header.alternate_lba = cpu_to_le64(dev_sz - 1);
+	pri_header.first_usable_lba = cpu_to_le64(FIRST_USABLE_LBA);
+	pri_header.last_usable_lba = cpu_to_le64(dev_sz - FIRST_USABLE_LBA);
+	random_uuid((unsigned char *)&pri_header.disk_guid);
+	pri_header.partition_entry_lba = cpu_to_le64(2);
+	pri_header.num_partition_entries = cpu_to_le32(ENTRY_NUM);
+	pri_header.sizeof_partition_entry = cpu_to_le32(GPT_SIZE);
+	pri_header.partition_entry_array_crc32 = cpu_to_le32(
+		crc32(0, (const unsigned char *)entry, sizeof(gpt_entry) * MAX_PART_ENTRY)
+		);
+
+	pri_header.header_crc32 = cpu_to_le32(
+		crc32(0, (const unsigned char *)&pri_header, HEADER_SIZE)
+		);
+
+	memcpy(&sec_header, &pri_header, sizeof(pri_header));
+	memset(&sec_header.header_crc32, 0, 4);
+
+	sec_header.my_lba = cpu_to_le64(dev_sz - 1);
+	sec_header.alternate_lba = 0;
+	sec_header.alternate_lba = cpu_to_le64(1);
+	sec_header.header_crc32 = cpu_to_le32(
+		crc32(0, (const unsigned char *)&sec_header, HEADER_SIZE)
+		);
+
+	memset(&leg_mbr, 0, sizeof(leg_mbr));
+
+	leg_mbr.partition_record[0].sector = 1;
+	leg_mbr.partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT;
+	leg_mbr.partition_record[0].end_head = 0xfe;
+	leg_mbr.partition_record[0].end_sector = 0xff;
+	leg_mbr.partition_record[0].end_cyl = 0xff;
+	leg_mbr.partition_record[0].start_sect = cpu_to_le32(1);
+	leg_mbr.partition_record[0].nr_sects = cpu_to_le32(dev_sz);
+	leg_mbr.signature = cpu_to_le16(MSDOS_MBR_SIGNATURE);
+
+	mbr = fopen(mbrfile1, "wb");
+	if (!mbr) {
+		fprintf(stderr, "Can't create %s: %s\n", mbrfile1, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	fwrite(&leg_mbr, 1, sizeof(leg_mbr), mbr);
+	fwrite(&pri_header, 1, sizeof(pri_header), mbr);
+	fwrite(gpt_header_pad, 1, sizeof(gpt_header_pad), mbr);
+	fwrite(entry, 1, sizeof(gpt_entry) * ENTRY_NUM, mbr);
+	fclose(mbr);
+
+	mbr = fopen(mbrfile2, "wb");
+	if (!mbr) {
+		fprintf(stderr, "Can't create %s: %s\n", mbrfile2, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	fwrite(entry, 1, sizeof(gpt_entry) * ENTRY_NUM, mbr);
+	fwrite(&sec_header, 1, sizeof(sec_header), mbr);
+	fwrite(gpt_header_pad, 1, sizeof(gpt_header_pad), mbr);
+	fclose(mbr);
+
+	printf("GPT create sucessfull!!!\n"
+		"Please write the primary mbr first from offset 0 to mmc device offset 0 with the size of 0x22\n"
+		"And write the second mbr to mmc device offset 0x"OUTPUT" with the size of 0x21\n",
+		dev_sz - FIRST_USABLE_LBA + 1);
+	return 0;
+}
+
+static void usage()
+{
+	fprintf(stderr, "Usage:\n"
+		"cmdname %s [partition description file] [mmc device size] [-o [gpt store place]]\n"
+		"---------------------------------------------------------\n"
+		"Partition description file example:\n"
+		"bootloader      0               0x100000\n"
+		"ramdisk         0x100000        0x140000\n"
+		"kernel          0x980000        0xc80000\n"
+		"system          0x3bc0000       0xabc0000\n"
+		"---------------------------------------------------------\n"
+		"The description file is created by [NAME] [Start offset] [End offset]\n"
+		"If [End offset] is not specified, it would auto calculate it out by\n"
+		"its following partition\n"
+		, cmdname);
+}
diff --git a/marvell/uboot/tools/mingw_support.c b/marvell/uboot/tools/mingw_support.c
new file mode 100644
index 0000000..95c4db8
--- /dev/null
+++ b/marvell/uboot/tools/mingw_support.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2008 Extreme Engineering Solutions, Inc.
+ *
+ * mmap/munmap implementation derived from:
+ * Clamav Native Windows Port : mmap win32 compatibility layer
+ * Copyright (c) 2005-2006 Gianluigi Tiesi <sherpya@netfarm.it>
+ * Parts by Kees Zeelenberg <kzlg@users.sourceforge.net> (LibGW32C)
+ *
+ * SPDX-License-Identifier:	LGPL-2.0+
+ */
+
+#include "mingw_support.h"
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <io.h>
+
+int fsync(int fd)
+{
+	return _commit(fd);
+}
+
+void *mmap(void *addr, size_t len, int prot, int flags, int fd, int offset)
+{
+	void *map = NULL;
+	HANDLE handle = INVALID_HANDLE_VALUE;
+	DWORD cfm_flags = 0, mvf_flags = 0;
+
+	switch (prot) {
+	case PROT_READ | PROT_WRITE:
+		cfm_flags = PAGE_READWRITE;
+		mvf_flags = FILE_MAP_ALL_ACCESS;
+		break;
+	case PROT_WRITE:
+		cfm_flags = PAGE_READWRITE;
+		mvf_flags = FILE_MAP_WRITE;
+		break;
+	case PROT_READ:
+		cfm_flags = PAGE_READONLY;
+		mvf_flags = FILE_MAP_READ;
+		break;
+	default:
+		return MAP_FAILED;
+	}
+
+	handle = CreateFileMappingA((HANDLE) _get_osfhandle(fd), NULL,
+				cfm_flags, HIDWORD(len), LODWORD(len), NULL);
+	if (!handle)
+		return MAP_FAILED;
+
+	map = MapViewOfFile(handle, mvf_flags, HIDWORD(offset),
+			LODWORD(offset), len);
+	CloseHandle(handle);
+
+	if (!map)
+		return MAP_FAILED;
+
+	return map;
+}
+
+int munmap(void *addr, size_t len)
+{
+	if (!UnmapViewOfFile(addr))
+		return -1;
+
+	return 0;
+}
+
+/* Reentrant string tokenizer.  Generic version.
+   Copyright (C) 1991,1996-1999,2001,2004,2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+  * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* Parse S into tokens separated by characters in DELIM.
+   If S is NULL, the saved pointer in SAVE_PTR is used as
+   the next starting point.  For example:
+	char s[] = "-abc-=-def";
+	char *sp;
+	x = strtok_r(s, "-", &sp);	// x = "abc", sp = "=-def"
+	x = strtok_r(NULL, "-=", &sp);	// x = "def", sp = NULL
+	x = strtok_r(NULL, "=", &sp);	// x = NULL
+		// s = "abc\0-def\0"
+*/
+char *strtok_r(char *s, const char *delim, char **save_ptr)
+{
+	char *token;
+
+	if (s == NULL)
+		s = *save_ptr;
+
+	/* Scan leading delimiters.  */
+	s += strspn(s, delim);
+	if (*s == '\0') {
+		*save_ptr = s;
+		return NULL;
+	}
+
+	/* Find the end of the token.  */
+	token = s;
+	s = strpbrk (token, delim);
+	if (s == NULL) {
+		/* This token finishes the string.  */
+		*save_ptr = memchr(token, '\0', strlen(token));
+	} else {
+		/* Terminate the token and make *SAVE_PTR point past it.  */
+		*s = '\0';
+		*save_ptr = s + 1;
+	}
+	return token;
+}
+
+#include "getline.c"
diff --git a/marvell/uboot/tools/mingw_support.h b/marvell/uboot/tools/mingw_support.h
new file mode 100644
index 0000000..f9535b3
--- /dev/null
+++ b/marvell/uboot/tools/mingw_support.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008 Extreme Engineering Solutions, Inc.
+ *
+ * SPDX-License-Identifier:	LGPL-2.0+
+ */
+
+#ifndef __MINGW_SUPPORT_H_
+#define __WINGW_SUPPORT_H_	1
+
+/* Defining __INSIDE_MSYS__ helps to prevent u-boot/mingw overlap */
+#define __INSIDE_MSYS__	1
+
+#include <windows.h>
+
+/* mmap protections */
+#define PROT_READ	0x1		/* Page can be read */
+#define PROT_WRITE	0x2		/* Page can be written */
+#define PROT_EXEC	0x4		/* Page can be executed */
+#define PROT_NONE	0x0		/* Page can not be accessed */
+
+/* Sharing types (must choose one and only one of these) */
+#define MAP_SHARED	0x01		/* Share changes */
+#define MAP_PRIVATE	0x02		/* Changes are private */
+
+/* File perms */
+#ifndef S_IRGRP
+# define S_IRGRP 0
+#endif
+#ifndef S_IWGRP
+# define S_IWGRP 0
+#endif
+
+/* Windows 64-bit access macros */
+#define LODWORD(x) ((DWORD)((DWORDLONG)(x)))
+#define HIDWORD(x) ((DWORD)(((DWORDLONG)(x) >> 32) & 0xffffffff))
+
+typedef	UINT	uint;
+typedef	ULONG	ulong;
+
+int fsync(int fd);
+void *mmap(void *, size_t, int, int, int, int);
+int munmap(void *, size_t);
+char *strtok_r(char *s, const char *delim, char **save_ptr);
+#include "getline.h"
+
+#endif /* __MINGW_SUPPORT_H_ */
diff --git a/marvell/uboot/tools/mkenvimage.c b/marvell/uboot/tools/mkenvimage.c
new file mode 100644
index 0000000..bbd3041
--- /dev/null
+++ b/marvell/uboot/tools/mkenvimage.c
@@ -0,0 +1,295 @@
+/*
+ * (C) Copyright 2011 Free Electrons
+ * David Wagner <david.wagner@free-electrons.com>
+ *
+ * Inspired from envcrc.c:
+ * (C) Copyright 2001
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "compiler.h"
+#include <u-boot/crc.h>
+#include <version.h>
+
+#define CRC_SIZE sizeof(uint32_t)
+
+static void usage(const char *exec_name)
+{
+	fprintf(stderr, "%s [-h] [-r] [-b] [-p <byte>] -s <environment partition size> -o <output> <input file>\n"
+	       "\n"
+	       "This tool takes a key=value input file (same as would a `printenv' show) and generates the corresponding environment image, ready to be flashed.\n"
+	       "\n"
+	       "\tThe input file is in format:\n"
+	       "\t\tkey1=value1\n"
+	       "\t\tkey2=value2\n"
+	       "\t\t...\n"
+	       "\t-r : the environment has multiple copies in flash\n"
+	       "\t-b : the target is big endian (default is little endian)\n"
+	       "\t-p <byte> : fill the image with <byte> bytes instead of 0xff bytes\n"
+	       "\t-V : print version information and exit\n"
+	       "\n"
+	       "If the input file is \"-\", data is read from standard input\n",
+	       exec_name);
+}
+
+long int xstrtol(const char *s)
+{
+	long int tmp;
+
+	errno = 0;
+	tmp = strtol(s, NULL, 0);
+	if (!errno)
+		return tmp;
+
+	if (errno == ERANGE)
+		fprintf(stderr, "Bad integer format: %s\n",  s);
+	else
+		fprintf(stderr, "Error while parsing %s: %s\n", s,
+				strerror(errno));
+
+	exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+	uint32_t crc, targetendian_crc;
+	const char *txt_filename = NULL, *bin_filename = NULL;
+	int txt_fd, bin_fd;
+	unsigned char *dataptr, *envptr;
+	unsigned char *filebuf = NULL;
+	unsigned int filesize = 0, envsize = 0, datasize = 0;
+	int bigendian = 0;
+	int redundant = 0;
+	unsigned char padbyte = 0xff;
+
+	int option;
+	int ret = EXIT_SUCCESS;
+
+	struct stat txt_file_stat;
+
+	int fp, ep;
+	const char *prg;
+
+	prg = basename(argv[0]);
+
+	/* Turn off getopt()'s internal error message */
+	opterr = 0;
+
+	/* Parse the cmdline */
+	while ((option = getopt(argc, argv, ":s:o:rbp:hV")) != -1) {
+		switch (option) {
+		case 's':
+			datasize = xstrtol(optarg);
+			break;
+		case 'o':
+			bin_filename = strdup(optarg);
+			if (!bin_filename) {
+				fprintf(stderr, "Can't strdup() the output filename\n");
+				return EXIT_FAILURE;
+			}
+			break;
+		case 'r':
+			redundant = 1;
+			break;
+		case 'b':
+			bigendian = 1;
+			break;
+		case 'p':
+			padbyte = xstrtol(optarg);
+			break;
+		case 'h':
+			usage(prg);
+			return EXIT_SUCCESS;
+		case 'V':
+			printf("%s version %s\n", prg, PLAIN_VERSION);
+			return EXIT_SUCCESS;
+		case ':':
+			fprintf(stderr, "Missing argument for option -%c\n",
+				optopt);
+			usage(prg);
+			return EXIT_FAILURE;
+		default:
+			fprintf(stderr, "Wrong option -%c\n", optopt);
+			usage(prg);
+			return EXIT_FAILURE;
+		}
+	}
+
+	/* Check datasize and allocate the data */
+	if (datasize == 0) {
+		fprintf(stderr, "Please specify the size of the environment partition.\n");
+		usage(prg);
+		return EXIT_FAILURE;
+	}
+
+	dataptr = malloc(datasize * sizeof(*dataptr));
+	if (!dataptr) {
+		fprintf(stderr, "Can't alloc %d bytes for dataptr.\n",
+				datasize);
+		return EXIT_FAILURE;
+	}
+
+	/*
+	 * envptr points to the beginning of the actual environment (after the
+	 * crc and possible `redundant' byte
+	 */
+	envsize = datasize - (CRC_SIZE + redundant);
+	envptr = dataptr + CRC_SIZE + redundant;
+
+	/* Pad the environment with the padding byte */
+	memset(envptr, padbyte, envsize);
+
+	/* Open the input file ... */
+	if (optind >= argc || strcmp(argv[optind], "-") == 0) {
+		int readbytes = 0;
+		int readlen = sizeof(*envptr) * 4096;
+		txt_fd = STDIN_FILENO;
+
+		do {
+			filebuf = realloc(filebuf, readlen);
+			if (!filebuf) {
+				fprintf(stderr, "Can't realloc memory for the input file buffer\n");
+				return EXIT_FAILURE;
+			}
+			readbytes = read(txt_fd, filebuf + filesize, readlen);
+			if (errno) {
+				fprintf(stderr, "Error while reading stdin: %s\n",
+						strerror(errno));
+				return EXIT_FAILURE;
+			}
+			filesize += readbytes;
+		} while (readbytes == readlen);
+
+	} else {
+		txt_filename = argv[optind];
+		txt_fd = open(txt_filename, O_RDONLY);
+		if (txt_fd == -1) {
+			fprintf(stderr, "Can't open \"%s\": %s\n",
+					txt_filename, strerror(errno));
+			return EXIT_FAILURE;
+		}
+		/* ... and check it */
+		ret = fstat(txt_fd, &txt_file_stat);
+		if (ret == -1) {
+			fprintf(stderr, "Can't stat() on \"%s\": %s\n",
+					txt_filename, strerror(errno));
+			return EXIT_FAILURE;
+		}
+
+		filesize = txt_file_stat.st_size;
+
+		filebuf = mmap(NULL, sizeof(*envptr) * filesize, PROT_READ,
+			       MAP_PRIVATE, txt_fd, 0);
+		if (filebuf == MAP_FAILED) {
+			fprintf(stderr, "mmap (%zu bytes) failed: %s\n",
+					sizeof(*envptr) * filesize,
+					strerror(errno));
+			fprintf(stderr, "Falling back to read()\n");
+
+			filebuf = malloc(sizeof(*envptr) * filesize);
+			ret = read(txt_fd, filebuf, sizeof(*envptr) * filesize);
+			if (ret != sizeof(*envptr) * filesize) {
+				fprintf(stderr, "Can't read the whole input file (%zu bytes): %s\n",
+					sizeof(*envptr) * filesize,
+					strerror(errno));
+
+				return EXIT_FAILURE;
+			}
+		}
+		ret = close(txt_fd);
+	}
+	/* The +1 is for the additionnal ending \0. See below. */
+	if (filesize + 1 > envsize) {
+		fprintf(stderr, "The input file is larger than the environment partition size\n");
+		return EXIT_FAILURE;
+	}
+
+	/* Replace newlines separating variables with \0 */
+	for (fp = 0, ep = 0 ; fp < filesize ; fp++) {
+		if (filebuf[fp] == '\n') {
+			if (ep == 0) {
+				/*
+				 * Newlines at the beginning of the file ?
+				 * Ignore them.
+				 */
+				continue;
+			} else if (filebuf[fp-1] == '\\') {
+				/*
+				 * Embedded newline in a variable.
+				 *
+				 * The backslash was added to the envptr; rewind
+				 * and replace it with a newline
+				 */
+				ep--;
+				envptr[ep++] = '\n';
+			} else {
+				/* End of a variable */
+				envptr[ep++] = '\0';
+			}
+		} else {
+			envptr[ep++] = filebuf[fp];
+		}
+	}
+	/*
+	 * Make sure there is a final '\0'
+	 * And do it again on the next byte to mark the end of the environment.
+	 */
+	if (envptr[ep-1] != '\0') {
+		envptr[ep++] = '\0';
+		/*
+		 * The text file doesn't have an ending newline.  We need to
+		 * check the env size again to make sure we have room for two \0
+		 */
+		if (ep >= envsize) {
+			fprintf(stderr, "The environment file is too large for the target environment storage\n");
+			return EXIT_FAILURE;
+		}
+		envptr[ep] = '\0';
+	} else {
+		envptr[ep] = '\0';
+	}
+
+	/* Computes the CRC and put it at the beginning of the data */
+	crc = crc32(0, envptr, envsize);
+	targetendian_crc = bigendian ? cpu_to_be32(crc) : cpu_to_le32(crc);
+
+	memcpy(dataptr, &targetendian_crc, sizeof(targetendian_crc));
+	if (redundant)
+		dataptr[sizeof(targetendian_crc)] = 1;
+
+	if (!bin_filename || strcmp(bin_filename, "-") == 0) {
+		bin_fd = STDOUT_FILENO;
+	} else {
+		bin_fd = creat(bin_filename, S_IRUSR | S_IWUSR | S_IRGRP |
+					     S_IWGRP);
+		if (bin_fd == -1) {
+			fprintf(stderr, "Can't open output file \"%s\": %s\n",
+					bin_filename, strerror(errno));
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (write(bin_fd, dataptr, sizeof(*dataptr) * datasize) !=
+			sizeof(*dataptr) * datasize) {
+		fprintf(stderr, "write() failed: %s\n", strerror(errno));
+		return EXIT_FAILURE;
+	}
+
+	ret = close(bin_fd);
+
+	return ret;
+}
diff --git a/marvell/uboot/tools/mkexynosspl.c b/marvell/uboot/tools/mkexynosspl.c
new file mode 100644
index 0000000..32b786c
--- /dev/null
+++ b/marvell/uboot/tools/mkexynosspl.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <compiler.h>
+
+#define CHECKSUM_OFFSET		(14*1024-4)
+#define FILE_PERM		(S_IRUSR | S_IWUSR | S_IRGRP \
+				| S_IWGRP | S_IROTH | S_IWOTH)
+/*
+ * Requirement for the fixed size SPL header:
+ * IROM code reads first (CHECKSUM_OFFSET + 4) bytes from boot device. It then
+ * calculates the checksum of CHECKSUM_OFFSET bytes and compares with data at
+ * CHECKSUM_OFFSET location.
+ *
+ * Requirement for the variable size SPL header:
+
+ * IROM code reads the below header to find out the size of the blob (total
+ * size, header size included) and its checksum. Then it reads the rest of the
+ * blob [i.e size - sizeof(struct var_size_header) bytes], calculates the
+ * checksum and compares it with value read from the header.
+ */
+struct var_size_header {
+	uint32_t spl_size;
+	uint32_t spl_checksum;
+	uint32_t reserved[2];
+};
+
+static const char *prog_name;
+
+static void write_to_file(int ofd, void *buffer, int size)
+{
+	if (write(ofd, buffer, size) == size)
+		return;
+
+	fprintf(stderr, "%s: Failed to write to output file: %s\n",
+		prog_name, strerror(errno));
+	exit(EXIT_FAILURE);
+}
+
+/*
+ * The argv is expected to include one optional parameter and two filenames:
+ * [--vs] IN OUT
+ *
+ * --vs - turns on the variable size SPL mode
+ * IN  - the u-boot SPL binary, usually u-boot-spl.bin
+ * OUT - the prepared SPL blob, usually ${BOARD}-spl.bin
+ *
+ * This utility first reads the "u-boot-spl.bin" into a buffer. In case of
+ * fixed size SPL the buffer size is exactly CHECKSUM_OFFSET (such that
+ * smaller u-boot-spl.bin gets padded with 0xff bytes, the larger than limit
+ * u-boot-spl.bin causes an error). For variable size SPL the buffer size is
+ * eqaul to size of the IN file.
+ *
+ * Then it calculates checksum of the buffer by just summing up all bytes.
+ * Then
+ *
+ * - for fixed size SPL the buffer is written into the output file and the
+ *   checksum is appended to the file in little endian format, which results
+ *   in checksum added exactly at CHECKSUM_OFFSET.
+ *
+ * - for variable size SPL the checksum and file size are stored in the
+ *   var_size_header structure (again, in little endian format) and the
+ *   structure is written into the output file. Then the buffer is written
+ *   into the output file.
+ */
+int main(int argc, char **argv)
+{
+	unsigned char *buffer;
+	int i, ifd, ofd;
+	uint32_t checksum = 0;
+	off_t	len;
+	int	var_size_flag, read_size, count;
+	struct stat stat;
+	const int if_index = argc - 2; /* Input file name index in argv. */
+	const int of_index = argc - 1; /* Output file name index in argv. */
+
+	/* Strip path off the program name. */
+	prog_name = strrchr(argv[0], '/');
+	if (prog_name)
+		prog_name++;
+	else
+		prog_name = argv[0];
+
+	if ((argc < 3) ||
+	    (argc > 4) ||
+	    ((argc == 4) && strcmp(argv[1], "--vs"))) {
+		fprintf(stderr, "Usage: %s [--vs] <infile> <outfile>\n",
+			prog_name);
+		exit(EXIT_FAILURE);
+	}
+
+	/* four args mean variable size SPL wrapper is required */
+	var_size_flag = (argc == 4);
+
+	ifd = open(argv[if_index], O_RDONLY);
+	if (ifd < 0) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			prog_name, argv[if_index], strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	ofd = open(argv[of_index], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
+	if (ifd < 0) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			prog_name, argv[of_index], strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fstat(ifd, &stat)) {
+		fprintf(stderr, "%s: Unable to get size of %s: %s\n",
+			prog_name, argv[if_index], strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	len = stat.st_size;
+
+	if (var_size_flag) {
+		read_size = len;
+		count = len;
+	} else {
+		if (len > CHECKSUM_OFFSET) {
+			fprintf(stderr,
+				"%s: %s is too big (exceeds %d bytes)\n",
+				prog_name, argv[if_index], CHECKSUM_OFFSET);
+			exit(EXIT_FAILURE);
+		}
+		count = CHECKSUM_OFFSET;
+		read_size = len;
+	}
+
+	buffer = malloc(count);
+	if (!buffer) {
+		fprintf(stderr,
+			"%s: Failed to allocate %d bytes to store %s\n",
+			prog_name, count, argv[if_index]);
+		exit(EXIT_FAILURE);
+	}
+
+	if (read(ifd, buffer, read_size) != read_size) {
+		fprintf(stderr, "%s: Can't read %s: %s\n",
+			prog_name, argv[if_index], strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Pad if needed with 0xff to make flashing faster. */
+	if (read_size < count)
+		memset((char *)buffer + read_size, 0xff, count - read_size);
+
+	for (i = 0, checksum = 0; i < count; i++)
+		checksum += buffer[i];
+	checksum = cpu_to_le32(checksum);
+
+	if (var_size_flag) {
+		/* Prepare and write out the variable size SPL header. */
+		struct var_size_header vsh;
+		uint32_t spl_size;
+
+		memset(&vsh, 0, sizeof(vsh));
+		memcpy(&vsh.spl_checksum, &checksum, sizeof(checksum));
+
+		spl_size = cpu_to_le32(count + sizeof(struct var_size_header));
+		memcpy(&vsh.spl_size, &spl_size, sizeof(spl_size));
+		write_to_file(ofd, &vsh, sizeof(vsh));
+	}
+
+	write_to_file(ofd, buffer, count);
+
+	/* For fixed size SPL checksum is appended in the end. */
+	if (!var_size_flag)
+		write_to_file(ofd, &checksum, sizeof(checksum));
+
+	close(ifd);
+	close(ofd);
+	free(buffer);
+
+	return EXIT_SUCCESS;
+}
diff --git a/marvell/uboot/tools/mkimage.c b/marvell/uboot/tools/mkimage.c
new file mode 100644
index 0000000..123d0c7
--- /dev/null
+++ b/marvell/uboot/tools/mkimage.c
@@ -0,0 +1,654 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2009
+ * DENX Software Engineering
+ * Wolfgang Denk, wd@denx.de
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "mkimage.h"
+#include <image.h>
+#include <version.h>
+
+static void copy_file(int, const char *, int);
+static void usage(void);
+
+/* image_type_params link list to maintain registered image type supports */
+struct image_type_params *mkimage_tparams = NULL;
+
+/* parameters initialized by core will be used by the image type code */
+struct image_tool_params params = {
+	.os = IH_OS_LINUX,
+	.arch = IH_ARCH_PPC,
+	.type = IH_TYPE_KERNEL,
+	.comp = IH_COMP_GZIP,
+	.dtc = MKIMAGE_DEFAULT_DTC_OPTIONS,
+	.imagename = "",
+	.imagename2 = "",
+};
+
+/*
+ * mkimage_register -
+ *
+ * It is used to register respective image generation/list support to the
+ * mkimage core
+ *
+ * the input struct image_type_params is checked and appended to the link
+ * list, if the input structure is already registered, error
+ */
+void mkimage_register (struct image_type_params *tparams)
+{
+	struct image_type_params **tp;
+
+	if (!tparams) {
+		fprintf (stderr, "%s: %s: Null input\n",
+			params.cmdname, __FUNCTION__);
+		exit (EXIT_FAILURE);
+	}
+
+	/* scan the linked list, check for registry and point the last one */
+	for (tp = &mkimage_tparams; *tp != NULL; tp = &(*tp)->next) {
+		if (!strcmp((*tp)->name, tparams->name)) {
+			fprintf (stderr, "%s: %s already registered\n",
+				params.cmdname, tparams->name);
+			return;
+		}
+	}
+
+	/* add input struct entry at the end of link list */
+	*tp = tparams;
+	/* mark input entry as last entry in the link list */
+	tparams->next = NULL;
+
+	debug ("Registered %s\n", tparams->name);
+}
+
+/*
+ * mkimage_get_type -
+ *
+ * It scans all registers image type supports
+ * checks the input type_id for each supported image type
+ *
+ * if successful,
+ * 	returns respective image_type_params pointer if success
+ * if input type_id is not supported by any of image_type_support
+ * 	returns NULL
+ */
+struct image_type_params *mkimage_get_type(int type)
+{
+	struct image_type_params *curr;
+
+	for (curr = mkimage_tparams; curr != NULL; curr = curr->next) {
+		if (curr->check_image_type) {
+			if (!curr->check_image_type (type))
+				return curr;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * mkimage_verify_print_header -
+ *
+ * It scans mkimage_tparams link list,
+ * verifies image_header for each supported image type
+ * if verification is successful, prints respective header
+ *
+ * returns negative if input image format does not match with any of
+ * supported image types
+ */
+int mkimage_verify_print_header (void *ptr, struct stat *sbuf)
+{
+	int retval = -1;
+	struct image_type_params *curr;
+
+	for (curr = mkimage_tparams; curr != NULL; curr = curr->next ) {
+		if (curr->verify_header) {
+			retval = curr->verify_header (
+				(unsigned char *)ptr, sbuf->st_size,
+				&params);
+
+			if (retval == 0) {
+				/*
+				 * Print the image information
+				 * if verify is successful
+				 */
+				if (curr->print_header)
+					curr->print_header (ptr);
+				else {
+					fprintf (stderr,
+					"%s: print_header undefined for %s\n",
+					params.cmdname, curr->name);
+				}
+				break;
+			}
+		}
+	}
+	return retval;
+}
+
+int
+main (int argc, char **argv)
+{
+	int ifd = -1;
+	struct stat sbuf;
+	char *ptr;
+	int retval = 0;
+	struct image_type_params *tparams = NULL;
+	int pad_len = 0;
+
+	/* Init all image generation/list support */
+	register_image_tool(mkimage_register);
+
+	params.cmdname = *argv;
+	params.addr = params.ep = 0;
+
+	while (--argc > 0 && **++argv == '-') {
+		while (*++*argv) {
+			switch (**argv) {
+			case 'l':
+				params.lflag = 1;
+				break;
+			case 'A':
+				if ((--argc <= 0) ||
+					(params.arch =
+					genimg_get_arch_id (*++argv)) < 0)
+					usage ();
+				goto NXTARG;
+			case 'c':
+				if (--argc <= 0)
+					usage();
+				params.comment = *++argv;
+				goto NXTARG;
+			case 'C':
+				if ((--argc <= 0) ||
+					(params.comp =
+					genimg_get_comp_id (*++argv)) < 0)
+					usage ();
+				goto NXTARG;
+			case 'D':
+				if (--argc <= 0)
+					usage ();
+				params.dtc = *++argv;
+				goto NXTARG;
+
+			case 'O':
+				if ((--argc <= 0) ||
+					(params.os =
+					genimg_get_os_id (*++argv)) < 0)
+					usage ();
+				goto NXTARG;
+			case 'T':
+				if ((--argc <= 0) ||
+					(params.type =
+					genimg_get_type_id (*++argv)) < 0)
+					usage ();
+				goto NXTARG;
+
+			case 'a':
+				if (--argc <= 0)
+					usage ();
+				params.addr = strtoul (*++argv, &ptr, 16);
+				if (*ptr) {
+					fprintf (stderr,
+						"%s: invalid load address %s\n",
+						params.cmdname, *argv);
+					exit (EXIT_FAILURE);
+				}
+				goto NXTARG;
+			case 'd':
+				if (--argc <= 0)
+					usage ();
+				params.datafile = *++argv;
+				params.dflag = 1;
+				goto NXTARG;
+			case 'e':
+				if (--argc <= 0)
+					usage ();
+				params.ep = strtoul (*++argv, &ptr, 16);
+				if (*ptr) {
+					fprintf (stderr,
+						"%s: invalid entry point %s\n",
+						params.cmdname, *argv);
+					exit (EXIT_FAILURE);
+				}
+				params.eflag = 1;
+				goto NXTARG;
+			case 'f':
+				if (--argc <= 0)
+					usage ();
+				params.datafile = *++argv;
+				/* no break */
+			case 'F':
+				/*
+				 * The flattened image tree (FIT) format
+				 * requires a flattened device tree image type
+				 */
+				params.type = IH_TYPE_FLATDT;
+				params.fflag = 1;
+				goto NXTARG;
+			case 'k':
+				if (--argc <= 0)
+					usage();
+				params.keydir = *++argv;
+				goto NXTARG;
+			case 'K':
+				if (--argc <= 0)
+					usage();
+				params.keydest = *++argv;
+				goto NXTARG;
+			case 'n':
+				if (--argc <= 0)
+					usage ();
+				params.imagename = *++argv;
+				goto NXTARG;
+			case 'r':
+				params.require_keys = 1;
+				break;
+			case 'R':
+				if (--argc <= 0)
+					usage();
+				/*
+				 * This entry is for the second configuration
+				 * file, if only one is not enough.
+				 */
+				params.imagename2 = *++argv;
+				goto NXTARG;
+			case 's':
+				params.skipcpy = 1;
+				break;
+			case 'v':
+				params.vflag++;
+				break;
+			case 'V':
+				printf("mkimage version %s\n", PLAIN_VERSION);
+				exit(EXIT_SUCCESS);
+			case 'x':
+				params.xflag++;
+				break;
+			default:
+				usage ();
+			}
+		}
+NXTARG:		;
+	}
+
+	if (argc != 1)
+		usage ();
+
+	/* set tparams as per input type_id */
+	tparams = mkimage_get_type(params.type);
+	if (tparams == NULL) {
+		fprintf (stderr, "%s: unsupported type %s\n",
+			params.cmdname, genimg_get_type_name(params.type));
+		exit (EXIT_FAILURE);
+	}
+
+	/*
+	 * check the passed arguments parameters meets the requirements
+	 * as per image type to be generated/listed
+	 */
+	if (tparams->check_params)
+		if (tparams->check_params (&params))
+			usage ();
+
+	if (!params.eflag) {
+		params.ep = params.addr;
+		/* If XIP, entry point must be after the U-Boot header */
+		if (params.xflag)
+			params.ep += tparams->header_size;
+	}
+
+	params.imagefile = *argv;
+
+	if (params.fflag){
+		if (tparams->fflag_handle)
+			/*
+			 * in some cases, some additional processing needs
+			 * to be done if fflag is defined
+			 *
+			 * For ex. fit_handle_file for Fit file support
+			 */
+			retval = tparams->fflag_handle(&params);
+
+		if (retval != EXIT_SUCCESS)
+			exit (retval);
+	}
+
+	if (params.lflag || params.fflag) {
+		ifd = open (params.imagefile, O_RDONLY|O_BINARY);
+	} else {
+		ifd = open (params.imagefile,
+			O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
+	}
+
+	if (ifd < 0) {
+		fprintf (stderr, "%s: Can't open %s: %s\n",
+			params.cmdname, params.imagefile,
+			strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (params.lflag || params.fflag) {
+		/*
+		 * list header information of existing image
+		 */
+		if (fstat(ifd, &sbuf) < 0) {
+			fprintf (stderr, "%s: Can't stat %s: %s\n",
+				params.cmdname, params.imagefile,
+				strerror(errno));
+			exit (EXIT_FAILURE);
+		}
+
+		if ((unsigned)sbuf.st_size < tparams->header_size) {
+			fprintf (stderr,
+				"%s: Bad size: \"%s\" is not valid image\n",
+				params.cmdname, params.imagefile);
+			exit (EXIT_FAILURE);
+		}
+
+		ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
+		if (ptr == MAP_FAILED) {
+			fprintf (stderr, "%s: Can't read %s: %s\n",
+				params.cmdname, params.imagefile,
+				strerror(errno));
+			exit (EXIT_FAILURE);
+		}
+
+		/*
+		 * scan through mkimage registry for all supported image types
+		 * and verify the input image file header for match
+		 * Print the image information for matched image type
+		 * Returns the error code if not matched
+		 */
+		retval = mkimage_verify_print_header (ptr, &sbuf);
+
+		(void) munmap((void *)ptr, sbuf.st_size);
+		(void) close (ifd);
+
+		exit (retval);
+	}
+
+	/*
+	 * In case there an header with a variable
+	 * length will be added, the corresponding
+	 * function is called. This is responsible to
+	 * allocate memory for the header itself.
+	 */
+	if (tparams->vrec_header)
+		pad_len = tparams->vrec_header(&params, tparams);
+	else
+		memset(tparams->hdr, 0, tparams->header_size);
+
+	if (write(ifd, tparams->hdr, tparams->header_size)
+					!= tparams->header_size) {
+		fprintf (stderr, "%s: Write error on %s: %s\n",
+			params.cmdname, params.imagefile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (!params.skipcpy) {
+		if (params.type == IH_TYPE_MULTI ||
+		    params.type == IH_TYPE_SCRIPT) {
+			char *file = params.datafile;
+			uint32_t size;
+
+			for (;;) {
+				char *sep = NULL;
+
+				if (file) {
+					if ((sep = strchr(file, ':')) != NULL) {
+						*sep = '\0';
+					}
+
+					if (stat (file, &sbuf) < 0) {
+						fprintf (stderr, "%s: Can't stat %s: %s\n",
+							 params.cmdname, file, strerror(errno));
+						exit (EXIT_FAILURE);
+					}
+					size = cpu_to_uimage (sbuf.st_size);
+				} else {
+					size = 0;
+				}
+
+				if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
+					fprintf (stderr, "%s: Write error on %s: %s\n",
+						 params.cmdname, params.imagefile,
+						 strerror(errno));
+					exit (EXIT_FAILURE);
+				}
+
+				if (!file) {
+					break;
+				}
+
+				if (sep) {
+					*sep = ':';
+					file = sep + 1;
+				} else {
+					file = NULL;
+				}
+			}
+
+			file = params.datafile;
+
+			for (;;) {
+				char *sep = strchr(file, ':');
+				if (sep) {
+					*sep = '\0';
+					copy_file (ifd, file, 1);
+					*sep++ = ':';
+					file = sep;
+				} else {
+					copy_file (ifd, file, 0);
+					break;
+				}
+			}
+		} else if (params.type == IH_TYPE_PBLIMAGE) {
+			/* PBL has special Image format, implements its' own */
+			pbl_load_uboot(ifd, &params);
+		} else {
+			copy_file(ifd, params.datafile, pad_len);
+		}
+	}
+
+	/* We're a bit of paranoid */
+#if defined(_POSIX_SYNCHRONIZED_IO) && \
+   !defined(__sun__) && \
+   !defined(__FreeBSD__) && \
+   !defined(__APPLE__)
+	(void) fdatasync (ifd);
+#else
+	(void) fsync (ifd);
+#endif
+
+	if (fstat(ifd, &sbuf) < 0) {
+		fprintf (stderr, "%s: Can't stat %s: %s\n",
+			params.cmdname, params.imagefile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf (stderr, "%s: Can't map %s: %s\n",
+			params.cmdname, params.imagefile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	/* Setup the image header as per input image type*/
+	if (tparams->set_header)
+		tparams->set_header (ptr, &sbuf, ifd, &params);
+	else {
+		fprintf (stderr, "%s: Can't set header for %s: %s\n",
+			params.cmdname, tparams->name, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	/* Print the image information by processing image header */
+	if (tparams->print_header)
+		tparams->print_header (ptr);
+	else {
+		fprintf (stderr, "%s: Can't print header for %s: %s\n",
+			params.cmdname, tparams->name, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	(void) munmap((void *)ptr, sbuf.st_size);
+
+	/* We're a bit of paranoid */
+#if defined(_POSIX_SYNCHRONIZED_IO) && \
+   !defined(__sun__) && \
+   !defined(__FreeBSD__) && \
+   !defined(__APPLE__)
+	(void) fdatasync (ifd);
+#else
+	(void) fsync (ifd);
+#endif
+
+	if (close(ifd)) {
+		fprintf (stderr, "%s: Write error on %s: %s\n",
+			params.cmdname, params.imagefile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	exit (EXIT_SUCCESS);
+}
+
+static void
+copy_file (int ifd, const char *datafile, int pad)
+{
+	int dfd;
+	struct stat sbuf;
+	unsigned char *ptr;
+	int tail;
+	int zero = 0;
+	uint8_t zeros[4096];
+	int offset = 0;
+	int size;
+	struct image_type_params *tparams = mkimage_get_type (params.type);
+
+	if (pad >= sizeof(zeros)) {
+		fprintf(stderr, "%s: Can't pad to %d\n",
+			params.cmdname, pad);
+		exit(EXIT_FAILURE);
+	}
+
+	memset(zeros, 0, sizeof(zeros));
+
+	if (params.vflag) {
+		fprintf (stderr, "Adding Image %s\n", datafile);
+	}
+
+	if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
+		fprintf (stderr, "%s: Can't open %s: %s\n",
+			params.cmdname, datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf (stderr, "%s: Can't stat %s: %s\n",
+			params.cmdname, datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf (stderr, "%s: Can't read %s: %s\n",
+			params.cmdname, datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (params.xflag) {
+		unsigned char *p = NULL;
+		/*
+		 * XIP: do not append the image_header_t at the
+		 * beginning of the file, but consume the space
+		 * reserved for it.
+		 */
+
+		if ((unsigned)sbuf.st_size < tparams->header_size) {
+			fprintf (stderr,
+				"%s: Bad size: \"%s\" is too small for XIP\n",
+				params.cmdname, datafile);
+			exit (EXIT_FAILURE);
+		}
+
+		for (p = ptr; p < ptr + tparams->header_size; p++) {
+			if ( *p != 0xff ) {
+				fprintf (stderr,
+					"%s: Bad file: \"%s\" has invalid buffer for XIP\n",
+					params.cmdname, datafile);
+				exit (EXIT_FAILURE);
+			}
+		}
+
+		offset = tparams->header_size;
+	}
+
+	size = sbuf.st_size - offset;
+	if (write(ifd, ptr + offset, size) != size) {
+		fprintf (stderr, "%s: Write error on %s: %s\n",
+			params.cmdname, params.imagefile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	tail = size % 4;
+	if ((pad == 1) && (tail != 0)) {
+
+		if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
+			fprintf (stderr, "%s: Write error on %s: %s\n",
+				params.cmdname, params.imagefile,
+				strerror(errno));
+			exit (EXIT_FAILURE);
+		}
+	} else if (pad > 1) {
+		if (write(ifd, (char *)&zeros, pad) != pad) {
+			fprintf(stderr, "%s: Write error on %s: %s\n",
+				params.cmdname, params.imagefile,
+				strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	(void) munmap((void *)ptr, sbuf.st_size);
+	(void) close (dfd);
+}
+
+static void usage(void)
+{
+	fprintf (stderr, "Usage: %s -l image\n"
+			 "          -l ==> list image header information\n",
+		params.cmdname);
+	fprintf (stderr, "       %s [-x] -A arch -O os -T type -C comp "
+			 "-a addr -e ep -n name -d data_file[:data_file...] image\n"
+			 "          -A ==> set architecture to 'arch'\n"
+			 "          -O ==> set operating system to 'os'\n"
+			 "          -T ==> set image type to 'type'\n"
+			 "          -C ==> set compression type 'comp'\n"
+			 "          -a ==> set load address to 'addr' (hex)\n"
+			 "          -e ==> set entry point to 'ep' (hex)\n"
+			 "          -n ==> set image name to 'name'\n"
+			 "          -d ==> use image data from 'datafile'\n"
+			 "          -x ==> set XIP (execute in place)\n",
+		params.cmdname);
+	fprintf(stderr, "       %s [-D dtc_options] [-f fit-image.its|-F] fit-image\n",
+		params.cmdname);
+	fprintf(stderr, "          -D => set options for device tree compiler\n"
+			"          -f => input filename for FIT source\n");
+#ifdef CONFIG_FIT_SIGNATURE
+	fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n"
+			"          -k => set directory containing private keys\n"
+			"          -K => write public keys to this .dtb file\n"
+			"          -c => add comment in signature node\n"
+			"          -F => re-sign existing FIT image\n"
+			"          -r => mark keys used as 'required' in dtb\n");
+#else
+	fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
+#endif
+	fprintf (stderr, "       %s -V ==> print version information and exit\n",
+		params.cmdname);
+
+	exit (EXIT_FAILURE);
+}
diff --git a/marvell/uboot/tools/mkimage.h b/marvell/uboot/tools/mkimage.h
new file mode 100644
index 0000000..d5491b6
--- /dev/null
+++ b/marvell/uboot/tools/mkimage.h
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2000-2004
+ * DENX Software Engineering
+ * Wolfgang Denk, wd@denx.de
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _MKIIMAGE_H_
+#define _MKIIMAGE_H_
+
+#include "os_support.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <sha1.h>
+#include "fdt_host.h"
+#include "imagetool.h"
+
+#undef MKIMAGE_DEBUG
+
+#ifdef MKIMAGE_DEBUG
+#define debug(fmt,args...)	printf (fmt ,##args)
+#else
+#define debug(fmt,args...)
+#endif /* MKIMAGE_DEBUG */
+
+static inline void *map_sysmem(ulong paddr, unsigned long len)
+{
+	return (void *)(uintptr_t)paddr;
+}
+
+static inline ulong map_to_sysmem(void *ptr)
+{
+	return (ulong)(uintptr_t)ptr;
+}
+
+#define MKIMAGE_TMPFILE_SUFFIX		".tmp"
+#define MKIMAGE_MAX_TMPFILE_LEN		256
+#define MKIMAGE_DEFAULT_DTC_OPTIONS	"-I dts -O dtb -p 500"
+#define MKIMAGE_MAX_DTC_CMDLINE_LEN	512
+#define MKIMAGE_DTC			"dtc"   /* assume dtc is in $PATH */
+
+#endif /* _MKIIMAGE_H_ */
diff --git a/marvell/uboot/tools/mpc86x_clk.c b/marvell/uboot/tools/mpc86x_clk.c
new file mode 100644
index 0000000..9f662f7
--- /dev/null
+++ b/marvell/uboot/tools/mpc86x_clk.c
@@ -0,0 +1,202 @@
+/*
+ * (C) Copyright 2003 Intracom S.A.
+ * Pantelis Antoniou <panto@intracom.gr>
+ *
+ * This little program makes an exhaustive search for the
+ * correct terms of pdf, mfi, mfn, mfd, s, dbrmo, in PLPRCR.
+ * The goal is to produce a gclk2 from a xin input, while respecting
+ * all the restrictions on their combination.
+ *
+ * Generaly you select the first row of the produced table.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define DPREF_MIN	 10000000
+#define DPREF_MAX	 32000000
+
+#define DPGDCK_MAX	320000000
+#define DPGDCK_MIN	160000000
+
+#define S_MIN		0
+#define S_MAX		2
+
+#define MFI_MIN		5
+#define MFI_MAX		15
+
+#define MFN_MIN		0
+#define MFN_MAX		15
+
+#define MFD_MIN		0
+#define MFD_MAX		31
+
+#define MF_MIN		5
+#define MF_MAX		15
+
+#define PDF_MIN		0
+#define PDF_MAX		15
+
+#define GCLK2_MAX	150000000
+
+static int calculate (int xin, int target_clock,
+		      int ppm, int pdf, int mfi, int mfn, int mfd, int s,
+		      int *dprefp, int *dpgdckp, int *jdbckp,
+		      int *gclk2p, int *dbrmop)
+{
+	unsigned int dpref, dpgdck, jdbck, gclk2, t1, t2, dbrmo;
+
+	/* valid MFI? */
+	if (mfi < MFI_MIN)
+		return -1;
+
+	/* valid num, denum? */
+	if (mfn > 0 && mfn >= mfd)
+		return -1;
+
+	dpref = xin / (pdf + 1);
+
+	/* valid dpef? */
+	if (dpref < DPREF_MIN || dpref > DPREF_MAX)
+		return -1;
+
+	if (mfn == 0) {
+		dpgdck  = (2 * mfi * xin) / (pdf + 1) ;
+		dbrmo = 0;
+	} else {
+		/* 5 <= mfi + (mfn / mfd + 1) <= 15 */
+		t1 = mfd + 1;
+		t2 = mfi * t1 + mfn;
+		if ( MF_MIN * t1 > t2 || MF_MAX * t1 < t2)
+			return -1;
+
+		dpgdck  = (unsigned int)(2 * (mfi * mfd + mfi + mfn) *
+				(unsigned int)xin) /
+				((mfd + 1) * (pdf + 1));
+
+		dbrmo = 10 * mfn < (mfd + 1);
+	}
+
+	/* valid dpgclk? */
+	if (dpgdck < DPGDCK_MIN || dpgdck > DPGDCK_MAX)
+		return -1;
+
+	jdbck = dpgdck >> s;
+	gclk2 = jdbck / 2;
+
+	/* valid gclk2 */
+	if (gclk2 > GCLK2_MAX)
+		return -1;
+
+	t1 = abs(gclk2 - target_clock);
+
+	/* XXX max 1MHz dev. in clock */
+	if (t1 > 1000000)
+		return -1;
+
+	/* dev within range (XXX gclk2 scaled to avoid overflow) */
+	if (t1 * 1000 > (unsigned int)ppm * (gclk2 / 1000))
+		return -1;
+
+	*dprefp = dpref;
+	*dpgdckp = dpgdck;
+	*jdbckp = jdbck;
+	*gclk2p = gclk2;
+	*dbrmop = dbrmo;
+
+	return gclk2;
+}
+
+int conf_clock(int xin, int target_clock, int ppm)
+{
+	int pdf, s, mfn, mfd, mfi;
+	int dpref, dpgdck, jdbck, gclk2, xout, dbrmo;
+	int found = 0;
+
+	/* integer multipliers */
+	for (pdf = PDF_MIN; pdf <= PDF_MAX; pdf++) {
+		for (mfi = MFI_MIN; mfi <= MFI_MAX; mfi++) {
+			for (s = 0; s <= S_MAX; s++) {
+				xout = calculate(xin, target_clock,
+						 ppm, pdf, mfi, 0, 0, s,
+						 &dpref, &dpgdck, &jdbck,
+						 &gclk2, &dbrmo);
+				if (xout < 0)
+					continue;
+
+				if (found == 0) {
+					printf("pdf mfi mfn mfd s dbrmo     dpref    dpgdck     jdbck     gclk2 exact?\n");
+					printf("--- --- --- --- - -----     -----    ------     -----     ----- ------\n");
+				}
+
+				printf("%3d %3d --- --- %1d %5d %9d %9d %9d %9d%s\n",
+					pdf, mfi, s, dbrmo,
+					dpref, dpgdck, jdbck, gclk2,
+					gclk2 == target_clock ? "    YES" : "");
+
+				found++;
+			}
+		}
+	}
+
+	/* fractional multipliers */
+	for (pdf = PDF_MIN; pdf <= PDF_MAX; pdf++) {
+		for (mfi = MFI_MIN; mfi <= MFI_MAX; mfi++) {
+			for (mfn = 1; mfn <= MFN_MAX; mfn++) {
+				for (mfd = 1; mfd <= MFD_MAX; mfd++) {
+					for (s = 0; s <= S_MAX; s++) {
+						xout = calculate(xin, target_clock,
+							    ppm, pdf, mfi, mfn, mfd, s,
+							    &dpref, &dpgdck, &jdbck,
+							    &gclk2, &dbrmo);
+						if (xout < 0)
+							continue;
+
+						if (found == 0) {
+							printf("pdf mfi mfn mfd s dbrmo     dpref    dpgdck     jdbck     gclk2 exact?\n");
+							printf("--- --- --- --- - -----     -----    ------     -----     ----- ------\n");
+						}
+
+						printf("%3d %3d %3d %3d %1d %5d %9d %9d %9d %9d%s\n",
+							pdf, mfi, mfn, mfd, s,
+							dbrmo, dpref, dpgdck, jdbck, gclk2,
+							gclk2 == target_clock ? "    YES" : "");
+
+						found++;
+					}
+				}
+			}
+
+		}
+	}
+
+	return found;
+}
+
+int main(int argc, char *argv[])
+{
+	int xin, want_gclk2, found, ppm = 100;
+
+	if (argc < 3) {
+		fprintf(stderr, "usage: mpc86x_clk <xin> <want_gclk2> [ppm]\n");
+		fprintf(stderr, "       default ppm is 100\n");
+		return 10;
+	}
+
+	xin  = atoi(argv[1]);
+	want_gclk2 = atoi(argv[2]);
+	if (argc >= 4)
+		ppm = atoi(argv[3]);
+
+	found = conf_clock(xin, want_gclk2, ppm);
+	if (found <= 0) {
+		fprintf(stderr, "cannot produce gclk2 %d from xin %d\n",
+			want_gclk2, xin);
+		return EXIT_FAILURE;
+	}
+
+	return EXIT_SUCCESS;
+}
diff --git a/marvell/uboot/tools/mxsboot.c b/marvell/uboot/tools/mxsboot.c
new file mode 100644
index 0000000..90b2173
--- /dev/null
+++ b/marvell/uboot/tools/mxsboot.c
@@ -0,0 +1,673 @@
+/*
+ * Freescale i.MX28 image generator
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "compiler.h"
+
+/*
+ * Default BCB layout.
+ *
+ * TWEAK this if you have blown any OCOTP fuses.
+ */
+#define	STRIDE_PAGES		64
+#define	STRIDE_COUNT		4
+
+/*
+ * Layout for 256Mb big NAND with 2048b page size, 64b OOB size and
+ * 128kb erase size.
+ *
+ * TWEAK this if you have different kind of NAND chip.
+ */
+static uint32_t nand_writesize = 2048;
+static uint32_t nand_oobsize = 64;
+static uint32_t nand_erasesize = 128 * 1024;
+
+/*
+ * Sector on which the SigmaTel boot partition (0x53) starts.
+ */
+static uint32_t sd_sector = 2048;
+
+/*
+ * Each of the U-Boot bootstreams is at maximum 1MB big.
+ *
+ * TWEAK this if, for some wild reason, you need to boot bigger image.
+ */
+#define	MAX_BOOTSTREAM_SIZE	(1 * 1024 * 1024)
+
+/* i.MX28 NAND controller-specific constants. DO NOT TWEAK! */
+#define	MXS_NAND_DMA_DESCRIPTOR_COUNT		4
+#define	MXS_NAND_CHUNK_DATA_CHUNK_SIZE		512
+#define	MXS_NAND_METADATA_SIZE			10
+#define	MXS_NAND_COMMAND_BUFFER_SIZE		32
+
+struct mx28_nand_fcb {
+	uint32_t		checksum;
+	uint32_t		fingerprint;
+	uint32_t		version;
+	struct {
+		uint8_t			data_setup;
+		uint8_t			data_hold;
+		uint8_t			address_setup;
+		uint8_t			dsample_time;
+		uint8_t			nand_timing_state;
+		uint8_t			rea;
+		uint8_t			rloh;
+		uint8_t			rhoh;
+	}			timing;
+	uint32_t		page_data_size;
+	uint32_t		total_page_size;
+	uint32_t		sectors_per_block;
+	uint32_t		number_of_nands;		/* Ignored */
+	uint32_t		total_internal_die;		/* Ignored */
+	uint32_t		cell_type;			/* Ignored */
+	uint32_t		ecc_block_n_ecc_type;
+	uint32_t		ecc_block_0_size;
+	uint32_t		ecc_block_n_size;
+	uint32_t		ecc_block_0_ecc_type;
+	uint32_t		metadata_bytes;
+	uint32_t		num_ecc_blocks_per_page;
+	uint32_t		ecc_block_n_ecc_level_sdk;	/* Ignored */
+	uint32_t		ecc_block_0_size_sdk;		/* Ignored */
+	uint32_t		ecc_block_n_size_sdk;		/* Ignored */
+	uint32_t		ecc_block_0_ecc_level_sdk;	/* Ignored */
+	uint32_t		num_ecc_blocks_per_page_sdk;	/* Ignored */
+	uint32_t		metadata_bytes_sdk;		/* Ignored */
+	uint32_t		erase_threshold;
+	uint32_t		boot_patch;
+	uint32_t		patch_sectors;
+	uint32_t		firmware1_starting_sector;
+	uint32_t		firmware2_starting_sector;
+	uint32_t		sectors_in_firmware1;
+	uint32_t		sectors_in_firmware2;
+	uint32_t		dbbt_search_area_start_address;
+	uint32_t		badblock_marker_byte;
+	uint32_t		badblock_marker_start_bit;
+	uint32_t		bb_marker_physical_offset;
+};
+
+struct mx28_nand_dbbt {
+	uint32_t		checksum;
+	uint32_t		fingerprint;
+	uint32_t		version;
+	uint32_t		number_bb;
+	uint32_t		number_2k_pages_bb;
+};
+
+struct mx28_nand_bbt {
+	uint32_t		nand;
+	uint32_t		number_bb;
+	uint32_t		badblock[510];
+};
+
+struct mx28_sd_drive_info {
+	uint32_t		chip_num;
+	uint32_t		drive_type;
+	uint32_t		tag;
+	uint32_t		first_sector_number;
+	uint32_t		sector_count;
+};
+
+struct mx28_sd_config_block {
+	uint32_t			signature;
+	uint32_t			primary_boot_tag;
+	uint32_t			secondary_boot_tag;
+	uint32_t			num_copies;
+	struct mx28_sd_drive_info	drv_info[1];
+};
+
+static inline uint32_t mx28_nand_ecc_size_in_bits(uint32_t ecc_strength)
+{
+	return ecc_strength * 13;
+}
+
+static inline uint32_t mx28_nand_get_ecc_strength(uint32_t page_data_size,
+						uint32_t page_oob_size)
+{
+	if (page_data_size == 2048)
+		return 8;
+
+	if (page_data_size == 4096) {
+		if (page_oob_size == 128)
+			return 8;
+
+		if (page_oob_size == 218)
+			return 16;
+	}
+
+	return 0;
+}
+
+static inline uint32_t mx28_nand_get_mark_offset(uint32_t page_data_size,
+						uint32_t ecc_strength)
+{
+	uint32_t chunk_data_size_in_bits;
+	uint32_t chunk_ecc_size_in_bits;
+	uint32_t chunk_total_size_in_bits;
+	uint32_t block_mark_chunk_number;
+	uint32_t block_mark_chunk_bit_offset;
+	uint32_t block_mark_bit_offset;
+
+	chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8;
+	chunk_ecc_size_in_bits  = mx28_nand_ecc_size_in_bits(ecc_strength);
+
+	chunk_total_size_in_bits =
+			chunk_data_size_in_bits + chunk_ecc_size_in_bits;
+
+	/* Compute the bit offset of the block mark within the physical page. */
+	block_mark_bit_offset = page_data_size * 8;
+
+	/* Subtract the metadata bits. */
+	block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8;
+
+	/*
+	 * Compute the chunk number (starting at zero) in which the block mark
+	 * appears.
+	 */
+	block_mark_chunk_number =
+			block_mark_bit_offset / chunk_total_size_in_bits;
+
+	/*
+	 * Compute the bit offset of the block mark within its chunk, and
+	 * validate it.
+	 */
+	block_mark_chunk_bit_offset = block_mark_bit_offset -
+			(block_mark_chunk_number * chunk_total_size_in_bits);
+
+	if (block_mark_chunk_bit_offset > chunk_data_size_in_bits)
+		return 1;
+
+	/*
+	 * Now that we know the chunk number in which the block mark appears,
+	 * we can subtract all the ECC bits that appear before it.
+	 */
+	block_mark_bit_offset -=
+		block_mark_chunk_number * chunk_ecc_size_in_bits;
+
+	return block_mark_bit_offset;
+}
+
+static inline uint32_t mx28_nand_mark_byte_offset(void)
+{
+	uint32_t ecc_strength;
+	ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
+	return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) >> 3;
+}
+
+static inline uint32_t mx28_nand_mark_bit_offset(void)
+{
+	uint32_t ecc_strength;
+	ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
+	return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) & 0x7;
+}
+
+static uint32_t mx28_nand_block_csum(uint8_t *block, uint32_t size)
+{
+	uint32_t csum = 0;
+	int i;
+
+	for (i = 0; i < size; i++)
+		csum += block[i];
+
+	return csum ^ 0xffffffff;
+}
+
+static struct mx28_nand_fcb *mx28_nand_get_fcb(uint32_t size)
+{
+	struct mx28_nand_fcb *fcb;
+	uint32_t bcb_size_bytes;
+	uint32_t stride_size_bytes;
+	uint32_t bootstream_size_pages;
+	uint32_t fw1_start_page;
+	uint32_t fw2_start_page;
+
+	fcb = malloc(nand_writesize);
+	if (!fcb) {
+		printf("MX28 NAND: Unable to allocate FCB\n");
+		return NULL;
+	}
+
+	memset(fcb, 0, nand_writesize);
+
+	fcb->fingerprint =			0x20424346;
+	fcb->version =				0x01000000;
+
+	/*
+	 * FIXME: These here are default values as found in kobs-ng. We should
+	 * probably retrieve the data from NAND or something.
+	 */
+	fcb->timing.data_setup =		80;
+	fcb->timing.data_hold =			60;
+	fcb->timing.address_setup =		25;
+	fcb->timing.dsample_time =		6;
+
+	fcb->page_data_size =		nand_writesize;
+	fcb->total_page_size =		nand_writesize + nand_oobsize;
+	fcb->sectors_per_block =	nand_erasesize / nand_writesize;
+
+	fcb->num_ecc_blocks_per_page =	(nand_writesize / 512) - 1;
+	fcb->ecc_block_0_size =		512;
+	fcb->ecc_block_n_size =		512;
+	fcb->metadata_bytes =		10;
+
+	if (nand_writesize == 2048) {
+		fcb->ecc_block_n_ecc_type =		4;
+		fcb->ecc_block_0_ecc_type =		4;
+	} else if (nand_writesize == 4096) {
+		if (nand_oobsize == 128) {
+			fcb->ecc_block_n_ecc_type =	4;
+			fcb->ecc_block_0_ecc_type =	4;
+		} else if (nand_oobsize == 218) {
+			fcb->ecc_block_n_ecc_type =	8;
+			fcb->ecc_block_0_ecc_type =	8;
+		}
+	}
+
+	if (fcb->ecc_block_n_ecc_type == 0) {
+		printf("MX28 NAND: Unsupported NAND geometry\n");
+		goto err;
+	}
+
+	fcb->boot_patch =			0;
+	fcb->patch_sectors =			0;
+
+	fcb->badblock_marker_byte =	mx28_nand_mark_byte_offset();
+	fcb->badblock_marker_start_bit = mx28_nand_mark_bit_offset();
+	fcb->bb_marker_physical_offset = nand_writesize;
+
+	stride_size_bytes = STRIDE_PAGES * nand_writesize;
+	bcb_size_bytes = stride_size_bytes * STRIDE_COUNT;
+
+	bootstream_size_pages = (size + (nand_writesize - 1)) /
+					nand_writesize;
+
+	fw1_start_page = 2 * bcb_size_bytes / nand_writesize;
+	fw2_start_page = (2 * bcb_size_bytes + MAX_BOOTSTREAM_SIZE) /
+				nand_writesize;
+
+	fcb->firmware1_starting_sector =	fw1_start_page;
+	fcb->firmware2_starting_sector =	fw2_start_page;
+	fcb->sectors_in_firmware1 =		bootstream_size_pages;
+	fcb->sectors_in_firmware2 =		bootstream_size_pages;
+
+	fcb->dbbt_search_area_start_address =	STRIDE_PAGES * STRIDE_COUNT;
+
+	return fcb;
+
+err:
+	free(fcb);
+	return NULL;
+}
+
+static struct mx28_nand_dbbt *mx28_nand_get_dbbt(void)
+{
+	struct mx28_nand_dbbt *dbbt;
+
+	dbbt = malloc(nand_writesize);
+	if (!dbbt) {
+		printf("MX28 NAND: Unable to allocate DBBT\n");
+		return NULL;
+	}
+
+	memset(dbbt, 0, nand_writesize);
+
+	dbbt->fingerprint	= 0x54424244;
+	dbbt->version		= 0x1;
+
+	return dbbt;
+}
+
+static inline uint8_t mx28_nand_parity_13_8(const uint8_t b)
+{
+	uint32_t parity = 0, tmp;
+
+	tmp = ((b >> 6) ^ (b >> 5) ^ (b >> 3) ^ (b >> 2)) & 1;
+	parity |= tmp << 0;
+
+	tmp = ((b >> 7) ^ (b >> 5) ^ (b >> 4) ^ (b >> 2) ^ (b >> 1)) & 1;
+	parity |= tmp << 1;
+
+	tmp = ((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 1) ^ (b >> 0)) & 1;
+	parity |= tmp << 2;
+
+	tmp = ((b >> 7) ^ (b >> 4) ^ (b >> 3) ^ (b >> 0)) & 1;
+	parity |= tmp << 3;
+
+	tmp = ((b >> 6) ^ (b >> 4) ^ (b >> 3) ^
+		(b >> 2) ^ (b >> 1) ^ (b >> 0)) & 1;
+	parity |= tmp << 4;
+
+	return parity;
+}
+
+static uint8_t *mx28_nand_fcb_block(struct mx28_nand_fcb *fcb)
+{
+	uint8_t *block;
+	uint8_t *ecc;
+	int i;
+
+	block = malloc(nand_writesize + nand_oobsize);
+	if (!block) {
+		printf("MX28 NAND: Unable to allocate FCB block\n");
+		return NULL;
+	}
+
+	memset(block, 0, nand_writesize + nand_oobsize);
+
+	/* Update the FCB checksum */
+	fcb->checksum = mx28_nand_block_csum(((uint8_t *)fcb) + 4, 508);
+
+	/* Figure 12-11. in iMX28RM, rev. 1, says FCB is at offset 12 */
+	memcpy(block + 12, fcb, sizeof(struct mx28_nand_fcb));
+
+	/* ECC is at offset 12 + 512 */
+	ecc = block + 12 + 512;
+
+	/* Compute the ECC parity */
+	for (i = 0; i < sizeof(struct mx28_nand_fcb); i++)
+		ecc[i] = mx28_nand_parity_13_8(block[i + 12]);
+
+	return block;
+}
+
+static int mx28_nand_write_fcb(struct mx28_nand_fcb *fcb, uint8_t *buf)
+{
+	uint32_t offset;
+	uint8_t *fcbblock;
+	int ret = 0;
+	int i;
+
+	fcbblock = mx28_nand_fcb_block(fcb);
+	if (!fcbblock)
+		return -1;
+
+	for (i = 0; i < STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
+		offset = i * nand_writesize;
+		memcpy(buf + offset, fcbblock, nand_writesize + nand_oobsize);
+		/* Mark the NAND page is OK. */
+		buf[offset + nand_writesize] = 0xff;
+	}
+
+	free(fcbblock);
+	return ret;
+}
+
+static int mx28_nand_write_dbbt(struct mx28_nand_dbbt *dbbt, uint8_t *buf)
+{
+	uint32_t offset;
+	int i = STRIDE_PAGES * STRIDE_COUNT;
+
+	for (; i < 2 * STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
+		offset = i * nand_writesize;
+		memcpy(buf + offset, dbbt, sizeof(struct mx28_nand_dbbt));
+	}
+
+	return 0;
+}
+
+static int mx28_nand_write_firmware(struct mx28_nand_fcb *fcb, int infd,
+				    uint8_t *buf)
+{
+	int ret;
+	off_t size;
+	uint32_t offset1, offset2;
+
+	size = lseek(infd, 0, SEEK_END);
+	lseek(infd, 0, SEEK_SET);
+
+	offset1 = fcb->firmware1_starting_sector * nand_writesize;
+	offset2 = fcb->firmware2_starting_sector * nand_writesize;
+
+	ret = read(infd, buf + offset1, size);
+	if (ret != size)
+		return -1;
+
+	memcpy(buf + offset2, buf + offset1, size);
+
+	return 0;
+}
+
+static void usage(void)
+{
+	printf(
+		"Usage: mxsboot [ops] <type> <infile> <outfile>\n"
+		"Augment BootStream file with a proper header for i.MX28 boot\n"
+		"\n"
+		"  <type>	type of image:\n"
+		"                 \"nand\" for NAND image\n"
+		"                 \"sd\" for SD image\n"
+		"  <infile>     input file, the u-boot.sb bootstream\n"
+		"  <outfile>    output file, the bootable image\n"
+		"\n");
+	printf(
+		"For NAND boot, these options are accepted:\n"
+		"  -w <size>    NAND page size\n"
+		"  -o <size>    NAND OOB size\n"
+		"  -e <size>    NAND erase size\n"
+		"\n"
+		"For SD boot, these options are accepted:\n"
+		"  -p <sector>  Sector where the SGTL partition starts\n"
+	);
+}
+
+static int mx28_create_nand_image(int infd, int outfd)
+{
+	struct mx28_nand_fcb *fcb;
+	struct mx28_nand_dbbt *dbbt;
+	int ret = -1;
+	uint8_t *buf;
+	int size;
+	ssize_t wr_size;
+
+	size = nand_writesize * 512 + 2 * MAX_BOOTSTREAM_SIZE;
+
+	buf = malloc(size);
+	if (!buf) {
+		printf("Can not allocate output buffer of %d bytes\n", size);
+		goto err0;
+	}
+
+	memset(buf, 0, size);
+
+	fcb = mx28_nand_get_fcb(MAX_BOOTSTREAM_SIZE);
+	if (!fcb) {
+		printf("Unable to compile FCB\n");
+		goto err1;
+	}
+
+	dbbt = mx28_nand_get_dbbt();
+	if (!dbbt) {
+		printf("Unable to compile DBBT\n");
+		goto err2;
+	}
+
+	ret = mx28_nand_write_fcb(fcb, buf);
+	if (ret) {
+		printf("Unable to write FCB to buffer\n");
+		goto err3;
+	}
+
+	ret = mx28_nand_write_dbbt(dbbt, buf);
+	if (ret) {
+		printf("Unable to write DBBT to buffer\n");
+		goto err3;
+	}
+
+	ret = mx28_nand_write_firmware(fcb, infd, buf);
+	if (ret) {
+		printf("Unable to write firmware to buffer\n");
+		goto err3;
+	}
+
+	wr_size = write(outfd, buf, size);
+	if (wr_size != size) {
+		ret = -1;
+		goto err3;
+	}
+
+	ret = 0;
+
+err3:
+	free(dbbt);
+err2:
+	free(fcb);
+err1:
+	free(buf);
+err0:
+	return ret;
+}
+
+static int mx28_create_sd_image(int infd, int outfd)
+{
+	int ret = -1;
+	uint32_t *buf;
+	int size;
+	off_t fsize;
+	ssize_t wr_size;
+	struct mx28_sd_config_block *cb;
+
+	fsize = lseek(infd, 0, SEEK_END);
+	lseek(infd, 0, SEEK_SET);
+	size = fsize + 4 * 512;
+
+	buf = malloc(size);
+	if (!buf) {
+		printf("Can not allocate output buffer of %d bytes\n", size);
+		goto err0;
+	}
+
+	ret = read(infd, (uint8_t *)buf + 4 * 512, fsize);
+	if (ret != fsize) {
+		ret = -1;
+		goto err1;
+	}
+
+	cb = (struct mx28_sd_config_block *)buf;
+
+	cb->signature = 0x00112233;
+	cb->primary_boot_tag = 0x1;
+	cb->secondary_boot_tag = 0x1;
+	cb->num_copies = 1;
+	cb->drv_info[0].chip_num = 0x0;
+	cb->drv_info[0].drive_type = 0x0;
+	cb->drv_info[0].tag = 0x1;
+	cb->drv_info[0].first_sector_number = sd_sector + 4;
+	cb->drv_info[0].sector_count = (size - 4) / 512;
+
+	wr_size = write(outfd, buf, size);
+	if (wr_size != size) {
+		ret = -1;
+		goto err1;
+	}
+
+	ret = 0;
+
+err1:
+	free(buf);
+err0:
+	return ret;
+}
+
+static int parse_ops(int argc, char **argv)
+{
+	int i;
+	int tmp;
+	char *end;
+	enum param {
+		PARAM_WRITE,
+		PARAM_OOB,
+		PARAM_ERASE,
+		PARAM_PART,
+		PARAM_SD,
+		PARAM_NAND
+	};
+	int type;
+
+	if (argc < 4)
+		return -1;
+
+	for (i = 1; i < argc; i++) {
+		if (!strncmp(argv[i], "-w", 2))
+			type = PARAM_WRITE;
+		else if (!strncmp(argv[i], "-o", 2))
+			type = PARAM_OOB;
+		else if (!strncmp(argv[i], "-e", 2))
+			type = PARAM_ERASE;
+		else if (!strncmp(argv[i], "-p", 2))
+			type = PARAM_PART;
+		else	/* SD/MMC */
+			break;
+
+		tmp = strtol(argv[++i], &end, 10);
+		if (tmp % 2)
+			return -1;
+		if (tmp <= 0)
+			return -1;
+
+		if (type == PARAM_WRITE)
+			nand_writesize = tmp;
+		if (type == PARAM_OOB)
+			nand_oobsize = tmp;
+		if (type == PARAM_ERASE)
+			nand_erasesize = tmp;
+		if (type == PARAM_PART)
+			sd_sector = tmp;
+	}
+
+	if (strcmp(argv[i], "sd") && strcmp(argv[i], "nand"))
+		return -1;
+
+	if (i + 3 != argc)
+		return -1;
+
+	return i;
+}
+
+int main(int argc, char **argv)
+{
+	int infd, outfd;
+	int ret = 0;
+	int offset;
+
+	offset = parse_ops(argc, argv);
+	if (offset < 0) {
+		usage();
+		ret = 1;
+		goto err1;
+	}
+
+	infd = open(argv[offset + 1], O_RDONLY);
+	if (infd < 0) {
+		printf("Input BootStream file can not be opened\n");
+		ret = 2;
+		goto err1;
+	}
+
+	outfd = open(argv[offset + 2], O_CREAT | O_TRUNC | O_WRONLY,
+					S_IRUSR | S_IWUSR);
+	if (outfd < 0) {
+		printf("Output file can not be created\n");
+		ret = 3;
+		goto err2;
+	}
+
+	if (!strcmp(argv[offset], "sd"))
+		ret = mx28_create_sd_image(infd, outfd);
+	else if (!strcmp(argv[offset], "nand"))
+		ret = mx28_create_nand_image(infd, outfd);
+
+	close(outfd);
+err2:
+	close(infd);
+err1:
+	return ret;
+}
diff --git a/marvell/uboot/tools/mxsimage.c b/marvell/uboot/tools/mxsimage.c
new file mode 100644
index 0000000..045b35a
--- /dev/null
+++ b/marvell/uboot/tools/mxsimage.c
@@ -0,0 +1,2348 @@
+/*
+ * Freescale i.MX23/i.MX28 SB image generator
+ *
+ * Copyright (C) 2012-2013 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifdef CONFIG_MXS
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include <openssl/evp.h>
+
+#include "imagetool.h"
+#include "mxsimage.h"
+#include <image.h>
+
+
+/*
+ * DCD block
+ * |-Write to address command block
+ * |  0xf00 == 0xf33d
+ * |  0xba2 == 0xb33f
+ * |-ORR address with mask command block
+ * |  0xf00 |= 0x1337
+ * |-Write to address command block
+ * |  0xba2 == 0xd00d
+ * :
+ */
+#define SB_HAB_DCD_WRITE	0xccUL
+#define SB_HAB_DCD_CHECK	0xcfUL
+#define SB_HAB_DCD_NOOP		0xc0UL
+#define SB_HAB_DCD_MASK_BIT	(1 << 3)
+#define SB_HAB_DCD_SET_BIT	(1 << 4)
+
+/* Addr.n = Value.n */
+#define	SB_DCD_WRITE	\
+	(SB_HAB_DCD_WRITE << 24)
+/* Addr.n &= ~Value.n */
+#define	SB_DCD_ANDC	\
+	((SB_HAB_DCD_WRITE << 24) | SB_HAB_DCD_SET_BIT)
+/* Addr.n |= Value.n */
+#define	SB_DCD_ORR	\
+	((SB_HAB_DCD_WRITE << 24) | SB_HAB_DCD_SET_BIT | SB_HAB_DCD_MASK_BIT)
+/* (Addr.n & Value.n) == 0 */
+#define	SB_DCD_CHK_EQZ	\
+	(SB_HAB_DCD_CHECK << 24)
+/* (Addr.n & Value.n) == Value.n */
+#define	SB_DCD_CHK_EQ	\
+	((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_SET_BIT)
+/* (Addr.n & Value.n) != Value.n */
+#define	SB_DCD_CHK_NEQ	\
+	((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_MASK_BIT)
+/* (Addr.n & Value.n) != 0 */
+#define	SB_DCD_CHK_NEZ	\
+	((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_SET_BIT | SB_HAB_DCD_MASK_BIT)
+/* NOP */
+#define	SB_DCD_NOOP	\
+	(SB_HAB_DCD_NOOP << 24)
+
+struct sb_dcd_ctx {
+	struct sb_dcd_ctx		*dcd;
+
+	uint32_t			id;
+
+	/* The DCD block. */
+	uint32_t			*payload;
+	/* Size of the whole DCD block. */
+	uint32_t			size;
+
+	/* Pointer to previous DCD command block. */
+	uint32_t			*prev_dcd_head;
+};
+
+/*
+ * IMAGE
+ *   |-SECTION
+ *   |    |-CMD
+ *   |    |-CMD
+ *   |    `-CMD
+ *   |-SECTION
+ *   |    |-CMD
+ *   :    :
+ */
+struct sb_cmd_list {
+	char				*cmd;
+	size_t				len;
+	unsigned int			lineno;
+};
+
+struct sb_cmd_ctx {
+	uint32_t			size;
+
+	struct sb_cmd_ctx		*cmd;
+
+	uint8_t				*data;
+	uint32_t			length;
+
+	struct sb_command		payload;
+	struct sb_command		c_payload;
+};
+
+struct sb_section_ctx {
+	uint32_t			size;
+
+	/* Section flags */
+	unsigned int			boot:1;
+
+	struct sb_section_ctx		*sect;
+
+	struct sb_cmd_ctx		*cmd_head;
+	struct sb_cmd_ctx		*cmd_tail;
+
+	struct sb_sections_header	payload;
+};
+
+struct sb_image_ctx {
+	unsigned int			in_section:1;
+	unsigned int			in_dcd:1;
+	/* Image configuration */
+	unsigned int			verbose_boot:1;
+	unsigned int			silent_dump:1;
+	char				*input_filename;
+	char				*output_filename;
+	char				*cfg_filename;
+	uint8_t				image_key[16];
+
+	/* Number of section in the image */
+	unsigned int			sect_count;
+	/* Bootable section */
+	unsigned int			sect_boot;
+	unsigned int			sect_boot_found:1;
+
+	struct sb_section_ctx		*sect_head;
+	struct sb_section_ctx		*sect_tail;
+
+	struct sb_dcd_ctx		*dcd_head;
+	struct sb_dcd_ctx		*dcd_tail;
+
+	EVP_CIPHER_CTX			cipher_ctx;
+	EVP_MD_CTX			md_ctx;
+	uint8_t				digest[32];
+	struct sb_key_dictionary_key	sb_dict_key;
+
+	struct sb_boot_image_header	payload;
+};
+
+/*
+ * Instruction semantics:
+ * NOOP
+ * TAG [LAST]
+ * LOAD       address file
+ * LOAD  IVT  address IVT_entry_point
+ * FILL address pattern length
+ * JUMP [HAB] address [r0_arg]
+ * CALL [HAB] address [r0_arg]
+ * MODE mode
+ *      For i.MX23, mode = USB/I2C/SPI1_FLASH/SPI2_FLASH/NAND_BCH
+ *                         JTAG/SPI3_EEPROM/SD_SSP0/SD_SSP1
+ *      For i.MX28, mode = USB/I2C/SPI2_FLASH/SPI3_FLASH/NAND_BCH
+ *                         JTAG/SPI2_EEPROM/SD_SSP0/SD_SSP1
+ */
+
+/*
+ * AES libcrypto
+ */
+static int sb_aes_init(struct sb_image_ctx *ictx, uint8_t *iv, int enc)
+{
+	EVP_CIPHER_CTX *ctx = &ictx->cipher_ctx;
+	int ret;
+
+	/* If there is no init vector, init vector is all zeroes. */
+	if (!iv)
+		iv = ictx->image_key;
+
+	EVP_CIPHER_CTX_init(ctx);
+	ret = EVP_CipherInit(ctx, EVP_aes_128_cbc(), ictx->image_key, iv, enc);
+	if (ret == 1)
+		EVP_CIPHER_CTX_set_padding(ctx, 0);
+	return ret;
+}
+
+static int sb_aes_crypt(struct sb_image_ctx *ictx, uint8_t *in_data,
+			uint8_t *out_data, int in_len)
+{
+	EVP_CIPHER_CTX *ctx = &ictx->cipher_ctx;
+	int ret, outlen;
+	uint8_t *outbuf;
+
+	outbuf = malloc(in_len);
+	if (!outbuf)
+		return -ENOMEM;
+	memset(outbuf, 0, sizeof(in_len));
+
+	ret = EVP_CipherUpdate(ctx, outbuf, &outlen, in_data, in_len);
+	if (!ret) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (out_data)
+		memcpy(out_data, outbuf, outlen);
+
+err:
+	free(outbuf);
+	return ret;
+}
+
+static int sb_aes_deinit(EVP_CIPHER_CTX *ctx)
+{
+	return EVP_CIPHER_CTX_cleanup(ctx);
+}
+
+static int sb_aes_reinit(struct sb_image_ctx *ictx, int enc)
+{
+	int ret;
+	EVP_CIPHER_CTX *ctx = &ictx->cipher_ctx;
+	struct sb_boot_image_header *sb_header = &ictx->payload;
+	uint8_t *iv = sb_header->iv;
+
+	ret = sb_aes_deinit(ctx);
+	if (!ret)
+		return ret;
+	return sb_aes_init(ictx, iv, enc);
+}
+
+/*
+ * CRC32
+ */
+static uint32_t crc32(uint8_t *data, uint32_t len)
+{
+	const uint32_t poly = 0x04c11db7;
+	uint32_t crc32 = 0xffffffff;
+	unsigned int byte, bit;
+
+	for (byte = 0; byte < len; byte++) {
+		crc32 ^= data[byte] << 24;
+
+		for (bit = 8; bit > 0; bit--) {
+			if (crc32 & (1UL << 31))
+				crc32 = (crc32 << 1) ^ poly;
+			else
+				crc32 = (crc32 << 1);
+		}
+	}
+
+	return crc32;
+}
+
+/*
+ * Debug
+ */
+static void soprintf(struct sb_image_ctx *ictx, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (ictx->silent_dump)
+		return;
+
+	va_start(ap, fmt);
+	vfprintf(stdout, fmt, ap);
+	va_end(ap);
+}
+
+/*
+ * Code
+ */
+static time_t sb_get_timestamp(void)
+{
+	struct tm time_2000 = {
+		.tm_yday	= 1,	/* Jan. 1st */
+		.tm_year	= 100,	/* 2000 */
+	};
+	time_t seconds_to_2000 = mktime(&time_2000);
+	time_t seconds_to_now = time(NULL);
+
+	return seconds_to_now - seconds_to_2000;
+}
+
+static int sb_get_time(time_t time, struct tm *tm)
+{
+	struct tm time_2000 = {
+		.tm_yday	= 1,	/* Jan. 1st */
+		.tm_year	= 0,	/* 1900 */
+	};
+	const time_t seconds_to_2000 = mktime(&time_2000);
+	const time_t seconds_to_now = seconds_to_2000 + time;
+	struct tm *ret;
+	ret = gmtime_r(&seconds_to_now, tm);
+	return ret ? 0 : -EINVAL;
+}
+
+static void sb_encrypt_sb_header(struct sb_image_ctx *ictx)
+{
+	EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+	struct sb_boot_image_header *sb_header = &ictx->payload;
+	uint8_t *sb_header_ptr = (uint8_t *)sb_header;
+
+	/* Encrypt the header, compute the digest. */
+	sb_aes_crypt(ictx, sb_header_ptr, NULL, sizeof(*sb_header));
+	EVP_DigestUpdate(md_ctx, sb_header_ptr, sizeof(*sb_header));
+}
+
+static void sb_encrypt_sb_sections_header(struct sb_image_ctx *ictx)
+{
+	EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+	struct sb_section_ctx *sctx = ictx->sect_head;
+	struct sb_sections_header *shdr;
+	uint8_t *sb_sections_header_ptr;
+	const int size = sizeof(*shdr);
+
+	while (sctx) {
+		shdr = &sctx->payload;
+		sb_sections_header_ptr = (uint8_t *)shdr;
+
+		sb_aes_crypt(ictx, sb_sections_header_ptr,
+			     ictx->sb_dict_key.cbc_mac, size);
+		EVP_DigestUpdate(md_ctx, sb_sections_header_ptr, size);
+
+		sctx = sctx->sect;
+	};
+}
+
+static void sb_encrypt_key_dictionary_key(struct sb_image_ctx *ictx)
+{
+	EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+
+	sb_aes_crypt(ictx, ictx->image_key, ictx->sb_dict_key.key,
+		     sizeof(ictx->sb_dict_key.key));
+	EVP_DigestUpdate(md_ctx, &ictx->sb_dict_key, sizeof(ictx->sb_dict_key));
+}
+
+static void sb_decrypt_key_dictionary_key(struct sb_image_ctx *ictx)
+{
+	EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+
+	EVP_DigestUpdate(md_ctx, &ictx->sb_dict_key, sizeof(ictx->sb_dict_key));
+	sb_aes_crypt(ictx, ictx->sb_dict_key.key, ictx->image_key,
+		     sizeof(ictx->sb_dict_key.key));
+}
+
+static void sb_encrypt_tag(struct sb_image_ctx *ictx,
+		struct sb_cmd_ctx *cctx)
+{
+	EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+	struct sb_command *cmd = &cctx->payload;
+
+	sb_aes_crypt(ictx, (uint8_t *)cmd,
+		     (uint8_t *)&cctx->c_payload, sizeof(*cmd));
+	EVP_DigestUpdate(md_ctx, &cctx->c_payload, sizeof(*cmd));
+}
+
+static int sb_encrypt_image(struct sb_image_ctx *ictx)
+{
+	/* Start image-wide crypto. */
+	EVP_MD_CTX_init(&ictx->md_ctx);
+	EVP_DigestInit(&ictx->md_ctx, EVP_sha1());
+
+	/*
+	 * SB image header.
+	 */
+	sb_aes_init(ictx, NULL, 1);
+	sb_encrypt_sb_header(ictx);
+
+	/*
+	 * SB sections header.
+	 */
+	sb_encrypt_sb_sections_header(ictx);
+
+	/*
+	 * Key dictionary.
+	 */
+	sb_aes_reinit(ictx, 1);
+	sb_encrypt_key_dictionary_key(ictx);
+
+	/*
+	 * Section tags.
+	 */
+	struct sb_cmd_ctx *cctx;
+	struct sb_command *ccmd;
+	struct sb_section_ctx *sctx = ictx->sect_head;
+
+	while (sctx) {
+		cctx = sctx->cmd_head;
+
+		sb_aes_reinit(ictx, 1);
+
+		while (cctx) {
+			ccmd = &cctx->payload;
+
+			sb_encrypt_tag(ictx, cctx);
+
+			if (ccmd->header.tag == ROM_TAG_CMD) {
+				sb_aes_reinit(ictx, 1);
+			} else if (ccmd->header.tag == ROM_LOAD_CMD) {
+				sb_aes_crypt(ictx, cctx->data, cctx->data,
+					     cctx->length);
+				EVP_DigestUpdate(&ictx->md_ctx, cctx->data,
+						 cctx->length);
+			}
+
+			cctx = cctx->cmd;
+		}
+
+		sctx = sctx->sect;
+	};
+
+	/*
+	 * Dump the SHA1 of the whole image.
+	 */
+	sb_aes_reinit(ictx, 1);
+
+	EVP_DigestFinal(&ictx->md_ctx, ictx->digest, NULL);
+	sb_aes_crypt(ictx, ictx->digest, ictx->digest, sizeof(ictx->digest));
+
+	/* Stop the encryption session. */
+	sb_aes_deinit(&ictx->cipher_ctx);
+
+	return 0;
+}
+
+static int sb_load_file(struct sb_cmd_ctx *cctx, char *filename)
+{
+	long real_size, roundup_size;
+	uint8_t *data;
+	long ret;
+	unsigned long size;
+	FILE *fp;
+
+	if (!filename) {
+		fprintf(stderr, "ERR: Missing filename!\n");
+		return -EINVAL;
+	}
+
+	fp = fopen(filename, "r");
+	if (!fp)
+		goto err_open;
+
+	ret = fseek(fp, 0, SEEK_END);
+	if (ret < 0)
+		goto err_file;
+
+	real_size = ftell(fp);
+	if (real_size < 0)
+		goto err_file;
+
+	ret = fseek(fp, 0, SEEK_SET);
+	if (ret < 0)
+		goto err_file;
+
+	roundup_size = roundup(real_size, SB_BLOCK_SIZE);
+	data = calloc(1, roundup_size);
+	if (!data)
+		goto err_file;
+
+	size = fread(data, 1, real_size, fp);
+	if (size != (unsigned long)real_size)
+		goto err_alloc;
+
+	cctx->data = data;
+	cctx->length = roundup_size;
+
+	fclose(fp);
+	return 0;
+
+err_alloc:
+	free(data);
+err_file:
+	fclose(fp);
+err_open:
+	fprintf(stderr, "ERR: Failed to load file \"%s\"\n", filename);
+	return -EINVAL;
+}
+
+static uint8_t sb_command_checksum(struct sb_command *inst)
+{
+	uint8_t *inst_ptr = (uint8_t *)inst;
+	uint8_t csum = 0;
+	unsigned int i;
+
+	for (i = 0; i < sizeof(struct sb_command); i++)
+		csum += inst_ptr[i];
+
+	return csum;
+}
+
+static int sb_token_to_long(char *tok, uint32_t *rid)
+{
+	char *endptr;
+	unsigned long id;
+
+	if (tok[0] != '0' || tok[1] != 'x') {
+		fprintf(stderr, "ERR: Invalid hexadecimal number!\n");
+		return -EINVAL;
+	}
+
+	tok += 2;
+
+	errno = 0;
+	id = strtoul(tok, &endptr, 16);
+	if ((errno == ERANGE && id == ULONG_MAX) || (errno != 0 && id == 0)) {
+		fprintf(stderr, "ERR: Value can't be decoded!\n");
+		return -EINVAL;
+	}
+
+	/* Check for 32-bit overflow. */
+	if (id > 0xffffffff) {
+		fprintf(stderr, "ERR: Value too big!\n");
+		return -EINVAL;
+	}
+
+	if (endptr == tok) {
+		fprintf(stderr, "ERR: Deformed value!\n");
+		return -EINVAL;
+	}
+
+	*rid = (uint32_t)id;
+	return 0;
+}
+
+static int sb_grow_dcd(struct sb_dcd_ctx *dctx, unsigned int inc_size)
+{
+	uint32_t *tmp;
+
+	if (!inc_size)
+		return 0;
+
+	dctx->size += inc_size;
+	tmp = realloc(dctx->payload, dctx->size);
+	if (!tmp)
+		return -ENOMEM;
+
+	dctx->payload = tmp;
+
+	/* Assemble and update the HAB DCD header. */
+	dctx->payload[0] = htonl((SB_HAB_DCD_TAG << 24) |
+				 (dctx->size << 8) |
+				 SB_HAB_VERSION);
+
+	return 0;
+}
+
+static int sb_build_dcd(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
+{
+	struct sb_dcd_ctx *dctx;
+
+	char *tok;
+	uint32_t id;
+	int ret;
+
+	dctx = calloc(1, sizeof(*dctx));
+	if (!dctx)
+		return -ENOMEM;
+
+	ret = sb_grow_dcd(dctx, 4);
+	if (ret)
+		goto err_dcd;
+
+	/* Read DCD block number. */
+	tok = strtok(cmd->cmd, " ");
+	if (!tok) {
+		fprintf(stderr, "#%i ERR: DCD block without number!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err_dcd;
+	}
+
+	/* Parse the DCD block number. */
+	ret = sb_token_to_long(tok, &id);
+	if (ret) {
+		fprintf(stderr, "#%i ERR: Malformed DCD block number!\n",
+			cmd->lineno);
+		goto err_dcd;
+	}
+
+	dctx->id = id;
+
+	/*
+	 * The DCD block is now constructed. Append it to the list.
+	 * WARNING: The DCD size is still not computed and will be
+	 * updated while parsing it's commands.
+	 */
+	if (!ictx->dcd_head) {
+		ictx->dcd_head = dctx;
+		ictx->dcd_tail = dctx;
+	} else {
+		ictx->dcd_tail->dcd = dctx;
+		ictx->dcd_tail = dctx;
+	}
+
+	return 0;
+
+err_dcd:
+	free(dctx->payload);
+	free(dctx);
+	return ret;
+}
+
+static int sb_build_dcd_block(struct sb_image_ctx *ictx,
+			      struct sb_cmd_list *cmd,
+			      uint32_t type)
+{
+	char *tok;
+	uint32_t address, value, length;
+	int ret;
+
+	struct sb_dcd_ctx *dctx = ictx->dcd_tail;
+	uint32_t *dcd;
+
+	if (dctx->prev_dcd_head && (type != SB_DCD_NOOP) &&
+	    ((dctx->prev_dcd_head[0] & 0xff0000ff) == type)) {
+		/* Same instruction as before, just append it. */
+		ret = sb_grow_dcd(dctx, 8);
+		if (ret)
+			return ret;
+	} else if (type == SB_DCD_NOOP) {
+		ret = sb_grow_dcd(dctx, 4);
+		if (ret)
+			return ret;
+
+		/* Update DCD command block pointer. */
+		dctx->prev_dcd_head = dctx->payload +
+				dctx->size / sizeof(*dctx->payload) - 1;
+
+		/* NOOP has only 4 bytes and no payload. */
+		goto noop;
+	} else {
+		/*
+		 * Either a different instruction block started now
+		 * or this is the first instruction block.
+		 */
+		ret = sb_grow_dcd(dctx, 12);
+		if (ret)
+			return ret;
+
+		/* Update DCD command block pointer. */
+		dctx->prev_dcd_head = dctx->payload +
+				dctx->size / sizeof(*dctx->payload) - 3;
+	}
+
+	dcd = dctx->payload + dctx->size / sizeof(*dctx->payload) - 2;
+
+	/*
+	 * Prepare the command.
+	 */
+	tok = strtok(cmd->cmd, " ");
+	if (!tok) {
+		fprintf(stderr, "#%i ERR: Missing DCD address!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Read DCD destination address. */
+	ret = sb_token_to_long(tok, &address);
+	if (ret) {
+		fprintf(stderr, "#%i ERR: Incorrect DCD address!\n",
+			cmd->lineno);
+		goto err;
+	}
+
+	tok = strtok(NULL, " ");
+	if (!tok) {
+		fprintf(stderr, "#%i ERR: Missing DCD value!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Read DCD operation value. */
+	ret = sb_token_to_long(tok, &value);
+	if (ret) {
+		fprintf(stderr, "#%i ERR: Incorrect DCD value!\n",
+			cmd->lineno);
+		goto err;
+	}
+
+	/* Fill in the new DCD entry. */
+	dcd[0] = htonl(address);
+	dcd[1] = htonl(value);
+
+noop:
+	/* Update the DCD command block. */
+	length = dctx->size -
+		 ((dctx->prev_dcd_head - dctx->payload) *
+		 sizeof(*dctx->payload));
+	dctx->prev_dcd_head[0] = htonl(type | (length << 8));
+
+err:
+	return ret;
+}
+
+static int sb_build_section(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
+{
+	struct sb_section_ctx *sctx;
+	struct sb_sections_header *shdr;
+	char *tok;
+	uint32_t bootable = 0;
+	uint32_t id;
+	int ret;
+
+	sctx = calloc(1, sizeof(*sctx));
+	if (!sctx)
+		return -ENOMEM;
+
+	/* Read section number. */
+	tok = strtok(cmd->cmd, " ");
+	if (!tok) {
+		fprintf(stderr, "#%i ERR: Section without number!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err_sect;
+	}
+
+	/* Parse the section number. */
+	ret = sb_token_to_long(tok, &id);
+	if (ret) {
+		fprintf(stderr, "#%i ERR: Malformed section number!\n",
+			cmd->lineno);
+		goto err_sect;
+	}
+
+	/* Read section's BOOTABLE flag. */
+	tok = strtok(NULL, " ");
+	if (tok && (strlen(tok) == 8) && !strncmp(tok, "BOOTABLE", 8))
+		bootable = SB_SECTION_FLAG_BOOTABLE;
+
+	sctx->boot = bootable;
+
+	shdr = &sctx->payload;
+	shdr->section_number = id;
+	shdr->section_flags = bootable;
+
+	/*
+	 * The section is now constructed. Append it to the list.
+	 * WARNING: The section size is still not computed and will
+	 * be updated while parsing it's commands.
+	 */
+	ictx->sect_count++;
+
+	/* Mark that this section is bootable one. */
+	if (bootable) {
+		if (ictx->sect_boot_found) {
+			fprintf(stderr,
+				"#%i WARN: Multiple bootable section!\n",
+				cmd->lineno);
+		} else {
+			ictx->sect_boot = id;
+			ictx->sect_boot_found = 1;
+		}
+	}
+
+	if (!ictx->sect_head) {
+		ictx->sect_head = sctx;
+		ictx->sect_tail = sctx;
+	} else {
+		ictx->sect_tail->sect = sctx;
+		ictx->sect_tail = sctx;
+	}
+
+	return 0;
+
+err_sect:
+	free(sctx);
+	return ret;
+}
+
+static int sb_build_command_nop(struct sb_image_ctx *ictx)
+{
+	struct sb_section_ctx *sctx = ictx->sect_tail;
+	struct sb_cmd_ctx *cctx;
+	struct sb_command *ccmd;
+
+	cctx = calloc(1, sizeof(*cctx));
+	if (!cctx)
+		return -ENOMEM;
+
+	ccmd = &cctx->payload;
+
+	/*
+	 * Construct the command.
+	 */
+	ccmd->header.checksum	= 0x5a;
+	ccmd->header.tag	= ROM_NOP_CMD;
+
+	cctx->size = sizeof(*ccmd);
+
+	/*
+	 * Append the command to the last section.
+	 */
+	if (!sctx->cmd_head) {
+		sctx->cmd_head = cctx;
+		sctx->cmd_tail = cctx;
+	} else {
+		sctx->cmd_tail->cmd = cctx;
+		sctx->cmd_tail = cctx;
+	}
+
+	return 0;
+}
+
+static int sb_build_command_tag(struct sb_image_ctx *ictx,
+				struct sb_cmd_list *cmd)
+{
+	struct sb_section_ctx *sctx = ictx->sect_tail;
+	struct sb_cmd_ctx *cctx;
+	struct sb_command *ccmd;
+	char *tok;
+
+	cctx = calloc(1, sizeof(*cctx));
+	if (!cctx)
+		return -ENOMEM;
+
+	ccmd = &cctx->payload;
+
+	/*
+	 * Prepare the command.
+	 */
+	/* Check for the LAST keyword. */
+	tok = strtok(cmd->cmd, " ");
+	if (tok && !strcmp(tok, "LAST"))
+		ccmd->header.flags = ROM_TAG_CMD_FLAG_ROM_LAST_TAG;
+
+	/*
+	 * Construct the command.
+	 */
+	ccmd->header.checksum	= 0x5a;
+	ccmd->header.tag	= ROM_TAG_CMD;
+
+	cctx->size = sizeof(*ccmd);
+
+	/*
+	 * Append the command to the last section.
+	 */
+	if (!sctx->cmd_head) {
+		sctx->cmd_head = cctx;
+		sctx->cmd_tail = cctx;
+	} else {
+		sctx->cmd_tail->cmd = cctx;
+		sctx->cmd_tail = cctx;
+	}
+
+	return 0;
+}
+
+static int sb_build_command_load(struct sb_image_ctx *ictx,
+				 struct sb_cmd_list *cmd)
+{
+	struct sb_section_ctx *sctx = ictx->sect_tail;
+	struct sb_cmd_ctx *cctx;
+	struct sb_command *ccmd;
+	char *tok;
+	int ret, is_ivt = 0, is_dcd = 0;
+	uint32_t dest, dcd = 0;
+
+	cctx = calloc(1, sizeof(*cctx));
+	if (!cctx)
+		return -ENOMEM;
+
+	ccmd = &cctx->payload;
+
+	/*
+	 * Prepare the command.
+	 */
+	tok = strtok(cmd->cmd, " ");
+	if (!tok) {
+		fprintf(stderr, "#%i ERR: Missing LOAD address or 'IVT'!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Check for "IVT" flag. */
+	if (!strcmp(tok, "IVT"))
+		is_ivt = 1;
+	if (!strcmp(tok, "DCD"))
+		is_dcd = 1;
+	if (is_ivt || is_dcd) {
+		tok = strtok(NULL, " ");
+		if (!tok) {
+			fprintf(stderr, "#%i ERR: Missing LOAD address!\n",
+				cmd->lineno);
+			ret = -EINVAL;
+			goto err;
+		}
+	}
+
+	/* Read load destination address. */
+	ret = sb_token_to_long(tok, &dest);
+	if (ret) {
+		fprintf(stderr, "#%i ERR: Incorrect LOAD address!\n",
+			cmd->lineno);
+		goto err;
+	}
+
+	/* Read filename or IVT entrypoint or DCD block ID. */
+	tok = strtok(NULL, " ");
+	if (!tok) {
+		fprintf(stderr,
+			"#%i ERR: Missing LOAD filename or IVT ep or DCD block ID!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (is_ivt) {
+		/* Handle IVT. */
+		struct sb_ivt_header *ivt;
+		uint32_t ivtep;
+		ret = sb_token_to_long(tok, &ivtep);
+
+		if (ret) {
+			fprintf(stderr,
+				"#%i ERR: Incorrect IVT entry point!\n",
+				cmd->lineno);
+			goto err;
+		}
+
+		ivt = calloc(1, sizeof(*ivt));
+		if (!ivt) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		ivt->header = sb_hab_ivt_header();
+		ivt->entry = ivtep;
+		ivt->self = dest;
+
+		cctx->data = (uint8_t *)ivt;
+		cctx->length = sizeof(*ivt);
+	} else if (is_dcd) {
+		struct sb_dcd_ctx *dctx = ictx->dcd_head;
+		uint32_t dcdid;
+		uint8_t *payload;
+		uint32_t asize;
+		ret = sb_token_to_long(tok, &dcdid);
+
+		if (ret) {
+			fprintf(stderr,
+				"#%i ERR: Incorrect DCD block ID!\n",
+				cmd->lineno);
+			goto err;
+		}
+
+		while (dctx) {
+			if (dctx->id == dcdid)
+				break;
+			dctx = dctx->dcd;
+		}
+
+		if (!dctx) {
+			fprintf(stderr, "#%i ERR: DCD block %08x not found!\n",
+				cmd->lineno, dcdid);
+			goto err;
+		}
+
+		asize = roundup(dctx->size, SB_BLOCK_SIZE);
+		payload = calloc(1, asize);
+		if (!payload) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		memcpy(payload, dctx->payload, dctx->size);
+
+		cctx->data = payload;
+		cctx->length = asize;
+
+		/* Set the Load DCD flag. */
+		dcd = ROM_LOAD_CMD_FLAG_DCD_LOAD;
+	} else {
+		/* Regular LOAD of a file. */
+		ret = sb_load_file(cctx, tok);
+		if (ret) {
+			fprintf(stderr, "#%i ERR: Cannot load '%s'!\n",
+				cmd->lineno, tok);
+			goto err;
+		}
+	}
+
+	if (cctx->length & (SB_BLOCK_SIZE - 1)) {
+		fprintf(stderr, "#%i ERR: Unaligned payload!\n",
+			cmd->lineno);
+	}
+
+	/*
+	 * Construct the command.
+	 */
+	ccmd->header.checksum	= 0x5a;
+	ccmd->header.tag	= ROM_LOAD_CMD;
+	ccmd->header.flags	= dcd;
+
+	ccmd->load.address	= dest;
+	ccmd->load.count	= cctx->length;
+	ccmd->load.crc32	= crc32(cctx->data, cctx->length);
+
+	cctx->size = sizeof(*ccmd) + cctx->length;
+
+	/*
+	 * Append the command to the last section.
+	 */
+	if (!sctx->cmd_head) {
+		sctx->cmd_head = cctx;
+		sctx->cmd_tail = cctx;
+	} else {
+		sctx->cmd_tail->cmd = cctx;
+		sctx->cmd_tail = cctx;
+	}
+
+	return 0;
+
+err:
+	free(cctx);
+	return ret;
+}
+
+static int sb_build_command_fill(struct sb_image_ctx *ictx,
+				 struct sb_cmd_list *cmd)
+{
+	struct sb_section_ctx *sctx = ictx->sect_tail;
+	struct sb_cmd_ctx *cctx;
+	struct sb_command *ccmd;
+	char *tok;
+	uint32_t address, pattern, length;
+	int ret;
+
+	cctx = calloc(1, sizeof(*cctx));
+	if (!cctx)
+		return -ENOMEM;
+
+	ccmd = &cctx->payload;
+
+	/*
+	 * Prepare the command.
+	 */
+	tok = strtok(cmd->cmd, " ");
+	if (!tok) {
+		fprintf(stderr, "#%i ERR: Missing FILL address!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Read fill destination address. */
+	ret = sb_token_to_long(tok, &address);
+	if (ret) {
+		fprintf(stderr, "#%i ERR: Incorrect FILL address!\n",
+			cmd->lineno);
+		goto err;
+	}
+
+	tok = strtok(NULL, " ");
+	if (!tok) {
+		fprintf(stderr, "#%i ERR: Missing FILL pattern!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Read fill pattern address. */
+	ret = sb_token_to_long(tok, &pattern);
+	if (ret) {
+		fprintf(stderr, "#%i ERR: Incorrect FILL pattern!\n",
+			cmd->lineno);
+		goto err;
+	}
+
+	tok = strtok(NULL, " ");
+	if (!tok) {
+		fprintf(stderr, "#%i ERR: Missing FILL length!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Read fill pattern address. */
+	ret = sb_token_to_long(tok, &length);
+	if (ret) {
+		fprintf(stderr, "#%i ERR: Incorrect FILL length!\n",
+			cmd->lineno);
+		goto err;
+	}
+
+	/*
+	 * Construct the command.
+	 */
+	ccmd->header.checksum	= 0x5a;
+	ccmd->header.tag	= ROM_FILL_CMD;
+
+	ccmd->fill.address	= address;
+	ccmd->fill.count	= length;
+	ccmd->fill.pattern	= pattern;
+
+	cctx->size = sizeof(*ccmd);
+
+	/*
+	 * Append the command to the last section.
+	 */
+	if (!sctx->cmd_head) {
+		sctx->cmd_head = cctx;
+		sctx->cmd_tail = cctx;
+	} else {
+		sctx->cmd_tail->cmd = cctx;
+		sctx->cmd_tail = cctx;
+	}
+
+	return 0;
+
+err:
+	free(cctx);
+	return ret;
+}
+
+static int sb_build_command_jump_call(struct sb_image_ctx *ictx,
+				      struct sb_cmd_list *cmd,
+				      unsigned int is_call)
+{
+	struct sb_section_ctx *sctx = ictx->sect_tail;
+	struct sb_cmd_ctx *cctx;
+	struct sb_command *ccmd;
+	char *tok;
+	uint32_t dest, arg = 0x0;
+	uint32_t hab = 0;
+	int ret;
+	const char *cmdname = is_call ? "CALL" : "JUMP";
+
+	cctx = calloc(1, sizeof(*cctx));
+	if (!cctx)
+		return -ENOMEM;
+
+	ccmd = &cctx->payload;
+
+	/*
+	 * Prepare the command.
+	 */
+	tok = strtok(cmd->cmd, " ");
+	if (!tok) {
+		fprintf(stderr,
+			"#%i ERR: Missing %s address or 'HAB'!\n",
+			cmd->lineno, cmdname);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Check for "HAB" flag. */
+	if (!strcmp(tok, "HAB")) {
+		hab = is_call ? ROM_CALL_CMD_FLAG_HAB : ROM_JUMP_CMD_FLAG_HAB;
+		tok = strtok(NULL, " ");
+		if (!tok) {
+			fprintf(stderr, "#%i ERR: Missing %s address!\n",
+				cmd->lineno, cmdname);
+			ret = -EINVAL;
+			goto err;
+		}
+	}
+	/* Read load destination address. */
+	ret = sb_token_to_long(tok, &dest);
+	if (ret) {
+		fprintf(stderr, "#%i ERR: Incorrect %s address!\n",
+			cmd->lineno, cmdname);
+		goto err;
+	}
+
+	tok = strtok(NULL, " ");
+	if (tok) {
+		ret = sb_token_to_long(tok, &arg);
+		if (ret) {
+			fprintf(stderr,
+				"#%i ERR: Incorrect %s argument!\n",
+				cmd->lineno, cmdname);
+			goto err;
+		}
+	}
+
+	/*
+	 * Construct the command.
+	 */
+	ccmd->header.checksum	= 0x5a;
+	ccmd->header.tag	= is_call ? ROM_CALL_CMD : ROM_JUMP_CMD;
+	ccmd->header.flags	= hab;
+
+	ccmd->call.address	= dest;
+	ccmd->call.argument	= arg;
+
+	cctx->size = sizeof(*ccmd);
+
+	/*
+	 * Append the command to the last section.
+	 */
+	if (!sctx->cmd_head) {
+		sctx->cmd_head = cctx;
+		sctx->cmd_tail = cctx;
+	} else {
+		sctx->cmd_tail->cmd = cctx;
+		sctx->cmd_tail = cctx;
+	}
+
+	return 0;
+
+err:
+	free(cctx);
+	return ret;
+}
+
+static int sb_build_command_jump(struct sb_image_ctx *ictx,
+				 struct sb_cmd_list *cmd)
+{
+	return sb_build_command_jump_call(ictx, cmd, 0);
+}
+
+static int sb_build_command_call(struct sb_image_ctx *ictx,
+				 struct sb_cmd_list *cmd)
+{
+	return sb_build_command_jump_call(ictx, cmd, 1);
+}
+
+static int sb_build_command_mode(struct sb_image_ctx *ictx,
+				 struct sb_cmd_list *cmd)
+{
+	struct sb_section_ctx *sctx = ictx->sect_tail;
+	struct sb_cmd_ctx *cctx;
+	struct sb_command *ccmd;
+	char *tok;
+	int ret;
+	unsigned int i;
+	uint32_t mode = 0xffffffff;
+
+	cctx = calloc(1, sizeof(*cctx));
+	if (!cctx)
+		return -ENOMEM;
+
+	ccmd = &cctx->payload;
+
+	/*
+	 * Prepare the command.
+	 */
+	tok = strtok(cmd->cmd, " ");
+	if (!tok) {
+		fprintf(stderr, "#%i ERR: Missing MODE boot mode argument!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(modetable); i++) {
+		if (!strcmp(tok, modetable[i].name)) {
+			mode = modetable[i].mode;
+			break;
+		}
+
+		if (!modetable[i].altname)
+			continue;
+
+		if (!strcmp(tok, modetable[i].altname)) {
+			mode = modetable[i].mode;
+			break;
+		}
+	}
+
+	if (mode == 0xffffffff) {
+		fprintf(stderr, "#%i ERR: Invalid MODE boot mode argument!\n",
+			cmd->lineno);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/*
+	 * Construct the command.
+	 */
+	ccmd->header.checksum	= 0x5a;
+	ccmd->header.tag	= ROM_MODE_CMD;
+
+	ccmd->mode.mode		= mode;
+
+	cctx->size = sizeof(*ccmd);
+
+	/*
+	 * Append the command to the last section.
+	 */
+	if (!sctx->cmd_head) {
+		sctx->cmd_head = cctx;
+		sctx->cmd_tail = cctx;
+	} else {
+		sctx->cmd_tail->cmd = cctx;
+		sctx->cmd_tail = cctx;
+	}
+
+	return 0;
+
+err:
+	free(cctx);
+	return ret;
+}
+
+static int sb_prefill_image_header(struct sb_image_ctx *ictx)
+{
+	struct sb_boot_image_header *hdr = &ictx->payload;
+
+	/* Fill signatures */
+	memcpy(hdr->signature1, "STMP", 4);
+	memcpy(hdr->signature2, "sgtl", 4);
+
+	/* SB Image version 1.1 */
+	hdr->major_version = SB_VERSION_MAJOR;
+	hdr->minor_version = SB_VERSION_MINOR;
+
+	/* Boot image major version */
+	hdr->product_version.major = htons(0x999);
+	hdr->product_version.minor = htons(0x999);
+	hdr->product_version.revision = htons(0x999);
+	/* Boot image major version */
+	hdr->component_version.major = htons(0x999);
+	hdr->component_version.minor = htons(0x999);
+	hdr->component_version.revision = htons(0x999);
+
+	/* Drive tag must be 0x0 for i.MX23 */
+	hdr->drive_tag = 0;
+
+	hdr->header_blocks =
+		sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE;
+	hdr->section_header_size =
+		sizeof(struct sb_sections_header) / SB_BLOCK_SIZE;
+	hdr->timestamp_us = sb_get_timestamp() * 1000000;
+
+	/* FIXME -- add proper config option */
+	hdr->flags = ictx->verbose_boot ? SB_IMAGE_FLAG_VERBOSE : 0,
+
+	/* FIXME -- We support only default key */
+	hdr->key_count = 1;
+
+	return 0;
+}
+
+static int sb_postfill_image_header(struct sb_image_ctx *ictx)
+{
+	struct sb_boot_image_header *hdr = &ictx->payload;
+	struct sb_section_ctx *sctx = ictx->sect_head;
+	uint32_t kd_size, sections_blocks;
+	EVP_MD_CTX md_ctx;
+
+	/* The main SB header size in blocks. */
+	hdr->image_blocks = hdr->header_blocks;
+
+	/* Size of the key dictionary, which has single zero entry. */
+	kd_size = hdr->key_count * sizeof(struct sb_key_dictionary_key);
+	hdr->image_blocks += kd_size / SB_BLOCK_SIZE;
+
+	/* Now count the payloads. */
+	hdr->section_count = ictx->sect_count;
+	while (sctx) {
+		hdr->image_blocks += sctx->size / SB_BLOCK_SIZE;
+		sctx = sctx->sect;
+	}
+
+	if (!ictx->sect_boot_found) {
+		fprintf(stderr, "ERR: No bootable section selected!\n");
+		return -EINVAL;
+	}
+	hdr->first_boot_section_id = ictx->sect_boot;
+
+	/* The n * SB section size in blocks. */
+	sections_blocks = hdr->section_count * hdr->section_header_size;
+	hdr->image_blocks += sections_blocks;
+
+	/* Key dictionary offset. */
+	hdr->key_dictionary_block = hdr->header_blocks + sections_blocks;
+
+	/* Digest of the whole image. */
+	hdr->image_blocks += 2;
+
+	/* Pointer past the dictionary. */
+	hdr->first_boot_tag_block =
+		hdr->key_dictionary_block + kd_size / SB_BLOCK_SIZE;
+
+	/* Compute header digest. */
+	EVP_MD_CTX_init(&md_ctx);
+
+	EVP_DigestInit(&md_ctx, EVP_sha1());
+	EVP_DigestUpdate(&md_ctx, hdr->signature1,
+			 sizeof(struct sb_boot_image_header) -
+			 sizeof(hdr->digest));
+	EVP_DigestFinal(&md_ctx, hdr->digest, NULL);
+
+	return 0;
+}
+
+static int sb_fixup_sections_and_tags(struct sb_image_ctx *ictx)
+{
+	/* Fixup the placement of sections. */
+	struct sb_boot_image_header *ihdr = &ictx->payload;
+	struct sb_section_ctx *sctx = ictx->sect_head;
+	struct sb_sections_header *shdr;
+	struct sb_cmd_ctx *cctx;
+	struct sb_command *ccmd;
+	uint32_t offset = ihdr->first_boot_tag_block;
+
+	while (sctx) {
+		shdr = &sctx->payload;
+
+		/* Fill in the section TAG offset. */
+		shdr->section_offset = offset + 1;
+		offset += shdr->section_size;
+
+		/* Section length is measured from the TAG block. */
+		shdr->section_size--;
+
+		/* Fixup the TAG command. */
+		cctx = sctx->cmd_head;
+		while (cctx) {
+			ccmd = &cctx->payload;
+			if (ccmd->header.tag == ROM_TAG_CMD) {
+				ccmd->tag.section_number = shdr->section_number;
+				ccmd->tag.section_length = shdr->section_size;
+				ccmd->tag.section_flags = shdr->section_flags;
+			}
+
+			/* Update the command checksum. */
+			ccmd->header.checksum = sb_command_checksum(ccmd);
+
+			cctx = cctx->cmd;
+		}
+
+		sctx = sctx->sect;
+	}
+
+	return 0;
+}
+
+static int sb_parse_line(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd)
+{
+	char *tok;
+	char *line = cmd->cmd;
+	char *rptr;
+	int ret;
+
+	/* Analyze the identifier on this line first. */
+	tok = strtok_r(line, " ", &rptr);
+	if (!tok || (strlen(tok) == 0)) {
+		fprintf(stderr, "#%i ERR: Invalid line!\n", cmd->lineno);
+		return -EINVAL;
+	}
+
+	cmd->cmd = rptr;
+
+	/* DCD */
+	if (!strcmp(tok, "DCD")) {
+		ictx->in_section = 0;
+		ictx->in_dcd = 1;
+		sb_build_dcd(ictx, cmd);
+		return 0;
+	}
+
+	/* Section */
+	if (!strcmp(tok, "SECTION")) {
+		ictx->in_section = 1;
+		ictx->in_dcd = 0;
+		sb_build_section(ictx, cmd);
+		return 0;
+	}
+
+	if (!ictx->in_section && !ictx->in_dcd) {
+		fprintf(stderr, "#%i ERR: Data outside of a section!\n",
+			cmd->lineno);
+		return -EINVAL;
+	}
+
+	if (ictx->in_section) {
+		/* Section commands */
+		if (!strcmp(tok, "NOP")) {
+			ret = sb_build_command_nop(ictx);
+		} else if (!strcmp(tok, "TAG")) {
+			ret = sb_build_command_tag(ictx, cmd);
+		} else if (!strcmp(tok, "LOAD")) {
+			ret = sb_build_command_load(ictx, cmd);
+		} else if (!strcmp(tok, "FILL")) {
+			ret = sb_build_command_fill(ictx, cmd);
+		} else if (!strcmp(tok, "JUMP")) {
+			ret = sb_build_command_jump(ictx, cmd);
+		} else if (!strcmp(tok, "CALL")) {
+			ret = sb_build_command_call(ictx, cmd);
+		} else if (!strcmp(tok, "MODE")) {
+			ret = sb_build_command_mode(ictx, cmd);
+		} else {
+			fprintf(stderr,
+				"#%i ERR: Unsupported instruction '%s'!\n",
+				cmd->lineno, tok);
+			return -ENOTSUP;
+		}
+	} else if (ictx->in_dcd) {
+		char *lptr;
+		uint32_t ilen = '1';
+
+		tok = strtok_r(tok, ".", &lptr);
+		if (!tok || (strlen(tok) == 0) || (lptr && strlen(lptr) != 1)) {
+			fprintf(stderr, "#%i ERR: Invalid line!\n",
+				cmd->lineno);
+			return -EINVAL;
+		}
+
+		if (lptr &&
+		    (lptr[0] != '1' && lptr[0] != '2' && lptr[0] != '4')) {
+			fprintf(stderr, "#%i ERR: Invalid instruction width!\n",
+				cmd->lineno);
+			return -EINVAL;
+		}
+
+		if (lptr)
+			ilen = lptr[0] - '1';
+
+		/* DCD commands */
+		if (!strcmp(tok, "WRITE")) {
+			ret = sb_build_dcd_block(ictx, cmd,
+						 SB_DCD_WRITE | ilen);
+		} else if (!strcmp(tok, "ANDC")) {
+			ret = sb_build_dcd_block(ictx, cmd,
+						 SB_DCD_ANDC | ilen);
+		} else if (!strcmp(tok, "ORR")) {
+			ret = sb_build_dcd_block(ictx, cmd,
+						 SB_DCD_ORR | ilen);
+		} else if (!strcmp(tok, "EQZ")) {
+			ret = sb_build_dcd_block(ictx, cmd,
+						 SB_DCD_CHK_EQZ | ilen);
+		} else if (!strcmp(tok, "EQ")) {
+			ret = sb_build_dcd_block(ictx, cmd,
+						 SB_DCD_CHK_EQ | ilen);
+		} else if (!strcmp(tok, "NEQ")) {
+			ret = sb_build_dcd_block(ictx, cmd,
+						 SB_DCD_CHK_NEQ | ilen);
+		} else if (!strcmp(tok, "NEZ")) {
+			ret = sb_build_dcd_block(ictx, cmd,
+						 SB_DCD_CHK_NEZ | ilen);
+		} else if (!strcmp(tok, "NOOP")) {
+			ret = sb_build_dcd_block(ictx, cmd, SB_DCD_NOOP);
+		} else {
+			fprintf(stderr,
+				"#%i ERR: Unsupported instruction '%s'!\n",
+				cmd->lineno, tok);
+			return -ENOTSUP;
+		}
+	} else {
+		fprintf(stderr, "#%i ERR: Unsupported instruction '%s'!\n",
+			cmd->lineno, tok);
+		return -ENOTSUP;
+	}
+
+	/*
+	 * Here we have at least one section with one command, otherwise we
+	 * would have failed already higher above.
+	 *
+	 * FIXME -- should the updating happen here ?
+	 */
+	if (ictx->in_section && !ret) {
+		ictx->sect_tail->size += ictx->sect_tail->cmd_tail->size;
+		ictx->sect_tail->payload.section_size =
+			ictx->sect_tail->size / SB_BLOCK_SIZE;
+	}
+
+	return ret;
+}
+
+static int sb_load_cmdfile(struct sb_image_ctx *ictx)
+{
+	struct sb_cmd_list cmd;
+	int lineno = 1;
+	FILE *fp;
+	char *line = NULL;
+	ssize_t rlen;
+	size_t len;
+
+	fp = fopen(ictx->cfg_filename, "r");
+	if (!fp)
+		goto err_file;
+
+	while ((rlen = getline(&line, &len, fp)) > 0) {
+		memset(&cmd, 0, sizeof(cmd));
+
+		/* Strip the trailing newline. */
+		line[rlen - 1] = '\0';
+
+		cmd.cmd = line;
+		cmd.len = rlen;
+		cmd.lineno = lineno++;
+
+		sb_parse_line(ictx, &cmd);
+	}
+
+	free(line);
+
+	fclose(fp);
+
+	return 0;
+
+err_file:
+	fclose(fp);
+	fprintf(stderr, "ERR: Failed to load file \"%s\"\n",
+		ictx->cfg_filename);
+	return -EINVAL;
+}
+
+static int sb_build_tree_from_cfg(struct sb_image_ctx *ictx)
+{
+	int ret;
+
+	ret = sb_load_cmdfile(ictx);
+	if (ret)
+		return ret;
+
+	ret = sb_prefill_image_header(ictx);
+	if (ret)
+		return ret;
+
+	ret = sb_postfill_image_header(ictx);
+	if (ret)
+		return ret;
+
+	ret = sb_fixup_sections_and_tags(ictx);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int sb_verify_image_header(struct sb_image_ctx *ictx,
+				  FILE *fp, long fsize)
+{
+	/* Verify static fields in the image header. */
+	struct sb_boot_image_header *hdr = &ictx->payload;
+	const char *stat[2] = { "[PASS]", "[FAIL]" };
+	struct tm tm;
+	int sz, ret = 0;
+	unsigned char digest[20];
+	EVP_MD_CTX md_ctx;
+	unsigned long size;
+
+	/* Start image-wide crypto. */
+	EVP_MD_CTX_init(&ictx->md_ctx);
+	EVP_DigestInit(&ictx->md_ctx, EVP_sha1());
+
+	soprintf(ictx, "---------- Verifying SB Image Header ----------\n");
+
+	size = fread(&ictx->payload, 1, sizeof(ictx->payload), fp);
+	if (size != sizeof(ictx->payload)) {
+		fprintf(stderr, "ERR: SB image header too short!\n");
+		return -EINVAL;
+	}
+
+	/* Compute header digest. */
+	EVP_MD_CTX_init(&md_ctx);
+	EVP_DigestInit(&md_ctx, EVP_sha1());
+	EVP_DigestUpdate(&md_ctx, hdr->signature1,
+			 sizeof(struct sb_boot_image_header) -
+			 sizeof(hdr->digest));
+	EVP_DigestFinal(&md_ctx, digest, NULL);
+
+	sb_aes_init(ictx, NULL, 1);
+	sb_encrypt_sb_header(ictx);
+
+	if (memcmp(digest, hdr->digest, 20))
+		ret = -EINVAL;
+	soprintf(ictx, "%s Image header checksum:        %s\n", stat[!!ret],
+		 ret ? "BAD" : "OK");
+	if (ret)
+		return ret;
+
+	if (memcmp(hdr->signature1, "STMP", 4) ||
+	    memcmp(hdr->signature2, "sgtl", 4))
+		ret = -EINVAL;
+	soprintf(ictx, "%s Signatures:                   '%.4s' '%.4s'\n",
+		 stat[!!ret], hdr->signature1, hdr->signature2);
+	if (ret)
+		return ret;
+
+	if ((hdr->major_version != SB_VERSION_MAJOR) ||
+	    ((hdr->minor_version != 1) && (hdr->minor_version != 2)))
+		ret = -EINVAL;
+	soprintf(ictx, "%s Image version:                v%i.%i\n", stat[!!ret],
+		 hdr->major_version, hdr->minor_version);
+	if (ret)
+		return ret;
+
+	ret = sb_get_time(hdr->timestamp_us / 1000000, &tm);
+	soprintf(ictx,
+		 "%s Creation time:                %02i:%02i:%02i %02i/%02i/%04i\n",
+		 stat[!!ret], tm.tm_hour, tm.tm_min, tm.tm_sec,
+		 tm.tm_mday, tm.tm_mon, tm.tm_year + 2000);
+	if (ret)
+		return ret;
+
+	soprintf(ictx, "%s Product version:              %x.%x.%x\n", stat[0],
+		 ntohs(hdr->product_version.major),
+		 ntohs(hdr->product_version.minor),
+		 ntohs(hdr->product_version.revision));
+	soprintf(ictx, "%s Component version:            %x.%x.%x\n", stat[0],
+		 ntohs(hdr->component_version.major),
+		 ntohs(hdr->component_version.minor),
+		 ntohs(hdr->component_version.revision));
+
+	if (hdr->flags & ~SB_IMAGE_FLAG_VERBOSE)
+		ret = -EINVAL;
+	soprintf(ictx, "%s Image flags:                  %s\n", stat[!!ret],
+		 hdr->flags & SB_IMAGE_FLAG_VERBOSE ? "Verbose_boot" : "");
+	if (ret)
+		return ret;
+
+	if (hdr->drive_tag != 0)
+		ret = -EINVAL;
+	soprintf(ictx, "%s Drive tag:                    %i\n", stat[!!ret],
+		 hdr->drive_tag);
+	if (ret)
+		return ret;
+
+	sz = sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE;
+	if (hdr->header_blocks != sz)
+		ret = -EINVAL;
+	soprintf(ictx, "%s Image header size (blocks):   %i\n", stat[!!ret],
+		 hdr->header_blocks);
+	if (ret)
+		return ret;
+
+	sz = sizeof(struct sb_sections_header) / SB_BLOCK_SIZE;
+	if (hdr->section_header_size != sz)
+		ret = -EINVAL;
+	soprintf(ictx, "%s Section header size (blocks): %i\n", stat[!!ret],
+		 hdr->section_header_size);
+	if (ret)
+		return ret;
+
+	soprintf(ictx, "%s Sections count:               %i\n", stat[!!ret],
+		 hdr->section_count);
+	soprintf(ictx, "%s First bootable section        %i\n", stat[!!ret],
+		 hdr->first_boot_section_id);
+
+	if (hdr->image_blocks != fsize / SB_BLOCK_SIZE)
+		ret = -EINVAL;
+	soprintf(ictx, "%s Image size (blocks):          %i\n", stat[!!ret],
+		 hdr->image_blocks);
+	if (ret)
+		return ret;
+
+	sz = hdr->header_blocks + hdr->section_header_size * hdr->section_count;
+	if (hdr->key_dictionary_block != sz)
+		ret = -EINVAL;
+	soprintf(ictx, "%s Key dict offset (blocks):     %i\n", stat[!!ret],
+		 hdr->key_dictionary_block);
+	if (ret)
+		return ret;
+
+	if (hdr->key_count != 1)
+		ret = -EINVAL;
+	soprintf(ictx, "%s Number of encryption keys:    %i\n", stat[!!ret],
+		 hdr->key_count);
+	if (ret)
+		return ret;
+
+	sz = hdr->header_blocks + hdr->section_header_size * hdr->section_count;
+	sz += hdr->key_count *
+		sizeof(struct sb_key_dictionary_key) / SB_BLOCK_SIZE;
+	if (hdr->first_boot_tag_block != (unsigned)sz)
+		ret = -EINVAL;
+	soprintf(ictx, "%s First TAG block (blocks):     %i\n", stat[!!ret],
+		 hdr->first_boot_tag_block);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void sb_decrypt_tag(struct sb_image_ctx *ictx,
+		struct sb_cmd_ctx *cctx)
+{
+	EVP_MD_CTX *md_ctx = &ictx->md_ctx;
+	struct sb_command *cmd = &cctx->payload;
+
+	sb_aes_crypt(ictx, (uint8_t *)&cctx->c_payload,
+		     (uint8_t *)&cctx->payload, sizeof(*cmd));
+	EVP_DigestUpdate(md_ctx, &cctx->c_payload, sizeof(*cmd));
+}
+
+static int sb_verify_command(struct sb_image_ctx *ictx,
+			     struct sb_cmd_ctx *cctx, FILE *fp,
+			     unsigned long *tsize)
+{
+	struct sb_command *ccmd = &cctx->payload;
+	unsigned long size, asize;
+	char *csum, *flag = "";
+	int ret;
+	unsigned int i;
+	uint8_t csn, csc = ccmd->header.checksum;
+	ccmd->header.checksum = 0x5a;
+	csn = sb_command_checksum(ccmd);
+	ccmd->header.checksum = csc;
+
+	if (csc == csn)
+		ret = 0;
+	else
+		ret = -EINVAL;
+	csum = ret ? "checksum BAD" : "checksum OK";
+
+	switch (ccmd->header.tag) {
+	case ROM_NOP_CMD:
+		soprintf(ictx, " NOOP # %s\n", csum);
+		return ret;
+	case ROM_TAG_CMD:
+		if (ccmd->header.flags & ROM_TAG_CMD_FLAG_ROM_LAST_TAG)
+			flag = "LAST";
+		soprintf(ictx, " TAG %s # %s\n", flag, csum);
+		sb_aes_reinit(ictx, 0);
+		return ret;
+	case ROM_LOAD_CMD:
+		soprintf(ictx, " LOAD addr=0x%08x length=0x%08x # %s\n",
+			 ccmd->load.address, ccmd->load.count, csum);
+
+		cctx->length = ccmd->load.count;
+		asize = roundup(cctx->length, SB_BLOCK_SIZE);
+		cctx->data = malloc(asize);
+		if (!cctx->data)
+			return -ENOMEM;
+
+		size = fread(cctx->data, 1, asize, fp);
+		if (size != asize) {
+			fprintf(stderr,
+				"ERR: SB LOAD command payload too short!\n");
+			return -EINVAL;
+		}
+
+		*tsize += size;
+
+		EVP_DigestUpdate(&ictx->md_ctx, cctx->data, asize);
+		sb_aes_crypt(ictx, cctx->data, cctx->data, asize);
+
+		if (ccmd->load.crc32 != crc32(cctx->data, asize)) {
+			fprintf(stderr,
+				"ERR: SB LOAD command payload CRC32 invalid!\n");
+			return -EINVAL;
+		}
+		return 0;
+	case ROM_FILL_CMD:
+		soprintf(ictx,
+			 " FILL addr=0x%08x length=0x%08x pattern=0x%08x # %s\n",
+			 ccmd->fill.address, ccmd->fill.count,
+			 ccmd->fill.pattern, csum);
+		return 0;
+	case ROM_JUMP_CMD:
+		if (ccmd->header.flags & ROM_JUMP_CMD_FLAG_HAB)
+			flag = " HAB";
+		soprintf(ictx,
+			 " JUMP%s addr=0x%08x r0_arg=0x%08x # %s\n",
+			 flag, ccmd->fill.address, ccmd->jump.argument, csum);
+		return 0;
+	case ROM_CALL_CMD:
+		if (ccmd->header.flags & ROM_CALL_CMD_FLAG_HAB)
+			flag = " HAB";
+		soprintf(ictx,
+			 " CALL%s addr=0x%08x r0_arg=0x%08x # %s\n",
+			 flag, ccmd->fill.address, ccmd->jump.argument, csum);
+		return 0;
+	case ROM_MODE_CMD:
+		for (i = 0; i < ARRAY_SIZE(modetable); i++) {
+			if (ccmd->mode.mode == modetable[i].mode) {
+				soprintf(ictx, " MODE %s # %s\n",
+					 modetable[i].name, csum);
+				break;
+			}
+		}
+		fprintf(stderr, " MODE !INVALID! # %s\n", csum);
+		return 0;
+	}
+
+	return ret;
+}
+
+static int sb_verify_commands(struct sb_image_ctx *ictx,
+			      struct sb_section_ctx *sctx, FILE *fp)
+{
+	unsigned long size, tsize = 0;
+	struct sb_cmd_ctx *cctx;
+	int ret;
+
+	sb_aes_reinit(ictx, 0);
+
+	while (tsize < sctx->size) {
+		cctx = calloc(1, sizeof(*cctx));
+		if (!cctx)
+			return -ENOMEM;
+		if (!sctx->cmd_head) {
+			sctx->cmd_head = cctx;
+			sctx->cmd_tail = cctx;
+		} else {
+			sctx->cmd_tail->cmd = cctx;
+			sctx->cmd_tail = cctx;
+		}
+
+		size = fread(&cctx->c_payload, 1, sizeof(cctx->c_payload), fp);
+		if (size != sizeof(cctx->c_payload)) {
+			fprintf(stderr, "ERR: SB command header too short!\n");
+			return -EINVAL;
+		}
+
+		tsize += size;
+
+		sb_decrypt_tag(ictx, cctx);
+
+		ret = sb_verify_command(ictx, cctx, fp, &tsize);
+		if (ret)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sb_verify_sections_cmds(struct sb_image_ctx *ictx, FILE *fp)
+{
+	struct sb_boot_image_header *hdr = &ictx->payload;
+	struct sb_sections_header *shdr;
+	unsigned int i;
+	int ret;
+	struct sb_section_ctx *sctx;
+	unsigned long size;
+	char *bootable = "";
+
+	soprintf(ictx, "----- Verifying  SB Sections and Commands -----\n");
+
+	for (i = 0; i < hdr->section_count; i++) {
+		sctx = calloc(1, sizeof(*sctx));
+		if (!sctx)
+			return -ENOMEM;
+		if (!ictx->sect_head) {
+			ictx->sect_head = sctx;
+			ictx->sect_tail = sctx;
+		} else {
+			ictx->sect_tail->sect = sctx;
+			ictx->sect_tail = sctx;
+		}
+
+		size = fread(&sctx->payload, 1, sizeof(sctx->payload), fp);
+		if (size != sizeof(sctx->payload)) {
+			fprintf(stderr, "ERR: SB section header too short!\n");
+			return -EINVAL;
+		}
+	}
+
+	size = fread(&ictx->sb_dict_key, 1, sizeof(ictx->sb_dict_key), fp);
+	if (size != sizeof(ictx->sb_dict_key)) {
+		fprintf(stderr, "ERR: SB key dictionary too short!\n");
+		return -EINVAL;
+	}
+
+	sb_encrypt_sb_sections_header(ictx);
+	sb_aes_reinit(ictx, 0);
+	sb_decrypt_key_dictionary_key(ictx);
+
+	sb_aes_reinit(ictx, 0);
+
+	sctx = ictx->sect_head;
+	while (sctx) {
+		shdr = &sctx->payload;
+
+		if (shdr->section_flags & SB_SECTION_FLAG_BOOTABLE) {
+			sctx->boot = 1;
+			bootable = " BOOTABLE";
+		}
+
+		sctx->size = (shdr->section_size * SB_BLOCK_SIZE) +
+			     sizeof(struct sb_command);
+		soprintf(ictx, "SECTION 0x%x%s # size = %i bytes\n",
+			 shdr->section_number, bootable, sctx->size);
+
+		if (shdr->section_flags & ~SB_SECTION_FLAG_BOOTABLE)
+			fprintf(stderr, " WARN: Unknown section flag(s) %08x\n",
+				shdr->section_flags);
+
+		if ((shdr->section_flags & SB_SECTION_FLAG_BOOTABLE) &&
+		    (hdr->first_boot_section_id != shdr->section_number)) {
+			fprintf(stderr,
+				" WARN: Bootable section does ID not match image header ID!\n");
+		}
+
+		ret = sb_verify_commands(ictx, sctx, fp);
+		if (ret)
+			return ret;
+
+		sctx = sctx->sect;
+	}
+
+	/*
+	 * FIXME IDEA:
+	 * check if the first TAG command is at sctx->section_offset
+	 */
+	return 0;
+}
+
+static int sb_verify_image_end(struct sb_image_ctx *ictx,
+			       FILE *fp, off_t filesz)
+{
+	uint8_t digest[32];
+	unsigned long size;
+	off_t pos;
+	int ret;
+
+	soprintf(ictx, "------------- Verifying image end -------------\n");
+
+	size = fread(digest, 1, sizeof(digest), fp);
+	if (size != sizeof(digest)) {
+		fprintf(stderr, "ERR: SB key dictionary too short!\n");
+		return -EINVAL;
+	}
+
+	pos = ftell(fp);
+	if (pos != filesz) {
+		fprintf(stderr, "ERR: Trailing data past the image!\n");
+		return -EINVAL;
+	}
+
+	/* Check the image digest. */
+	EVP_DigestFinal(&ictx->md_ctx, ictx->digest, NULL);
+
+	/* Decrypt the image digest from the input image. */
+	sb_aes_reinit(ictx, 0);
+	sb_aes_crypt(ictx, digest, digest, sizeof(digest));
+
+	/* Check all of 20 bytes of the SHA1 hash. */
+	ret = memcmp(digest, ictx->digest, 20) ? -EINVAL : 0;
+
+	if (ret)
+		soprintf(ictx, "[FAIL] Full-image checksum:          BAD\n");
+	else
+		soprintf(ictx, "[PASS] Full-image checksum:          OK\n");
+
+	return ret;
+}
+
+
+static int sb_build_tree_from_img(struct sb_image_ctx *ictx)
+{
+	long filesize;
+	int ret;
+	FILE *fp;
+
+	if (!ictx->input_filename) {
+		fprintf(stderr, "ERR: Missing filename!\n");
+		return -EINVAL;
+	}
+
+	fp = fopen(ictx->input_filename, "r");
+	if (!fp)
+		goto err_open;
+
+	ret = fseek(fp, 0, SEEK_END);
+	if (ret < 0)
+		goto err_file;
+
+	filesize = ftell(fp);
+	if (filesize < 0)
+		goto err_file;
+
+	ret = fseek(fp, 0, SEEK_SET);
+	if (ret < 0)
+		goto err_file;
+
+	if (filesize < (signed)sizeof(ictx->payload)) {
+		fprintf(stderr, "ERR: File too short!\n");
+		goto err_file;
+	}
+
+	if (filesize & (SB_BLOCK_SIZE - 1)) {
+		fprintf(stderr, "ERR: The file is not aligned!\n");
+		goto err_file;
+	}
+
+	/* Load and verify image header */
+	ret = sb_verify_image_header(ictx, fp, filesize);
+	if (ret)
+		goto err_verify;
+
+	/* Load and verify sections and commands */
+	ret = sb_verify_sections_cmds(ictx, fp);
+	if (ret)
+		goto err_verify;
+
+	ret = sb_verify_image_end(ictx, fp, filesize);
+	if (ret)
+		goto err_verify;
+
+	ret = 0;
+
+err_verify:
+	soprintf(ictx, "-------------------- Result -------------------\n");
+	soprintf(ictx, "Verification %s\n", ret ? "FAILED" : "PASSED");
+
+	/* Stop the encryption session. */
+	sb_aes_deinit(&ictx->cipher_ctx);
+
+	fclose(fp);
+	return ret;
+
+err_file:
+	fclose(fp);
+err_open:
+	fprintf(stderr, "ERR: Failed to load file \"%s\"\n",
+		ictx->input_filename);
+	return -EINVAL;
+}
+
+static void sb_free_image(struct sb_image_ctx *ictx)
+{
+	struct sb_section_ctx *sctx = ictx->sect_head, *s_head;
+	struct sb_dcd_ctx *dctx = ictx->dcd_head, *d_head;
+	struct sb_cmd_ctx *cctx, *c_head;
+
+	while (sctx) {
+		s_head = sctx;
+		c_head = sctx->cmd_head;
+
+		while (c_head) {
+			cctx = c_head;
+			c_head = c_head->cmd;
+			if (cctx->data)
+				free(cctx->data);
+			free(cctx);
+		}
+
+		sctx = sctx->sect;
+		free(s_head);
+	}
+
+	while (dctx) {
+		d_head = dctx;
+		dctx = dctx->dcd;
+		free(d_head->payload);
+		free(d_head);
+	}
+}
+
+/*
+ * MXSSB-MKIMAGE glue code.
+ */
+static int mxsimage_check_image_types(uint8_t type)
+{
+	if (type == IH_TYPE_MXSIMAGE)
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+}
+
+static void mxsimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+}
+
+int mxsimage_check_params(struct image_tool_params *params)
+{
+	if (!params)
+		return -1;
+	if (!strlen(params->imagename)) {
+		fprintf(stderr,
+			"Error: %s - Configuration file not specified, it is needed for mxsimage generation\n",
+			params->cmdname);
+		return -1;
+	}
+
+	/*
+	 * Check parameters:
+	 * XIP is not allowed and verify that incompatible
+	 * parameters are not sent at the same time
+	 * For example, if list is required a data image must not be provided
+	 */
+	return	(params->dflag && (params->fflag || params->lflag)) ||
+		(params->fflag && (params->dflag || params->lflag)) ||
+		(params->lflag && (params->dflag || params->fflag)) ||
+		(params->xflag) || !(strlen(params->imagename));
+}
+
+static int mxsimage_verify_print_header(char *file, int silent)
+{
+	int ret;
+	struct sb_image_ctx ctx;
+
+	memset(&ctx, 0, sizeof(ctx));
+
+	ctx.input_filename = file;
+	ctx.silent_dump = silent;
+
+	ret = sb_build_tree_from_img(&ctx);
+	sb_free_image(&ctx);
+
+	return ret;
+}
+
+char *imagefile;
+static int mxsimage_verify_header(unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	struct sb_boot_image_header *hdr;
+
+	if (!ptr)
+		return -EINVAL;
+
+	hdr = (struct sb_boot_image_header *)ptr;
+
+	/*
+	 * Check if the header contains the MXS image signatures,
+	 * if so, do a full-image verification.
+	 */
+	if (memcmp(hdr->signature1, "STMP", 4) ||
+	    memcmp(hdr->signature2, "sgtl", 4))
+		return -EINVAL;
+
+	imagefile = params->imagefile;
+
+	return mxsimage_verify_print_header(params->imagefile, 1);
+}
+
+static void mxsimage_print_header(const void *hdr)
+{
+	if (imagefile)
+		mxsimage_verify_print_header(imagefile, 0);
+}
+
+static int sb_build_image(struct sb_image_ctx *ictx,
+			  struct image_type_params *tparams)
+{
+	struct sb_boot_image_header *sb_header = &ictx->payload;
+	struct sb_section_ctx *sctx;
+	struct sb_cmd_ctx *cctx;
+	struct sb_command *ccmd;
+	struct sb_key_dictionary_key *sb_dict_key = &ictx->sb_dict_key;
+
+	uint8_t *image, *iptr;
+
+	/* Calculate image size. */
+	uint32_t size = sizeof(*sb_header) +
+		ictx->sect_count * sizeof(struct sb_sections_header) +
+		sizeof(*sb_dict_key) + sizeof(ictx->digest);
+
+	sctx = ictx->sect_head;
+	while (sctx) {
+		size += sctx->size;
+		sctx = sctx->sect;
+	};
+
+	image = malloc(size);
+	if (!image)
+		return -ENOMEM;
+	iptr = image;
+
+	memcpy(iptr, sb_header, sizeof(*sb_header));
+	iptr += sizeof(*sb_header);
+
+	sctx = ictx->sect_head;
+	while (sctx) {
+		memcpy(iptr, &sctx->payload, sizeof(struct sb_sections_header));
+		iptr += sizeof(struct sb_sections_header);
+		sctx = sctx->sect;
+	};
+
+	memcpy(iptr, sb_dict_key, sizeof(*sb_dict_key));
+	iptr += sizeof(*sb_dict_key);
+
+	sctx = ictx->sect_head;
+	while (sctx) {
+		cctx = sctx->cmd_head;
+		while (cctx) {
+			ccmd = &cctx->payload;
+
+			memcpy(iptr, &cctx->c_payload, sizeof(cctx->payload));
+			iptr += sizeof(cctx->payload);
+
+			if (ccmd->header.tag == ROM_LOAD_CMD) {
+				memcpy(iptr, cctx->data, cctx->length);
+				iptr += cctx->length;
+			}
+
+			cctx = cctx->cmd;
+		}
+
+		sctx = sctx->sect;
+	};
+
+	memcpy(iptr, ictx->digest, sizeof(ictx->digest));
+	iptr += sizeof(ictx->digest);
+
+	/* Configure the mkimage */
+	tparams->hdr = image;
+	tparams->header_size = size;
+
+	return 0;
+}
+
+static int mxsimage_generate(struct image_tool_params *params,
+	struct image_type_params *tparams)
+{
+	int ret;
+	struct sb_image_ctx ctx;
+
+	/* Do not copy the U-Boot image! */
+	params->skipcpy = 1;
+
+	memset(&ctx, 0, sizeof(ctx));
+
+	ctx.cfg_filename = params->imagename;
+	ctx.output_filename = params->imagefile;
+	ctx.verbose_boot = 1;
+
+	ret = sb_build_tree_from_cfg(&ctx);
+	if (ret)
+		goto fail;
+
+	ret = sb_encrypt_image(&ctx);
+	if (!ret)
+		ret = sb_build_image(&ctx, tparams);
+
+fail:
+	sb_free_image(&ctx);
+
+	return ret;
+}
+
+/*
+ * mxsimage parameters
+ */
+static struct image_type_params mxsimage_params = {
+	.name		= "Freescale MXS Boot Image support",
+	.header_size	= 0,
+	.hdr		= NULL,
+	.check_image_type = mxsimage_check_image_types,
+	.verify_header	= mxsimage_verify_header,
+	.print_header	= mxsimage_print_header,
+	.set_header	= mxsimage_set_header,
+	.check_params	= mxsimage_check_params,
+	.vrec_header	= mxsimage_generate,
+};
+
+void init_mxs_image_type(void)
+{
+	register_image_type(&mxsimage_params);
+}
+
+#else
+void init_mxs_image_type(void)
+{
+}
+#endif
diff --git a/marvell/uboot/tools/mxsimage.h b/marvell/uboot/tools/mxsimage.h
new file mode 100644
index 0000000..6cd59d2
--- /dev/null
+++ b/marvell/uboot/tools/mxsimage.h
@@ -0,0 +1,230 @@
+/*
+ * Freescale i.MX28 SB image generator
+ *
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __MXSSB_H__
+#define __MXSSB_H__
+
+#include <stdint.h>
+#include <arpa/inet.h>
+
+#define SB_BLOCK_SIZE		16
+
+#define roundup(x, y)		((((x) + ((y) - 1)) / (y)) * (y))
+#define ARRAY_SIZE(x)		(sizeof(x) / sizeof((x)[0]))
+
+struct sb_boot_image_version {
+	uint16_t	major;
+	uint16_t	pad0;
+	uint16_t	minor;
+	uint16_t	pad1;
+	uint16_t	revision;
+	uint16_t	pad2;
+};
+
+struct sb_boot_image_header {
+	union {
+		/* SHA1 of the header. */
+		uint8_t	digest[20];
+		struct {
+			/* CBC-MAC initialization vector. */
+			uint8_t iv[16];
+			uint8_t extra[4];
+		};
+	};
+	/* 'STMP' */
+	uint8_t		signature1[4];
+	/* Major version of the image format. */
+	uint8_t		major_version;
+	/* Minor version of the image format. */
+	uint8_t		minor_version;
+	/* Flags associated with the image. */
+	uint16_t	flags;
+	/* Size of the image in 16b blocks. */
+	uint32_t	image_blocks;
+	/* Offset of the first tag in 16b blocks. */
+	uint32_t	first_boot_tag_block;
+	/* ID of the section to boot from. */
+	uint32_t	first_boot_section_id;
+	/* Amount of crypto keys. */
+	uint16_t	key_count;
+	/* Offset to the key dictionary in 16b blocks. */
+	uint16_t	key_dictionary_block;
+	/* Size of this header in 16b blocks. */
+	uint16_t	header_blocks;
+	/* Amount of section headers. */
+	uint16_t	section_count;
+	/* Section header size in 16b blocks. */
+	uint16_t	section_header_size;
+	/* Padding to align timestamp to uint64_t. */
+	uint8_t		padding0[2];
+	/* 'sgtl' (since v1.1) */
+	uint8_t		signature2[4];
+	/* Image generation date, in microseconds since 1.1.2000 . */
+	uint64_t	timestamp_us;
+	/* Product version. */
+	struct sb_boot_image_version
+			product_version;
+	/* Component version. */
+	struct sb_boot_image_version
+			component_version;
+	/* Drive tag for the system drive. (since v1.1) */
+	uint16_t	drive_tag;
+	/* Padding. */
+	uint8_t		padding1[6];
+};
+
+#define	SB_VERSION_MAJOR	1
+#define	SB_VERSION_MINOR	1
+
+/* Enable to HTLLC verbose boot report. */
+#define SB_IMAGE_FLAG_VERBOSE	(1 << 0)
+
+struct sb_key_dictionary_key {
+	/* The CBC-MAC of image and sections header. */
+	uint8_t		cbc_mac[SB_BLOCK_SIZE];
+	/* The AES key encrypted by image key (zero). */
+	uint8_t		key[SB_BLOCK_SIZE];
+};
+
+struct sb_ivt_header {
+	uint32_t	header;
+	uint32_t	entry;
+	uint32_t	reserved1;
+	uint32_t	dcd;
+	uint32_t	boot_data;
+	uint32_t	self;
+	uint32_t	csf;
+	uint32_t	reserved2;
+};
+
+#define	SB_HAB_IVT_TAG			0xd1UL
+#define	SB_HAB_DCD_TAG			0xd2UL
+
+#define	SB_HAB_VERSION			0x40UL
+
+/*
+ * The "size" field in the IVT header is not naturally aligned,
+ * use this macro to fill first 4 bytes of the IVT header without
+ * causing issues on some systems (esp. M68k, PPC, MIPS-BE, ARM-BE).
+ */
+static inline uint32_t sb_hab_ivt_header(void)
+{
+	uint32_t ret = 0;
+	ret |= SB_HAB_IVT_TAG << 24;
+	ret |= sizeof(struct sb_ivt_header) << 16;
+	ret |= SB_HAB_VERSION;
+	return htonl(ret);
+}
+
+struct sb_sections_header {
+	/* Section number. */
+	uint32_t	section_number;
+	/* Offset of this sections first instruction after "TAG". */
+	uint32_t	section_offset;
+	/* Size of the section in 16b blocks. */
+	uint32_t	section_size;
+	/* Section flags. */
+	uint32_t	section_flags;
+};
+
+#define	SB_SECTION_FLAG_BOOTABLE	(1 << 0)
+
+struct sb_command {
+	struct {
+		uint8_t		checksum;
+		uint8_t		tag;
+		uint16_t	flags;
+#define ROM_TAG_CMD_FLAG_ROM_LAST_TAG	0x1
+#define ROM_LOAD_CMD_FLAG_DCD_LOAD	0x1	/* MX28 only */
+#define ROM_JUMP_CMD_FLAG_HAB		0x1	/* MX28 only */
+#define ROM_CALL_CMD_FLAG_HAB		0x1	/* MX28 only */
+	} header;
+
+	union {
+	struct {
+		uint32_t	reserved[3];
+	} nop;
+	struct {
+		uint32_t	section_number;
+		uint32_t	section_length;
+		uint32_t	section_flags;
+	} tag;
+	struct {
+		uint32_t	address;
+		uint32_t	count;
+		uint32_t	crc32;
+	} load;
+	struct {
+		uint32_t	address;
+		uint32_t	count;
+		uint32_t	pattern;
+	} fill;
+	struct {
+		uint32_t	address;
+		uint32_t	reserved;
+		/* Passed in register r0 before JUMP */
+		uint32_t	argument;
+	} jump;
+	struct {
+		uint32_t	address;
+		uint32_t	reserved;
+		/* Passed in register r0 before CALL */
+		uint32_t	argument;
+	} call;
+	struct {
+		uint32_t	reserved1;
+		uint32_t	reserved2;
+		uint32_t	mode;
+	} mode;
+
+	};
+};
+
+/*
+ * Most of the mode names are same or at least similar
+ * on i.MX23 and i.MX28, but some of the mode names
+ * differ. The "name" field represents the mode name
+ * on i.MX28 as seen in Table 12-2 of the datasheet.
+ * The "altname" field represents the differently named
+ * fields on i.MX23 as seen in Table 35-3 of the
+ * datasheet.
+ */
+static const struct {
+	const char	*name;
+	const char	*altname;
+	const uint8_t	mode;
+} modetable[] = {
+	{ "USB",		NULL,		0x00 },
+	{ "I2C",		NULL,		0x01 },
+	{ "SPI2_FLASH",		"SPI1_FLASH",	0x02 },
+	{ "SPI3_FLASH",		"SPI2_FLASH",	0x03 },
+	{ "NAND_BCH",		NULL,		0x04 },
+	{ "JTAG",		NULL,		0x06 },
+	{ "SPI3_EEPROM",	"SPI2_EEPROM",	0x08 },
+	{ "SD_SSP0",		NULL,		0x09 },
+	{ "SD_SSP1",		NULL,		0x0A }
+};
+
+enum sb_tag {
+	ROM_NOP_CMD	= 0x00,
+	ROM_TAG_CMD	= 0x01,
+	ROM_LOAD_CMD	= 0x02,
+	ROM_FILL_CMD	= 0x03,
+	ROM_JUMP_CMD	= 0x04,
+	ROM_CALL_CMD	= 0x05,
+	ROM_MODE_CMD	= 0x06
+};
+
+struct sb_source_entry {
+	uint8_t		tag;
+	uint32_t	address;
+	uint32_t	flags;
+	char		*filename;
+};
+
+#endif	/* __MXSSB_H__ */
diff --git a/marvell/uboot/tools/ncb.c b/marvell/uboot/tools/ncb.c
new file mode 100644
index 0000000..ec8d8a7
--- /dev/null
+++ b/marvell/uboot/tools/ncb.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int main (int argc, char *argv[])
+{
+	int s, len, o, port = 6666;
+	char buf[512];
+	struct sockaddr_in addr;
+	socklen_t addr_len = sizeof addr;
+
+	if (argc > 1)
+		port = atoi (argv[1]);
+
+	s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+	o = 1;
+	len = 4;
+	setsockopt (3, SOL_SOCKET, SO_REUSEADDR, &o, len);
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons (port);
+	addr.sin_addr.s_addr = INADDR_ANY;	/* receive broadcasts */
+
+	bind (s, (struct sockaddr *) &addr, sizeof addr);
+
+	for (;;) {
+		len = recvfrom (s, buf, sizeof buf, 0, (struct sockaddr *) &addr, &addr_len);
+		if (len < 0)
+			break;
+		if (write (1, buf, len) != len)
+			fprintf(stderr, "WARNING: serial characters dropped\n");
+	}
+
+	return 0;
+}
diff --git a/marvell/uboot/tools/netconsole b/marvell/uboot/tools/netconsole
new file mode 100755
index 0000000..1a0ef22
--- /dev/null
+++ b/marvell/uboot/tools/netconsole
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+usage() {
+	(
+	echo "Usage: $0 <board-IP> [board-port [board-in-port]]"
+	echo ""
+	echo "If port is not specified, '6666' will be used"
+	[ -z "$*" ] && exit 0
+	echo ""
+	echo "ERROR: $*"
+	exit 1
+	) 1>&2
+	exit $?
+}
+
+while [ -n "$1" ] ; do
+	case $1 in
+		-h|--help) usage;;
+		--)        break;;
+		-*)        usage "Invalid option $1";;
+		*)         break;;
+	esac
+	shift
+done
+
+ip=$1
+board_out_port=${2:-6666}
+board_in_port=${3:-${board_out_port}}
+
+echo Board out port: ${board_out_port}
+echo Board in port: ${board_in_port}
+
+if [ -z "${ip}" ] || [ -n "$4" ] ; then
+	usage "Invalid number of arguments"
+fi
+
+for nc in netcat nc ; do
+	type ${nc} >/dev/null 2>&1 && break
+done
+
+trap "stty icanon echo intr ^C" 0 2 3 5 10 13 15
+echo "NOTE: the interrupt signal (normally ^C) has been remapped to ^T"
+
+stty -icanon -echo intr ^T
+(
+if type ncb 2>/dev/null ; then
+	# see if ncb is in $PATH
+	exec ncb ${board_out_port}
+
+elif [ -x ${0%/*}/ncb ] ; then
+	# maybe it's in the same dir as the netconsole script
+	exec ${0%/*}/ncb ${board_out_port}
+
+else
+	# blah, just use regular netcat
+	while ${nc} -u -l -p ${board_out_port} < /dev/null ; do
+		:
+	done
+fi
+) &
+pid=$!
+${nc} -u ${ip} ${board_in_port}
+kill ${pid} 2>/dev/null
diff --git a/marvell/uboot/tools/omap/clocks_get_m_n.c b/marvell/uboot/tools/omap/clocks_get_m_n.c
new file mode 100644
index 0000000..57e2575
--- /dev/null
+++ b/marvell/uboot/tools/omap/clocks_get_m_n.c
@@ -0,0 +1,186 @@
+/*
+ * Program for finding M & N values for DPLLs
+ * To be run on Host PC
+ *
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *
+ * Aneesh V <aneesh@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <stdlib.h>
+#include <stdio.h>
+typedef unsigned int u32;
+#define MAX_N	127
+
+/*
+ * get_m_n_optimized() - Finds optimal DPLL multiplier(M) and divider(N)
+ * values based on the reference frequency, required output frequency,
+ * maximum tolerance for output frequency etc.
+ *
+ * target_freq_khz - output frequency required in KHz
+ * ref_freq_khz - reference(input) frequency in KHz
+ * m - pointer to computed M value
+ * n - pointer to computed N value
+ * tolerance_khz - tolerance for the output frequency. When the algorithm
+ * succeeds in finding vialble M and N values the corresponding output
+ * frequency will be in the range:
+ *	[target_freq_khz - tolerance_khz, target_freq_khz]
+ *
+ * Formula:
+ *	Fdpll = (2 * M * Fref) / (N + 1)
+ *
+ * Considerations for lock-time:
+ *	- Smaller the N, better lock-time, especially lock-time will be
+ *	- For acceptable lock-times:
+ *		Fref / (M + 1) >= 1 MHz
+ *
+ * Considerations for power:
+ *	- The difference in power for different N values giving the same
+ *	  output is negligible. So, we optimize for lock-time
+ *
+ * Hard-constraints:
+ *	- N can not be greater than 127(7 bit field for representing N)
+ *
+ * Usage:
+ *	$ gcc clocks_get_m_n.c
+ *	$ ./a.out
+ */
+int get_m_n_optimized(u32 target_freq_khz, u32 ref_freq_khz, u32 *M, u32 *N)
+{
+	u32 freq = target_freq_khz;
+	u32 m_optimal, n_optimal, freq_optimal = 0, freq_old;
+	u32 m, n;
+	n = 1;
+	while (1) {
+		m = target_freq_khz / ref_freq_khz / 2 * n;
+		freq_old = 0;
+		while (1) {
+			freq = ref_freq_khz * 2 * m / n;
+			if (freq > target_freq_khz) {
+				freq = freq_old;
+				m--;
+				break;
+			}
+			m++;
+			freq_old = freq;
+		}
+		if (freq > freq_optimal) {
+			freq_optimal = freq;
+			m_optimal = m;
+			n_optimal = n;
+		}
+		n++;
+		if ((freq_optimal == target_freq_khz) ||
+			((ref_freq_khz / n) < 1000)) {
+			break;
+		}
+	}
+	n--;
+	*M = m_optimal;
+	*N = n_optimal - 1;
+	printf("ref %d m %d n %d target %d locked %d\n", ref_freq_khz,
+		m_optimal, n_optimal - 1, target_freq_khz, freq_optimal);
+	return 0;
+}
+
+void main(void)
+{
+	u32 m, n;
+	printf("\nMPU - 2000000\n");
+	get_m_n_optimized(2000000, 12000, &m, &n);
+	get_m_n_optimized(2000000, 13000, &m, &n);
+	get_m_n_optimized(2000000, 16800, &m, &n);
+	get_m_n_optimized(2000000, 19200, &m, &n);
+	get_m_n_optimized(2000000, 26000, &m, &n);
+	get_m_n_optimized(2000000, 27000, &m, &n);
+	get_m_n_optimized(2000000, 38400, &m, &n);
+
+	printf("\nMPU - 1200000\n");
+	get_m_n_optimized(1200000, 12000, &m, &n);
+	get_m_n_optimized(1200000, 13000, &m, &n);
+	get_m_n_optimized(1200000, 16800, &m, &n);
+	get_m_n_optimized(1200000, 19200, &m, &n);
+	get_m_n_optimized(1200000, 26000, &m, &n);
+	get_m_n_optimized(1200000, 27000, &m, &n);
+	get_m_n_optimized(1200000, 38400, &m, &n);
+
+	printf("\nMPU - 1584000\n");
+	get_m_n_optimized(1584000, 12000, &m, &n);
+	get_m_n_optimized(1584000, 13000, &m, &n);
+	get_m_n_optimized(1584000, 16800, &m, &n);
+	get_m_n_optimized(1584000, 19200, &m, &n);
+	get_m_n_optimized(1584000, 26000, &m, &n);
+	get_m_n_optimized(1584000, 27000, &m, &n);
+	get_m_n_optimized(1584000, 38400, &m, &n);
+
+	printf("\nCore 1600000\n");
+	get_m_n_optimized(1600000, 12000, &m, &n);
+	get_m_n_optimized(1600000, 13000, &m, &n);
+	get_m_n_optimized(1600000, 16800, &m, &n);
+	get_m_n_optimized(1600000, 19200, &m, &n);
+	get_m_n_optimized(1600000, 26000, &m, &n);
+	get_m_n_optimized(1600000, 27000, &m, &n);
+	get_m_n_optimized(1600000, 38400, &m, &n);
+
+	printf("\nPER 1536000\n");
+	get_m_n_optimized(1536000, 12000, &m, &n);
+	get_m_n_optimized(1536000, 13000, &m, &n);
+	get_m_n_optimized(1536000, 16800, &m, &n);
+	get_m_n_optimized(1536000, 19200, &m, &n);
+	get_m_n_optimized(1536000, 26000, &m, &n);
+	get_m_n_optimized(1536000, 27000, &m, &n);
+	get_m_n_optimized(1536000, 38400, &m, &n);
+
+	printf("\nIVA 1862000\n");
+	get_m_n_optimized(1862000, 12000, &m, &n);
+	get_m_n_optimized(1862000, 13000, &m, &n);
+	get_m_n_optimized(1862000, 16800, &m, &n);
+	get_m_n_optimized(1862000, 19200, &m, &n);
+	get_m_n_optimized(1862000, 26000, &m, &n);
+	get_m_n_optimized(1862000, 27000, &m, &n);
+	get_m_n_optimized(1862000, 38400, &m, &n);
+
+	printf("\nIVA Nitro - 1290000\n");
+	get_m_n_optimized(1290000, 12000, &m, &n);
+	get_m_n_optimized(1290000, 13000, &m, &n);
+	get_m_n_optimized(1290000, 16800, &m, &n);
+	get_m_n_optimized(1290000, 19200, &m, &n);
+	get_m_n_optimized(1290000, 26000, &m, &n);
+	get_m_n_optimized(1290000, 27000, &m, &n);
+	get_m_n_optimized(1290000, 38400, &m, &n);
+
+	printf("\nABE 196608 sys clk\n");
+	get_m_n_optimized(196608, 12000, &m, &n);
+	get_m_n_optimized(196608, 13000, &m, &n);
+	get_m_n_optimized(196608, 16800, &m, &n);
+	get_m_n_optimized(196608, 19200, &m, &n);
+	get_m_n_optimized(196608, 26000, &m, &n);
+	get_m_n_optimized(196608, 27000, &m, &n);
+	get_m_n_optimized(196608, 38400, &m, &n);
+
+	printf("\nABE 196608 32K\n");
+	get_m_n_optimized(196608000/4, 32768, &m, &n);
+
+	printf("\nUSB 1920000\n");
+	get_m_n_optimized(1920000, 12000, &m, &n);
+	get_m_n_optimized(1920000, 13000, &m, &n);
+	get_m_n_optimized(1920000, 16800, &m, &n);
+	get_m_n_optimized(1920000, 19200, &m, &n);
+	get_m_n_optimized(1920000, 26000, &m, &n);
+	get_m_n_optimized(1920000, 27000, &m, &n);
+	get_m_n_optimized(1920000, 38400, &m, &n);
+
+	printf("\nCore ES1 1523712\n");
+	get_m_n_optimized(1524000, 12000, &m, &n);
+	get_m_n_optimized(1524000, 13000, &m, &n);
+	get_m_n_optimized(1524000, 16800, &m, &n);
+	get_m_n_optimized(1524000, 19200, &m, &n);
+	get_m_n_optimized(1524000, 26000, &m, &n);
+	get_m_n_optimized(1524000, 27000, &m, &n);
+
+	/* exact recommendation for SDPs */
+	get_m_n_optimized(1523712, 38400, &m, &n);
+
+}
diff --git a/marvell/uboot/tools/omapimage.c b/marvell/uboot/tools/omapimage.c
new file mode 100644
index 0000000..d59bc4d
--- /dev/null
+++ b/marvell/uboot/tools/omapimage.c
@@ -0,0 +1,251 @@
+/*
+ * (C) Copyright 2010
+ * Linaro LTD, www.linaro.org
+ * Author: John Rigby <john.rigby@linaro.org>
+ * Based on TI's signGP.c
+ *
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "imagetool.h"
+#include <image.h>
+#include "omapimage.h"
+
+/* Header size is CH header rounded up to 512 bytes plus GP header */
+#define OMAP_CH_HDR_SIZE 512
+#define OMAP_GP_HDR_SIZE (sizeof(struct gp_header))
+#define OMAP_FILE_HDR_SIZE (OMAP_CH_HDR_SIZE+OMAP_GP_HDR_SIZE)
+
+static int do_swap32 = 0;
+
+static uint32_t omapimage_swap32(uint32_t data)
+{
+	uint32_t result = 0;
+	result  = (data & 0xFF000000) >> 24;
+	result |= (data & 0x00FF0000) >> 8;
+	result |= (data & 0x0000FF00) << 8;
+	result |= (data & 0x000000FF) << 24;
+	return result;
+}
+
+static uint8_t omapimage_header[OMAP_FILE_HDR_SIZE];
+
+static int omapimage_check_image_types(uint8_t type)
+{
+	if (type == IH_TYPE_OMAPIMAGE)
+		return EXIT_SUCCESS;
+	else {
+		return EXIT_FAILURE;
+	}
+}
+
+/*
+ * Only the simplest image type is currently supported:
+ * TOC pointing to CHSETTINGS
+ * TOC terminator
+ * CHSETTINGS
+ *
+ * padding to OMAP_CH_HDR_SIZE bytes
+ *
+ * gp header
+ *   size
+ *   load_addr
+ */
+static int valid_gph_size(uint32_t size)
+{
+	return size;
+}
+
+static int valid_gph_load_addr(uint32_t load_addr)
+{
+	return load_addr;
+}
+
+static int omapimage_verify_header(unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	struct ch_toc *toc = (struct ch_toc *)ptr;
+	struct gp_header *gph = (struct gp_header *)(ptr+OMAP_CH_HDR_SIZE);
+	uint32_t offset, size, gph_size, gph_load_addr;
+
+	while (toc->section_offset != 0xffffffff
+			&& toc->section_size != 0xffffffff) {
+		if (do_swap32) {
+			offset = omapimage_swap32(toc->section_offset);
+			size = omapimage_swap32(toc->section_size);
+		} else {
+			offset = toc->section_offset;
+			size = toc->section_size;
+		}
+		if (!offset || !size)
+			return -1;
+		if (offset >= OMAP_CH_HDR_SIZE ||
+		    offset+size >= OMAP_CH_HDR_SIZE)
+			return -1;
+		toc++;
+	}
+
+	if (do_swap32) {
+		gph_size = omapimage_swap32(gph->size);
+		gph_load_addr = omapimage_swap32(gph->load_addr);
+	} else {
+		gph_size = gph->size;
+		gph_load_addr = gph->load_addr;
+	}
+
+	if (!valid_gph_size(gph_size))
+		return -1;
+	if (!valid_gph_load_addr(gph_load_addr))
+		return -1;
+
+	return 0;
+}
+
+static void omapimage_print_section(struct ch_settings *chs)
+{
+	const char *section_name;
+
+	if (chs->section_key)
+		section_name = "CHSETTINGS";
+	else
+		section_name = "UNKNOWNKEY";
+
+	printf("%s (%x) "
+		"valid:%x "
+		"version:%x "
+		"reserved:%x "
+		"flags:%x\n",
+		section_name,
+		chs->section_key,
+		chs->valid,
+		chs->version,
+		chs->reserved,
+		chs->flags);
+}
+
+static void omapimage_print_header(const void *ptr)
+{
+	const struct ch_toc *toc = (struct ch_toc *)ptr;
+	const struct gp_header *gph =
+			(struct gp_header *)(ptr+OMAP_CH_HDR_SIZE);
+	uint32_t offset, size, gph_size, gph_load_addr;
+
+	while (toc->section_offset != 0xffffffff
+			&& toc->section_size != 0xffffffff) {
+		if (do_swap32) {
+			offset = omapimage_swap32(toc->section_offset);
+			size = omapimage_swap32(toc->section_size);
+		} else {
+			offset = toc->section_offset;
+			size = toc->section_size;
+		}
+
+		if (offset >= OMAP_CH_HDR_SIZE ||
+		    offset+size >= OMAP_CH_HDR_SIZE)
+			exit(EXIT_FAILURE);
+
+		printf("Section %s offset %x length %x\n",
+			toc->section_name,
+			toc->section_offset,
+			toc->section_size);
+
+		omapimage_print_section((struct ch_settings *)(ptr+offset));
+		toc++;
+	}
+
+	if (do_swap32) {
+		gph_size = omapimage_swap32(gph->size);
+		gph_load_addr = omapimage_swap32(gph->load_addr);
+	} else {
+		gph_size = gph->size;
+		gph_load_addr = gph->load_addr;
+	}
+
+	if (!valid_gph_size(gph_size)) {
+		fprintf(stderr, "Error: invalid image size %x\n", gph_size);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!valid_gph_load_addr(gph_load_addr)) {
+		fprintf(stderr, "Error: invalid image load address %x\n",
+				gph_load_addr);
+		exit(EXIT_FAILURE);
+	}
+
+	printf("GP Header: Size %x LoadAddr %x\n", gph_size, gph_load_addr);
+}
+
+static int toc_offset(void *hdr, void *member)
+{
+	return member - hdr;
+}
+
+static void omapimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+	struct ch_toc *toc = (struct ch_toc *)ptr;
+	struct ch_settings *chs = (struct ch_settings *)
+					(ptr + 2 * sizeof(*toc));
+	struct gp_header *gph = (struct gp_header *)(ptr + OMAP_CH_HDR_SIZE);
+
+	toc->section_offset = toc_offset(ptr, chs);
+	toc->section_size = sizeof(struct ch_settings);
+	strcpy((char *)toc->section_name, "CHSETTINGS");
+
+	chs->section_key = KEY_CHSETTINGS;
+	chs->valid = 0;
+	chs->version = 1;
+	chs->reserved = 0;
+	chs->flags = 0;
+
+	toc++;
+	memset(toc, 0xff, sizeof(*toc));
+
+	gph->size = sbuf->st_size - OMAP_FILE_HDR_SIZE;
+	gph->load_addr = params->addr;
+
+	if (strncmp(params->imagename, "byteswap", 8) == 0) {
+		do_swap32 = 1;
+		int swapped = 0;
+		uint32_t *data = (uint32_t *)ptr;
+
+		while (swapped <= (sbuf->st_size / sizeof(uint32_t))) {
+			*data = omapimage_swap32(*data);
+			swapped++;
+			data++;
+		}
+	}
+}
+
+int omapimage_check_params(struct image_tool_params *params)
+{
+	return	(params->dflag && (params->fflag || params->lflag)) ||
+		(params->fflag && (params->dflag || params->lflag)) ||
+		(params->lflag && (params->dflag || params->fflag));
+}
+
+/*
+ * omapimage parameters
+ */
+static struct image_type_params omapimage_params = {
+	.name		= "TI OMAP CH/GP Boot Image support",
+	.header_size	= OMAP_FILE_HDR_SIZE,
+	.hdr		= (void *)&omapimage_header,
+	.check_image_type = omapimage_check_image_types,
+	.verify_header	= omapimage_verify_header,
+	.print_header	= omapimage_print_header,
+	.set_header	= omapimage_set_header,
+	.check_params	= omapimage_check_params,
+};
+
+void init_omap_image_type(void)
+{
+	register_image_type(&omapimage_params);
+}
diff --git a/marvell/uboot/tools/omapimage.h b/marvell/uboot/tools/omapimage.h
new file mode 100644
index 0000000..45d14ea
--- /dev/null
+++ b/marvell/uboot/tools/omapimage.h
@@ -0,0 +1,34 @@
+/*
+ * (C) Copyright 2010
+ * Linaro LTD, www.linaro.org
+ * Author John Rigby <john.rigby@linaro.org>
+ * Based on TI's signGP.c
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _OMAPIMAGE_H_
+#define _OMAPIMAGE_H_
+
+struct ch_toc {
+	uint32_t section_offset;
+	uint32_t section_size;
+	uint8_t unused[12];
+	uint8_t section_name[12];
+};
+
+struct ch_settings {
+	uint32_t section_key;
+	uint8_t valid;
+	uint8_t version;
+	uint16_t reserved;
+	uint32_t flags;
+};
+
+struct gp_header {
+	uint32_t size;
+	uint32_t load_addr;
+};
+
+#define KEY_CHSETTINGS 0xC0C0C0C1
+#endif /* _OMAPIMAGE_H_ */
diff --git a/marvell/uboot/tools/os_support.c b/marvell/uboot/tools/os_support.c
new file mode 100644
index 0000000..f7651d0
--- /dev/null
+++ b/marvell/uboot/tools/os_support.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2009 Extreme Engineering Solutions, Inc.
+ *
+ * SPDX-License-Identifier:	LGPL-2.0+
+ */
+
+/*
+ * Include additional files required for supporting different operating systems
+ */
+#include "compiler.h"
+#ifdef __MINGW32__
+#include "mingw_support.c"
+#endif
+#if defined(__APPLE__) && __DARWIN_C_LEVEL < 200809L
+#include "getline.c"
+#endif
diff --git a/marvell/uboot/tools/os_support.h b/marvell/uboot/tools/os_support.h
new file mode 100644
index 0000000..695ffcf
--- /dev/null
+++ b/marvell/uboot/tools/os_support.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2009 Extreme Engineering Solutions, Inc.
+ *
+ * SPDX-License-Identifier:	LGPL-2.0+
+ */
+
+#ifndef __OS_SUPPORT_H_
+#define __OS_SUPPORT_H_
+
+#include "compiler.h"
+
+/*
+ * Include additional files required for supporting different operating systems
+ */
+#ifdef __MINGW32__
+#include "mingw_support.h"
+#endif
+
+#if defined(__APPLE__) && __DARWIN_C_LEVEL < 200809L
+#include "getline.h"
+#endif
+
+#endif /* __OS_SUPPORT_H_ */
diff --git a/marvell/uboot/tools/palmtreo680/flash_u-boot.c b/marvell/uboot/tools/palmtreo680/flash_u-boot.c
new file mode 100644
index 0000000..3d8296f
--- /dev/null
+++ b/marvell/uboot/tools/palmtreo680/flash_u-boot.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ *
+ *
+ * This is a userspace Linux utility that, when run on the Treo 680, will
+ * program u-boot to flash.  The docg4 driver *must* be loaded with the
+ * reliable_mode and ignore_badblocks parameters enabled:
+ *
+ *        modprobe docg4 ignore_badblocks=1 reliable_mode=1
+ *
+ * This utility writes the concatenated spl + u-boot image to the start of the
+ * mtd device in the format expected by the IPL/SPL.  The image file and mtd
+ * device node are passed to the utility as arguments.  The blocks must have
+ * been erased beforehand.
+ *
+ * When you compile this, note that it links to libmtd from mtd-utils, so ensure
+ * that your include and lib paths include this.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <mtd/mtd-user.h>
+#include "libmtd.h"
+
+#define RELIABLE_BLOCKSIZE  0x10000 /* block capacity in reliable mode */
+#define STANDARD_BLOCKSIZE  0x40000 /* block capacity in normal mode */
+#define PAGESIZE 512
+#define PAGES_PER_BLOCK 512
+#define OOBSIZE 7		/* available to user (16 total) */
+
+uint8_t ff_oob[OOBSIZE] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+/* this is the magic number the IPL looks for (ASCII "BIPO") */
+uint8_t page0_oob[OOBSIZE] = {'B', 'I', 'P', 'O', 0xff, 0xff, 0xff};
+
+int main(int argc, char * const argv[])
+{
+	int devfd, datafd, num_blocks, block;
+	off_t file_size;
+	libmtd_t mtd_desc;
+	struct mtd_dev_info devinfo;
+	uint8_t *blockbuf;
+	char response[8];
+
+	if (argc != 3) {
+		printf("usage: %s <image file> <mtd dev node>\n", argv[0]);
+		return -EINVAL;
+	}
+
+	mtd_desc = libmtd_open();
+	if (mtd_desc == NULL) {
+		int errsv = errno;
+		fprintf(stderr, "can't initialize libmtd\n");
+		return -errsv;
+	}
+
+	/* open the spl image file and mtd device */
+	datafd = open(argv[1], O_RDONLY);
+	if (datafd == -1) {
+		int errsv = errno;
+		perror(argv[1]);
+		return -errsv;
+	}
+	devfd = open(argv[2], O_WRONLY);
+	if (devfd == -1) {
+		int errsv = errno;
+		perror(argv[2]);
+		return -errsv;
+	}
+	if (mtd_get_dev_info(mtd_desc, argv[2], &devinfo) < 0) {
+		int errsv = errno;
+		perror(argv[2]);
+		return -errsv;
+	}
+
+	/* determine the number of blocks needed by the image */
+	file_size = lseek(datafd, 0, SEEK_END);
+	if (file_size == (off_t)-1) {
+		int errsv = errno;
+		perror("lseek");
+		return -errsv;
+	}
+	num_blocks = (file_size + RELIABLE_BLOCKSIZE - 1) / RELIABLE_BLOCKSIZE;
+	file_size = lseek(datafd, 0, SEEK_SET);
+	if (file_size == (off_t)-1) {
+		int errsv = errno;
+		perror("lseek");
+		return -errsv;
+	}
+	printf("The mtd partition contains %d blocks\n", devinfo.eb_cnt);
+	printf("U-boot will occupy %d blocks\n", num_blocks);
+	if (num_blocks > devinfo.eb_cnt) {
+		fprintf(stderr, "Insufficient blocks on partition\n");
+		return -EINVAL;
+	}
+
+	printf("IMPORTANT: These blocks must be in an erased state!\n");
+	printf("Do you want to proceed?\n");
+	scanf("%s", response);
+	if ((response[0] != 'y') && (response[0] != 'Y')) {
+		printf("Exiting\n");
+		close(devfd);
+		close(datafd);
+		return 0;
+	}
+
+	blockbuf = calloc(RELIABLE_BLOCKSIZE, 1);
+	if (blockbuf == NULL) {
+		int errsv = errno;
+		perror("calloc");
+		return -errsv;
+	}
+
+	for (block = 0; block < num_blocks; block++) {
+		int ofs, page;
+		uint8_t *pagebuf = blockbuf, *buf = blockbuf;
+		uint8_t *oobbuf = page0_oob; /* magic num in oob of 1st page */
+		size_t len = RELIABLE_BLOCKSIZE;
+		int ret;
+
+		/* read data for one block from file */
+		while (len) {
+			ssize_t read_ret = read(datafd, buf, len);
+			if (read_ret == -1) {
+				int errsv = errno;
+				if (errno == EINTR)
+					continue;
+				perror("read");
+				return -errsv;
+			} else if (read_ret == 0) {
+				break; /* EOF */
+			}
+			len -= read_ret;
+			buf += read_ret;
+		}
+
+		printf("Block %d: writing\r", block + 1);
+		fflush(stdout);
+
+		for (page = 0, ofs = 0;
+		     page < PAGES_PER_BLOCK;
+		     page++, ofs += PAGESIZE) {
+			if (page & 0x04)  /* Odd-numbered 2k page */
+				continue; /* skipped in reliable mode */
+
+			ret = mtd_write(mtd_desc, &devinfo, devfd, block, ofs,
+					pagebuf, PAGESIZE, oobbuf, OOBSIZE,
+					MTD_OPS_PLACE_OOB);
+			if (ret) {
+				fprintf(stderr,
+					"\nmtd_write returned %d on block %d, ofs %x\n",
+					ret, block + 1, ofs);
+				return -EIO;
+			}
+			oobbuf = ff_oob;  /* oob for subsequent pages */
+
+			if (page & 0x01)  /* odd-numbered subpage */
+				pagebuf += PAGESIZE;
+		}
+	}
+
+	printf("\nDone\n");
+
+	close(devfd);
+	close(datafd);
+	free(blockbuf);
+	return 0;
+}
diff --git a/marvell/uboot/tools/patman/.gitignore b/marvell/uboot/tools/patman/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/marvell/uboot/tools/patman/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/marvell/uboot/tools/patman/README b/marvell/uboot/tools/patman/README
new file mode 100644
index 0000000..59f1776
--- /dev/null
+++ b/marvell/uboot/tools/patman/README
@@ -0,0 +1,464 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+What is this?
+=============
+
+This tool is a Python script which:
+- Creates patch directly from your branch
+- Cleans them up by removing unwanted tags
+- Inserts a cover letter with change lists
+- Runs the patches through checkpatch.pl and its own checks
+- Optionally emails them out to selected people
+
+It is intended to automate patch creation and make it a less
+error-prone process. It is useful for U-Boot and Linux work so far,
+since it uses the checkpatch.pl script.
+
+It is configured almost entirely by tags it finds in your commits.
+This means that you can work on a number of different branches at
+once, and keep the settings with each branch rather than having to
+git format-patch, git send-email, etc. with the correct parameters
+each time. So for example if you put:
+
+Series-to: fred.blogs@napier.co.nz
+
+in one of your commits, the series will be sent there.
+
+In Linux this will also call get_maintainer.pl on each of your
+patches automatically.
+
+
+How to use this tool
+====================
+
+This tool requires a certain way of working:
+
+- Maintain a number of branches, one for each patch series you are
+working on
+- Add tags into the commits within each branch to indicate where the
+series should be sent, cover letter, version, etc. Most of these are
+normally in the top commit so it is easy to change them with 'git
+commit --amend'
+- Each branch tracks the upstream branch, so that this script can
+automatically determine the number of commits in it (optional)
+- Check out a branch, and run this script to create and send out your
+patches. Weeks later, change the patches and repeat, knowing that you
+will get a consistent result each time.
+
+
+How to configure it
+===================
+
+For most cases of using patman for U-Boot development, patman will
+locate and use the file 'doc/git-mailrc' in your U-Boot directory.
+This contains most of the aliases you will need.
+
+For Linux the 'scripts/get_maintainer.pl' handles figuring out where
+to send patches pretty well.
+
+During the first run patman creates a config file for you by taking the default
+user name and email address from the global .gitconfig file.
+
+To add your own, create a file ~/.patman like this:
+
+>>>>
+# patman alias file
+
+[alias]
+me: Simon Glass <sjg@chromium.org>
+
+u-boot: U-Boot Mailing List <u-boot@lists.denx.de>
+wolfgang: Wolfgang Denk <wd@denx.de>
+others: Mike Frysinger <vapier@gentoo.org>, Fred Bloggs <f.bloggs@napier.net>
+
+<<<<
+
+Aliases are recursive.
+
+The checkpatch.pl in the U-Boot tools/ subdirectory will be located and
+used. Failing that you can put it into your path or ~/bin/checkpatch.pl
+
+
+If you want to change the defaults for patman's command-line arguments,
+you can add a [settings] section to your .patman file.  This can be used
+for any command line option by referring to the "dest" for the option in
+patman.py.  For reference, the useful ones (at the moment) shown below
+(all with the non-default setting):
+
+>>>
+
+[settings]
+ignore_errors: True
+process_tags: False
+verbose: True
+
+<<<
+
+
+If you want to adjust settings (or aliases) that affect just a single
+project you can add a section that looks like [project_settings] or
+[project_alias].  If you want to use tags for your linux work, you could
+do:
+
+>>>
+
+[linux_settings]
+process_tags: True
+
+<<<
+
+
+How to run it
+=============
+
+First do a dry run:
+
+$ ./tools/patman/patman -n
+
+If it can't detect the upstream branch, try telling it how many patches
+there are in your series:
+
+$ ./tools/patman/patman -n -c5
+
+This will create patch files in your current directory and tell you who
+it is thinking of sending them to. Take a look at the patch files.
+
+$ ./tools/patman/patman -n -c5 -s1
+
+Similar to the above, but skip the first commit and take the next 5. This
+is useful if your top commit is for setting up testing.
+
+
+How to add tags
+===============
+
+To make this script useful you must add tags like the following into any
+commit. Most can only appear once in the whole series.
+
+Series-to: email / alias
+	Email address / alias to send patch series to (you can add this
+	multiple times)
+
+Series-cc: email / alias, ...
+	Email address / alias to Cc patch series to (you can add this
+	multiple times)
+
+Series-version: n
+	Sets the version number of this patch series
+
+Series-prefix: prefix
+	Sets the subject prefix. Normally empty but it can be RFC for
+	RFC patches, or RESEND if you are being ignored.
+
+Series-name: name
+	Sets the name of the series. You don't need to have a name, and
+	patman does not yet use it, but it is convenient to put the branch
+	name here to help you keep track of multiple upstreaming efforts.
+
+Cover-letter:
+This is the patch set title
+blah blah
+more blah blah
+END
+	Sets the cover letter contents for the series. The first line
+	will become the subject of the cover letter
+
+Cover-letter-cc: email / alias
+	Additional email addresses / aliases to send cover letter to (you
+	can add this multiple times)
+
+Series-notes:
+blah blah
+blah blah
+more blah blah
+END
+	Sets some notes for the patch series, which you don't want in
+	the commit messages, but do want to send, The notes are joined
+	together and put after the cover letter. Can appear multiple
+	times.
+
+Commit-notes:
+blah blah
+blah blah
+more blah blah
+END
+	Similar, but for a single commit (patch). These notes will appear
+	immediately below the --- cut in the patch file.
+
+ Signed-off-by: Their Name <email>
+	A sign-off is added automatically to your patches (this is
+	probably a bug). If you put this tag in your patches, it will
+	override the default signoff that patman automatically adds.
+
+ Tested-by: Their Name <email>
+ Reviewed-by: Their Name <email>
+ Acked-by: Their Name <email>
+	These indicate that someone has tested/reviewed/acked your patch.
+	When you get this reply on the mailing list, you can add this
+	tag to the relevant commit and the script will include it when
+	you send out the next version. If 'Tested-by:' is set to
+	yourself, it will be removed. No one will believe you.
+
+Series-changes: n
+- Guinea pig moved into its cage
+- Other changes ending with a blank line
+<blank line>
+	This can appear in any commit. It lists the changes for a
+	particular version n of that commit. The change list is
+	created based on this information. Each commit gets its own
+	change list and also the whole thing is repeated in the cover
+	letter (where duplicate change lines are merged).
+
+	By adding your change lists into your commits it is easier to
+	keep track of what happened. When you amend a commit, remember
+	to update the log there and then, knowing that the script will
+	do the rest.
+
+ Cc: Their Name <email>
+	This copies a single patch to another email address.
+
+Series-process-log: sort, uniq
+	This tells patman to sort and/or uniq the change logs. It is
+	assumed that each change log entry is only a single line long.
+	Use 'sort' to sort the entries, and 'uniq' to include only
+	unique entries. If omitted, no change log processing is done.
+	Separate each tag with a comma.
+
+Various other tags are silently removed, like these Chrome OS and
+Gerrit tags:
+
+BUG=...
+TEST=...
+Change-Id:
+Review URL:
+Reviewed-on:
+Commit-xxxx: (except Commit-notes)
+
+Exercise for the reader: Try adding some tags to one of your current
+patch series and see how the patches turn out.
+
+
+Where Patches Are Sent
+======================
+
+Once the patches are created, patman sends them using git send-email. The
+whole series is sent to the recipients in Series-to: and Series-cc.
+You can Cc individual patches to other people with the Cc: tag. Tags in the
+subject are also picked up to Cc patches. For example, a commit like this:
+
+>>>>
+commit 10212537b85ff9b6e09c82045127522c0f0db981
+Author: Mike Frysinger <vapier@gentoo.org>
+Date:	Mon Nov 7 23:18:44 2011 -0500
+
+    x86: arm: add a git mailrc file for maintainers
+
+    This should make sending out e-mails to the right people easier.
+
+    Cc: sandbox, mikef, ag
+    Cc: afleming
+<<<<
+
+will create a patch which is copied to x86, arm, sandbox, mikef, ag and
+afleming.
+
+If you have a cover letter it will get sent to the union of the CC lists of
+all of the other patches. If you want to sent it to additional people you
+can add a tag:
+
+Cover-letter-cc: <list of addresses>
+
+These people will get the cover letter even if they are not on the To/Cc
+list for any of the patches.
+
+
+Example Work Flow
+=================
+
+The basic workflow is to create your commits, add some tags to the top
+commit, and type 'patman' to check and send them.
+
+Here is an example workflow for a series of 4 patches. Let's say you have
+these rather contrived patches in the following order in branch us-cmd in
+your tree where 'us' means your upstreaming activity (newest to oldest as
+output by git log --oneline):
+
+    7c7909c wip
+    89234f5 Don't include standard parser if hush is used
+    8d640a7 mmc: sparc: Stop using builtin_run_command()
+    0c859a9 Rename run_command2() to run_command()
+    a74443f sandbox: Rename run_command() to builtin_run_command()
+
+The first patch is some test things that enable your code to be compiled,
+but that you don't want to submit because there is an existing patch for it
+on the list. So you can tell patman to create and check some patches
+(skipping the first patch) with:
+
+    patman -s1 -n
+
+If you want to do all of them including the work-in-progress one, then
+(if you are tracking an upstream branch):
+
+    patman -n
+
+Let's say that patman reports an error in the second patch. Then:
+
+    git rebase -i HEAD~6
+    <change 'pick' to 'edit' in 89234f5>
+    <use editor to make code changes>
+    git add -u
+    git rebase --continue
+
+Now you have an updated patch series. To check it:
+
+    patman -s1 -n
+
+Let's say it is now clean and you want to send it. Now you need to set up
+the destination. So amend the top commit with:
+
+    git commit --amend
+
+Use your editor to add some tags, so that the whole commit message is:
+
+    The current run_command() is really only one of the options, with
+    hush providing the other. It really shouldn't be called directly
+    in case the hush parser is bring used, so rename this function to
+    better explain its purpose.
+
+    Series-to: u-boot
+    Series-cc: bfin, marex
+    Series-prefix: RFC
+    Cover-letter:
+    Unified command execution in one place
+
+    At present two parsers have similar code to execute commands. Also
+    cmd_usage() is called all over the place. This series adds a single
+    function which processes commands called cmd_process().
+    END
+
+    Change-Id: Ica71a14c1f0ecb5650f771a32fecb8d2eb9d8a17
+
+
+You want this to be an RFC and Cc the whole series to the bfin alias and
+to Marek. Two of the patches have tags (those are the bits at the front of
+the subject that say mmc: sparc: and sandbox:), so 8d640a7 will be Cc'd to
+mmc and sparc, and the last one to sandbox.
+
+Now to send the patches, take off the -n flag:
+
+   patman -s1
+
+The patches will be created, shown in your editor, and then sent along with
+the cover letter. Note that patman's tags are automatically removed so that
+people on the list don't see your secret info.
+
+Of course patches often attract comments and you need to make some updates.
+Let's say one person sent comments and you get an Acked-by: on one patch.
+Also, the patch on the list that you were waiting for has been merged,
+so you can drop your wip commit. So you resync with upstream:
+
+    git fetch origin		(or whatever upstream is called)
+    git rebase origin/master
+
+and use git rebase -i to edit the commits, dropping the wip one. You add
+the ack tag to one commit:
+
+    Acked-by: Heiko Schocher <hs@denx.de>
+
+update the Series-cc: in the top commit:
+
+    Series-cc: bfin, marex, Heiko Schocher <hs@denx.de>
+
+and remove the Series-prefix: tag since it it isn't an RFC any more. The
+series is now version two, so the series info in the top commit looks like
+this:
+
+    Series-to: u-boot
+    Series-cc: bfin, marex, Heiko Schocher <hs@denx.de>
+    Series-version: 2
+    Cover-letter:
+    ...
+
+Finally, you need to add a change log to the two commits you changed. You
+add change logs to each individual commit where the changes happened, like
+this:
+
+    Series-changes: 2
+    - Updated the command decoder to reduce code size
+    - Wound the torque propounder up a little more
+
+(note the blank line at the end of the list)
+
+When you run patman it will collect all the change logs from the different
+commits and combine them into the cover letter, if you have one. So finally
+you have a new series of commits:
+
+    faeb973 Don't include standard parser if hush is used
+    1b2f2fe mmc: sparc: Stop using builtin_run_command()
+    cfbe330 Rename run_command2() to run_command()
+    0682677 sandbox: Rename run_command() to builtin_run_command()
+
+so to send them:
+
+    patman
+
+and it will create and send the version 2 series.
+
+General points:
+
+1. When you change back to the us-cmd branch days or weeks later all your
+information is still there, safely stored in the commits. You don't need
+to remember what version you are up to, who you sent the last lot of patches
+to, or anything about the change logs.
+
+2. If you put tags in the subject, patman will Cc the maintainers
+automatically in many cases.
+
+3. If you want to keep the commits from each series you sent so that you can
+compare change and see what you did, you can either create a new branch for
+each version, or just tag the branch before you start changing it:
+
+    git tag sent/us-cmd-rfc
+    ...later...
+    git tag sent/us-cmd-v2
+
+4. If you want to modify the patches a little before sending, you can do
+this in your editor, but be careful!
+
+5. If you want to run git send-email yourself, use the -n flag which will
+print out the command line patman would have used.
+
+6. It is a good idea to add the change log info as you change the commit,
+not later when you can't remember which patch you changed. You can always
+go back and change or remove logs from commits.
+
+
+Other thoughts
+==============
+
+This script has been split into sensible files but still needs work.
+Most of these are indicated by a TODO in the code.
+
+It would be nice if this could handle the In-reply-to side of things.
+
+The tests are incomplete, as is customary. Use the --test flag to run them,
+and make sure you are in the tools/patman directory first:
+
+    $ cd /path/to/u-boot
+    $ cd tools/patman
+    $ ./patman --test
+
+Error handling doesn't always produce friendly error messages - e.g.
+putting an incorrect tag in a commit may provide a confusing message.
+
+There might be a few other features not mentioned in this README. They
+might be bugs. In particular, tags are case sensitive which is probably
+a bad thing.
+
+
+Simon Glass <sjg@chromium.org>
+v1, v2, 19-Oct-11
+revised v3 24-Nov-11
diff --git a/marvell/uboot/tools/patman/checkpatch.py b/marvell/uboot/tools/patman/checkpatch.py
new file mode 100644
index 0000000..0d4e935
--- /dev/null
+++ b/marvell/uboot/tools/patman/checkpatch.py
@@ -0,0 +1,174 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import collections
+import command
+import gitutil
+import os
+import re
+import sys
+import terminal
+
+def FindCheckPatch():
+    top_level = gitutil.GetTopLevel()
+    try_list = [
+        os.getcwd(),
+        os.path.join(os.getcwd(), '..', '..'),
+        os.path.join(top_level, 'tools'),
+        os.path.join(top_level, 'scripts'),
+        '%s/bin' % os.getenv('HOME'),
+        ]
+    # Look in current dir
+    for path in try_list:
+        fname = os.path.join(path, 'checkpatch.pl')
+        if os.path.isfile(fname):
+            return fname
+
+    # Look upwwards for a Chrome OS tree
+    while not os.path.ismount(path):
+        fname = os.path.join(path, 'src', 'third_party', 'kernel', 'files',
+                'scripts', 'checkpatch.pl')
+        if os.path.isfile(fname):
+            return fname
+        path = os.path.dirname(path)
+
+    print >> sys.stderr, ('Cannot find checkpatch.pl - please put it in your ' +
+                '~/bin directory or use --no-check')
+    sys.exit(1)
+
+def CheckPatch(fname, verbose=False):
+    """Run checkpatch.pl on a file.
+
+    Returns:
+        namedtuple containing:
+            ok: False=failure, True=ok
+            problems: List of problems, each a dict:
+                'type'; error or warning
+                'msg': text message
+                'file' : filename
+                'line': line number
+            errors: Number of errors
+            warnings: Number of warnings
+            checks: Number of checks
+            lines: Number of lines
+            stdout: Full output of checkpatch
+    """
+    fields = ['ok', 'problems', 'errors', 'warnings', 'checks', 'lines',
+              'stdout']
+    result = collections.namedtuple('CheckPatchResult', fields)
+    result.ok = False
+    result.errors, result.warning, result.checks = 0, 0, 0
+    result.lines = 0
+    result.problems = []
+    chk = FindCheckPatch()
+    item = {}
+    result.stdout = command.Output(chk, '--no-tree', fname)
+    #pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+    #stdout, stderr = pipe.communicate()
+
+    # total: 0 errors, 0 warnings, 159 lines checked
+    # or:
+    # total: 0 errors, 2 warnings, 7 checks, 473 lines checked
+    re_stats = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)')
+    re_stats_full = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)'
+                               ' checks, (\d+)')
+    re_ok = re.compile('.*has no obvious style problems')
+    re_bad = re.compile('.*has style problems, please review')
+    re_error = re.compile('ERROR: (.*)')
+    re_warning = re.compile('WARNING: (.*)')
+    re_check = re.compile('CHECK: (.*)')
+    re_file = re.compile('#\d+: FILE: ([^:]*):(\d+):')
+
+    for line in result.stdout.splitlines():
+        if verbose:
+            print line
+
+        # A blank line indicates the end of a message
+        if not line and item:
+            result.problems.append(item)
+            item = {}
+        match = re_stats_full.match(line)
+        if not match:
+            match = re_stats.match(line)
+        if match:
+            result.errors = int(match.group(1))
+            result.warnings = int(match.group(2))
+            if len(match.groups()) == 4:
+                result.checks = int(match.group(3))
+                result.lines = int(match.group(4))
+            else:
+                result.lines = int(match.group(3))
+        elif re_ok.match(line):
+            result.ok = True
+        elif re_bad.match(line):
+            result.ok = False
+        err_match = re_error.match(line)
+        warn_match = re_warning.match(line)
+        file_match = re_file.match(line)
+        check_match = re_check.match(line)
+        if err_match:
+            item['msg'] = err_match.group(1)
+            item['type'] = 'error'
+        elif warn_match:
+            item['msg'] = warn_match.group(1)
+            item['type'] = 'warning'
+        elif check_match:
+            item['msg'] = check_match.group(1)
+            item['type'] = 'check'
+        elif file_match:
+            item['file'] = file_match.group(1)
+            item['line'] = int(file_match.group(2))
+
+    return result
+
+def GetWarningMsg(col, msg_type, fname, line, msg):
+    '''Create a message for a given file/line
+
+    Args:
+        msg_type: Message type ('error' or 'warning')
+        fname: Filename which reports the problem
+        line: Line number where it was noticed
+        msg: Message to report
+    '''
+    if msg_type == 'warning':
+        msg_type = col.Color(col.YELLOW, msg_type)
+    elif msg_type == 'error':
+        msg_type = col.Color(col.RED, msg_type)
+    elif msg_type == 'check':
+        msg_type = col.Color(col.MAGENTA, msg_type)
+    return '%s: %s,%d: %s' % (msg_type, fname, line, msg)
+
+def CheckPatches(verbose, args):
+    '''Run the checkpatch.pl script on each patch'''
+    error_count, warning_count, check_count = 0, 0, 0
+    col = terminal.Color()
+
+    for fname in args:
+        result = CheckPatch(fname, verbose)
+        if not result.ok:
+            error_count += result.errors
+            warning_count += result.warnings
+            check_count += result.checks
+            print '%d errors, %d warnings, %d checks for %s:' % (result.errors,
+                    result.warnings, result.checks, col.Color(col.BLUE, fname))
+            if (len(result.problems) != result.errors + result.warnings +
+                    result.checks):
+                print "Internal error: some problems lost"
+            for item in result.problems:
+                print GetWarningMsg(col, item.get('type', '<unknown>'),
+                        item.get('file', '<unknown>'),
+                        item.get('line', 0), item.get('msg', 'message'))
+            print
+            #print stdout
+    if error_count or warning_count or check_count:
+        str = 'checkpatch.pl found %d error(s), %d warning(s), %d checks(s)'
+        color = col.GREEN
+        if warning_count:
+            color = col.YELLOW
+        if error_count:
+            color = col.RED
+        print col.Color(color, str % (error_count, warning_count, check_count))
+        return False
+    return True
diff --git a/marvell/uboot/tools/patman/command.py b/marvell/uboot/tools/patman/command.py
new file mode 100644
index 0000000..449d3d0
--- /dev/null
+++ b/marvell/uboot/tools/patman/command.py
@@ -0,0 +1,101 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import os
+import cros_subprocess
+
+"""Shell command ease-ups for Python."""
+
+class CommandResult:
+    """A class which captures the result of executing a command.
+
+    Members:
+        stdout: stdout obtained from command, as a string
+        stderr: stderr obtained from command, as a string
+        return_code: Return code from command
+        exception: Exception received, or None if all ok
+    """
+    def __init__(self):
+        self.stdout = None
+        self.stderr = None
+        self.return_code = None
+        self.exception = None
+
+
+def RunPipe(pipe_list, infile=None, outfile=None,
+            capture=False, capture_stderr=False, oneline=False,
+            raise_on_error=True, cwd=None, **kwargs):
+    """
+    Perform a command pipeline, with optional input/output filenames.
+
+    Args:
+        pipe_list: List of command lines to execute. Each command line is
+            piped into the next, and is itself a list of strings. For
+            example [ ['ls', '.git'] ['wc'] ] will pipe the output of
+            'ls .git' into 'wc'.
+        infile: File to provide stdin to the pipeline
+        outfile: File to store stdout
+        capture: True to capture output
+        capture_stderr: True to capture stderr
+        oneline: True to strip newline chars from output
+        kwargs: Additional keyword arguments to cros_subprocess.Popen()
+    Returns:
+        CommandResult object
+    """
+    result = CommandResult()
+    last_pipe = None
+    pipeline = list(pipe_list)
+    user_pipestr =  '|'.join([' '.join(pipe) for pipe in pipe_list])
+    while pipeline:
+        cmd = pipeline.pop(0)
+        if last_pipe is not None:
+            kwargs['stdin'] = last_pipe.stdout
+        elif infile:
+            kwargs['stdin'] = open(infile, 'rb')
+        if pipeline or capture:
+            kwargs['stdout'] = cros_subprocess.PIPE
+        elif outfile:
+            kwargs['stdout'] = open(outfile, 'wb')
+        if capture_stderr:
+            kwargs['stderr'] = cros_subprocess.PIPE
+
+        try:
+            last_pipe = cros_subprocess.Popen(cmd, cwd=cwd, **kwargs)
+        except Exception, err:
+            result.exception = err
+            if raise_on_error:
+                raise Exception("Error running '%s': %s" % (user_pipestr, str))
+            result.return_code = 255
+            return result
+
+    if capture:
+        result.stdout, result.stderr, result.combined = (
+                last_pipe.CommunicateFilter(None))
+        if result.stdout and oneline:
+            result.output = result.stdout.rstrip('\r\n')
+        result.return_code = last_pipe.wait()
+    else:
+        result.return_code = os.waitpid(last_pipe.pid, 0)[1]
+    if raise_on_error and result.return_code:
+        raise Exception("Error running '%s'" % user_pipestr)
+    return result
+
+def Output(*cmd):
+    return RunPipe([cmd], capture=True, raise_on_error=False).stdout
+
+def OutputOneLine(*cmd, **kwargs):
+    raise_on_error = kwargs.pop('raise_on_error', True)
+    return (RunPipe([cmd], capture=True, oneline=True,
+            raise_on_error=raise_on_error,
+            **kwargs).stdout.strip())
+
+def Run(*cmd, **kwargs):
+    return RunPipe([cmd], **kwargs).stdout
+
+def RunList(cmd):
+    return RunPipe([cmd], capture=True).stdout
+
+def StopAll():
+    cros_subprocess.stay_alive = False
diff --git a/marvell/uboot/tools/patman/commit.py b/marvell/uboot/tools/patman/commit.py
new file mode 100644
index 0000000..89cce7f
--- /dev/null
+++ b/marvell/uboot/tools/patman/commit.py
@@ -0,0 +1,74 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import re
+
+# Separates a tag: at the beginning of the subject from the rest of it
+re_subject_tag = re.compile('([^:\s]*):\s*(.*)')
+
+class Commit:
+    """Holds information about a single commit/patch in the series.
+
+    Args:
+        hash: Commit hash (as a string)
+
+    Variables:
+        hash: Commit hash
+        subject: Subject line
+        tags: List of maintainer tag strings
+        changes: Dict containing a list of changes (single line strings).
+            The dict is indexed by change version (an integer)
+        cc_list: List of people to aliases/emails to cc on this commit
+        notes: List of lines in the commit (not series) notes
+    """
+    def __init__(self, hash):
+        self.hash = hash
+        self.subject = None
+        self.tags = []
+        self.changes = {}
+        self.cc_list = []
+        self.notes = []
+
+    def AddChange(self, version, info):
+        """Add a new change line to the change list for a version.
+
+        Args:
+            version: Patch set version (integer: 1, 2, 3)
+            info: Description of change in this version
+        """
+        if not self.changes.get(version):
+            self.changes[version] = []
+        self.changes[version].append(info)
+
+    def CheckTags(self):
+        """Create a list of subject tags in the commit
+
+        Subject tags look like this:
+
+            propounder: fort: Change the widget to propound correctly
+
+        Here the tags are propounder and fort. Multiple tags are supported.
+        The list is updated in self.tag.
+
+        Returns:
+            None if ok, else the name of a tag with no email alias
+        """
+        str = self.subject
+        m = True
+        while m:
+            m = re_subject_tag.match(str)
+            if m:
+                tag = m.group(1)
+                self.tags.append(tag)
+                str = m.group(2)
+        return None
+
+    def AddCc(self, cc_list):
+        """Add a list of people to Cc when we send this patch.
+
+        Args:
+            cc_list:    List of aliases or email addresses
+        """
+        self.cc_list += cc_list
diff --git a/marvell/uboot/tools/patman/cros_subprocess.py b/marvell/uboot/tools/patman/cros_subprocess.py
new file mode 100644
index 0000000..0fc4a06
--- /dev/null
+++ b/marvell/uboot/tools/patman/cros_subprocess.py
@@ -0,0 +1,397 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Copyright (c) 2003-2005 by Peter Astrand <astrand@lysator.liu.se>
+# Licensed to PSF under a Contributor Agreement.
+# See http://www.python.org/2.4/license for licensing details.
+
+"""Subprocress execution
+
+This module holds a subclass of subprocess.Popen with our own required
+features, mainly that we get access to the subprocess output while it
+is running rather than just at the end. This makes it easiler to show
+progress information and filter output in real time.
+"""
+
+import errno
+import os
+import pty
+import select
+import subprocess
+import sys
+import unittest
+
+
+# Import these here so the caller does not need to import subprocess also.
+PIPE = subprocess.PIPE
+STDOUT = subprocess.STDOUT
+PIPE_PTY = -3     # Pipe output through a pty
+stay_alive = True
+
+
+class Popen(subprocess.Popen):
+    """Like subprocess.Popen with ptys and incremental output
+
+    This class deals with running a child process and filtering its output on
+    both stdout and stderr while it is running. We do this so we can monitor
+    progress, and possibly relay the output to the user if requested.
+
+    The class is similar to subprocess.Popen, the equivalent is something like:
+
+        Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+    But this class has many fewer features, and two enhancement:
+
+    1. Rather than getting the output data only at the end, this class sends it
+         to a provided operation as it arrives.
+    2. We use pseudo terminals so that the child will hopefully flush its output
+         to us as soon as it is produced, rather than waiting for the end of a
+         line.
+
+    Use CommunicateFilter() to handle output from the subprocess.
+
+    """
+
+    def __init__(self, args, stdin=None, stdout=PIPE_PTY, stderr=PIPE_PTY,
+                 shell=False, cwd=None, env=None, **kwargs):
+        """Cut-down constructor
+
+        Args:
+            args: Program and arguments for subprocess to execute.
+            stdin: See subprocess.Popen()
+            stdout: See subprocess.Popen(), except that we support the sentinel
+                    value of cros_subprocess.PIPE_PTY.
+            stderr: See subprocess.Popen(), except that we support the sentinel
+                    value of cros_subprocess.PIPE_PTY.
+            shell: See subprocess.Popen()
+            cwd: Working directory to change to for subprocess, or None if none.
+            env: Environment to use for this subprocess, or None to inherit parent.
+            kwargs: No other arguments are supported at the moment.    Passing other
+                    arguments will cause a ValueError to be raised.
+        """
+        stdout_pty = None
+        stderr_pty = None
+
+        if stdout == PIPE_PTY:
+            stdout_pty = pty.openpty()
+            stdout = os.fdopen(stdout_pty[1])
+        if stderr == PIPE_PTY:
+            stderr_pty = pty.openpty()
+            stderr = os.fdopen(stderr_pty[1])
+
+        super(Popen, self).__init__(args, stdin=stdin,
+                stdout=stdout, stderr=stderr, shell=shell, cwd=cwd, env=env,
+                **kwargs)
+
+        # If we're on a PTY, we passed the slave half of the PTY to the subprocess.
+        # We want to use the master half on our end from now on.    Setting this here
+        # does make some assumptions about the implementation of subprocess, but
+        # those assumptions are pretty minor.
+
+        # Note that if stderr is STDOUT, then self.stderr will be set to None by
+        # this constructor.
+        if stdout_pty is not None:
+            self.stdout = os.fdopen(stdout_pty[0])
+        if stderr_pty is not None:
+            self.stderr = os.fdopen(stderr_pty[0])
+
+        # Insist that unit tests exist for other arguments we don't support.
+        if kwargs:
+            raise ValueError("Unit tests do not test extra args - please add tests")
+
+    def CommunicateFilter(self, output):
+        """Interact with process: Read data from stdout and stderr.
+
+        This method runs until end-of-file is reached, then waits for the
+        subprocess to terminate.
+
+        The output function is sent all output from the subprocess and must be
+        defined like this:
+
+            def Output([self,] stream, data)
+            Args:
+                stream: the stream the output was received on, which will be
+                        sys.stdout or sys.stderr.
+                data: a string containing the data
+
+        Note: The data read is buffered in memory, so do not use this
+        method if the data size is large or unlimited.
+
+        Args:
+            output: Function to call with each fragment of output.
+
+        Returns:
+            A tuple (stdout, stderr, combined) which is the data received on
+            stdout, stderr and the combined data (interleaved stdout and stderr).
+
+            Note that the interleaved output will only be sensible if you have
+            set both stdout and stderr to PIPE or PIPE_PTY. Even then it depends on
+            the timing of the output in the subprocess. If a subprocess flips
+            between stdout and stderr quickly in succession, by the time we come to
+            read the output from each we may see several lines in each, and will read
+            all the stdout lines, then all the stderr lines. So the interleaving
+            may not be correct. In this case you might want to pass
+            stderr=cros_subprocess.STDOUT to the constructor.
+
+            This feature is still useful for subprocesses where stderr is
+            rarely used and indicates an error.
+
+            Note also that if you set stderr to STDOUT, then stderr will be empty
+            and the combined output will just be the same as stdout.
+        """
+
+        read_set = []
+        write_set = []
+        stdout = None # Return
+        stderr = None # Return
+
+        if self.stdin:
+            # Flush stdio buffer.    This might block, if the user has
+            # been writing to .stdin in an uncontrolled fashion.
+            self.stdin.flush()
+            if input:
+                write_set.append(self.stdin)
+            else:
+                self.stdin.close()
+        if self.stdout:
+            read_set.append(self.stdout)
+            stdout = []
+        if self.stderr and self.stderr != self.stdout:
+            read_set.append(self.stderr)
+            stderr = []
+        combined = []
+
+        input_offset = 0
+        while read_set or write_set:
+            try:
+                rlist, wlist, _ = select.select(read_set, write_set, [], 0.2)
+            except select.error, e:
+                if e.args[0] == errno.EINTR:
+                    continue
+                raise
+
+            if not stay_alive:
+                    self.terminate()
+
+            if self.stdin in wlist:
+                # When select has indicated that the file is writable,
+                # we can write up to PIPE_BUF bytes without risk
+                # blocking.    POSIX defines PIPE_BUF >= 512
+                chunk = input[input_offset : input_offset + 512]
+                bytes_written = os.write(self.stdin.fileno(), chunk)
+                input_offset += bytes_written
+                if input_offset >= len(input):
+                    self.stdin.close()
+                    write_set.remove(self.stdin)
+
+            if self.stdout in rlist:
+                data = ""
+                # We will get an error on read if the pty is closed
+                try:
+                    data = os.read(self.stdout.fileno(), 1024)
+                except OSError:
+                    pass
+                if data == "":
+                    self.stdout.close()
+                    read_set.remove(self.stdout)
+                else:
+                    stdout.append(data)
+                    combined.append(data)
+                    if output:
+                        output(sys.stdout, data)
+            if self.stderr in rlist:
+                data = ""
+                # We will get an error on read if the pty is closed
+                try:
+                    data = os.read(self.stderr.fileno(), 1024)
+                except OSError:
+                    pass
+                if data == "":
+                    self.stderr.close()
+                    read_set.remove(self.stderr)
+                else:
+                    stderr.append(data)
+                    combined.append(data)
+                    if output:
+                        output(sys.stderr, data)
+
+        # All data exchanged.    Translate lists into strings.
+        if stdout is not None:
+            stdout = ''.join(stdout)
+        else:
+            stdout = ''
+        if stderr is not None:
+            stderr = ''.join(stderr)
+        else:
+            stderr = ''
+        combined = ''.join(combined)
+
+        # Translate newlines, if requested.    We cannot let the file
+        # object do the translation: It is based on stdio, which is
+        # impossible to combine with select (unless forcing no
+        # buffering).
+        if self.universal_newlines and hasattr(file, 'newlines'):
+            if stdout:
+                stdout = self._translate_newlines(stdout)
+            if stderr:
+                stderr = self._translate_newlines(stderr)
+
+        self.wait()
+        return (stdout, stderr, combined)
+
+
+# Just being a unittest.TestCase gives us 14 public methods.    Unless we
+# disable this, we can only have 6 tests in a TestCase.    That's not enough.
+#
+# pylint: disable=R0904
+
+class TestSubprocess(unittest.TestCase):
+    """Our simple unit test for this module"""
+
+    class MyOperation:
+        """Provides a operation that we can pass to Popen"""
+        def __init__(self, input_to_send=None):
+            """Constructor to set up the operation and possible input.
+
+            Args:
+                input_to_send: a text string to send when we first get input. We will
+                    add \r\n to the string.
+            """
+            self.stdout_data = ''
+            self.stderr_data = ''
+            self.combined_data = ''
+            self.stdin_pipe = None
+            self._input_to_send = input_to_send
+            if input_to_send:
+                pipe = os.pipe()
+                self.stdin_read_pipe = pipe[0]
+                self._stdin_write_pipe = os.fdopen(pipe[1], 'w')
+
+        def Output(self, stream, data):
+            """Output handler for Popen. Stores the data for later comparison"""
+            if stream == sys.stdout:
+                self.stdout_data += data
+            if stream == sys.stderr:
+                self.stderr_data += data
+            self.combined_data += data
+
+            # Output the input string if we have one.
+            if self._input_to_send:
+                self._stdin_write_pipe.write(self._input_to_send + '\r\n')
+                self._stdin_write_pipe.flush()
+
+    def _BasicCheck(self, plist, oper):
+        """Basic checks that the output looks sane."""
+        self.assertEqual(plist[0], oper.stdout_data)
+        self.assertEqual(plist[1], oper.stderr_data)
+        self.assertEqual(plist[2], oper.combined_data)
+
+        # The total length of stdout and stderr should equal the combined length
+        self.assertEqual(len(plist[0]) + len(plist[1]), len(plist[2]))
+
+    def test_simple(self):
+        """Simple redirection: Get process list"""
+        oper = TestSubprocess.MyOperation()
+        plist = Popen(['ps']).CommunicateFilter(oper.Output)
+        self._BasicCheck(plist, oper)
+
+    def test_stderr(self):
+        """Check stdout and stderr"""
+        oper = TestSubprocess.MyOperation()
+        cmd = 'echo fred >/dev/stderr && false || echo bad'
+        plist = Popen([cmd], shell=True).CommunicateFilter(oper.Output)
+        self._BasicCheck(plist, oper)
+        self.assertEqual(plist [0], 'bad\r\n')
+        self.assertEqual(plist [1], 'fred\r\n')
+
+    def test_shell(self):
+        """Check with and without shell works"""
+        oper = TestSubprocess.MyOperation()
+        cmd = 'echo test >/dev/stderr'
+        self.assertRaises(OSError, Popen, [cmd], shell=False)
+        plist = Popen([cmd], shell=True).CommunicateFilter(oper.Output)
+        self._BasicCheck(plist, oper)
+        self.assertEqual(len(plist [0]), 0)
+        self.assertEqual(plist [1], 'test\r\n')
+
+    def test_list_args(self):
+        """Check with and without shell works using list arguments"""
+        oper = TestSubprocess.MyOperation()
+        cmd = ['echo', 'test', '>/dev/stderr']
+        plist = Popen(cmd, shell=False).CommunicateFilter(oper.Output)
+        self._BasicCheck(plist, oper)
+        self.assertEqual(plist [0], ' '.join(cmd[1:]) + '\r\n')
+        self.assertEqual(len(plist [1]), 0)
+
+        oper = TestSubprocess.MyOperation()
+
+        # this should be interpreted as 'echo' with the other args dropped
+        cmd = ['echo', 'test', '>/dev/stderr']
+        plist = Popen(cmd, shell=True).CommunicateFilter(oper.Output)
+        self._BasicCheck(plist, oper)
+        self.assertEqual(plist [0], '\r\n')
+
+    def test_cwd(self):
+        """Check we can change directory"""
+        for shell in (False, True):
+            oper = TestSubprocess.MyOperation()
+            plist = Popen('pwd', shell=shell, cwd='/tmp').CommunicateFilter(oper.Output)
+            self._BasicCheck(plist, oper)
+            self.assertEqual(plist [0], '/tmp\r\n')
+
+    def test_env(self):
+        """Check we can change environment"""
+        for add in (False, True):
+            oper = TestSubprocess.MyOperation()
+            env = os.environ
+            if add:
+                env ['FRED'] = 'fred'
+            cmd = 'echo $FRED'
+            plist = Popen(cmd, shell=True, env=env).CommunicateFilter(oper.Output)
+            self._BasicCheck(plist, oper)
+            self.assertEqual(plist [0], add and 'fred\r\n' or '\r\n')
+
+    def test_extra_args(self):
+        """Check we can't add extra arguments"""
+        self.assertRaises(ValueError, Popen, 'true', close_fds=False)
+
+    def test_basic_input(self):
+        """Check that incremental input works
+
+        We set up a subprocess which will prompt for name. When we see this prompt
+        we send the name as input to the process. It should then print the name
+        properly to stdout.
+        """
+        oper = TestSubprocess.MyOperation('Flash')
+        prompt = 'What is your name?: '
+        cmd = 'echo -n "%s"; read name; echo Hello $name' % prompt
+        plist = Popen([cmd], stdin=oper.stdin_read_pipe,
+                shell=True).CommunicateFilter(oper.Output)
+        self._BasicCheck(plist, oper)
+        self.assertEqual(len(plist [1]), 0)
+        self.assertEqual(plist [0], prompt + 'Hello Flash\r\r\n')
+
+    def test_isatty(self):
+        """Check that ptys appear as terminals to the subprocess"""
+        oper = TestSubprocess.MyOperation()
+        cmd = ('if [ -t %d ]; then echo "terminal %d" >&%d; '
+                'else echo "not %d" >&%d; fi;')
+        both_cmds = ''
+        for fd in (1, 2):
+            both_cmds += cmd % (fd, fd, fd, fd, fd)
+        plist = Popen(both_cmds, shell=True).CommunicateFilter(oper.Output)
+        self._BasicCheck(plist, oper)
+        self.assertEqual(plist [0], 'terminal 1\r\n')
+        self.assertEqual(plist [1], 'terminal 2\r\n')
+
+        # Now try with PIPE and make sure it is not a terminal
+        oper = TestSubprocess.MyOperation()
+        plist = Popen(both_cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+                shell=True).CommunicateFilter(oper.Output)
+        self._BasicCheck(plist, oper)
+        self.assertEqual(plist [0], 'not 1\n')
+        self.assertEqual(plist [1], 'not 2\n')
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/marvell/uboot/tools/patman/get_maintainer.py b/marvell/uboot/tools/patman/get_maintainer.py
new file mode 100644
index 0000000..00b4939
--- /dev/null
+++ b/marvell/uboot/tools/patman/get_maintainer.py
@@ -0,0 +1,47 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import command
+import gitutil
+import os
+
+def FindGetMaintainer():
+    """Look for the get_maintainer.pl script.
+
+    Returns:
+        If the script is found we'll return a path to it; else None.
+    """
+    try_list = [
+        os.path.join(gitutil.GetTopLevel(), 'scripts'),
+        ]
+    # Look in the list
+    for path in try_list:
+        fname = os.path.join(path, 'get_maintainer.pl')
+        if os.path.isfile(fname):
+            return fname
+
+    return None
+
+def GetMaintainer(fname, verbose=False):
+    """Run get_maintainer.pl on a file if we find it.
+
+    We look for get_maintainer.pl in the 'scripts' directory at the top of
+    git.  If we find it we'll run it.  If we don't find get_maintainer.pl
+    then we fail silently.
+
+    Args:
+        fname: Path to the patch file to run get_maintainer.pl on.
+
+    Returns:
+        A list of email addresses to CC to.
+    """
+    get_maintainer = FindGetMaintainer()
+    if not get_maintainer:
+        if verbose:
+            print "WARNING: Couldn't find get_maintainer.pl"
+        return []
+
+    stdout = command.Output(get_maintainer, '--norolestats', fname)
+    return stdout.splitlines()
diff --git a/marvell/uboot/tools/patman/gitutil.py b/marvell/uboot/tools/patman/gitutil.py
new file mode 100644
index 0000000..5dcbaa3
--- /dev/null
+++ b/marvell/uboot/tools/patman/gitutil.py
@@ -0,0 +1,547 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import command
+import re
+import os
+import series
+import subprocess
+import sys
+import terminal
+
+import settings
+
+
+def CountCommitsToBranch():
+    """Returns number of commits between HEAD and the tracking branch.
+
+    This looks back to the tracking branch and works out the number of commits
+    since then.
+
+    Return:
+        Number of patches that exist on top of the branch
+    """
+    pipe = [['git', 'log', '--no-color', '--oneline', '--no-decorate',
+             '@{upstream}..'],
+            ['wc', '-l']]
+    stdout = command.RunPipe(pipe, capture=True, oneline=True).stdout
+    patch_count = int(stdout)
+    return patch_count
+
+def GetUpstream(git_dir, branch):
+    """Returns the name of the upstream for a branch
+
+    Args:
+        git_dir: Git directory containing repo
+        branch: Name of branch
+
+    Returns:
+        Name of upstream branch (e.g. 'upstream/master') or None if none
+    """
+    try:
+        remote = command.OutputOneLine('git', '--git-dir', git_dir, 'config',
+                                       'branch.%s.remote' % branch)
+        merge = command.OutputOneLine('git', '--git-dir', git_dir, 'config',
+                                      'branch.%s.merge' % branch)
+    except:
+        return None
+
+    if remote == '.':
+        return merge
+    elif remote and merge:
+        leaf = merge.split('/')[-1]
+        return '%s/%s' % (remote, leaf)
+    else:
+        raise ValueError, ("Cannot determine upstream branch for branch "
+                "'%s' remote='%s', merge='%s'" % (branch, remote, merge))
+
+
+def GetRangeInBranch(git_dir, branch, include_upstream=False):
+    """Returns an expression for the commits in the given branch.
+
+    Args:
+        git_dir: Directory containing git repo
+        branch: Name of branch
+    Return:
+        Expression in the form 'upstream..branch' which can be used to
+        access the commits. If the branch does not exist, returns None.
+    """
+    upstream = GetUpstream(git_dir, branch)
+    if not upstream:
+        return None
+    return '%s%s..%s' % (upstream, '~' if include_upstream else '', branch)
+
+def CountCommitsInBranch(git_dir, branch, include_upstream=False):
+    """Returns the number of commits in the given branch.
+
+    Args:
+        git_dir: Directory containing git repo
+        branch: Name of branch
+    Return:
+        Number of patches that exist on top of the branch, or None if the
+        branch does not exist.
+    """
+    range_expr = GetRangeInBranch(git_dir, branch, include_upstream)
+    if not range_expr:
+        return None
+    pipe = [['git', '--git-dir', git_dir, 'log', '--oneline', '--no-decorate',
+             range_expr],
+            ['wc', '-l']]
+    result = command.RunPipe(pipe, capture=True, oneline=True)
+    patch_count = int(result.stdout)
+    return patch_count
+
+def CountCommits(commit_range):
+    """Returns the number of commits in the given range.
+
+    Args:
+        commit_range: Range of commits to count (e.g. 'HEAD..base')
+    Return:
+        Number of patches that exist on top of the branch
+    """
+    pipe = [['git', 'log', '--oneline', '--no-decorate', commit_range],
+            ['wc', '-l']]
+    stdout = command.RunPipe(pipe, capture=True, oneline=True).stdout
+    patch_count = int(stdout)
+    return patch_count
+
+def Checkout(commit_hash, git_dir=None, work_tree=None, force=False):
+    """Checkout the selected commit for this build
+
+    Args:
+        commit_hash: Commit hash to check out
+    """
+    pipe = ['git']
+    if git_dir:
+        pipe.extend(['--git-dir', git_dir])
+    if work_tree:
+        pipe.extend(['--work-tree', work_tree])
+    pipe.append('checkout')
+    if force:
+        pipe.append('-f')
+    pipe.append(commit_hash)
+    result = command.RunPipe([pipe], capture=True, raise_on_error=False)
+    if result.return_code != 0:
+        raise OSError, 'git checkout (%s): %s' % (pipe, result.stderr)
+
+def Clone(git_dir, output_dir):
+    """Checkout the selected commit for this build
+
+    Args:
+        commit_hash: Commit hash to check out
+    """
+    pipe = ['git', 'clone', git_dir, '.']
+    result = command.RunPipe([pipe], capture=True, cwd=output_dir)
+    if result.return_code != 0:
+        raise OSError, 'git clone: %s' % result.stderr
+
+def Fetch(git_dir=None, work_tree=None):
+    """Fetch from the origin repo
+
+    Args:
+        commit_hash: Commit hash to check out
+    """
+    pipe = ['git']
+    if git_dir:
+        pipe.extend(['--git-dir', git_dir])
+    if work_tree:
+        pipe.extend(['--work-tree', work_tree])
+    pipe.append('fetch')
+    result = command.RunPipe([pipe], capture=True)
+    if result.return_code != 0:
+        raise OSError, 'git fetch: %s' % result.stderr
+
+def CreatePatches(start, count, series):
+    """Create a series of patches from the top of the current branch.
+
+    The patch files are written to the current directory using
+    git format-patch.
+
+    Args:
+        start: Commit to start from: 0=HEAD, 1=next one, etc.
+        count: number of commits to include
+    Return:
+        Filename of cover letter
+        List of filenames of patch files
+    """
+    if series.get('version'):
+        version = '%s ' % series['version']
+    cmd = ['git', 'format-patch', '-M', '--signoff']
+    if series.get('cover'):
+        cmd.append('--cover-letter')
+    prefix = series.GetPatchPrefix()
+    if prefix:
+        cmd += ['--subject-prefix=%s' % prefix]
+    cmd += ['HEAD~%d..HEAD~%d' % (start + count, start)]
+
+    stdout = command.RunList(cmd)
+    files = stdout.splitlines()
+
+    # We have an extra file if there is a cover letter
+    if series.get('cover'):
+       return files[0], files[1:]
+    else:
+       return None, files
+
+def ApplyPatch(verbose, fname):
+    """Apply a patch with git am to test it
+
+    TODO: Convert these to use command, with stderr option
+
+    Args:
+        fname: filename of patch file to apply
+    """
+    cmd = ['git', 'am', fname]
+    pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE)
+    stdout, stderr = pipe.communicate()
+    re_error = re.compile('^error: patch failed: (.+):(\d+)')
+    for line in stderr.splitlines():
+        if verbose:
+            print line
+        match = re_error.match(line)
+        if match:
+            print GetWarningMsg('warning', match.group(1), int(match.group(2)),
+                    'Patch failed')
+    return pipe.returncode == 0, stdout
+
+def ApplyPatches(verbose, args, start_point):
+    """Apply the patches with git am to make sure all is well
+
+    Args:
+        verbose: Print out 'git am' output verbatim
+        args: List of patch files to apply
+        start_point: Number of commits back from HEAD to start applying.
+            Normally this is len(args), but it can be larger if a start
+            offset was given.
+    """
+    error_count = 0
+    col = terminal.Color()
+
+    # Figure out our current position
+    cmd = ['git', 'name-rev', 'HEAD', '--name-only']
+    pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+    stdout, stderr = pipe.communicate()
+    if pipe.returncode:
+        str = 'Could not find current commit name'
+        print col.Color(col.RED, str)
+        print stdout
+        return False
+    old_head = stdout.splitlines()[0]
+
+    # Checkout the required start point
+    cmd = ['git', 'checkout', 'HEAD~%d' % start_point]
+    pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE)
+    stdout, stderr = pipe.communicate()
+    if pipe.returncode:
+        str = 'Could not move to commit before patch series'
+        print col.Color(col.RED, str)
+        print stdout, stderr
+        return False
+
+    # Apply all the patches
+    for fname in args:
+        ok, stdout = ApplyPatch(verbose, fname)
+        if not ok:
+            print col.Color(col.RED, 'git am returned errors for %s: will '
+                    'skip this patch' % fname)
+            if verbose:
+                print stdout
+            error_count += 1
+            cmd = ['git', 'am', '--skip']
+            pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+            stdout, stderr = pipe.communicate()
+            if pipe.returncode != 0:
+                print col.Color(col.RED, 'Unable to skip patch! Aborting...')
+                print stdout
+                break
+
+    # Return to our previous position
+    cmd = ['git', 'checkout', old_head]
+    pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    stdout, stderr = pipe.communicate()
+    if pipe.returncode:
+        print col.Color(col.RED, 'Could not move back to head commit')
+        print stdout, stderr
+    return error_count == 0
+
+def BuildEmailList(in_list, tag=None, alias=None, raise_on_error=True):
+    """Build a list of email addresses based on an input list.
+
+    Takes a list of email addresses and aliases, and turns this into a list
+    of only email address, by resolving any aliases that are present.
+
+    If the tag is given, then each email address is prepended with this
+    tag and a space. If the tag starts with a minus sign (indicating a
+    command line parameter) then the email address is quoted.
+
+    Args:
+        in_list:        List of aliases/email addresses
+        tag:            Text to put before each address
+        alias:          Alias dictionary
+        raise_on_error: True to raise an error when an alias fails to match,
+                False to just print a message.
+
+    Returns:
+        List of email addresses
+
+    >>> alias = {}
+    >>> alias['fred'] = ['f.bloggs@napier.co.nz']
+    >>> alias['john'] = ['j.bloggs@napier.co.nz']
+    >>> alias['mary'] = ['Mary Poppins <m.poppins@cloud.net>']
+    >>> alias['boys'] = ['fred', ' john']
+    >>> alias['all'] = ['fred ', 'john', '   mary   ']
+    >>> BuildEmailList(['john', 'mary'], None, alias)
+    ['j.bloggs@napier.co.nz', 'Mary Poppins <m.poppins@cloud.net>']
+    >>> BuildEmailList(['john', 'mary'], '--to', alias)
+    ['--to "j.bloggs@napier.co.nz"', \
+'--to "Mary Poppins <m.poppins@cloud.net>"']
+    >>> BuildEmailList(['john', 'mary'], 'Cc', alias)
+    ['Cc j.bloggs@napier.co.nz', 'Cc Mary Poppins <m.poppins@cloud.net>']
+    """
+    quote = '"' if tag and tag[0] == '-' else ''
+    raw = []
+    for item in in_list:
+        raw += LookupEmail(item, alias, raise_on_error=raise_on_error)
+    result = []
+    for item in raw:
+        if not item in result:
+            result.append(item)
+    if tag:
+        return ['%s %s%s%s' % (tag, quote, email, quote) for email in result]
+    return result
+
+def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,
+        self_only=False, alias=None, in_reply_to=None):
+    """Email a patch series.
+
+    Args:
+        series: Series object containing destination info
+        cover_fname: filename of cover letter
+        args: list of filenames of patch files
+        dry_run: Just return the command that would be run
+        raise_on_error: True to raise an error when an alias fails to match,
+                False to just print a message.
+        cc_fname: Filename of Cc file for per-commit Cc
+        self_only: True to just email to yourself as a test
+        in_reply_to: If set we'll pass this to git as --in-reply-to.
+            Should be a message ID that this is in reply to.
+
+    Returns:
+        Git command that was/would be run
+
+    # For the duration of this doctest pretend that we ran patman with ./patman
+    >>> _old_argv0 = sys.argv[0]
+    >>> sys.argv[0] = './patman'
+
+    >>> alias = {}
+    >>> alias['fred'] = ['f.bloggs@napier.co.nz']
+    >>> alias['john'] = ['j.bloggs@napier.co.nz']
+    >>> alias['mary'] = ['m.poppins@cloud.net']
+    >>> alias['boys'] = ['fred', ' john']
+    >>> alias['all'] = ['fred ', 'john', '   mary   ']
+    >>> alias[os.getenv('USER')] = ['this-is-me@me.com']
+    >>> series = series.Series()
+    >>> series.to = ['fred']
+    >>> series.cc = ['mary']
+    >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \
+            False, alias)
+    'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \
+"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" cover p1 p2'
+    >>> EmailPatches(series, None, ['p1'], True, True, 'cc-fname', False, \
+            alias)
+    'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \
+"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" p1'
+    >>> series.cc = ['all']
+    >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \
+            True, alias)
+    'git send-email --annotate --to "this-is-me@me.com" --cc-cmd "./patman \
+--cc-cmd cc-fname" cover p1 p2'
+    >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \
+            False, alias)
+    'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \
+"f.bloggs@napier.co.nz" --cc "j.bloggs@napier.co.nz" --cc \
+"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" cover p1 p2'
+
+    # Restore argv[0] since we clobbered it.
+    >>> sys.argv[0] = _old_argv0
+    """
+    to = BuildEmailList(series.get('to'), '--to', alias, raise_on_error)
+    if not to:
+        print ("No recipient, please add something like this to a commit\n"
+            "Series-to: Fred Bloggs <f.blogs@napier.co.nz>")
+        return
+    cc = BuildEmailList(series.get('cc'), '--cc', alias, raise_on_error)
+    if self_only:
+        to = BuildEmailList([os.getenv('USER')], '--to', alias, raise_on_error)
+        cc = []
+    cmd = ['git', 'send-email', '--annotate']
+    if in_reply_to:
+        cmd.append('--in-reply-to="%s"' % in_reply_to)
+
+    cmd += to
+    cmd += cc
+    cmd += ['--cc-cmd', '"%s --cc-cmd %s"' % (sys.argv[0], cc_fname)]
+    if cover_fname:
+        cmd.append(cover_fname)
+    cmd += args
+    str = ' '.join(cmd)
+    if not dry_run:
+        os.system(str)
+    return str
+
+
+def LookupEmail(lookup_name, alias=None, raise_on_error=True, level=0):
+    """If an email address is an alias, look it up and return the full name
+
+    TODO: Why not just use git's own alias feature?
+
+    Args:
+        lookup_name: Alias or email address to look up
+        alias: Dictionary containing aliases (None to use settings default)
+        raise_on_error: True to raise an error when an alias fails to match,
+                False to just print a message.
+
+    Returns:
+        tuple:
+            list containing a list of email addresses
+
+    Raises:
+        OSError if a recursive alias reference was found
+        ValueError if an alias was not found
+
+    >>> alias = {}
+    >>> alias['fred'] = ['f.bloggs@napier.co.nz']
+    >>> alias['john'] = ['j.bloggs@napier.co.nz']
+    >>> alias['mary'] = ['m.poppins@cloud.net']
+    >>> alias['boys'] = ['fred', ' john', 'f.bloggs@napier.co.nz']
+    >>> alias['all'] = ['fred ', 'john', '   mary   ']
+    >>> alias['loop'] = ['other', 'john', '   mary   ']
+    >>> alias['other'] = ['loop', 'john', '   mary   ']
+    >>> LookupEmail('mary', alias)
+    ['m.poppins@cloud.net']
+    >>> LookupEmail('arthur.wellesley@howe.ro.uk', alias)
+    ['arthur.wellesley@howe.ro.uk']
+    >>> LookupEmail('boys', alias)
+    ['f.bloggs@napier.co.nz', 'j.bloggs@napier.co.nz']
+    >>> LookupEmail('all', alias)
+    ['f.bloggs@napier.co.nz', 'j.bloggs@napier.co.nz', 'm.poppins@cloud.net']
+    >>> LookupEmail('odd', alias)
+    Traceback (most recent call last):
+    ...
+    ValueError: Alias 'odd' not found
+    >>> LookupEmail('loop', alias)
+    Traceback (most recent call last):
+    ...
+    OSError: Recursive email alias at 'other'
+    >>> LookupEmail('odd', alias, raise_on_error=False)
+    \033[1;31mAlias 'odd' not found\033[0m
+    []
+    >>> # In this case the loop part will effectively be ignored.
+    >>> LookupEmail('loop', alias, raise_on_error=False)
+    \033[1;31mRecursive email alias at 'other'\033[0m
+    \033[1;31mRecursive email alias at 'john'\033[0m
+    \033[1;31mRecursive email alias at 'mary'\033[0m
+    ['j.bloggs@napier.co.nz', 'm.poppins@cloud.net']
+    """
+    if not alias:
+        alias = settings.alias
+    lookup_name = lookup_name.strip()
+    if '@' in lookup_name: # Perhaps a real email address
+        return [lookup_name]
+
+    lookup_name = lookup_name.lower()
+    col = terminal.Color()
+
+    out_list = []
+    if level > 10:
+        msg = "Recursive email alias at '%s'" % lookup_name
+        if raise_on_error:
+            raise OSError, msg
+        else:
+            print col.Color(col.RED, msg)
+            return out_list
+
+    if lookup_name:
+        if not lookup_name in alias:
+            msg = "Alias '%s' not found" % lookup_name
+            if raise_on_error:
+                raise ValueError, msg
+            else:
+                print col.Color(col.RED, msg)
+                return out_list
+        for item in alias[lookup_name]:
+            todo = LookupEmail(item, alias, raise_on_error, level + 1)
+            for new_item in todo:
+                if not new_item in out_list:
+                    out_list.append(new_item)
+
+    #print "No match for alias '%s'" % lookup_name
+    return out_list
+
+def GetTopLevel():
+    """Return name of top-level directory for this git repo.
+
+    Returns:
+        Full path to git top-level directory
+
+    This test makes sure that we are running tests in the right subdir
+
+    >>> os.path.realpath(os.path.dirname(__file__)) == \
+            os.path.join(GetTopLevel(), 'tools', 'patman')
+    True
+    """
+    return command.OutputOneLine('git', 'rev-parse', '--show-toplevel')
+
+def GetAliasFile():
+    """Gets the name of the git alias file.
+
+    Returns:
+        Filename of git alias file, or None if none
+    """
+    fname = command.OutputOneLine('git', 'config', 'sendemail.aliasesfile',
+            raise_on_error=False)
+    if fname:
+        fname = os.path.join(GetTopLevel(), fname.strip())
+    return fname
+
+def GetDefaultUserName():
+    """Gets the user.name from .gitconfig file.
+
+    Returns:
+        User name found in .gitconfig file, or None if none
+    """
+    uname = command.OutputOneLine('git', 'config', '--global', 'user.name')
+    return uname
+
+def GetDefaultUserEmail():
+    """Gets the user.email from the global .gitconfig file.
+
+    Returns:
+        User's email found in .gitconfig file, or None if none
+    """
+    uemail = command.OutputOneLine('git', 'config', '--global', 'user.email')
+    return uemail
+
+def Setup():
+    """Set up git utils, by reading the alias files."""
+    # Check for a git alias file also
+    alias_fname = GetAliasFile()
+    if alias_fname:
+        settings.ReadGitAliases(alias_fname)
+
+def GetHead():
+    """Get the hash of the current HEAD
+
+    Returns:
+        Hash of HEAD
+    """
+    return command.OutputOneLine('git', 'show', '-s', '--pretty=format:%H')
+
+if __name__ == "__main__":
+    import doctest
+
+    doctest.testmod()
diff --git a/marvell/uboot/tools/patman/patchstream.py b/marvell/uboot/tools/patman/patchstream.py
new file mode 100644
index 0000000..684204c
--- /dev/null
+++ b/marvell/uboot/tools/patman/patchstream.py
@@ -0,0 +1,487 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import os
+import re
+import shutil
+import tempfile
+
+import command
+import commit
+import gitutil
+from series import Series
+
+# Tags that we detect and remove
+re_remove = re.compile('^BUG=|^TEST=|^BRANCH=|^Change-Id:|^Review URL:'
+    '|Reviewed-on:|Commit-\w*:')
+
+# Lines which are allowed after a TEST= line
+re_allowed_after_test = re.compile('^Signed-off-by:')
+
+# Signoffs
+re_signoff = re.compile('^Signed-off-by:')
+
+# The start of the cover letter
+re_cover = re.compile('^Cover-letter:')
+
+# A cover letter Cc
+re_cover_cc = re.compile('^Cover-letter-cc: *(.*)')
+
+# Patch series tag
+re_series_tag = re.compile('^Series-([a-z-]*): *(.*)')
+
+# Commit series tag
+re_commit_tag = re.compile('^Commit-([a-z-]*): *(.*)')
+
+# Commit tags that we want to collect and keep
+re_tag = re.compile('^(Tested-by|Acked-by|Reviewed-by|Cc): (.*)')
+
+# The start of a new commit in the git log
+re_commit = re.compile('^commit ([0-9a-f]*)$')
+
+# We detect these since checkpatch doesn't always do it
+re_space_before_tab = re.compile('^[+].* \t')
+
+# States we can be in - can we use range() and still have comments?
+STATE_MSG_HEADER = 0        # Still in the message header
+STATE_PATCH_SUBJECT = 1     # In patch subject (first line of log for a commit)
+STATE_PATCH_HEADER = 2      # In patch header (after the subject)
+STATE_DIFFS = 3             # In the diff part (past --- line)
+
+class PatchStream:
+    """Class for detecting/injecting tags in a patch or series of patches
+
+    We support processing the output of 'git log' to read out the tags we
+    are interested in. We can also process a patch file in order to remove
+    unwanted tags or inject additional ones. These correspond to the two
+    phases of processing.
+    """
+    def __init__(self, series, name=None, is_log=False):
+        self.skip_blank = False          # True to skip a single blank line
+        self.found_test = False          # Found a TEST= line
+        self.lines_after_test = 0        # MNumber of lines found after TEST=
+        self.warn = []                   # List of warnings we have collected
+        self.linenum = 1                 # Output line number we are up to
+        self.in_section = None           # Name of start...END section we are in
+        self.notes = []                  # Series notes
+        self.section = []                # The current section...END section
+        self.series = series             # Info about the patch series
+        self.is_log = is_log             # True if indent like git log
+        self.in_change = 0               # Non-zero if we are in a change list
+        self.blank_count = 0             # Number of blank lines stored up
+        self.state = STATE_MSG_HEADER    # What state are we in?
+        self.tags = []                   # Tags collected, like Tested-by...
+        self.signoff = []                # Contents of signoff line
+        self.commit = None               # Current commit
+
+    def AddToSeries(self, line, name, value):
+        """Add a new Series-xxx tag.
+
+        When a Series-xxx tag is detected, we come here to record it, if we
+        are scanning a 'git log'.
+
+        Args:
+            line: Source line containing tag (useful for debug/error messages)
+            name: Tag name (part after 'Series-')
+            value: Tag value (part after 'Series-xxx: ')
+        """
+        if name == 'notes':
+            self.in_section = name
+            self.skip_blank = False
+        if self.is_log:
+            self.series.AddTag(self.commit, line, name, value)
+
+    def AddToCommit(self, line, name, value):
+        """Add a new Commit-xxx tag.
+
+        When a Commit-xxx tag is detected, we come here to record it.
+
+        Args:
+            line: Source line containing tag (useful for debug/error messages)
+            name: Tag name (part after 'Commit-')
+            value: Tag value (part after 'Commit-xxx: ')
+        """
+        if name == 'notes':
+            self.in_section = 'commit-' + name
+            self.skip_blank = False
+
+    def CloseCommit(self):
+        """Save the current commit into our commit list, and reset our state"""
+        if self.commit and self.is_log:
+            self.series.AddCommit(self.commit)
+            self.commit = None
+
+    def FormatTags(self, tags):
+        out_list = []
+        for tag in sorted(tags):
+            if tag.startswith('Cc:'):
+                tag_list = tag[4:].split(',')
+                out_list += gitutil.BuildEmailList(tag_list, 'Cc:')
+            else:
+                out_list.append(tag)
+        return out_list
+
+    def ProcessLine(self, line):
+        """Process a single line of a patch file or commit log
+
+        This process a line and returns a list of lines to output. The list
+        may be empty or may contain multiple output lines.
+
+        This is where all the complicated logic is located. The class's
+        state is used to move between different states and detect things
+        properly.
+
+        We can be in one of two modes:
+            self.is_log == True: This is 'git log' mode, where most output is
+                indented by 4 characters and we are scanning for tags
+
+            self.is_log == False: This is 'patch' mode, where we already have
+                all the tags, and are processing patches to remove junk we
+                don't want, and add things we think are required.
+
+        Args:
+            line: text line to process
+
+        Returns:
+            list of output lines, or [] if nothing should be output
+        """
+        # Initially we have no output. Prepare the input line string
+        out = []
+        line = line.rstrip('\n')
+        if self.is_log:
+            if line[:4] == '    ':
+                line = line[4:]
+
+        # Handle state transition and skipping blank lines
+        series_tag_match = re_series_tag.match(line)
+        commit_tag_match = re_commit_tag.match(line)
+        commit_match = re_commit.match(line) if self.is_log else None
+        cover_cc_match = re_cover_cc.match(line)
+        tag_match = None
+        if self.state == STATE_PATCH_HEADER:
+            tag_match = re_tag.match(line)
+        is_blank = not line.strip()
+        if is_blank:
+            if (self.state == STATE_MSG_HEADER
+                    or self.state == STATE_PATCH_SUBJECT):
+                self.state += 1
+
+            # We don't have a subject in the text stream of patch files
+            # It has its own line with a Subject: tag
+            if not self.is_log and self.state == STATE_PATCH_SUBJECT:
+                self.state += 1
+        elif commit_match:
+            self.state = STATE_MSG_HEADER
+
+        # If we are in a section, keep collecting lines until we see END
+        if self.in_section:
+            if line == 'END':
+                if self.in_section == 'cover':
+                    self.series.cover = self.section
+                elif self.in_section == 'notes':
+                    if self.is_log:
+                        self.series.notes += self.section
+                elif self.in_section == 'commit-notes':
+                    if self.is_log:
+                        self.commit.notes += self.section
+                else:
+                    self.warn.append("Unknown section '%s'" % self.in_section)
+                self.in_section = None
+                self.skip_blank = True
+                self.section = []
+            else:
+                self.section.append(line)
+
+        # Detect the commit subject
+        elif not is_blank and self.state == STATE_PATCH_SUBJECT:
+            self.commit.subject = line
+
+        # Detect the tags we want to remove, and skip blank lines
+        elif re_remove.match(line) and not commit_tag_match:
+            self.skip_blank = True
+
+            # TEST= should be the last thing in the commit, so remove
+            # everything after it
+            if line.startswith('TEST='):
+                self.found_test = True
+        elif self.skip_blank and is_blank:
+            self.skip_blank = False
+
+        # Detect the start of a cover letter section
+        elif re_cover.match(line):
+            self.in_section = 'cover'
+            self.skip_blank = False
+
+        elif cover_cc_match:
+            value = cover_cc_match.group(1)
+            self.AddToSeries(line, 'cover-cc', value)
+
+        # If we are in a change list, key collected lines until a blank one
+        elif self.in_change:
+            if is_blank:
+                # Blank line ends this change list
+                self.in_change = 0
+            elif line == '---' or re_signoff.match(line):
+                self.in_change = 0
+                out = self.ProcessLine(line)
+            else:
+                if self.is_log:
+                    self.series.AddChange(self.in_change, self.commit, line)
+            self.skip_blank = False
+
+        # Detect Series-xxx tags
+        elif series_tag_match:
+            name = series_tag_match.group(1)
+            value = series_tag_match.group(2)
+            if name == 'changes':
+                # value is the version number: e.g. 1, or 2
+                try:
+                    value = int(value)
+                except ValueError as str:
+                    raise ValueError("%s: Cannot decode version info '%s'" %
+                        (self.commit.hash, line))
+                self.in_change = int(value)
+            else:
+                self.AddToSeries(line, name, value)
+                self.skip_blank = True
+
+        # Detect Commit-xxx tags
+        elif commit_tag_match:
+            name = commit_tag_match.group(1)
+            value = commit_tag_match.group(2)
+            if name == 'notes':
+                self.AddToCommit(line, name, value)
+                self.skip_blank = True
+
+        # Detect the start of a new commit
+        elif commit_match:
+            self.CloseCommit()
+            # TODO: We should store the whole hash, and just display a subset
+            self.commit = commit.Commit(commit_match.group(1)[:8])
+
+        # Detect tags in the commit message
+        elif tag_match:
+            # Remove Tested-by self, since few will take much notice
+            if (tag_match.group(1) == 'Tested-by' and
+                    tag_match.group(2).find(os.getenv('USER') + '@') != -1):
+                self.warn.append("Ignoring %s" % line)
+            elif tag_match.group(1) == 'Cc':
+                self.commit.AddCc(tag_match.group(2).split(','))
+            else:
+                self.tags.append(line);
+
+        # Well that means this is an ordinary line
+        else:
+            pos = 1
+            # Look for ugly ASCII characters
+            for ch in line:
+                # TODO: Would be nicer to report source filename and line
+                if ord(ch) > 0x80:
+                    self.warn.append("Line %d/%d ('%s') has funny ascii char" %
+                        (self.linenum, pos, line))
+                pos += 1
+
+            # Look for space before tab
+            m = re_space_before_tab.match(line)
+            if m:
+                self.warn.append('Line %d/%d has space before tab' %
+                    (self.linenum, m.start()))
+
+            # OK, we have a valid non-blank line
+            out = [line]
+            self.linenum += 1
+            self.skip_blank = False
+            if self.state == STATE_DIFFS:
+                pass
+
+            # If this is the start of the diffs section, emit our tags and
+            # change log
+            elif line == '---':
+                self.state = STATE_DIFFS
+
+                # Output the tags (signeoff first), then change list
+                out = []
+                log = self.series.MakeChangeLog(self.commit)
+                out += self.FormatTags(self.tags)
+                out += [line] + self.commit.notes + [''] + log
+            elif self.found_test:
+                if not re_allowed_after_test.match(line):
+                    self.lines_after_test += 1
+
+        return out
+
+    def Finalize(self):
+        """Close out processing of this patch stream"""
+        self.CloseCommit()
+        if self.lines_after_test:
+            self.warn.append('Found %d lines after TEST=' %
+                    self.lines_after_test)
+
+    def ProcessStream(self, infd, outfd):
+        """Copy a stream from infd to outfd, filtering out unwanting things.
+
+        This is used to process patch files one at a time.
+
+        Args:
+            infd: Input stream file object
+            outfd: Output stream file object
+        """
+        # Extract the filename from each diff, for nice warnings
+        fname = None
+        last_fname = None
+        re_fname = re.compile('diff --git a/(.*) b/.*')
+        while True:
+            line = infd.readline()
+            if not line:
+                break
+            out = self.ProcessLine(line)
+
+            # Try to detect blank lines at EOF
+            for line in out:
+                match = re_fname.match(line)
+                if match:
+                    last_fname = fname
+                    fname = match.group(1)
+                if line == '+':
+                    self.blank_count += 1
+                else:
+                    if self.blank_count and (line == '-- ' or match):
+                        self.warn.append("Found possible blank line(s) at "
+                                "end of file '%s'" % last_fname)
+                    outfd.write('+\n' * self.blank_count)
+                    outfd.write(line + '\n')
+                    self.blank_count = 0
+        self.Finalize()
+
+
+def GetMetaDataForList(commit_range, git_dir=None, count=None,
+                       series = Series()):
+    """Reads out patch series metadata from the commits
+
+    This does a 'git log' on the relevant commits and pulls out the tags we
+    are interested in.
+
+    Args:
+        commit_range: Range of commits to count (e.g. 'HEAD..base')
+        git_dir: Path to git repositiory (None to use default)
+        count: Number of commits to list, or None for no limit
+        series: Series object to add information into. By default a new series
+            is started.
+    Returns:
+        A Series object containing information about the commits.
+    """
+    params = ['git', 'log', '--no-color', '--reverse', '--no-decorate',
+                    commit_range]
+    if count is not None:
+        params[2:2] = ['-n%d' % count]
+    if git_dir:
+        params[1:1] = ['--git-dir', git_dir]
+    pipe = [params]
+    stdout = command.RunPipe(pipe, capture=True).stdout
+    ps = PatchStream(series, is_log=True)
+    for line in stdout.splitlines():
+        ps.ProcessLine(line)
+    ps.Finalize()
+    return series
+
+def GetMetaData(start, count):
+    """Reads out patch series metadata from the commits
+
+    This does a 'git log' on the relevant commits and pulls out the tags we
+    are interested in.
+
+    Args:
+        start: Commit to start from: 0=HEAD, 1=next one, etc.
+        count: Number of commits to list
+    """
+    return GetMetaDataForList('HEAD~%d' % start, None, count)
+
+def FixPatch(backup_dir, fname, series, commit):
+    """Fix up a patch file, by adding/removing as required.
+
+    We remove our tags from the patch file, insert changes lists, etc.
+    The patch file is processed in place, and overwritten.
+
+    A backup file is put into backup_dir (if not None).
+
+    Args:
+        fname: Filename to patch file to process
+        series: Series information about this patch set
+        commit: Commit object for this patch file
+    Return:
+        A list of errors, or [] if all ok.
+    """
+    handle, tmpname = tempfile.mkstemp()
+    outfd = os.fdopen(handle, 'w')
+    infd = open(fname, 'r')
+    ps = PatchStream(series)
+    ps.commit = commit
+    ps.ProcessStream(infd, outfd)
+    infd.close()
+    outfd.close()
+
+    # Create a backup file if required
+    if backup_dir:
+        shutil.copy(fname, os.path.join(backup_dir, os.path.basename(fname)))
+    shutil.move(tmpname, fname)
+    return ps.warn
+
+def FixPatches(series, fnames):
+    """Fix up a list of patches identified by filenames
+
+    The patch files are processed in place, and overwritten.
+
+    Args:
+        series: The series object
+        fnames: List of patch files to process
+    """
+    # Current workflow creates patches, so we shouldn't need a backup
+    backup_dir = None  #tempfile.mkdtemp('clean-patch')
+    count = 0
+    for fname in fnames:
+        commit = series.commits[count]
+        commit.patch = fname
+        result = FixPatch(backup_dir, fname, series, commit)
+        if result:
+            print '%d warnings for %s:' % (len(result), fname)
+            for warn in result:
+                print '\t', warn
+            print
+        count += 1
+    print 'Cleaned %d patches' % count
+    return series
+
+def InsertCoverLetter(fname, series, count):
+    """Inserts a cover letter with the required info into patch 0
+
+    Args:
+        fname: Input / output filename of the cover letter file
+        series: Series object
+        count: Number of patches in the series
+    """
+    fd = open(fname, 'r')
+    lines = fd.readlines()
+    fd.close()
+
+    fd = open(fname, 'w')
+    text = series.cover
+    prefix = series.GetPatchPrefix()
+    for line in lines:
+        if line.startswith('Subject:'):
+            # TODO: if more than 10 patches this should save 00/xx, not 0/xx
+            line = 'Subject: [%s 0/%d] %s\n' % (prefix, count, text[0])
+
+        # Insert our cover letter
+        elif line.startswith('*** BLURB HERE ***'):
+            # First the blurb test
+            line = '\n'.join(text[1:]) + '\n'
+            if series.get('notes'):
+                line += '\n'.join(series.notes) + '\n'
+
+            # Now the change list
+            out = series.MakeChangeLog(None)
+            line += '\n' + '\n'.join(out)
+        fd.write(line)
+    fd.close()
diff --git a/marvell/uboot/tools/patman/patman b/marvell/uboot/tools/patman/patman
new file mode 120000
index 0000000..6cc3d7a
--- /dev/null
+++ b/marvell/uboot/tools/patman/patman
@@ -0,0 +1 @@
+patman.py
\ No newline at end of file
diff --git a/marvell/uboot/tools/patman/patman.py b/marvell/uboot/tools/patman/patman.py
new file mode 100755
index 0000000..c60aa5a
--- /dev/null
+++ b/marvell/uboot/tools/patman/patman.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+"""See README for more information"""
+
+from optparse import OptionParser
+import os
+import re
+import sys
+import unittest
+
+# Our modules
+import checkpatch
+import command
+import gitutil
+import patchstream
+import project
+import settings
+import terminal
+import test
+
+
+parser = OptionParser()
+parser.add_option('-a', '--no-apply', action='store_false',
+                  dest='apply_patches', default=True,
+                  help="Don't test-apply patches with git am")
+parser.add_option('-H', '--full-help', action='store_true', dest='full_help',
+       default=False, help='Display the README file')
+parser.add_option('-c', '--count', dest='count', type='int',
+       default=-1, help='Automatically create patches from top n commits')
+parser.add_option('-i', '--ignore-errors', action='store_true',
+       dest='ignore_errors', default=False,
+       help='Send patches email even if patch errors are found')
+parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
+       default=False, help="Do a dry run (create but don't email patches)")
+parser.add_option('-p', '--project', default=project.DetectProject(),
+                  help="Project name; affects default option values and "
+                  "aliases [default: %default]")
+parser.add_option('-r', '--in-reply-to', type='string', action='store',
+                  help="Message ID that this series is in reply to")
+parser.add_option('-s', '--start', dest='start', type='int',
+       default=0, help='Commit to start creating patches from (0 = HEAD)')
+parser.add_option('-t', '--ignore-bad-tags', action='store_true',
+                  default=False, help='Ignore bad tags / aliases')
+parser.add_option('--test', action='store_true', dest='test',
+                  default=False, help='run tests')
+parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
+       default=False, help='Verbose output of errors and warnings')
+parser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store',
+       default=None, help='Output cc list for patch file (used by git)')
+parser.add_option('--no-check', action='store_false', dest='check_patch',
+                  default=True,
+                  help="Don't check for patch compliance")
+parser.add_option('--no-tags', action='store_false', dest='process_tags',
+                  default=True, help="Don't process subject tags as aliaes")
+
+parser.usage = """patman [options]
+
+Create patches from commits in a branch, check them and email them as
+specified by tags you place in the commits. Use -n to do a dry run first."""
+
+
+# Parse options twice: first to get the project and second to handle
+# defaults properly (which depends on project).
+(options, args) = parser.parse_args()
+settings.Setup(parser, options.project, '')
+(options, args) = parser.parse_args()
+
+# Run our meagre tests
+if options.test:
+    import doctest
+
+    sys.argv = [sys.argv[0]]
+    suite = unittest.TestLoader().loadTestsFromTestCase(test.TestPatch)
+    result = unittest.TestResult()
+    suite.run(result)
+
+    for module in ['gitutil', 'settings']:
+        suite = doctest.DocTestSuite(module)
+        suite.run(result)
+
+    # TODO: Surely we can just 'print' result?
+    print result
+    for test, err in result.errors:
+        print err
+    for test, err in result.failures:
+        print err
+
+# Called from git with a patch filename as argument
+# Printout a list of additional CC recipients for this patch
+elif options.cc_cmd:
+    fd = open(options.cc_cmd, 'r')
+    re_line = re.compile('(\S*) (.*)')
+    for line in fd.readlines():
+        match = re_line.match(line)
+        if match and match.group(1) == args[0]:
+            for cc in match.group(2).split(', '):
+                cc = cc.strip()
+                if cc:
+                    print cc
+    fd.close()
+
+elif options.full_help:
+    pager = os.getenv('PAGER')
+    if not pager:
+        pager = 'more'
+    fname = os.path.join(os.path.dirname(sys.argv[0]), 'README')
+    command.Run(pager, fname)
+
+# Process commits, produce patches files, check them, email them
+else:
+    gitutil.Setup()
+
+    if options.count == -1:
+        # Work out how many patches to send if we can
+        options.count = gitutil.CountCommitsToBranch() - options.start
+
+    col = terminal.Color()
+    if not options.count:
+        str = 'No commits found to process - please use -c flag'
+        print col.Color(col.RED, str)
+        sys.exit(1)
+
+    # Read the metadata from the commits
+    if options.count:
+        series = patchstream.GetMetaData(options.start, options.count)
+        cover_fname, args = gitutil.CreatePatches(options.start, options.count,
+                series)
+
+    # Fix up the patch files to our liking, and insert the cover letter
+    series = patchstream.FixPatches(series, args)
+    if series and cover_fname and series.get('cover'):
+        patchstream.InsertCoverLetter(cover_fname, series, options.count)
+
+    # Do a few checks on the series
+    series.DoChecks()
+
+    # Check the patches, and run them through 'git am' just to be sure
+    if options.check_patch:
+        ok = checkpatch.CheckPatches(options.verbose, args)
+    else:
+        ok = True
+    if options.apply_patches:
+        if not gitutil.ApplyPatches(options.verbose, args,
+                                    options.count + options.start):
+            ok = False
+
+    cc_file = series.MakeCcFile(options.process_tags, cover_fname,
+                                not options.ignore_bad_tags)
+
+    # Email the patches out (giving the user time to check / cancel)
+    cmd = ''
+    if ok or options.ignore_errors:
+        cmd = gitutil.EmailPatches(series, cover_fname, args,
+                options.dry_run, not options.ignore_bad_tags, cc_file,
+                in_reply_to=options.in_reply_to)
+
+    # For a dry run, just show our actions as a sanity check
+    if options.dry_run:
+        series.ShowActions(args, cmd, options.process_tags)
+
+    os.remove(cc_file)
diff --git a/marvell/uboot/tools/patman/project.py b/marvell/uboot/tools/patman/project.py
new file mode 100644
index 0000000..e05ff11
--- /dev/null
+++ b/marvell/uboot/tools/patman/project.py
@@ -0,0 +1,27 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import os.path
+
+import gitutil
+
+def DetectProject():
+    """Autodetect the name of the current project.
+
+    This looks for signature files/directories that are unlikely to exist except
+    in the given project.
+
+    Returns:
+        The name of the project, like "linux" or "u-boot".  Returns "unknown"
+        if we can't detect the project.
+    """
+    top_level = gitutil.GetTopLevel()
+
+    if os.path.exists(os.path.join(top_level, "include", "u-boot")):
+        return "u-boot"
+    elif os.path.exists(os.path.join(top_level, "kernel")):
+        return "linux"
+
+    return "unknown"
diff --git a/marvell/uboot/tools/patman/series.py b/marvell/uboot/tools/patman/series.py
new file mode 100644
index 0000000..88c0d87
--- /dev/null
+++ b/marvell/uboot/tools/patman/series.py
@@ -0,0 +1,267 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import itertools
+import os
+
+import get_maintainer
+import gitutil
+import terminal
+
+# Series-xxx tags that we understand
+valid_series = ['to', 'cc', 'version', 'changes', 'prefix', 'notes', 'name',
+                'cover-cc', 'process_log']
+
+class Series(dict):
+    """Holds information about a patch series, including all tags.
+
+    Vars:
+        cc: List of aliases/emails to Cc all patches to
+        commits: List of Commit objects, one for each patch
+        cover: List of lines in the cover letter
+        notes: List of lines in the notes
+        changes: (dict) List of changes for each version, The key is
+            the integer version number
+        allow_overwrite: Allow tags to overwrite an existing tag
+    """
+    def __init__(self):
+        self.cc = []
+        self.to = []
+        self.cover_cc = []
+        self.commits = []
+        self.cover = None
+        self.notes = []
+        self.changes = {}
+        self.allow_overwrite = False
+
+        # Written in MakeCcFile()
+        #  key: name of patch file
+        #  value: list of email addresses
+        self._generated_cc = {}
+
+    # These make us more like a dictionary
+    def __setattr__(self, name, value):
+        self[name] = value
+
+    def __getattr__(self, name):
+        return self[name]
+
+    def AddTag(self, commit, line, name, value):
+        """Add a new Series-xxx tag along with its value.
+
+        Args:
+            line: Source line containing tag (useful for debug/error messages)
+            name: Tag name (part after 'Series-')
+            value: Tag value (part after 'Series-xxx: ')
+        """
+        # If we already have it, then add to our list
+        name = name.replace('-', '_')
+        if name in self and not self.allow_overwrite:
+            values = value.split(',')
+            values = [str.strip() for str in values]
+            if type(self[name]) != type([]):
+                raise ValueError("In %s: line '%s': Cannot add another value "
+                        "'%s' to series '%s'" %
+                            (commit.hash, line, values, self[name]))
+            self[name] += values
+
+        # Otherwise just set the value
+        elif name in valid_series:
+            self[name] = value
+        else:
+            raise ValueError("In %s: line '%s': Unknown 'Series-%s': valid "
+                        "options are %s" % (commit.hash, line, name,
+                            ', '.join(valid_series)))
+
+    def AddCommit(self, commit):
+        """Add a commit into our list of commits
+
+        We create a list of tags in the commit subject also.
+
+        Args:
+            commit: Commit object to add
+        """
+        commit.CheckTags()
+        self.commits.append(commit)
+
+    def ShowActions(self, args, cmd, process_tags):
+        """Show what actions we will/would perform
+
+        Args:
+            args: List of patch files we created
+            cmd: The git command we would have run
+            process_tags: Process tags as if they were aliases
+        """
+        col = terminal.Color()
+        print 'Dry run, so not doing much. But I would do this:'
+        print
+        print 'Send a total of %d patch%s with %scover letter.' % (
+                len(args), '' if len(args) == 1 else 'es',
+                self.get('cover') and 'a ' or 'no ')
+
+        # TODO: Colour the patches according to whether they passed checks
+        for upto in range(len(args)):
+            commit = self.commits[upto]
+            print col.Color(col.GREEN, '   %s' % args[upto])
+            cc_list = list(self._generated_cc[commit.patch])
+
+            # Skip items in To list
+            if 'to' in self:
+                try:
+                    map(cc_list.remove, gitutil.BuildEmailList(self.to))
+                except ValueError:
+                    pass
+
+            for email in cc_list:
+                if email == None:
+                    email = col.Color(col.YELLOW, "<alias '%s' not found>"
+                            % tag)
+                if email:
+                    print '      Cc: ',email
+        print
+        for item in gitutil.BuildEmailList(self.get('to', '<none>')):
+            print 'To:\t ', item
+        for item in gitutil.BuildEmailList(self.cc):
+            print 'Cc:\t ', item
+        print 'Version: ', self.get('version')
+        print 'Prefix:\t ', self.get('prefix')
+        if self.cover:
+            print 'Cover: %d lines' % len(self.cover)
+            cover_cc = gitutil.BuildEmailList(self.get('cover_cc', ''))
+            all_ccs = itertools.chain(cover_cc, *self._generated_cc.values())
+            for email in set(all_ccs):
+                    print '      Cc: ',email
+        if cmd:
+            print 'Git command: %s' % cmd
+
+    def MakeChangeLog(self, commit):
+        """Create a list of changes for each version.
+
+        Return:
+            The change log as a list of strings, one per line
+
+            Changes in v4:
+            - Jog the dial back closer to the widget
+
+            Changes in v3: None
+            Changes in v2:
+            - Fix the widget
+            - Jog the dial
+
+            etc.
+        """
+        final = []
+        process_it = self.get('process_log', '').split(',')
+        process_it = [item.strip() for item in process_it]
+        need_blank = False
+        for change in sorted(self.changes, reverse=True):
+            out = []
+            for this_commit, text in self.changes[change]:
+                if commit and this_commit != commit:
+                    continue
+                if 'uniq' not in process_it or text not in out:
+                    out.append(text)
+            line = 'Changes in v%d:' % change
+            have_changes = len(out) > 0
+            if 'sort' in process_it:
+                out = sorted(out)
+            if have_changes:
+                out.insert(0, line)
+            else:
+                out = [line + ' None']
+            if need_blank:
+                out.insert(0, '')
+            final += out
+            need_blank = have_changes
+        if self.changes:
+            final.append('')
+        return final
+
+    def DoChecks(self):
+        """Check that each version has a change log
+
+        Print an error if something is wrong.
+        """
+        col = terminal.Color()
+        if self.get('version'):
+            changes_copy = dict(self.changes)
+            for version in range(1, int(self.version) + 1):
+                if self.changes.get(version):
+                    del changes_copy[version]
+                else:
+                    if version > 1:
+                        str = 'Change log missing for v%d' % version
+                        print col.Color(col.RED, str)
+            for version in changes_copy:
+                str = 'Change log for unknown version v%d' % version
+                print col.Color(col.RED, str)
+        elif self.changes:
+            str = 'Change log exists, but no version is set'
+            print col.Color(col.RED, str)
+
+    def MakeCcFile(self, process_tags, cover_fname, raise_on_error):
+        """Make a cc file for us to use for per-commit Cc automation
+
+        Also stores in self._generated_cc to make ShowActions() faster.
+
+        Args:
+            process_tags: Process tags as if they were aliases
+            cover_fname: If non-None the name of the cover letter.
+            raise_on_error: True to raise an error when an alias fails to match,
+                False to just print a message.
+        Return:
+            Filename of temp file created
+        """
+        # Look for commit tags (of the form 'xxx:' at the start of the subject)
+        fname = '/tmp/patman.%d' % os.getpid()
+        fd = open(fname, 'w')
+        all_ccs = []
+        for commit in self.commits:
+            list = []
+            if process_tags:
+                list += gitutil.BuildEmailList(commit.tags,
+                                               raise_on_error=raise_on_error)
+            list += gitutil.BuildEmailList(commit.cc_list,
+                                           raise_on_error=raise_on_error)
+            list += get_maintainer.GetMaintainer(commit.patch)
+            all_ccs += list
+            print >>fd, commit.patch, ', '.join(list)
+            self._generated_cc[commit.patch] = list
+
+        if cover_fname:
+            cover_cc = gitutil.BuildEmailList(self.get('cover_cc', ''))
+            print >>fd, cover_fname, ', '.join(set(cover_cc + all_ccs))
+
+        fd.close()
+        return fname
+
+    def AddChange(self, version, commit, info):
+        """Add a new change line to a version.
+
+        This will later appear in the change log.
+
+        Args:
+            version: version number to add change list to
+            info: change line for this version
+        """
+        if not self.changes.get(version):
+            self.changes[version] = []
+        self.changes[version].append([commit, info])
+
+    def GetPatchPrefix(self):
+        """Get the patch version string
+
+        Return:
+            Patch string, like 'RFC PATCH v5' or just 'PATCH'
+        """
+        version = ''
+        if self.get('version'):
+            version = ' v%s' % self['version']
+
+        # Get patch name prefix
+        prefix = ''
+        if self.get('prefix'):
+            prefix = '%s ' % self['prefix']
+        return '%sPATCH%s' % (prefix, version)
diff --git a/marvell/uboot/tools/patman/settings.py b/marvell/uboot/tools/patman/settings.py
new file mode 100644
index 0000000..122e8fd
--- /dev/null
+++ b/marvell/uboot/tools/patman/settings.py
@@ -0,0 +1,268 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import ConfigParser
+import os
+import re
+
+import command
+import gitutil
+
+"""Default settings per-project.
+
+These are used by _ProjectConfigParser.  Settings names should match
+the "dest" of the option parser from patman.py.
+"""
+_default_settings = {
+    "u-boot": {},
+    "linux": {
+        "process_tags": "False",
+    }
+}
+
+class _ProjectConfigParser(ConfigParser.SafeConfigParser):
+    """ConfigParser that handles projects.
+
+    There are two main goals of this class:
+    - Load project-specific default settings.
+    - Merge general default settings/aliases with project-specific ones.
+
+    # Sample config used for tests below...
+    >>> import StringIO
+    >>> sample_config = '''
+    ... [alias]
+    ... me: Peter P. <likesspiders@example.com>
+    ... enemies: Evil <evil@example.com>
+    ...
+    ... [sm_alias]
+    ... enemies: Green G. <ugly@example.com>
+    ...
+    ... [sm2_alias]
+    ... enemies: Doc O. <pus@example.com>
+    ...
+    ... [settings]
+    ... am_hero: True
+    ... '''
+
+    # Check to make sure that bogus project gets general alias.
+    >>> config = _ProjectConfigParser("zzz")
+    >>> config.readfp(StringIO.StringIO(sample_config))
+    >>> config.get("alias", "enemies")
+    'Evil <evil@example.com>'
+
+    # Check to make sure that alias gets overridden by project.
+    >>> config = _ProjectConfigParser("sm")
+    >>> config.readfp(StringIO.StringIO(sample_config))
+    >>> config.get("alias", "enemies")
+    'Green G. <ugly@example.com>'
+
+    # Check to make sure that settings get merged with project.
+    >>> config = _ProjectConfigParser("linux")
+    >>> config.readfp(StringIO.StringIO(sample_config))
+    >>> sorted(config.items("settings"))
+    [('am_hero', 'True'), ('process_tags', 'False')]
+
+    # Check to make sure that settings works with unknown project.
+    >>> config = _ProjectConfigParser("unknown")
+    >>> config.readfp(StringIO.StringIO(sample_config))
+    >>> sorted(config.items("settings"))
+    [('am_hero', 'True')]
+    """
+    def __init__(self, project_name):
+        """Construct _ProjectConfigParser.
+
+        In addition to standard SafeConfigParser initialization, this also loads
+        project defaults.
+
+        Args:
+            project_name: The name of the project.
+        """
+        self._project_name = project_name
+        ConfigParser.SafeConfigParser.__init__(self)
+
+        # Update the project settings in the config based on
+        # the _default_settings global.
+        project_settings = "%s_settings" % project_name
+        if not self.has_section(project_settings):
+            self.add_section(project_settings)
+        project_defaults = _default_settings.get(project_name, {})
+        for setting_name, setting_value in project_defaults.iteritems():
+            self.set(project_settings, setting_name, setting_value)
+
+    def get(self, section, option, *args, **kwargs):
+        """Extend SafeConfigParser to try project_section before section.
+
+        Args:
+            See SafeConfigParser.
+        Returns:
+            See SafeConfigParser.
+        """
+        try:
+            return ConfigParser.SafeConfigParser.get(
+                self, "%s_%s" % (self._project_name, section), option,
+                *args, **kwargs
+            )
+        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+            return ConfigParser.SafeConfigParser.get(
+                self, section, option, *args, **kwargs
+            )
+
+    def items(self, section, *args, **kwargs):
+        """Extend SafeConfigParser to add project_section to section.
+
+        Args:
+            See SafeConfigParser.
+        Returns:
+            See SafeConfigParser.
+        """
+        project_items = []
+        has_project_section = False
+        top_items = []
+
+        # Get items from the project section
+        try:
+            project_items = ConfigParser.SafeConfigParser.items(
+                self, "%s_%s" % (self._project_name, section), *args, **kwargs
+            )
+            has_project_section = True
+        except ConfigParser.NoSectionError:
+            pass
+
+        # Get top-level items
+        try:
+            top_items = ConfigParser.SafeConfigParser.items(
+                self, section, *args, **kwargs
+            )
+        except ConfigParser.NoSectionError:
+            # If neither section exists raise the error on...
+            if not has_project_section:
+                raise
+
+        item_dict = dict(top_items)
+        item_dict.update(project_items)
+        return item_dict.items()
+
+def ReadGitAliases(fname):
+    """Read a git alias file. This is in the form used by git:
+
+    alias uboot  u-boot@lists.denx.de
+    alias wd     Wolfgang Denk <wd@denx.de>
+
+    Args:
+        fname: Filename to read
+    """
+    try:
+        fd = open(fname, 'r')
+    except IOError:
+        print "Warning: Cannot find alias file '%s'" % fname
+        return
+
+    re_line = re.compile('alias\s+(\S+)\s+(.*)')
+    for line in fd.readlines():
+        line = line.strip()
+        if not line or line[0] == '#':
+            continue
+
+        m = re_line.match(line)
+        if not m:
+            print "Warning: Alias file line '%s' not understood" % line
+            continue
+
+        list = alias.get(m.group(1), [])
+        for item in m.group(2).split(','):
+            item = item.strip()
+            if item:
+                list.append(item)
+        alias[m.group(1)] = list
+
+    fd.close()
+
+def CreatePatmanConfigFile(config_fname):
+    """Creates a config file under $(HOME)/.patman if it can't find one.
+
+    Args:
+        config_fname: Default config filename i.e., $(HOME)/.patman
+
+    Returns:
+        None
+    """
+    name = gitutil.GetDefaultUserName()
+    if name == None:
+        name = raw_input("Enter name: ")
+
+    email = gitutil.GetDefaultUserEmail()
+
+    if email == None:
+        email = raw_input("Enter email: ")
+
+    try:
+        f = open(config_fname, 'w')
+    except IOError:
+        print "Couldn't create patman config file\n"
+        raise
+
+    print >>f, "[alias]\nme: %s <%s>" % (name, email)
+    f.close();
+
+def _UpdateDefaults(parser, config):
+    """Update the given OptionParser defaults based on config.
+
+    We'll walk through all of the settings from the parser
+    For each setting we'll look for a default in the option parser.
+    If it's found we'll update the option parser default.
+
+    The idea here is that the .patman file should be able to update
+    defaults but that command line flags should still have the final
+    say.
+
+    Args:
+        parser: An instance of an OptionParser whose defaults will be
+            updated.
+        config: An instance of _ProjectConfigParser that we will query
+            for settings.
+    """
+    defaults = parser.get_default_values()
+    for name, val in config.items('settings'):
+        if hasattr(defaults, name):
+            default_val = getattr(defaults, name)
+            if isinstance(default_val, bool):
+                val = config.getboolean('settings', name)
+            elif isinstance(default_val, int):
+                val = config.getint('settings', name)
+            parser.set_default(name, val)
+        else:
+            print "WARNING: Unknown setting %s" % name
+
+def Setup(parser, project_name, config_fname=''):
+    """Set up the settings module by reading config files.
+
+    Args:
+        parser:         The parser to update
+        project_name:   Name of project that we're working on; we'll look
+            for sections named "project_section" as well.
+        config_fname:   Config filename to read ('' for default)
+    """
+    config = _ProjectConfigParser(project_name)
+    if config_fname == '':
+        config_fname = '%s/.patman' % os.getenv('HOME')
+
+    if not os.path.exists(config_fname):
+        print "No config file found ~/.patman\nCreating one...\n"
+        CreatePatmanConfigFile(config_fname)
+
+    config.read(config_fname)
+
+    for name, value in config.items('alias'):
+        alias[name] = value.split(',')
+
+    _UpdateDefaults(parser, config)
+
+# These are the aliases we understand, indexed by alias. Each member is a list.
+alias = {}
+
+if __name__ == "__main__":
+    import doctest
+
+    doctest.testmod()
diff --git a/marvell/uboot/tools/patman/terminal.py b/marvell/uboot/tools/patman/terminal.py
new file mode 100644
index 0000000..597d526
--- /dev/null
+++ b/marvell/uboot/tools/patman/terminal.py
@@ -0,0 +1,80 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+"""Terminal utilities
+
+This module handles terminal interaction including ANSI color codes.
+"""
+
+import os
+import sys
+
+# Selection of when we want our output to be colored
+COLOR_IF_TERMINAL, COLOR_ALWAYS, COLOR_NEVER = range(3)
+
+class Color(object):
+  """Conditionally wraps text in ANSI color escape sequences."""
+  BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
+  BOLD = -1
+  BRIGHT_START = '\033[1;%dm'
+  NORMAL_START = '\033[22;%dm'
+  BOLD_START = '\033[1m'
+  RESET = '\033[0m'
+
+  def __init__(self, colored=COLOR_IF_TERMINAL):
+    """Create a new Color object, optionally disabling color output.
+
+    Args:
+      enabled: True if color output should be enabled. If False then this
+        class will not add color codes at all.
+    """
+    self._enabled = (colored == COLOR_ALWAYS or
+        (colored == COLOR_IF_TERMINAL and os.isatty(sys.stdout.fileno())))
+
+  def Start(self, color, bright=True):
+    """Returns a start color code.
+
+    Args:
+      color: Color to use, .e.g BLACK, RED, etc.
+
+    Returns:
+      If color is enabled, returns an ANSI sequence to start the given color,
+      otherwise returns empty string
+    """
+    if self._enabled:
+        base = self.BRIGHT_START if bright else self.NORMAL_START
+        return base % (color + 30)
+    return ''
+
+  def Stop(self):
+    """Retruns a stop color code.
+
+    Returns:
+      If color is enabled, returns an ANSI color reset sequence, otherwise
+      returns empty string
+    """
+    if self._enabled:
+        return self.RESET
+    return ''
+
+  def Color(self, color, text, bright=True):
+    """Returns text with conditionally added color escape sequences.
+
+    Keyword arguments:
+      color: Text color -- one of the color constants defined in this class.
+      text: The text to color.
+
+    Returns:
+      If self._enabled is False, returns the original text. If it's True,
+      returns text with color escape sequences based on the value of color.
+    """
+    if not self._enabled:
+        return text
+    if color == self.BOLD:
+        start = self.BOLD_START
+    else:
+        base = self.BRIGHT_START if bright else self.NORMAL_START
+        start = base % (color + 30)
+    return start + text + self.RESET
diff --git a/marvell/uboot/tools/patman/test.py b/marvell/uboot/tools/patman/test.py
new file mode 100644
index 0000000..8fcfe53
--- /dev/null
+++ b/marvell/uboot/tools/patman/test.py
@@ -0,0 +1,242 @@
+#
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+import os
+import tempfile
+import unittest
+
+import checkpatch
+import gitutil
+import patchstream
+import series
+
+
+class TestPatch(unittest.TestCase):
+    """Test this program
+
+    TODO: Write tests for the rest of the functionality
+    """
+
+    def testBasic(self):
+        """Test basic filter operation"""
+        data='''
+
+From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Thu, 28 Apr 2011 09:58:51 -0700
+Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support
+
+This adds functions to enable/disable clocks and reset to on-chip peripherals.
+
+BUG=chromium-os:13875
+TEST=build U-Boot for Seaboard, boot
+
+Change-Id: I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413
+
+Review URL: http://codereview.chromium.org/6900006
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+---
+ arch/arm/cpu/armv7/tegra2/Makefile         |    2 +-
+ arch/arm/cpu/armv7/tegra2/ap20.c           |   57 ++----
+ arch/arm/cpu/armv7/tegra2/clock.c          |  163 +++++++++++++++++
+'''
+        expected='''
+
+From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Thu, 28 Apr 2011 09:58:51 -0700
+Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support
+
+This adds functions to enable/disable clocks and reset to on-chip peripherals.
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+---
+ arch/arm/cpu/armv7/tegra2/Makefile         |    2 +-
+ arch/arm/cpu/armv7/tegra2/ap20.c           |   57 ++----
+ arch/arm/cpu/armv7/tegra2/clock.c          |  163 +++++++++++++++++
+'''
+        out = ''
+        inhandle, inname = tempfile.mkstemp()
+        infd = os.fdopen(inhandle, 'w')
+        infd.write(data)
+        infd.close()
+
+        exphandle, expname = tempfile.mkstemp()
+        expfd = os.fdopen(exphandle, 'w')
+        expfd.write(expected)
+        expfd.close()
+
+        patchstream.FixPatch(None, inname, series.Series(), None)
+        rc = os.system('diff -u %s %s' % (inname, expname))
+        self.assertEqual(rc, 0)
+
+        os.remove(inname)
+        os.remove(expname)
+
+    def GetData(self, data_type):
+        data='''
+From 4924887af52713cabea78420eff03badea8f0035 Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Thu, 7 Apr 2011 10:14:41 -0700
+Subject: [PATCH 1/4] Add microsecond boot time measurement
+
+This defines the basics of a new boot time measurement feature. This allows
+logging of very accurate time measurements as the boot proceeds, by using
+an available microsecond counter.
+
+%s
+---
+ README              |   11 ++++++++
+ common/bootstage.c  |   50 ++++++++++++++++++++++++++++++++++++
+ include/bootstage.h |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ include/common.h    |    8 ++++++
+ 5 files changed, 141 insertions(+), 0 deletions(-)
+ create mode 100644 common/bootstage.c
+ create mode 100644 include/bootstage.h
+
+diff --git a/README b/README
+index 6f3748d..f9e4e65 100644
+--- a/README
++++ b/README
+@@ -2026,6 +2026,17 @@ The following options need to be configured:
+ 		example, some LED's) on your board. At the moment,
+ 		the following checkpoints are implemented:
+
++- Time boot progress
++		CONFIG_BOOTSTAGE
++
++		Define this option to enable microsecond boot stage timing
++		on supported platforms. For this to work your platform
++		needs to define a function timer_get_us() which returns the
++		number of microseconds since reset. This would normally
++		be done in your SOC or board timer.c file.
++
++		You can add calls to bootstage_mark() to set time markers.
++
+ - Standalone program support:
+ 		CONFIG_STANDALONE_LOAD_ADDR
+
+diff --git a/common/bootstage.c b/common/bootstage.c
+new file mode 100644
+index 0000000..2234c87
+--- /dev/null
++++ b/common/bootstage.c
+@@ -0,0 +1,39 @@
++/*
++ * Copyright (c) 2011, Google Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++
++/*
++ * This module records the progress of boot and arbitrary commands, and
++ * permits accurate timestamping of each. The records can optionally be
++ * passed to kernel in the ATAGs
++ */
++
++#include <common.h>
++
++
++struct bootstage_record {
++	uint32_t time_us;
++	const char *name;
++};
++
++static struct bootstage_record record[BOOTSTAGE_COUNT];
++
++uint32_t bootstage_mark(enum bootstage_id id, const char *name)
++{
++	struct bootstage_record *rec = &record[id];
++
++	/* Only record the first event for each */
++%sif (!rec->name) {
++		rec->time_us = (uint32_t)timer_get_us();
++		rec->name = name;
++	}
++	if (!rec->name &&
++	%ssomething_else) {
++		rec->time_us = (uint32_t)timer_get_us();
++		rec->name = name;
++	}
++%sreturn rec->time_us;
++}
+--
+1.7.3.1
+'''
+        signoff = 'Signed-off-by: Simon Glass <sjg@chromium.org>\n'
+        tab = '	'
+        indent = '    '
+        if data_type == 'good':
+            pass
+        elif data_type == 'no-signoff':
+            signoff = ''
+        elif data_type == 'spaces':
+            tab = '   '
+        elif data_type == 'indent':
+            indent = tab
+        else:
+            print 'not implemented'
+        return data % (signoff, tab, indent, tab)
+
+    def SetupData(self, data_type):
+        inhandle, inname = tempfile.mkstemp()
+        infd = os.fdopen(inhandle, 'w')
+        data = self.GetData(data_type)
+        infd.write(data)
+        infd.close()
+        return inname
+
+    def testGood(self):
+        """Test checkpatch operation"""
+        inf = self.SetupData('good')
+        result = checkpatch.CheckPatch(inf)
+        self.assertEqual(result.ok, True)
+        self.assertEqual(result.problems, [])
+        self.assertEqual(result.errors, 0)
+        self.assertEqual(result.warnings, 0)
+        self.assertEqual(result.checks, 0)
+        self.assertEqual(result.lines, 67)
+        os.remove(inf)
+
+    def testNoSignoff(self):
+        inf = self.SetupData('no-signoff')
+        result = checkpatch.CheckPatch(inf)
+        self.assertEqual(result.ok, False)
+        self.assertEqual(len(result.problems), 1)
+        self.assertEqual(result.errors, 1)
+        self.assertEqual(result.warnings, 0)
+        self.assertEqual(result.checks, 0)
+        self.assertEqual(result.lines, 67)
+        os.remove(inf)
+
+    def testSpaces(self):
+        inf = self.SetupData('spaces')
+        result = checkpatch.CheckPatch(inf)
+        self.assertEqual(result.ok, False)
+        self.assertEqual(len(result.problems), 1)
+        self.assertEqual(result.errors, 0)
+        self.assertEqual(result.warnings, 1)
+        self.assertEqual(result.checks, 0)
+        self.assertEqual(result.lines, 67)
+        os.remove(inf)
+
+    def testIndent(self):
+        inf = self.SetupData('indent')
+        result = checkpatch.CheckPatch(inf)
+        self.assertEqual(result.ok, False)
+        self.assertEqual(len(result.problems), 1)
+        self.assertEqual(result.errors, 0)
+        self.assertEqual(result.warnings, 0)
+        self.assertEqual(result.checks, 1)
+        self.assertEqual(result.lines, 67)
+        os.remove(inf)
+
+
+if __name__ == "__main__":
+    unittest.main()
+    gitutil.RunTests()
diff --git a/marvell/uboot/tools/pblimage.c b/marvell/uboot/tools/pblimage.c
new file mode 100644
index 0000000..ef3d7f6
--- /dev/null
+++ b/marvell/uboot/tools/pblimage.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include "imagetool.h"
+#include <image.h>
+#include "pblimage.h"
+
+/*
+ * Initialize to an invalid value.
+ */
+static uint32_t next_pbl_cmd = 0x82000000;
+/*
+ * need to store all bytes in memory for calculating crc32, then write the
+ * bytes to image file for PBL boot.
+ */
+static unsigned char mem_buf[1000000];
+static unsigned char *pmem_buf = mem_buf;
+static int pbl_size;
+static char *fname = "Unknown";
+static int lineno = -1;
+static struct pbl_header pblimage_header;
+
+static union
+{
+	char c[4];
+	unsigned char l;
+} endian_test = { {'l', '?', '?', 'b'} };
+
+#define ENDIANNESS ((char)endian_test.l)
+
+/*
+ * The PBL can load up to 64 bytes at a time, so we split the U-Boot
+ * image into 64 byte chunks. PBL needs a command for each piece, of
+ * the form "81xxxxxx", where "xxxxxx" is the offset. Calculate the
+ * start offset by subtracting the size of the u-boot image from the
+ * top of the allowable 24-bit range.
+ */
+static void init_next_pbl_cmd(FILE *fp_uboot)
+{
+	struct stat st;
+	int fd = fileno(fp_uboot);
+
+	if (fstat(fd, &st) == -1) {
+		printf("Error: Could not determine u-boot image size. %s\n",
+			strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	next_pbl_cmd = 0x82000000 - st.st_size;
+}
+
+static void generate_pbl_cmd(void)
+{
+	uint32_t val = next_pbl_cmd;
+	next_pbl_cmd += 0x40;
+	int i;
+
+	for (i = 3; i >= 0; i--) {
+		*pmem_buf++ = (val >> (i * 8)) & 0xff;
+		pbl_size++;
+	}
+}
+
+static void pbl_fget(size_t size, FILE *stream)
+{
+	unsigned char c;
+	int c_temp;
+
+	while (size && (c_temp = fgetc(stream)) != EOF) {
+		c = (unsigned char)c_temp;
+		*pmem_buf++ = c;
+		pbl_size++;
+		size--;
+	}
+}
+
+/* load split u-boot with PBI command 81xxxxxx. */
+static void load_uboot(FILE *fp_uboot)
+{
+	init_next_pbl_cmd(fp_uboot);
+	while (next_pbl_cmd < 0x82000000) {
+		generate_pbl_cmd();
+		pbl_fget(64, fp_uboot);
+	}
+}
+
+static void check_get_hexval(char *token)
+{
+	uint32_t hexval;
+	int i;
+
+	if (!sscanf(token, "%x", &hexval)) {
+		printf("Error:%s[%d] - Invalid hex data(%s)\n", fname,
+			lineno, token);
+		exit(EXIT_FAILURE);
+	}
+	for (i = 3; i >= 0; i--) {
+		*pmem_buf++ = (hexval >> (i * 8)) & 0xff;
+		pbl_size++;
+	}
+}
+
+static void pbl_parser(char *name)
+{
+	FILE *fd = NULL;
+	char *line = NULL;
+	char *token, *saveptr1, *saveptr2;
+	size_t len = 0;
+
+	fname = name;
+	fd = fopen(name, "r");
+	if (fd == NULL) {
+		printf("Error:%s - Can't open\n", fname);
+		exit(EXIT_FAILURE);
+	}
+
+	while ((getline(&line, &len, fd)) > 0) {
+		lineno++;
+		token = strtok_r(line, "\r\n", &saveptr1);
+		/* drop all lines with zero tokens (= empty lines) */
+		if (token == NULL)
+			continue;
+		for (line = token;; line = NULL) {
+			token = strtok_r(line, " \t", &saveptr2);
+			if (token == NULL)
+				break;
+			/* Drop all text starting with '#' as comments */
+			if (token[0] == '#')
+				break;
+			check_get_hexval(token);
+		}
+	}
+	if (line)
+		free(line);
+	fclose(fd);
+}
+
+static uint32_t crc_table[256];
+
+static void make_crc_table(void)
+{
+	uint32_t mask;
+	int i, j;
+	uint32_t poly; /* polynomial exclusive-or pattern */
+
+	/*
+	 * the polynomial used by PBL is 1 + x1 + x2 + x4 + x5 + x7 + x8 + x10
+	 * + x11 + x12 + x16 + x22 + x23 + x26 + x32.
+	 */
+	poly = 0x04c11db7;
+
+	for (i = 0; i < 256; i++) {
+		mask = i << 24;
+		for (j = 0; j < 8; j++) {
+			if (mask & 0x80000000)
+				mask = (mask << 1) ^ poly;
+			else
+				mask <<= 1;
+		}
+		crc_table[i] = mask;
+	}
+}
+
+unsigned long pbl_crc32(unsigned long crc, const char *buf, uint32_t len)
+{
+	uint32_t crc32_val = 0xffffffff;
+	uint32_t xor = 0x0;
+	int i;
+
+	make_crc_table();
+
+	for (i = 0; i < len; i++)
+		crc32_val = (crc32_val << 8) ^
+			crc_table[(crc32_val >> 24) ^ (*buf++ & 0xff)];
+
+	crc32_val = crc32_val ^ xor;
+	if (crc32_val < 0) {
+		crc32_val += 0xffffffff;
+		crc32_val += 1;
+	}
+	return crc32_val;
+}
+
+static uint32_t reverse_byte(uint32_t val)
+{
+	uint32_t temp;
+	unsigned char *p1;
+	int j;
+
+	temp = val;
+	p1 = (unsigned char *)&temp;
+	for (j = 3; j >= 0; j--)
+		*p1++ = (val >> (j * 8)) & 0xff;
+	return temp;
+}
+
+/* write end command and crc command to memory. */
+static void add_end_cmd(void)
+{
+	uint32_t pbl_end_cmd[4] = {0x09138000, 0x00000000,
+		0x091380c0, 0x00000000};
+	uint32_t crc32_pbl;
+	int i;
+	unsigned char *p = (unsigned char *)&pbl_end_cmd;
+
+	if (ENDIANNESS == 'l') {
+		for (i = 0; i < 4; i++)
+			pbl_end_cmd[i] = reverse_byte(pbl_end_cmd[i]);
+	}
+
+	for (i = 0; i < 16; i++) {
+		*pmem_buf++ = *p++;
+		pbl_size++;
+	}
+
+	/* Add PBI CRC command. */
+	*pmem_buf++ = 0x08;
+	*pmem_buf++ = 0x13;
+	*pmem_buf++ = 0x80;
+	*pmem_buf++ = 0x40;
+	pbl_size += 4;
+
+	/* calculated CRC32 and write it to memory. */
+	crc32_pbl = pbl_crc32(0, (const char *)mem_buf, pbl_size);
+	*pmem_buf++ = (crc32_pbl >> 24) & 0xff;
+	*pmem_buf++ = (crc32_pbl >> 16) & 0xff;
+	*pmem_buf++ = (crc32_pbl >> 8) & 0xff;
+	*pmem_buf++ = (crc32_pbl) & 0xff;
+	pbl_size += 4;
+
+	if ((pbl_size % 16) != 0) {
+		for (i = 0; i < 8; i++) {
+			*pmem_buf++ = 0x0;
+			pbl_size++;
+		}
+	}
+	if ((pbl_size % 16 != 0)) {
+		printf("Error: Bad size of image file\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+void pbl_load_uboot(int ifd, struct image_tool_params *params)
+{
+	FILE *fp_uboot;
+	int size;
+
+	/* parse the rcw.cfg file. */
+	pbl_parser(params->imagename);
+
+	/* parse the pbi.cfg file. */
+	pbl_parser(params->imagename2);
+
+	fp_uboot = fopen(params->datafile, "r");
+	if (fp_uboot == NULL) {
+		printf("Error: %s open failed\n", params->datafile);
+		exit(EXIT_FAILURE);
+	}
+
+	load_uboot(fp_uboot);
+	add_end_cmd();
+	fclose(fp_uboot);
+	lseek(ifd, 0, SEEK_SET);
+
+	size = pbl_size;
+	if (write(ifd, (const void *)&mem_buf, size) != size) {
+		fprintf(stderr, "Write error on %s: %s\n",
+			params->imagefile, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+}
+
+static int pblimage_check_image_types(uint8_t type)
+{
+	if (type == IH_TYPE_PBLIMAGE)
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+}
+
+static int pblimage_verify_header(unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	struct pbl_header *pbl_hdr = (struct pbl_header *) ptr;
+
+	/* Only a few checks can be done: search for magic numbers */
+	if (ENDIANNESS == 'l') {
+		if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE))
+			return -FDT_ERR_BADSTRUCTURE;
+
+		if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER))
+			return -FDT_ERR_BADSTRUCTURE;
+	} else {
+		if (pbl_hdr->preamble != RCW_PREAMBLE)
+			return -FDT_ERR_BADSTRUCTURE;
+
+		if (pbl_hdr->rcwheader != RCW_HEADER)
+			return -FDT_ERR_BADSTRUCTURE;
+	}
+	return 0;
+}
+
+static void pblimage_print_header(const void *ptr)
+{
+	printf("Image Type:   Freescale PBL Boot Image\n");
+}
+
+static void pblimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+	/*nothing need to do, pbl_load_uboot takes care of whole file. */
+}
+
+/* pblimage parameters */
+static struct image_type_params pblimage_params = {
+	.name		= "Freescale PBL Boot Image support",
+	.header_size	= sizeof(struct pbl_header),
+	.hdr		= (void *)&pblimage_header,
+	.check_image_type = pblimage_check_image_types,
+	.verify_header	= pblimage_verify_header,
+	.print_header	= pblimage_print_header,
+	.set_header	= pblimage_set_header,
+};
+
+void init_pbl_image_type(void)
+{
+	pbl_size = 0;
+	register_image_type(&pblimage_params);
+}
diff --git a/marvell/uboot/tools/pblimage.h b/marvell/uboot/tools/pblimage.h
new file mode 100644
index 0000000..12bece5
--- /dev/null
+++ b/marvell/uboot/tools/pblimage.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef PBLIMAGE_H
+#define PBLIMAGE_H
+
+#define RCW_BYTES	64
+#define RCW_PREAMBLE	0xaa55aa55
+#define RCW_HEADER	0x010e0100
+
+struct pbl_header {
+	uint32_t preamble;
+	uint32_t rcwheader;
+	uint8_t rcw_data[RCW_BYTES];
+};
+
+#endif /* PBLIMAGE_H */
diff --git a/marvell/uboot/tools/proftool.c b/marvell/uboot/tools/proftool.c
new file mode 100644
index 0000000..3482951
--- /dev/null
+++ b/marvell/uboot/tools/proftool.c
@@ -0,0 +1,598 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* Decode and dump U-Boot profiling information */
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+#include <compiler.h>
+#include <trace.h>
+
+#define MAX_LINE_LEN 500
+
+enum {
+	FUNCF_TRACE	= 1 << 0,	/* Include this function in trace */
+};
+
+struct func_info {
+	unsigned long offset;
+	const char *name;
+	unsigned long code_size;
+	unsigned long call_count;
+	unsigned flags;
+	/* the section this function is in */
+	struct objsection_info *objsection;
+};
+
+enum trace_line_type {
+	TRACE_LINE_INCLUDE,
+	TRACE_LINE_EXCLUDE,
+};
+
+struct trace_configline_info {
+	struct trace_configline_info *next;
+	enum trace_line_type type;
+	const char *name;	/* identifier name / wildcard */
+	regex_t regex;		/* Regex to use if name starts with / */
+};
+
+/* The contents of the trace config file */
+struct trace_configline_info *trace_config_head;
+
+struct func_info *func_list;
+int func_count;
+struct trace_call *call_list;
+int call_count;
+int verbose;	/* Verbosity level 0=none, 1=warn, 2=notice, 3=info, 4=debug */
+unsigned long text_offset;		/* text address of first function */
+
+static void outf(int level, const char *fmt, ...)
+		__attribute__ ((format (__printf__, 2, 3)));
+#define error(fmt, b...) outf(0, fmt, ##b)
+#define warn(fmt, b...) outf(1, fmt, ##b)
+#define notice(fmt, b...) outf(2, fmt, ##b)
+#define info(fmt, b...) outf(3, fmt, ##b)
+#define debug(fmt, b...) outf(4, fmt, ##b)
+
+
+static void outf(int level, const char *fmt, ...)
+{
+	if (verbose >= level) {
+		va_list args;
+
+		va_start(args, fmt);
+		vfprintf(stderr, fmt, args);
+		va_end(args);
+	}
+}
+
+static void usage(void)
+{
+	fprintf(stderr,
+		"Usage: proftool -cds -v3 <cmd> <profdata>\n"
+		"\n"
+		"Commands\n"
+		"   dump-ftrace\t\tDump out textual data in ftrace format\n"
+		"\n"
+		"Options:\n"
+		"   -m <map>\tSpecify Systen.map file\n"
+		"   -t <trace>\tSpecific trace data file (from U-Boot)\n"
+		"   -v <0-4>\tSpecify verbosity\n");
+	exit(EXIT_FAILURE);
+}
+
+static int h_cmp_offset(const void *v1, const void *v2)
+{
+	const struct func_info *f1 = v1, *f2 = v2;
+
+	return (f1->offset / FUNC_SITE_SIZE) - (f2->offset / FUNC_SITE_SIZE);
+}
+
+static int read_system_map(FILE *fin)
+{
+	unsigned long offset, start = 0;
+	struct func_info *func;
+	char buff[MAX_LINE_LEN];
+	char symtype;
+	char symname[MAX_LINE_LEN + 1];
+	int linenum;
+	int alloced;
+
+	for (linenum = 1, alloced = func_count = 0;; linenum++) {
+		int fields = 0;
+
+		if (fgets(buff, sizeof(buff), fin))
+			fields = sscanf(buff, "%lx %c %100s\n", &offset,
+				&symtype, symname);
+		if (fields == 2) {
+			continue;
+		} else if (feof(fin)) {
+			break;
+		} else if (fields < 2) {
+			error("Map file line %d: invalid format\n", linenum);
+			return 1;
+		}
+
+		/* Must be a text symbol */
+		symtype = tolower(symtype);
+		if (symtype != 't' && symtype != 'w')
+			continue;
+
+		if (func_count == alloced) {
+			alloced += 256;
+			func_list = realloc(func_list,
+					sizeof(struct func_info) * alloced);
+			assert(func_list);
+		}
+		if (!func_count)
+			start = offset;
+
+		func = &func_list[func_count++];
+		memset(func, '\0', sizeof(*func));
+		func->offset = offset - start;
+		func->name = strdup(symname);
+		func->flags = FUNCF_TRACE;	/* trace by default */
+
+		/* Update previous function's code size */
+		if (func_count > 1)
+			func[-1].code_size = func->offset - func[-1].offset;
+	}
+	notice("%d functions found in map file\n", func_count);
+	text_offset = start;
+	return 0;
+}
+
+static int read_data(FILE *fin, void *buff, int size)
+{
+	int err;
+
+	err = fread(buff, 1, size, fin);
+	if (!err)
+		return 1;
+	if (err != size) {
+		error("Cannot read profile file at pos %ld\n", ftell(fin));
+		return -1;
+	}
+	return 0;
+}
+
+static struct func_info *find_func_by_offset(uint32_t offset)
+{
+	struct func_info key, *found;
+
+	key.offset = offset;
+	found = bsearch(&key, func_list, func_count, sizeof(struct func_info),
+			h_cmp_offset);
+
+	return found;
+}
+
+/* This finds the function which contains the given offset */
+static struct func_info *find_caller_by_offset(uint32_t offset)
+{
+	int low;	/* least function that could be a match */
+	int high;	/* greated function that could be a match */
+	struct func_info key;
+
+	low = 0;
+	high = func_count - 1;
+	key.offset = offset;
+	while (high > low + 1) {
+		int mid = (low + high) / 2;
+		int result;
+
+		result = h_cmp_offset(&key, &func_list[mid]);
+		if (result > 0)
+			low = mid;
+		else if (result < 0)
+			high = mid;
+		else
+			return &func_list[mid];
+	}
+
+	return low >= 0 ? &func_list[low] : NULL;
+}
+
+static int read_calls(FILE *fin, int count)
+{
+	struct trace_call *call_data;
+	int i;
+
+	notice("call count: %d\n", count);
+	call_list = (struct trace_call *)calloc(count, sizeof(*call_data));
+	if (!call_list) {
+		error("Cannot allocate call_list\n");
+		return -1;
+	}
+	call_count = count;
+
+	call_data = call_list;
+	for (i = 0; i < count; i++, call_data++) {
+		if (read_data(fin, call_data, sizeof(*call_data)))
+			return 1;
+	}
+	return 0;
+}
+
+static int read_profile(FILE *fin, int *not_found)
+{
+	struct trace_output_hdr hdr;
+
+	*not_found = 0;
+	while (!feof(fin)) {
+		int err;
+
+		err = read_data(fin, &hdr, sizeof(hdr));
+		if (err == 1)
+			break; /* EOF */
+		else if (err)
+			return 1;
+
+		switch (hdr.type) {
+		case TRACE_CHUNK_FUNCS:
+			/* Ignored at present */
+			break;
+
+		case TRACE_CHUNK_CALLS:
+			if (read_calls(fin, hdr.rec_count))
+				return 1;
+			break;
+		}
+	}
+	return 0;
+}
+
+static int read_map_file(const char *fname)
+{
+	FILE *fmap;
+	int err = 0;
+
+	fmap = fopen(fname, "r");
+	if (!fmap) {
+		error("Cannot open map file '%s'\n", fname);
+		return 1;
+	}
+	if (fmap) {
+		err = read_system_map(fmap);
+		fclose(fmap);
+	}
+	return err;
+}
+
+static int read_profile_file(const char *fname)
+{
+	int not_found = INT_MAX;
+	FILE *fprof;
+	int err;
+
+	fprof = fopen(fname, "rb");
+	if (!fprof) {
+		error("Cannot open profile data file '%s'\n",
+		      fname);
+		return 1;
+	} else {
+		err = read_profile(fprof, &not_found);
+		fclose(fprof);
+		if (err)
+			return err;
+
+		if (not_found) {
+			warn("%d profile functions could not be found in the map file - are you sure that your profile data and map file correspond?\n",
+			     not_found);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int regex_report_error(regex_t *regex, int err, const char *op,
+			      const char *name)
+{
+	char buf[200];
+
+	regerror(err, regex, buf, sizeof(buf));
+	error("Regex error '%s' in %s '%s'\n", buf, op, name);
+	return -1;
+}
+
+static void check_trace_config_line(struct trace_configline_info *item)
+{
+	struct func_info *func, *end;
+	int err;
+
+	debug("Checking trace config line '%s'\n", item->name);
+	for (func = func_list, end = func + func_count; func < end; func++) {
+		err = regexec(&item->regex, func->name, 0, NULL, 0);
+		debug("   - regex '%s', string '%s': %d\n", item->name,
+		      func->name, err);
+		if (err == REG_NOMATCH)
+			continue;
+
+		if (err) {
+			regex_report_error(&item->regex, err, "match",
+					   item->name);
+			break;
+		}
+
+		/* It matches, so perform the action */
+		switch (item->type) {
+		case TRACE_LINE_INCLUDE:
+			info("      include %s at %lx\n", func->name,
+			     text_offset + func->offset);
+			func->flags |= FUNCF_TRACE;
+			break;
+
+		case TRACE_LINE_EXCLUDE:
+			info("      exclude %s at %lx\n", func->name,
+			     text_offset + func->offset);
+			func->flags &= ~FUNCF_TRACE;
+			break;
+		}
+	}
+}
+
+static void check_trace_config(void)
+{
+	struct trace_configline_info *line;
+
+	for (line = trace_config_head; line; line = line->next)
+		check_trace_config_line(line);
+}
+
+/**
+ * Check the functions to see if they each have an objsection. If not, then
+ * the linker must have eliminated them.
+ */
+static void check_functions(void)
+{
+	struct func_info *func, *end;
+	unsigned long removed_code_size = 0;
+	int not_found = 0;
+
+	/* Look for missing functions */
+	for (func = func_list, end = func + func_count; func < end; func++) {
+		if (!func->objsection) {
+			removed_code_size += func->code_size;
+			not_found++;
+		}
+	}
+
+	/* Figure out what functions we want to trace */
+	check_trace_config();
+
+	warn("%d functions removed by linker, %ld code size\n",
+	     not_found, removed_code_size);
+}
+
+static int read_trace_config(FILE *fin)
+{
+	char buff[200];
+	int linenum = 0;
+	struct trace_configline_info **tailp = &trace_config_head;
+
+	while (fgets(buff, sizeof(buff), fin)) {
+		int len = strlen(buff);
+		struct trace_configline_info *line;
+		char *saveptr;
+		char *s, *tok;
+		int err;
+
+		linenum++;
+		if (len && buff[len - 1] == '\n')
+			buff[len - 1] = '\0';
+
+		/* skip blank lines and comments */
+		for (s = buff; *s == ' ' || *s == '\t'; s++)
+			;
+		if (!*s || *s == '#')
+			continue;
+
+		line = (struct trace_configline_info *)calloc(1,
+							      sizeof(*line));
+		if (!line) {
+			error("Cannot allocate config line\n");
+			return -1;
+		}
+
+		tok = strtok_r(s, " \t", &saveptr);
+		if (!tok) {
+			error("Invalid trace config data on line %d\n",
+			      linenum);
+			return -1;
+		}
+		if (0 == strcmp(tok, "include-func")) {
+			line->type = TRACE_LINE_INCLUDE;
+		} else if (0 == strcmp(tok, "exclude-func")) {
+			line->type = TRACE_LINE_EXCLUDE;
+		} else {
+			error("Unknown command in trace config data line %d\n",
+			      linenum);
+			return -1;
+		}
+
+		tok = strtok_r(NULL, " \t", &saveptr);
+		if (!tok) {
+			error("Missing pattern in trace config data line %d\n",
+			      linenum);
+			return -1;
+		}
+
+		err = regcomp(&line->regex, tok, REG_NOSUB);
+		if (err) {
+			free(line);
+			return regex_report_error(&line->regex, err, "compile",
+						  tok);
+		}
+
+		/* link this new one to the end of the list */
+		line->name = strdup(tok);
+		line->next = NULL;
+		*tailp = line;
+		tailp = &line->next;
+	}
+
+	if (!feof(fin)) {
+		error("Cannot read from trace config file at position %ld\n",
+		      ftell(fin));
+		return -1;
+	}
+	return 0;
+}
+
+static int read_trace_config_file(const char *fname)
+{
+	FILE *fin;
+	int err;
+
+	fin = fopen(fname, "r");
+	if (!fin) {
+		error("Cannot open trace_config file '%s'\n", fname);
+		return -1;
+	}
+	err = read_trace_config(fin);
+	fclose(fin);
+	return err;
+}
+
+static void out_func(ulong func_offset, int is_caller, const char *suffix)
+{
+	struct func_info *func;
+
+	func = (is_caller ? find_caller_by_offset : find_func_by_offset)
+		(func_offset);
+
+	if (func)
+		printf("%s%s", func->name, suffix);
+	else
+		printf("%lx%s", func_offset, suffix);
+}
+
+/*
+ * # tracer: function
+ * #
+ * #           TASK-PID   CPU#    TIMESTAMP  FUNCTION
+ * #              | |      |          |         |
+ * #           bash-4251  [01] 10152.583854: path_put <-path_walk
+ * #           bash-4251  [01] 10152.583855: dput <-path_put
+ * #           bash-4251  [01] 10152.583855: _atomic_dec_and_lock <-dput
+ */
+static int make_ftrace(void)
+{
+	struct trace_call *call;
+	int missing_count = 0, skip_count = 0;
+	int i;
+
+	printf("# tracer: ftrace\n"
+		"#\n"
+		"#           TASK-PID   CPU#    TIMESTAMP  FUNCTION\n"
+		"#              | |      |          |         |\n");
+	for (i = 0, call = call_list; i < call_count; i++, call++) {
+		struct func_info *func = find_func_by_offset(call->func);
+		ulong time = call->flags & FUNCF_TIMESTAMP_MASK;
+
+		if (TRACE_CALL_TYPE(call) != FUNCF_ENTRY &&
+		    TRACE_CALL_TYPE(call) != FUNCF_EXIT)
+			continue;
+		if (!func) {
+			warn("Cannot find function at %lx\n",
+			     text_offset + call->func);
+			missing_count++;
+			continue;
+		}
+
+		if (!(func->flags & FUNCF_TRACE)) {
+			debug("Funcion '%s' is excluded from trace\n",
+			      func->name);
+			skip_count++;
+			continue;
+		}
+
+		printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1,
+		       time / 1000000, time % 1000000);
+
+		out_func(call->func, 0, " <- ");
+		out_func(call->caller, 1, "\n");
+	}
+	info("ftrace: %d functions not found, %d excluded\n", missing_count,
+	     skip_count);
+
+	return 0;
+}
+
+static int prof_tool(int argc, char * const argv[],
+		     const char *prof_fname, const char *map_fname,
+		     const char *trace_config_fname)
+{
+	int err = 0;
+
+	if (read_map_file(map_fname))
+		return -1;
+	if (prof_fname && read_profile_file(prof_fname))
+		return -1;
+	if (trace_config_fname && read_trace_config_file(trace_config_fname))
+		return -1;
+
+	check_functions();
+
+	for (; argc; argc--, argv++) {
+		const char *cmd = *argv;
+
+		if (0 == strcmp(cmd, "dump-ftrace"))
+			err = make_ftrace();
+		else
+			warn("Unknown command '%s'\n", cmd);
+	}
+
+	return err;
+}
+
+int main(int argc, char *argv[])
+{
+	const char *map_fname = "System.map";
+	const char *prof_fname = NULL;
+	const char *trace_config_fname = NULL;
+	int opt;
+
+	verbose = 2;
+	while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) {
+		switch (opt) {
+		case 'm':
+			map_fname = optarg;
+			break;
+
+		case 'p':
+			prof_fname = optarg;
+			break;
+
+		case 't':
+			trace_config_fname = optarg;
+			break;
+
+		case 'v':
+			verbose = atoi(optarg);
+			break;
+
+		default:
+			usage();
+		}
+	}
+	argc -= optind; argv += optind;
+	if (argc < 1)
+		usage();
+
+	debug("Debug enabled\n");
+	return prof_tool(argc, argv, prof_fname, map_fname,
+			 trace_config_fname);
+}
diff --git a/marvell/uboot/tools/reformat.py b/marvell/uboot/tools/reformat.py
new file mode 100755
index 0000000..61306d0
--- /dev/null
+++ b/marvell/uboot/tools/reformat.py
@@ -0,0 +1,132 @@
+#! /usr/bin/python
+########################################################################
+#
+# reorder and reformat a file in columns
+#
+# this utility takes lines from its standard input and reproduces them,
+# partially reordered and reformatted, on its standard output.
+#
+# It has the same effect as a 'sort | column -t', with the exception
+# that empty lines, as well as lines which start with a '#' sign, are
+# not affected, i.e. they keep their position and formatting, and act
+# as separators, i.e. the parts before and after them are each sorted
+# separately (but overall field widths are computed across the whole
+# input).
+#
+# Options:
+#   -i:
+#   --ignore-case:
+#	Do not consider case when sorting.
+#   -d:
+#   --default:
+#	What to chage empty fields to.
+#    -s <N>:
+#    --split=<N>:
+#       Treat only the first N whitespace sequences as separators.
+#       line content after the Nth separator will count as only one
+#       field even if it contains whitespace.
+#       Example : '-s 2' causes input 'a b c d e' to be split into
+#       three fields, 'a', 'b', and 'c d e'.
+#
+# boards.cfg requires -ids 6.
+#
+########################################################################
+
+import sys, getopt, locale
+
+# ensure we sort using the C locale.
+
+locale.setlocale(locale.LC_ALL, 'C')
+
+# check options
+
+maxsplit = 0
+ignore_case = 0
+default_field =''
+
+try:
+	opts, args = getopt.getopt(sys.argv[1:], "id:s:",
+		["ignore-case","default","split="])
+except getopt.GetoptError as err:
+	print str(err) # will print something like "option -a not recognized"
+	sys.exit(2)
+
+for o, a in opts:
+	if o in ("-s", "--split"):
+		maxsplit = eval(a)
+	elif o in ("-i", "--ignore-case"):
+		ignore_case = 1
+	elif o in ("-d", "--default"):
+		default_field = a
+	else:
+		assert False, "unhandled option"
+
+# collect all lines from standard input and, for the ones which must be
+# reformatted and sorted, count their fields and compute each field's
+# maximum size
+
+input_lines = []
+field_width = []
+
+for line in sys.stdin:
+	# remove final end of line
+	input_line = line.strip('\n')
+	if (len(input_line)>0) and (input_line[0] != '#'):
+		# sortable line: split into fields
+		fields = input_line.split(None,maxsplit)
+		# if there are new fields, top up field_widths
+		for f in range(len(field_width), len(fields)):
+			field_width.append(0)
+		# compute the maximum witdh of each field
+		for f in range(len(fields)):
+			field_width[f] = max(field_width[f],len(fields[f]))
+	# collect the line for next stage
+	input_lines.append(input_line)
+
+# run through collected input lines, collect the ones which must be
+# reformatted and sorted, and whenever a non-reformattable, non-sortable
+# line is met, sort the collected lines before it and append them to the
+# output lines, then add the non-sortable line too.
+
+output_lines = []
+sortable_lines = []
+for input_line in input_lines:
+	if (len(input_line)>0) and (input_line[0] != '#'):
+		# this line should be reformatted and sorted
+		input_fields = input_line.split(None,maxsplit)
+		output_fields = [];
+		# reformat each field to this field's column width
+		for f in range(len(input_fields)):
+			output_field = input_fields[f];
+			output_fields.append(output_field.ljust(field_width[f]))
+		# any missing field is set to default if it exists
+		if default_field != '':
+			for f in range(len(input_fields),len(field_width)):
+				output_fields.append(default_field.ljust(field_width[f]))
+		# join fields using two spaces, like column -t would
+		output_line = '  '.join(output_fields);
+		# collect line for later
+		sortable_lines.append(output_line)
+	else:
+		# this line is non-sortable
+		# sort collected sortable lines
+		if ignore_case!=0:
+			sortable_lines.sort(key=lambda x: str.lower(locale.strxfrm(x)))
+		else:
+			sortable_lines.sort(key=lambda x: locale.strxfrm(x))
+		# append sortable lines to the final output
+		output_lines.extend(sortable_lines)
+		sortable_lines = []
+		# append non-sortable line to the final output
+		output_lines.append(input_line)
+# maybe we had sortable lines pending, so append them to the final output
+if ignore_case!=0:
+	sortable_lines.sort(key=lambda x: str.lower(locale.strxfrm(x)))
+else:
+	sortable_lines.sort(key=lambda x: locale.strxfrm(x))
+output_lines.extend(sortable_lines)
+
+# run through output lines and print them, except rightmost whitespace
+
+for output_line in output_lines:
+	print output_line.rstrip()
diff --git a/marvell/uboot/tools/relocate-rela.c b/marvell/uboot/tools/relocate-rela.c
new file mode 100644
index 0000000..93b4c39
--- /dev/null
+++ b/marvell/uboot/tools/relocate-rela.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+ BSD-2-Clause
+ *
+ * 64-bit and little-endian target only until we need to support a different
+ * arch that needs this.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef R_AARCH64_RELATIVE
+#define R_AARCH64_RELATIVE	1027
+#endif
+
+static const bool debug_en;
+
+static void debug(const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	if (debug_en)
+		vprintf(fmt, args);
+}
+
+static bool supported_rela(Elf64_Rela *rela)
+{
+	uint64_t mask = 0xffffffffULL; /* would be different on 32-bit */
+	uint32_t type = rela->r_info & mask;
+
+	switch (type) {
+#ifdef R_AARCH64_RELATIVE
+	case R_AARCH64_RELATIVE:
+		return true;
+#endif
+	default:
+		fprintf(stderr, "warning: unsupported relocation type %"
+				PRIu32 " at %" PRIx64 "\n",
+			type, rela->r_offset);
+
+		return false;
+	}
+}
+
+static inline uint64_t swap64(uint64_t val)
+{
+	return ((val >> 56) & 0x00000000000000ffULL) |
+	       ((val >> 40) & 0x000000000000ff00ULL) |
+	       ((val >> 24) & 0x0000000000ff0000ULL) |
+	       ((val >>  8) & 0x00000000ff000000ULL) |
+	       ((val <<  8) & 0x000000ff00000000ULL) |
+	       ((val << 24) & 0x0000ff0000000000ULL) |
+	       ((val << 40) & 0x00ff000000000000ULL) |
+	       ((val << 56) & 0xff00000000000000ULL);
+}
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static inline uint64_t be64(uint64_t val)
+{
+	return swap64(val);
+}
+
+static inline uint64_t le64(uint64_t val)
+{
+	return val;
+}
+#else
+static inline uint64_t le64(uint64_t val)
+{
+	return swap64(val);
+}
+
+static inline uint64_t be64(uint64_t val)
+{
+	return val;
+}
+#endif
+
+static bool read_num(const char *str, uint64_t *num)
+{
+	char *endptr;
+	*num = strtoull(str, &endptr, 16);
+	return str[0] && !endptr[0];
+}
+
+int main(int argc, char **argv)
+{
+	FILE *f;
+	int i, num;
+	uint64_t rela_start, rela_end, text_base;
+
+	if (argc != 5) {
+		fprintf(stderr, "Statically apply ELF rela relocations\n");
+		fprintf(stderr, "Usage: %s <bin file> <text base> " \
+				"<rela start> <rela end>\n", argv[0]);
+		fprintf(stderr, "All numbers in hex.\n");
+		return 1;
+	}
+
+	f = fopen(argv[1], "r+b");
+	if (!f) {
+		fprintf(stderr, "%s: Cannot open %s: %s\n",
+			argv[0], argv[1], strerror(errno));
+		return 2;
+	}
+
+	if (!read_num(argv[2], &text_base) ||
+	    !read_num(argv[3], &rela_start) ||
+	    !read_num(argv[4], &rela_end)) {
+		fprintf(stderr, "%s: bad number\n", argv[0]);
+		return 3;
+	}
+
+	if (rela_start > rela_end || rela_start < text_base ||
+	    (rela_end - rela_start) % 24) {
+		fprintf(stderr, "%s: bad rela bounds\n", argv[0]);
+		return 3;
+	}
+
+	rela_start -= text_base;
+	rela_end -= text_base;
+
+	num = (rela_end - rela_start) / sizeof(Elf64_Rela);
+
+	for (i = 0; i < num; i++) {
+		Elf64_Rela rela, swrela;
+		uint64_t pos = rela_start + sizeof(Elf64_Rela) * i;
+		uint64_t addr;
+
+		if (fseek(f, pos, SEEK_SET) < 0) {
+			fprintf(stderr, "%s: %s: seek to %" PRIx64
+					" failed: %s\n",
+				argv[0], argv[1], pos, strerror(errno));
+		}
+
+		if (fread(&rela, sizeof(rela), 1, f) != 1) {
+			fprintf(stderr, "%s: %s: read rela failed at %"
+					PRIx64 "\n",
+				argv[0], argv[1], pos);
+			return 4;
+		}
+
+		swrela.r_offset = le64(rela.r_offset);
+		swrela.r_info = le64(rela.r_info);
+		swrela.r_addend = le64(rela.r_addend);
+
+		if (!supported_rela(&swrela))
+			continue;
+
+		debug("Rela %" PRIx64 " %" PRIu64 " %" PRIx64 "\n",
+		      swrela.r_offset, swrela.r_info, swrela.r_addend);
+
+		if (swrela.r_offset < text_base) {
+			fprintf(stderr, "%s: %s: bad rela at %" PRIx64 "\n",
+				argv[0], argv[1], pos);
+			return 4;
+		}
+
+		addr = swrela.r_offset - text_base;
+
+		if (fseek(f, addr, SEEK_SET) < 0) {
+			fprintf(stderr, "%s: %s: seek to %"
+					PRIx64 " failed: %s\n",
+				argv[0], argv[1], addr, strerror(errno));
+		}
+
+		if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) {
+			fprintf(stderr, "%s: %s: write failed at %" PRIx64 "\n",
+				argv[0], argv[1], addr);
+			return 4;
+		}
+	}
+
+	if (fclose(f) < 0) {
+		fprintf(stderr, "%s: %s: close failed: %s\n",
+			argv[0], argv[1], strerror(errno));
+		return 4;
+	}
+
+	return 0;
+}
diff --git a/marvell/uboot/tools/scripts/README b/marvell/uboot/tools/scripts/README
new file mode 100644
index 0000000..dbc4425
--- /dev/null
+++ b/marvell/uboot/tools/scripts/README
@@ -0,0 +1,51 @@
+#
+# (C) Copyright 2001
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+This directory contains scripts that help to perform certain actions
+that need to be done frequently when working with U-Boot.
+
+They are meant as EXAMPLE code, so it is very likely  that  you  will
+have to modify them before use.
+
+
+Short description:
+==================
+
+dot.kermrc:
+
+	Example for "~/.kermrc" Kermit init file for use with U-Boot
+
+	by Wolfgang Denk, 24 Jun 2001
+
+flash_param:
+
+	"kermit" script to automatically initialize the environment
+	variables on your target. This is most useful during
+	development when your environment variables are stored in an
+	embedded flash sector which is erased whenever you install a
+	new U-Boot image.
+
+	by Swen Anderson, 10 May 2001
+
+send_cmd:
+
+	send_cmd U_BOOT_COMMAND
+
+	"kermit" script to send a U-Boot command and print the
+	results. When used from a shell with history (like the bash)
+	this indirectly adds kind of history to U-Boot ;-)
+
+	by Swen Anderson, 10 May 2001
+
+send_image:
+
+	send_image FILE_NAME OFFSET
+
+	"kermit" script to automatically download a file to the
+	target using the "loadb" command (kermit binary protocol)
+
+	by Swen Anderson, 10 May 2001
diff --git a/marvell/uboot/tools/scripts/define2mk.sed b/marvell/uboot/tools/scripts/define2mk.sed
new file mode 100644
index 0000000..c641edf
--- /dev/null
+++ b/marvell/uboot/tools/scripts/define2mk.sed
@@ -0,0 +1,35 @@
+#
+# Sed script to parse CPP macros and generate output usable by make
+#
+# It is expected that this script is fed the output of 'gpp -dM'
+# which preprocesses the common.h header files and outputs the final
+# list of CPP macros (and whitespace is sanitized)
+#
+
+# Only process values prefixed with #define CONFIG_
+/^#define CONFIG_[A-Za-z0-9_][A-Za-z0-9_]*/ {
+	# Strip the #define prefix
+	s/#define *//;
+	# Change to form CONFIG_*=VALUE
+	s/  */=/;
+	# Drop trailing spaces
+	s/ *$//;
+	# drop quotes around string values
+	s/="\(.*\)"$/=\1/;
+	# Concatenate string values
+	s/" *"//g;
+	# Assume strings as default - add quotes around values
+	s/=\(..*\)/="\1"/;
+	# but remove again from decimal numbers
+	s/="\([0-9][0-9]*\)"/=\1/;
+	# ... and from hex numbers
+	s/="\(0[Xx][0-9a-fA-F][0-9a-fA-F]*\)"/=\1/;
+	# ... and from configs defined from other configs
+	s/="\(CONFIG_[A-Za-z0-9_][A-Za-z0-9_]*\)"/=$(\1)/;
+	# Change '1' and empty values to "y" (not perfect, but
+	# supports conditional compilation in the makefiles
+	s/=$/=y/;
+	s/=1$/=y/;
+	# print the line
+	p
+}
diff --git a/marvell/uboot/tools/scripts/dot.kermrc b/marvell/uboot/tools/scripts/dot.kermrc
new file mode 100644
index 0000000..0fc6c15
--- /dev/null
+++ b/marvell/uboot/tools/scripts/dot.kermrc
@@ -0,0 +1,16 @@
+set line /dev/ttyS0
+set speed 115200
+set carrier-watch off
+set handshake none
+set flow-control none
+robust
+set file type bin
+set file name lit
+set rec pack 1000
+set send pack 1000
+set window 5
+set prompt Kermit>
+define sz !sz \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line)
+define rz !rz \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line)
+define sx !sx \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line)
+define rx !rx \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line)
diff --git a/marvell/uboot/tools/scripts/flash_param b/marvell/uboot/tools/scripts/flash_param
new file mode 100644
index 0000000..847f99e
--- /dev/null
+++ b/marvell/uboot/tools/scripts/flash_param
@@ -0,0 +1,60 @@
+#!/usr/bin/kermit +
+# usage: ./flash_param parameters
+# Parameters: IP Address       ETH Address        ERIC Number
+# Format:     xxx.xxx.xxx.xxx  xx:xx:xx:xx:xx:xx  xxxx
+
+set line /dev/ttyS0
+set speed 115200
+set serial 8N1
+set carrier-watch off
+set handshake none
+#set flow-control none
+set flow-control xon/xoff
+#robust
+set file type bin
+set file name lit
+set rec pack 1000
+set send pack 1000
+set window 5
+set prompt Kermit>
+#robust
+# Milliseconds to pause between each OUTPUT character
+set output pacing 1
+
+out \13
+in 10 =>
+#first erase the environment memory within NVRAM
+out mw f0000000 0 200\13
+in 10 =>
+out reset\13
+in 5 autoboot
+out \13\13
+in 10 =>
+#set additional env parameter
+out setenv ethaddr \%2\13
+in 10 =>
+out setenv serial# ERIC 1.0 \%3\13
+in 10 =>
+out setenv eric_id \%3\13
+in 10 =>
+#out setenv prec_videocard_bus unknown\13
+#in 10 =>
+#out setenv prec_bios_type unknown\13
+#in 10 =>
+out setenv eric_passwd .eRIC.\13
+in 10 =>
+#out setenv bootargs root=/dev/ram ramdisk_size=8192 init=/sbin/init ip=\%1:192.168.1.100:192.168.1.254:255.255.255.0\13
+#out setenv bootargs root=/dev/ram ramdisk_size=8192 init=/sbin/init ip=\%1:192.168.0.1\13
+#out setenv bootargs root=/dev/ram ramdisk_size=8192 init=/sbin/init ip=\%1\13
+out setenv bootargs console=/dev/ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.26:/eric_root_devel ip=\%1:192.168.1.26\13
+in 10 =>
+out setenv bootcmd bootm FFC00000\13
+in 10 =>
+out saveenv\13
+in 10 =>
+out reset\13
+in 5 autoboot
+out \13\13
+in 10 =>
+quit
+exit 0
diff --git a/marvell/uboot/tools/scripts/make-asm-offsets b/marvell/uboot/tools/scripts/make-asm-offsets
new file mode 100755
index 0000000..4c33756
--- /dev/null
+++ b/marvell/uboot/tools/scripts/make-asm-offsets
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# Adapted from Linux kernel's "Kbuild":
+# commit 1cdf25d704f7951d02a04064c97db547d6021872
+# Author: Christoph Lameter <clameter@sgi.com>
+
+mkdir -p $(dirname $2)
+
+# Default sed regexp - multiline due to syntax constraints
+SED_CMD="/^->/{s:->#\(.*\):/* \1 */:; \
+	s:^->\([^ ]*\) [\$#]*\([-0-9]*\) \(.*\):#define \1 (\2) /* \3 */:; \
+	s:^->\([^ ]*\) [\$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
+	s:->::; p;}"
+
+(set -e
+ echo "#ifndef __ASM_OFFSETS_H__"
+ echo "#define __ASM_OFFSETS_H__"
+ echo "/*"
+ echo " * DO NOT MODIFY."
+ echo " *"
+ echo " * This file was generated by $(basename $0)"
+ echo " *"
+ echo " */"
+ echo ""
+ sed -ne "${SED_CMD}" $1 
+ echo ""
+ echo "#endif" ) > $2
diff --git a/marvell/uboot/tools/scripts/send_cmd b/marvell/uboot/tools/scripts/send_cmd
new file mode 100644
index 0000000..4131331
--- /dev/null
+++ b/marvell/uboot/tools/scripts/send_cmd
@@ -0,0 +1,21 @@
+#!/usr/bin/kermit +
+set line /dev/ttyS0
+set speed 115200
+set serial 8N1
+set carrier-watch off
+set handshake none
+set flow-control none
+robust
+set file type bin
+set file name lit
+set rec pack 1000
+set send pack 1000
+set window 5
+set prompt Kermit>
+
+#out \13
+#in 10 =>
+out \%1 \%2 \%3 \%4 \%5 \%6 \%7\13
+in 10 =>
+quit
+exit 0
diff --git a/marvell/uboot/tools/scripts/send_image b/marvell/uboot/tools/scripts/send_image
new file mode 100644
index 0000000..9b89d6b
--- /dev/null
+++ b/marvell/uboot/tools/scripts/send_image
@@ -0,0 +1,26 @@
+#!/usr/bin/kermit +
+# usage: send_image FILE_NAME OFFSET
+# e.g.   send_image output.bin 1F00000
+set line /dev/ttyS0
+set speed 115200
+set serial 8N1
+set carrier-watch off
+set handshake none
+set flow-control none
+robust
+set file type bin
+set file name lit
+set rec pack 1000
+set send pack 1000
+set window 5
+set prompt Kermit>
+
+out \13
+in 10 =>
+out loadb \%2 \13
+in 10 download ...
+send \%1
+out \13
+in 10 ## Start Addr
+quit
+exit 0
diff --git a/marvell/uboot/tools/ublimage.c b/marvell/uboot/tools/ublimage.c
new file mode 100644
index 0000000..cbbbe20
--- /dev/null
+++ b/marvell/uboot/tools/ublimage.c
@@ -0,0 +1,261 @@
+/*
+ * (C) Copyright 2011
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * Based on:
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "imagetool.h"
+#include <image.h>
+#include "ublimage.h"
+
+/*
+ * Supported commands for configuration file
+ */
+static table_entry_t ublimage_cmds[] = {
+	{CMD_BOOT_MODE,	"MODE",		"UBL special modes", },
+	{CMD_ENTRY,	"ENTRY",	"Entry point addr for bootloader", },
+	{CMD_PAGE,	"PAGES",
+		"number of pages (size of bootloader)", },
+	{CMD_ST_BLOCK,	"START_BLOCK",
+		"block number where bootloader is present", },
+	{CMD_ST_PAGE,	"START_PAGE",
+		"page number where bootloader is present", },
+	{CMD_LD_ADDR,	"LD_ADDR",
+		"load addr", },
+	{-1,		"",		"", },
+};
+
+/*
+ * Supported Boot options for configuration file
+ * this is needed to set the correct flash offset
+ */
+static table_entry_t ublimage_bootops[] = {
+	{UBL_MAGIC_SAFE,	"safe",	"Safe boot mode",	},
+	{-1,			"",	"Invalid",		},
+};
+
+static struct ubl_header ublimage_header;
+
+static uint32_t get_cfg_value(char *token, char *name,  int linenr)
+{
+	char *endptr;
+	uint32_t value;
+
+	errno = 0;
+	value = strtoul(token, &endptr, 16);
+	if (errno || (token == endptr)) {
+		fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n",
+			name,  linenr, token);
+		exit(EXIT_FAILURE);
+	}
+	return value;
+}
+
+static void print_hdr(struct ubl_header *ubl_hdr)
+{
+	printf("Image Type : Davinci UBL Boot Image\n");
+	printf("UBL magic  : %08x\n", ubl_hdr->magic);
+	printf("Entry Point: %08x\n", ubl_hdr->entry);
+	printf("nr of pages: %08x\n", ubl_hdr->pages);
+	printf("start block: %08x\n", ubl_hdr->block);
+	printf("start page : %08x\n", ubl_hdr->page);
+}
+
+static void parse_cfg_cmd(struct ubl_header *ublhdr, int32_t cmd, char *token,
+				char *name, int lineno, int fld, int dcd_len)
+{
+	static int cmd_ver_first = ~0;
+
+	switch (cmd) {
+	case CMD_BOOT_MODE:
+		ublhdr->magic = get_table_entry_id(ublimage_bootops,
+					"ublimage special boot mode", token);
+		if (ublhdr->magic == -1) {
+			fprintf(stderr, "Error: %s[%d] -Invalid boot mode"
+				"(%s)\n", name, lineno, token);
+			exit(EXIT_FAILURE);
+		}
+		ublhdr->magic += UBL_MAGIC_BASE;
+		if (unlikely(cmd_ver_first != 1))
+			cmd_ver_first = 0;
+		break;
+	case CMD_ENTRY:
+		ublhdr->entry = get_cfg_value(token, name, lineno);
+		break;
+	case CMD_PAGE:
+		ublhdr->pages = get_cfg_value(token, name, lineno);
+		break;
+	case CMD_ST_BLOCK:
+		ublhdr->block = get_cfg_value(token, name, lineno);
+		break;
+	case CMD_ST_PAGE:
+		ublhdr->page = get_cfg_value(token, name, lineno);
+		break;
+	case CMD_LD_ADDR:
+		ublhdr->pll_m = get_cfg_value(token, name, lineno);
+		break;
+	}
+}
+
+static void parse_cfg_fld(struct ubl_header *ublhdr, int32_t *cmd,
+		char *token, char *name, int lineno, int fld, int *dcd_len)
+{
+
+	switch (fld) {
+	case CFG_COMMAND:
+		*cmd = get_table_entry_id(ublimage_cmds,
+			"ublimage commands", token);
+		if (*cmd < 0) {
+			fprintf(stderr, "Error: %s[%d] - Invalid command"
+			"(%s)\n", name, lineno, token);
+			exit(EXIT_FAILURE);
+		}
+		break;
+	case CFG_REG_VALUE:
+		parse_cfg_cmd(ublhdr, *cmd, token, name, lineno, fld, *dcd_len);
+		break;
+	default:
+		break;
+	}
+}
+static uint32_t parse_cfg_file(struct ubl_header *ublhdr, char *name)
+{
+	FILE *fd = NULL;
+	char *line = NULL;
+	char *token, *saveptr1, *saveptr2;
+	int lineno = 0;
+	int	i;
+	char *ptr = (char *)ublhdr;
+	int fld;
+	size_t len;
+	int dcd_len = 0;
+	int32_t cmd;
+	int ublhdrlen = sizeof(struct ubl_header);
+
+	fd = fopen(name, "r");
+	if (fd == 0) {
+		fprintf(stderr, "Error: %s - Can't open DCD file\n", name);
+		exit(EXIT_FAILURE);
+	}
+
+	/* Fill header with 0xff */
+	for (i = 0; i < ublhdrlen; i++) {
+		*ptr = 0xff;
+		ptr++;
+	}
+
+	/*
+	 * Very simple parsing, line starting with # are comments
+	 * and are dropped
+	 */
+	while ((getline(&line, &len, fd)) > 0) {
+		lineno++;
+
+		token = strtok_r(line, "\r\n", &saveptr1);
+		if (token == NULL)
+			continue;
+
+		/* Check inside the single line */
+		for (fld = CFG_COMMAND, cmd = CMD_INVALID,
+				line = token; ; line = NULL, fld++) {
+			token = strtok_r(line, " \t", &saveptr2);
+			if (token == NULL)
+				break;
+
+			/* Drop all text starting with '#' as comments */
+			if (token[0] == '#')
+				break;
+
+			parse_cfg_fld(ublhdr, &cmd, token, name,
+					lineno, fld, &dcd_len);
+		}
+	}
+	fclose(fd);
+
+	return dcd_len;
+}
+
+static int ublimage_check_image_types(uint8_t type)
+{
+	if (type == IH_TYPE_UBLIMAGE)
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+}
+
+static int ublimage_verify_header(unsigned char *ptr, int image_size,
+			struct image_tool_params *params)
+{
+	struct ubl_header *ubl_hdr = (struct ubl_header *)ptr;
+
+	if ((ubl_hdr->magic & 0xFFFFFF00) != UBL_MAGIC_BASE)
+		return -1;
+
+	return 0;
+}
+
+static void ublimage_print_header(const void *ptr)
+{
+	struct ubl_header *ubl_hdr = (struct ubl_header *) ptr;
+
+	print_hdr(ubl_hdr);
+}
+
+static void ublimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+				struct image_tool_params *params)
+{
+	struct ubl_header *ublhdr = (struct ubl_header *)ptr;
+
+	/* Parse configuration file */
+	parse_cfg_file(ublhdr, params->imagename);
+}
+
+int ublimage_check_params(struct image_tool_params *params)
+{
+	if (!params)
+		return CFG_INVALID;
+	if (!strlen(params->imagename)) {
+		fprintf(stderr, "Error: %s - Configuration file not"
+			"specified, it is needed for ublimage generation\n",
+			params->cmdname);
+		return CFG_INVALID;
+	}
+	/*
+	 * Check parameters:
+	 * XIP is not allowed and verify that incompatible
+	 * parameters are not sent at the same time
+	 * For example, if list is required a data image must not be provided
+	 */
+	return	(params->dflag && (params->fflag || params->lflag)) ||
+		(params->fflag && (params->dflag || params->lflag)) ||
+		(params->lflag && (params->dflag || params->fflag)) ||
+		(params->xflag) || !(strlen(params->imagename));
+}
+
+/*
+ * ublimage parameters
+ */
+static struct image_type_params ublimage_params = {
+	.name		= "Davinci UBL boot support",
+	.header_size	= sizeof(struct ubl_header),
+	.hdr		= (void *)&ublimage_header,
+	.check_image_type = ublimage_check_image_types,
+	.verify_header	= ublimage_verify_header,
+	.print_header	= ublimage_print_header,
+	.set_header	= ublimage_set_header,
+	.check_params	= ublimage_check_params,
+};
+
+void init_ubl_image_type(void)
+{
+	register_image_type(&ublimage_params);
+}
diff --git a/marvell/uboot/tools/ublimage.h b/marvell/uboot/tools/ublimage.h
new file mode 100644
index 0000000..32cc582
--- /dev/null
+++ b/marvell/uboot/tools/ublimage.h
@@ -0,0 +1,84 @@
+/*
+ * (C) Copyright 2011
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * Vased on:
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _UBLIMAGE_H_
+#define _UBLIMAGE_H_
+
+enum ublimage_cmd {
+	CMD_INVALID,
+	CMD_BOOT_MODE,
+	CMD_ENTRY,
+	CMD_PAGE,
+	CMD_ST_BLOCK,
+	CMD_ST_PAGE,
+	CMD_LD_ADDR
+};
+
+enum ublimage_fld_types {
+	CFG_INVALID = -1,
+	CFG_COMMAND,
+	CFG_REG_VALUE
+};
+
+/*
+ * from sprufg5a.pdf Table 110
+ * Used by RBL when doing NAND boot
+ */
+#define UBL_MAGIC_BASE              (0xA1ACED00)
+/* Safe boot mode */
+#define UBL_MAGIC_SAFE              (0x00)
+/* DMA boot mode */
+#define UBL_MAGIC_DMA               (0x11)
+/* I Cache boot mode */
+#define UBL_MAGIC_IC                (0x22)
+/* Fast EMIF boot mode */
+#define UBL_MAGIC_FAST              (0x33)
+/* DMA + ICache boot mode */
+#define UBL_MAGIC_DMA_IC            (0x44)
+/* DMA + ICache + Fast EMIF boot mode */
+#define UBL_MAGIC_DMA_IC_FAST       (0x55)
+
+/* Define max UBL image size */
+#define UBL_IMAGE_SIZE              (0x00003800u)
+
+/* one NAND block */
+#define UBL_BLOCK_SIZE 2048
+
+/* from sprufg5a.pdf Table 109 */
+struct ubl_header {
+	uint32_t	magic;	/* Magic Number, see UBL_* defines */
+	uint32_t	entry;	/* entry point address for bootloader */
+	uint32_t	pages;	/* number of pages (size of bootloader) */
+	uint32_t	block;	/*
+				 * blocknumber where user bootloader is
+				 * present
+				 */
+	uint32_t	page;	/*
+				 * page number where user bootloader is
+				 * present.
+				 */
+	uint32_t	pll_m;	/*
+				 * PLL setting -Multiplier (only valid if
+				 * Magic Number indicates PLL enable).
+				 */
+	uint32_t	pll_n;	/*
+				 * PLL setting -Divider (only valid if
+				 * Magic Number indicates PLL enable).
+				 */
+	uint32_t	emif;	/*
+				 * fast EMIF setting (only valid if
+				 * Magic Number indicates fast EMIF boot).
+				 */
+	/* to fit in one nand block */
+	unsigned char	res[UBL_BLOCK_SIZE - 8 * 4];
+};
+
+#endif /* _UBLIMAGE_H_ */
diff --git a/marvell/uboot/tools/ubsha1.c b/marvell/uboot/tools/ubsha1.c
new file mode 100644
index 0000000..1041588
--- /dev/null
+++ b/marvell/uboot/tools/ubsha1.c
@@ -0,0 +1,84 @@
+/*
+ * (C) Copyright 2007
+ * Heiko Schocher, DENX Software Engineering, <hs@denx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "os_support.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "sha1.h"
+
+int main (int argc, char **argv)
+{
+	unsigned char output[20];
+	int i, len;
+
+	char	*imagefile;
+	char	*cmdname = *argv;
+	unsigned char	*ptr;
+	unsigned char	*data;
+	struct stat sbuf;
+	unsigned char	*ptroff;
+	int	ifd;
+	int	off;
+
+	if (argc > 1) {
+		imagefile = argv[1];
+		ifd = open (imagefile, O_RDWR|O_BINARY);
+		if (ifd < 0) {
+			fprintf (stderr, "%s: Can't open %s: %s\n",
+				cmdname, imagefile, strerror(errno));
+			exit (EXIT_FAILURE);
+		}
+		if (fstat (ifd, &sbuf) < 0) {
+			fprintf (stderr, "%s: Can't stat %s: %s\n",
+				cmdname, imagefile, strerror(errno));
+			exit (EXIT_FAILURE);
+		}
+		len = sbuf.st_size;
+		ptr = (unsigned char *)mmap(0, len,
+				    PROT_READ, MAP_SHARED, ifd, 0);
+		if (ptr == (unsigned char *)MAP_FAILED) {
+			fprintf (stderr, "%s: Can't read %s: %s\n",
+				cmdname, imagefile, strerror(errno));
+			exit (EXIT_FAILURE);
+		}
+
+		/* create a copy, so we can blank out the sha1 sum */
+		data = malloc (len);
+		memcpy (data, ptr, len);
+		off = SHA1_SUM_POS;
+		ptroff = &data[len +  off];
+		for (i = 0; i < SHA1_SUM_LEN; i++) {
+			ptroff[i] = 0;
+		}
+
+		sha1_csum ((unsigned char *) data, len, (unsigned char *)output);
+
+		printf ("U-Boot sum:\n");
+		for (i = 0; i < 20 ; i++) {
+		    printf ("%02X ", output[i]);
+		}
+		printf ("\n");
+		/* overwrite the sum in the bin file, with the actual */
+		lseek (ifd, SHA1_SUM_POS, SEEK_END);
+		if (write (ifd, output, SHA1_SUM_LEN) != SHA1_SUM_LEN) {
+			fprintf (stderr, "%s: Can't write %s: %s\n",
+				cmdname, imagefile, strerror(errno));
+			exit (EXIT_FAILURE);
+		}
+
+		free (data);
+		(void) munmap((void *)ptr, len);
+		(void) close (ifd);
+	}
+
+	return EXIT_SUCCESS;
+}
diff --git a/marvell/uboot/tools/xway-swap-bytes.c b/marvell/uboot/tools/xway-swap-bytes.c
new file mode 100644
index 0000000..3a6d82d
--- /dev/null
+++ b/marvell/uboot/tools/xway-swap-bytes.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef BUFSIZ
+# define BUFSIZ 4096
+#endif
+
+#undef BUFSIZ
+# define BUFSIZ 64
+int main (void)
+{
+	short ibuff[BUFSIZ], obuff[BUFSIZ];
+	int rc, i, len;
+
+	while ((rc = read (0, ibuff, sizeof (ibuff))) > 0) {
+		memset (obuff, 0, sizeof (obuff));
+		for (i = 0; i < (rc + 1) / 2; i++) {
+			obuff[i] = ibuff[i ^ 1];
+		}
+
+		len = (rc + 1) & ~1;
+
+		if (write (1, obuff, len) != len) {
+			perror ("read error");
+			return (EXIT_FAILURE);
+		}
+
+		memset (ibuff, 0, sizeof (ibuff));
+	}
+
+	if (rc < 0) {
+		perror ("read error");
+		return (EXIT_FAILURE);
+	}
+	return (EXIT_SUCCESS);
+}