mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
8de16794a0
The MX23 Boot ROM does blindly load from 2048 offset while the MX28 does parse the BCB header to known where to load the image from. We move the BCB header to 4 sectors offset so same code can be used by both SoCs avoiding code duplication. This idea was given by Marek Vasut <marex@denx.de> Signed-off-by: Otavio Salvador <otavio@ossystems.com.br> Tested-by: Fabio Estevam <fabio.estevam@freescale.com> Tested-by: Marek Vasut <marex@denx.de>
687 lines
16 KiB
C
687 lines
16 KiB
C
/*
|
|
* Freescale i.MX28 image generator
|
|
*
|
|
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
|
* on behalf of DENX Software Engineering GmbH
|
|
*
|
|
* See file CREDITS for list of people who contributed to this
|
|
* project.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* 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., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*/
|
|
|
|
#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.
|
|
*/
|
|
uint32_t nand_writesize = 2048;
|
|
uint32_t nand_oobsize = 64;
|
|
uint32_t nand_erasesize = 128 * 1024;
|
|
|
|
/*
|
|
* Sector on which the SigmaTel boot partition (0x53) starts.
|
|
*/
|
|
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, char *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);
|
|
}
|
|
|
|
free(fcbblock);
|
|
return ret;
|
|
}
|
|
|
|
static int mx28_nand_write_dbbt(struct mx28_nand_dbbt *dbbt, char *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,
|
|
char *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;
|
|
}
|
|
|
|
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;
|
|
char *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;
|
|
}
|
|
|
|
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;
|
|
}
|