From patchwork Tue Apr 16 20:15:07 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Dunn X-Patchwork-Id: 237075 X-Patchwork-Delegate: albert.aribaud@free.fr Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 63E1F2C0142 for ; Wed, 17 Apr 2013 06:15:09 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id CC6194A23D; Tue, 16 Apr 2013 22:15:06 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2ApeyZ3SoK0i; Tue, 16 Apr 2013 22:15:06 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 0A3924A235; Tue, 16 Apr 2013 22:15:05 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 203B34A235 for ; Tue, 16 Apr 2013 22:15:04 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id goRdNIaDTSV6 for ; Tue, 16 Apr 2013 22:15:02 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from smtp.newsguy.com (smtp.newsguy.com [74.209.136.69]) by theia.denx.de (Postfix) with ESMTPS id 7BC4E4A22C for ; Tue, 16 Apr 2013 22:15:00 +0200 (CEST) Received: from localhost.localdomain (244.sub-70-199-129.myvzw.com [70.199.129.244]) by smtp.newsguy.com (8.14.3/8.14.3) with ESMTP id r3GKErek038196 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 16 Apr 2013 13:14:53 -0700 (PDT) (envelope-from mikedunn@newsguy.com) From: Mike Dunn To: u-boot@lists.denx.de Date: Tue, 16 Apr 2013 13:15:07 -0700 Message-Id: <1366143307-7055-1-git-send-email-mikedunn@newsguy.com> X-Mailer: git-send-email 1.7.8.6 Cc: Marek Vasut , Tomas Cech , Haojian Zhuang Subject: [U-Boot] [PATCH v4] palmtreo680: add utility that writes u-boot to flash X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This adds a userspace linux utility that writes the u-boot image to an mtd partition on the docg4 nand flash. A special utility is required to do this because u-boot is partially loaded by an initial program loader (IPL) that is permanently programmed to the boot region of the flash. This IPL expects the image to be written in a unique format. The characteristics of this format can be summarized as follows: - Flash blocks to be loaded must have a magic number in the oob bytes of the first page of the block. - Each page must be written redundantly in the subsequent page. - The integrated flash controller's "reliable mode" is used, requiring that alternate 2k regions (4 pages) are skipped when writing. For these reasons, a u-boot image can not be written using nandwrite from mtd-utils. Signed-off-by: Mike Dunn --- Changelog: v4: - use return instead of exit - use calloc() instead of malloc() - remove call to read() from within while loop test v3: new patch; split off from patch 7 in v2 of patchset I was wrong, Marek... the read() will return EOF while writing the last block, unless the size of the image is such that it fills the last block. Otherwise, the last block is only partially written, and stops at EOF. This is fine. tools/palmtreo680/flash_u-boot.c | 168 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 168 insertions(+), 0 deletions(-) create mode 100644 tools/palmtreo680/flash_u-boot.c diff --git a/tools/palmtreo680/flash_u-boot.c b/tools/palmtreo680/flash_u-boot.c new file mode 100644 index 0000000..8f8dadf --- /dev/null +++ b/tools/palmtreo680/flash_u-boot.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2013 Mike Dunn + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 \n", argv[0]); + return -1; + } + + mtd_desc = libmtd_open(); + if (mtd_desc == NULL) { + fprintf(stderr, "can't initialize libmtd\n"); + return -1; + } + + /* open the spl image file and mtd device */ + datafd = open(argv[1], O_RDONLY); + if (datafd == -1) { + perror(argv[1]); + return -1; + } + devfd = open(argv[2], O_WRONLY); + if (devfd == -1) { + perror(argv[2]); + return -1; + } + if (mtd_get_dev_info(mtd_desc, argv[2], &devinfo) < 0) { + fprintf(stderr, "mtd_get_dev_info failed\n"); + return -1; + } + + /* determine the number of blocks needed by the image */ + file_size = lseek(datafd, 0, SEEK_END); + if (file_size == (off_t)-1) { + perror("lseek"); + return -1; + } + num_blocks = (file_size + RELIABLE_BLOCKSIZE - 1) / RELIABLE_BLOCKSIZE; + file_size = lseek(datafd, 0, SEEK_SET); + if (file_size == (off_t)-1) { + perror("lseek"); + return -1; + } + 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 -1; + } + + 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) { + perror("calloc"); + return -1; + } + + 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) { + if (errno == EINTR) + continue; + perror("read"); + return -1; + } 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 -1; + } + 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; +}