blob: 7d84dbd419a0370e68f6674985802a139c3e2683 [file] [log] [blame]
/*
* nandwrite and nanddump ported to busybox from mtd-utils
*
* Author: Baruch Siach <baruch@tkos.co.il>, Orex Computed Radiography
*
* Licensed under GPLv2, see file LICENSE in this source tree.
*
* TODO: add support for large (>4GB) MTD devices
*/
#include "libbb.h"
#include <mtd/mtd-user.h>
#include <linux/jffs2.h>
#include <getopt.h>
#define PROGRAM "nandwrite"
#define VERSION "$Revision: 1.32-dropcam $"
#define AMB_VERSION "Ambarella: 0-20110318 $"
#define MAX_PAGE_SIZE 2048
#define MAX_OOB_SIZE 64
struct globals {
/* Buffer array used for writing data */
unsigned char writebuf[MAX_PAGE_SIZE];
unsigned char oobbuf[MAX_OOB_SIZE];
unsigned char oobreadbuf[MAX_OOB_SIZE];
/* oob layouts to pass into the kernel as default */
struct nand_oobinfo none_oobinfo;
struct nand_oobinfo jffs2_oobinfo;
struct nand_oobinfo yaffs_oobinfo;
struct nand_oobinfo autoplace_oobinfo;
};
#define G (*ptr_to_globals)
#define INIT_G() do { \
SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
\
G.none_oobinfo.useecc = MTD_NANDECC_OFF; \
G.autoplace_oobinfo.useecc = MTD_NANDECC_AUTOPLACE; \
\
G.jffs2_oobinfo.useecc = MTD_NANDECC_PLACE; \
G.jffs2_oobinfo.eccbytes = 6; \
G.jffs2_oobinfo.eccpos[0] = 0; \
G.jffs2_oobinfo.eccpos[1] = 1; \
G.jffs2_oobinfo.eccpos[2] = 2; \
G.jffs2_oobinfo.eccpos[3] = 3; \
G.jffs2_oobinfo.eccpos[4] = 6; \
G.jffs2_oobinfo.eccpos[5] = 7; \
\
G.yaffs_oobinfo.useecc = MTD_NANDECC_PLACE; \
G.yaffs_oobinfo.eccbytes = 6; \
G.yaffs_oobinfo.eccpos[0] = 8; \
G.yaffs_oobinfo.eccpos[1] = 9; \
G.yaffs_oobinfo.eccpos[2] = 10; \
G.yaffs_oobinfo.eccpos[3] = 13; \
G.yaffs_oobinfo.eccpos[4] = 14; \
G.yaffs_oobinfo.eccpos[5] = 15; \
} while (0)
#define FLPART_MAGIC 0x8732dfe6
#define __ARMCC_PACK__
#define __ATTRIB_PACK__ __attribute__ ((packed))
#define ETH_INSTANCES 2
#define USE_WIFI 1
#define CMD_LINE_SIZE 512
#define MAC_SIZE 6
#define SN_SIZE 32
typedef __ARMCC_PACK__ struct flpart_s
{
uint32_t crc32; /**< CRC32 checksum of image */
uint32_t ver_num; /**< Version number */
uint32_t ver_date; /**< Version date */
uint32_t img_len; /**< Lengh of image in the partition */
uint32_t mem_addr; /**< Starting address to copy to RAM */
uint32_t flag; /**< Special properties of this partition */
uint32_t magic; /**< Magic number */
} __ATTRIB_PACK__ flpart_t;
/**
* Partitions on device.
*/
/* ------------------------------------------------------------------------- */
/* Below are firmware partitions. (with pre-built image) */
#define PART_BST 0
#define PART_PTB 1
#define PART_BLD 2
#define PART_HAL 3
#define PART_PBA 4
#define PART_PRI 5
#define PART_SEC 6
#define PART_BAK 7
#define PART_RMD 8
#define PART_ROM 9
#define PART_DSP 10
#define PART_LNX 11
/* ------------------------------------------------------------------------- */
/* Below are general purpose partitions. (without pre-built image) */
#define PART_SWP 12
#define PART_ADD 13
#define PART_ADC 14
/* ------------------------------------------------------------------------- */
/* Below are media(nftl) partitions. (without pre-built image) */
#define PART_RAW 15
#define PART_STG2 16
#define PART_STG 17
#define PART_PRF 18
#define PART_CAL 19
const char *g_part_str[] = {"bst", "ptb", "bld", "hal", "pba",
"pri", "sec", "bak", "rmd", "rom",
"dsp", "lnx", "swp", "add", "adc",
"raw", "stg2", "stg", "prf", "cal",
"all"};
#define FLDEV_CMD_LINE_SIZE 1024
/**
* Properties of the network device
*/
typedef __ARMCC_PACK__ struct netdev_s
{
/* This section contains networking related settings */
uint8_t mac[6]; /**< MAC address*/
uint32_t ip; /**< Boot loader's LAN IP */
uint32_t mask; /**< Boot loader's LAN mask */
uint32_t gw; /**< Boot loader's LAN gateway */
} __ATTRIB_PACK__ netdev_t;
/**
* Properties of the target device that is stored in the flash.
*/
typedef __ARMCC_PACK__ struct fldev_s
{
char sn[32]; /**< Serial number */
uint8_t usbdl_mode; /**< USB download mode */
uint8_t auto_boot; /**< Automatic boot */
char cmdline[FLDEV_CMD_LINE_SIZE]; /**< Boot command line options */
uint8_t rsv[2];
uint32_t splash_id;
/* This section contains networking related settings */
netdev_t eth[2];
netdev_t wifi[1]; /* Updating the fldev_t struct */
//netdev_t usb_eth[2];
/* This section contains update by network related settings */
uint8_t auto_dl; /**< Automatic download? */
uint32_t tftpd; /**< Boot loader's TFTP server */
uint32_t pri_addr; /**< RTOS download address */
char pri_file[32]; /**< RTOS file name */
uint8_t pri_comp; /**< RTOS compressed? */
uint32_t rmd_addr; /**< Ramdisk download address */
char rmd_file[32]; /**< Ramdisk file name */
uint8_t rmd_comp; /**< Ramdisk compressed? */
uint32_t dsp_addr; /**< DSP download address */
char dsp_file[32]; /**< DSP file name */
uint8_t dsp_comp; /**< DSP compressed? */
uint8_t rsv2[2];
uint32_t magic; /**< Magic number */
} __ATTRIB_PACK__ fldev_t;
/**
* The partition table is a region in flash where meta data about
* different partitions are stored.
*/
#define PART_MAX_WITH_RSV 32
#define PTB_SIZE 4096
#define PTB_PAD_SIZE \
(PTB_SIZE - PART_MAX_WITH_RSV * sizeof(flpart_t) - sizeof(fldev_t))
typedef __ARMCC_PACK__ struct flpart_table_s
{
flpart_t part[PART_MAX_WITH_RSV];/** Partitions */
/* ------------------------------------------ */
fldev_t dev; /**< Device properties */
uint8_t rsv[PTB_PAD_SIZE]; /**< Padding to 2048 bytes */
} __ATTRIB_PACK__ flpart_table_t;
static const uint32_t *crc32_table;
/* Return a 32-bit CRC of the contents of the buffer. */
static inline uint32_t crc32(uint32_t val, const void *ss, int len)
{
const unsigned char *s = ss;
while (--len >= 0)
val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
return val;
}
static void display_version (void)
{
printf(PROGRAM " " VERSION "" AMB_VERSION "\n"
"\n"
"Copyright (C) 2003 Thomas Gleixner \n"
"\n"
PROGRAM " comes with NO WARRANTY\n"
"to the extent permitted by law.\n"
"\n"
"You may redistribute copies of " PROGRAM "\n"
"under the terms of the GNU General Public Licence.\n"
"See the file `COPYING' for more information.\n");
exit(0);
}
static void display_flpart (const char *name, flpart_t *p_flpart)
{
printf("%s:\n", name);
printf("crc32 \t= 0x%08x\n", p_flpart->crc32);
printf("ver_num = 0x%08x\n", p_flpart->ver_num);
printf("ver_date= 0x%08x\n", p_flpart->ver_date);
printf("img_len = 0x%08x\n", p_flpart->img_len);
printf("mem_addr= 0x%08x\n", p_flpart->mem_addr);
printf("flag \t= 0x%08x\n", p_flpart->flag);
printf("magic \t= 0x%08x\n", p_flpart->magic);
printf("\n");
}
static void display_dev (fldev_t *p_dev)
{
int i;
printf("sn = %s\n", p_dev->sn);
printf("magic = 0x%08x\n", p_dev->magic);
printf("usbdl_mode = 0x%08x\n", p_dev->usbdl_mode);
printf("cmdline = %s\n", p_dev->cmdline);
printf("force_ptb = 0x%08x\n", p_dev->rsv[0]);
printf("auto_boot = %d\n", p_dev->auto_boot);
printf("auto_dl = %d\n", p_dev->auto_dl);
printf("pri_file = %s\n", p_dev->pri_file);
printf("pri_addr = 0x%08x\n", p_dev->pri_addr);
for (i=0 ; i< ETH_INSTANCES ; i++)
{
printf("eth%d MAC = %02x:%02x:%02x:%02x:%02x:%02x\n",i,
p_dev->eth[i].mac[0], p_dev->eth[i].mac[1],
p_dev->eth[i].mac[2], p_dev->eth[i].mac[3],
p_dev->eth[i].mac[4], p_dev->eth[i].mac[5]);
printf("Eth%d ip = %d.%d.%d.%d\n",i,
(p_dev->eth[i].ip) &0xff, (p_dev->eth[i].ip>>8) &0xff,
(p_dev->eth[i].ip>>16) &0xff, (p_dev->eth[i].ip>>24) &0xff);
printf("Eth%d mask = %d.%d.%d.%d\n",i,
(p_dev->eth[i].mask) &0xff, (p_dev->eth[i].mask>>8) &0xff,
(p_dev->eth[i].mask>>16) &0xff, (p_dev->eth[i].mask>>24) &0xff);
printf("Eth%d gw = %d.%d.%d.%d\n",i,
(p_dev->eth[i].gw) &0xff, (p_dev->eth[i].gw>>8) &0xff,
(p_dev->eth[i].gw>>16) &0xff, (p_dev->eth[i].gw>>24) &0xff);
}
if (USE_WIFI)
{
for (i=0; i< USE_WIFI; i++)
{
printf("WIFI%d MAC = %02x:%02x:%02x:%02x:%02x:%02x\n",i,
p_dev->wifi[i].mac[0], p_dev->wifi[i].mac[1],
p_dev->wifi[i].mac[2], p_dev->wifi[i].mac[3],
p_dev->wifi[i].mac[4], p_dev->wifi[i].mac[5]);
printf("WIFI%d ip = %d.%d.%d.%d\n",i,
(p_dev->wifi[i].ip) &0xff,(p_dev->wifi[i].ip>>8) &0xff,
(p_dev->wifi[i].ip>>16) &0xff, (p_dev->wifi[i].ip>>24) &0xff);
printf("WIFI%d mask = %d.%d.%d.%d\n",i,
(p_dev->wifi[i].mask) &0xff,(p_dev->wifi[i].mask>>8) &0xff,
(p_dev->wifi[i].mask>>16) &0xff, (p_dev->wifi[i].mask>>24) &0xff);
printf("WIFI%d gw = %d.%d.%d.%d\n",i,
(p_dev->wifi[i].gw) &0xff,(p_dev->wifi[i].gw>>8) &0xff,
(p_dev->wifi[i].gw>>16) &0xff, (p_dev->wifi[i].gw>>24) &0xff);
}
}
printf("tftpd = %d.%d.%d.%d\n",
( p_dev->tftpd) &0xff,(p_dev->tftpd>>8) &0xff,
(p_dev->tftpd>>16) &0xff, (p_dev->tftpd>>24) &0xff);
printf("\n");
}
#define NANDWRITE_OPTIONS_BASE 0
#define NETWORK_OPTION_BASE 20
enum numeric_short_options {
HELP = NANDWRITE_OPTIONS_BASE,
VERSION_INFO,
AUTO_DOWNLOAD,
AUTO_BOOT,
PRI_ADDR,
PRI_FILE,
SHOW_INFO,
ETH0_IP = NETWORK_OPTION_BASE,
ETH0_MASK,
ETH0_GW,
TFTPD,
ETH1_MAC,
ETH1_IP,
ETH1_MASK,
ETH1_GW,
WIFI0_MAC, //20120331+ for updating with the fldev_t struct
WIFI0_IP,
WIFI0_MASK,
WIFI0_GW,
#if (USE_WIFI >= 2)
WIFI1_MAC,
WIFI1_IP,
WIFI1_MASK,
WIFI1_GW,
#endif
USB_ETH0_MAC,
USB_ETH0_IP,
USB_ETH0_MASK,
USB_ETH0_GW,
USB_ETH1_MAC,
USB_ETH1_IP,
USB_ETH1_MASK,
USB_ETH1_GW,
};
static const char *short_options = "ab:fjnopqd:s:yKMRBGHQIUWXYZC:F:L:S:D:V:E:N:B:";
static struct option long_options[] = {
{"autoplace", no_argument, 0, 'a'},
{"jffs2", no_argument, 0, 'j'},
{"yaffs", no_argument, 0, 'y'},
{"forcelegacy", no_argument, 0, 'f'},
{"noecc", no_argument, 0, 'n'},
{"oob", no_argument, 0, 'o'},
{"start", required_argument, 0, 's'},
{"pad", no_argument, 0, 'p'},
{"blockalign", required_argument, 0, 'b'},
{"quiet", no_argument, 0, 'q'},
{"delay", required_argument, 0, 'd'},
{"help", no_argument, 0, HELP},
{"version", no_argument, 0, VERSION_INFO},
//{"ptb", required_argument, 0, 'P'},
{"bld", no_argument, 0, 'G'},
{"hal", no_argument, 0, 'H'},
{"pba", no_argument, 0, 'Q'},
{"sec", no_argument, 0, 'I'},
{"dsp", no_argument, 0, 'U'},
{"lnx", no_argument, 0, 'W'},
{"swp", no_argument, 0, 'X'},
{"add", no_argument, 0, 'Y'},
{"adc", no_argument, 0, 'Z'},
{"pri", no_argument, 0, 'K'},
{"rmd", no_argument, 0, 'M'},
{"rom", no_argument, 0, 'R'},
{"bak", no_argument, 0, 'B'},
{"cmd", required_argument, 0, 'C'},
{"flag", required_argument, 0, 'F'},
{"safe", required_argument, 0, 'S'},
{"load", required_argument, 0, 'L'},
{"date", required_argument, 0, 'D'},
{"ver", required_argument, 0, 'V'},
{"ethmac", required_argument, 0, 'E'},
{"sn ", required_argument, 0, 'N'},
{"auto_boot", required_argument, 0, AUTO_BOOT},
{"auto_dl", required_argument, 0, AUTO_DOWNLOAD},
{"pri_addr", required_argument, 0, PRI_ADDR},
{"pri_file", required_argument, 0, PRI_FILE},
{"lan_ip", required_argument, 0, ETH0_IP},
{"lan_mask", required_argument, 0, ETH0_MASK},
{"lan_gw", required_argument, 0, ETH0_GW},
{"tftpd ", required_argument, 0, TFTPD},
{"eth1_mac", required_argument, 0, ETH1_MAC},
{"eth1_ip", required_argument, 0, ETH1_IP},
{"eth1_mask", required_argument, 0, ETH1_MASK},
{"eth1_gw", required_argument, 0, ETH1_GW},
{"wifi0_mac", required_argument, 0, WIFI0_MAC},
{"wifi0_ip", required_argument, 0, WIFI0_IP},
{"wifi0_mask", required_argument, 0, WIFI0_MASK},
{"wifi0_gw", required_argument, 0, WIFI0_GW},
#if (USE_WIFI >= 2)
{"wifi1_mac", required_argument, 0, WIFI1_MAC},
{"wifi1_ip", required_argument, 0, WIFI1_IP},
{"wifi1_mask", required_argument, 0, WIFI1_MASK},
{"wifi1_gw", required_argument, 0, WIFI1_GW},
#endif
{"show_info", no_argument, 0, SHOW_INFO},
{0, 0, 0, 0},
};
struct hint_s {
const char *arg;
const char *str;
};
static const struct hint_s hint[] = {
{"", "Use auto oob layout"},
{"", "force jffs2 oob layout (legacy support)"},
{"", "force yaffs oob layout (legacy support)"},
{"", "force legacy support on autoplacement enabled mtd device"},
{"", "write without ecc"},
{"", "image contains oob data"},
{"", "set start address (default is 0)"},
{"", "pad to page size"},
{"blockalign=1|2|4", "set multiple of eraseblocks to align to"},
{"", "don't display progress messages"},
{"", "add x microsecond delay between block writes"},
{"", "display this help and exit"},
{"", "output version information and exit"},
{"", "Update Ambarella AMBOOT BLD Partition"},
{"", "Update Ambarella AMBOOT HAL Partition"},
{"", "Update Ambarella AMBOOT PBA Partition"},
{"", "Update Ambarella AMBOOT SEC Partition "},
{"", "Update Ambarella AMBOOT DSP Partition "},
{"", "Update Ambarella AMBOOT LNX Partition "},
{"", "Update Ambarella AMBOOT SWP Partition "},
{"", "Update Ambarella AMBOOT ADD Partition "},
{"", "Update Ambarella AMBOOT ADC Partition "},
{"", "Update Ambarella AMBOOT PRI Partition "},
{"", "Update Ambarella AMBOOT RMD Partition "},
{"", "Update Ambarella AMBOOT ROM Partition "},
{"", "Update Ambarella AMBOOT BAK Partition "},
{"", "Update Ambarella AMBOOT CMD line "},
{"hex", "Update Ambarella AMBOOT Partition load flag "},
{"hex", "force AMBOOT boot form PTB, safe recovery "},
{"hex", "Update Ambarella AMBOOT Partition load address "},
{"hex", "Update Ambarella AMBOOT Partition date "},
{"hex", "Update Ambarella AMBOOT Partition version "},
{"MAC", "Update Ambarella AMBOOT eth0 MAC "},
{"sn", "Update Ambarella AMBOOT SN "},
{"hex", "Update Ambarella AMBOOT load linux from nandflash or no "},
{"hex", "Update Ambarella AMBOOT load linux from network or no "},
{"str", "Update Ambarella updated file name(32bytes) "},
{"hex", "Update Ambarella AMBOOT pri_addr "},
{"ip", "Update Ambarella AMBOOT eth0 lan ip "},
{"ip", "Update Ambarella AMBOOT eth0 lan mask "},
{"ip", "Update Ambarella AMBOOT eth0 lan gw "},
{"ip", "Update Ambarella AMBOOT eth0 tftpd ip "},
{"MAC", "Update Ambarella AMBOOT eth1 MAC "},
{"ip", "Update Ambarella AMBOOT eth1 lan ip "},
{"ip", "Update Ambarella AMBOOT eth1 lan mask "},
{"ip", "Update Ambarella AMBOOT eth1 lan gw "},
{"MAC", "Update Ambarella AMBOOT wifi0 MAC "},
{"ip", "Update Ambarella AMBOOT wifi0 ip "},
{"ip", "Update Ambarella AMBOOT wifi0 mask"},
{"ip", "Update Ambarella AMBOOT wifi0 gw "},
#if (USE_WIFI >= 2)
{"MAC", "Update Ambarella AMBOOT wifi1 MAC "},
{"ip", "Update Ambarella AMBOOT wifi1 ip "},
{"ip", "Update Ambarella AMBOOT wifi1 mask"},
{"ip", "Update Ambarella AMBOOT wifi1 gw "},
#endif
{"", "Show Ambarella AMBOOT information "},
};
static void usage(void)
{
int i;
printf("Usage:nandwrite [OPTION] MTD_DEVICE INPUTFILE\n"
"Writes to the specified MTD device.\n"
"\n");
for (i = 0; i < sizeof(long_options) / sizeof(long_options[0]) - 1; i++) {
if (isalpha(long_options[i].val))
printf("-%c ", long_options[i].val);
else
printf(" ");
printf("--%s", long_options[i].name);
if (hint[i].arg[0] != 0)
printf(" [%s]", hint[i].arg);
printf("\t%s\n", hint[i].str);
}
printf("\n");
}
/**
* Converts a string to a ethernet HW address. (xx:xx:xx:xx:xx:xx).
*/
static int str_to_hwaddr(const char *bufp, uint8_t *hwaddr)
{
unsigned char *ptr;
int i, j;
unsigned char val;
unsigned char c;
ptr = hwaddr;
i = 0;
do {
j = val = 0;
/* We might get a semicolon here - not required. */
if (i && (*bufp == ':')) {
bufp++;
}
do {
c = *bufp;
if (((unsigned char)(c - '0')) <= 9) {
c -= '0';
} else if (((unsigned char)((c | 0x20) - 'a')) <= 5) {
c = (c | 0x20) - ('a' - 10);
} else if (j && (c == ':' || c == 0)) {
break;
} else {
return -1;
}
++bufp;
val <<= 4;
val += c;
} while (++j < 2);
*ptr++ = val;
} while (++i < MAC_SIZE);
return (int) (*bufp); /* Error if we don't end at end of string. */
}
static int str_to_ipaddr(const char *src, uint32_t *addr)
{
int saw_digit, octets, ch;
unsigned char tmp[4], *tp;
saw_digit = 0;
octets = 0;
*(tp = tmp) = 0;
while ((ch = *src++) != '\0') {
if (ch >= '0' && ch <= '9') {
unsigned int new = *tp * 10 + (ch - '0');
if (new > 255)
return (0);
*tp = new;
if (! saw_digit) {
if (++octets > 4)
return (0);
saw_digit = 1;
}
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return (0);
*++tp = 0;
saw_digit = 0;
} else
return -1;
}
if (octets < 4)
return -2;
memcpy(addr, tmp, 4);
return 0;
}
static char *mtd_device, *img;
static int mtdoffset = 0;
static int quiet = 0;
static int delay = 0;
static int writeoob = 0;
static int autoplace = 0;
static int forcejffs2 = 0;
static int forceyaffs = 0;
static int forcelegacy = 0;
static int noecc = 0;
static int pad = 0;
static int blockalign = 1; /*default to using 16K block size */
static char ptb_device[1024] = "/dev/mtd1";
//static int ambarella_ptb = 0;
static int ambarella_bld = 0;
static int ambarella_hal = 0;
static int ambarella_pba = 0;
static int ambarella_sec = 0;
static int ambarella_dsp = 0;
static int ambarella_lnx = 0;
static int ambarella_swp = 0;
static int ambarella_add = 0;
static int ambarella_adc = 0;
static int ambarella_pri = 0;
static int ambarella_rmd = 0;
static int ambarella_rom = 0;
static int ambarella_bak = 0;
static int ambarella_cmd = 0;
static uint32_t ambarella_flpart_flag = 0;
static uint32_t ambarella_flpart_mem_addr = 0;
static uint32_t ambarella_flpart_version = 0;
static uint32_t ambarella_flpart_date = 0;
static int ambarella_force_ptb = 0;
static int ambarella_ptb_data = 0;
static char ambarella_cmdline[CMD_LINE_SIZE];
static int ambarella_skip_img = 0;
static int ambarella_sn = 0;
static char ambarella_sn_data[SN_SIZE];
static int ambarella_auto_dl = 0;
static uint8_t ambarella_auto_dl_data=1;
static int ambarella_auto_boot = 0;
static uint8_t ambarella_auto_boot_data=1;
static int ambarella_eth = 0;
static uint8_t ambarella_eth_mac[MAC_SIZE];
static int ambarella_lan_ip = 0;
static uint32_t ambarella_lan_ip_data;
static int ambarella_lan_mask = 0;
static uint32_t ambarella_lan_mask_data;
static int ambarella_lan_gw = 0;
static uint32_t ambarella_lan_gw_data;
static int ambarella_tftpd = 0;
static uint32_t ambarella_tftpd_data;
#if (ETH_INSTANCES >= 2)
static int ambarella_eth1 = 0;
static uint8_t ambarella_eth1_mac[MAC_SIZE];
static int ambarella_eth1_ip = 0;
static uint32_t ambarella_eth1_ip_data;
static int ambarella_eth1_mask = 0;
static uint32_t ambarella_eth1_mask_data;
static int ambarella_eth1_gw = 0;
static uint32_t ambarella_eth1_gw_data;
#endif
#if ( USE_WIFI >=1 )
static int ambarella_wifi0 = 0;
static uint8_t ambarella_wifi0_mac[MAC_SIZE];
static int ambarella_wifi0_ip = 0;
static uint32_t ambarella_wifi0_ip_data;
static int ambarella_wifi0_mask = 0;
static uint32_t ambarella_wifi0_mask_data;
static int ambarella_wifi0_gw = 0;
static uint32_t ambarella_wifi0_gw_data;
#endif
/* 20120331+ for updating with the fldev_t struct */
#if (USE_WIFI >=2)
static int ambarella_wifi1 = 0;
static uint8_t ambarella_wifi1_mac[MAC_SIZE];
static int ambarella_wifi1_ip = 0;
static uint32_t ambarella_wifi1_ip_data;
static int ambarella_wifi1_mask = 0;
static uint32_t ambarella_wifi1_mask_data;
static int ambarella_wifi1_gw = 0;
static uint32_t ambarella_wifi1_gw_data;
#endif
static int ambarella_show_info_flag = 0;
static int ambarella_pri_addr = 0;
static uint32_t ambarella_pri_addr_data;
static int ambarella_pri_file = 0;
static char ambarella_pri_file_data[32];
static void process_options (int argc, char *argv[])
{
int error = 0;
int ch;
int option_index = 0;
while ((ch = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
switch (ch) {
case HELP:
usage();
break;
case VERSION_INFO:
display_version();
break;
case AUTO_DOWNLOAD:
ambarella_auto_dl = 1;
ambarella_auto_dl_data=strtoul (optarg, NULL, 0);
ambarella_skip_img = 1;
break;
case AUTO_BOOT:
ambarella_auto_boot = 1;
ambarella_auto_boot_data=strtoul (optarg, NULL, 0);
ambarella_skip_img = 1;
break;
case PRI_ADDR:
ambarella_pri_addr = 1;
ambarella_pri_addr_data = strtoul (optarg, NULL, 0);
ambarella_skip_img = 1;
break;
case PRI_FILE:
ambarella_pri_file = 1;
strncpy(ambarella_pri_file_data, optarg, SN_SIZE);
ambarella_skip_img = 1;
break;
case ETH0_IP:
ambarella_lan_ip=1;
if (str_to_ipaddr(optarg,&ambarella_lan_ip_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case ETH0_MASK:
ambarella_lan_mask = 1;
if (str_to_ipaddr(optarg,&ambarella_lan_mask_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case ETH0_GW:
ambarella_lan_gw = 1;
if (str_to_ipaddr(optarg,&ambarella_lan_gw_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case TFTPD:
ambarella_tftpd = 1;
if (str_to_ipaddr(optarg,&ambarella_tftpd_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case ETH1_MAC:
if (str_to_hwaddr(optarg, ambarella_eth1_mac) != 0) {
perror ("hwaddr error!\n");
error = 1;
}
ambarella_eth1 = 1;
ambarella_skip_img = 1;
break;
case ETH1_IP:
ambarella_eth1_ip=1;
if (str_to_ipaddr(optarg,&ambarella_eth1_ip_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case ETH1_MASK:
ambarella_eth1_mask = 1;
if (str_to_ipaddr(optarg,&ambarella_eth1_mask_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case ETH1_GW:
ambarella_eth1_gw=1;
if (str_to_ipaddr(optarg,&ambarella_eth1_gw_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case WIFI0_MAC:
if (str_to_hwaddr(optarg, ambarella_wifi0_mac) != 0) {
perror ("hwaddr error!\n");
error = 1;
}
ambarella_wifi0 = 1;
ambarella_skip_img = 1;
break;
case WIFI0_IP:
ambarella_wifi0_ip = 1;
if (str_to_ipaddr(optarg,&ambarella_wifi0_ip_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case WIFI0_MASK:
ambarella_wifi0_mask = 1;
if (str_to_ipaddr(optarg,&ambarella_wifi0_mask_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case WIFI0_GW:
ambarella_wifi0_gw = 1;
if (str_to_ipaddr(optarg,&ambarella_wifi0_gw_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
#if (USE_WIFI >= 2)
case WIFI1_MAC:
if (str_to_hwaddr(optarg, ambarella_wifi1_mac) != 0) {
perror ("hwaddr error!\n");
error = 1;
}
ambarella_wifi1 = 1;
ambarella_skip_img = 1;
break;
case WIFI1_IP:
ambarella_wifi1_ip = 1;
if (str_to_ipaddr(optarg,&ambarella_wifi1_ip_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case WIFI1_MASK:
ambarella_wifi1_mask = 1;
if (str_to_ipaddr(optarg,&ambarella_wifi1_mask_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
case WIFI1_GW:
ambarella_wifi1_gw = 1;
if (str_to_ipaddr(optarg,&ambarella_wifi1_gw_data))
{
printf ("IP error \n");
return;
}
ambarella_skip_img = 1;
break;
#endif
case SHOW_INFO:
ambarella_show_info_flag = 1;
ambarella_skip_img = 1;
break;
case 'q':
quiet = 1;
break;
case 'd':
delay = atoi(optarg);
fprintf(stdout, "delay will be %dus between block writes\n", delay);
break;
case 'a':
autoplace = 1;
break;
case 'j':
forcejffs2 = 1;
break;
case 'y':
forceyaffs = 1;
break;
case 'f':
forcelegacy = 1;
break;
case 'n':
noecc = 1;
break;
case 'o':
writeoob = 1;
break;
case 'p':
pad = 1;
break;
case 's':
mtdoffset = strtol (optarg, NULL, 0);
break;
case 'b':
blockalign = atoi (optarg);
break;
case 'T':
strncpy(ptb_device, optarg, sizeof(ptb_device));
break;
case 'K':
ambarella_pri = 1;
break;
case 'M':
ambarella_rmd = 1;
break;
case 'R':
ambarella_rom = 1;
break;
case 'B':
ambarella_bak = 1;
break;
//case 'A':
//ambarella_ptb = 1;
//break;
case 'G':
ambarella_bld = 1;
break;
case 'H':
ambarella_hal = 1;
break;
case 'Q':
ambarella_pba = 1;
break;
case 'I':
ambarella_sec = 1;
break;
case 'U':
ambarella_dsp = 1;
break;
case 'W':
ambarella_lnx = 1;
break;
case 'X':
ambarella_swp = 1;
break;
case 'Y':
ambarella_add = 1;
break;
case 'Z':
ambarella_adc = 1;
break;
case 'C':
ambarella_cmd = 1;
strncpy(ambarella_cmdline, optarg, CMD_LINE_SIZE);
ambarella_skip_img = 1;
break;
case 'F':
ambarella_flpart_flag = strtoul (optarg, NULL, 0);
break;
case 'L':
ambarella_flpart_mem_addr = strtoul (optarg, NULL, 0);
break;
case 'V':
ambarella_flpart_version = strtoul (optarg, NULL, 0);
break;
case 'D':
ambarella_flpart_date = strtoul (optarg, NULL, 0);
break;
case 'S':
ambarella_force_ptb = 1;
ambarella_ptb_data = atoi (optarg);
ambarella_skip_img = 1;
break;
case 'E':
if (str_to_hwaddr(optarg, ambarella_eth_mac) != 0) {
perror ("hwaddr error!\n");
error = 1;
}
ambarella_eth = 1;
ambarella_skip_img = 1;
break;
case 'N':
strncpy(ambarella_sn_data, optarg, SN_SIZE);
ambarella_sn = 1;
ambarella_skip_img = 1;
break;
case '?':
error = 1;
break;
}
}
if ((((argc - optind) != 2) && (ambarella_skip_img != 1)) || error)
usage ();
if ((argc - optind) == 2) {
mtd_device = argv[optind++];
img = argv[optind];
ambarella_skip_img = 0;
}
}
/**
* Get the ptb.dev parameters which are original settings of firmware.
*/
#if 0
static void flprog_get_dev_param(flpart_table_t *table)
{
table->dev.usbdl_mode = 0;
table->dev.auto_boot = 1;
memset(table->dev.cmdline, 0x0, sizeof(table->dev.cmdline));
}
#endif
/**
* Get the content of the partition table.
*/
static int flprog_get_part_table (uint8_t **ptb_buf)
{
int ret, i, count;
int ptb_fd, ptb_offset;
struct mtd_info_user ptb_meminfo;
loff_t ptb_bad_offset;
flpart_table_t *table;
/* Open the PTB device */
if ((ptb_fd = open(ptb_device, O_RDONLY)) == -1) {
perror("open PTB");
exit(1);
}
/* Fill in MTD device capability structure */
if ((ret = ioctl(ptb_fd, MEMGETINFO, &ptb_meminfo)) != 0) {
perror("PTB MEMGETINFO");
goto closeall;
}
for (ptb_offset = 0; ptb_offset < ptb_meminfo.size; ptb_offset += ptb_meminfo.erasesize) {
ptb_bad_offset = ptb_offset;
if ((ret = ioctl(ptb_fd, MEMGETBADBLOCK, &ptb_bad_offset)) < 0) {
perror("ioctl(MEMGETBADBLOCK)");
goto closeall;
}
if (ret == 0)
break;
if (!quiet)
fprintf (stderr,
"Bad block at %x, from %x will be skipped\n",
(int)ptb_bad_offset, ptb_offset);
}
if (ptb_offset >= ptb_meminfo.size) {
fprintf(stderr, "Can't find good block in PTB.\n");
ret = -1;
goto closeall;
}
/* ptb_buf will be freed in flprog_set_part_table() */
*ptb_buf = xmalloc(ptb_meminfo.erasesize);
/* Read partition table.
* Note: we need to read and save the entire block data, because the
* entire block will be erased when write partition table back to flash.
* BTW, flpart_meta_t is located in the same block as flpart_table_t
*/
count = ptb_meminfo.erasesize;
if (pread(ptb_fd, *ptb_buf, count, ptb_offset) != count) {
perror("pread PTB");
ret = -1;
free(*ptb_buf);
goto closeall;
}
table = (flpart_table_t *)(*ptb_buf);
if (!quiet) {
for(i = 0; i < PART_MAX_WITH_RSV; i++){
if( table->part[i].img_len!=0)
display_flpart(g_part_str[i], &(table->part[i]));
}
display_dev(&(table->dev));
}
closeall:
close(ptb_fd);
return ret;
}
/**
* Program the PTB entry.
*/
static int flprog_set_part_table(uint8_t **ptb_buf)
{
int ret, i, count, ptb_fd, ptb_offset;
struct mtd_info_user ptb_meminfo;
loff_t ptb_bad_offset;
flpart_table_t *table = (flpart_table_t *)(*ptb_buf);
/* Open the PTB device */
if ((ptb_fd = open(ptb_device, O_RDWR)) == -1) {
perror("open PTB");
exit(1);
}
/* Fill in MTD device capability structure */
if ((ret = ioctl(ptb_fd, MEMGETINFO, &ptb_meminfo)) != 0) {
perror("PTB MEMGETINFO");
goto closeall;
}
if (PTB_SIZE > ptb_meminfo.erasesize) {
fprintf(stderr, "PTB can't fit into erasesize.\n");
ret = -1;
goto closeall;
}
for (ptb_offset = 0; ptb_offset < ptb_meminfo.size; ptb_offset += ptb_meminfo.erasesize) {
ptb_bad_offset = ptb_offset;
if ((ret = ioctl(ptb_fd, MEMGETBADBLOCK, &ptb_bad_offset)) < 0) {
perror("ioctl(MEMGETBADBLOCK)");
goto closeall;
}
if (ret == 0) {
/* This isn't a bad block, so erase it first */
erase_info_t erase;
erase.start = ptb_offset;
erase.length = ptb_meminfo.erasesize;
if ((ret = ioctl(ptb_fd, MEMERASE, &erase)) != 0) {
perror("PTB MEMERASE");
continue;
}
break;
}
if (!quiet)
fprintf (stderr,
"Bad block at %x, from %x will be skipped\n",
(int)ptb_bad_offset, ptb_offset);
}
if (ptb_offset >= ptb_meminfo.size) {
fprintf(stderr, "Can't find good block in PTB.\n");
ret = -1;
goto closeall;
}
#if 0
if (table->dev.magic != FLPART_MAGIC) {
memset(&table->dev, 0x0, sizeof(table->dev));
flprog_get_dev_param(table);
table->dev.magic = FLPART_MAGIC;
}
for(i = 0; i < PART_MAX_WITH_RSV; i++){
if (table->part[i].img_len != 0 && table->part[i].magic != FLPART_MAGIC) {
memset(&table->part[i], 0x0, sizeof(table->part[i]));
table->part[i].magic = FLPART_MAGIC;
}
}
#else
if (table->dev.magic != FLPART_MAGIC) {
fprintf(stderr, "Invalid dev magic: 0x%08x(0x%08x)\n",
table->dev.magic, FLPART_MAGIC);
ret = -1;
goto closeall;
}
for(i = 0; i < PART_MAX_WITH_RSV; i++){
if (table->part[i].img_len != 0 && table->part[i].magic != FLPART_MAGIC) {
fprintf(stderr,
"Invalid partition table magic(%d): 0x%08x(0x%08x)\n",
i, table->part[i].magic, FLPART_MAGIC);
ret = -1;
goto closeall;
}
}
#endif
count = ptb_meminfo.erasesize;
if (pwrite(ptb_fd, *ptb_buf, count, ptb_offset) != count) {
perror ("pwrite PTB");
ret = -1;
goto closeall;
}
if (!quiet) {
for(i = 0;i < PART_MAX_WITH_RSV; i++){
if( table->part[i].img_len!=0)
display_flpart(g_part_str[i], &table->part[i]);
}
display_dev(&table->dev);
}
closeall:
free(*ptb_buf);
close(ptb_fd);
return ret;
}
/*
* Main program
*/
int nandwrite_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int nandwrite_main(int argc, char **argv)
{
int cnt, fd, ifd, pagelen, baderaseblock, blockstart = -1;
int ret, readlen, oobinfochanged = 0;
int image_crc = ~0U, image_length = 0, imglen = 0;
uint8_t *ptb_buf = NULL;
flpart_table_t *ptb_table;
struct nand_oobinfo old_oobinfo;
struct mtd_info_user meminfo;
struct mtd_oob_buf oob;
loff_t offs;
unsigned char readbuf[MAX_PAGE_SIZE];
int file_offset = mtdoffset;
int buf_num = 0;
INIT_G();
if (argc < 2) {
usage();
return -1;
}
process_options(argc, argv);
if (ambarella_skip_img == 1)
goto ambarella_process;
memset(G.oobbuf, 0xff, sizeof(G.oobbuf));
if (pad && writeoob) {
fprintf(stderr, "Can't pad when oob data is present.\n");
exit(1);
}
/* Open the device */
if ((fd = open(mtd_device, O_RDWR)) == -1) {
perror("open flash");
exit(1);
}
/* Fill in MTD device capability structure */
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
perror("MEMGETINFO");
close(fd);
exit(1);
}
/* Set erasesize to specified number of blocks - to match jffs2
* (virtual) block size */
meminfo.erasesize *= blockalign;
/* Make sure device page sizes are valid */
if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
!(meminfo.oobsize == 8 && meminfo.writesize == 256) &&
!(meminfo.oobsize == 64 && meminfo.writesize == 2048)) {
fprintf(stderr, "Unknown flash (not normal NAND)\n");
close(fd);
exit(1);
}
if (autoplace) {
/* Read the current oob info */
if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMGETOOBSEL");
close (fd);
exit (1);
}
// autoplace ECC ?
if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
if (ioctl (fd, MEMSETOOBSEL, &G.autoplace_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close (fd);
exit (1);
}
oobinfochanged = 1;
}
}
if (noecc) {
ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW);
if (ret == 0) {
oobinfochanged = 2;
} else {
switch (errno) {
case ENOTTY:
if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMGETOOBSEL");
close (fd);
exit (1);
}
if (ioctl (fd, MEMSETOOBSEL, &G.none_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close (fd);
exit (1);
}
oobinfochanged = 1;
break;
default:
perror ("MTDFILEMODE");
close (fd);
exit (1);
}
}
}
/*
* force oob layout for jffs2 or yaffs ?
* Legacy support
*/
if (forcejffs2 || forceyaffs) {
struct nand_oobinfo *oobsel = forcejffs2 ? &G.jffs2_oobinfo : &G.yaffs_oobinfo;
if (autoplace) {
fprintf(stderr, "Autoplacement is not possible for legacy -j/-y options\n");
goto restoreoob;
}
if ((old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) && !forcelegacy) {
fprintf(stderr, "Use -f option to enforce legacy placement on autoplacement enabled mtd device\n");
goto restoreoob;
}
if (meminfo.oobsize == 8) {
if (forceyaffs) {
fprintf (stderr, "YAFSS cannot operate on 256 Byte page size");
goto restoreoob;
}
/* Adjust number of ecc bytes */
G.jffs2_oobinfo.eccbytes = 3;
}
if (ioctl (fd, MEMSETOOBSEL, oobsel) != 0) {
perror ("MEMSETOOBSEL");
goto restoreoob;
}
}
oob.length = meminfo.oobsize;
oob.ptr = noecc ? G.oobreadbuf : G.oobbuf;
/* Open the input file */
if ((ifd = open(img, O_RDONLY)) == -1) {
perror("open input file");
goto restoreoob;
}
// get image length
imglen = lseek(ifd, 0, SEEK_END);
lseek (ifd, 0, SEEK_SET);
image_length = imglen;
pagelen = meminfo.writesize + ((writeoob == 1) ? meminfo.oobsize : 0);
// Check, if file is pagealigned
if ((!pad) && ((imglen % pagelen) != 0)) {
fprintf (stderr, "Input file is not page aligned\n");
goto closeall;
}
// Check, if length fits into device
if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) {
fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %u bytes\n",
imglen, pagelen, meminfo.writesize, meminfo.size);
perror ("Input file does not fit into device");
goto closeall;
}
crc32_table = crc32_filltable(NULL, 0);
/* Get data from input and write to the device */
while (imglen && (mtdoffset < meminfo.size)) {
// new eraseblock , check for bad block(s)
// Stay in the loop to be sure if the mtdoffset changes because
// of a bad block, that the next block that will be written to
// is also checked. Thus avoiding errors if the block(s) after the
// skipped block(s) is also bad (number of blocks depending on
// the blockalign
while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) {
if (delay) {
usleep(delay);
}
blockstart = mtdoffset & (~meminfo.erasesize + 1);
offs = blockstart;
baderaseblock = 0;
if (!quiet)
fprintf (stdout, "Writing data to block %x\n", blockstart);
/* Check all the blocks in an erase block for bad blocks */
do {
if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
perror("ioctl(MEMGETBADBLOCK)");
goto closeall;
}
if (ret == 1) {
baderaseblock = 1;
if (!quiet)
fprintf (stderr, "Bad block at %x, %u block(s) "
"from %x will be skipped\n",
(int) offs, blockalign, blockstart);
}
if (baderaseblock) {
mtdoffset = blockstart + meminfo.erasesize;
}
offs += meminfo.erasesize / blockalign ;
} while ( offs < blockstart + meminfo.erasesize );
}
readlen = meminfo.writesize;
if (pad && (imglen < readlen))
{
readlen = imglen;
memset(G.writebuf + readlen, 0xff, meminfo.writesize - readlen);
}
/* Read Page Data from input file */
if ((cnt = pread(ifd, G.writebuf, readlen,file_offset)) != readlen) {
if (cnt == 0) // EOF
break;
perror ("File I/O error on input file");
goto closeall;
}
image_crc = crc32(image_crc, G.writebuf, cnt);
if (writeoob) {
/* Read OOB data from input file, exit on failure */
if ((cnt = pread(ifd, G.oobreadbuf, meminfo.oobsize,file_offset)) != meminfo.oobsize) {
perror ("File I/O error on input file");
goto closeall;
}
if (!noecc) {
int i, start, len, filled;
/*
* We use autoplacement and have the oobinfo with the autoplacement
* information from the kernel available
*
* Modified to support out of order oobfree segments,
* such as the layout used by diskonchip.c
*/
if (!oobinfochanged && (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE)) {
for (filled = 0, i = 0; old_oobinfo.oobfree[i][1] && (i < MTD_MAX_OOBFREE_ENTRIES); i++) {
/* Set the reserved bytes to 0xff */
start = old_oobinfo.oobfree[i][0];
len = old_oobinfo.oobfree[i][1];
memcpy(G.oobbuf + start,
G.oobreadbuf + filled,
len);
filled += len;
}
} else {
/* Set at least the ecc byte positions to 0xff */
start = old_oobinfo.eccbytes;
len = meminfo.oobsize - start;
memcpy(G.oobbuf + start,
G.oobreadbuf + start,
len);
}
}
/* Write OOB data first, as ecc will be placed in there*/
oob.start = mtdoffset;
if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
perror ("ioctl(MEMWRITEOOB)");
goto closeall;
}
imglen -= meminfo.oobsize;
}
/* Write out the Page data */
if (pwrite(fd, G.writebuf, meminfo.writesize, mtdoffset) != meminfo.writesize) {
perror ("pwrite");
goto closeall;
}
/* read out the Page data */
if (pread(fd, readbuf, meminfo.writesize, mtdoffset) != meminfo.writesize) {
perror ("pread");
goto closeall;
}
buf_num=0;
while ((G.writebuf[buf_num]==readbuf[buf_num]) && (buf_num < readlen)) buf_num++;
//if (((blockstart/MAX_PAGE_SIZE/64) % 10) == 9)
if (buf_num < readlen)
{
//printf("offs[%x ],blockstart[%x],mtdoffset[%x],writesize[0x%x], buf_num[0x%x]\n",(int)offs,blockstart,mtdoffset,meminfo.writesize, buf_num);
/* set bad blocks */
offs = (loff_t) blockstart;
if ((ret = ioctl(fd, MEMSETBADBLOCK, &offs)) < 0) {
perror("ioctl(MEMSETBADBLOCK)");
goto closeall;
}
if ((ret == 0) && (!quiet)) {
fprintf (stdout, "set Bad block at %x !\n",blockstart);
file_offset = file_offset - (mtdoffset-blockstart);
imglen = imglen+ (mtdoffset-blockstart);;
mtdoffset = blockstart + meminfo.erasesize;
}
}
else {
imglen -= readlen;
mtdoffset += meminfo.writesize;
file_offset+= meminfo.writesize;
}
}
closeall:
close(ifd);
restoreoob:
if (oobinfochanged == 1) {
if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
perror ("MEMSETOOBSEL");
close (fd);
exit (1);
}
}
close(fd);
if (imglen > 0) {
perror ("Data was only partially written due to error\n");
exit (1);
}
image_crc ^= ~0U;
printf ("image_length = 0x%08x\n", image_length);
printf ("image_crc = 0x%08x\n", image_crc);
ambarella_process:
if (ambarella_bld ||ambarella_force_ptb|| ambarella_hal ||
ambarella_pba || ambarella_sec || ambarella_dsp ||
ambarella_lnx || ambarella_swp || ambarella_add ||
ambarella_adc || ambarella_pri || ambarella_rmd ||
ambarella_rom || ambarella_cmd || ambarella_eth ||
ambarella_sn || ambarella_bak || ambarella_auto_dl ||
ambarella_auto_boot || ambarella_lan_ip || ambarella_lan_mask ||
ambarella_lan_gw || ambarella_tftpd || ambarella_pri_addr ||
ambarella_pri_file || ambarella_show_info_flag||
ambarella_eth1 || ambarella_eth1_ip || ambarella_eth1_mask ||
ambarella_eth1_gw ||
ambarella_wifi0 || ambarella_wifi0_ip || ambarella_wifi0_mask ||
ambarella_wifi0_gw
#if (USE_WIFI >= 2)
|| ambarella_wifi1 || ambarella_wifi1_ip || ambarella_wifi1_mask ||
ambarella_wifi1_gw
#endif
) {
if (flprog_get_part_table(&ptb_buf) < 0)
exit (1);
}
ptb_table = (flpart_table_t *)ptb_buf;
if (ambarella_pri) {
ptb_table->part[PART_PRI].img_len = image_length;
ptb_table->part[PART_PRI].crc32 = image_crc;
ptb_table->part[PART_PRI].flag = ambarella_flpart_flag;
ptb_table->part[PART_PRI].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_PRI].ver_num = ambarella_flpart_version;
ptb_table->part[PART_PRI].ver_date = ambarella_flpart_date;
}
if (ambarella_rmd) {
ptb_table->part[PART_RMD].img_len = image_length;
ptb_table->part[PART_RMD].crc32 = image_crc;
ptb_table->part[PART_RMD].flag = ambarella_flpart_flag;
ptb_table->part[PART_RMD].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_RMD].ver_num = ambarella_flpart_version;
ptb_table->part[PART_RMD].ver_date = ambarella_flpart_date;
}
if (ambarella_rom) {
ptb_table->part[PART_ROM].img_len = image_length;
ptb_table->part[PART_ROM].crc32 = image_crc;
ptb_table->part[PART_ROM].flag = ambarella_flpart_flag;
ptb_table->part[PART_ROM].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_ROM].ver_num = ambarella_flpart_version;
ptb_table->part[PART_ROM].ver_date = ambarella_flpart_date;
}
if (ambarella_bak) {
ptb_table->part[PART_BAK].img_len = image_length;
ptb_table->part[PART_BAK].crc32 = image_crc;
ptb_table->part[PART_BAK].flag = ambarella_flpart_flag;
ptb_table->part[PART_BAK].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_BAK].ver_num = ambarella_flpart_version;
ptb_table->part[PART_BAK].ver_date = ambarella_flpart_date;
}
//if (ambarella_ptb) {
//ptb_table->part[PART_PTB].img_len = image_length;
//ptb_table->part[PART_PTB].crc32 = image_crc;
//ptb_table->part[PART_PTB].flag = ambarella_flpart_flag;
//ptb_table->part[PART_PTB].mem_addr = ambarella_flpart_mem_addr;
//ptb_table->part[PART_PTB].ver_num = ambarella_flpart_version;
//ptb_table->part[PART_PTB].ver_date = ambarella_flpart_date;
//}
if (ambarella_bld) {
ptb_table->part[PART_BLD].img_len = image_length;
ptb_table->part[PART_BLD].crc32 = image_crc;
ptb_table->part[PART_BLD].flag = ambarella_flpart_flag;
ptb_table->part[PART_BLD].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_BLD].ver_num = ambarella_flpart_version;
ptb_table->part[PART_BLD].ver_date = ambarella_flpart_date;
}
if (ambarella_hal) {
ptb_table->part[PART_HAL].img_len = image_length;
ptb_table->part[PART_HAL].crc32 = image_crc;
ptb_table->part[PART_HAL].flag = ambarella_flpart_flag;
ptb_table->part[PART_HAL].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_HAL].ver_num = ambarella_flpart_version;
ptb_table->part[PART_HAL].ver_date = ambarella_flpart_date;
}
if (ambarella_pba) {
ptb_table->part[PART_PBA].img_len = image_length;
ptb_table->part[PART_PBA].crc32 = image_crc;
ptb_table->part[PART_PBA].flag = ambarella_flpart_flag;
ptb_table->part[PART_PBA].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_PBA].ver_num = ambarella_flpart_version;
ptb_table->part[PART_PBA].ver_date = ambarella_flpart_date;
}
if (ambarella_sec) {
ptb_table->part[PART_SEC].img_len = image_length;
ptb_table->part[PART_SEC].crc32 = image_crc;
ptb_table->part[PART_SEC].flag = ambarella_flpart_flag;
ptb_table->part[PART_SEC].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_SEC].ver_num = ambarella_flpart_version;
ptb_table->part[PART_SEC].ver_date = ambarella_flpart_date;
}
if (ambarella_dsp) {
ptb_table->part[PART_DSP].img_len = image_length;
ptb_table->part[PART_DSP].crc32 = image_crc;
ptb_table->part[PART_DSP].flag = ambarella_flpart_flag;
ptb_table->part[PART_DSP].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_DSP].ver_num = ambarella_flpart_version;
ptb_table->part[PART_DSP].ver_date = ambarella_flpart_date;
}
if (ambarella_lnx) {
ptb_table->part[PART_LNX].img_len = image_length;
ptb_table->part[PART_LNX].crc32 = image_crc;
ptb_table->part[PART_LNX].flag = ambarella_flpart_flag;
ptb_table->part[PART_LNX].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_LNX].ver_num = ambarella_flpart_version;
ptb_table->part[PART_LNX].ver_date = ambarella_flpart_date;
}
if (ambarella_swp) {
ptb_table->part[PART_SWP].img_len = image_length;
ptb_table->part[PART_SWP].crc32 = image_crc;
ptb_table->part[PART_SWP].flag = ambarella_flpart_flag;
ptb_table->part[PART_SWP].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_SWP].ver_num = ambarella_flpart_version;
ptb_table->part[PART_SWP].ver_date = ambarella_flpart_date;
}
if (ambarella_add) {
ptb_table->part[PART_ADD].img_len = image_length;
ptb_table->part[PART_ADD].crc32 = image_crc;
ptb_table->part[PART_ADD].flag = ambarella_flpart_flag;
ptb_table->part[PART_ADD].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_ADD].ver_num = ambarella_flpart_version;
ptb_table->part[PART_ADD].ver_date = ambarella_flpart_date;
}
if (ambarella_adc) {
ptb_table->part[PART_ADC].img_len = image_length;
ptb_table->part[PART_ADC].crc32 = image_crc;
ptb_table->part[PART_ADC].flag = ambarella_flpart_flag;
ptb_table->part[PART_ADC].mem_addr = ambarella_flpart_mem_addr;
ptb_table->part[PART_ADC].ver_num = ambarella_flpart_version;
ptb_table->part[PART_ADC].ver_date = ambarella_flpart_date;
}
if (ambarella_force_ptb) {
ptb_table->dev.rsv[0] = ambarella_ptb_data;
}
if (ambarella_cmd) {
strncpy(ptb_table->dev.cmdline, ambarella_cmdline, CMD_LINE_SIZE);
}
if (ambarella_sn) {
strncpy(ptb_table->dev.sn, ambarella_sn_data, SN_SIZE);
}
if (ambarella_auto_dl) {
ptb_table->dev.auto_dl = ambarella_auto_dl_data;
}
if (ambarella_auto_boot) {
ptb_table->dev.auto_boot = ambarella_auto_boot_data;
}
if (ambarella_eth) {
memcpy(ptb_table->dev.eth[0].mac, ambarella_eth_mac, MAC_SIZE);
}
if (ambarella_lan_ip) {
ptb_table->dev.eth[0].ip = ambarella_lan_ip_data;
}
if (ambarella_lan_mask) {
ptb_table->dev.eth[0].mask = ambarella_lan_mask_data;
}
if (ambarella_lan_gw) {
ptb_table->dev.eth[0].gw = ambarella_lan_gw_data;
}
if (ambarella_tftpd) {
ptb_table->dev.tftpd = ambarella_tftpd_data;
}
if (ambarella_eth1) {
memcpy(ptb_table->dev.eth[1].mac, ambarella_eth1_mac, MAC_SIZE);
}
if (ambarella_eth1_ip) {
ptb_table->dev.eth[1].ip = ambarella_eth1_ip_data;
}
if (ambarella_eth1_mask) {
ptb_table->dev.eth[1].mask = ambarella_eth1_mask_data;
}
if (ambarella_eth1_gw) {
ptb_table->dev.eth[1].gw = ambarella_eth1_gw_data;
}
if (ambarella_wifi0) {
memcpy(ptb_table->dev.wifi[0].mac, ambarella_wifi0_mac, MAC_SIZE);
}
if (ambarella_wifi0_ip) {
ptb_table->dev.wifi[0].ip = ambarella_wifi0_ip_data;
}
if (ambarella_wifi0_mask) {
ptb_table->dev.wifi[0].mask = ambarella_wifi0_mask_data;
}
if (ambarella_wifi0_gw) {
ptb_table->dev.wifi[0].gw = ambarella_wifi0_gw_data;
}
#if (USE_WIFI >= 2)
if (ambarella_wifi1) {
memcpy(ptb_table->dev.wifi[1].mac, ambarella_wifi1_mac, MAC_SIZE);
}
if (ambarella_wifi1_ip) {
ptb_table->dev.wifi[1].ip = ambarella_wifi1_ip_data;
}
if (ambarella_wifi1_mask) {
ptb_table->dev.wifi[1].mask = ambarella_wifi1_mask_data;
}
if (ambarella_wifi1_gw) {
ptb_table->dev.wifi[1].gw = ambarella_wifi1_gw_data;
}
#endif
if (ambarella_pri_addr) {
ptb_table->dev.pri_addr = ambarella_pri_addr_data;
}
if (ambarella_pri_file) {
strncpy(ptb_table->dev.pri_file, ambarella_pri_file_data, SN_SIZE);
}
if (ambarella_bld ||ambarella_force_ptb|| ambarella_hal ||
ambarella_pba || ambarella_sec || ambarella_dsp ||
ambarella_lnx || ambarella_swp || ambarella_add ||
ambarella_adc || ambarella_pri || ambarella_rmd ||
ambarella_rom || ambarella_cmd || ambarella_eth ||
ambarella_sn || ambarella_bak ||ambarella_auto_dl||
ambarella_auto_boot || ambarella_lan_ip || ambarella_lan_mask ||
ambarella_lan_gw || ambarella_tftpd || ambarella_pri_addr ||
ambarella_pri_file ||
ambarella_eth1 || ambarella_eth1_ip || ambarella_eth1_mask ||
ambarella_eth1_gw ||
ambarella_wifi0 || ambarella_wifi0_ip || ambarella_wifi0_mask ||
ambarella_wifi0_gw
#if (USE_WIFI >= 2)
|| ambarella_wifi1 || ambarella_wifi1_ip || ambarella_wifi1_mask ||
ambarella_wifi1_gw
#endif
) {
if (flprog_set_part_table(&ptb_buf) < 0)
exit (1);
}
sync();
/* Return happy */
return 0;
}