diff --git a/Makefile.inc b/Makefile.inc index c29ae348a6..8f45fc29ce 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -71,7 +71,7 @@ subdirs-y += src/ec/acpi $(wildcard src/ec/*/*) $(wildcard src/southbridge/*/*) subdirs-y += $(wildcard src/soc/*/*) $(wildcard src/northbridge/*/*) subdirs-y += src/superio $(wildcard src/drivers/*) src/cpu src/vendorcode subdirs-y += util/cbfstool util/sconfig util/nvramtool util/broadcom -subdirs-y += util/futility +subdirs-y += util/futility util/marvell subdirs-y += $(wildcard src/arch/*) subdirs-y += src/mainboard/$(MAINBOARDDIR) subdirs-y += payloads/external diff --git a/src/soc/marvell/armada38x/Makefile.inc b/src/soc/marvell/armada38x/Makefile.inc index c62d95f96e..c55bfff6e3 100644 --- a/src/soc/marvell/armada38x/Makefile.inc +++ b/src/soc/marvell/armada38x/Makefile.inc @@ -34,10 +34,10 @@ ramstage-y += clock.c CPPFLAGS_common += -Isrc/soc/marvell/armada38x/include/ -Isrc/commonlib/include/commonlib/ -BIN_HDR = 3rdparty/blobs/cpu/marvell/armada38x/bin_hdr.bin -DOIMAGE = 3rdparty/blobs/cpu/marvell/armada38x/doimage +BIN_HDR = 3rdparty/cpu/marvell/armada38x/bin_hdr.bin +DOIMAGE = $(objutil)/marvell/doimage_mv/doimage -$(objcbfs)/bootblock.bin: $(objcbfs)/bootblock.raw.bin +$(objcbfs)/bootblock.bin: $(objcbfs)/bootblock.raw.bin $(DOIMAGE) @chmod a+x $(DOIMAGE) $(DOIMAGE) -T flash -D 0 -E 0 -G $(BIN_HDR) $< $@ rm $< diff --git a/util/marvell/Makefile.inc b/util/marvell/Makefile.inc new file mode 100644 index 0000000000..08dbf72c77 --- /dev/null +++ b/util/marvell/Makefile.inc @@ -0,0 +1 @@ +subdirs-$(CONFIG_SOC_MARVELL_ARMADA38X) += doimage_mv diff --git a/util/marvell/doimage_mv/Makefile.inc b/util/marvell/doimage_mv/Makefile.inc new file mode 100644 index 0000000000..83665df010 --- /dev/null +++ b/util/marvell/doimage_mv/Makefile.inc @@ -0,0 +1,13 @@ +DOIMAGE_FOLDER = marvell/doimage_mv +DOIMAGE_BINARY = doimage + +CFLAGS = -g -O1 -I./../inc -DMV_CPU_LE + +$(objutil)/$(DOIMAGE_FOLDER): + mkdir -p $@ + +$(objutil)/$(DOIMAGE_FOLDER)/doimage.o: $(top)/util/marvell/doimage_mv/doimage.c $(objutil)/$(DOIMAGE_FOLDER) + $(HOSTCC) $(CFLAGS) -c $< -o $@ + +$(objutil)/$(DOIMAGE_FOLDER)/$(DOIMAGE_BINARY): $(objutil)/$(DOIMAGE_FOLDER)/doimage.o + $(HOSTCC) $(CFLAGS) -o $@ $^ diff --git a/util/marvell/doimage_mv/bootstrap_def.h b/util/marvell/doimage_mv/bootstrap_def.h new file mode 100644 index 0000000000..1585b8191d --- /dev/null +++ b/util/marvell/doimage_mv/bootstrap_def.h @@ -0,0 +1,171 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. + +*******************************************************************************/ + +#ifndef _INC_BOOTSTRAP__DEF_H +#define _INC_BOOTSTRAP__DEF_H +#include "bootstrap_os.h" + +#ifndef MV_ASMLANGUAGE + +#define MAIN_HDR_VERSION 1 + +#define MAIN_HDR_NAND_SLC 0 +#define MAIN_HDR_NAND_MLC 1 + +typedef struct BHR_t { + /* type name byte order */ + MV_U8 blockID; /* 0 */ + MV_U8 flags; /* 1 */ + MV_U16 nandPageSize; /* 2-3 */ + MV_U32 blockSize; /* 4-7 */ + MV_U8 version; /* 8 */ + MV_U8 hdrSizeMsb; /* 9 */ + MV_U16 hdrSizeLsb; /* 10-11 */ + MV_U32 sourceAddr; /* 12-15 */ + MV_U32 destinationAddr; /* 16-19 */ + MV_U32 executionAddr; /* 20-23 */ + MV_U8 options; /* 24 */ + MV_U8 nandBlockSize; /* 25 */ + MV_U8 nandTechnology; /* 26 */ + MV_U8 rsvd4; /* 27 */ + MV_U16 rsvd2; /* 28-29 */ + MV_U8 ext; /* 30 */ + MV_U8 checkSum; /* 31 */ + +} BHR_t, *pBHR_t; + +#define MAIN_HDR_GET_LEN(pHdr) \ + (((MV_U32)((pHdr)->hdrSizeMsb) << 16) | ((MV_U32)((pHdr)->hdrSizeLsb))) + +#define EXT_HDR_TYP_SECURITY 0x01 +#define EXT_HDR_TYP_BINARY 0x02 +#define EXT_HDR_TYP_REGISTER 0x03 + +typedef struct headExtBHR_t {/* Common extension header head */ + // type name byte order + MV_U8 type; + MV_U8 lenMsb; + MV_U16 lenLsb; + +} headExtBHR_t; + +#define EXT_HDR_SET_LEN(pHead, len) \ + do { \ + (pHead)->lenMsb = ((len)&0x00FF0000) >> 16; \ + (pHead)->lenLsb = (len)&0x0000FFFF; \ + } while (0) + +#define EXT_HDR_GET_LEN(pHead) \ + (((MV_U32)((pHead)->lenMsb) << 16) | ((pHead)->lenLsb)) + +typedef struct tailExtBHR_t {/* Common extension header tail */ + // type name byte order + MV_U8 nextHdr; + MV_U8 delay; + MV_U16 rsvd2; + +} tailExtBHR_t; + +typedef struct publicKey_t {/* public key*/ + MV_U8 Key[524]; +} publicKey_t; + +#define RSA_MAX_KEY_LEN_BYTES 256 + +typedef struct secExtBHR_t { + headExtBHR_t head; + MV_U8 encrypt; + MV_U8 rsrvd0; + MV_U16 rsrvd1; + publicKey_t pubKey; + MV_U8 jtagEn; + MV_U8 rsrvd2; + MV_U16 rsrvd3; + MV_U32 boxId; + MV_U32 flashId; + MV_U8 hdrSign[256]; + MV_U8 imgSign[256]; + publicKey_t cskArray[16]; + MV_U8 cskBlockSign[256]; + tailExtBHR_t tail; + +} secExtBHR_t, *pSecExtBHR_T; + +/***********************/ +/* SECURE PARAMS */ +/***********************/ +#define CSK_BLOCK_OFFSET 0x420 +#define PUB_KEY_SIZE 524 +#define CSK_KEY_NUM 16 +#define CSK_BLOCK_SIGN_OFFSET (CSK_BLOCK_OFFSET + (PUB_KEY_SIZE * CSK_KEY_NUM)) +/* 16 keys + 256 bytes long signature */ +#define CSK_BLOCK_SIZE ((PUB_KEY_SIZE * CSK_KEY_NUM) + 0x100) + +#define BOOTROM_SIZE (64 * 1024) +#define EXT_HDR_BASE_SIZE (sizeof(headExtBHR_t) + sizeof(tailExtBHR_t)) +/* MAX size of entire headers block */ +#define MAX_HEADER_SIZE (192 * 1024) +#define MAX_TWSI_HDR_SIZE \ + (60 * 1024) /* MAX eeprom is 64K & leave 4K for image and header */ + +/* Boot Type - block ID */ +#define IBR_HDR_I2C_ID 0x4D +#define IBR_HDR_SPI_ID 0x5A +#define IBR_HDR_NAND_ID 0x8B +#define IBR_HDR_SATA_ID 0x78 +#define IBR_HDR_PEX_ID 0x9C +#define IBR_HDR_MMC_ID 0xAE +#define IBR_HDR_UART_ID 0x69 +#define IBR_DEF_ATTRIB 0x00 + +/* ROM flags */ +#define BHR_FLAG_PRINT_EN 0x01 +#define BHR_FLAG_RESERVED1 0x02 +#define BHR_FLAG_RESERVED2 0x04 +#define BHR_FLAG_RESERVED3 0x08 +#define BHR_FLAG_RESERVED4 0x10 +#define BHR_FLAG_RESERVED5 0x20 +#define BHR_FLAG_RESERVED6 0x40 +#define BHR_FLAG_RESERVED7 0x80 + +/* ROM options */ +#define BHR_OPT_BAUDRATE_OFFS 0x0 +#define BHR_OPT_BAUDRATE_MASK (0x7 << BHR_OPT_BAUDRATE_OFFS) +#define BHR_OPT_BAUD_DEFAULT (0x0 << BHR_OPT_BAUDRATE_OFFS) +#define BHR_OPT_BAUD_2400 (0x1 << BHR_OPT_BAUDRATE_OFFS) +#define BHR_OPT_BAUD_4800 (0x2 << BHR_OPT_BAUDRATE_OFFS) +#define BHR_OPT_BAUD_9600 (0x3 << BHR_OPT_BAUDRATE_OFFS) +#define BHR_OPT_BAUD_19200 (0x4 << BHR_OPT_BAUDRATE_OFFS) +#define BHR_OPT_BAUD_38400 (0x5 << BHR_OPT_BAUDRATE_OFFS) +#define BHR_OPT_BAUD_57600 (0x6 << BHR_OPT_BAUDRATE_OFFS) +#define BHR_OPT_BAUD_115200 (0x7 << BHR_OPT_BAUDRATE_OFFS) + +#define BHR_OPT_UART_PORT_OFFS 0x3 +#define BHR_OPT_UART_PORT_MASK (0x3 << BHR_OPT_UART_PORT_OFFS) + +#define BHR_OPT_UART_MPPS_OFFS 0x5 +#define BHR_OPT_UART_MPPS_MASK (0x7 << BHR_OPT_UART_MPPS_OFFS) + +typedef struct _mvCpuArmClk { + MV_U32 cpuClk; /* CPU clock MHz */ + MV_U32 ddrClk; /* DDR clock MHz */ + MV_U32 l2cClk; /* L2 cache clock MHz */ +} MV_CPU_ARM_CLK; + +#endif /* MV_ASMLANGUAGE */ +#endif /* _INC_BOOTSTRAP_H */ diff --git a/util/marvell/doimage_mv/bootstrap_os.h b/util/marvell/doimage_mv/bootstrap_os.h new file mode 100644 index 0000000000..888e730c99 --- /dev/null +++ b/util/marvell/doimage_mv/bootstrap_os.h @@ -0,0 +1,403 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. + +*******************************************************************************/ +#ifndef _INC_BOOTSTRAP_OS_H +#define _INC_BOOTSTRAP_OS_H + +/* BE/ LE swap for Asm */ +#if defined(MV_CPU_LE) + +#define htoll(x) x +#define HTOLL(sr, tr) + +#elif defined(MV_CPU_BE) + +#define htoll(x) \ + ((((x)&0x00ff) << 24) | (((x)&0xff00) << 8) | (((x) >> 8) & 0xff00) | \ + (((x) >> 24) & 0x00ff)) + +#define HTOLL(sr, temp) do { /*sr = A ,B ,C ,D */ \ + eor temp, sr, sr, ROR #16; /*temp = A^C,B^D,C^A,D^B */ \ + bic temp, temp, #0xFF0000; /*temp = A^C,0 ,C^A,D^B */ \ + mov sr, sr, ROR #8; /*sr = D ,A ,B ,C */ \ + eor sr, sr, temp, LSR #8 /*sr = D ,C ,B ,A */ \ + } while (0) + +#endif + +#define MV_REG_READ_ASM(toReg, tmpReg, regOffs) do { \ + ldr tmpReg, = (INTER_REGS_BASE + regOffs); \ + ldr toReg, [tmpReg]; \ + HTOLL(toReg, tmpReg) \ + } while (0) + +#define MV_REG_WRITE_ASM(fromReg, tmpReg, regOffs) \ + HTOLL(fromReg, tmpReg); \ + ldr tmpReg, = (INTER_REGS_BASE + regOffs); \ + str fromReg, [tmpReg] + +#define MV_DV_REG_READ_ASM(toReg, tmpReg, regOffs) \ + ldr tmpReg, = (CFG_DFL_MV_REGS + regOffs); \ + ldr toReg, [tmpReg]; \ + HTOLL(toReg, tmpReg) + +#define MV_DV_REG_WRITE_ASM(fromReg, tmpReg, regOffs) \ + HTOLL(fromReg, tmpReg); \ + ldr tmpReg, = (CFG_DFL_MV_REGS + regOffs); \ + str fromReg, [tmpReg] + +/* Defines */ + +/* The following is a list of Marvell status */ +#define MV_ERROR (-1) +#define MV_OK (0x00) /* Operation succeeded */ +#define MV_FAIL (0x01) /* Operation failed */ +#define MV_BAD_VALUE (0x02) /* Illegal value (general) */ +#define MV_OUT_OF_RANGE (0x03) /* The value is out of range */ +#define MV_BAD_PARAM (0x04) /* Illegal parameter in function called */ +#define MV_BAD_PTR (0x05) /* Illegal pointer value */ +#define MV_BAD_SIZE (0x06) /* Illegal size */ +#define MV_BAD_STATE (0x07) /* Illegal state of state machine */ +#define MV_SET_ERROR (0x08) /* Set operation failed */ +#define MV_GET_ERROR (0x09) /* Get operation failed */ +#define MV_CREATE_ERROR (0x0A) /* Fail while creating an item */ +#define MV_NOT_FOUND (0x0B) /* Item not found */ +#define MV_NO_MORE (0x0C) /* No more items found */ +#define MV_NO_SUCH (0x0D) /* No such item */ +#define MV_TIMEOUT (0x0E) /* Time Out */ +#define MV_NO_CHANGE (0x0F) /* Parameter(s) is already in this value */ +#define MV_NOT_SUPPORTED (0x10) /* This request is not support */ +#define MV_NOT_IMPLEMENTED (0x11) /* Request supported but not implemented */ +#define MV_NOT_INITIALIZED (0x12) /* The item is not initialized */ +#define MV_NO_RESOURCE (0x13) /* Resource not available (memory ...) */ +#define MV_FULL (0x14) /* Item is full (Queue or table etc...) */ +#define MV_EMPTY (0x15) /* Item is empty (Queue or table etc...) */ +#define MV_INIT_ERROR (0x16) /* Error occurred while INIT process */ +#define MV_HW_ERROR (0x17) /* Hardware error */ +#define MV_TX_ERROR (0x18) /* Transmit operation not succeeded */ +#define MV_RX_ERROR (0x19) /* Receive operation not succeeded */ +#define MV_NOT_READY (0x1A) /* The other side is not ready yet */ +#define MV_ALREADY_EXIST (0x1B) /* Tried to create existing item */ +#define MV_OUT_OF_CPU_MEM (0x1C) /* Cpu memory allocation failed. */ +#define MV_NOT_STARTED (0x1D) /* Not started yet */ +#define MV_BUSY (0x1E) /* Item is busy. */ +#define MV_TERMINATE (0x1F) /* Item terminates it's work. */ +#define MV_NOT_ALIGNED (0x20) /* Wrong alignment */ +#define MV_NOT_ALLOWED (0x21) /* Operation NOT allowed */ +#define MV_WRITE_PROTECT (0x22) /* Write protected */ + +#define MV_INVALID (int)(-1) + +#define MV_FALSE 0 +#define MV_TRUE (!(MV_FALSE)) + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef MV_ASMLANGUAGE +/* typedefs */ + +typedef char MV_8; +typedef unsigned char MV_U8; + +typedef int MV_32; +typedef unsigned int MV_U32; + +typedef short MV_16; +typedef unsigned short MV_U16; +/* +#ifdef MV_PPC64 +typedef long MV_64; +typedef unsigned long MV_U64; +#else +typedef long long MV_64; +typedef unsigned long long MV_U64; +#endif +*/ +typedef long MV_LONG; /* 32/64 */ +typedef unsigned long MV_ULONG; /* 32/64 */ + +typedef int MV_STATUS; +typedef int MV_BOOL; +/*typedef void MV_VOID;*/ +#define MV_VOID void +typedef float MV_FLOAT; + +typedef int (*MV_FUNCPTR)(void); /* ptr to function returning int */ +typedef void (*MV_VOIDFUNCPTR)(void); /* ptr to function returning void */ +typedef double (*MV_DBLFUNCPTR)(void); /* ptr to function returning double*/ +typedef float (*MV_FLTFUNCPTR)(void); /* ptr to function returning float */ + +typedef MV_U32 MV_KHZ; +typedef MV_U32 MV_MHZ; +typedef MV_U32 MV_HZ; +#if defined(_HOST_COMPILER) +#define __MV_PACKED +#else +#define __MV_PACKED /*__packed*/ +#endif + +#endif /* MV_ASMLANGUAGE */ + +/* Bit field definitions */ +#define NO_BIT 0x00000000 +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +/* includes */ +#define _1K 0x00000400 +#define _4K 0x00001000 +#define _8K 0x00002000 +#define _16K 0x00004000 +#define _32K 0x00008000 +#define _64K 0x00010000 +#define _128K 0x00020000 +#define _256K 0x00040000 +#define _512K 0x00080000 +/* Sizes */ +#define _1M 0x00100000 +#define _2M 0x00200000 +#define _4M 0x00400000 +#define _8M 0x00800000 +#define _16M 0x01000000 +#define _32M 0x02000000 +#define _64M 0x04000000 +#define _128M 0x08000000 +#define _256M 0x10000000 +#define _512M 0x20000000 +#define _1G 0x40000000 +#define _2G 0x80000000 +/* Speed */ +#define _25MHZ 25000000 +#define _125MHZ 125000000 +#define _133MHZ 133333333 +#define _150MHZ 150000000 +#define _166MHZ 166666667 +#define _200MHZ 200000000 +#define _250MHZ 250000000 + +/* Swap tool */ + +/* 16bit nibble swap. For example 0x1234 -> 0x2143 */ +#define MV_NIBBLE_SWAP_16BIT(X) \ + (((X & 0xf) << 4) | ((X & 0xf0) >> 4) | ((X & 0xf00) << 4) | \ + ((X & 0xf000) >> 4)) + +/* 32bit nibble swap. For example 0x12345678 -> 0x21436587 */ +#define MV_NIBBLE_SWAP_32BIT(X) \ + (((X & 0xf) << 4) | ((X & 0xf0) >> 4) | ((X & 0xf00) << 4) | \ + ((X & 0xf000) >> 4) | ((X & 0xf0000) << 4) | ((X & 0xf00000) >> 4) | \ + ((X & 0xf000000) << 4) | ((X & 0xf0000000) >> 4)) + +/* 16bit byte swap. For example 0x1122 -> 0x2211 */ +#define MV_BYTE_SWAP_16BIT(X) ((((X)&0xff) << 8) | (((X)&0xff00) >> 8)) + +/* 32bit byte swap. For example 0x11223344 -> 0x44332211 */ +#define MV_BYTE_SWAP_32BIT(X) \ + ((((X)&0xff) << 24) | (((X)&0xff00) << 8) | (((X)&0xff0000) >> 8) | \ + (((X)&0xff000000) >> 24)) + +/* 64bit byte swap. For example 0x11223344.55667788 -> 0x88776655.44332211 */ +#define MV_BYTE_SWAP_64BIT(X) \ + ((l64)((((X)&0xffULL) << 56) | (((X)&0xff00ULL) << 40) | \ + (((X)&0xff0000ULL) << 24) | (((X)&0xff000000ULL) << 8) | \ + (((X)&0xff00000000ULL) >> 8) | \ + (((X)&0xff0000000000ULL) >> 24) | \ + (((X)&0xff000000000000ULL) >> 40) | \ + (((X)&0xff00000000000000ULL) >> 56))) + +/* Endianness macros. */ +#if defined(MV_CPU_LE) +#define MV_16BIT_LE(X) (X) +#define MV_32BIT_LE(X) (X) +#define MV_64BIT_LE(X) (X) +#define MV_16BIT_BE(X) MV_BYTE_SWAP_16BIT(X) +#define MV_32BIT_BE(X) MV_BYTE_SWAP_32BIT(X) +#define MV_64BIT_BE(X) MV_BYTE_SWAP_64BIT(X) +#elif defined(MV_CPU_BE) +#define MV_16BIT_LE(X) MV_BYTE_SWAP_16BIT(X) +#define MV_32BIT_LE(X) MV_BYTE_SWAP_32BIT(X) +#define MV_64BIT_LE(X) MV_BYTE_SWAP_64BIT(X) +#define MV_16BIT_BE(X) (X) +#define MV_32BIT_BE(X) (X) +#define MV_64BIT_BE(X) (X) +#else +#error "CPU endianness isn't defined!\n" +#endif + +#ifndef MV_ASMLANGUAGE +/* Get the min between 'a' or 'b' */ +#define MV_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/* Marvell controller register read/write macros */ +#define CPU_PHY_MEM(x) ((MV_U32) x) +#define CPU_MEMIO_CACHED_ADDR(x) ((void *) x) +#define CPU_MEMIO_UNCACHED_ADDR(x) ((void *) x) + +/* CPU architecture dependent 32, 16, 8 bit read/write IO addresses */ +#define MV_MEMIO32_WRITE(addr, data) \ + ((*((volatile unsigned int *)(addr))) = ((unsigned int)(data))) + +#define MV_MEMIO32_READ(addr) ((*((volatile unsigned int *)(addr)))) + +#define MV_MEMIO16_WRITE(addr, data) \ + ((*((volatile unsigned short *)(addr))) = ((unsigned short)(data))) + +#define MV_MEMIO16_READ(addr) ((*((volatile unsigned short *)(addr)))) + +#define MV_MEMIO8_WRITE(addr, data) \ + ((*((volatile unsigned char *)(addr))) = ((unsigned char)(data))) + +#define MV_MEMIO8_READ(addr) ((*((volatile unsigned char *)(addr)))) + +/* No Fast Swap implementation (in assembler) for ARM */ +#define MV_32BIT_LE_FAST(val) MV_32BIT_LE(val) +#define MV_16BIT_LE_FAST(val) MV_16BIT_LE(val) +#define MV_32BIT_BE_FAST(val) MV_32BIT_BE(val) +#define MV_16BIT_BE_FAST(val) MV_16BIT_BE(val) + +/* 32 and 16 bit read/write in big/little endian mode */ + +/* 16bit write in little endian mode */ +#define MV_MEMIO_LE16_WRITE(addr, data) \ + MV_MEMIO16_WRITE(addr, MV_16BIT_LE_FAST(data)) + +/* 16bit read in little endian mode */ +static inline MV_U16 MV_MEMIO_LE16_READ(void *addr) +{ + MV_U16 data; + MV_U16 *addr1 = (MV_U16 *)addr; + + data = (MV_U16)MV_MEMIO16_READ(addr1); + + return (MV_U16)MV_16BIT_LE_FAST(data); +} + +/* 32bit write in little endian mode */ +#define MV_MEMIO_LE32_WRITE(addr, data) \ + MV_MEMIO32_WRITE(addr, MV_32BIT_LE_FAST(data)) + +/* 32bit read in little endian mode */ +static inline MV_U32 MV_MEMIO_LE32_READ(void *addr) +{ + MV_U32 data; + MV_U32 *addr1 = (MV_U32 *)addr; + + data = (MV_U32)MV_MEMIO32_READ(addr1); + + return (MV_U32)MV_32BIT_LE_FAST(data); +} + +/* Flash APIs */ +#define MV_FL_8_READ MV_MEMIO8_READ +#define MV_FL_16_READ MV_MEMIO_LE16_READ +#define MV_FL_32_READ MV_MEMIO_LE32_READ +#define MV_FL_8_DATA_READ MV_MEMIO8_READ +#define MV_FL_16_DATA_READ MV_MEMIO16_READ +#define MV_FL_32_DATA_READ MV_MEMIO32_READ +#define MV_FL_8_WRITE MV_MEMIO8_WRITE +#define MV_FL_16_WRITE MV_MEMIO_LE16_WRITE +#define MV_FL_32_WRITE MV_MEMIO_LE32_WRITE +#define MV_FL_8_DATA_WRITE MV_MEMIO8_WRITE +#define MV_FL_16_DATA_WRITE MV_MEMIO16_WRITE +#define MV_FL_32_DATA_WRITE MV_MEMIO32_WRITE + +/* CPU cache information */ +#define CPU_I_CACHE_LINE_SIZE 32 /* 2do: replace 32 with linux core macro */ +#define CPU_D_CACHE_LINE_SIZE 32 /* 2do: replace 32 with linux core macro */ + +#define MV_REG_VALUE(offset) (MV_MEMIO32_READ((INTER_REGS_BASE | (offset)))) + +#define MV_REG_READ(offset) (MV_MEMIO_LE32_READ(INTER_REGS_BASE | (offset))) + +#define MV_REG_WRITE(offset, val) \ + MV_MEMIO_LE32_WRITE((INTER_REGS_BASE | (offset)), (val)) + +#define MV_REG_BYTE_READ(offset) (MV_MEMIO8_READ((INTER_REGS_BASE | (offset)))) + +#define MV_REG_BYTE_WRITE(offset, val) \ + MV_MEMIO8_WRITE((INTER_REGS_BASE | (offset)), (val)) + +#define MV_REG_SHORT_READ(offset) \ + (MV_MEMIO_LE16_READ(INTER_REGS_BASE | (offset))) + +#define MV_REG_BIT_SET(offset, bitMask) \ + (MV_MEMIO32_WRITE((INTER_REGS_BASE | (offset)), \ + (MV_MEMIO32_READ((INTER_REGS_BASE | (offset))) | \ + MV_32BIT_LE_FAST((bitMask))))) + +#define MV_REG_BIT_RESET(offset, bitMask) \ + (MV_MEMIO32_WRITE((INTER_REGS_BASE | (offset)), \ + (MV_MEMIO32_READ((INTER_REGS_BASE | (offset))) & \ + MV_32BIT_LE_FAST(~(bitMask))))) + +#define mvOsUDelay uDelay +#define mvOsMDelay(msec) uDelay(msec * 1000) +#define mvOsDelay(sec) mvOsMDelay(sec * 1000) + +#define u32 MV_U32 +#define u16 MV_U16 +#define u8 MV_U8 +#define s16 short +#define s32 long +#define s8 char + +#define UINT32 MV_U32 +#define UINT16 MV_U16 +#define UINT8 MV_U8 + +typedef UINT32 * PUINT32; +typedef UINT16 * PUINT16; +typedef UINT8 * PUINT8; + +#define TRUE MV_TRUE +#define FALSE MV_FALSE + +#endif /* #ifndef MV_ASMLANGUAGE */ + +#endif /* _INC_BOOTSTRAP_OS_H */ diff --git a/util/marvell/doimage_mv/doimage.c b/util/marvell/doimage_mv/doimage.c new file mode 100644 index 0000000000..18675aa56d --- /dev/null +++ b/util/marvell/doimage_mv/doimage.c @@ -0,0 +1,1781 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. + +*******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _HOST_COMPILER +#include "bootstrap_def.h" + +#include "doimage.h" + +#undef DEBUG + +#ifdef DEBUG +#define DB(x...) fprintf(stdout, x) +#else +#define DB(x...) +#endif + +/* Global variables */ + +int f_in = -1; +int f_out = -1; +int f_header = -1; +struct stat fs_stat; + +/******************************************************************************* +* pre_load_image +* pre-load the binary image into memory buffer taking into account +*paddings +* INPUT: +* opt user options +* buf_in mmapped input file +* OUTPUT: +* none +* RETURN: +* 0 on success +*******************************************************************************/ +int pre_load_image(USER_OPTIONS *opt, char *buf_in) +{ + int offset = 0; + + opt->image_buf = malloc(opt->image_sz); + if (opt->image_buf == NULL) + return -1; + + memset(opt->image_buf, 0, opt->image_sz); + + if ((opt->pre_padding) && (opt->prepadding_size)) { + memset(opt->image_buf, 0x5, opt->prepadding_size); + offset = opt->prepadding_size; + } + + if ((opt->post_padding) && (opt->postpadding_size)) + memset(opt->image_buf + opt->image_sz - 4 - + opt->postpadding_size, + 0xA, opt->postpadding_size); + + memcpy(opt->image_buf + offset, buf_in, fs_stat.st_size); + + return 0; +} /* end of pre_load_image() */ + +/******************************************************************************* +* build_twsi_header +* create TWSI header and write it into output stream +* INPUT: +* opt user options +* OUTPUT: +* none +* RETURN: +* 0 on success +*******************************************************************************/ +int build_twsi_header(USER_OPTIONS *opt) +{ + FILE *f_twsi; + MV_U8 *tmpTwsi = NULL; + MV_U32 *twsi_reg; + int i; + MV_U32 twsi_size = 0; + + tmpTwsi = malloc(MAX_TWSI_HDR_SIZE); + if (tmpTwsi == NULL) { + fprintf(stderr, "TWSI space allocation error!\n"); + return -1; + } + memset(tmpTwsi, 0xFF, MAX_TWSI_HDR_SIZE); + twsi_reg = (MV_U32 *)tmpTwsi; + + f_twsi = fopen(opt->fname_twsi, "r"); + if (f_twsi == NULL) { + fprintf(stderr, "Failed to open file '%s'\n", opt->fname_twsi); + perror("Error:"); + return -1; + } + + for (i = 0; i < (MAX_TWSI_HDR_SIZE / 4); i++) { + if (EOF == fscanf(f_twsi, "%x\n", twsi_reg)) + break; + + /* Swap Enianess */ + *twsi_reg = + (((*twsi_reg >> 24) & 0xFF) | ((*twsi_reg >> 8) & 0xFF00) | + ((*twsi_reg << 8) & 0xFF0000) | + ((*twsi_reg << 24) & 0xFF000000)); + twsi_reg++; + } + + fclose(f_twsi); + + /* Align to size = 512,1024,.. with at least 8 0xFF bytes @ the end */ + twsi_size = ((((i + 2) * 4) & ~0x1FF) + 0x200); + + if ((write(f_out, tmpTwsi, twsi_size)) != twsi_size) { + fprintf(stderr, "Error writing %s file\n", opt->fname.out); + return -1; + } + + return 0; +} /* end of build_twsi_header() */ + +/******************************************************************************* +* build_reg_header +* create BIN header and write it into output stream +* INPUT: +* fname - source file name +* buffer - Start address of boot image buffer +* current_size - number of bytes already placed into the boot image buffer +* OUTPUT: +* none +* RETURN: +* size of a reg header or 0 on fail +*******************************************************************************/ +int build_reg_header(char *fname, MV_U8 *buffer, MV_U32 current_size) +{ + FILE *f_dram; + BHR_t *mainHdr = (BHR_t *)buffer; + headExtBHR_t *headExtHdr = headExtHdr = + (headExtBHR_t *)(buffer + current_size); + tailExtBHR_t *prevExtHdrTail = + NULL; /* tail of the previous extension header */ + MV_U32 max_bytes_to_write; + MV_U32 *dram_reg = + (MV_U32 *)(buffer + current_size + sizeof(headExtBHR_t)); + MV_U32 tmp_len; + int i; + + if (mainHdr->ext == 255) { + fprintf(stderr, "Maximum number of extensions reached!\n"); + return 0; + } + + /* Indicate next header in previous extension if any */ + if (mainHdr->ext != 0) { + prevExtHdrTail = (tailExtBHR_t *)(buffer + current_size - + sizeof(tailExtBHR_t)); + prevExtHdrTail->nextHdr = 1; + } + + /* Count extension headers in the main header */ + mainHdr->ext++; + + headExtHdr->type = EXT_HDR_TYP_REGISTER; + max_bytes_to_write = MAX_HEADER_SIZE - current_size - EXT_HDR_BASE_SIZE; + f_dram = fopen(fname, "r"); + if (f_dram == NULL) { + fprintf(stderr, "Failed to open file '%s'\n", fname); + perror("Error:"); + return 0; + } + + for (i = 0; i < (max_bytes_to_write / 8); i += 2) { + if (fscanf(f_dram, "%x %x\n", &dram_reg[i], &dram_reg[i + 1]) == + EOF) + break; + else if ((dram_reg[i] == 0x0) && (dram_reg[i + 1] == 0x0)) + break; + } + + fclose(f_dram); + + if (i >= (max_bytes_to_write / 8)) { + fprintf(stderr, "Registers configure exceeds maximum size\n"); + return 0; + } + + /* Include extended header head and tail sizes */ + tmp_len = EXT_HDR_BASE_SIZE + i * 4; + /* Write total length into the current header fields */ + EXT_HDR_SET_LEN(headExtHdr, tmp_len); + + return tmp_len; +} /* end of build_reg_header() */ + +/******************************************************************************* +* build_bin_header +* create BIN header and write it into putput stream +* INPUT: +* fname - source file name +* buffer - Start address of boot image buffer +* current_size - number of bytes already placed into the boot image buffer +* OUTPUT: +* none +* RETURN: +* size of reg header +*******************************************************************************/ +int build_bin_header(char *fname, MV_U8 *buffer, MV_U32 current_size) +{ + FILE *f_bin; + BHR_t *mainHdr = (BHR_t *)buffer; + headExtBHR_t *headExtHdr = (headExtBHR_t *)(buffer + current_size); + tailExtBHR_t *prevExtHdrTail = + NULL; /* tail of the previous extension header */ + MV_U32 max_bytes_to_write; + MV_U32 *bin_reg = + (MV_U32 *)(buffer + current_size + sizeof(headExtBHR_t)); + MV_U32 tmp_len; + int i; + + if (mainHdr->ext == 255) { + fprintf(stderr, "Maximum number of extensions reached!\n"); + return 0; + } + + /* Indicate next header in previous extension if any */ + if (mainHdr->ext != 0) { + prevExtHdrTail = (tailExtBHR_t *)(buffer + current_size - + sizeof(tailExtBHR_t)); + prevExtHdrTail->nextHdr = 1; + } + + /* Count extension headers in main header */ + mainHdr->ext++; + + headExtHdr->type = EXT_HDR_TYP_BINARY; + max_bytes_to_write = MAX_HEADER_SIZE - current_size - EXT_HDR_BASE_SIZE; + + f_bin = fopen(fname, "r"); + if (f_bin == NULL) { + fprintf(stderr, "Failed to open file '%s'\n", fname); + perror("Error:"); + return 0; + } + + for (i = 0; i < (max_bytes_to_write / 4); i++) { + if (fread(bin_reg, 1, 4, f_bin) != 4) + break; + + bin_reg++; + } + + fclose(f_bin); + + if (i >= (max_bytes_to_write / 4)) { + fprintf(stderr, "Binary extension exeeds the maximum size\n"); + return 0; + } + + /* Include extended header head and tail sizes */ + tmp_len = EXT_HDR_BASE_SIZE + i * 4; + /* Write total length into the current header fields */ + EXT_HDR_SET_LEN(headExtHdr, tmp_len); + + return tmp_len; +} /* end of build_exec_header() */ + +/******************************************************************************* +* build_headers +* build headers block based on user options and write it into output +*stream +* INPUT: +* opt user options +* buf_in mmapped input file +* OUTPUT: +* none +* RETURN: +* 0 on success +*******************************************************************************/ +int build_headers(USER_OPTIONS *opt, char *buf_in) +{ + BHR_t *hdr = NULL; + secExtBHR_t *secExtHdr = NULL; + headExtBHR_t *headExtHdr = NULL; + tailExtBHR_t *tailExtHdr = NULL; + MV_U8 *tmpHeader = NULL; + int i; + MV_U32 header_size = 0; + int size_written = 0; + MV_U32 max_bytes_to_write; + int error = 1; + + tmpHeader = malloc(MAX_HEADER_SIZE); + if (tmpHeader == NULL) { + fprintf(stderr, "Header space allocation error!\n"); + goto header_error; + } + + memset(tmpHeader, 0, MAX_HEADER_SIZE); + hdr = (BHR_t *)tmpHeader; + + switch (opt->image_type) { + case IMG_SATA: + hdr->blockID = IBR_HDR_SATA_ID; + break; + + case IMG_UART: + hdr->blockID = IBR_HDR_UART_ID; + break; + + case IMG_FLASH: + hdr->blockID = IBR_HDR_SPI_ID; + break; + + case IMG_MMC: + hdr->blockID = IBR_HDR_MMC_ID; + break; + + case IMG_NAND: + hdr->blockID = IBR_HDR_NAND_ID; + /*hdr->nandEccMode = (MV_U8)opt->nandEccMode; <<== reserved */ + /*hdr->nandPageSize = (MV_U16)opt->nandPageSize; <<== reserved + */ + hdr->nandBlockSize = (MV_U8)opt->nandBlkSize; + if ((opt->nandCellTech == 'S') || (opt->nandCellTech == 's')) + hdr->nandTechnology = MAIN_HDR_NAND_SLC; + else + hdr->nandTechnology = MAIN_HDR_NAND_MLC; + break; + + case IMG_PEX: + hdr->blockID = IBR_HDR_PEX_ID; + break; + + case IMG_I2C: + hdr->blockID = IBR_HDR_I2C_ID; + break; + + default: + fprintf(stderr, + "Illegal image type %d for header construction!\n", + opt->image_type); + return 1; + } + + /* Debug print options */ + if (opt->flags & p_OPTION_MASK) + hdr->flags &= ~BHR_FLAG_PRINT_EN; + else + hdr->flags |= + BHR_FLAG_PRINT_EN; /* Enable printing by default */ + + if (opt->flags & b_OPTION_MASK) { + switch (opt->baudRate) { + case 2400: + hdr->options = BHR_OPT_BAUD_2400; + break; + + case 4800: + hdr->options = BHR_OPT_BAUD_4800; + break; + + case 9600: + hdr->options = BHR_OPT_BAUD_9600; + break; + + case 19200: + hdr->options = BHR_OPT_BAUD_19200; + break; + + case 38400: + hdr->options = BHR_OPT_BAUD_38400; + break; + + case 57600: + hdr->options = BHR_OPT_BAUD_57600; + break; + + case 115200: + hdr->options = BHR_OPT_BAUD_115200; + break; + + default: + fprintf(stderr, "Unsupported baud rate - %d!\n", + opt->baudRate); + return 1; + } + } else + hdr->options = BHR_OPT_BAUD_DEFAULT; + + /* debug port number */ + if (opt->flags & u_OPTION_MASK) + hdr->options |= (opt->debugPortNum << BHR_OPT_UART_PORT_OFFS) & + BHR_OPT_UART_PORT_MASK; + + /* debug port MPP setup index */ + if (opt->flags & m_OPTION_MASK) + hdr->options |= (opt->debugPortMpp << BHR_OPT_UART_MPPS_OFFS) & + BHR_OPT_UART_MPPS_MASK; + + hdr->destinationAddr = opt->image_dest; + hdr->executionAddr = (MV_U32)opt->image_exec; + hdr->version = MAIN_HDR_VERSION; + hdr->blockSize = fs_stat.st_size; + + header_size = sizeof(BHR_t); + + /* Update Block size address */ + if ((opt->flags & X_OPTION_MASK) || (opt->flags & Y_OPTION_MASK)) { + /* Align padding to 32 bit */ + if (opt->prepadding_size & 0x3) + opt->prepadding_size += + (4 - (opt->prepadding_size & 0x3)); + + if (opt->postpadding_size & 0x3) + opt->postpadding_size += + (4 - (opt->postpadding_size & 0x3)); + + hdr->blockSize += opt->prepadding_size + opt->postpadding_size; + } + + /* Align the image size to 4 byte boundary */ + if (hdr->blockSize & 0x3) { + opt->bytesToAlign = (4 - (hdr->blockSize & 0x3)); + hdr->blockSize += opt->bytesToAlign; + } + + /***************************** TWSI Header + * ********************************/ + + /* TWSI header has a special purpose and placed ahead of the main header + */ + if (opt->flags & M_OPTION_MASK) { + if (opt->fname_twsi) { + if (build_twsi_header(opt) != 0) + goto header_error; + } /* opt->fname_twsi */ + } /* (opt->flags & M_OPTION_MASK) */ + + /************************** End of TWSI Header + * ****************************/ + + /********************** Single Register Header + * ***************************/ + + if (opt->flags & R_OPTION_MASK) { + if (opt->fname_dram) { + MV_U32 rhdr_len = build_reg_header( + opt->fname_dram, tmpHeader, header_size); + if (rhdr_len <= 0) + goto header_error; + + header_size += rhdr_len; + tailExtHdr = (tailExtBHR_t *)(tmpHeader + header_size - + sizeof(tailExtBHR_t)); + } /* if (fname_dram) */ + } /* if (opts & R_OPTION_MASK) */ + + /******************** End of Single Register Header + * ************************/ + + /************************* Single Binary Header + * ****************************/ + + if (opt->flags & G_OPTION_MASK) { + if (opt->fname_bin) { + MV_U32 bhdr_len = build_bin_header( + opt->fname_bin, tmpHeader, header_size); + if (bhdr_len <= 0) + goto header_error; + + header_size += bhdr_len; + tailExtHdr = (tailExtBHR_t *)(tmpHeader + header_size - + sizeof(tailExtBHR_t)); + } /* if (fname_bin) */ + } /* (opt->flags & G_OPTION_MASK) */ + + /******************* End of Single Binary Header + * ***************************/ + + /************************* BIN/REG Headers list + * ****************************/ + + if (opt->flags & C_OPTION_MASK) { + if (opt->fname_list) { + FILE *f_list; + char buffer[PATH_MAX + 5]; + char *fname; + MV_U32 hdr_len = 0, last; + int (*build_hdr_func)(char *, MV_U8 *, MV_U32); + + f_list = fopen(opt->fname_list, "r"); + if (f_list == NULL) { + fprintf(stderr, "File not found\n"); + goto header_error; + } + /* read the headers list row by row */ + while (fgets(buffer, PATH_MAX + 4, f_list) != NULL) { + /* Ignore strings that are not starting with + * BIN/REG */ + if (strncmp(buffer, "BIN", 3) == 0) + build_hdr_func = build_bin_header; + else if (strncmp(buffer, "REG", 3) == 0) + build_hdr_func = build_reg_header; + else + continue; + + fname = buffer + 3; + /* strip leading spaces/tabs if any */ + while ((strncmp(fname, " ", 1) == 0) || + (strncmp(fname, "\t", 1) == 0)) + fname++; + + /* strip trailing LF/CR symbols */ + last = strlen(fname) - 1; + while ((strncmp(fname + last, "\n", 1) == 0) || + (strncmp(fname + last, "\r", 1) == 0)) { + fname[last] = 0; + last--; + } + /* Insert required header into the output buffer + */ + hdr_len = build_hdr_func(fname, tmpHeader, + header_size); + if (hdr_len <= 0) + goto header_error; + + header_size += hdr_len; + tailExtHdr = + (tailExtBHR_t *)(tmpHeader + header_size - + sizeof(tailExtBHR_t)); + } + + fclose(f_list); + } /* if (fname_list) */ + } /* (opt->flags & C_OPTION_MASK) */ + + /********************** End of BIN/REG Headers list + * ************************/ + + /* Align the headers block to... */ + if (opt->image_type == IMG_NAND) { + /* ... NAND page size */ + header_size += + opt->nandPageSize - (header_size & (opt->nandPageSize - 1)); + } else if ((opt->image_type == IMG_SATA) || + (opt->image_type == IMG_MMC)) { + /* ... disk logical block size */ + header_size += 512 - (header_size & 0x1FF); + } else if (opt->image_type == IMG_UART) { + /* ... Xmodem packet size */ + header_size += 128 - (header_size & 0x7F); + } + /* Setup the image source address */ + if (opt->image_type == IMG_SATA) { + if ((opt->image_source) && (opt->image_source > header_size)) + hdr->sourceAddr = opt->image_source; + else + hdr->sourceAddr = + header_size >> 9; /* Already aligned to 512 */ + } else { + if ((opt->image_source) && (opt->image_source > header_size)) { + hdr->sourceAddr = opt->image_source; + opt->img_gap = opt->image_source - header_size; + } else { + /* The source imgage address should be aligned + to 32 byte boundary (cache line size). + For NAND it should be aligned to 512 bytes boundary + (for ECC) + The image immediately follows the header block, + so if the source addess is undefined, it should be + derived from the header size. + The headers size is always alighed to 4 byte + boundary */ + int boundary = 32; + + if ((opt->image_type == IMG_NAND) || + (opt->image_type == IMG_MMC)) + boundary = 512; + + if (header_size & (boundary - 1)) + opt->img_gap = + boundary - (header_size & (boundary - 1)); + + hdr->sourceAddr = header_size + opt->img_gap; + } + } + + /* source address and extension headers number can be written now */ + fprintf(stdout, + "Ext. headers = %d, Header size = %d bytes Hdr-to-Img gap = %d bytes\n", + hdr->ext, header_size, opt->img_gap); + + /* If not UART/TWSI image, an extra word for boot image checksum is + * needed */ + if ((opt->image_type == IMG_FLASH) || (opt->image_type == IMG_NAND) || + (opt->image_type == IMG_MMC) || (opt->image_type == IMG_SATA) || + (opt->image_type == IMG_PEX) || (opt->image_type == IMG_I2C)) + hdr->blockSize += 4; + + fprintf(stdout, + "New image size = %#x[%d] Source image size = %#x[%d]\n", + hdr->blockSize, hdr->blockSize, (unsigned int)fs_stat.st_size, + (int)fs_stat.st_size); + + hdr->hdrSizeMsb = (header_size & 0x00FF0000) >> 16; + hdr->hdrSizeLsb = header_size & 0x0000FFFF; + + opt->image_sz = hdr->blockSize; + + /* Load image into memory buffer */ + if (REGULAR_IMAGE(opt)) { + if (0 != pre_load_image(opt, buf_in)) { + fprintf(stderr, "Failed image pre-load!\n"); + goto header_error; + } + } + + /* Now the headers block checksum should be calculated and wrote in the + * header */ + /* This checksum value should be valid for both secure and unsecure boot + * modes */ + /* This value will be checked first before RSA key and signature + * verification */ + hdr->checkSum = checksum8((void *)hdr, MAIN_HDR_GET_LEN(hdr), 0); + + /* Write to file(s) */ + if (opt->header_mode == HDR_IMG_TWO_FILES) { + /* copy header to output image */ + size_written = write(f_header, tmpHeader, header_size); + if (size_written != header_size) { + fprintf(stderr, "Error writing %s file\n" + , opt->fname.hdr_out); + goto header_error; + } + + fprintf(stdout, "====>>>> %s was created\n", + opt->fname_arr[HDR_FILE_INDX]); + /* if (header_mode == HDR_IMG_TWO_FILES) */ + } else { + /* copy header to output image */ + size_written = write(f_out, tmpHeader, header_size); + if (size_written != header_size) { + fprintf(stderr, "Error writing %s file\n" + , opt->fname.out); + goto header_error; + } + + } /* if (header_mode != HDR_IMG_TWO_FILES) */ + + error = 0; + +header_error: + + if (tmpHeader) + free(tmpHeader); + + return error; + +} /* end of build_headers() */ + +/******************************************************************************* +* build_bootrom_img +* create image in bootrom format and write it into output stream +* INPUT: +* opt user options +* buf_in mmapped input file +* OUTPUT: +* none +* RETURN: +* 0 on success +*******************************************************************************/ +int build_bootrom_img(USER_OPTIONS *opt, char *buf_in) +{ + unsigned int CRC_32 = 0; + int tmpSize = BOOTROM_SIZE - sizeof(CRC_32); + char *tmpImg = NULL; + int size_written = 0; + int error = 1; + + tmpImg = malloc(tmpSize); + if (tmpImg == NULL) + return 1; + + /* PAD image with Zeros until BOOTROM_SIZE*/ + memcpy(tmpImg, buf_in, fs_stat.st_size); + memset(tmpImg + fs_stat.st_size, 0, tmpSize - fs_stat.st_size); + + /* copy input image to output image */ + size_written = write(f_out, tmpImg, tmpSize); + + /* calculate checsum */ + CRC_32 = crc32(0, (u32 *)tmpImg, tmpSize / 4); + tmpSize += sizeof(CRC_32); + printf("Image CRC32 (size = %d) = 0x%08x\n", tmpSize, CRC_32); + + size_written += write(f_out, &CRC_32, sizeof(CRC_32)); + + if (size_written == tmpSize) + error = 0; + +bootrom_img_error: + + if (tmpImg) + free(tmpImg); + + return error; +} /* end of build_bootrom_img() */ + +/******************************************************************************* +* build_hex_img +* create image in hex format and write it into output stream +* INPUT: +* opt user options +* buf_in mmapped input file +* OUTPUT: +* none +* RETURN: +* 0 on success +*******************************************************************************/ +int build_hex_img(USER_OPTIONS *opt, char *buf_in) +{ + FILE *f_desc[2] = {NULL}; + char *tmpImg = NULL; + int hex_len; + int hex_unaligned_len = 0; + unsigned char *hex8 = NULL; + unsigned char tmp8; + unsigned short *hex16 = NULL; + unsigned short tmp16; + unsigned int *hex32 = NULL; + unsigned int tmp32; + unsigned int tmp32_low; + int size_written = 0; + int alignment = 0; + int files_num; + int i; + int error = 1; + + /* Calculate aligned image size */ + hex_len = fs_stat.st_size; + + alignment = opt->hex_width >> 3; + hex_unaligned_len = fs_stat.st_size & (alignment - 1); + + if (hex_unaligned_len) { + hex_len -= hex_unaligned_len; + hex_len += alignment; + } + + /* Copy the input image to memory buffer */ + tmpImg = malloc(hex_len); + if (tmpImg == NULL) + goto hex_image_end; + + memset(tmpImg, 0, hex_len); + memcpy(tmpImg, buf_in, fs_stat.st_size); + + if (opt->fname.hdr_out) + files_num = 2; + else + files_num = 1; + + for (i = 0; i < files_num; i++) { + f_desc[i] = fopen(opt->fname_arr[i + 1], "w"); + if (f_desc[i] == NULL) + goto hex_image_end; + } + + switch (opt->hex_width) { + case 8: + hex8 = (unsigned char *)tmpImg; + + for (i = 0; hex_len > 0; hex_len--) { + fprintf(f_desc[i], "%02X\n", *hex8++); + size_written += 1; + i ^= files_num - 1; + } + break; + + case 16: + hex16 = (unsigned short *)tmpImg; + + for (; hex_len > 0; hex_len -= 2) { + fprintf(f_desc[0], "%04X\n", *hex16++); + size_written += 2; + } + break; + + case 32: + hex32 = (unsigned int *)tmpImg; + + for (; hex_len > 0; hex_len -= 4) { + fprintf(f_desc[0], "%08X\n", *hex32++); + size_written += 4; + } + break; + + case 64: + hex32 = (unsigned int *)tmpImg; + + for (; hex_len > 0; hex_len -= 8) { + fprintf(f_desc[0], "%08X%08X\n", *hex32++, *hex32++); + size_written += 8; + } + break; + + } /* switch (opt->hex_width)*/ + + error = 0; + +hex_image_end: + + if (tmpImg) + free(tmpImg); + + for (i = 0; i < files_num; i++) { + if (f_desc[i] != NULL) + fclose(f_desc[i]); + } + + return error; +} /* end of build_hex_img() */ + +/******************************************************************************* +* build_bin_img +* create image in binary format and write it into output stream +* INPUT: +* opt user options +* buf_in mmapped input file +* OUTPUT: +* none +* RETURN: +* 0 on success +*******************************************************************************/ +int build_bin_img(USER_OPTIONS *opt, char *buf_in) +{ + FILE *f_ds = NULL; + FILE *f_desc[4] = {NULL}; + char *tmpImg = NULL; + int hex_len = 0; + int one_file_len = 0; + int size_written = 0; + int alignment = 0; + int hex_unaligned_len = 0; + unsigned char *hex8 = NULL; + unsigned char tmp8; + unsigned short *hex16 = NULL; + unsigned short tmp16; + unsigned long *hex32 = NULL; + unsigned long tmp32; + unsigned long tmp32low; + int i; + int fidx; + int files_num = 1; + int error = 1; + + /* Calculate aligned image size */ + hex_len = fs_stat.st_size; + + alignment = opt->hex_width >> 3; + hex_unaligned_len = fs_stat.st_size & (alignment - 1); + + if (hex_unaligned_len) { + hex_len -= hex_unaligned_len; + hex_len += alignment; + } + + /* prepare output files */ + if (opt->fname.romd) /*16KB*/ + files_num = 4; + else if (opt->fname.romc) /*12KB*/ + files_num = 3; + else if (opt->fname.hdr_out) + files_num = 2; + + one_file_len = hex_len / files_num; + + for (i = 0; i < files_num; i++) { + f_desc[i] = fopen(opt->fname_arr[i + 1], "w"); + if (f_desc[i] == NULL) + goto bin_image_end; + } + + /* Copy the input image to memory buffer */ + tmpImg = malloc(hex_len); + if (tmpImg == NULL) + goto bin_image_end; + + memset(tmpImg, 0, (hex_len)); + memcpy(tmpImg, buf_in, fs_stat.st_size); + + /* Split output image buffer according to width and number of files */ + switch (opt->hex_width) { + case 8: + hex8 = (unsigned char *)tmpImg; + if (files_num != 2) { + fprintf(stderr, + "Must supply two output file names for this width!\n"); + goto bin_image_end; + } + + for (fidx = 1; (fidx >= 0) && (hex_len > 0); fidx--) { + f_ds = f_desc[1 - fidx]; + + for (; hex_len > (fidx * one_file_len); hex_len--) { + tmp8 = *hex8; + + for (i = 0; i < opt->hex_width; i++) { + fprintf(f_ds, "%d", + ((tmp8 & 0x80) >> 7)); + tmp8 <<= 1; + } + fprintf(f_ds, "\n"); + + hex8++; + size_written += 1; + } + } + break; + + case 16: + hex16 = (unsigned short *)tmpImg; + + for (; hex_len > 0; hex_len -= 2) { + tmp16 = *hex16; + + for (i = 0; i < opt->hex_width; i++) { + fprintf(f_desc[0], "%d", + ((tmp16 & 0x8000) >> 15)); + tmp16 <<= 1; + } + fprintf(f_desc[0], "\n"); + + hex16++; + size_written += 2; + } + break; + + case 32: + hex32 = (long *)tmpImg; + + for (fidx = files_num - 1; (fidx >= 0) && (hex_len > 0); + fidx--) { + f_ds = f_desc[files_num - 1 - fidx]; + + for (; hex_len > (fidx * one_file_len); hex_len -= 4) { + tmp32 = *hex32; + + for (i = 0; i < opt->hex_width; i++) { + fprintf(f_ds, "%ld", + ((tmp32 & 0x80000000) >> 31)); + tmp32 <<= 1; + } + fprintf(f_ds, "\n"); + hex32++; + size_written += 4; + } + } + break; + + case 64: + hex32 = (long *)tmpImg; + + for (; hex_len > 0; hex_len -= 8) { + tmp32low = *hex32++; + tmp32 = *hex32++; + + for (i = 0; i < 32; i++) { + fprintf(f_desc[0], "%ld", + ((tmp32 & 0x80000000) >> 31)); + tmp32 <<= 1; + } + for (i = 0; i < 32; i++) { + fprintf(f_desc[0], "%ld", + ((tmp32low & 0x80000000) >> 31)); + tmp32low <<= 1; + } + fprintf(f_desc[0], "\n"); + size_written += 8; + } + break; + } /* switch (opt->hex_width) */ + + error = 0; + +bin_image_end: + + if (tmpImg) + free(tmpImg); + + for (i = 0; i < files_num; i++) { + if (f_desc[i] != NULL) + fclose(f_desc[i]); + } + + return error; + +} /* end of build_bin_img() */ + +/******************************************************************************* +* build_regular_img +* create regular boot image and write it into output stream +* INPUT: +* opt user options +* buf_in mmapped input file +* OUTPUT: +* none +* RETURN: +* 0 on success +*******************************************************************************/ +int build_regular_img(USER_OPTIONS *opt, char *buf_in) +{ + int size_written = 0; + int new_file_size = 0; + MV_U32 chsum32 = 0; + + new_file_size = opt->image_sz; + + if (0 != opt->img_gap) { /* cache line/NAND page/requested offset image + alignment */ + MV_U8 *gap_buf; + + gap_buf = calloc(opt->img_gap, sizeof(MV_U8)); + if (gap_buf == NULL) { + fprintf(stderr, + "Failed to allocate memory for header to image gap!\n"); + return 1; + } + size_written += write(f_out, gap_buf, opt->img_gap); + new_file_size += opt->img_gap; + free(gap_buf); + } + + /* Calculate checksum and copy it to the image tail */ + chsum32 = checksum32((void *)opt->image_buf, opt->image_sz - 4, 0); + memcpy(opt->image_buf + opt->image_sz - 4, &chsum32, 4); + + /* copy input image to output image */ + size_written += write(f_out, opt->image_buf, opt->image_sz); + free(opt->image_buf); + + if (new_file_size != size_written) { + fprintf(stderr, "Size mismatch between calculated/written\n"); + return 1; + } + + return 0; +} /* end of build_other_img() */ + +/******************************************************************************* +* process_image +* handle input and output file options, read and verify RSA and AES +*keys. +* INPUT: +* opt user options +* OUTPUT: +* none +* RETURN: +* 0 on success +******************************************************************************/ +int process_image(USER_OPTIONS *opt) +{ + int i; + int override[2]; + char *buf_in = NULL; + int err = 1; + + /* check if the output image exist */ + printf(" "); + for (i = IMG_FILE_INDX; i <= HDR_FILE_INDX; i++) { + if (opt->fname_arr[i]) { + override[i] = 0; + + if (0 == stat(opt->fname_arr[i], &fs_stat)) { + char c; + /* ask for overwrite permissions */ + fprintf(stderr, + "File '%s' already exist! Overwrite it (Y/n)?", + opt->fname_arr[i]); + c = getc(stdin); + if ((c == 'N') || (c == 'n')) { + printf("exit.. nothing done.\n"); + exit(0); + } else if ((c == 'Y') || (c == 'y')) { + /* additional read is needed for Enter + * key */ + c = getc(stdin); + } + override[i] = 1; + } + } + } + + /* open input image file and check if it's size is OK */ + if (opt->header_mode != HDR_ONLY) { + f_in = open(opt->fname.in, O_RDONLY | O_BINARY); + if (f_in == -1) { + fprintf(stderr, "File '%s' not found\n", opt->fname.in); + goto end; + } + /* get the size of the input image */ + if (0 != fstat(f_in, &fs_stat)) { + fprintf(stderr, "fstat failed for file: '%s' err=%d\n", + opt->fname.in, err); + goto end; + } + /*Check the source image size for limited output storage + * (bootrom) */ + if (opt->image_type == IMG_BOOTROM) { + int max_img_size = BOOTROM_SIZE - sizeof(u32); + + if (fs_stat.st_size > max_img_size) { + fprintf(stderr, + "ERROR : source image is bigger than %d bytes\n", + max_img_size); + goto end; + } + } + /* map the input image */ + buf_in = + mmap(0, fs_stat.st_size, PROT_READ, MAP_SHARED, f_in, 0); + if (!buf_in) { + fprintf(stderr, "Error mapping %s file\n", + opt->fname.in); + goto end; + } + } + + /* open the output image file */ + if (override[IMG_FILE_INDX] == 0) + f_out = open(opt->fname.out, + O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0666); + else + f_out = open(opt->fname.out, O_RDWR | O_BINARY); + + if (f_out == -1) { + fprintf(stderr, "Error opening %s file\n", opt->fname.out); + goto end; + } + + /* open the output header file */ + if (opt->header_mode == HDR_IMG_TWO_FILES) { + if (override[HDR_FILE_INDX] == 0) + f_header = + open(opt->fname.hdr_out, + O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0666); + else + f_header = open(opt->fname.hdr_out, O_RDWR | O_BINARY); + + if (f_header == -1) { + fprintf(stderr, "Error opening %s file\n", + opt->fname.hdr_out); + goto end; + } + } + + /* Image Header(s) */ + if (opt->header_mode != IMG_ONLY) { + if (0 != build_headers(opt, buf_in)) + goto end; + } + + /* Output Image */ + if (opt->header_mode != HDR_ONLY) { + if (opt->image_type == IMG_BOOTROM) + err = build_bootrom_img(opt, buf_in); + else if (opt->image_type == IMG_HEX) + err = build_hex_img(opt, buf_in); + else if (opt->image_type == IMG_BIN) + err = build_bin_img(opt, buf_in); + else + err = build_regular_img(opt, buf_in); + + if (err != 0) { + fprintf(stderr, "Error writing %s file\n" + , opt->fname.out); + goto end; + } + + fprintf(stdout, "====>>>> %s was created\n", + opt->fname_arr[IMG_FILE_INDX]); + + } /* if (opt->header_mode != HDR_ONLY) */ + +end: + /* close handles */ + if (f_out != -1) + close(f_out); + + if (f_header != -1) + close(f_header); + + if (buf_in) + munmap((void *)buf_in, fs_stat.st_size); + + if (f_in != -1) + close(f_in); + + return err; + +} /* end of process_image() */ + +/******************************************************************************* +* print_usage +* print command switches and their description +* INPUT: +* none +* OUTPUT: +* none +* RETURN: +* none +*******************************************************************************/ +void print_usage(void) +{ + printf( + "==============================================================================================\n\n"); + printf("Marvell doimage Tool version %s\n", VERSION_NUMBER); + printf("Supported SoC devices:\n\t%s\n", PRODUCT_SUPPORT); + printf( + "==============================================================================================\n\n"); + printf("Usage:\n"); + printf( + "doimage [other_options] [bootrom_output] [header_out]\n\n"); + + printf(" - can be one or more of the following:\n"); + printf( + "==============================================================================================\n\n"); + + printf( + "-T image_type: sata\\uart\\flash\\bootrom\\nand\\hex\\bin\\pex\\mmc\n"); + printf("-D image_dest: image destination in dram (in hex)\n"); + printf("-E image_exec: execution address in dram (in hex)\n"); + printf( + " if image_type is 'flash' and image_dest is 0xffffffff\n"); + printf(" then execution address on the flash\n"); + printf( + "-S image_source: if image_type is sata then the starting sector of\n"); + printf(" the source image on the disk\n"); + printf( + " if image_type is flash\\nand then the starting offset of\n"); + printf( + " the source image at the flash - optional for flash\\nand\n"); + printf("-W hex_width : HEX file width, can be 8,16,32,64\n"); + printf( + "-M twsi_file: ascii file name that contains the I2C init regs set by h/w.\n"); + printf(" this is used in i2c boot only\n"); + + printf("\nThe following options are mandatory for NAND image type:\n"); + printf( + "-----------------------------------------------------------------------------------------------\n\n"); + + printf( + "-L nand_blk_size:NAND block size in KBytes (decimal int in range 64-16320)\n"); + printf( + " This parameter is ignored for flashes with 512B pages\n"); + printf( + " Such small page flashes always use 16K block sizes\n"); + printf( + "-N nand_cell_typ:NAND cell technology type (char: M for MLC, S for SLC)\n"); + printf( + "-P nand_pg_size: NAND page size: (decimal 512, 2048, 4096 or 8192)\n"); + + printf( + "-G exec_file: ascii file name that contains binary routine (ARM 5TE THUMB)\n"); + printf( + " to run before the bootloader image execution.\n"); + printf( + " The routine must contain an appropriate code for saving\n"); + printf( + " all registers at the routine start and restore them\n"); + printf(" before return from the routine\n"); + printf( + "-R dram_file: ascii file name that contains the list of dram regs\n"); + printf( + "-C hdrs_file: ascii file name that defines BIN/REG headers order and their sources\n"); + printf("-X pre_padding_size (hex)\n"); + printf("-Y post_padding_size (hex)\n"); + printf("-H header_mode: Header mode, can be:\n"); + printf( + " -H 1 : will create one file (image_out) for header and image\n"); + printf( + " -H 2 : will create two files, (image_out) for image , (header_out) for header\n"); + printf( + " -H 3 : will create one file (image_out) for header only\n"); + printf( + " -H 4 : will create one file (image_out) for image only\n"); + + printf( + "\n[bootrom_output] - optional and can be one or more of the following:\n"); + printf( + "==============================================================================================\n\n"); + + printf( + "-p Disable BootROM messages output to UART port (enabled by default)\n"); + printf("-b baudrate Set BootROM debug port UART baudrate\n"); + printf( + " value = 2400,4800,9600,19200,38400,57600,115200 (use default baudrate is omitted)\n"); + printf( + "-u port_num Set BootROM debug port UART number value = 0-3 (use default port if omitted)\n"); + printf( + "-m mpp_config Select BootROM debug port MPPs configuration value = 0-7 (BootROM-specific)\n"); + + printf("\nCommand examples:\n\n"); + + printf("doimage -T hex -W width image_in image_out\n"); + printf("doimage -T bootrom image_in image_out\n"); + printf("doimage -T resume image_in image_out\n"); + printf("doimage -T sata -S sector -D image_dest -E image_exec\n"); + printf(" [other_options] image_in image_out header_out\n\n"); + printf("doimage -T flash -D image_dest -E image_exec [-S address]\n"); + printf(" [other_options] image_in image_out\n\n"); + printf("doimage -T pex -D image_dest -E image_exec\n"); + printf(" [other_options] image_in image_out\n\n"); + printf( + "doimage -T nand -D image_dest -E image_exec [-S address] -P page_size\n"); + printf(" -L 2 -N S [other_options] image_in image_out\n\n"); + printf("doimage -T uart -D image_dest -E image_exec\n"); + printf(" [other_options] image_in image_out\n\n"); + printf("doimage -T pex -D image_dest -E image_exec\n"); + printf(" [other_options] image_in image_out\n\n"); + printf("\n\n"); + +} /* end of print_usage() */ + +/******************************************************************************* +* checksum8 +* calculate 8-bit checksum of memory buffer +* INPUT: +* start buffer start +* len buffer length +* csum initial checksum value +* OUTPUT: +* none +* RETURN: +* 8-bit buffer checksum +*******************************************************************************/ +MV_U8 checksum8(void *start, MV_U32 len, MV_U8 csum) +{ + register MV_U8 sum = csum; + + volatile MV_U8 *startp = (volatile MV_U8 *)start; + + do { + sum += *(MV_U8 *)startp; + startp++; + + } while (--len); + + return sum; + +} /* end of checksum8 */ + +/******************************************************************************* +* checksum32 +* calculate 32-bit checksum of memory buffer +* INPUT: +* start buffer start +* len buffer length +* csum initial checksum value +* OUTPUT: +* none +* RETURN: +* 32-bit buffer checksum +*******************************************************************************/ +MV_U32 checksum32(void *start, MV_U32 len, MV_U32 csum) +{ + register MV_U32 sum = csum; + volatile MV_U32 *startp = (volatile MV_U32 *)start; + + do { + sum += *(MV_U32 *)startp; + startp++; + len -= 4; + + } while (len); + + return sum; + +} /* *end of checksum32() */ + +/******************************************************************************* +* make_crc_table +* init CRC table +* INPUT: +* crc_table CRC table location +* OUTPUT: +* crc_table CRC table location +* RETURN: +* none +*******************************************************************************/ +void make_crc_table(MV_U32 *crc_table) +{ + MV_U32 c; + MV_32 n, k; + MV_U32 poly; + + /* terms of polynomial defining this crc (except x^32): */ + static const MV_U8 p[] = {0, 1, 2, 4, 5, 7, 8, + 10, 11, 12, 16, 22, 23, 26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p) / sizeof(MV_U8); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) { + c = (MV_U32)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + +} /* end of make_crc_table */ + +#define DO1(buf) (crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)) +#define DO2(buf) do { \ + DO1(buf); \ + DO1(buf); \ + } while (0) +#define DO4(buf) do { \ + DO2(buf); \ + DO2(buf); \ + } while (0) +#define DO8(buf) do { \ + DO4(buf); \ + DO4(buf); \ + } while (0) + +/******************************************************************************* +* crc32 +* calculate CRC32 on memory buffer +* INPUT: +* crc initial CRC value +* buf memory buffer +* len buffer length +* OUTPUT: +* none +* RETURN: +* CRC32 of the memory buffer +*******************************************************************************/ +MV_U32 crc32(MV_U32 crc, volatile MV_U32 *buf, MV_U32 len) +{ + MV_U32 crc_table[256]; + + /* Create the CRC table */ + make_crc_table(crc_table); + + crc = crc ^ 0xffffffffL; + while (len >= 8) { + DO8(buf); + len -= 8; + } + + if (len) { + do { + DO1(buf); + } while (--len); + } + + return crc ^ 0xffffffffL; + +} /* end of crc32() */ + +/******************************************************************************* +* select_image +* select image options by the image name +* INPUT: +* img_name image name +* OUTPUT: +* opt image options +* RETURN: +* 0 on success, 1 if image name is invalid +*******************************************************************************/ +int select_image(char *img_name, USER_OPTIONS *opt) +{ + int i; + + static IMG_MAP img_map[] = { + {IMG_SATA, "sata", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK}, + {IMG_UART, "uart", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK}, + {IMG_FLASH, "flash", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK}, + {IMG_MMC, "mmc", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK}, + {IMG_BOOTROM, "bootrom", T_OPTION_MASK}, + {IMG_NAND, "nand", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK | + L_OPTION_MASK | N_OPTION_MASK | + P_OPTION_MASK}, + {IMG_HEX, "hex", T_OPTION_MASK | W_OPTION_MASK}, + {IMG_BIN, "bin", T_OPTION_MASK | W_OPTION_MASK}, + {IMG_PEX, "pex", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK}, + {IMG_I2C, "i2c", + D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK | M_OPTION_MASK}, + }; + + for (i = 0; i < ARRAY_SIZE(img_map); i++) { + if (strcmp(img_name, img_map[i].img_name) == 0) { + opt->image_type = img_map[i].img_type; + opt->req_flags = img_map[i].img_opt; + return 0; + } + } + + return 1; + +} /* *end of select_image() */ + +/******************************************************************************* +* main +*******************************************************************************/ +int main(int argc, char **argv) +{ + USER_OPTIONS options; + int optch; /* command-line option char */ + static char optstring[] = + "T:D:E:X:Y:S:P:W:H:R:M:G:L:N:C:b:u:m:p"; + int i, k; + + if (argc < 2) + goto parse_error; + + memset(&options, 0, sizeof(USER_OPTIONS)); + options.header_mode = HDR_IMG_ONE_FILE; + + fprintf(stdout, "\n"); + + while ((optch = getopt(argc, argv, optstring)) != -1) { + char *endptr = NULL; + + switch (optch) { + case 'T': /* image type */ + if ((select_image(optarg, &options) != 0) || + (options.flags & T_OPTION_MASK)) + goto parse_error; + options.flags |= T_OPTION_MASK; + break; + + case 'D': /* image destination */ + options.image_dest = strtoul(optarg, &endptr, 16); + if (*endptr || (options.flags & D_OPTION_MASK)) + goto parse_error; + options.flags |= D_OPTION_MASK; + DB("Image destination address %#x\n", + options.image_dest); + break; + + case 'E': /* image execution */ + options.image_exec = strtoul(optarg, &endptr, 16); + if (*endptr || (options.flags & E_OPTION_MASK)) + goto parse_error; + options.flags |= E_OPTION_MASK; + DB("Image execution address %#x\n", options.image_exec); + break; + + case 'X': /* Pre - Padding */ + options.prepadding_size = strtoul(optarg, &endptr, 16); + if (*endptr || (options.flags & X_OPTION_MASK)) + goto parse_error; + options.pre_padding = 1; + options.flags |= X_OPTION_MASK; + DB("Pre-pad image by %#x bytes\n", + options.prepadding_size); + break; + + case 'Y': /* Post - Padding */ + options.postpadding_size = strtoul(optarg, &endptr, 16); + if (*endptr || (options.flags & Y_OPTION_MASK)) + goto parse_error; + options.post_padding = 1; + options.flags |= Y_OPTION_MASK; + DB("Post-pad image by %#x bytes\n", + options.postpadding_size); + break; + + case 'S': /* starting sector */ + options.image_source = strtoul(optarg, &endptr, 16); + if (*endptr || (options.flags & S_OPTION_MASK)) + goto parse_error; + options.flags |= S_OPTION_MASK; + DB("Image start sector (image source) %#x\n", + options.image_source); + break; + + case 'P': /* NAND Page Size */ + options.nandPageSize = strtoul(optarg, &endptr, 10); + if (*endptr || (options.flags & P_OPTION_MASK)) + goto parse_error; + options.flags |= P_OPTION_MASK; + DB("NAND page size %d bytes\n", options.nandPageSize); + break; + + case 'C': /* headers definition filename */ + options.fname_list = optarg; + if (options.flags & C_OPTION_MASK) + goto parse_error; + options.flags |= C_OPTION_MASK; + DB("Headers definition file name %s\n", + options.fname_list); + break; + + case 'W': /* HEX file width */ + options.hex_width = strtoul(optarg, &endptr, 10); + if (*endptr || (options.flags & W_OPTION_MASK)) + goto parse_error; + options.flags |= W_OPTION_MASK; + DB("HEX file width %d bytes\n", options.hex_width); + break; + + case 'H': /* Header file mode */ + options.header_mode = strtoul(optarg, &endptr, 10); + if (*endptr || (options.flags & H_OPTION_MASK)) + goto parse_error; + options.flags |= H_OPTION_MASK; + DB("Header file mode is %d\n", options.header_mode); + break; + + case 'R': /* dram file */ + options.fname_dram = optarg; + if (options.flags & R_OPTION_MASK) + goto parse_error; + options.flags |= R_OPTION_MASK; + DB("Registers header file name %s\n", + options.fname_dram); + break; + + case 'M': /* TWSI file */ + options.fname_twsi = optarg; + if (options.flags & M_OPTION_MASK) + goto parse_error; + options.flags |= M_OPTION_MASK; + DB("TWSI header file name %s\n", options.fname_twsi); + break; + + case 'G': /* binary file */ + options.fname_bin = optarg; + if (options.flags & G_OPTION_MASK) + goto parse_error; + options.flags |= G_OPTION_MASK; + DB("Binary header file name %s\n", options.fname_bin); + break; + + case 'L': /* NAND block size */ + options.nandBlkSize = strtoul(optarg, &endptr, 10) / 64; + if (*endptr || (options.flags & L_OPTION_MASK)) + goto parse_error; + options.flags |= L_OPTION_MASK; + DB("NAND block size %d\n", options.nandBlkSize); + break; + + case 'N': /* NAND cell technology */ + options.nandCellTech = optarg[0]; + if (options.flags & N_OPTION_MASK) + goto parse_error; + options.flags |= N_OPTION_MASK; + DB("NAND cell technology %c\n", options.nandCellTech); + break; + + case 'p': /* BootROM debug output */ + if (options.flags & p_OPTION_MASK) + goto parse_error; + options.flags |= p_OPTION_MASK; + DB("BootROM debug output disabled\n"); + break; + + case 'b': /* BootROM debug port baudrate */ + options.baudRate = strtoul(optarg, &endptr, 10); + if (*endptr || (options.flags & b_OPTION_MASK)) + goto parse_error; + options.flags |= b_OPTION_MASK; + DB("BootROM debug port baudrate %d\n", + options.baudRate); + break; + + case 'u': /* BootROM debug port number */ + options.debugPortNum = strtoul(optarg, &endptr, 10); + if (*endptr || (options.flags & u_OPTION_MASK)) + goto parse_error; + options.flags |= u_OPTION_MASK; + DB("BootROM debug port number %d\n", + options.debugPortNum); + break; + + case 'm': /* BootROM debug port MPP settings */ + options.debugPortMpp = strtoul(optarg, &endptr, 10); + if (*endptr || (options.flags & m_OPTION_MASK)) + goto parse_error; + options.flags |= m_OPTION_MASK; + DB("BootROM debug port MPP setup # %d\n", + options.debugPortMpp); + break; + + default: + goto parse_error; + } + } /* parse command-line options */ + + /* assign file names */ + for (i = 0; (optind < argc) && (i < ARRAY_SIZE(options.fname_arr)); + ++optind, i++) { + options.fname_arr[i] = argv[optind]; + DB("File @ array index %d is %s (option index is %d)\n", i, + argv[optind], optind); + /* verify that all file names are different */ + for (k = 0; k < i; k++) { + if (0 == strcmp(options.fname_arr[i], + options.fname_arr[k])) { + fprintf(stderr, + "\nError: Input and output images can't be the same\n"); + exit(1); + } + } + } + + if (!(options.flags & T_OPTION_MASK)) + goto parse_error; + + /* verify HEX/BIN file width selection to be valid */ + if ((options.flags & W_OPTION_MASK) && (options.hex_width != 8) && + (options.hex_width != 16) && (options.hex_width != 32) && + (options.hex_width != 64)) + goto parse_error; + /* BootROM test images, no header is needed */ + if ((options.image_type == IMG_BOOTROM) || + (options.image_type == IMG_HEX) || (options.image_type == IMG_BIN)) + options.header_mode = IMG_ONLY; + + if (options.header_mode == IMG_ONLY) { + /* remove unneeded options */ + options.req_flags &= + ~(D_OPTION_MASK | E_OPTION_MASK | S_OPTION_MASK | + R_OPTION_MASK | P_OPTION_MASK | L_OPTION_MASK | + N_OPTION_MASK); + } + + if (options.req_flags != (options.flags & options.req_flags)) + goto parse_error; + + if ((options.flags & L_OPTION_MASK) && + ((options.nandBlkSize > 255) || + ((options.nandBlkSize == 0) && (options.nandPageSize != 512)))) { + fprintf(stderr, "Error: wrong NAND block size %d!\n\n\n\n\n", + 64 * options.nandBlkSize); + goto parse_error; + } + + if ((options.flags & N_OPTION_MASK) && (options.nandCellTech != 'S') && + (options.nandCellTech != 'M') && (options.nandCellTech != 's') && + (options.nandCellTech != 'm')) { + fprintf(stderr, + "Error: Wrong NAND cell technology type!\n\n\n\n\n"); + goto parse_error; + } + + return process_image(&options); + +parse_error: + + print_usage(); + exit(1); + +} /* end of main() */ diff --git a/util/marvell/doimage_mv/doimage.h b/util/marvell/doimage_mv/doimage.h new file mode 100644 index 0000000000..d0000c2731 --- /dev/null +++ b/util/marvell/doimage_mv/doimage.h @@ -0,0 +1,155 @@ +/******************************************************************************* +Copyright (C) Marvell International Ltd. and its affiliates + +Marvell GPL License Option + +If you received this File from Marvell, you may opt to use, redistribute and/or +modify this File in accordance with the terms and conditions of the General +Public License Version 2, June 1991 (the "GPL License"), a copy of which is +available along with the File in the license.txt file or by writing to the Free +Software Foundation, Inc. + +THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY +DISCLAIMED. The GPL License provides additional details about this warranty +disclaimer. + +*******************************************************************************/ +#ifndef _INC_DOIMAGE_H +#define _INC_DOIMAGE_H + +#include + +/* use the same version as in "bootrom.inc" file */ +#define VERSION_NUMBER "2.20" +#define PRODUCT_SUPPORT "Marvell Armada-3xx series" + +#define RSA_KEY_SIZE 2048 +#define RSA_EXPONENT 65537 + +#define T_OPTION_MASK 0x1 /* image type */ +#define D_OPTION_MASK 0x2 /* image destination */ +#define E_OPTION_MASK 0x4 /* image execution address */ +#define S_OPTION_MASK 0x8 /* starting sector */ +#define R_OPTION_MASK 0x10 /* DRAM file */ +#define C_OPTION_MASK 0x20 /* headers definition file */ +#define P_OPTION_MASK 0x40 /* NAND Page size */ +#define M_OPTION_MASK 0x80 /* TWSI serial init file */ +#define W_OPTION_MASK 0x100 /* HEX file width */ +#define H_OPTION_MASK 0x200 /* Header mode */ +#define X_OPTION_MASK 0x400 /* Pre padding */ +#define Y_OPTION_MASK 0x800 /* Post padding */ +#define J_OPTION_MASK 0x1000 /* JTAG Enabled */ +#define B_OPTION_MASK 0x2000 /* Box ID */ +#define Z_OPTION_MASK 0x4000 /* secure boot mode - KAK private key */ +#define F_OPTION_MASK 0x8000 /* Flash ID */ +#define A_OPTION_MASK 0x10000 /* secure boot mode - CSK private key */ +#define G_OPTION_MASK 0x20000 /* binary file */ +#define K_OPTION_MASK 0x40000 /* secure boot mode - CSK private key index */ +#define L_OPTION_MASK 0x80000 /* NAND block size (in 64K chunks) */ +#define N_OPTION_MASK 0x100000 /* NAND cell technology MLC/SLC */ +#define p_OPTION_MASK 0x200000 /* Print enable */ +#define b_OPTION_MASK 0x400000 /* Baudrate */ +#define u_OPTION_MASK 0x800000 /* debug serial port number */ +#define m_OPTION_MASK 0x1000000 /* debug serial port MPP configuration */ + +#ifndef O_BINARY /* should be defined on __WIN32__ */ +#define O_BINARY 0 +#endif + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +typedef enum { + IMG_SATA, + IMG_UART, + IMG_FLASH, + IMG_MMC, + IMG_BOOTROM, + IMG_NAND, + IMG_HEX, + IMG_BIN, + IMG_PEX, + IMG_I2C + +} IMG_TYPE; + +#define REGULAR_IMAGE(opt) \ + (((opt)->image_type != IMG_BOOTROM) && \ + ((opt)->image_type != IMG_HEX) && ((opt)->image_type != IMG_BIN)) + +typedef struct { + IMG_TYPE img_type; /* image type */ + char *img_name; /* image name string */ + unsigned int img_opt; /* mandatory options for this image type */ + +} IMG_MAP; + +typedef enum { + IMG_FILE_INDX = 1, + HDR_FILE_INDX = 2 + +} FILE_IDX; + +typedef enum { + HDR_IMG_ONE_FILE = 1, /* Create one file with header and image */ + HDR_IMG_TWO_FILES = 2, /* Create separate header and image files */ + HDR_ONLY = 3, /* Create only header */ + IMG_ONLY = 4, /* Create only image */ + +} HEADER_MODE; + +typedef struct { + IMG_TYPE image_type; + char *fname_dram; /* DRAM init file for "register" header */ + char *fname_twsi; /* TWSI serial init file */ + char *fname_bin; /* binary code file for "binary" header */ + char *fname_prkey; /* KAK RSA Private key file */ + char *fname_prkeyCsk; /* CSK RSA Private key file */ + char *fname_list; /* headers definition file */ + u32 flags; /* user-defined flags */ + u32 req_flags; /* mandatory flags */ + u32 image_source; /* starting sector */ + u32 image_dest; /* image destination */ + u32 image_exec; /* image execution */ + unsigned int hex_width; /* HEX file width */ + unsigned int header_mode; /* Header file mode */ + int csk_index; + int pre_padding; + int post_padding; + int prepadding_size; + int postpadding_size; + unsigned int bytesToAlign; + unsigned int nandPageSize; + unsigned int nandBlkSize; + char nandCellTech; + u32 boxId; + u32 flashId; + u32 jtagDelay; + char *image_buf; /* image buffer for image pre-load */ + u32 image_sz; /* total size of pre-loaded image buffer including + paddings */ + u32 img_gap; /* gap between header and image start point */ + u32 baudRate; /* debug print port baudrate */ + u32 debugPortNum; /* debug print port number */ + u32 debugPortMpp; /* debug print port MPP configuration */ + union { + char *fname_arr[5]; + struct { + char *in; + char *out; + char *hdr_out; + char *romc; + char *romd; + } fname; + }; +} USER_OPTIONS; + +/* Function declaration */ +void print_usage(void); + +/* 32 bit checksum */ +MV_U32 checksum32(void *start, MV_U32 len, MV_U32 csum); +MV_U8 checksum8(void *start, MV_U32 len, MV_U8 csum); +MV_U32 crc32(MV_U32 crc, volatile MV_U32 *buf, MV_U32 len); + +#endif /* _INC_DOIMAGE_H */