-
Notifications
You must be signed in to change notification settings - Fork 76
Porting Binary Header
The binary header is the first hardware initialization routine. It is executed by the Boot ROM before loading and running U-Boot. The execution flow of the binary header is shown below:
-
General Initialization
-
SERDES Initialization
-
DDR3 Initialization
-
DDR3 Silicon Initialization
-
DDR3 Driver
-
Suspend Wake Up
The binary header source code is included in the U-Boot source package in the tools/marvell/bin_hdr directory, but is compiled separately. Using the doimage tool, the binary header and U-Boot are combined into one image. The table below lists the binary header components and respective locations.
Table: Binary Header Components/Locations
Component | Location |
---|---|
Initial general initialization |
src_init/a38x/ |
SERDES configuration and initialization |
src_phy/a38x |
DDR3 Initialization |
src_ddr/ |
DDR3 Silicon Initialization |
src_ddr/ddr3libv2/src/Silicon/ |
DDR3 Driver |
src_ddr/ddr3libv2/src/Driver/ddr3/ |
Common included files |
inc/common/, inc/ddr3_soc/a38x/ |
Common utilities (such as UART, TWSI, and TIMER) |
platform/utils/, platform/sysEnv/a38x/, platform/drivers/ |
System environment |
platform/sysEnv/a38x |
The binary header initialization steps are described below.
The general initialization component is used for tasks that must be performed prior to DDR and SERDES configurations, for example the UART initialization sequence.
In contrast to all other flavors, 6W21(A383) and 6W23(A384) flavors are controlled in the software, and all the hardware limitations are enforced via U-Boot software. All other flavors have a Device ID field in the S@R register (values 0-6), The 6W21 flavors must be configured differently, as explained below, because wrong configuration might cause a problem with the interface numbers problem. To enable 6W21(A383), remove the comment characters from the relevant REDUCED_FLAVOR section, defined in the generalInit.h file, For example, to configure 6W21(A383), the relevant section in generalInit.h looks like the following:
#define REDUCED_FLAVOR 0x383 /* 0x383: A383 - 6W22 */ //#define REDUCED_FLAVOR 0x384 /* 0x384: A384 - 6W23 */
NOTE: The above comment in the code mentions the device 6W22 but it refers to 6W21. Since the code is frozen for 2015_T1, this comment remains as is in order to be aligned with the code.
The following section elaborates how to select the configuration for SERDES initialization.
The SERDES lane configuration setup is defined in: mvHighSpeedTopologySpec-38x.c under tools/marvell/bin_hdr/src_phy/a38x/ with SERDES_MAP struct for each lane. The following example demonstrates a full configuration selection for customer board #0, the following struct is the only struct that must be changed for customer implementation.
For the A38x:
SERDES_MAP CustomerBoardTopologyConfig[][MAX_SERDES_LANES] = { /* Customer Board #0 Topology - reference from Marvell DB-BP board */ /* serdesType, serdesSpeed, serdesMode, swapTx, swapRx */ { SATA0, __3Gbps, SERDES_DEFAULT_MODE, MV_FALSE, MV_FALSE }, { PEX0, __5Gbps, PEX_ROOT_COMPLEX_x1, MV_FALSE, MV_FALSE }, { PEX1, __5Gbps, PEX_ROOT_COMPLEX_x1, MV_FALSE, MV_FALSE }, { SATA3, __3Gbps, SERDES_DEFAULT_MODE, MV_FALSE, MV_FALSE }, { USB3_HOST0, __5Gbps, SERDES_DEFAULT_MODE, MV_FALSE, MV_FALSE }, { USB3_HOST1, __5Gbps, SERDES_DEFAULT_MODE, MV_FALSE, MV_FALSE } }
The above configuration entries may be modified according to customer’s board needs. If a certain lane is not in use, it must be set to DEFAULT_SERDES mode.
SERDES_MAP struct definition:
typedef struct { SERDES_TYPE serdesType; SERDES_SPEED serdesSpeed; SERDES_MODE serdesMode; MV_BOOL swapRx; MV_BOOL swapTx; } SERDES_MAP;
If a specific lane’s Tx/Rx polarity is swapped (on board assembly), it must be indicated accordingly in the Boolean swapTx/swapRx fields as MV_TRUE.
A specific SERDES mode must be set only for the PCIe lane type. Other SERDES types must use SERDES_DEFAULT mode.
See the hardware specification for optional lane selection options for different flavors.
Table: ARMADA 38x Valid SERDES Type/Mode per Lane
Lane | Options |
---|---|
Lane 0 |
DEFAULT_SERDES, PEX0(X1), PEX0(X4), SATA0, SGMII0 |
Lane 1 |
DEFAULT_SERDES, PEX0(X1), PEX1(X4), SATA0, SGMII0, SGMII1, USB3_HOST0, QSGMII |
Lane 2 |
DEFAULT_SERDES, PEX1(X1), PEX2(X4), SATA1, SGMII1 |
Lane 3 |
DEFAULT_SERDES, PEX3(X1), PEX3(X4), SATA3, SGMII2, USB3_HOST1, USB3_DEVICE |
Lane 4 |
DEFAULT_SERDES, PEX1, SGMII1,USB3_HOST0, USB3_DEVICE, SATA2 |
Lane 5 |
DEFAULT_SERDES, PEX2, SATA2, SGMII2,USB3_HOST1, USB3_DEVICE |
Table: ARMADA 38x Valid SERDES Speed per Type
Lane Type | Valid Speed Settings |
---|---|
PEX |
2.5 Gbps (GEN1), 5 Gbps (GEN2) |
SATA |
1.5 Gbps (GEN1), 3 Gbps (GEN2), 6Gbps (GEN3) |
SGMII |
1.25 Gbps (SGMII), 3.125 Gbps (SGMII2.5) |
QSGMII |
5 Gbps |
USB3_HOST0 |
5 Gbps |
USB3_DEVICE |
5 Gbps |
NOTE: Board specification does not require any changes when porting to a single customer board.
The array loadTopologyFuncArr (defined at bin_hdr/src_phy/a38x/mvHighSpeedTopologySpec-38x.c) includes pointers to the load topology routines per board. Board ID index is used as the index of the array derived by mvBoardIdIndexGet().
In the following example, two customer boards are supported, with the same SERDES configuration routine for both (loadTopologyCustomer). Configuration entries can be modified according to customer’s board needs.
loadTopologyFuncPtr loadTopologyFuncArr[] = { loadTopologyCustomer, /* Customer Board 0 */ loadTopologyCustomer, /* Customer Board 1*/ };
DRAM initialization is performed by the DDR3 training sequence. The DDR3 training sequence binary header is executed by the Boot ROM. The training sequence object library is included in the U-Boot source package.
Table below lists the DRAM initialization header files that must be modified for DRAM Initialization. These files are located in tools/marvell/bin_hdr/inc/ddr3_soc/a38x.
Table: DRAM Initialization Header Files
Component | Component File |
---|---|
DRAM static modes, DLB configuration |
ddr3_a38x_vars.h and ddr3_a39x_vars.h |
Static Initialization of Memory Controller Registers |
ddr3_a38x_static.h and ddr3_a39x_static.h |
DDR3 Topology configuration |
ddr3_a38x_topolgy.h and ddr3_a39x_topolgy.h |
DDR topology is the main configuration structure configured outside of the DDR3 training algorithm. The topology defines DRAM device parameters and other board-related information (DQS/Ck swap, mirroring, etc). The 3 tables below list the parameters that must be set in the /tools/marvell/bin_hdr/inc/ddr3_soc/a38x/ddr3_a38x_topology.h file to configure the binary header behavior. The configuration is done by the entry in the topology map matched to the board’s board ID. The main topology entry type is MV_HWS_TOPOLOGY_MAP, defined in tools/marvell/bin_hdr/inc/common, with existing definitions for two customer boards. Customer board configuration entries can be changed according to customer’s board requirements.
Table: MV_HWS_TOPOLOGY_MAP
Parameter Name | Parameter Description | Possible Values |
---|---|---|
interfaceActiveMask |
Mask of active DDR3 interfaces |
Static integer bitmask per SoC (should not be modified) |
interfaceParams |
Array of parameters for each enabled interface (for each enabled interface and within an interface for each 8-bit memory device interface), adapted interfaceParams entry must be configured - respectively) |
For details see Table Interface Parameters below. |
activeBusMask |
Mask of active 8-bit memory device bus interfaces, i.e. 0xF (32BIT) is 4-busses, 32-bit configuration, 0x13(16BIT_ECC) is 16-bit configuration with ECC on bus4 |
BUS_WIDTH_16BIT BUS_WIDTH_32BIT |
Table: Interface Parameters
Parameter Name | Parameter Description | Possible Values |
---|---|---|
asBusParams |
Per bus parameters explained below |
See Table BusParams Fields below |
speedBinIndex |
Index of speed bin table will be used |
Speed bin list in mvDdr3TopologyDef.h |
busWidth |
Width of the memory device bus, 8 or 16 bits |
BUS_WIDTH_8, BUS_WIDTH_16 (any value other than 16 will set bus width of 8BIT) |
memorySize |
Total size of the DRAM |
Sizes list in mvDdr3TopologyDef.h |
memoryFreq |
Frequency of the DRAM (may be overwritten by sample at reset values) |
List of frequencies in mvDdr3TopologyDef.h |
casWL, casL |
If set to 0, will be computed at runtime using speed bin parameters, if different – overwrites speed bin parameters |
Integer |
interfaceTemp |
The interface temperature impacts the value of the refresh rate. The refresh rate depends on the frequency and temperature: a high temperature refresh rate is double the low temperature refresh rate |
Temperature list in mvDdr3TopologyDef.h |
NOTE: There might be more than one bus per interface and each memory device bus interface has its own quad parameters group. Therefore, per active memory device bus interface, configure the 4 parameters shown in the Table BusParams Fields below.
Table: BusParams Fields
Parameter Name | Parameter Description | Possible Values |
---|---|---|
csBitmask |
Chip Select bitmask |
0x1 for single CS0, 0x3 for Dual CS |
mirrorEnableBitmask |
Mirror configuration of the bus |
0 = Not Mirrored 1 = Mirrored |
isDqsSwap |
Are DQS signals swapped |
0 = Not Swapped 1 = Swapped |
isCkSwap |
Are CK signals swapped |
0 = Not Swapped 1 = Swapped |
The following topology example describes customer board #0, with single DRAM interface, single CS, speed grade of 1866L, device bus width of 8 bits, density is 4 Gb, target frequency 800 MHz and CAS calculated by speed bin, with low refresh rate. The number of octet buses supported is 5, but only 4 are used, meaning a 32-bit mode without EEC2 are used, meaning a 16-bit mode without ECC.
NOTE: All BusParams parameters must be identical for all buses.
interfaceActiveMask=0x1, interfaceParams: asBusParams: csBitmask = 0x1 mirrorEnableBitmask = 0 isDqsSwap = 0 isCkSwap = 0 speedBinIndex = SPEED_BIN_DDR_1866L busWidth = BUS_WIDTH_8 memorySize = MEM_4G memoryFreq = DDR_FREQ_800 casWL = casL = 0 interfaceTemp = MV_HWS_TEMP_LOW activeBusMask = INTERFACE_BUS_MASK_32BIT MV_HWS_TOPOLOGY_MAP TopologyMap[] = { /* 1st customer board */ { 0x1, /* active interfaces */ /*cs_mask, mirror, dqs_swap, ck_swap x PUPs speed_bin, memory_width mem_size, frequency, casL casWL temperature */ {{{{0x1,0,0,0}, {0x1,0,0,0}, {0x1,0,0,0}, {0x1,0,0,0}, {0x1,0,0,0}}, SPEED_BIN_DDR_1866L, BUS_WIDTH_8, MEM_4G, DDR_FREQ_800, 0 , 0 , MV_HWS_TEMP_LOW}}, INTERFACE_BUS_MASK_32BIT, /* Bus mask */ INTERFACE_BUS_MASK_16BIT, /* Bus mask */ }
The following topology example describes customer board #0, with single DRAM interface, single CS, speed grade of 1866L, device bus width of 8 bits, density of 4-Gbit, target frequency of 800 MHz and CAS calculated by speed bin, with low refresh rate. The number of octet buses supported is 5, but 2 are used, meaning a 16-bit mode without ECC.
interfaceActiveMask=0x1, interfaceParams: asBusParams: csBitmask = 0x1 mirrorEnableBitmask = 0 isDqsSwap = 0 isCkSwap = 0 speedBinIndex = SPEED_BIN_DDR_1866L busWidth = BUS_WIDTH_8 memorySize = MEM_4G memoryFreq = DDR_FREQ_800 casWL = casL = 0 interfaceTemp = MV_HWS_TEMP_LOW activeBusMask = INTERFACE_BUS_MASK_16BIT MV_HWS_TOPOLOGY_MAP TopologyMap[] = { /* 1st customer board */ { 0x1, /* active interfaces */ /*cs_mask, mirror, dqs_swap, ck_swap x PUPs speed_bin, memory_width mem_size, frequency, casL casWL temperature */ {{{{0x1,0,0,0}, {0x1,0,0,0}, {0x0,0,0,0}, {0x0,0,0,0}, {0x0,0,0,0}}, SPEED_BIN_DDR_1866L, BUS_WIDTH_8, MEM_4G, DDR_FREQ_800, 0 , 0 , MV_HWS_TEMP_LOW}}, INTERFACE_BUS_MASK_16BIT, /* Buses mask */ }
DRAM modes structures contains the STATIC Dunit configuration per board per frequency. If the compilation flag SUPPORT_STATIC_DUNIT_CONFIG is defined, and the parameter genericInitController is set to 0, the DDR initialization flow executes the static configuration of DDR (rather than the dynamic algorithm). The genericInitController variable is a global variable, defined under tools/marvell/bin_hdr/src_ddr/ddr3_init_tipv2.c. DRAM mode configuration is defined in the ddr3_a38x_vars.h file, with existing definitions for 2 customer boards. The table entry is selected according to the board ID index, which is selected before compilation and returned by the mvBoardIdIndexGet() routine.
The MCregs register table pointer contains register-value pairs for static initialization of the memory controller (ddr3_a38x_mc_static.h). This register table must end with register-value pair of 0,0 that marks the end of the table.
In the following example, 800 represents the target DRAM frequency:
MV_DRAM_MODES ddr_modes[] = { /* Conf name CPUFreq FabFreq Chip ID Chip/Board MC regs*/ {"a38x_customer_0_800", DDR_FREQ_800, 0, 0x0, ARMADA_38x_CUSTOMER_BOARD_ID0, ddr3_customer_800}, {"a38x_customer_1_800", DDR_FREQ_800, 0, 0x0, ARMADA_38x_CUSTOMER_BOARD_ID1, ddr3_customer_800}, };
The ddr3HwsTuneTrainingParams() function sets the number of training global parameters and passes the configuration to the training library.
NOTE: Marvell recommends using dynamic DDR configuration.
The function is implemented in ddr3_init_tipv2.c and is used per SoC as shown below:
#define MV_TUNE_TRAINING_PARAMS_CK_DELAY 160 #define MV_TUNE_TRAINING_PARAMS_PHYREG3VAL 0xA #define MV_TUNE_TRAINING_PARAMS_PRI_DATA 123 #define MV_TUNE_TRAINING_PARAMS_NRI_DATA 123 #define MV_TUNE_TRAINING_PARAMS_PRI_CTRL 74 #define MV_TUNE_TRAINING_PARAMS_NRI_CTRL 74 #define MV_TUNE_TRAINING_PARAMS_P_ODT_DATA 45 #define MV_TUNE_TRAINING_PARAMS_N_ODT_DATA 45 #define MV_TUNE_TRAINING_PARAMS_P_ODT_CTRL 45 #define MV_TUNE_TRAINING_PARAMS_N_ODT_CTRL 45 #define MV_TUNE_TRAINING_PARAMS_DIC 0x2 #define MV_TUNE_TRAINING_PARAMS_ODT_CONFIG 0x120012 #define MV_TUNE_TRAINING_PARAMS_RTT_NOM 0x44
Table: DDR3 Training Lib Internal Parameters Configuration
Parameter Name | Description |
---|---|
CK_DELAY |
The delay between command and clock signals by 8-memory devices |
CK_DELAY_16 |
The delay between a command and clock signals by 16-memory devices |
PRI_DATA |
P-finger configuration for data driver strength |
NRI_DATA |
N-finger configuration for data driver strength |
PRI_CTRL |
P-finger configuration for control driver strength |
NRI_CTRL |
N-finger configuration for control driver strength |
P_ODT_DATA |
P-finger configuration for data ODT (On-die termination) |
P_ODT_CTRL |
Reserved, but not in use |
N_ODT_CTRL |
Reserved, but not in use |
DIC |
SDRAM Output Driver Impedance Control |
ODT_CONFIG |
Marvell ODT (On-die termination) control |
RTT_NOM |
SDRAM Input Nominal ODT (On-die termination) |
RTT_WR |
SDRAM Input Dynamic ODT (On-die termination) |
NOTE: The default defines is configured according to the Marvell recommendation (Marvell recommends using dynamic DDR configuration). Each define may be changed to a different value according to Marvell field engineer recommendations.
The DDR3 logging level can be modified by calling ddr3HwsSetLogLevel() function with blocks and levels defined in tools/marvell/bin_hdr/inc/common/mvDdr3LoggingDef.h.
Table Log Levels describes the log levels that can be selected. Contact your Marvell field application engineer with these logs if there is a problem.
Table: Log Levels
Debug Block | Log Level | Description |
---|---|---|
First stage |
MV_DEBUG_BLOCK_TRAINING_MAIN |
High-level information and status of each stage (run/passed/failed) |
Second stage (various stages of training) |
MV_DEBUG_BLOCK_STATIC |
Static configuration stages, not run in default |
MV_DEBUG_BLOCK_LEVELING |
Read/write leveling stages |
|
MV_DEBUG_BLOCK_CENTRALIZATION |
Centralization stages |
|
MV_DEBUG_BLOCK_PBS |
PBS stages |
|
Last stage |
MV_DEBUG_BLOCK_IP |
IP engine low-level function dumps |
MV_DEBUG_STAGES_REG_DUMP |
Register dumps in significant training stages |
|
MV_DEBUG_BLOCK_ACCESS |
Read/write trace for all registers |
|
Other |
MV_DEBUG_BLOCK_BIST |
Not relevant for SoC |
MV_DEBUG_BLOCK_ALG |
VREF stage, not supported yet |
|
MV_DEBUG_BLOCK_DEVICE |
SoC-specific configurations |
|
MV_DEBUG_BLOCK_ALL |
All excluding IP and REG_DUMP, that must be enabled separately |
By default, all logs are configured to the error log level by the following call: ddr3HwsSetLogLevel(MV_DEBUG_BLOCK_ALL, DEBUG_LEVEL_ERROR); under tools/marvell/bin_hdr/src_ddr/ddr3_init_tipv2.c
For example, to enable memory dumps in significant algorithms, call ddr3HwsSetLogLevel() again, after exiting the previous call, as shown below:
ddr3HwsSetLogLevel(MV_DEBUG_STAGES_REG_DUMP, DEBUG_LEVEL_TRACE); ddr3HwsSetLogLevel(MV_DEBUG_BLOCK_TRAINING_MAIN, DEBUG_LEVEL_TRACE);
DDR4 porting is the same as DDR3 porting. To compile the U-Boot image, add the "-m 4" option to invocation of the build.pl. The following is an example of this:
/build.pl -f spi -v 15t1 -i spi -b armada_38x_customer0 –c -m4
Also update in the relevant topology entry, the speedBinIndex field. The list of DDR4 speed bins supported is placed in inc/common/mvDdr3TopolgyDef.h under the #else of the DDR3 speed bins, listed under #ifdef CONFIG_DDR3.
The speedBinIndex field and busWidth definitions for DDR4 speed bins supported are placed in ddr3_a38x_topology.h under the #else of the DDR3 definitions under #ifdef CONFIG_DDR3.
By default, the DDR3 training is compiled, and the resulting library file ddr3_training_a38x.lib is placed under tools\marvell\bin_hdr\src_ddr\ddr3libv2.
NOTE: Generally, the DDR3 sources should not be modified. To modify the DDR3 training, contact your Marvell application engineer.
This component configures common utilities, such as UART, TWSI, Timers, etc.
UART0 is the default UART interface, and is defined in mv_uart.c under tools/marvell/bin_hdr/platform/drivers:
MV_U32 uartOffset = UART0_REG_OFFSET;
To set UART1 as the default UART interface instead of UART0:
-
Update the uartOffset definition to UART1_REG_OFFSET.
-
Update the UART MPP configuration in the correct MPP register (by default only UART0 MPP values are defined).
The example below shows how to set UART1 MPP values for the ARMADA 38x SoC:
-
UART1 MPP configuration for A38x: MPP19 =0x6, and MPP20 = 0x6
-
MPP19 and MPP20 are defined in the 3rd MPP register (each MPP register consists of 8 MPP values)
MV_U32 regData = MV_REG_READ(MPP_CONTROL_REG(2)); regData |= 0x00066000; MV_REG_WRITE(MPP_CONTROL_REG(2), regData);
This section describes how to add or update an existing binary header component.
The structure MV_BINARY_HEADER_COMPONENTS defined in tools/marvell/bin_hdr/in_common/mvBinHdrComponents.h defines a component’s name and its main function.
CAUTION: Do not use the Marvell proprietary board names. Instead, create new names. The Marvell naming may imply a specific implementation of the Marvell board that may not be relevant to a customer board.
The main function of a component must be defined in the following format:
MV_STATUS (*ComponentFunc) (void);
For example, the general initialization sequence is stated by:
MV_STATUS mvGeneralInit(void);
The main dispatcher calls the component’s main function in the BIN_HEADER_COMPONENT_TABLE. This table must end with a NULL entry.
typedef struct _binaryHeaderComponent { char *ComponentName; /* component name */ MV_STATUS (*ComponentFunc) (void); /* main function */ } MV_BINARY_HEADER_COMPONENTS;
The component’s main function must return MV_OK for U-Boot execution to continue.
Each component is compiled twice: the first time for normal operation and the second time for booting from UART.
NOTE: Printing output via UART is disabled for the second image created for booting from UART.
To add a new component to the binary header:
-
Create a new directory in tools/marvell/bin_hdr.
-
For example, tools/marvell/bin_hdr/src_<component_name>.
-
-
Place the component source code and makefile in the new component directory.
-
Edit the makefile:
-
Add the component directory to the COMPONENT_SUBDIRS.
-
Add the component library name to the HDR_COMPONENT.
-
Add the UART component library name to HDR_COMPONENT_UART.
-
-
Open and edit mvBinHdrComponents.h that is placed in the directory tools/marvell/bin_hdr/inc/common:
-
Add the new entry to table BIN_HEADER_COMPONENT_TABLE.
-
Add the main component subroutine definition.
-
-
Recompile U-Boot.