i2SOM: add write bootstream to NAND flash
The u-boot of i.MX6ULL chip needs header data.The update_nand.c will add header data when writing into NAND flash. These code reference from Digi ccimx6ul.
This commit is contained in:
14
board/i2som/common/Makefile
Normal file
14
board/i2som/common/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
#
|
||||
# (C) Copyright 2017
|
||||
# i2SOM Team.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
$(if $(CONFIG_CMD_BOOTSTREAM), $(shell mkdir -p $(obj)cmd_bootstream))
|
||||
|
||||
obj-$(CONFIG_CMD_BOOTSTREAM) += cmd_bootstream/bch.o \
|
||||
cmd_bootstream/ncb.o \
|
||||
cmd_bootstream/cmd_bootstream.o \
|
||||
cmd_bootstream/mxsboot.o
|
||||
obj-$(CONFIG_CMD_UPDATE_NAND) += cmd_update_nand.o helper.o
|
||||
353
board/i2som/common/cmd_bootstream/BootControlBlocks.h
Normal file
353
board/i2som/common/cmd_bootstream/BootControlBlocks.h
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#ifndef BOOTCONTROLBLOCKS_H_
|
||||
#define BOOTCONTROLBLOCKS_H_
|
||||
|
||||
#define NCB_FINGERPRINT1 0x504d5453 //!< 'STMP'
|
||||
#define NCB_FINGERPRINT2 0x2042434e //!< 'NCB<space>' - NAND Control Block
|
||||
#define NCB_FINGERPRINT3 0x4e494252 //!< 'RBIN' - ROM Boot Image Block - N
|
||||
|
||||
#define FCB_FINGERPRINT 0x20424346 //!< 'FCB '
|
||||
#define FCB_VERSION_1 0x01000000
|
||||
|
||||
#define LDLB_FINGERPRINT1 0x504d5453 //!< 'STMP'
|
||||
#define LDLB_FINGERPRINT2 0x424c444c //!< 'LDLB' - Logical Device Layout Block
|
||||
#define LDLB_FINGERPRINT3 0x4c494252 //!< 'RBIL' - ROM Boot Image Block - L
|
||||
|
||||
#define DBBT_FINGERPRINT1 0x504d5453 //!< 'STMP'
|
||||
#define DBBT_FINGERPRINT2 0x54424244 //!< 'DBBT' - Discovered Bad Block Table.
|
||||
#define DBBT_FINGERPRINT3 0x44494252 //!< 'RBID' - ROM Boot Image Block - D
|
||||
#define DBBT_VERSION_1 0x01000000
|
||||
|
||||
#define LDLB_VERSION_MAJOR 0x0001
|
||||
#define LDLB_VERSION_MINOR 0x0000
|
||||
#define LDLB_VERSION_SUB 0x0000
|
||||
|
||||
#define TYPICAL_NAND_READ_SIZE 2048
|
||||
|
||||
#define BCB_MAGIC_OFFSET 12
|
||||
|
||||
#define MAXSEQLEN 183
|
||||
|
||||
//==============================================================================
|
||||
|
||||
//! \brief NAND Timing structure for setting up the GPMI timing.
|
||||
//!
|
||||
//! This structure holds the timing for the NAND. This data is used by
|
||||
//! rom_nand_hal_GpmiSetNandTiming to setup the GPMI hardware registers.
|
||||
|
||||
typedef struct _NAND_Timing {
|
||||
uint8_t m_u8DataSetup;
|
||||
uint8_t m_u8DataHold;
|
||||
uint8_t m_u8AddressSetup;
|
||||
uint8_t m_u8DSAMPLE_TIME;
|
||||
} NCB_NAND_Timing_t;
|
||||
|
||||
//==============================================================================
|
||||
|
||||
//! \brief Structure defining where NCB and LDLB parameters are located.
|
||||
//!
|
||||
//! This structure defines the basic fingerprint template for both the Nand
|
||||
//! Control Block (NCB) and the Logical Drive Layout Block (LDLB). This
|
||||
//! template is used to determine if the sector read is a Boot Control Block.
|
||||
//! This structure defines the NAND Control Block (NCB). This block
|
||||
//! contains information describing the timing for the NAND, the number of
|
||||
//! NANDs in the system, the block size of the NAND, the page size of the NAND,
|
||||
//! and other criteria for the NAND. This is information that is
|
||||
//! required just to successfully communicate with the NAND.
|
||||
//! This structure also defines the Logical Drive Layout Block (LDLB). This
|
||||
//! block contains information describing the version as well as the layout of
|
||||
//! the code and data on the NAND Media. For the ROM, we're only concerned
|
||||
//! with the boot firmware start. Additional information may be stored in
|
||||
//! the Reserved3 area. This area will be of interest to the SDK.
|
||||
//! This structure also defines the Discovered Bad Block Table (DBBT) header.
|
||||
//! This block contains the information used for parsing the bad block tables
|
||||
//! which are stored in subsequent 2K sectors. The DBBT header is 8K, followed
|
||||
//! by the first NANDs entries, then the 2nd NANDs entries on a subsequent 2K
|
||||
//! page (determined by how many 2K pages the first nand requires), and so on.
|
||||
|
||||
typedef struct _NCB_BootBlockStruct_t {
|
||||
uint32_t m_u32FingerPrint1; //!< First fingerprint in first byte.
|
||||
union {
|
||||
struct {
|
||||
NCB_NAND_Timing_t m_NANDTiming; //!< Optimum timing parameters for Tas, Tds, Tdh in nsec.
|
||||
uint32_t m_u32DataPageSize; //!< 2048 for 2K pages, 4096 for 4K pages.
|
||||
uint32_t m_u32TotalPageSize; //!< 2112 for 2K pages, 4314 for 4K pages.
|
||||
uint32_t m_u32SectorsPerBlock; //!< Number of 2K sections per block.
|
||||
uint32_t m_u32SectorInPageMask; //!< Mask for handling pages > 2K.
|
||||
uint32_t m_u32SectorToPageShift; //!< Address shift for handling pages > 2K.
|
||||
uint32_t m_u32NumberOfNANDs; //!< Total Number of NANDs - not used by ROM.
|
||||
} NCB_Block1;
|
||||
struct {
|
||||
struct {
|
||||
uint16_t m_u16Major;
|
||||
uint16_t m_u16Minor;
|
||||
uint16_t m_u16Sub;
|
||||
uint16_t m_u16Reserved;
|
||||
} LDLB_Version; //!< LDLB version - not used by ROM.
|
||||
uint32_t m_u32NANDBitmap; //!< bit 0 == NAND 0, bit 1 == NAND 1, bit 2 = NAND 2, bit 3 = NAND3
|
||||
} LDLB_Block1;
|
||||
struct {
|
||||
uint32_t m_u32NumberBB_NAND0; //!< # Bad Blocks stored in this table for NAND0.
|
||||
uint32_t m_u32NumberBB_NAND1; //!< # Bad Blocks stored in this table for NAND1.
|
||||
uint32_t m_u32NumberBB_NAND2; //!< # Bad Blocks stored in this table for NAND2.
|
||||
uint32_t m_u32NumberBB_NAND3; //!< # Bad Blocks stored in this table for NAND3.
|
||||
uint32_t m_u32Number2KPagesBB_NAND0; //!< Bad Blocks for NAND0 consume this # of 2K pages.
|
||||
uint32_t m_u32Number2KPagesBB_NAND1; //!< Bad Blocks for NAND1 consume this # of 2K pages.
|
||||
uint32_t m_u32Number2KPagesBB_NAND2; //!< Bad Blocks for NAND2 consume this # of 2K pages.
|
||||
uint32_t m_u32Number2KPagesBB_NAND3; //!< Bad Blocks for NAND3 consume this # of 2K pages.
|
||||
} DBBT_Block1;
|
||||
// This one just forces the spacing.
|
||||
uint32_t m_Reserved1[10];
|
||||
};
|
||||
uint32_t m_u32FingerPrint2; //!< 2nd fingerprint at byte 10.
|
||||
union {
|
||||
struct {
|
||||
uint32_t m_u32NumRowBytes; //!< Number of row bytes in read/write transactions.
|
||||
uint32_t m_u32NumColumnBytes; //!< Number of row bytes in read/write transactions.
|
||||
uint32_t m_u32TotalInternalDie; //!< Number of separate chips in this NAND.
|
||||
uint32_t m_u32InternalPlanesPerDie; //!< Number of internal planes - treat like separate chips.
|
||||
uint32_t m_u32CellType; //!< MLC or SLC.
|
||||
uint32_t m_u32ECCType; //!< 4 symbol or 8 symbol ECC?
|
||||
|
||||
/**********************************/
|
||||
uint32_t m_u32EccBlock0Size; //!< Number of bytes for Block0 - BCH
|
||||
uint32_t m_u32EccBlockNSize; //!< Block size in bytes for all blocks other than Block0 - BCH
|
||||
uint32_t m_u32EccBlock0EccLevel; //!< Ecc level for Block 0 - BCH
|
||||
uint32_t m_u32NumEccBlocksPerPage; //!< Number of blocks per page - BCH
|
||||
uint32_t m_u32MetadataBytes; //!< Metadata size - BCH
|
||||
uint32_t m_u32EraseThreshold; //!< To set into BCH_MODE register.
|
||||
/**************** above is NCBv2 */
|
||||
|
||||
uint32_t m_u32Read1stCode; //!< First value sent to initiate a NAND Read sequence.
|
||||
uint32_t m_u32Read2ndCode; //!< Second value sent to initiate a NAND Read sequence.
|
||||
uint32_t m_u32BootPatch;
|
||||
uint32_t m_u32PatchSectors;
|
||||
uint32_t m_u32Firmware_startingNAND2;
|
||||
} NCB_Block2;
|
||||
struct {
|
||||
uint32_t m_u32Firmware_startingNAND; //!< Firmware image starts on this NAND.
|
||||
uint32_t m_u32Firmware_startingSector; //!< Firmware image starts on this sector.
|
||||
uint32_t m_u32Firmware_sectorStride; //!< Amount to jump between sectors - unused in ROM.
|
||||
uint32_t m_uSectorsInFirmware; //!< Number of sectors in firmware image.
|
||||
uint32_t m_u32Firmware_startingNAND2; //!< Secondary FW Image starting NAND.
|
||||
uint32_t m_u32Firmware_startingSector2; //!< Secondary FW Image starting Sector.
|
||||
uint32_t m_u32Firmware_sectorStride2; //!< Secondary FW Image stride - unused in ROM.
|
||||
uint32_t m_uSectorsInFirmware2; //!< Number of sector in secondary FW image.
|
||||
struct {
|
||||
uint16_t m_u16Major;
|
||||
uint16_t m_u16Minor;
|
||||
uint16_t m_u16Sub;
|
||||
uint16_t m_u16Reserved;
|
||||
} FirmwareVersion;
|
||||
uint32_t m_u32DiscoveredBBTableSector; //!< Location of Discovered Bad Block Table (DBBT).
|
||||
uint32_t m_u32DiscoveredBBTableSector2; //!< Location of backup DBBT
|
||||
} LDLB_Block2;
|
||||
// This one just forces the spacing.
|
||||
uint32_t m_Reserved2[20];
|
||||
};
|
||||
uint32_t m_u32FingerPrint3; //!< 3rd fingerprint at byte 30.
|
||||
union {
|
||||
struct {
|
||||
unsigned char ncb_unknown[12];
|
||||
};
|
||||
};
|
||||
} NCB_BootBlockStruct_t;
|
||||
|
||||
typedef enum _nand_ecc_type {
|
||||
RS_Ecc_4bit = 0,
|
||||
RS_Ecc_8bit,
|
||||
BCH_Ecc_0bit,
|
||||
BCH_Ecc_2bit,
|
||||
BCH_Ecc_4bit,
|
||||
BCH_Ecc_6bit,
|
||||
BCH_Ecc_8bit,
|
||||
BCH_Ecc_10bit,
|
||||
BCH_Ecc_12bit,
|
||||
BCH_Ecc_14bit,
|
||||
BCH_Ecc_16bit,
|
||||
BCH_Ecc_18bit,
|
||||
BCH_Ecc_20bit
|
||||
} nand_ecc_type_t;
|
||||
|
||||
typedef enum {
|
||||
ROM_BCH_Ecc_0bit = 0,
|
||||
ROM_BCH_Ecc_2bit,
|
||||
ROM_BCH_Ecc_4bit,
|
||||
ROM_BCH_Ecc_6bit,
|
||||
ROM_BCH_Ecc_8bit,
|
||||
ROM_BCH_Ecc_10bit,
|
||||
ROM_BCH_Ecc_12bit,
|
||||
ROM_BCH_Ecc_14bit,
|
||||
ROM_BCH_Ecc_16bit,
|
||||
ROM_BCH_Ecc_18bit,
|
||||
ROM_BCH_Ecc_20bit
|
||||
} rom_ecc_type_t;
|
||||
|
||||
//==============================================================================
|
||||
|
||||
//! \brief Structure of the Bad Block Entry Table in NAND.
|
||||
//!
|
||||
//! This structure defines the Discovered Bad Block Table (DBBT) entries. This
|
||||
//! block contains a word holding the NAND number then a word describing the number
|
||||
//! of Bad Blocks on the NAND and an array containing these bad blocks. The ROM
|
||||
//! will use these entries in the Bad Block table to correctly index to the next
|
||||
//! sector (skip over bad blocks) while reading from the NAND.
|
||||
//! Blocks are not guaranteed to be sorted in this table.
|
||||
typedef struct _BadBlockTableNand_t {
|
||||
uint32_t uNAND; //!< Which NAND this table is for.
|
||||
uint32_t uNumberBB; //!< Number of Bad Blocks in this NAND.
|
||||
// Divide by 4 because of 32 bit words. Subtract 2 because of the 2 above
|
||||
// 32 bit words.
|
||||
uint32_t u32BadBlock[(TYPICAL_NAND_READ_SIZE / 4) - 2]; //!< Table of the Bad Blocks.
|
||||
} BadBlockTableNand_t;
|
||||
|
||||
//==============================================================================
|
||||
|
||||
//! \brief NAND Timing structure for setting up the GPMI timing.
|
||||
//!
|
||||
//! This structure holds the timing for the NAND. This data is used by
|
||||
//! rom_nand_hal_GpmiSetNandTiming to setup the GPMI hardware registers.
|
||||
typedef struct {
|
||||
uint8_t m_u8DataSetup;
|
||||
uint8_t m_u8DataHold;
|
||||
uint8_t m_u8AddressSetup;
|
||||
uint8_t m_u8DSAMPLE_TIME;
|
||||
/* These are for application use only and not for ROM. */
|
||||
uint8_t m_u8NandTimingState;
|
||||
uint8_t m_u8REA;
|
||||
uint8_t m_u8RLOH;
|
||||
uint8_t m_u8RHOH;
|
||||
} FCB_ROM_NAND_Timing_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t m_u32TMTiming2_ReadLatency;
|
||||
uint32_t m_u32TMTiming2_PreambleDelay;
|
||||
uint32_t m_u32TMTiming2_CEDelay;
|
||||
uint32_t m_u32TMTiming2_PostambleDelay;
|
||||
uint32_t m_u32TMTiming2_CmdAddPause;
|
||||
uint32_t m_u32TMTiming2_DataPause;
|
||||
uint32_t m_u32TMSpeed;
|
||||
uint32_t m_u32TMTiming1_BusyTimeout;
|
||||
} FCB_ROM_NAND_TM_Timing_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t m_u32ONFISpeed;
|
||||
uint32_t m_u32ONFITiming_ReadLatency;
|
||||
uint32_t m_u32ONFITiming_CEDelay;
|
||||
uint32_t m_u32ONFITiming_PreambleDelay;
|
||||
uint32_t m_u32ONFITiming_PostambleDelay;
|
||||
uint32_t m_u32ONFITiming_CmdAddPause;
|
||||
uint32_t m_u32ONFITiming_DataPause;
|
||||
uint32_t m_u32ONFITiming_BusyTimeout;
|
||||
} FCB_ROM_NAND_ONFI_Timing_t;
|
||||
|
||||
struct fcb_block {
|
||||
FCB_ROM_NAND_Timing_t m_NANDTiming; //!< Optimum timing parameters for Tas, Tds, Tdh in nsec.
|
||||
uint32_t m_u32PageDataSize; //!< 2048 for 2K pages, 4096 for 4K pages.
|
||||
uint32_t m_u32TotalPageSize; //!< 2112 for 2K pages, 4314 for 4K pages.
|
||||
uint32_t m_u32SectorsPerBlock; //!< Number of 2K sections per block.
|
||||
uint32_t m_u32NumberOfNANDs; //!< Total Number of NANDs - not used by ROM.
|
||||
uint32_t m_u32TotalInternalDie; //!< Number of separate chips in this NAND.
|
||||
uint32_t m_u32CellType; //!< MLC or SLC.
|
||||
uint32_t m_u32EccBlockNEccType; //!< Type of ECC, can be one of BCH-0-20
|
||||
uint32_t m_u32EccBlock0Size; //!< Number of bytes for Block0 - BCH
|
||||
uint32_t m_u32EccBlockNSize; //!< Block size in bytes for all blocks other than Block0 - BCH
|
||||
uint32_t m_u32EccBlock0EccType; //!< Ecc level for Block 0 - BCH
|
||||
uint32_t m_u32MetadataBytes; //!< Metadata size - BCH
|
||||
uint32_t m_u32NumEccBlocksPerPage; //!< Number of blocks per page for ROM use - BCH
|
||||
uint32_t m_u32EccBlockNEccLevelSDK; //!< Type of ECC, can be one of BCH-0-20
|
||||
uint32_t m_u32EccBlock0SizeSDK; //!< Number of bytes for Block0 - BCH
|
||||
uint32_t m_u32EccBlockNSizeSDK; //!< Block size in bytes for all blocks other than Block0 - BCH
|
||||
uint32_t m_u32EccBlock0EccLevelSDK; //!< Ecc level for Block 0 - BCH
|
||||
uint32_t m_u32NumEccBlocksPerPageSDK; //!< Number of blocks per page for SDK use - BCH
|
||||
uint32_t m_u32MetadataBytesSDK; //!< Metadata size - BCH
|
||||
uint32_t m_u32EraseThreshold; //!< To set into BCH_MODE register.
|
||||
uint32_t m_u32BootPatch; //!< 0 for normal boot and 1 to load patch starting next to FCB.
|
||||
uint32_t m_u32PatchSectors; //!< Size of patch in sectors.
|
||||
uint32_t m_u32Firmware1_startingPage; //!< Firmware image starts on this sector.
|
||||
uint32_t m_u32Firmware2_startingPage; //!< Secondary FW Image starting Sector.
|
||||
uint32_t m_u32PagesInFirmware1; //!< Number of sectors in firmware image.
|
||||
uint32_t m_u32PagesInFirmware2; //!< Number of sector in secondary FW image.
|
||||
uint32_t m_u32DBBTSearchAreaStartAddress;//!< Page address where dbbt search area begins
|
||||
uint32_t m_u32BadBlockMarkerByte; //!< Byte in page data that have manufacturer marked bad block marker, this will
|
||||
//!< bw swapped with metadata[0] to complete page data.
|
||||
uint32_t m_u32BadBlockMarkerStartBit; //!< For BCH ECC sizes other than 8 and 16 the bad block marker does not start
|
||||
//!< at 0th bit of m_u32BadBlockMarkerByte. This field is used to get to the
|
||||
//!< start bit of bad block marker byte with in m_u32BadBlockMarkerByte.
|
||||
uint32_t m_u32BBMarkerPhysicalOffset; //!< FCB value that gives byte offset for bad block marker on physical NAND page.
|
||||
uint32_t m_u32BCHType;
|
||||
FCB_ROM_NAND_TM_Timing_t m_NANDTMTiming;
|
||||
uint32_t m_u32DISBBM; /* the flag to enable (1)/disable(0) bi swap */
|
||||
uint32_t m_u32BBMarkerPhysicalOffsetInSpareData; /* The swap position of main area in spare area */
|
||||
|
||||
uint32_t m_u32OnfiSyncEnable; //!< Enable the Onfi nand sync mode support
|
||||
FCB_ROM_NAND_ONFI_Timing_t m_NANDONFITiming;
|
||||
uint32_t m_u32DISBBSearch; //!< Disable the badblock search when reading the firmware, only using DBBT.
|
||||
|
||||
uint32_t m_u32RandomizerEnable; //!< Enable randomizer support
|
||||
uint32_t reserved[15];
|
||||
uint32_t m_u32ReadRetryEnable; //!< Enable ready retry support
|
||||
uint32_t m_u32ReadRetrySeqLength; //!< Read retry sequence length
|
||||
uint32_t m_u32ReadRetrySeq[MAXSEQLEN]; //!< Read retry sequence length
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
||||
//! \brief Structure defining where FCB and DBBT parameters are located.
|
||||
//!
|
||||
//! This structure defines the basic fingerprint template for both the Firmware
|
||||
//! Control Block (FCB) and the Discovered Bad Block Table (DBBT). This
|
||||
//! template is used to determine if the sector read is a Boot Control Block.
|
||||
//! This structure defines the Firmware Control Block (FCB). This block
|
||||
//! contains information describing the timing for the NAND, the number of
|
||||
//! NANDs in the system, the block size of the NAND, the page size of the NAND,
|
||||
//! and other criteria for the NAND. This is information that is
|
||||
//! required just to successfully communicate with the NAND.
|
||||
//! This block contains information describing the version as well as the layout of
|
||||
//! the code and data on the NAND Media. For the ROM, we're only concerned
|
||||
//! with the boot firmware start. Additional information may be stored in
|
||||
//! the Reserved area. This area will be of interest to the SDK.
|
||||
//! This structure also defines the Discovered Bad Block Table (DBBT) header.
|
||||
//! This block contains the information used for parsing the bad block tables
|
||||
//! which are stored in subsequent 2K sectors. The DBBT header is 8K, followed
|
||||
//! by the first NANDs entries on a subsequent 2K page (determined by how many
|
||||
//! 2K pages the first nand requires)
|
||||
typedef struct {
|
||||
uint32_t m_u32Checksum; //!< First fingerprint in first byte.
|
||||
uint32_t m_u32FingerPrint; //!< 2nd fingerprint at byte 4.
|
||||
uint32_t m_u32Version; //!< 3rd fingerprint at byte 8.
|
||||
union {
|
||||
struct fcb_block FCB_Block;
|
||||
union {
|
||||
struct {
|
||||
uint32_t m_u32NumberBB; //!< # Bad Blocks stored in this table for NAND0.
|
||||
uint32_t m_u32Number2KPagesBB; //!< Bad Blocks for NAND0 consume this # of 2K pages.
|
||||
} v2;
|
||||
struct {
|
||||
uint32_t m_u32res;
|
||||
uint32_t m_u32DBBTNumOfPages;
|
||||
} v3;
|
||||
} DBBT_Block;
|
||||
};
|
||||
} BCB_ROM_BootBlockStruct_t;
|
||||
|
||||
#endif /*BOOTCONTROLBLOCKS_H_ */
|
||||
|
||||
1541
board/i2som/common/cmd_bootstream/bch.c
Normal file
1541
board/i2som/common/cmd_bootstream/bch.c
Normal file
File diff suppressed because it is too large
Load Diff
100
board/i2som/common/cmd_bootstream/bch.h
Normal file
100
board/i2som/common/cmd_bootstream/bch.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*
|
||||
* Generic binary BCH encoding/decoding library
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright © 2011 Parrot S.A.
|
||||
*
|
||||
* Author: Ivan Djelic <ivan.djelic@parrot.com>
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* This library provides runtime configurable encoding/decoding of binary
|
||||
* Bose-Chaudhuri-Hocquenghem (BCH) codes.
|
||||
*/
|
||||
#ifndef _BCH_H
|
||||
#define _BCH_H
|
||||
|
||||
//#include <types.h>
|
||||
|
||||
/**
|
||||
* struct bch_control - BCH control structure
|
||||
* @m: Galois field order
|
||||
* @n: maximum codeword size in bits (= 2^m-1)
|
||||
* @t: error correction capability in bits
|
||||
* @ecc_bits: ecc exact size in bits, i.e. generator polynomial degree (<=m*t)
|
||||
* @ecc_bytes: ecc max size (m*t bits) in bytes
|
||||
* @a_pow_tab: Galois field GF(2^m) exponentiation lookup table
|
||||
* @a_log_tab: Galois field GF(2^m) log lookup table
|
||||
* @mod8_tab: remainder generator polynomial lookup tables
|
||||
* @ecc_buf: ecc parity words buffer
|
||||
* @ecc_buf2: ecc parity words buffer
|
||||
* @xi_tab: GF(2^m) base for solving degree 2 polynomial roots
|
||||
* @syn: syndrome buffer
|
||||
* @cache: log-based polynomial representation buffer
|
||||
* @elp: error locator polynomial
|
||||
* @poly_2t: temporary polynomials of degree 2t
|
||||
*/
|
||||
struct bch_control {
|
||||
unsigned int m;
|
||||
unsigned int n;
|
||||
unsigned int t;
|
||||
unsigned int ecc_bits;
|
||||
unsigned int ecc_bytes;
|
||||
/* private: */
|
||||
uint16_t *a_pow_tab;
|
||||
uint16_t *a_log_tab;
|
||||
uint32_t *mod8_tab;
|
||||
uint32_t *ecc_buf;
|
||||
uint32_t *ecc_buf2;
|
||||
unsigned int *xi_tab;
|
||||
unsigned int *syn;
|
||||
int *cache;
|
||||
struct gf_poly *elp;
|
||||
struct gf_poly *poly_2t[4];
|
||||
};
|
||||
|
||||
struct bch_control *init_bch(int m, int t, unsigned int prim_poly);
|
||||
|
||||
void free_bch(struct bch_control *bch);
|
||||
|
||||
void encode_bch(struct bch_control *bch, const uint8_t *data,
|
||||
unsigned int len, uint8_t *ecc);
|
||||
|
||||
int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len,
|
||||
const uint8_t *recv_ecc, const uint8_t *calc_ecc,
|
||||
const unsigned int *syn, unsigned int *errloc);
|
||||
|
||||
int encode_bch_ecc(void *source_block, size_t source_size,
|
||||
void *target_block, size_t target_size, int version);
|
||||
#endif /* _BCH_H */
|
||||
696
board/i2som/common/cmd_bootstream/cmd_bootstream.c
Normal file
696
board/i2som/common/cmd_bootstream/cmd_bootstream.c
Normal file
@ -0,0 +1,696 @@
|
||||
/*
|
||||
* Copyright (C) 2017 i2SOM Team.
|
||||
* Copyright (C) 2011 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* i2SOM Team used for i.MX6 platform.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bootstream support for Freescale platforms
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#if defined(CONFIG_CMD_BOOTSTREAM) && defined(CONFIG_CMD_NAND)
|
||||
#include <div64.h>
|
||||
#include <command.h>
|
||||
#include <nand.h>
|
||||
#include <jffs2/load_kernel.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <net.h> /* DHCP */
|
||||
#include "cmd_bootstream.h"
|
||||
#include "BootControlBlocks.h"
|
||||
|
||||
extern uint32_t mx28_nand_mark_byte_offset(void);
|
||||
extern uint32_t mx28_nand_mark_bit_offset(void);
|
||||
|
||||
const struct mtd_config default_mtd_config = {
|
||||
.chip_count = 1,
|
||||
.chip_0_offset = 0,
|
||||
.chip_0_size = 0,
|
||||
.chip_1_offset = 0,
|
||||
.chip_1_size = 0,
|
||||
.search_exponent = 2,
|
||||
.data_setup_time = 80,
|
||||
.data_hold_time = 60,
|
||||
.address_setup_time = 25,
|
||||
.data_sample_time = 6,
|
||||
.row_address_size = 3,
|
||||
.column_address_size = 2,
|
||||
.read_command_code1 = 0x00,
|
||||
.read_command_code2 = 0x30,
|
||||
.boot_stream_major_version = 1,
|
||||
.boot_stream_minor_version = 0,
|
||||
.boot_stream_sub_version = 0,
|
||||
.ncb_version = 3,
|
||||
.boot_stream_1_address = 0,
|
||||
.boot_stream_2_address = 0,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
void dump_buffer(unsigned char *buf, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((i % 16) == 0)
|
||||
printf("\n");
|
||||
if (i == 0 || (i % 8) == 0)
|
||||
printf(" ");
|
||||
printf("%02x ", buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int write_firmware(struct mtd_info *mtd,
|
||||
struct mtd_config *cfg,
|
||||
struct mtd_bootblock *bootblock,
|
||||
unsigned long bs_start_address,
|
||||
unsigned int boot_stream_size_in_bytes,
|
||||
unsigned int pre_padding)
|
||||
{
|
||||
int startpage, start, size;
|
||||
int i, r, chunk;
|
||||
loff_t ofs, end;
|
||||
int chip = 0;
|
||||
unsigned long read_addr;
|
||||
size_t nbytes = 0;
|
||||
char *readbuf = NULL;
|
||||
|
||||
readbuf = malloc(mtd->writesize);
|
||||
if (NULL == readbuf)
|
||||
return -1;
|
||||
|
||||
if (pre_padding) {
|
||||
/*
|
||||
* rewind bs_start_address pre_padding bytes and fill it with
|
||||
* zeros.
|
||||
*/
|
||||
if (bs_start_address - pre_padding < PHYS_SDRAM) {
|
||||
printf("pre-padding required! "
|
||||
"Use a $loadaddr of at least 0x%08x\n",
|
||||
PHYS_SDRAM + pre_padding);
|
||||
goto _error;
|
||||
}
|
||||
bs_start_address -= pre_padding;
|
||||
memset((u8 *)bs_start_address, 0, pre_padding);
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
// Loop over the two boot streams.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* Set start address where bootstream is in RAM */
|
||||
read_addr = bs_start_address;
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Figure out where to put the current boot stream.
|
||||
//--------------------------------------------------------------
|
||||
|
||||
if (i == 0) {
|
||||
startpage = bootblock->fcb.FCB_Block.m_u32Firmware1_startingPage;
|
||||
size = bootblock->fcb.FCB_Block.m_u32PagesInFirmware1;
|
||||
end = bootblock->fcb.FCB_Block.m_u32Firmware2_startingPage;
|
||||
} else {
|
||||
startpage = bootblock->fcb.FCB_Block.m_u32Firmware2_startingPage;
|
||||
size = bootblock->fcb.FCB_Block.m_u32PagesInFirmware2;
|
||||
end = lldiv(mtd->size, mtd->writesize);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Compute the byte addresses corresponding to the page
|
||||
// addresses.
|
||||
//--------------------------------------------------------------
|
||||
|
||||
start = startpage * mtd->writesize;
|
||||
size = size * mtd->writesize;
|
||||
end = end * mtd->writesize;
|
||||
|
||||
if (cfg->flags & F_VERBOSE)
|
||||
printf("mtd: Writting firmware image #%d @%d: 0x%08x - 0x%08x\n", i,
|
||||
chip, start, start + size);
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Loop over pages as we write them.
|
||||
//--------------------------------------------------------------
|
||||
|
||||
ofs = start;
|
||||
while (ofs < end && size > 0) {
|
||||
|
||||
//------------------------------------------------------
|
||||
// Check if the current block is bad.
|
||||
//------------------------------------------------------
|
||||
|
||||
while (nand_block_isbad(mtd, ofs) == 1) {
|
||||
if (cfg->flags & F_VERBOSE)
|
||||
fprintf(stdout, "mtd: Skipping bad block at 0x%llx\n", ofs);
|
||||
ofs += mtd->erasesize;
|
||||
}
|
||||
|
||||
chunk = size;
|
||||
|
||||
//------------------------------------------------------
|
||||
// Check if we've entered a new block and, if so, erase
|
||||
// it before beginning to write it.
|
||||
//------------------------------------------------------
|
||||
|
||||
if (llmod(ofs, mtd->erasesize) == 0) {
|
||||
if (cfg->flags & F_VERBOSE) {
|
||||
fprintf(stdout, "erasing block at 0x%llx\n", ofs);
|
||||
}
|
||||
if (!(cfg->flags & F_DRYRUN)) {
|
||||
r = nand_erase(mtd, ofs, mtd->erasesize);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "mtd: Failed to erase block @0x%llx\n", ofs);
|
||||
ofs += mtd->erasesize;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk > mtd->writesize)
|
||||
chunk = mtd->writesize;
|
||||
|
||||
//------------------------------------------------------
|
||||
// Write the current chunk to the medium.
|
||||
//------------------------------------------------------
|
||||
|
||||
if (cfg->flags & F_VERBOSE) {
|
||||
fprintf(stdout, "Writing bootstream file from 0x%lx to offset 0x%llx\n", read_addr, ofs);
|
||||
}
|
||||
if (!(cfg->flags & F_DRYRUN)) {
|
||||
r = nand_write_skip_bad(mtd, ofs, (size_t *)&chunk, &nbytes, mtd->size, (unsigned char *)read_addr, WITH_WR_VERIFY);
|
||||
if (r || nbytes != chunk) {
|
||||
fprintf(stderr, "mtd: Failed to write BS @0x%llx (%d)\n", ofs, r);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------
|
||||
// Verify the written data
|
||||
//------------------------------------------------------
|
||||
r = nand_read_skip_bad(mtd, ofs, (size_t*)&chunk, &nbytes, mtd->size, (unsigned char *)readbuf);
|
||||
if (r || nbytes != chunk) {
|
||||
fprintf(stderr, "mtd: Failed to read BS @0x%llx (%d)\n", ofs, r);
|
||||
goto _error;
|
||||
}
|
||||
if (memcmp((void *)read_addr, readbuf, chunk)) {
|
||||
fprintf(stderr, "mtd: Verification error @0x%llx\n", ofs);
|
||||
goto _error;
|
||||
}
|
||||
|
||||
ofs += mtd->writesize;
|
||||
read_addr += mtd->writesize;
|
||||
size -= chunk;
|
||||
}
|
||||
if (cfg->flags & F_VERBOSE)
|
||||
printf("mtd: Verified firmware image #%d @%d: 0x%08x - 0x%08x\n", i,
|
||||
chip, start, start + size);
|
||||
|
||||
/*
|
||||
* Write one safe guard page:
|
||||
* The Image_len of uboot is bigger then the real size of
|
||||
* uboot by 1K. The ROM will get all 0xff error in this case.
|
||||
* So we write one more page for safe guard.
|
||||
*/
|
||||
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Check if we ran out of room.
|
||||
//--------------------------------------------------------------
|
||||
|
||||
if (ofs >= end) {
|
||||
fprintf(stderr, "mtd: Failed to write BS#%d\n", i);
|
||||
goto _error;
|
||||
}
|
||||
}
|
||||
|
||||
free(readbuf);
|
||||
return 0;
|
||||
_error:
|
||||
free(readbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int v1_rom_mtd_init(struct mtd_info *mtd,
|
||||
struct mtd_config *cfg,
|
||||
struct mtd_bootblock *bootblock,
|
||||
unsigned int boot_stream_size_in_bytes,
|
||||
uint64_t part_size)
|
||||
{
|
||||
unsigned int stride_size_in_bytes;
|
||||
unsigned int search_area_size_in_bytes;
|
||||
#ifdef CONFIG_USE_NAND_DBBT
|
||||
unsigned int search_area_size_in_pages;
|
||||
#endif
|
||||
unsigned int max_boot_stream_size_in_bytes;
|
||||
unsigned int boot_stream_size_in_pages;
|
||||
unsigned int boot_stream1_pos;
|
||||
unsigned int boot_stream2_pos;
|
||||
BCB_ROM_BootBlockStruct_t *fcb;
|
||||
BCB_ROM_BootBlockStruct_t *dbbt;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Compute the geometry of a search area.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
stride_size_in_bytes = PAGES_PER_STRIDE * mtd->writesize;
|
||||
search_area_size_in_bytes = (1 << cfg->search_exponent) * stride_size_in_bytes;
|
||||
#ifdef CONFIG_USE_NAND_DBBT
|
||||
search_area_size_in_pages = (1 << cfg->search_exponent) * PAGES_PER_STRIDE;
|
||||
#endif
|
||||
//----------------------------------------------------------------------
|
||||
// Check if the target MTD is too small to even contain the necessary
|
||||
// search areas.
|
||||
//
|
||||
// Recall that the boot area for the i.MX28 appears at the beginning of
|
||||
// the first chip and contains two search areas: one each for the FCB
|
||||
// and DBBT.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
if ((search_area_size_in_bytes * 2) > mtd->size) {
|
||||
fprintf(stderr, "mtd: mtd size too small\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Figure out how large a boot stream the target MTD could possibly
|
||||
// hold.
|
||||
//
|
||||
// The boot area will contain both search areas and two copies of the
|
||||
// boot stream.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
max_boot_stream_size_in_bytes =
|
||||
|
||||
lldiv(part_size - search_area_size_in_bytes * 2,
|
||||
//--------------------------------------------//
|
||||
2);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Figure out how large the boot stream is.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
boot_stream_size_in_pages =
|
||||
|
||||
(boot_stream_size_in_bytes + (mtd->writesize - 1)) /
|
||||
//---------------------------------------------------//
|
||||
mtd->writesize;
|
||||
|
||||
if (cfg->flags & F_VERBOSE) {
|
||||
printf("mtd: max_boot_stream_size_in_bytes = %d\n", max_boot_stream_size_in_bytes);
|
||||
printf("mtd: boot_stream_size_in_bytes = %d\n", boot_stream_size_in_bytes);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Check if the boot stream will fit.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
if (boot_stream_size_in_bytes >= max_boot_stream_size_in_bytes) {
|
||||
fprintf(stderr, "mtd: bootstream too large\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Compute the positions of the boot stream copies.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
boot_stream1_pos = 2 * search_area_size_in_bytes;
|
||||
boot_stream2_pos = boot_stream1_pos + max_boot_stream_size_in_bytes;
|
||||
|
||||
if (cfg->flags & F_VERBOSE) {
|
||||
printf("mtd: #1 0x%08x - 0x%08x (0x%08x)\n",
|
||||
boot_stream1_pos, boot_stream1_pos + max_boot_stream_size_in_bytes,
|
||||
boot_stream1_pos + boot_stream_size_in_bytes);
|
||||
printf("mtd: #2 0x%08x - 0x%08x (0x%08x)\n",
|
||||
boot_stream2_pos, boot_stream2_pos + max_boot_stream_size_in_bytes,
|
||||
boot_stream2_pos + boot_stream_size_in_bytes);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Fill in the FCB.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
fcb = &(bootblock->fcb);
|
||||
memset(fcb, 0, sizeof(*fcb));
|
||||
|
||||
fcb->m_u32FingerPrint = FCB_FINGERPRINT;
|
||||
fcb->m_u32Version = FCB_VERSION_1;
|
||||
|
||||
fcb->FCB_Block.m_NANDTiming.m_u8DataSetup = cfg->data_setup_time;
|
||||
fcb->FCB_Block.m_NANDTiming.m_u8DataHold = cfg->data_hold_time;
|
||||
fcb->FCB_Block.m_NANDTiming.m_u8AddressSetup = cfg->address_setup_time;
|
||||
fcb->FCB_Block.m_NANDTiming.m_u8DSAMPLE_TIME = cfg->data_sample_time;
|
||||
|
||||
fcb->FCB_Block.m_u32PageDataSize = mtd->writesize;
|
||||
fcb->FCB_Block.m_u32TotalPageSize = mtd->writesize + mtd->oobsize;
|
||||
fcb->FCB_Block.m_u32SectorsPerBlock = mtd->erasesize / mtd->writesize;
|
||||
|
||||
if (mtd->writesize == 2048) {
|
||||
fcb->FCB_Block.m_u32NumEccBlocksPerPage = mtd->writesize / 512 - 1;
|
||||
fcb->FCB_Block.m_u32MetadataBytes = 10;
|
||||
fcb->FCB_Block.m_u32EccBlock0Size = 512;
|
||||
fcb->FCB_Block.m_u32EccBlockNSize = 512;
|
||||
#if CONFIG_MX6UL
|
||||
fcb->FCB_Block.m_u32EccBlock0EccType = ROM_BCH_Ecc_4bit;
|
||||
fcb->FCB_Block.m_u32EccBlockNEccType = ROM_BCH_Ecc_4bit;
|
||||
#endif
|
||||
|
||||
} else if (mtd->writesize == 4096) {
|
||||
fcb->FCB_Block.m_u32NumEccBlocksPerPage = (mtd->writesize / 512) - 1;
|
||||
fcb->FCB_Block.m_u32MetadataBytes = 10;
|
||||
fcb->FCB_Block.m_u32EccBlock0Size = 512;
|
||||
fcb->FCB_Block.m_u32EccBlockNSize = 512;
|
||||
if (mtd->oobsize == 218) {
|
||||
fcb->FCB_Block.m_u32EccBlock0EccType = ROM_BCH_Ecc_16bit;
|
||||
fcb->FCB_Block.m_u32EccBlockNEccType = ROM_BCH_Ecc_16bit;
|
||||
} else if ((mtd->oobsize == 128)){
|
||||
fcb->FCB_Block.m_u32EccBlock0EccType = ROM_BCH_Ecc_8bit;
|
||||
fcb->FCB_Block.m_u32EccBlockNEccType = ROM_BCH_Ecc_8bit;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Illegal page size %d\n", mtd->writesize);
|
||||
}
|
||||
|
||||
fcb->FCB_Block.m_u32BootPatch = 0; // Normal boot.
|
||||
|
||||
fcb->FCB_Block.m_u32Firmware1_startingPage = boot_stream1_pos / mtd->writesize;
|
||||
fcb->FCB_Block.m_u32Firmware2_startingPage = boot_stream2_pos / mtd->writesize;
|
||||
fcb->FCB_Block.m_u32PagesInFirmware1 = boot_stream_size_in_pages;
|
||||
fcb->FCB_Block.m_u32PagesInFirmware2 = boot_stream_size_in_pages;
|
||||
#ifdef CONFIG_USE_NAND_DBBT
|
||||
fcb->FCB_Block.m_u32DBBTSearchAreaStartAddress = search_area_size_in_pages;
|
||||
#else
|
||||
fcb->FCB_Block.m_u32DBBTSearchAreaStartAddress = 0;
|
||||
#endif
|
||||
fcb->FCB_Block.m_u32BadBlockMarkerByte = mx28_nand_mark_byte_offset();
|
||||
fcb->FCB_Block.m_u32BadBlockMarkerStartBit = mx28_nand_mark_bit_offset();
|
||||
fcb->FCB_Block.m_u32BBMarkerPhysicalOffset = mtd->writesize;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Fill in the DBBT.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
dbbt = &(bootblock->dbbt28);
|
||||
memset(dbbt, 0, sizeof(*dbbt));
|
||||
|
||||
dbbt->m_u32FingerPrint = DBBT_FINGERPRINT2;
|
||||
dbbt->m_u32Version = 1;
|
||||
|
||||
dbbt->DBBT_Block.v2.m_u32NumberBB = 0;
|
||||
dbbt->DBBT_Block.v2.m_u32Number2KPagesBB = 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// This function writes the search areas for a given BCB. It will write *two*
|
||||
// search areas for a given BCB. If there are multiple chips, it will write one
|
||||
// search area on each chip. If there is one chip, it will write two search
|
||||
// areas on the first chip.
|
||||
//
|
||||
// md A pointer to the current struct mtd_data.
|
||||
// bcb_name A pointer to a human-readable string that indicates what kind of
|
||||
// BCB we're writing. This string will only be used in log messages.
|
||||
// ofs1 If there is one chips, the index of the
|
||||
// ofs2
|
||||
// ofs_mchip If there are multiple chips, the index of the search area to write
|
||||
// on both chips.
|
||||
// end The number of consecutive search areas to be written.
|
||||
// size The size of the BCB data to be written.
|
||||
// ecc Indicates whether or not to use hardware ECC.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int mtd_commit_bcb(struct mtd_info *mtd,
|
||||
struct mtd_config *cfg,
|
||||
struct mtd_bootblock *bootblock,
|
||||
char *bcb_name,
|
||||
loff_t ofs1, loff_t ofs2, loff_t ofs_mchip,
|
||||
loff_t end, size_t size)
|
||||
{
|
||||
int chip;
|
||||
loff_t end_index, search_area_indices[2], o;
|
||||
int err = 0, r = -1;
|
||||
int i;
|
||||
int j;
|
||||
unsigned stride_size_in_bytes;
|
||||
unsigned search_area_size_in_strides;
|
||||
unsigned search_area_size_in_bytes;
|
||||
size_t nbytes = 0;
|
||||
unsigned char *readbuf = NULL;
|
||||
unsigned count;
|
||||
|
||||
readbuf = malloc(mtd->writesize);
|
||||
if (NULL == readbuf)
|
||||
return -1;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Compute some important facts about geometry.
|
||||
//----------------------------------------------------------------------
|
||||
#ifdef MX_USE_SINGLE_PAGE_STRIDE /* mx23, mx28 */
|
||||
stride_size_in_bytes = mtd->erasesize;
|
||||
search_area_size_in_strides = 4;
|
||||
search_area_size_in_bytes = search_area_size_in_strides * stride_size_in_bytes;
|
||||
count = 2; //write two copy on mx23/28
|
||||
#else
|
||||
stride_size_in_bytes = PAGES_PER_STRIDE * mtd->writesize;
|
||||
search_area_size_in_strides = 1 << cfg->search_exponent;
|
||||
search_area_size_in_bytes = search_area_size_in_strides * stride_size_in_bytes;
|
||||
count = 1; //only write one copy
|
||||
#endif
|
||||
/* NOTE (hpalacio): For i.MX28 we are not defining MX_USE_SINGLE_PAGE_STRIDE and
|
||||
* so we are getting into the 'else' above. The calculated figures result the same
|
||||
* except for the 'count' field. Having the 'count' field to a value of 2 simply
|
||||
* loops to write twice the four FCB or DBBT copies.
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Check whether there are multiple chips and set up the two search area
|
||||
// indices accordingly.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
if (cfg->chip_count > 1)
|
||||
search_area_indices[0] = search_area_indices[1] = ofs_mchip;
|
||||
else {
|
||||
search_area_indices[0] = ofs1;
|
||||
search_area_indices[1] = ofs2;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Loop over search areas for this BCB.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
for (i = 0; !err && i < count; i++) {
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Compute the search area index that marks the end of the
|
||||
// writing on this chip.
|
||||
//--------------------------------------------------------------
|
||||
|
||||
end_index = search_area_indices[i] + end;
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Figure out which chip we're writing.
|
||||
//--------------------------------------------------------------
|
||||
|
||||
chip = (cfg->chip_count > 1) ? i : 0;
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Loop over consecutive search areas to write.
|
||||
//--------------------------------------------------------------
|
||||
|
||||
for (; search_area_indices[i] < end_index; search_area_indices[i]++) {
|
||||
|
||||
//------------------------------------------------------
|
||||
// Compute the byte offset of the beginning of this
|
||||
// search area.
|
||||
//------------------------------------------------------
|
||||
|
||||
o = search_area_indices[i] * search_area_size_in_bytes;
|
||||
|
||||
//------------------------------------------------------
|
||||
// Loop over strides in this search area.
|
||||
//------------------------------------------------------
|
||||
|
||||
for (j = 0; j < search_area_size_in_strides; j++, o += stride_size_in_bytes) {
|
||||
|
||||
//----------------------------------------------
|
||||
// If we're crossing into a new block, erase it
|
||||
// first.
|
||||
//----------------------------------------------
|
||||
|
||||
if (llmod(o, mtd->erasesize) == 0) {
|
||||
if (cfg->flags & F_VERBOSE) {
|
||||
fprintf(stdout, "erasing block at 0x%llx\n", o);
|
||||
}
|
||||
if (!(cfg->flags & F_DRYRUN)) {
|
||||
r = nand_erase(mtd, o, mtd->erasesize);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "mtd: Failed to erase block @0x%llx\n", o);
|
||||
err++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
// Write & verify the page.
|
||||
//----------------------------------------------
|
||||
|
||||
if (cfg->flags & F_VERBOSE)
|
||||
fprintf(stdout, "mtd: Writing %s%d @%d:0x%llx(%x)\n",
|
||||
bcb_name, j, chip, o, size);
|
||||
|
||||
if (!(cfg->flags & F_DRYRUN)) {
|
||||
if (size == mtd->writesize + mtd->oobsize) {
|
||||
/* We're going to write a raw page (data+oob) */
|
||||
mtd_oob_ops_t ops = {
|
||||
.datbuf = bootblock->buf,
|
||||
.len = mtd->writesize,
|
||||
.mode = MTD_OPS_RAW,
|
||||
};
|
||||
|
||||
r = mtd_write_oob(mtd, o, &ops);
|
||||
if (r) {
|
||||
fprintf(stderr, "mtd: Failed to write %s @%d: 0x%llx (%d)\n",
|
||||
bcb_name, chip, o, r);
|
||||
err ++;
|
||||
}
|
||||
//------------------------------------------------------
|
||||
// Verify the written data
|
||||
//------------------------------------------------------
|
||||
ops.datbuf = (u8 *)readbuf;
|
||||
r = mtd_read_oob(mtd, o, &ops);
|
||||
if (r) {
|
||||
fprintf(stderr, "mtd: Failed to read @0x%llx (%d)\n", o, r);
|
||||
err++;
|
||||
goto _error;
|
||||
}
|
||||
if (memcmp(bootblock->buf, readbuf, mtd->writesize)) {
|
||||
fprintf(stderr, "mtd: Verification error @0x%llx\n", o);
|
||||
err++;
|
||||
goto _error;
|
||||
}
|
||||
|
||||
if (cfg->flags & F_VERBOSE)
|
||||
fprintf(stdout, "mtd: Verified %s%d @%d:0x%llx(%x)\n",
|
||||
bcb_name, j, chip, o, size);
|
||||
}
|
||||
else {
|
||||
r = nand_write_skip_bad(mtd, o, &size, &nbytes, mtd->size, bootblock->buf, WITH_WR_VERIFY);
|
||||
if (r || nbytes != size) {
|
||||
fprintf(stderr, "mtd: Failed to write %s @%d: 0x%llx (%d)\n",
|
||||
bcb_name, chip, o, r);
|
||||
err ++;
|
||||
}
|
||||
//------------------------------------------------------
|
||||
// Verify the written data
|
||||
//------------------------------------------------------
|
||||
r = nand_read_skip_bad(mtd, o, &size, &nbytes, mtd->size, readbuf);
|
||||
if (r || nbytes != size) {
|
||||
fprintf(stderr, "mtd: Failed to read @0x%llx (%d)\n", o, r);
|
||||
err++;
|
||||
goto _error;
|
||||
}
|
||||
if (memcmp(bootblock->buf, readbuf, size)) {
|
||||
fprintf(stderr, "mtd: Verification error @0x%llx\n", o);
|
||||
err++;
|
||||
goto _error;
|
||||
}
|
||||
if (cfg->flags & F_VERBOSE)
|
||||
fprintf(stdout, "mtd: Verified %s%d @%d:0x%llx(%x)\n",
|
||||
bcb_name, j, chip, o, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (cfg->flags & F_VERBOSE)
|
||||
printf("%s(%s): status %d\n", __func__, bcb_name, err);
|
||||
|
||||
_error:
|
||||
free(readbuf);
|
||||
return err;
|
||||
}
|
||||
|
||||
int v6_rom_mtd_commit_structures(struct mtd_info *mtd,
|
||||
struct mtd_config *cfg,
|
||||
struct mtd_bootblock *bootblock,
|
||||
unsigned long bs_start_address,
|
||||
unsigned int boot_stream_size_in_bytes)
|
||||
{
|
||||
int size, r;
|
||||
|
||||
/* [1] Write the FCB search area. */
|
||||
size = mtd->writesize + mtd->oobsize;
|
||||
|
||||
r = fcb_encrypt(&bootblock->fcb, bootblock->buf, size, 3);
|
||||
if (r < 0)
|
||||
return r;
|
||||
mtd_commit_bcb(mtd, cfg, bootblock, "FCB", 0, 0, 0, 1, size);
|
||||
|
||||
/* [2] Write the DBBT search area. */
|
||||
memset(bootblock->buf, 0, size);
|
||||
memcpy(bootblock->buf, &(bootblock->dbbt28), sizeof(bootblock->dbbt28));
|
||||
|
||||
mtd_commit_bcb(mtd, cfg, bootblock, "DBBT", 1, 1, 1, 1, mtd->writesize);
|
||||
|
||||
/* [3] Write the two boot streams using a 1K padding. */
|
||||
return write_firmware(mtd, cfg, bootblock, bs_start_address,
|
||||
boot_stream_size_in_bytes, 1024);
|
||||
}
|
||||
|
||||
int write_bootstream(struct part_info *part,
|
||||
unsigned long bs_start_address,
|
||||
int bs_size)
|
||||
{
|
||||
/* TODO: considering chip = 0 */
|
||||
int chip = 0;
|
||||
struct mtd_info *mtd = &nand_info[chip];
|
||||
int r = -1;
|
||||
struct mtd_config cfg;
|
||||
struct mtd_bootblock bootblock;
|
||||
|
||||
/* copy defaults */
|
||||
memcpy(&cfg, &default_mtd_config, sizeof(cfg));
|
||||
|
||||
/* flags (TODO: parse command arguments?) */
|
||||
//cfg.flags |= F_VERBOSE;
|
||||
//cfg.flags |= F_DRYRUN;
|
||||
|
||||
/* alloc buffer */
|
||||
bootblock.buf = malloc(mtd->writesize + mtd->oobsize);
|
||||
if (NULL == bootblock.buf) {
|
||||
fprintf(stderr, "mtd: unable to allocate page buffer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Writing bootstream...");
|
||||
#if defined(CONFIG_MX6ULL) || defined(CONFIG_MX6UL)
|
||||
r = v1_rom_mtd_init(mtd, &cfg, &bootblock, bs_size, part->size);
|
||||
#endif
|
||||
if (r < 0) {
|
||||
printf("mtd_init failed!\n");
|
||||
}
|
||||
else {
|
||||
#if defined(CONFIG_MX6ULL) || defined(CONFIG_MX6UL)
|
||||
r = v6_rom_mtd_commit_structures(mtd, &cfg, &bootblock, bs_start_address, bs_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* free buffer */
|
||||
free(bootblock.buf);
|
||||
if (r)
|
||||
printf("FAILED\n");
|
||||
else
|
||||
printf("OK\n");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CMD_BOOTSTREAM && CONFIG_CMD_NAND */
|
||||
109
board/i2som/common/cmd_bootstream/cmd_bootstream.h
Normal file
109
board/i2som/common/cmd_bootstream/cmd_bootstream.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2011 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bootstream support for Freescale platforms
|
||||
*/
|
||||
|
||||
#ifndef __DIGI_CMD_BOOTSTREAM_H
|
||||
#define __DIGI_CMD_BOOTSTREAM_H
|
||||
|
||||
#include <jffs2/load_kernel.h>
|
||||
#include <mtd/mtd-abi.h>
|
||||
#include "BootControlBlocks.h"
|
||||
|
||||
/* flags */
|
||||
#define F_VERBOSE (1 << 0)
|
||||
#define F_DRYRUN (1 << 1)
|
||||
|
||||
struct mtd_config {
|
||||
int chip_count;
|
||||
int chip_0_offset;
|
||||
int chip_0_size;
|
||||
int chip_1_offset;
|
||||
int chip_1_size;
|
||||
int search_exponent;
|
||||
int data_setup_time;
|
||||
int data_hold_time;
|
||||
int address_setup_time;
|
||||
int data_sample_time;
|
||||
int row_address_size;
|
||||
int column_address_size;
|
||||
int read_command_code1;
|
||||
int read_command_code2;
|
||||
int boot_stream_major_version;
|
||||
int boot_stream_minor_version;
|
||||
int boot_stream_sub_version;
|
||||
int ncb_version;
|
||||
int boot_stream_1_address;
|
||||
int boot_stream_2_address;
|
||||
int flags;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// This structure represents an MTD device in which we will write boot
|
||||
// information.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
struct mtd_part {
|
||||
// A bit set where each bit corresponds to a block in a given MTD.
|
||||
uint32_t *bad_blocks;
|
||||
|
||||
// The number of bad blocks appearing in this MTD.
|
||||
int nrbad;
|
||||
|
||||
int oobinfochanged;
|
||||
struct nand_oobinfo old_oobinfo;
|
||||
int ecc;
|
||||
};
|
||||
|
||||
/* partially implements mtd_data in kobs-ng */
|
||||
struct mtd_bootblock {
|
||||
struct mtd_part part[2];
|
||||
/* writesize + oobsize buffer */
|
||||
void *buf;
|
||||
|
||||
/* NCBs */
|
||||
NCB_BootBlockStruct_t *curr_ncb;
|
||||
NCB_BootBlockStruct_t ncb[2];
|
||||
loff_t ncb_ofs[2];
|
||||
int ncb_version; /* 0, 1, or 3. Negative means error */
|
||||
|
||||
/* LDLBs */
|
||||
NCB_BootBlockStruct_t *curr_ldlb;
|
||||
NCB_BootBlockStruct_t ldlb[2];
|
||||
loff_t ldlb_ofs[2];
|
||||
|
||||
/* DBBTs */
|
||||
NCB_BootBlockStruct_t *curr_dbbt;
|
||||
NCB_BootBlockStruct_t dbbt[2];
|
||||
loff_t dbbt_ofs[2];
|
||||
/* the 2 NANDs */
|
||||
BadBlockTableNand_t *bbtn[2];
|
||||
|
||||
/* In fact, we can reuse the boot block
|
||||
* struct for mx53 on mx28, it's compatible
|
||||
*/
|
||||
|
||||
/* FCB */
|
||||
BCB_ROM_BootBlockStruct_t fcb;
|
||||
|
||||
/* DBBT */
|
||||
BCB_ROM_BootBlockStruct_t dbbt28;
|
||||
};
|
||||
|
||||
#define PAGES_PER_STRIDE 64
|
||||
|
||||
/* Functions */
|
||||
int ncb_get_version(void *ncb_candidate, NCB_BootBlockStruct_t **result);
|
||||
int fcb_encrypt(BCB_ROM_BootBlockStruct_t *fcb, void *target, size_t size, int version);
|
||||
int write_bootstream(struct part_info *part,
|
||||
unsigned long bs_start_address,
|
||||
int bs_size);
|
||||
#endif /* __DIGI_CMD_BOOTSTREAM_H */
|
||||
227
board/i2som/common/cmd_bootstream/mxsboot.c
Normal file
227
board/i2som/common/cmd_bootstream/mxsboot.c
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Freescale i.MX28 image generator
|
||||
*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
/*
|
||||
* Default BCB layout.
|
||||
*
|
||||
* TWEAK this if you have blown any OCOTP fuses.
|
||||
*/
|
||||
#define STRIDE_PAGES 64
|
||||
#define STRIDE_COUNT 4
|
||||
|
||||
/*
|
||||
* Layout for 256Mb big NAND with 2048b page size, 64b OOB size and
|
||||
* 128kb erase size.
|
||||
*
|
||||
* TWEAK this if you have different kind of NAND chip.
|
||||
*/
|
||||
uint32_t nand_writesize = 2048;
|
||||
uint32_t nand_oobsize = 64;
|
||||
uint32_t nand_erasesize = 128 * 1024;
|
||||
|
||||
/*
|
||||
* Sector on which the SigmaTel boot partition (0x53) starts.
|
||||
*/
|
||||
uint32_t sd_sector = 2048;
|
||||
|
||||
/*
|
||||
* Each of the U-Boot bootstreams is at maximum 1MB big.
|
||||
*
|
||||
* TWEAK this if, for some wild reason, you need to boot bigger image.
|
||||
*/
|
||||
#define MAX_BOOTSTREAM_SIZE (1 * 1024 * 1024)
|
||||
|
||||
/* i.MX28 NAND controller-specific constants. DO NOT TWEAK! */
|
||||
#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4
|
||||
#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE 512
|
||||
#define MXS_NAND_METADATA_SIZE 10
|
||||
#define MXS_NAND_COMMAND_BUFFER_SIZE 32
|
||||
|
||||
struct mx28_nand_fcb {
|
||||
uint32_t checksum;
|
||||
uint32_t fingerprint;
|
||||
uint32_t version;
|
||||
struct {
|
||||
uint8_t data_setup;
|
||||
uint8_t data_hold;
|
||||
uint8_t address_setup;
|
||||
uint8_t dsample_time;
|
||||
uint8_t nand_timing_state;
|
||||
uint8_t rea;
|
||||
uint8_t rloh;
|
||||
uint8_t rhoh;
|
||||
} timing;
|
||||
uint32_t page_data_size;
|
||||
uint32_t total_page_size;
|
||||
uint32_t sectors_per_block;
|
||||
uint32_t number_of_nands; /* Ignored */
|
||||
uint32_t total_internal_die; /* Ignored */
|
||||
uint32_t cell_type; /* Ignored */
|
||||
uint32_t ecc_block_n_ecc_type;
|
||||
uint32_t ecc_block_0_size;
|
||||
uint32_t ecc_block_n_size;
|
||||
uint32_t ecc_block_0_ecc_type;
|
||||
uint32_t metadata_bytes;
|
||||
uint32_t num_ecc_blocks_per_page;
|
||||
uint32_t ecc_block_n_ecc_level_sdk; /* Ignored */
|
||||
uint32_t ecc_block_0_size_sdk; /* Ignored */
|
||||
uint32_t ecc_block_n_size_sdk; /* Ignored */
|
||||
uint32_t ecc_block_0_ecc_level_sdk; /* Ignored */
|
||||
uint32_t num_ecc_blocks_per_page_sdk; /* Ignored */
|
||||
uint32_t metadata_bytes_sdk; /* Ignored */
|
||||
uint32_t erase_threshold;
|
||||
uint32_t boot_patch;
|
||||
uint32_t patch_sectors;
|
||||
uint32_t firmware1_starting_sector;
|
||||
uint32_t firmware2_starting_sector;
|
||||
uint32_t sectors_in_firmware1;
|
||||
uint32_t sectors_in_firmware2;
|
||||
uint32_t dbbt_search_area_start_address;
|
||||
uint32_t badblock_marker_byte;
|
||||
uint32_t badblock_marker_start_bit;
|
||||
uint32_t bb_marker_physical_offset;
|
||||
};
|
||||
|
||||
struct mx28_nand_dbbt {
|
||||
uint32_t checksum;
|
||||
uint32_t fingerprint;
|
||||
uint32_t version;
|
||||
uint32_t number_bb;
|
||||
uint32_t number_2k_pages_bb;
|
||||
};
|
||||
|
||||
struct mx28_nand_bbt {
|
||||
uint32_t nand;
|
||||
uint32_t number_bb;
|
||||
uint32_t badblock[510];
|
||||
};
|
||||
|
||||
struct mx28_sd_drive_info {
|
||||
uint32_t chip_num;
|
||||
uint32_t drive_type;
|
||||
uint32_t tag;
|
||||
uint32_t first_sector_number;
|
||||
uint32_t sector_count;
|
||||
};
|
||||
|
||||
struct mx28_sd_config_block {
|
||||
uint32_t signature;
|
||||
uint32_t primary_boot_tag;
|
||||
uint32_t secondary_boot_tag;
|
||||
uint32_t num_copies;
|
||||
struct mx28_sd_drive_info drv_info[1];
|
||||
};
|
||||
|
||||
static inline uint32_t mx28_nand_ecc_size_in_bits(uint32_t ecc_strength)
|
||||
{
|
||||
return ecc_strength * 13;
|
||||
}
|
||||
|
||||
static inline uint32_t mx28_nand_get_ecc_strength(uint32_t page_data_size,
|
||||
uint32_t page_oob_size)
|
||||
{
|
||||
if (page_data_size == 2048) {
|
||||
#if defined(CONFIG_MX28)
|
||||
return 8;
|
||||
#elif defined(CONFIG_MX6UL)
|
||||
return 4;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (page_data_size == 4096) {
|
||||
if (page_oob_size == 128)
|
||||
return 8;
|
||||
|
||||
if (page_oob_size == 218)
|
||||
return 16;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t mx28_nand_get_mark_offset(uint32_t page_data_size,
|
||||
uint32_t ecc_strength)
|
||||
{
|
||||
uint32_t chunk_data_size_in_bits;
|
||||
uint32_t chunk_ecc_size_in_bits;
|
||||
uint32_t chunk_total_size_in_bits;
|
||||
uint32_t block_mark_chunk_number;
|
||||
uint32_t block_mark_chunk_bit_offset;
|
||||
uint32_t block_mark_bit_offset;
|
||||
|
||||
chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8;
|
||||
chunk_ecc_size_in_bits = mx28_nand_ecc_size_in_bits(ecc_strength);
|
||||
|
||||
chunk_total_size_in_bits =
|
||||
chunk_data_size_in_bits + chunk_ecc_size_in_bits;
|
||||
|
||||
/* Compute the bit offset of the block mark within the physical page. */
|
||||
block_mark_bit_offset = page_data_size * 8;
|
||||
|
||||
/* Subtract the metadata bits. */
|
||||
block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8;
|
||||
|
||||
/*
|
||||
* Compute the chunk number (starting at zero) in which the block mark
|
||||
* appears.
|
||||
*/
|
||||
block_mark_chunk_number =
|
||||
block_mark_bit_offset / chunk_total_size_in_bits;
|
||||
|
||||
/*
|
||||
* Compute the bit offset of the block mark within its chunk, and
|
||||
* validate it.
|
||||
*/
|
||||
block_mark_chunk_bit_offset = block_mark_bit_offset -
|
||||
(block_mark_chunk_number * chunk_total_size_in_bits);
|
||||
|
||||
if (block_mark_chunk_bit_offset > chunk_data_size_in_bits)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Now that we know the chunk number in which the block mark appears,
|
||||
* we can subtract all the ECC bits that appear before it.
|
||||
*/
|
||||
block_mark_bit_offset -=
|
||||
block_mark_chunk_number * chunk_ecc_size_in_bits;
|
||||
|
||||
return block_mark_bit_offset;
|
||||
}
|
||||
|
||||
uint32_t mx28_nand_mark_byte_offset(void)
|
||||
{
|
||||
uint32_t ecc_strength;
|
||||
ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
|
||||
return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) >> 3;
|
||||
}
|
||||
|
||||
uint32_t mx28_nand_mark_bit_offset(void)
|
||||
{
|
||||
uint32_t ecc_strength;
|
||||
ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
|
||||
return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) & 0x7;
|
||||
}
|
||||
497
board/i2som/common/cmd_bootstream/ncb.c
Normal file
497
board/i2som/common/cmd_bootstream/ncb.c
Normal file
@ -0,0 +1,497 @@
|
||||
/*
|
||||
* ncb.c - verify and encode NCB
|
||||
*
|
||||
* Copyright (c) 2008 by Embedded Alley Solution Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
#include "cmd_bootstream.h"
|
||||
//#include "config.h"
|
||||
#include "rom_nand_hamming_code_ecc.h"
|
||||
#include "BootControlBlocks.h"
|
||||
#include "bch.h"
|
||||
|
||||
static inline int even_number_of_1s(uint8_t byte)
|
||||
{
|
||||
int even = 1;
|
||||
|
||||
while (byte > 0) {
|
||||
even ^= (byte & 0x1);
|
||||
byte >>= 1;
|
||||
}
|
||||
return even;
|
||||
}
|
||||
|
||||
|
||||
#define BIT(v,n) (((v) >> (n)) & 0x1)
|
||||
#define B(n) (BIT(d,n))
|
||||
#define BSEQ(a1,a2,a3,a4,a5,a6,a7,a8) \
|
||||
(B(a1) ^ B(a2) ^ B(a3) ^ B(a4) ^ B(a5) ^ B(a6) ^ B(a7) ^ B(a8))
|
||||
|
||||
static uint8_t calculate_parity_22_16(uint16_t d)
|
||||
{
|
||||
uint8_t p = 0;
|
||||
|
||||
if (d == 0 || d == 0xFFFF)
|
||||
return 0; /* optimization :) */
|
||||
|
||||
p |= BSEQ(15, 12, 11, 8, 5, 4, 3, 2) << 0;
|
||||
p |= BSEQ(13, 12, 11, 10, 9, 7, 3, 1) << 1;
|
||||
p |= BSEQ(15, 14, 13, 11, 10, 9, 6, 5) << 2;
|
||||
p |= BSEQ(15, 14, 13, 8, 7, 6, 4, 0) << 3;
|
||||
p |= BSEQ(12, 9, 8, 7, 6, 2, 1, 0) << 4;
|
||||
p |= BSEQ(14, 10, 5, 4, 3, 2, 1, 0) << 5;
|
||||
return p;
|
||||
}
|
||||
|
||||
static uint8_t calculate_parity_13_8(uint8_t d)
|
||||
{
|
||||
uint8_t p = 0;
|
||||
|
||||
p |= (B(6) ^ B(5) ^ B(3) ^ B(2)) << 0;
|
||||
p |= (B(7) ^ B(5) ^ B(4) ^ B(2) ^ B(1)) << 1;
|
||||
p |= (B(7) ^ B(6) ^ B(5) ^ B(1) ^ B(0)) << 2;
|
||||
p |= (B(7) ^ B(4) ^ B(3) ^ B(0)) << 3;
|
||||
p |= (B(6) ^ B(4) ^ B(3) ^ B(2) ^ B(1) ^ B(0)) << 4;
|
||||
return p;
|
||||
}
|
||||
#undef BIT
|
||||
#undef B
|
||||
#undef BSEQ
|
||||
|
||||
static int encode_hamming_code_22_16(void *source_block, size_t source_size,
|
||||
void *target_block, size_t target_size)
|
||||
{
|
||||
int i, j, bit_index;
|
||||
uint16_t *src;
|
||||
uint8_t *dst;
|
||||
uint8_t np;
|
||||
uint8_t ecc[NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES];
|
||||
uint8_t data[NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES];
|
||||
|
||||
memset(data, 0, ARRAY_SIZE(data));
|
||||
memcpy(data, source_block, source_size);
|
||||
|
||||
src = (uint16_t *) data;
|
||||
dst = (uint8_t *) target_block;
|
||||
|
||||
/* create THREE copies of source block */
|
||||
for (i = 0; i < NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES; i++) {
|
||||
dst[i + NAND_HC_ECC_OFFSET_FIRST_DATA_COPY] =
|
||||
dst[i + NAND_HC_ECC_OFFSET_SECOND_DATA_COPY] =
|
||||
dst[i + NAND_HC_ECC_OFFSET_THIRD_DATA_COPY] =
|
||||
((uint8_t *) src)[i];
|
||||
}
|
||||
|
||||
/* finally, point to the end of populated data */
|
||||
for (bit_index = j = i = 0;
|
||||
j < NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES / sizeof(uint16_t);
|
||||
j++) {
|
||||
np = calculate_parity_22_16(src[j]);
|
||||
|
||||
switch (bit_index) {
|
||||
|
||||
case 0:
|
||||
ecc[i] = np & 0x3F;
|
||||
break;
|
||||
case 2:
|
||||
ecc[i++] |= (np & 0x03) << 6;
|
||||
ecc[i] = (np & 0x3C) >> 2;
|
||||
break;
|
||||
case 4:
|
||||
ecc[i++] |= (np & 0x0F) << 4;
|
||||
ecc[i] = (np & 0x30) >> 4;
|
||||
break;
|
||||
case 6:
|
||||
ecc[i++] |= (np & 0x3F) << 2;
|
||||
break;
|
||||
}
|
||||
bit_index = (bit_index + 2) % 8;
|
||||
}
|
||||
|
||||
for (i = 0; i < NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES; i++) {
|
||||
dst[i + NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY] =
|
||||
dst[i + NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY] =
|
||||
dst[i + NAND_HC_ECC_OFFSET_THIRD_PARITY_COPY] = ecc[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int encode_hamming_code_13_8(void *source_block, size_t source_size,
|
||||
void *target_block, size_t target_size)
|
||||
{
|
||||
uint8_t ecc[NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES];
|
||||
uint8_t data[NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES];
|
||||
int i;
|
||||
|
||||
memset(ecc, 0, ARRAY_SIZE(ecc));
|
||||
memset(data, 0, ARRAY_SIZE(data));
|
||||
memcpy(data, source_block, source_size);
|
||||
|
||||
for (i = 0; i < source_size; i ++)
|
||||
ecc[i] = calculate_parity_13_8(data[i]);
|
||||
|
||||
memcpy((uint8_t*)target_block + BCB_MAGIC_OFFSET, data, NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES);
|
||||
memcpy((uint8_t*)target_block + BCB_MAGIC_OFFSET + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES,
|
||||
ecc, NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ncb_single_pair_check(uint8_t *n1, uint8_t *p1, uint8_t *n2, uint8_t *p2)
|
||||
{
|
||||
return (memcmp(n1, n2, NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES) == 0 &&
|
||||
memcmp(p1, p2, NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES) == 0);
|
||||
}
|
||||
|
||||
static int ncb_triple_check(void *page)
|
||||
{
|
||||
uint8_t *n1 = (uint8_t*)page + NAND_HC_ECC_OFFSET_FIRST_DATA_COPY,
|
||||
*n2 = (uint8_t*)page + NAND_HC_ECC_OFFSET_SECOND_DATA_COPY,
|
||||
*n3 = (uint8_t*)page + NAND_HC_ECC_OFFSET_THIRD_DATA_COPY,
|
||||
*p1 = (uint8_t*)page + NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY,
|
||||
*p2 = (uint8_t*)page + NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY,
|
||||
*p3 = (uint8_t*)page + NAND_HC_ECC_OFFSET_THIRD_PARITY_COPY;
|
||||
|
||||
if (ncb_single_pair_check(n1, p1, n2, p2))
|
||||
return 1;
|
||||
if (ncb_single_pair_check(n2, p2, n3, p3))
|
||||
return 2;
|
||||
if (ncb_single_pair_check(n1, p1, n3, p3))
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int lookup_single_error_22_16(uint8_t syndrome)
|
||||
{
|
||||
int i;
|
||||
uint8_t syndrome_table[] = {
|
||||
0x38, 0x32, 0x31, 0x23, 0x29, 0x25, 0x1C, 0x1A,
|
||||
0x19, 0x16, 0x26, 0x07, 0x13, 0x0E, 0x2C, 0x0D,
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(syndrome_table); i ++)
|
||||
if (syndrome_table[i] == syndrome)
|
||||
return i;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int lookup_single_error_13_8(uint8_t syndrome)
|
||||
{
|
||||
int i;
|
||||
uint8_t syndrome_table[] = {
|
||||
0x1C, 0x16, 0x13, 0x19,
|
||||
0x1A, 0x07, 0x15, 0x0E,
|
||||
0x01, 0x02, 0x04, 0x08,
|
||||
0x10,
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(syndrome_table); i ++)
|
||||
if (syndrome_table[i] == syndrome)
|
||||
return i;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static inline NCB_BootBlockStruct_t *ncb_verify_hamming_22_16(void *page)
|
||||
{
|
||||
int r;
|
||||
uint16_t* n1 = (uint16_t*)((uint8_t*)page + NAND_HC_ECC_OFFSET_FIRST_DATA_COPY),
|
||||
*n2 = ((uint16_t*)(uint8_t*)page + NAND_HC_ECC_OFFSET_SECOND_DATA_COPY),
|
||||
*n, *data;
|
||||
uint8_t *p1 = (uint8_t*)page + NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY,
|
||||
*p2 = (uint8_t*)page + NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY,
|
||||
*parity, p, np, syndrome;
|
||||
int bit_index, i, j, bit_to_flip;
|
||||
|
||||
r = ncb_triple_check(page);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
if (r == 1) {
|
||||
data = n = n1;
|
||||
parity = p1;
|
||||
}
|
||||
else if (r == 2) {
|
||||
data = n = n2;
|
||||
parity = p2;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "internal error: %s, r = %d\n", __func__, r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (bit_index = i = j = 0, r = 0;
|
||||
i < NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES / sizeof(uint16_t) && r == 0;
|
||||
i ++, data++) {
|
||||
|
||||
switch (bit_index) {
|
||||
|
||||
case 0:
|
||||
p = parity[j] & 0x3F;
|
||||
break;
|
||||
case 2:
|
||||
p = (parity[j++] & 0xC0) >> 6;
|
||||
p |= (parity[j] & 0x0F) << 2;
|
||||
break;
|
||||
case 4:
|
||||
p = (parity[j++] & 0xF0) >> 4;
|
||||
p |= (parity[j] & 0x03) << 4;
|
||||
break;
|
||||
case 6:
|
||||
p = (parity[j++] & 0xFC) >> 2;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "internal error at %s:%d\n", __func__, __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
bit_index = (bit_index + 2) % 8;
|
||||
|
||||
np = calculate_parity_22_16(*data);
|
||||
syndrome = np ^ p;
|
||||
if (syndrome == 0) /* cool */ {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (even_number_of_1s(syndrome)) {
|
||||
r = i;
|
||||
break;
|
||||
}
|
||||
|
||||
bit_to_flip = lookup_single_error_22_16(syndrome);
|
||||
if (bit_to_flip < 0) {
|
||||
r = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bit_to_flip < 16)
|
||||
*data ^= (1 << bit_to_flip);
|
||||
}
|
||||
return r == 0 ? (NCB_BootBlockStruct_t*)n : NULL;
|
||||
}
|
||||
|
||||
static inline NCB_BootBlockStruct_t *ncb_verify_hamming_13_8(void *ncb_page)
|
||||
{
|
||||
int i, bit_to_flip;
|
||||
uint8_t *data, *parity, np, syndrome;
|
||||
|
||||
data = (uint8_t*)ncb_page + 12;
|
||||
parity = (uint8_t*)ncb_page + 12 + NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES;
|
||||
|
||||
for (i = 0; i < NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES; i ++, data++) {
|
||||
np = calculate_parity_13_8(*data);
|
||||
syndrome = np ^ parity[i];
|
||||
if (syndrome == 0)
|
||||
continue;
|
||||
|
||||
if (even_number_of_1s(syndrome))
|
||||
return NULL;
|
||||
|
||||
bit_to_flip = lookup_single_error_13_8(syndrome);
|
||||
if (bit_to_flip < 0)
|
||||
return NULL;
|
||||
|
||||
if (bit_to_flip < 8)
|
||||
*data ^= (1 << bit_to_flip);
|
||||
}
|
||||
return (NCB_BootBlockStruct_t*)(ncb_page + 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* ncb_encrypt - Encrypt the NCB block, assuming that target system uses NCB
|
||||
* version 'version'
|
||||
*
|
||||
* ncb: Points to valid NCB_BootBlockStruct_t structure
|
||||
* target: Points to a buffer large enough to contain an entire NAND Flash page
|
||||
* (both data and OOB).
|
||||
* size: The size of an entire NAND Flash page (both data and OOB).
|
||||
* version: The version number of the NCB.
|
||||
*/
|
||||
int ncb_encrypt(NCB_BootBlockStruct_t *ncb, void *target, size_t size, int version)
|
||||
{
|
||||
assert(version == 0 || version == 1 || version == 3);
|
||||
assert(size >= sizeof(NCB_BootBlockStruct_t));
|
||||
|
||||
memset(target, 0, size);
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
memcpy(target, ncb, sizeof(*ncb));
|
||||
return size;
|
||||
case 1:
|
||||
return encode_hamming_code_22_16(ncb, sizeof(*ncb), target, size);
|
||||
case 3:
|
||||
return encode_hamming_code_13_8(ncb, sizeof(*ncb), target, size);
|
||||
default:
|
||||
fprintf(stderr, "NCB version == %d? Something is wrong!\n", version);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fcb_encrypt - Encrypt the FCB block, assuming that target system uses NCB
|
||||
* version 'version'
|
||||
*
|
||||
* fcb: Points to valid imx28_BootBlockStruct_t structure.
|
||||
* target: Points to a buffer large enough to contain an entire NAND Flash page
|
||||
* (both data and OOB).
|
||||
* size: The size of an entire NAND Flash page (both data and OOB).
|
||||
* version: The version number of the NCB.
|
||||
*
|
||||
*/
|
||||
int fcb_encrypt(BCB_ROM_BootBlockStruct_t *fcb, void *target, size_t size, int version)
|
||||
{
|
||||
uint32_t accumulator;
|
||||
uint8_t *p;
|
||||
uint8_t *q;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Check for nonsense.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
assert(version == 1);
|
||||
assert(size >= sizeof(BCB_ROM_BootBlockStruct_t));
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Clear out the target.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
memset(target, 0, size);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Compute the checksum.
|
||||
//
|
||||
// Note that we're computing the checksum only over the FCB itself,
|
||||
// whereas it's actually supposed to reflect the entire 508 bytes
|
||||
// in the FCB page between the base of the of FCB and the base of the
|
||||
// ECC bytes. However, the entire space between the top of the FCB and
|
||||
// the base of the ECC bytes will be all zeros, so this is OK.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
p = ((uint8_t *) fcb) + 4;
|
||||
q = (uint8_t *) (fcb + 1);
|
||||
|
||||
accumulator = 0;
|
||||
|
||||
for (; p < q; p++) {
|
||||
accumulator += *p;
|
||||
}
|
||||
|
||||
accumulator ^= 0xffffffff;
|
||||
|
||||
fcb->m_u32Checksum = accumulator;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Compute the ECC bytes.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
memcpy(target, fcb, sizeof(*fcb));
|
||||
return size;
|
||||
case 1:
|
||||
return encode_hamming_code_13_8(fcb, sizeof(*fcb), target, size);
|
||||
case 2:
|
||||
return encode_bch_ecc(fcb, sizeof(*fcb), target, size, version);
|
||||
case 3:
|
||||
return encode_bch_ecc(fcb, sizeof(*fcb), target, size, version);
|
||||
default:
|
||||
fprintf(stderr, "FCB version == %d? Something is wrong!\n", version);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ncb_get_version - parse the boot block ncb_candidate and on success store
|
||||
* the pointer to NCB to result
|
||||
*
|
||||
* returns version of found NCB, or -1 otherwise - try further scanning..
|
||||
*/
|
||||
int ncb_get_version(void *ncb_candidate, NCB_BootBlockStruct_t **result)
|
||||
{
|
||||
NCB_BootBlockStruct_t *bbs, *p1, *p2, *p3;
|
||||
|
||||
assert(result != NULL);
|
||||
|
||||
printf("%s(*result=%p)\n", __FUNCTION__, *result);
|
||||
*result = NULL;
|
||||
|
||||
/* first of all, check version 3 of ncb */
|
||||
bbs = (NCB_BootBlockStruct_t*)((uint8_t*)ncb_candidate + 12);
|
||||
if (bbs->m_u32FingerPrint1 == NCB_FINGERPRINT1 &&
|
||||
bbs->m_u32FingerPrint2 == NCB_FINGERPRINT2 &&
|
||||
bbs->m_u32FingerPrint3 == NCB_FINGERPRINT3) {
|
||||
/* fingerprints match, so it is either v3 or corrupted NCB */
|
||||
*result = ncb_verify_hamming_13_8(ncb_candidate);
|
||||
printf("%d: *result=%p\n", __LINE__, *result);
|
||||
if (*result)
|
||||
return 3;
|
||||
fprintf(stderr, "ncb_verify_hamming_13_8 failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* then, check if it is version 1 (yes, there was not NCBv2
|
||||
*
|
||||
* To match the v1, there should be at least two identical copies
|
||||
* of NCB
|
||||
*/
|
||||
|
||||
p1 = (NCB_BootBlockStruct_t*)ncb_candidate /* + NAND_HC_OFFSET_FIRST_DATA_COPY */;
|
||||
p2 = (NCB_BootBlockStruct_t*)((uint8_t*)ncb_candidate + NAND_HC_ECC_OFFSET_SECOND_DATA_COPY);
|
||||
p3 = (NCB_BootBlockStruct_t*)((uint8_t*)ncb_candidate + NAND_HC_ECC_OFFSET_THIRD_DATA_COPY);
|
||||
|
||||
if (memcmp(p1, p2, sizeof(NCB_BootBlockStruct_t)) == 0 ||
|
||||
memcmp(p1, p3, sizeof(NCB_BootBlockStruct_t)) == 0 ||
|
||||
memcmp(p2, p3, sizeof(NCB_BootBlockStruct_t)) == 0) {
|
||||
/*
|
||||
* we found at least two identical copies of NCB; verify
|
||||
* against the ECC
|
||||
*/
|
||||
*result = ncb_verify_hamming_22_16(ncb_candidate);
|
||||
printf("%d: *result=%p\n", __LINE__, *result);
|
||||
if (*result)
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* and finally, does it look like NCBv0 ?
|
||||
*/
|
||||
if (p1->m_u32FingerPrint1 == NCB_FINGERPRINT1 &&
|
||||
p1->m_u32FingerPrint2 == NCB_FINGERPRINT2 &&
|
||||
p1->m_u32FingerPrint3 == NCB_FINGERPRINT3) {
|
||||
*result = p1;
|
||||
printf("%d: *result=%p\n", __LINE__, *result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* we did try.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! \addtogroup rom_nand_boot
|
||||
//! @{
|
||||
//
|
||||
// Copyright (c) 2006 SigmaTel, Inc.
|
||||
//
|
||||
//! \file rom_nand_hamming_code_ecc.h
|
||||
//! \brief This file provides header info for hamming code ecc.
|
||||
//!
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _ROM_NAND_HAMMING_CODE_ECC_H
|
||||
#define _ROM_NAND_HAMMING_CODE_ECC_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//!< Bytes per NCB data block
|
||||
#define NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES (512)
|
||||
//! Size of a parity block in bytes for all 16-bit data blocks present inside one 512 byte NCB block.
|
||||
#define NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES ((((512*8)/16)*6)/8)
|
||||
//! Offset to first copy of NCB in a NAND page
|
||||
#define NAND_HC_ECC_OFFSET_FIRST_DATA_COPY (0)
|
||||
//! Offset to second copy of NCB in a NAND page
|
||||
#define NAND_HC_ECC_OFFSET_SECOND_DATA_COPY (NAND_HC_ECC_OFFSET_FIRST_DATA_COPY+NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
|
||||
//! Offset to third copy of NCB in a NAND page
|
||||
#define NAND_HC_ECC_OFFSET_THIRD_DATA_COPY (NAND_HC_ECC_OFFSET_SECOND_DATA_COPY+NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
|
||||
//! Offset to first copy of Parity block in a NAND page
|
||||
#define NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY (NAND_HC_ECC_OFFSET_THIRD_DATA_COPY+NAND_HC_ECC_SIZEOF_DATA_BLOCK_IN_BYTES)
|
||||
//! Offset to second copy of Parity block in a NAND page
|
||||
#define NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY (NAND_HC_ECC_OFFSET_FIRST_PARITY_COPY+NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES)
|
||||
//! Offset to third copy of Parity block in a NAND page
|
||||
#define NAND_HC_ECC_OFFSET_THIRD_PARITY_COPY (NAND_HC_ECC_OFFSET_SECOND_PARITY_COPY+NAND_HC_ECC_SIZEOF_PARITY_BLOCK_IN_BYTES)
|
||||
|
||||
#define BITMASK_HAMMINGCHECKED_ALL_THREE_COPIES 0x7 //!< to indicate all three copies of NCB in first page are processed with Hamming codes.
|
||||
#define BITMASK_HAMMINGCHECKED_FIRST_COPY 0x1 //!< to indicate first copy of NCB is processed with Hamming codes.
|
||||
#define BITMASK_HAMMINGCHECKED_SECOND_COPY 0x2 //!< to indicate second copy of NCB is processed with Hamming codes.
|
||||
#define BITMASK_HAMMINGCHECKED_THIRD_COPY 0x4 //!< to indicate third copy of NCB is processed with Hamming codes.
|
||||
int TripleRedundancyCheck(uint8_t * pNCBCopy1, uint8_t * pNCBCopy2,
|
||||
uint8_t * pNCBCopy3, uint8_t * pP1, uint8_t * pP2,
|
||||
uint8_t * pP3, uint8_t * pu8HammingCopy);
|
||||
int IsNumOf1sEven(uint8_t u8);
|
||||
void CalculateParity(uint16_t d, uint8_t * p);
|
||||
int TableLookupSingleErrors(uint8_t u8Synd, uint8_t * pu8BitToFlip);
|
||||
int HammingCheck(uint8_t * pNCB, uint8_t * pParityBlock);
|
||||
|
||||
#endif /* */
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// End of file
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// @}
|
||||
368
board/i2som/common/cmd_update_nand.c
Normal file
368
board/i2som/common/cmd_update_nand.c
Normal file
@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright (C) 2017 i2SOM Team.
|
||||
* Copyright (C) 2016 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
#include <asm/imx-common/boot_mode.h>
|
||||
#include <common.h>
|
||||
#include <jffs2/load_kernel.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <nand.h>
|
||||
#include <otf_update.h>
|
||||
#include <ubi_uboot.h>
|
||||
|
||||
#include "helper.h"
|
||||
#ifdef CONFIG_CMD_BOOTSTREAM
|
||||
#include "cmd_bootstream/cmd_bootstream.h"
|
||||
#endif
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
enum {
|
||||
ERR_WRITE = 1,
|
||||
ERR_READ,
|
||||
ERR_VERIFY,
|
||||
};
|
||||
|
||||
static int write_firmware(unsigned long loadaddr, unsigned long filesize,
|
||||
struct part_info *part, char *ubivolname)
|
||||
{
|
||||
char cmd[CONFIG_SYS_CBSIZE] = "";
|
||||
unsigned long verifyaddr, u, m;
|
||||
|
||||
if (filesize > part->size) {
|
||||
printf("File size (%lu bytes) exceeds partition size (%lu bytes)!\n",
|
||||
filesize, (unsigned long)part->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ubivolname) {
|
||||
/* A UBI volume exists in the partition, use 'ubi write' */
|
||||
sprintf(cmd, "ubi write %lx %s %lx", loadaddr, ubivolname,
|
||||
filesize);
|
||||
} else {
|
||||
/* raw-write firmware command (erase first) */
|
||||
sprintf(cmd, "if nand erase.part %s; then "
|
||||
"nand write %lx %s %lx;fi", part->name,
|
||||
loadaddr, part->name, filesize);
|
||||
}
|
||||
if (run_command(cmd, 0))
|
||||
return ERR_WRITE;
|
||||
|
||||
#ifdef CONFIG_I2SOM_UBI
|
||||
/* If it is a UBIFS file system, verify it using a special function */
|
||||
if (ubivolname) {
|
||||
printf("Verifying firmware...\n");
|
||||
if (ubi_volume_verify(part->name, (char *)loadaddr, 0,
|
||||
filesize, 0))
|
||||
return ERR_VERIFY;
|
||||
printf("Update was successful\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If there is enough RAM to hold two copies of the firmware,
|
||||
* verify written firmware.
|
||||
* +--------|---------------------|------------------|--------------+
|
||||
* | L V | U-Boot+Stack |
|
||||
* +--------|---------------------|------------------|--------------+
|
||||
* P U M
|
||||
*
|
||||
* P = PHYS_SDRAM (base address of SDRAM)
|
||||
* L = $loadaddr
|
||||
* V = $verifyaddr
|
||||
* M = last address of SDRAM (CONFIG_DDR_MB (size of SDRAM) + P)
|
||||
* U = SDRAM address where U-Boot is located (plus margin)
|
||||
*/
|
||||
verifyaddr = getenv_ulong("verifyaddr", 16, 0);
|
||||
m = PHYS_SDRAM + gd->ram_size;
|
||||
u = m - CONFIG_UBOOT_RESERVED;
|
||||
|
||||
/*
|
||||
* ($loadaddr + firmware size) must not exceed $verifyaddr
|
||||
* ($verifyaddr + firmware size) must not exceed U.
|
||||
*/
|
||||
if ((loadaddr + filesize) < verifyaddr &&
|
||||
(verifyaddr + filesize) < u) {
|
||||
unsigned long filesize_padded;
|
||||
int i;
|
||||
|
||||
/* Read back data... */
|
||||
printf("Reading back firmware...\n");
|
||||
sprintf(cmd, "nand read %lx %s %lx", verifyaddr, part->name,
|
||||
filesize);
|
||||
if (run_command(cmd, 0))
|
||||
return ERR_READ;
|
||||
/*
|
||||
* ...then compare by 32-bit words (faster than by bytes)
|
||||
* padding with zeros any bytes at the end to make the size
|
||||
* be a multiple of 4.
|
||||
*
|
||||
* Reference: http://stackoverflow.com/a/2022252
|
||||
*/
|
||||
printf("Verifying firmware...\n");
|
||||
filesize_padded = (filesize + (4 - 1)) & ~(4 - 1);
|
||||
|
||||
for (i = filesize; i < filesize_padded; i++) {
|
||||
*((char *)loadaddr + i) = 0;
|
||||
*((char *)verifyaddr + i) = 0;
|
||||
}
|
||||
sprintf(cmd, "cmp.l %lx %lx %lx", loadaddr, verifyaddr,
|
||||
(filesize_padded / 4));
|
||||
if (run_command(cmd, 0))
|
||||
return ERR_VERIFY;
|
||||
printf("Update was successful\n");
|
||||
} else {
|
||||
printf("Firmware updated but not verified "
|
||||
"(not enough available RAM to verify)\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attaches an MTD partition to UBI and gets its volume name.
|
||||
* If a volume does not exist, it creates one with the same name of the
|
||||
* partition.
|
||||
*/
|
||||
static int ubi_attach_getcreatevol(char *partname, const char **volname)
|
||||
{
|
||||
char cmd[CONFIG_SYS_CBSIZE] = "";
|
||||
int ret = -1;
|
||||
|
||||
*volname = NULL;
|
||||
|
||||
/* Attach partition and get volume name */
|
||||
if (!ubi_part(partname, NULL)) {
|
||||
*volname = ubi_get_volume_name(0);
|
||||
if (!*volname) {
|
||||
/* Create UBI volume with the name of the partition */
|
||||
sprintf(cmd, "ubi createvol %s", partname);
|
||||
if (run_command(cmd, 0))
|
||||
return -1;
|
||||
|
||||
*volname = partname;
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_update(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
int ret;
|
||||
int otf = 0;
|
||||
unsigned long loadaddr;
|
||||
unsigned long verifyaddr;
|
||||
unsigned long filesize = 0;
|
||||
struct mtd_device *dev;
|
||||
struct part_info *part;
|
||||
char *ubootpartname = CONFIG_UBOOT_PARTITION;
|
||||
char *partname;
|
||||
u8 pnum;
|
||||
int ubifs_ext = 0;
|
||||
const char *ubivolname = NULL;
|
||||
struct load_fw fwinfo;
|
||||
char cmd[CONFIG_SYS_CBSIZE] = "";
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
memset(&fwinfo, 0, sizeof(fwinfo));
|
||||
|
||||
/* Initialize partitions */
|
||||
if (mtdparts_init()) {
|
||||
printf("Cannot initialize MTD partitions\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get data of partition to be updated (might be a reserved name) */
|
||||
if (!strcmp(argv[1], "uboot"))
|
||||
partname = ubootpartname;
|
||||
else
|
||||
partname = argv[1];
|
||||
|
||||
if (find_dev_and_part(partname, &dev, &pnum, &part)) {
|
||||
printf("Cannot find '%s' partition\n", partname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dev->id->type != MTD_DEV_TYPE_NAND) {
|
||||
printf("not a NAND device\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Ask for confirmation if needed */
|
||||
if (getenv_yesno("forced_update") != 1) {
|
||||
/* Confirm programming */
|
||||
if (!strcmp(part->name, CONFIG_UBOOT_PARTITION) &&
|
||||
!confirm_msg("Do you really want to program "
|
||||
"the boot loader? <y/N> "))
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
/* Get source of update firmware file */
|
||||
if (get_source(argc, argv, &fwinfo))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
loadaddr = getenv_ulong("loadaddr", 16, CONFIG_LOADADDR);
|
||||
/*
|
||||
* If undefined, calculate 'verifyaddr' as halfway through the RAM
|
||||
* from $loadaddr.
|
||||
*/
|
||||
if (NULL == getenv("verifyaddr")) {
|
||||
verifyaddr = loadaddr +
|
||||
((gd->ram_size - (loadaddr - PHYS_SDRAM)) / 2);
|
||||
if (verifyaddr > loadaddr &&
|
||||
verifyaddr < (PHYS_SDRAM + gd->ram_size))
|
||||
setenv_hex("verifyaddr", verifyaddr);
|
||||
}
|
||||
|
||||
if (fwinfo.src == SRC_RAM) {
|
||||
/* Get address in RAM where firmware file is */
|
||||
if (argc > 3)
|
||||
loadaddr = simple_strtol(argv[3], NULL, 16);
|
||||
|
||||
/* Get filesize */
|
||||
if (argc > 4)
|
||||
filesize = simple_strtol(argv[4], NULL, 16);
|
||||
} else {
|
||||
/*
|
||||
* TODO: If otf-update is undefined, check if there is enough
|
||||
* RAM to hold the largest possible file that fits into
|
||||
* the destiny partition.
|
||||
*/
|
||||
|
||||
/* Get firmware file name */
|
||||
ret = get_fw_filename(argc, argv, &fwinfo);
|
||||
if (ret) {
|
||||
/* Filename was not provided. Look for default one */
|
||||
fwinfo.filename = get_default_filename(argv[1],
|
||||
CMD_UPDATE);
|
||||
if (!fwinfo.filename) {
|
||||
printf("Error: need a filename\n");
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the filename has extension UBIFS */
|
||||
if (!strcmp(get_filename_ext(fwinfo.filename), "ubifs"))
|
||||
ubifs_ext = 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_I2SOM_UBI
|
||||
/*
|
||||
* If the partition is not U-Boot (whose sectors must be raw-read),
|
||||
* check if the partition is UBI formatted.
|
||||
*/
|
||||
if (strcmp(part->name, CONFIG_UBOOT_PARTITION)) {
|
||||
bool erase_ubi = 0;
|
||||
|
||||
if (is_ubi_partition(part)) {
|
||||
/* Silent UBI commands during the update */
|
||||
run_command("ubi silent 1", 0);
|
||||
|
||||
/* Attach partition and get volume name */
|
||||
if (ubi_attach_getcreatevol(partname, &ubivolname)) {
|
||||
/* On error, erase partition and retry */
|
||||
erase_ubi = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the partition does not have a valid UBI volume
|
||||
* but we are updating a *.ubifs filename, erase the
|
||||
* partition and create the UBI volume.
|
||||
*/
|
||||
if ((ubifs_ext && ubivolname == NULL) || erase_ubi) {
|
||||
sprintf(cmd, "nand erase.part %s", partname);
|
||||
if (run_command(cmd, 0)) {
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto _ret;
|
||||
}
|
||||
|
||||
/* Attach partition and get volume name */
|
||||
if (ubi_attach_getcreatevol(partname, &ubivolname)) {
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto _ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_I2SOM_UBI */
|
||||
|
||||
/* TODO: Activate on-the-fly update if needed */
|
||||
|
||||
if (fwinfo.src != SRC_RAM) {
|
||||
/*
|
||||
* Load firmware file to RAM (this process may write the file
|
||||
* to the target media if OTF mechanism is enabled).
|
||||
*/
|
||||
fwinfo.loadaddr = "$loadaddr";
|
||||
ret = load_firmware(&fwinfo);
|
||||
if (ret == LDFW_ERROR) {
|
||||
printf("Error loading firmware file to RAM\n");
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto _ret;
|
||||
} else if (ret == LDFW_LOADED && otf) {
|
||||
ret = CMD_RET_SUCCESS;
|
||||
goto _ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Write firmware file from RAM to storage */
|
||||
if (!filesize)
|
||||
filesize = getenv_ulong("filesize", 16, 0);
|
||||
#ifdef CONFIG_CMD_BOOTSTREAM
|
||||
/* U-Boot is written in a special way */
|
||||
if (!strcmp(partname, CONFIG_UBOOT_PARTITION)) {
|
||||
ret = write_bootstream(part, loadaddr, filesize);
|
||||
goto _ret;
|
||||
}
|
||||
#endif
|
||||
ret = write_firmware(loadaddr, filesize, part, (char *)ubivolname);
|
||||
if (ret) {
|
||||
if (ret == ERR_READ)
|
||||
printf("Error while reading back written firmware!\n");
|
||||
else if (ret == ERR_VERIFY)
|
||||
printf("Error while verifying written firmware!\n");
|
||||
else
|
||||
printf("Error writing firmware!\n");
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto _ret;
|
||||
}
|
||||
|
||||
_ret:
|
||||
#ifdef CONFIG_I2SOM_UBI
|
||||
/* restore UBI commands verbosity */
|
||||
run_command("ubi silent 0", 0);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
update, 6, 0, do_update,
|
||||
"i2SOM modules update command",
|
||||
"<partition> [source] [extra-args...]\n"
|
||||
" Description: updates <partition> in NAND via <source>\n"
|
||||
" If the partition is UBI formatted, or a filename with\n"
|
||||
" extension *.ubifs is passed, writing a UBIFS is assumed\n"
|
||||
" Otherwise, this command raw-writes the file to the partition.\n"
|
||||
"\n"
|
||||
" Arguments:\n"
|
||||
" - partition: a partition index, a GUID partition name, or one\n"
|
||||
" of the reserved names: uboot\n"
|
||||
" - [source]: " CONFIG_UPDATE_SUPPORTED_SOURCES_LIST "\n"
|
||||
" - [extra-args]: extra arguments depending on 'source'\n"
|
||||
"\n"
|
||||
CONFIG_UPDATE_SUPPORTED_SOURCES_ARGS_HELP
|
||||
);
|
||||
715
board/i2som/common/helper.c
Normal file
715
board/i2som/common/helper.c
Normal file
@ -0,0 +1,715 @@
|
||||
/*
|
||||
* Copyright (C) 2017 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <asm/errno.h>
|
||||
#include <malloc.h>
|
||||
#include <nand.h>
|
||||
#include <version.h>
|
||||
#include <watchdog.h>
|
||||
#ifdef CONFIG_OF_LIBFDT
|
||||
#include <fdt_support.h>
|
||||
#endif
|
||||
#include <otf_update.h>
|
||||
#include "helper.h"
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
#if defined(CONFIG_CMD_UPDATE_MMC) || defined(CONFIG_CMD_UPDATE_NAND)
|
||||
#define CONFIG_CMD_UPDATE
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_UPDATE) || defined(CONFIG_CMD_DBOOT)
|
||||
enum {
|
||||
FWLOAD_NO,
|
||||
FWLOAD_YES,
|
||||
FWLOAD_TRY,
|
||||
};
|
||||
|
||||
static const char *src_strings[] = {
|
||||
[SRC_TFTP] = "tftp",
|
||||
[SRC_NFS] = "nfs",
|
||||
[SRC_NAND] = "nand",
|
||||
[SRC_USB] = "usb",
|
||||
[SRC_MMC] = "mmc",
|
||||
[SRC_RAM] = "ram",
|
||||
[SRC_SATA] = "sata",
|
||||
};
|
||||
|
||||
/* hook for on-the-fly update and register function */
|
||||
static int (*otf_update_hook)(otf_data_t *data) = NULL;
|
||||
/* Data struct for on-the-fly update */
|
||||
static otf_data_t otfd;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AUTO_BOOTSCRIPT
|
||||
#define AUTOSCRIPT_TFTP_MSEC 100
|
||||
#define AUTOSCRIPT_TFTP_CNT 15
|
||||
#define AUTOSCRIPT_START_AGAIN 100
|
||||
extern ulong TftpRRQTimeoutMSecs;
|
||||
extern int TftpRRQTimeoutCountMax;
|
||||
extern unsigned long NetStartAgainTimeout;
|
||||
int DownloadingAutoScript = 0;
|
||||
int RunningAutoScript = 0;
|
||||
#endif
|
||||
|
||||
int confirm_msg(char *msg)
|
||||
{
|
||||
#ifdef CONFIG_AUTO_BOOTSCRIPT
|
||||
/* From autoscript we shouldn't expect user's confirmations.
|
||||
* Assume yes is the correct answer here to avoid halting the script.
|
||||
*/
|
||||
if (RunningAutoScript)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
printf(msg);
|
||||
if (confirm_yesno())
|
||||
return 1;
|
||||
|
||||
puts("Operation aborted by user\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CMD_UPDATE) || defined(CONFIG_CMD_DBOOT)
|
||||
int get_source(int argc, char * const argv[], struct load_fw *fwinfo)
|
||||
{
|
||||
int i;
|
||||
char *src;
|
||||
#ifdef CONFIG_CMD_MTDPARTS
|
||||
struct mtd_device *dev;
|
||||
u8 pnum;
|
||||
char *partname;
|
||||
#endif
|
||||
|
||||
if (argc < 3) {
|
||||
fwinfo->src = SRC_TFTP; /* default to TFTP */
|
||||
return 0;
|
||||
}
|
||||
|
||||
src = argv[2];
|
||||
for (i = 0; i < ARRAY_SIZE(src_strings); i++) {
|
||||
if (!strncmp(src_strings[i], src, strlen(src))) {
|
||||
if (1 << i & CONFIG_SUPPORTED_SOURCES) {
|
||||
break;
|
||||
} else {
|
||||
fwinfo->src = SRC_UNSUPPORTED;
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= ARRAY_SIZE(src_strings)) {
|
||||
fwinfo->src = SRC_UNDEFINED;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case SRC_USB:
|
||||
case SRC_MMC:
|
||||
case SRC_SATA:
|
||||
/* Get device:partition and file system */
|
||||
if (argc > 3)
|
||||
fwinfo->devpartno = (char *)argv[3];
|
||||
if (argc > 4)
|
||||
fwinfo->fs = (char *)argv[4];
|
||||
break;
|
||||
case SRC_NAND:
|
||||
#ifdef CONFIG_CMD_MTDPARTS
|
||||
/* Initialize partitions */
|
||||
if (mtdparts_init()) {
|
||||
printf("Cannot initialize MTD partitions\n");
|
||||
goto _err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use partition name if provided, or else search for a
|
||||
* partition with the same name as the OS.
|
||||
*/
|
||||
if (argc > 3)
|
||||
partname = argv[3];
|
||||
else
|
||||
partname = argv[1];
|
||||
if (find_dev_and_part(partname, &dev, &pnum, &fwinfo->part)) {
|
||||
printf("Cannot find '%s' partition\n", partname);
|
||||
goto _err;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
fwinfo->src = i;
|
||||
return 0;
|
||||
|
||||
_err:
|
||||
if (fwinfo->src == SRC_UNSUPPORTED)
|
||||
printf("Error: '%s' is not supported as source\n", argv[2]);
|
||||
else if (fwinfo->src == SRC_UNDEFINED)
|
||||
printf("Error: undefined source\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *get_source_string(int src)
|
||||
{
|
||||
if (SRC_UNDEFINED != src && src < ARRAY_SIZE(src_strings))
|
||||
return src_strings[src];
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
int get_fw_filename(int argc, char * const argv[], struct load_fw *fwinfo)
|
||||
{
|
||||
switch (fwinfo->src) {
|
||||
case SRC_TFTP:
|
||||
case SRC_NFS:
|
||||
if (argc > 3) {
|
||||
fwinfo->filename = argv[3];
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case SRC_MMC:
|
||||
case SRC_USB:
|
||||
case SRC_SATA:
|
||||
if (argc > 5) {
|
||||
fwinfo->filename = argv[5];
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case SRC_NAND:
|
||||
if (argc > 4) {
|
||||
fwinfo->filename = argv[4];
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case SRC_RAM:
|
||||
return 0; /* No file is needed */
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *get_default_filename(char *partname, int cmd)
|
||||
{
|
||||
switch(cmd) {
|
||||
case CMD_DBOOT:
|
||||
if (!strcmp(partname, "linux") ||
|
||||
!strcmp(partname, "android")) {
|
||||
return "$" CONFIG_DBOOT_DEFAULTKERNELVAR;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_UPDATE:
|
||||
if (!strcmp(partname, "uboot")) {
|
||||
return "$uboot_file";
|
||||
} else {
|
||||
/* Read the default filename from a variable called
|
||||
* after the partition name: <partname>_file
|
||||
*/
|
||||
char varname[100];
|
||||
|
||||
sprintf(varname, "%s_file", partname);
|
||||
return getenv(varname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_default_devpartno(int src, char *devpartno)
|
||||
{
|
||||
char *dev, *part;
|
||||
|
||||
switch (src) {
|
||||
case SRC_MMC:
|
||||
dev = getenv("mmcdev");
|
||||
if (dev == NULL)
|
||||
return -1;
|
||||
part = getenv("mmcpart");
|
||||
/* If mmcpart not defined, default to 1 */
|
||||
if (part == NULL)
|
||||
sprintf(devpartno, "%s:1", dev);
|
||||
else
|
||||
sprintf(devpartno, "%s:%s", dev, part);
|
||||
break;
|
||||
case SRC_USB: // TODO
|
||||
case SRC_SATA: // TODO
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DIGI_UBI
|
||||
bool is_ubi_partition(struct part_info *part)
|
||||
{
|
||||
struct mtd_info *nand = &nand_info[0];
|
||||
size_t rsize = nand->writesize;
|
||||
unsigned char *page;
|
||||
unsigned long ubi_magic = 0x23494255; /* "UBI#" */
|
||||
bool ret = false;
|
||||
|
||||
/*
|
||||
* Check if the partition is UBI formatted by reading the first word
|
||||
* in the first page, which should contain the UBI magic "UBI#".
|
||||
* Then verify it contains a UBI volume and get its name.
|
||||
*/
|
||||
page = malloc(rsize);
|
||||
if (page) {
|
||||
if (!nand_read_skip_bad(nand, part->offset, &rsize, NULL,
|
||||
part->size, page)) {
|
||||
unsigned long *magic = (unsigned long *)page;
|
||||
|
||||
if (*magic == ubi_magic)
|
||||
ret = true;
|
||||
}
|
||||
free(page);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_DIGI_UBI */
|
||||
#endif /* CONFIG_CMD_UPDATE || CONFIG_CMD_DBOOT */
|
||||
|
||||
#ifdef CONFIG_CMD_UPDATE
|
||||
void register_fs_otf_update_hook(int (*hook)(otf_data_t *data),
|
||||
disk_partition_t *partition)
|
||||
{
|
||||
otf_update_hook = hook;
|
||||
/* Initialize data for new transfer */
|
||||
otfd.buf = NULL;
|
||||
otfd.part = partition;
|
||||
otfd.flags = OTF_FLAG_INIT;
|
||||
otfd.offset = 0;
|
||||
}
|
||||
|
||||
void unregister_fs_otf_update_hook(void)
|
||||
{
|
||||
otf_update_hook = NULL;
|
||||
}
|
||||
|
||||
/* On-the-fly update for files in a filesystem on mass storage media
|
||||
* The function returns:
|
||||
* 0 if the file was loaded successfully
|
||||
* -1 on error
|
||||
*/
|
||||
static int write_file_fs_otf(int src, char *filename, char *devpartno)
|
||||
{
|
||||
char cmd[CONFIG_SYS_CBSIZE] = "";
|
||||
unsigned long filesize;
|
||||
unsigned long remaining;
|
||||
unsigned long offset = 0;
|
||||
|
||||
/* Obtain file size */
|
||||
sprintf(cmd, "size %s %s %s", src_strings[src], devpartno, filename);
|
||||
if (run_command(cmd, 0)) {
|
||||
printf("Couldn't determine file size\n");
|
||||
return -1;
|
||||
}
|
||||
filesize = getenv_ulong("filesize", 16, 0);
|
||||
remaining = filesize;
|
||||
|
||||
/* Init otf data */
|
||||
otfd.loadaddr = getenv_ulong("loadaddr", 16, 0);
|
||||
|
||||
while (remaining > 0) {
|
||||
debug("%lu remaining bytes\n", remaining);
|
||||
/* Determine chunk length to write */
|
||||
if (remaining > CONFIG_OTF_CHUNK) {
|
||||
otfd.len = CONFIG_OTF_CHUNK;
|
||||
} else {
|
||||
otfd.flags |= OTF_FLAG_FLUSH;
|
||||
otfd.len = remaining;
|
||||
}
|
||||
|
||||
/* Load 'len' bytes from file[offset] into RAM */
|
||||
sprintf(cmd, "load %s %s $loadaddr %s %x %x", src_strings[src],
|
||||
devpartno, filename, otfd.len, (unsigned int)offset);
|
||||
if (run_command(cmd, 0)) {
|
||||
printf("Couldn't load file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write chunk */
|
||||
if (otf_update_hook(&otfd)) {
|
||||
printf("Error writing on-the-fly. Aborting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update local target offset */
|
||||
offset += otfd.len;
|
||||
/* Update remaining bytes */
|
||||
remaining -= otfd.len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A variable determines if the file must be loaded.
|
||||
* The function returns:
|
||||
* LDFW_LOADED if the file was loaded successfully
|
||||
* LDFW_NOT_LOADED if the file was not loaded, but isn't required
|
||||
* LDFW_ERROR on error
|
||||
*/
|
||||
int load_firmware(struct load_fw *fwinfo)
|
||||
{
|
||||
char cmd[CONFIG_SYS_CBSIZE] = "";
|
||||
char def_devpartno[] = "0:1";
|
||||
int ret;
|
||||
int fwload = FWLOAD_YES;
|
||||
|
||||
/* 'fwinfo->varload' determines if the file must be loaded:
|
||||
* - yes|NULL: the file must be loaded. Return error otherwise.
|
||||
* - try: the file may be loaded. Return ok even if load fails.
|
||||
* - no: skip the load.
|
||||
*/
|
||||
if (NULL != fwinfo->varload) {
|
||||
if (!strcmp(fwinfo->varload, "no"))
|
||||
return LDFW_NOT_LOADED; /* skip load and return ok */
|
||||
else if (!strcmp(fwinfo->varload, "try"))
|
||||
fwload = FWLOAD_TRY;
|
||||
}
|
||||
|
||||
/* Use default values if not provided */
|
||||
if (NULL == fwinfo->devpartno) {
|
||||
if (get_default_devpartno(fwinfo->src, def_devpartno))
|
||||
strcpy(def_devpartno, "0:1");
|
||||
fwinfo->devpartno = def_devpartno;
|
||||
}
|
||||
|
||||
switch (fwinfo->src) {
|
||||
case SRC_TFTP:
|
||||
sprintf(cmd, "tftpboot %s %s", fwinfo->loadaddr,
|
||||
fwinfo->filename);
|
||||
break;
|
||||
case SRC_NFS:
|
||||
sprintf(cmd, "nfs %s $rootpath/%s", fwinfo->loadaddr,
|
||||
fwinfo->filename);
|
||||
break;
|
||||
case SRC_MMC:
|
||||
case SRC_USB:
|
||||
case SRC_SATA:
|
||||
if (otf_update_hook) {
|
||||
ret = write_file_fs_otf(fwinfo->src, fwinfo->filename,
|
||||
fwinfo->devpartno);
|
||||
goto _ret;
|
||||
} else {
|
||||
sprintf(cmd, "load %s %s %s %s", src_strings[fwinfo->src],
|
||||
fwinfo->devpartno, fwinfo->loadaddr,
|
||||
fwinfo->filename);
|
||||
}
|
||||
break;
|
||||
case SRC_NAND:
|
||||
#ifdef CONFIG_DIGI_UBI
|
||||
/*
|
||||
* If the partition is UBI formatted, use 'ubiload' to read
|
||||
* a file from the UBIFS file system. Otherwise use a raw
|
||||
* read using 'nand read'.
|
||||
*/
|
||||
if (is_ubi_partition(fwinfo->part)) {
|
||||
sprintf(cmd,
|
||||
"if ubi part %s;then "
|
||||
"if ubifsmount ubi0:%s;then "
|
||||
"ubifsload %s %s;"
|
||||
"ubifsumount;"
|
||||
"fi;"
|
||||
"fi;",
|
||||
fwinfo->part->name, fwinfo->part->name,
|
||||
fwinfo->loadaddr, fwinfo->filename);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
sprintf(cmd, "nand read %s %s %x", fwinfo->part->name,
|
||||
fwinfo->loadaddr, (u32)fwinfo->part->size);
|
||||
}
|
||||
break;
|
||||
case SRC_RAM:
|
||||
ret = LDFW_NOT_LOADED; /* file is already in RAM */
|
||||
goto _ret;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = run_command(cmd, 0);
|
||||
_ret:
|
||||
if (FWLOAD_TRY == fwload) {
|
||||
if (ret)
|
||||
return LDFW_NOT_LOADED;
|
||||
else
|
||||
return LDFW_LOADED;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return LDFW_ERROR;
|
||||
|
||||
return LDFW_LOADED; /* ok, file was loaded */
|
||||
}
|
||||
#endif /* CONFIG_CMD_UPDATE */
|
||||
|
||||
#if defined(CONFIG_SOURCE) && defined(CONFIG_AUTO_BOOTSCRIPT)
|
||||
void run_auto_bootscript(void)
|
||||
{
|
||||
#ifdef CONFIG_CMD_NET
|
||||
int ret;
|
||||
char *bootscript;
|
||||
/* Save original timeouts */
|
||||
ulong saved_rrqtimeout_msecs = TftpRRQTimeoutMSecs;
|
||||
int saved_rrqtimeout_count = TftpRRQTimeoutCountMax;
|
||||
ulong saved_startagain_timeout = NetStartAgainTimeout;
|
||||
unsigned long saved_flags = gd->flags;
|
||||
char *retrycnt = getenv("netretry");
|
||||
|
||||
bootscript = getenv("bootscript");
|
||||
if (bootscript) {
|
||||
printf("Bootscript from TFTP... ");
|
||||
|
||||
/* Silence console */
|
||||
gd->flags |= GD_FLG_SILENT;
|
||||
/* set timeouts for bootscript */
|
||||
TftpRRQTimeoutMSecs = AUTOSCRIPT_TFTP_MSEC;
|
||||
TftpRRQTimeoutCountMax = AUTOSCRIPT_TFTP_CNT;
|
||||
NetStartAgainTimeout = AUTOSCRIPT_START_AGAIN;
|
||||
/* set retrycnt */
|
||||
setenv("netretry", "no");
|
||||
|
||||
/* Silence net commands during the bootscript download */
|
||||
DownloadingAutoScript = 1;
|
||||
ret = run_command("tftp ${loadaddr} ${bootscript}", 0);
|
||||
/* First restore original values of global variables
|
||||
* and then evaluate the result of the run_command */
|
||||
DownloadingAutoScript = 0;
|
||||
/* Restore original timeouts */
|
||||
TftpRRQTimeoutMSecs = saved_rrqtimeout_msecs;
|
||||
TftpRRQTimeoutCountMax = saved_rrqtimeout_count;
|
||||
NetStartAgainTimeout = saved_startagain_timeout;
|
||||
/* restore retrycnt */
|
||||
if (retrycnt)
|
||||
setenv("netretry", retrycnt);
|
||||
else
|
||||
setenv("netretry", "");
|
||||
/* Restore flags */
|
||||
gd->flags = saved_flags;
|
||||
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
printf("[ready]\nRunning bootscript...\n");
|
||||
RunningAutoScript = 1;
|
||||
/* Launch bootscript */
|
||||
run_command("source ${loadaddr}", 0);
|
||||
RunningAutoScript = 0;
|
||||
return;
|
||||
error:
|
||||
printf( "[not available]\n" );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int strtou32(const char *str, unsigned int base, u32 *result)
|
||||
{
|
||||
char *ep;
|
||||
|
||||
*result = simple_strtoul(str, &ep, base);
|
||||
if (ep == str || *ep != '\0')
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int confirm_prog(void)
|
||||
{
|
||||
puts("Warning: Programming fuses is an irreversible operation!\n"
|
||||
" This may brick your system.\n"
|
||||
" Use this command only if you are sure of "
|
||||
"what you are doing!\n"
|
||||
"\nReally perform this fuse programming? <y/N>\n");
|
||||
|
||||
if (getc() == 'y') {
|
||||
int c;
|
||||
|
||||
putc('y');
|
||||
c = getc();
|
||||
putc('\n');
|
||||
if (c == '\r')
|
||||
return 1;
|
||||
}
|
||||
|
||||
puts("Fuse programming aborted\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF_BOARD_SETUP)
|
||||
void fdt_fixup_mac(void *fdt, char *varname, char *node, char *property)
|
||||
{
|
||||
char *tmp, *end;
|
||||
unsigned char mac_addr[6];
|
||||
int i;
|
||||
|
||||
if ((tmp = getenv(varname)) != NULL) {
|
||||
for (i = 0; i < 6; i++) {
|
||||
mac_addr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
|
||||
if (tmp)
|
||||
tmp = (*end) ? end+1 : end;
|
||||
}
|
||||
do_fixup_by_path(fdt, node, property, &mac_addr, 6, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void fdt_fixup_regulatory(void *fdt)
|
||||
{
|
||||
unsigned int val;
|
||||
char *regdomain = getenv("regdomain");
|
||||
|
||||
if (regdomain != NULL) {
|
||||
val = simple_strtoul(regdomain, NULL, 16);
|
||||
if (val < DIGI_MAX_CERT) {
|
||||
sprintf(regdomain, "0x%x", val);
|
||||
do_fixup_by_path(fdt, "/wireless",
|
||||
"regulatory-domain", regdomain,
|
||||
strlen(regdomain) + 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OF_BOARD_SETUP */
|
||||
|
||||
void fdt_fixup_uboot_info(void *fdt) {
|
||||
do_fixup_by_path(fdt, "/", "digi,uboot,version", version_string,
|
||||
strlen(version_string), 1);
|
||||
#ifdef CONFIG_DYNAMIC_ENV_LOCATION
|
||||
do_fixup_by_path(fdt, "/", "digi,uboot,dynamic-env", NULL, 0, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *get_filename_ext(const char *filename)
|
||||
{
|
||||
const char *dot;
|
||||
|
||||
if (NULL == filename)
|
||||
return "";
|
||||
|
||||
dot = strrchr(filename, '.');
|
||||
if (!dot || dot == filename)
|
||||
return "";
|
||||
|
||||
return dot + 1;
|
||||
}
|
||||
|
||||
#define STR_HEX_CHUNK 8
|
||||
/*
|
||||
* Convert string with hexadecimal characters into a hex number
|
||||
* @in: Pointer to input string
|
||||
* @out Pointer to output number array
|
||||
* @len Number of elements in the output array
|
||||
*/
|
||||
void strtohex(char *in, unsigned long *out, int len)
|
||||
{
|
||||
char tmp[] = "ffffffff";
|
||||
int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i += STR_HEX_CHUNK, j++) {
|
||||
strncpy(tmp, &in[i], STR_HEX_CHUNK);
|
||||
out[j] = cpu_to_be32(simple_strtol(tmp, NULL, 16));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies if a MAC address has a default value (dummy) and prints a warning
|
||||
* if so.
|
||||
* @var: Variable to check
|
||||
* @default_mac: Default MAC to check with (as a string)
|
||||
*/
|
||||
void verify_mac_address(char *var, char *default_mac)
|
||||
{
|
||||
char *mac;
|
||||
|
||||
mac = getenv(var);
|
||||
if (NULL == mac)
|
||||
printf(" WARNING: MAC not set in '%s'\n", var);
|
||||
else if (!strcmp(mac, default_mac))
|
||||
printf(" WARNING: Dummy default MAC in '%s'\n", var);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the storage media address/block is empty
|
||||
* @in: Address/offset in media
|
||||
* @in: Partition index, only applies for MMC
|
||||
* The function returns:
|
||||
* 1 if the block is empty
|
||||
* 0 if the block is not empty
|
||||
* -1 on error
|
||||
*/
|
||||
int media_block_is_empty(u32 addr, uint hwpart)
|
||||
{
|
||||
size_t len;
|
||||
int ret = -1;
|
||||
int i;
|
||||
uint64_t empty_pattern = 0;
|
||||
uint64_t *readbuf = NULL;
|
||||
|
||||
if (strcmp(CONFIG_SYS_STORAGE_MEDIA, "nand") == 0)
|
||||
empty_pattern = ~0;
|
||||
|
||||
len = media_get_block_size();
|
||||
if (!len)
|
||||
return ret;
|
||||
|
||||
readbuf = malloc(len);
|
||||
if (!readbuf)
|
||||
return ret;
|
||||
|
||||
if (media_read_block(addr, (unsigned char *)readbuf, hwpart))
|
||||
goto out_free;
|
||||
|
||||
ret = 1; /* media block empty */
|
||||
for (i = 0; i < len / 8; i++) {
|
||||
if (readbuf[i] != empty_pattern) {
|
||||
ret = 0; /* media block not empty */
|
||||
break;
|
||||
}
|
||||
}
|
||||
out_free:
|
||||
free(readbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string into a number. The number stored at ptr is
|
||||
* potentially suffixed with K (for kilobytes, or 1024 bytes),
|
||||
* M (for megabytes, or 1048576 bytes), or G (for gigabytes, or
|
||||
* 1073741824). If the number is suffixed with K, M, or G, then
|
||||
* the return value is the number multiplied by one kilobyte, one
|
||||
* megabyte, or one gigabyte, respectively.
|
||||
*
|
||||
* @param ptr where parse begins
|
||||
* @param retptr output pointer to next char after parse completes (output)
|
||||
* @return resulting unsigned int
|
||||
*/
|
||||
u64 memsize_parse(const char *const ptr, const char **retptr)
|
||||
{
|
||||
u64 ret = simple_strtoull(ptr, (char **)retptr, 0);
|
||||
|
||||
switch (**retptr) {
|
||||
case 'G':
|
||||
case 'g':
|
||||
ret <<= 10;
|
||||
case 'M':
|
||||
case 'm':
|
||||
ret <<= 10;
|
||||
case 'K':
|
||||
case 'k':
|
||||
ret <<= 10;
|
||||
(*retptr)++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
75
board/i2som/common/helper.h
Normal file
75
board/i2som/common/helper.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2014 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __DIGI_HELPER_H
|
||||
#define __DIGI_HELPER_H
|
||||
|
||||
#include <jffs2/load_kernel.h>
|
||||
|
||||
enum {
|
||||
SRC_UNDEFINED = -2,
|
||||
SRC_UNSUPPORTED = -1,
|
||||
SRC_TFTP,
|
||||
SRC_NFS,
|
||||
SRC_NAND,
|
||||
SRC_USB,
|
||||
SRC_MMC,
|
||||
SRC_RAM,
|
||||
SRC_SATA,
|
||||
};
|
||||
|
||||
enum {
|
||||
CMD_DBOOT,
|
||||
CMD_UPDATE,
|
||||
};
|
||||
|
||||
enum {
|
||||
LDFW_ERROR = -1,
|
||||
LDFW_NOT_LOADED,
|
||||
LDFW_LOADED,
|
||||
};
|
||||
|
||||
struct load_fw {
|
||||
int src;
|
||||
char *filename;
|
||||
char *devpartno;
|
||||
char *fs;
|
||||
char *loadaddr;
|
||||
char *varload;
|
||||
struct part_info *part;
|
||||
};
|
||||
|
||||
int confirm_msg(char *msg);
|
||||
int get_source(int argc, char * const argv[], struct load_fw *fwinfo);
|
||||
const char *get_source_string(int src);
|
||||
int get_fw_filename(int argc, char * const argv[], struct load_fw *fwinfo);
|
||||
char *get_default_filename(char *partname, int cmd);
|
||||
#ifdef CONFIG_DIGI_UBI
|
||||
bool is_ubi_partition(struct part_info *part);
|
||||
#endif
|
||||
int strtou32(const char *str, unsigned int base, u32 *result);
|
||||
int confirm_prog(void);
|
||||
void fdt_fixup_mac(void *fdt, char *varname, char *node, char *property);
|
||||
void fdt_fixup_regulatory(void *fdt);
|
||||
void fdt_fixup_uboot_info(void *fdt);
|
||||
int load_firmware(struct load_fw *fwinfo);
|
||||
const char *get_filename_ext(const char *filename);
|
||||
void strtohex(char *in, unsigned long *out, int len);
|
||||
void verify_mac_address(char *var, char *default_mac);
|
||||
int get_partition_offset(char *part_name, u32 *offset);
|
||||
int media_block_is_empty(u32 addr, uint hwpart);
|
||||
int media_read_block(u32 addr, unsigned char *readbuf, uint hwpart);
|
||||
int media_write_block(u32 addr, unsigned char *readbuf, uint hwpart);
|
||||
void media_erase_fskey(u32 addr, uint hwpart);
|
||||
size_t media_get_block_size(void);
|
||||
unsigned int get_filesystem_key_offset(void);
|
||||
uint get_env_hwpart(void);
|
||||
u64 memsize_parse(const char *const ptr, const char **retptr);
|
||||
|
||||
#endif /* __DIGI_HELPER_H */
|
||||
@ -46,4 +46,10 @@ static inline uint64_t lldiv(uint64_t dividend, uint32_t divisor)
|
||||
return(__res);
|
||||
}
|
||||
|
||||
static inline uint64_t llmod(uint64_t dividend, uint32_t divisor)
|
||||
{
|
||||
uint64_t __res = dividend;
|
||||
return (do_div(__res, divisor));
|
||||
}
|
||||
|
||||
#endif /* _ASM_GENERIC_DIV64_H */
|
||||
|
||||
26
include/otf_update.h
Normal file
26
include/otf_update.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2014 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __OTF_UPDATE_H
|
||||
#define __OTF_UPDATE_H
|
||||
|
||||
/* OTF flags */
|
||||
#define OTF_FLAG_FLUSH (1 << 0) /* flag to write last chunk */
|
||||
#define OTF_FLAG_INIT (1 << 1) /* flag to write first chunk */
|
||||
|
||||
typedef struct otf_data {
|
||||
unsigned int loadaddr; /* address in RAM to load data to */
|
||||
unsigned int offset; /* offset in media to write data to */
|
||||
unsigned char *buf; /* buffer with data to write */
|
||||
unsigned int len; /* length of chunk to write */
|
||||
disk_partition_t *part; /* partition data */
|
||||
unsigned int flags; /* on-the-fly flags */
|
||||
}otf_data_t;
|
||||
|
||||
#endif /* __OTF_UPDATE_H */
|
||||
Reference in New Issue
Block a user