diff mbox

[U-Boot] Davinci: Utility for MMC boot

Message ID 1340708826-26707-1-git-send-email-prabhakar.lad@ti.com
State Rejected
Delegated to: Tom Rini
Headers show

Commit Message

Prabhakar Lad June 26, 2012, 11:07 a.m. UTC
From: Alagu Sankar <alagusankar@embwise.com>

This is a Linux command line tool specific to TI's Davinci platforms, for
flashing UBL (User Boot Loader), u-boot and u-boot Environment in the MMC/SD
card. This MMC/SD card can be used for booting Davinci platforms that supports
MMC/SD boot option.

This patch was submitted by Alagu Sankar
(http://www.mail-archive.com/u-boot@lists.denx.de/msg32309.html),
but couldn't make into mainline. Resubmitting the patch, with modifications to
build with u-boot, Fixed compilation issues and fixed uflash.c to write u-boot properly.

Signed-off-by: Alagu Sankar <alagusankar@embwise.com>
Signed-off-by: Rajashekhara, Sudhakar <sudhakar.raj@ti.com>
Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
---
 Makefile                |    2 +-
 tools/Makefile          |    2 +-
 tools/uflash/Makefile   |   13 ++
 tools/uflash/README     |  125 +++++++++++++++
 tools/uflash/config.txt |   11 ++
 tools/uflash/uflash.c   |  383 +++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 534 insertions(+), 2 deletions(-)
 create mode 100644 tools/uflash/Makefile
 create mode 100644 tools/uflash/README
 create mode 100644 tools/uflash/config.txt
 create mode 100644 tools/uflash/uflash.c

Comments

Wolfgang Denk June 26, 2012, 9:42 p.m. UTC | #1
Dear Prabhakar Lad,

In message <1340708826-26707-1-git-send-email-prabhakar.lad@ti.com> you wrote:
> From: Alagu Sankar <alagusankar@embwise.com>
> 
> This is a Linux command line tool specific to TI's Davinci platforms, for
> flashing UBL (User Boot Loader), u-boot and u-boot Environment in the MMC/SD
> card. This MMC/SD card can be used for booting Davinci platforms that supports
> MMC/SD boot option.

Do we also build UBL as part of the U-Boot source tree?

If not, then why is this tool supposed to be part of the U-Boot tree?

How does this work with a SPL?

> --- a/Makefile
> +++ b/Makefile
> @@ -726,7 +726,7 @@ clean:
>  	@rm -f $(obj)examples/api/demo{,.bin}
>  	@rm -f $(obj)tools/bmp_logo	   $(obj)tools/easylogo/easylogo  \
>  	       $(obj)tools/env/{fw_printenv,fw_setenv}			  \
> -	       $(obj)tools/envcrc					  \
> +	       $(obj)tools/envcrc	   $(obj)tools/uflash/uflash	  \
>  	       $(obj)tools/gdb/{astest,gdbcont,gdbsend}			  \
>  	       $(obj)tools/gen_eth_addr    $(obj)tools/img2srec		  \
>  	       $(obj)tools/mk{env,}image   $(obj)tools/mpc86x_clk	  \

Please keep list sorted.


> +e. Using the 'uflash' utility, place the UBL and u-uoot binaries on the MMC
> +   card. Copy the u-boot.bin to tools/uflash directory

Why is this copy operation needed?

And where is the UBL binary coming from?



> diff --git a/tools/uflash/config.txt b/tools/uflash/config.txt
> new file mode 100644
> index 0000000..f6acb22
> --- /dev/null
> +++ b/tools/uflash/config.txt
> @@ -0,0 +1,11 @@
> +bootargs=console=ttyS0,115200n8 root=/dev/mmcblk0p1 rootwait rootfstype=ext3 rw
> +bootcmd=ext2load mmc 0 0x80700000 boot/uImage; bootm 0x80700000
> +bootdelay=1
> +baudrate=115200
> +bootfile="uImage"
> +stdin=serial
> +stdout=serial
> +stderr=serial
> +ethact=dm9000
> +videostd=ntsc

This looks like U-Boot environment settings?  Why are these in the
tools/uflash/ directory?  I would expect these are board specific?
For example, what in case a board uses a different baud rate?

Is this really supposed to be board independent?  It doesn't look
so...

> +

And please, no trailing empty lines!

...
> +	if (!strcmp(platform, "DM3XX")) {
> +		if (!uboot_load_address)
> +			uboot_load_address = DM3XX_UBOOT_LOAD_ADDRESS;
> +		if (!uboot_entry_point)
> +			uboot_entry_point = DM3XX_UBOOT_LOAD_ADDRESS;
> +	}
> +
> +	if (!strcmp(platform, "OMAPL138")) {
> +		if (!uboot_load_address)
> +			uboot_load_address = DA850_UBOOT_LOAD_ADDRESS;
> +		if (!uboot_entry_point)
> +			uboot_entry_point = DA850_UBOOT_LOAD_ADDRESS;
> +	}

So this is actually all hardwired for a few very specific board
configurations, right?

.
> +static int get_file_size(char *fname)
> +{
> +	FILE *fp;
> +	int size;
> +
> +	fp = fopen(fname, "rb");
> +	if (fp == NULL) {
> +		fprintf(stdout, "File %s Open Error : %s\n",
> +					fname, strerror(errno));
> +		return -1;
> +	}
> +
> +	fseek(fp, 0, SEEK_END);
> +	size = ftell(fp);
> +	fclose(fp);

Why not simply using stat() ?

> +static int write_file(int devfd, char *fname)
> +{
> +	FILE *fp;
> +	int readlen, writelen;
> +
> +	fp = fopen(fname, "rb");
> +	if (fp == NULL) {
> +		fprintf(stderr, "File %s Open Error: %s",
> +				fname, strerror(errno));
> +		return -1;
> +	}
> +
> +	while ((readlen = fread(readbuf, 1, BLOCK_SIZE, fp)) > 0) {
> +		if (readlen < BLOCK_SIZE)
> +			memset(&readbuf[readlen], 0, BLOCK_SIZE-readlen);
> +
> +		writelen = write(devfd, readbuf, BLOCK_SIZE);
> +		if (writelen < BLOCK_SIZE) {
> +			close(devfd);
> +			return -1;
> +		}
> +	}
> +
> +	fclose(fp);

You don't even print a warning or error message in case of read
errors?  Ouch...


Best regards,

Wolfgang Denk
Prabhakar Lad June 27, 2012, 6:07 a.m. UTC | #2
Hi Wolfgang,

On Wed, Jun 27, 2012 at 03:12:07, Wolfgang Denk wrote:
> Dear Prabhakar Lad,
> 
> In message <1340708826-26707-1-git-send-email-prabhakar.lad@ti.com> you wrote:
> > From: Alagu Sankar <alagusankar@embwise.com>
> > 
> > This is a Linux command line tool specific to TI's Davinci platforms, for
> > flashing UBL (User Boot Loader), u-boot and u-boot Environment in the MMC/SD
> > card. This MMC/SD card can be used for booting Davinci platforms that supports
> > MMC/SD boot option.
> 
> Do we also build UBL as part of the U-Boot source tree?
> 
  No, we do not build UBL as part of U-Boot.

> If not, then why is this tool supposed to be part of the U-Boot tree?
> 
> How does this work with a SPL?
> 
  This command has options to flash u-boot images to MMC/SD card. When SPL
  is supported, this command can be used to flash the single SPL image to
  MMC/SD card.

> > --- a/Makefile
> > +++ b/Makefile
> > @@ -726,7 +726,7 @@ clean:
> >  	@rm -f $(obj)examples/api/demo{,.bin}
> >  	@rm -f $(obj)tools/bmp_logo	   $(obj)tools/easylogo/easylogo  \
> >  	       $(obj)tools/env/{fw_printenv,fw_setenv}			  \
> > -	       $(obj)tools/envcrc					  \
> > +	       $(obj)tools/envcrc	   $(obj)tools/uflash/uflash	  \
> >  	       $(obj)tools/gdb/{astest,gdbcont,gdbsend}			  \
> >  	       $(obj)tools/gen_eth_addr    $(obj)tools/img2srec		  \
> >  	       $(obj)tools/mk{env,}image   $(obj)tools/mpc86x_clk	  \
> 
> Please keep list sorted.
> 
  Ok.

> 
> > +e. Using the 'uflash' utility, place the UBL and u-uoot binaries on the MMC
> > +   card. Copy the u-boot.bin to tools/uflash directory
> 
> Why is this copy operation needed?
> 
  This copy is not needed as long as the path to u-boot.bin is specified
  Correctly in command line.

> And where is the UBL binary coming from?
> 
  UBL binary is optional. We can flash only u-boot.bin.
> 
> 
> > diff --git a/tools/uflash/config.txt b/tools/uflash/config.txt
> > new file mode 100644
> > index 0000000..f6acb22
> > --- /dev/null
> > +++ b/tools/uflash/config.txt
> > @@ -0,0 +1,11 @@
> > +bootargs=console=ttyS0,115200n8 root=/dev/mmcblk0p1 rootwait rootfstype=ext3 rw
> > +bootcmd=ext2load mmc 0 0x80700000 boot/uImage; bootm 0x80700000
> > +bootdelay=1
> > +baudrate=115200
> > +bootfile="uImage"
> > +stdin=serial
> > +stdout=serial
> > +stderr=serial
> > +ethact=dm9000
> > +videostd=ntsc
> 
> This looks like U-Boot environment settings?  Why are these in the
> tools/uflash/ directory?  I would expect these are board specific?
> For example, what in case a board uses a different baud rate?
> 
> Is this really supposed to be board independent?  It doesn't look
> so...
> 
 I agree with this. Can you think of any other scenario?

> > +
> 
> And please, no trailing empty lines!
> 
  Ok.

> ...
> > +	if (!strcmp(platform, "DM3XX")) {
> > +		if (!uboot_load_address)
> > +			uboot_load_address = DM3XX_UBOOT_LOAD_ADDRESS;
> > +		if (!uboot_entry_point)
> > +			uboot_entry_point = DM3XX_UBOOT_LOAD_ADDRESS;
> > +	}
> > +
> > +	if (!strcmp(platform, "OMAPL138")) {
> > +		if (!uboot_load_address)
> > +			uboot_load_address = DA850_UBOOT_LOAD_ADDRESS;
> > +		if (!uboot_entry_point)
> > +			uboot_entry_point = DA850_UBOOT_LOAD_ADDRESS;
> > +	}
> 
> So this is actually all hardwired for a few very specific board
> configurations, right?
> 
  Yes.

> .
> > +static int get_file_size(char *fname)
> > +{
> > +	FILE *fp;
> > +	int size;
> > +
> > +	fp = fopen(fname, "rb");
> > +	if (fp == NULL) {
> > +		fprintf(stdout, "File %s Open Error : %s\n",
> > +					fname, strerror(errno));
> > +		return -1;
> > +	}
> > +
> > +	fseek(fp, 0, SEEK_END);
> > +	size = ftell(fp);
> > +	fclose(fp);
> 
> Why not simply using stat() ?
> 
   Yes that makes sense.

> > +static int write_file(int devfd, char *fname)
> > +{
> > +	FILE *fp;
> > +	int readlen, writelen;
> > +
> > +	fp = fopen(fname, "rb");
> > +	if (fp == NULL) {
> > +		fprintf(stderr, "File %s Open Error: %s",
> > +				fname, strerror(errno));
> > +		return -1;
> > +	}
> > +
> > +	while ((readlen = fread(readbuf, 1, BLOCK_SIZE, fp)) > 0) {
> > +		if (readlen < BLOCK_SIZE)
> > +			memset(&readbuf[readlen], 0, BLOCK_SIZE-readlen);
> > +
> > +		writelen = write(devfd, readbuf, BLOCK_SIZE);
> > +		if (writelen < BLOCK_SIZE) {
> > +			close(devfd);
> > +			return -1;
> > +		}
> > +	}
> > +
> > +	fclose(fp);
> 
> You don't even print a warning or error message in case of read
> errors?  Ouch...
> 
  Ok , I'll fix it in V2 version.

Thx,
--Prabhakar Lad

> 
> Best regards,
> 
> Wolfgang Denk
> 
> -- 
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
> C makes it easy for you to shoot yourself in the foot. C++ makes that
> harder, but when you do, it blows away your whole leg.
>                                                  -- Bjarne Stroustrup
>
Wolfgang Denk June 27, 2012, 7:03 a.m. UTC | #3
Dear "Lad, Prabhakar",

In message <4665BC9CC4253445B213A010E6DC7B35CDD4FE@DBDE01.ent.ti.com> you wrote:
> 
> > > This is a Linux command line tool specific to TI's Davinci platforms, f> or
> > > flashing UBL (User Boot Loader), u-boot and u-boot Environment in the M> MC/SD
> > > card. This MMC/SD card can be used for booting Davinci platforms that s> upports
> > > MMC/SD boot option.
> > 
> > Do we also build UBL as part of the U-Boot source tree?
> > 
>   No, we do not build UBL as part of U-Boot.

Why not?

I assume by adding this tool to the U-Boot tree you want to provide a
single, self-contained build system for the boot loader on such
boards.  But this doesn;t work if we are not also building the UBL
image.

> > If not, then why is this tool supposed to be part of the U-Boot tree?
> > 
> > How does this work with a SPL?
> > 
>   This command has options to flash u-boot images to MMC/SD card. When SPL
>   is supported, this command can be used to flash the single SPL image to
>   MMC/SD card.

How exactly does this work?  You do not document this use case.

> > > +e. Using the 'uflash' utility, place the UBL and u-uoot binaries on th> e MMC
> > > +   card. Copy the u-boot.bin to tools/uflash directory
> > 
> > Why is this copy operation needed?
> > 
>   This copy is not needed as long as the path to u-boot.bin is specified
>   Correctly in command line.
>
> > And where is the UBL binary coming from?
> > 
>   UBL binary is optional. We can flash only u-boot.bin.

I did not understand this from your documentation.  Can you please add
this information?

> > This looks like U-Boot environment settings?  Why are these in the
> > tools/uflash/ directory?  I would expect these are board specific?
> > For example, what in case a board uses a different baud rate?
> > 
> > Is this really supposed to be board independent?  It doesn't look
> > so...
> > 
>  I agree with this. Can you think of any other scenario?

I have no idea what you are trying to do here.  The envrionment
settings are inherently part of U-Boot, and I don't understand why you
are adding another set of settings here.

> > > +	if (!strcmp(platform, "DM3XX")) {
> > > +		if (!uboot_load_address)
> > > +			uboot_load_address = DM3XX_UBOOT_LOAD_ADDRESS;
> > > +		if (!uboot_entry_point)
> > > +			uboot_entry_point = DM3XX_UBOOT_LOAD_ADDRESS;
> > > +	}
> > > +
> > > +	if (!strcmp(platform, "OMAPL138")) {
> > > +		if (!uboot_load_address)
> > > +			uboot_load_address = DA850_UBOOT_LOAD_ADDRESS;
> > > +		if (!uboot_entry_point)
> > > +			uboot_entry_point = DA850_UBOOT_LOAD_ADDRESS;
> > > +	}
> > 
> > So this is actually all hardwired for a few very specific board
> > configurations, right?
> > 
>   Yes.

Sorry, but this doesn't make sense then.  It doesn't scale.  It should
be possible to use such a tool with any such board - and without
changing the code of the tool.  Instead of gard-coding all this
information, you should make the tool data driven, so that it's
sufficient to provide respective configuration data - actually I think
all this information is already present in the existing header files,
especially the board configuration file. So why not just reuse this
information?

> > You don't even print a warning or error message in case of read
> > errors?  Ouch...
> > 
>   Ok , I'll fix it in V2 version.

Please check error checking / handling for all system calls and calls
to library functions.

Best regards,

Wolfgang Denk
diff mbox

Patch

diff --git a/Makefile b/Makefile
index 7368f1f..c5afe9d 100644
--- a/Makefile
+++ b/Makefile
@@ -726,7 +726,7 @@  clean:
 	@rm -f $(obj)examples/api/demo{,.bin}
 	@rm -f $(obj)tools/bmp_logo	   $(obj)tools/easylogo/easylogo  \
 	       $(obj)tools/env/{fw_printenv,fw_setenv}			  \
-	       $(obj)tools/envcrc					  \
+	       $(obj)tools/envcrc	   $(obj)tools/uflash/uflash	  \
 	       $(obj)tools/gdb/{astest,gdbcont,gdbsend}			  \
 	       $(obj)tools/gen_eth_addr    $(obj)tools/img2srec		  \
 	       $(obj)tools/mk{env,}image   $(obj)tools/mpc86x_clk	  \
diff --git a/tools/Makefile b/tools/Makefile
index 8993fdd..e15c21e 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -21,7 +21,7 @@ 
 # MA 02111-1307 USA
 #
 
-TOOLSUBDIRS =
+TOOLSUBDIRS = uflash
 
 #
 # Include this after HOSTOS HOSTARCH check
diff --git a/tools/uflash/Makefile b/tools/uflash/Makefile
new file mode 100644
index 0000000..8ade3c4
--- /dev/null
+++ b/tools/uflash/Makefile
@@ -0,0 +1,13 @@ 
+include $(TOPDIR)/config.mk
+
+all: $(obj)uflash
+
+HOSTCFLAGS_NOPED += -I $(SRCTREE)/include -DUSE_HOSTCC
+
+$(obj)uflash: $(SRCTREE)/tools/uflash/uflash.c $(SRCTREE)/lib/crc32.c $(SRCTREE)/lib/errno.c
+	$(HOSTCC) $(HOSTCFLAGS_NOPED) $(HOSTLDFLAGS) -o $@ $^
+
+clean:
+	rm -f $(obj)uflash
+
+.PHONY: all clean
diff --git a/tools/uflash/README b/tools/uflash/README
new file mode 100644
index 0000000..8e9c22c
--- /dev/null
+++ b/tools/uflash/README
@@ -0,0 +1,125 @@ 
+This is a Linux command line tool specific to TI's Davinci platforms, for
+flashing UBL (User Boot Loader), u-boot and u-boot Environment in the MMC/SD
+card. This MMC/SD card can be used for booting Davinci platforms that supports
+MMC/SD boot option.
+
+For simplicity, MMC is used in the following section to represent both MMC and
+SD cards.
+
+
+Building uflash utility
+=======================
+Set the TOOLSUBDIRS macro in the tools/Makefile to contain uflash directory
+TOOLSUBDIRS = uflash
+
+While building the u-boot binary, the uflash utility is also built and is placed
+under tools/uflash directory.
+
+
+Creating a Davinci bootable MMC card
+=====================================
+This document is based on the assumption that UBL is used the primary boot
+loader for booting u-boot. For more information on Davinci Boot modes, please
+refer the TMS320DM644x DMSoC ARM Subsystem Reference Guide (SPRUE14A).
+
+The embedded ROM boot loader (RBL) in Davinci expects the bootable code
+descriptor to be present in sectors 1 to 25 of the MMC card. Sector 0 is used
+for storing DOS partition information. Hence the UBL descriptor is stored
+from sectors 1 till 24. The descriptor is 512 bytes in size and is replicated
+in each of these sectors. This is followed by the u-boot descriptor,
+environment space, UBL binary and u-boot binary as depicted below:
+
+                    _______________________________________
+                   |                                       |
+                   |       Sector 0 - Partition Table      |
+                   |---------------------------------------|
+                   |        Sector 1 - UBL descriptor      |
+                   |---------------------------------------|
+                   |        Sector 2 - UBL descriptor      |
+                   |---------------------------------------|
+                   |                  ....                 |
+                   |---------------------------------------|
+                   |       Sector 24 - UBL descriptor      |
+                   |---------------------------------------|
+                   |      Sector 25 - u-boot descriptor    |
+                   |---------------------------------------|
+                   |      Sector 26 - u-boot descriptor    |
+                   |---------------------------------------|
+                   |                  ...                  |
+                   |---------------------------------------|
+                   |      Sector 51 - u-boot descriptor    |
+                   |---------------------------------------|
+                   | Sectors 52 to 83 - u-boot environment |
+                   |---------------------------------------|
+                   |      Sectors 84 till 116 - empty      |
+                   |---------------------------------------|
+                   |        Sector 117 - UBL binary        |
+                   |---------------------------------------|
+                   |                  ...                  |
+                   |---------------------------------------|
+                   |        Sector X = u-boot binary       |
+                   |  X = 117 + UBL binary size in blocks  |
+                   |---------------------------------------|
+                   |                  ...                  |
+                   |---------------------------------------|
+                   |       Sector Y = Application use      |
+                   |  Y = X + u-boot binary size in blocks |
+                   |---------------------------------------|
+                   |                  ...                  |
+                   |_______________________________________|
+
+a. The MMC card shall be re-partitioned and formated to create some room for
+   storing UBL and u-boot. Use fdisk utility (as super user) to delete the
+   existing partition and create a new one.
+    # fdisk /dev/mmcblk0 (device name might change if USB card reader is used)
+        - Delete the existing partitions with 'd' command.
+        - Create a new partition with 'n' command, followed by 'p' command
+        - Mark the first cylinder as 20.  Typical cylinder size is 32KBytes. So
+          starting the first cylinder at 20 provides us about 600Kbytes for
+          storing UBL and u-boot.  If the fdisk utility displays a different
+          cylinder size, make sure that you are leaving atleast 500K space
+          before the first cylinder.
+        - Leave the last cylinder to default value (or) any other value
+          depending on the partition size requirements.
+        - Save and exit with 'w' command
+
+b. Format the partition for EXT3 file system
+    # mkfs.ext3 /dev/mmcblk0p1
+
+c. Copy the root file system and kernel uImage onto the newly formated
+   partition. Pre-built images for Davinci DM355EVM platform are available at:
+   http://arago-project.org/files/releases/davinci-psp_3.x.0.0/images/dm355-evm/arago-demo-image-dm355-evm.tar.gz  (and)
+   http://arago-project.org/files/releases/davinci-psp_3.x.0.0/images/dm355-evm/uImage-dm355-evm.bin
+    # mount /dev/mmcblk0p1 /mnt
+    # cd /mnt
+    # tar xzf /path_to_binaries/arago-demo-image-dm355-evm.tar.gz
+    # cp /path_to_binaries/uImage-dm355-evm.bin boot/uImage
+    # cd /home
+    # umount /mnt
+
+d. Modify the config.txt file to set environment variables for u-boot.  These
+   environment variables will be used by default by the u-boot.
+
+e. Using the 'uflash' utility, place the UBL and u-uoot binaries on the MMC
+   card. Copy the u-boot.bin to tools/uflash directory
+    # ./uflash -d /dev/mmcblk0 -u UBL.bin -b u-boot.bin -vv
+        UBL Size 20991
+        u-boot Size 252087
+        First partition starts at 1216(622592)
+        Required Blocks 660, Available Blocks 1215
+        UBL Magic Number        : a1aced00
+        UBL Entry Point         : 00000100
+        UBL Number of Blocks    : 00000028
+        UBL Starting Block      : 00000075
+        UBL Load Address        : 00000000
+        Writing UBL Signature
+        Writing UBL
+        U-Boot Magic Number     : a1aced66
+        U-Boot Entry Point      : 81080000
+        U-Boot Number of Blocks : 000001ec
+        U-Boot Starting Block   : 000000a7
+        Load U-Boot Address     : 81080000
+        Writing U-Boot Signature
+        Writing U-Boot
+        Done...
+
diff --git a/tools/uflash/config.txt b/tools/uflash/config.txt
new file mode 100644
index 0000000..f6acb22
--- /dev/null
+++ b/tools/uflash/config.txt
@@ -0,0 +1,11 @@ 
+bootargs=console=ttyS0,115200n8 root=/dev/mmcblk0p1 rootwait rootfstype=ext3 rw
+bootcmd=ext2load mmc 0 0x80700000 boot/uImage; bootm 0x80700000
+bootdelay=1
+baudrate=115200
+bootfile="uImage"
+stdin=serial
+stdout=serial
+stderr=serial
+ethact=dm9000
+videostd=ntsc
+
diff --git a/tools/uflash/uflash.c b/tools/uflash/uflash.c
new file mode 100644
index 0000000..6b5b609
--- /dev/null
+++ b/tools/uflash/uflash.c
@@ -0,0 +1,383 @@ 
+/*
+ * (C) Copyright, Alagu Sankar <alagusankar@embwise.com>
+ *
+ * Utility for flashing the UBL and U-Boot binary onto SD/MMC cards.
+ * Signature as Required by RBL is Added by this utility.
+ * Tested with DM355EVM Platform with UBL v1.65 and Uboot 2009-03
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+struct rbl_header {
+	unsigned int magic_num;
+	unsigned int entry_point;
+	unsigned int num_blocks;
+	unsigned int start_block;
+	unsigned int load_address;
+	unsigned int padding[123];
+};
+
+#define verbose_printf(x...)	if (verbose) printf(x)
+#define BLOCK_SIZE		512UL
+
+#define UBL_SIGN_START		1
+#define UBL_SIGN_COUNT		24
+#define UBL_MAGIC_NUM		0xA1ACED00
+#define UBL_ENTRY_POINT		0x00000100
+#define UBL_START_BLOCK		0x00000075
+#define UBL_BLOCK_OFFSET	0x0000000A
+
+#define UBOOT_SIGN_START		25
+#define UBOOT_SIGN_COUNT		26
+#define UBOOT_MAGIC_NUM			0xA1ACED66
+#define DM3XX_UBOOT_LOAD_ADDRESS	0x81080000
+#define DA850_UBOOT_LOAD_ADDRESS	0xC1080000
+
+#define PART1_LBA_OFFSET		0x000001C6
+#define DEV_NAME			"/dev/mmcblk0"
+#define UBL_NAME			"UBL.bin"
+#define UBOOT_NAME			"u-boot.bin"
+
+unsigned char ubl_signature[BLOCK_SIZE];
+unsigned char uboot_signature[BLOCK_SIZE];
+unsigned char readbuf[BLOCK_SIZE];
+
+static void print_hex(unsigned char *buf, int len);
+static int get_file_size(char *fname);
+static int write_file(int devfd, char *fname);
+static unsigned int get_le32(unsigned char *buf);
+
+static int verbose;
+static char *dev_name;
+static char *ubl_name;
+static char *uboot_name;
+static char *platform;
+static void usage(void)
+{
+	printf("Usage : uflash [options]\r\n");
+	printf("\t-d DEVNAME     - Block device Name/Node (%s)\r\n", DEV_NAME);
+	printf("\t-u UBL_FILE    - UBL File Name (%s)\r\n", UBL_NAME);
+	printf("\t-b UBOOT_FILE  - UBoot File Name (%s)\r\n", UBOOT_NAME);
+	printf("\t-p PLATFORM    - Platform name (DM3XX/OMAPL138)\r\n");
+	printf("\t-e UBOOT_ENTRY - UBoot Entry Point (0x%X - for DM3XX, 0x%X -"\
+				" for OMAPL138)\r\n", DM3XX_UBOOT_LOAD_ADDRESS,
+						DA850_UBOOT_LOAD_ADDRESS);
+	printf("\t-l UBOOT_LOAD  - UBoot Load Address (0x%X - for DM3XX,"\
+				" 0x%X - for OMAPL138)\r\n",
+		DM3XX_UBOOT_LOAD_ADDRESS, DA850_UBOOT_LOAD_ADDRESS);
+	printf("\r\n");
+}
+
+int main(int argc, char *argv[])
+{
+	int i, devfd, c, readlen, writelen;
+	int req_blocks, part1_offset;
+	int ubl_size = 0, uboot_size;
+	struct rbl_header *rblp;
+	unsigned int uboot_load_address = 0, uboot_entry_point = 0;
+	unsigned int uboot_sign_start = 0, uboot_start_block = 0;
+
+	while ((c = getopt(argc, argv, "?hvd:u:b:l:e:p:")) >= 0) {
+		switch (c) {
+		case 'd':
+			dev_name = optarg;
+			break;
+		case 'u':
+			ubl_name = optarg;
+			break;
+		case 'l':
+			uboot_load_address = strtoul(optarg, NULL, 16);
+			break;
+		case 'e':
+			uboot_entry_point = strtoul(optarg, NULL, 16);
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'b':
+			uboot_name = optarg;
+			break;
+		case 'p':
+			platform = optarg;
+			for (i = 0; i < strlen(platform) - 1; i++)
+				platform[i] = toupper(platform[i]);
+			printf("%s\n", platform);
+			break;
+		case 'h':
+		case '?':
+			usage();
+			return 0;
+		}
+	}
+
+	if (!ubl_name)
+		uboot_start_block = UBL_START_BLOCK;
+
+	if (!strcmp(platform, "DM3XX")) {
+		if (!uboot_load_address)
+			uboot_load_address = DM3XX_UBOOT_LOAD_ADDRESS;
+		if (!uboot_entry_point)
+			uboot_entry_point = DM3XX_UBOOT_LOAD_ADDRESS;
+	}
+
+	if (!strcmp(platform, "OMAPL138")) {
+		if (!uboot_load_address)
+			uboot_load_address = DA850_UBOOT_LOAD_ADDRESS;
+		if (!uboot_entry_point)
+			uboot_entry_point = DA850_UBOOT_LOAD_ADDRESS;
+	}
+
+	/* Open the SD/MMC Device in Read-Write Mode */
+	devfd = open(dev_name, O_RDWR);
+	if (devfd <= 0) {
+		fprintf(stderr, "Device open Error : %s\n", strerror(errno));
+		exit(-1);
+	}
+
+	/* Read Master Boot Record - MBR */
+	readlen = read(devfd, readbuf, BLOCK_SIZE);
+	if (readlen < 0)
+		fprintf(stderr, "Device Read Error : %s\n", strerror(errno));
+
+	if (verbose > 2) {
+		printf("====================Master Boot Record============\n");
+		print_hex(readbuf, BLOCK_SIZE);
+		printf("==================================================\n");
+	}
+
+	/* Get UBL file size and round it to upper 512 byte boundary */
+	if (!strcmp(platform, "DM3XX")) {
+		ubl_size = get_file_size(ubl_name);
+		if (ubl_size < 0) {
+			close(devfd);
+			return -1;
+		}
+
+		ubl_size = (ubl_size + BLOCK_SIZE - 1) & ~BLOCK_SIZE;
+		verbose_printf("UBL Size %d\n", ubl_size);
+	}
+
+	/* Get U-boot file size and round it to upper 512 byte boundary */
+	uboot_size = get_file_size(uboot_name);
+	if (uboot_size <= 0) {
+		fprintf(stderr, "Invalid U-Boot Size %d\n", uboot_size);
+		close(devfd);
+		return -1;
+	}
+	uboot_size = (uboot_size + BLOCK_SIZE - 1) & ~BLOCK_SIZE;
+	verbose_printf("U-Boot Size %d\n", uboot_size);
+
+	/* Get first partition start address offset from Master Boot Record */
+	part1_offset = get_le32 (&readbuf[PART1_LBA_OFFSET]);
+	verbose_printf("First partition starts at %d(%ld)\n", part1_offset,
+			(part1_offset * BLOCK_SIZE));
+
+	/* Add MBR + UBL Size + Uboot Size */
+
+	if (!(strcmp(platform, "DM3XX"))) {
+		req_blocks = UBL_START_BLOCK + (ubl_size / BLOCK_SIZE) +
+		UBL_BLOCK_OFFSET + (uboot_size / BLOCK_SIZE) + 1;
+		printf("Required Blocks %d, Available Blocks %d\n", req_blocks,
+			part1_offset - 1);
+
+		/*
+		 * Return if the card does not have enough
+		 * space for writing UBL/Uboot
+		 */
+		if (req_blocks > part1_offset) {
+			fprintf(stderr, "Not enough space left for "
+					"flashing UBL and U-boot\n");
+			fprintf(stderr, "Make sure that the First Partition "
+				" Starts after %d sectors\n", req_blocks);
+			close(devfd);
+			return -1;
+		}
+
+		/* Generate UBL Signature */
+		rblp = (struct rbl_header *)ubl_signature;
+		memset(rblp, 0, sizeof(struct rbl_header));
+		rblp->magic_num   = UBL_MAGIC_NUM;
+		rblp->entry_point = UBL_ENTRY_POINT;
+		rblp->num_blocks  = ubl_size / BLOCK_SIZE;
+		rblp->start_block = UBL_START_BLOCK;
+
+		if (verbose > 1) {
+			printf("UBL Magic Number     : %08x\n",
+							rblp->magic_num);
+			printf("UBL Entry Point      : %08x\n",
+							rblp->entry_point);
+			printf("UBL Number of Blocks : %08x\n",
+							rblp->num_blocks);
+			printf("UBL Starting Block   : %08x\n",
+							rblp->start_block);
+			printf("UBL Load Address     : %08x\n",
+							rblp->load_address);
+		}
+
+		/* Write UBL Signature */
+		verbose_printf("Writing UBL Signature\n");
+		lseek(devfd, (BLOCK_SIZE * UBL_SIGN_START), SEEK_SET);
+		for (i = UBL_SIGN_START; i <
+				(UBL_SIGN_COUNT + UBL_SIGN_START); i++) {
+			writelen = write(devfd, rblp, BLOCK_SIZE);
+			if (writelen < BLOCK_SIZE) {
+				close(devfd);
+				return -1;
+			}
+		}
+
+		/* Write UBL Binary */
+		verbose_printf("Writing UBL\n");
+		lseek(devfd, (BLOCK_SIZE * rblp->start_block), SEEK_SET);
+		write_file(devfd, ubl_name);
+	}
+
+	/* Generate U-boot signature */
+	rblp = (struct rbl_header *)uboot_signature;
+	memset(rblp, 0, sizeof(struct rbl_header));
+	rblp->magic_num = UBOOT_MAGIC_NUM;
+	rblp->entry_point = uboot_entry_point;
+	rblp->num_blocks = (uboot_size / BLOCK_SIZE) + 1;
+
+	if (!strcmp(platform, "DM3XX")) {
+		rblp->start_block = UBL_START_BLOCK + (ubl_size / BLOCK_SIZE) +
+					UBL_BLOCK_OFFSET;
+	} else if (!strcmp(platform, "OMAPL138")) {
+		rblp->start_block = uboot_start_block;
+		uboot_sign_start = 1;
+	} else {
+		printf("error\n");
+		return -1;
+	}
+
+	rblp->load_address = uboot_load_address;
+
+	if (verbose > 1) {
+		printf("U-Boot Magic Number     : %08x\n", rblp->magic_num);
+		printf("U-Boot Entry Point      : %08x\n", rblp->entry_point);
+		printf("U-Boot Number of Blocks : %08x\n", rblp->num_blocks);
+		printf("U-Boot Starting Block   : %08x\n", rblp->start_block);
+		printf("Load U-Boot Address     : %08x\n", rblp->load_address);
+	}
+
+	/* Write U-Boot Signature */
+	verbose_printf("Writing U-Boot Signature\n");
+	if (!strcmp(platform, "DM3XX"))
+		lseek(devfd, (BLOCK_SIZE * UBOOT_SIGN_START), SEEK_SET);
+	else
+		lseek(devfd, (BLOCK_SIZE * uboot_sign_start), SEEK_SET);
+
+	for (i = UBOOT_SIGN_START; i <
+				(UBOOT_SIGN_COUNT + UBOOT_SIGN_START); i++) {
+		writelen = write(devfd, rblp, BLOCK_SIZE);
+		if (writelen < BLOCK_SIZE) {
+			close(devfd);
+			return -1;
+		}
+	}
+
+	/* Write U-Boot File */
+	lseek(devfd, (BLOCK_SIZE * rblp->start_block), SEEK_SET);
+	verbose_printf("Writing U-Boot\n");
+	write_file(devfd, uboot_name);
+
+	printf("Done...\n");
+	close(devfd);
+	return 0;
+}
+
+static void print_hex(unsigned char *buf, int len)
+{
+	int i, j;
+	for (i = 0 ; i < len; i += 16) {
+		printf("%08x : ", i);
+		for (j = i ; (j < (i+16)) && (j < len); j++)
+			printf("%02x,", buf[j]);
+
+		printf("    ");
+		for (j = i ; (j < (i+16)) && (j < len); j++) {
+			if ((buf[j] > 0x20) && (buf[j] < 0x7F))
+				printf("%c", buf[j]);
+			else
+				printf(".");
+		}
+		printf("\n");
+	}
+}
+
+static int get_file_size(char *fname)
+{
+	FILE *fp;
+	int size;
+
+	fp = fopen(fname, "rb");
+	if (fp == NULL) {
+		fprintf(stdout, "File %s Open Error : %s\n",
+					fname, strerror(errno));
+		return -1;
+	}
+
+	fseek(fp, 0, SEEK_END);
+	size = ftell(fp);
+	fclose(fp);
+
+	return size;
+}
+
+static int write_file(int devfd, char *fname)
+{
+	FILE *fp;
+	int readlen, writelen;
+
+	fp = fopen(fname, "rb");
+	if (fp == NULL) {
+		fprintf(stderr, "File %s Open Error: %s",
+				fname, strerror(errno));
+		return -1;
+	}
+
+	while ((readlen = fread(readbuf, 1, BLOCK_SIZE, fp)) > 0) {
+		if (readlen < BLOCK_SIZE)
+			memset(&readbuf[readlen], 0, BLOCK_SIZE-readlen);
+
+		writelen = write(devfd, readbuf, BLOCK_SIZE);
+		if (writelen < BLOCK_SIZE) {
+			close(devfd);
+			return -1;
+		}
+	}
+
+	fclose(fp);
+
+	return 0;
+}
+
+static unsigned int get_le32 (unsigned char *buf)
+{
+	return (unsigned int)(((unsigned int)buf[0]) |
+		((unsigned int)buf[1] << 8) |
+		((unsigned int)buf[2] << 16) |
+		((unsigned int)buf[3] << 24));
+}