diff options
author | Alagu Sankar <alagusankar@embwise.com> | 2012-06-27 14:57:31 +0530 |
---|---|---|
committer | Rajashekhara, Sudhakar <sudhakar.raj@ti.com> | 2012-06-27 14:57:31 +0530 |
commit | 269d186ab8eb3ad22d4fa89b159d02c060b95be7 (patch) | |
tree | 2340320a1abaa05822d0cafb7a1878c6d26b36e2 | |
parent | c99eac11764a9ecda292982469f519e2083d31a5 (diff) |
Davinci: Utility for MMC boot
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>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | tools/Makefile | 2 | ||||
-rw-r--r-- | tools/uflash/Makefile | 13 | ||||
-rw-r--r-- | tools/uflash/README | 125 | ||||
-rw-r--r-- | tools/uflash/config.txt | 11 | ||||
-rw-r--r-- | tools/uflash/uflash.c | 383 |
6 files changed, 534 insertions, 2 deletions
@@ -719,7 +719,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 8993fdd7b2d..e15c21e3fb3 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 00000000000..8ade3c4a176 --- /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 00000000000..8e9c22ca81c --- /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 00000000000..f6acb225fb6 --- /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 00000000000..6b5b6092618 --- /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)); +} |