- mvebu: Move PCIe code from serdes to PCIe driver (Pali)
- mtd: nand: pxa3xx: use marvell, prefix for custom DT properties
  (Pierre)
- Add PCIe support for Iomega iConnect board (Tony)
- ddr: marvell: a38x: Misc improvements / fixes (Marek)
- tools: kwbimage: Load address fixes (Pali)
- mvebu: db-88f6720: Fix CONFIG_SPL_TEXT_BASE and remove wrong memory
  layout (Pali)
- mvebu: Replace hardcoded values 0x0030/0x4030 by proper calculation
  (Pali)
This commit is contained in:
Tom Rini 2022-01-14 10:43:14 -05:00
commit 9b72d934c2
47 changed files with 925 additions and 335 deletions

View File

@ -384,9 +384,10 @@
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
}; };
system-controller@18200 { systemc: system-controller@18200 {
compatible = "marvell,armada-375-system-controller"; compatible = "marvell,armada-375-system-controller";
reg = <0x18200 0x100>; reg = <0x18200 0x100>;
#reset-cells = <2>;
}; };
gateclk: clock-gating-control@18220 { gateclk: clock-gating-control@18220 {
@ -616,6 +617,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 5>; clocks = <&gateclk 5>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -634,6 +636,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <1>; marvell,pcie-lane = <1>;
clocks = <&gateclk 6>; clocks = <&gateclk 6>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };

View File

@ -73,6 +73,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 8>; clocks = <&gateclk 8>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -92,6 +93,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 5>; clocks = <&gateclk 5>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
@ -111,6 +113,7 @@
marvell,pcie-port = <2>; marvell,pcie-port = <2>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 6>; clocks = <&gateclk 6>;
resets = <&systemc 0 2>;
status = "disabled"; status = "disabled";
}; };
}; };

View File

@ -78,6 +78,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 8>; clocks = <&gateclk 8>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -97,6 +98,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 5>; clocks = <&gateclk 5>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
@ -116,6 +118,7 @@
marvell,pcie-port = <2>; marvell,pcie-port = <2>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 6>; clocks = <&gateclk 6>;
resets = <&systemc 0 2>;
status = "disabled"; status = "disabled";
}; };
@ -138,6 +141,7 @@
marvell,pcie-port = <3>; marvell,pcie-port = <3>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 7>; clocks = <&gateclk 7>;
resets = <&systemc 0 3>;
status = "disabled"; status = "disabled";
}; };
}; };

View File

@ -328,6 +328,7 @@
compatible = "marvell,armada-380-system-controller", compatible = "marvell,armada-380-system-controller",
"marvell,armada-370-xp-system-controller"; "marvell,armada-370-xp-system-controller";
reg = <0x18200 0x100>; reg = <0x18200 0x100>;
#reset-cells = <2>;
}; };
gateclk: clock-gating-control@18220 { gateclk: clock-gating-control@18220 {

View File

@ -231,7 +231,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
clocks = <&CP110_LABEL(syscon0) 1 2>; clocks = <&CP110_LABEL(syscon0) 1 2>;
nand-enable-arbiter; marvell,nand-enable-arbiter;
num-cs = <1>; num-cs = <1>;
nand-ecc-strength = <8>; nand-ecc-strength = <8>;
nand-ecc-step-size = <512>; nand-ecc-step-size = <512>;

View File

@ -85,6 +85,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 5>; clocks = <&gateclk 5>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
}; };
@ -136,6 +137,7 @@
systemc: system-controller@18200 { systemc: system-controller@18200 {
compatible = "marvell,armada-370-xp-system-controller"; compatible = "marvell,armada-370-xp-system-controller";
reg = <0x18200 0x500>; reg = <0x18200 0x500>;
#reset-cells = <2>;
}; };
gateclk: clock-gating-control@18220 { gateclk: clock-gating-control@18220 {

View File

@ -92,6 +92,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 5>; clocks = <&gateclk 5>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -110,6 +111,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <1>; marvell,pcie-lane = <1>;
clocks = <&gateclk 6>; clocks = <&gateclk 6>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -128,6 +130,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <2>; marvell,pcie-lane = <2>;
clocks = <&gateclk 7>; clocks = <&gateclk 7>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -146,6 +149,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <3>; marvell,pcie-lane = <3>;
clocks = <&gateclk 8>; clocks = <&gateclk 8>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -164,6 +168,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 9>; clocks = <&gateclk 9>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
}; };

View File

@ -107,6 +107,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 5>; clocks = <&gateclk 5>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -125,6 +126,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <1>; marvell,pcie-lane = <1>;
clocks = <&gateclk 6>; clocks = <&gateclk 6>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -143,6 +145,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <2>; marvell,pcie-lane = <2>;
clocks = <&gateclk 7>; clocks = <&gateclk 7>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -161,6 +164,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <3>; marvell,pcie-lane = <3>;
clocks = <&gateclk 8>; clocks = <&gateclk 8>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -179,6 +183,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 9>; clocks = <&gateclk 9>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
@ -197,6 +202,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <1>; marvell,pcie-lane = <1>;
clocks = <&gateclk 10>; clocks = <&gateclk 10>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
@ -215,6 +221,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <2>; marvell,pcie-lane = <2>;
clocks = <&gateclk 11>; clocks = <&gateclk 11>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
@ -233,6 +240,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <3>; marvell,pcie-lane = <3>;
clocks = <&gateclk 12>; clocks = <&gateclk 12>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
@ -251,6 +259,7 @@
marvell,pcie-port = <2>; marvell,pcie-port = <2>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 26>; clocks = <&gateclk 26>;
resets = <&systemc 0 2>;
status = "disabled"; status = "disabled";
}; };
}; };

View File

@ -128,6 +128,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 5>; clocks = <&gateclk 5>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -146,6 +147,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <1>; marvell,pcie-lane = <1>;
clocks = <&gateclk 6>; clocks = <&gateclk 6>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -164,6 +166,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <2>; marvell,pcie-lane = <2>;
clocks = <&gateclk 7>; clocks = <&gateclk 7>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -182,6 +185,7 @@
marvell,pcie-port = <0>; marvell,pcie-port = <0>;
marvell,pcie-lane = <3>; marvell,pcie-lane = <3>;
clocks = <&gateclk 8>; clocks = <&gateclk 8>;
resets = <&systemc 0 0>;
status = "disabled"; status = "disabled";
}; };
@ -200,6 +204,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 9>; clocks = <&gateclk 9>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
@ -218,6 +223,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <1>; marvell,pcie-lane = <1>;
clocks = <&gateclk 10>; clocks = <&gateclk 10>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
@ -236,6 +242,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <2>; marvell,pcie-lane = <2>;
clocks = <&gateclk 11>; clocks = <&gateclk 11>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
@ -254,6 +261,7 @@
marvell,pcie-port = <1>; marvell,pcie-port = <1>;
marvell,pcie-lane = <3>; marvell,pcie-lane = <3>;
clocks = <&gateclk 12>; clocks = <&gateclk 12>;
resets = <&systemc 0 1>;
status = "disabled"; status = "disabled";
}; };
@ -272,6 +280,7 @@
marvell,pcie-port = <2>; marvell,pcie-port = <2>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 26>; clocks = <&gateclk 26>;
resets = <&systemc 0 2>;
status = "disabled"; status = "disabled";
}; };
@ -290,6 +299,7 @@
marvell,pcie-port = <3>; marvell,pcie-port = <3>;
marvell,pcie-lane = <0>; marvell,pcie-lane = <0>;
clocks = <&gateclk 27>; clocks = <&gateclk 27>;
resets = <&systemc 0 3>;
status = "disabled"; status = "disabled";
}; };
}; };

View File

@ -187,6 +187,7 @@
pcie@1,0 { pcie@1,0 {
/* Port 0, Lane 0 */ /* Port 0, Lane 0 */
status = "okay"; status = "okay";
num-lanes = <4>;
}; };
/* /*

View File

@ -214,5 +214,6 @@
pcie@9,0 { pcie@9,0 {
/* Port 2, Lane 0 */ /* Port 2, Lane 0 */
status = "okay"; status = "okay";
num-lanes = <4>;
}; };
}; };

View File

@ -78,6 +78,7 @@
systemc: system-controller@18200 { systemc: system-controller@18200 {
compatible = "marvell,armada-370-xp-system-controller"; compatible = "marvell,armada-370-xp-system-controller";
reg = <0x18200 0x500>; reg = <0x18200 0x500>;
#reset-cells = <2>;
}; };
gateclk: clock-gating-control@18220 { gateclk: clock-gating-control@18220 {

View File

@ -21,6 +21,7 @@ else # CONFIG_ARCH_KIRKWOOD
obj-y = cpu.o obj-y = cpu.o
obj-y += dram.o obj-y += dram.o
obj-$(CONFIG_DM_RESET) += system-controller.o
ifndef CONFIG_SPL_BUILD ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o
obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o
@ -30,6 +31,17 @@ obj-$(CONFIG_MVEBU_EFUSE) += efuse.o
extra-y += kwbimage.cfg extra-y += kwbimage.cfg
ifneq ($(CONFIG_ARMADA_370)$(CONFIG_ARMADA_XP),)
KWB_REPLACE += CPU
KWB_CFG_CPU = SHEEVA
else ifneq ($(CONFIG_ARMADA_375)$(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X),)
KWB_REPLACE += CPU
KWB_CFG_CPU = A9
endif
KWB_REPLACE += LOAD_ADDRESS
KWB_CFG_LOAD_ADDRESS = $(CONFIG_SPL_TEXT_BASE)
KWB_REPLACE += BOOT_FROM KWB_REPLACE += BOOT_FROM
ifneq ($(CONFIG_MVEBU_SPL_BOOT_DEVICE_SPI),) ifneq ($(CONFIG_MVEBU_SPL_BOOT_DEVICE_SPI),)
KWB_CFG_BOOT_FROM=spi KWB_CFG_BOOT_FROM=spi
@ -58,10 +70,20 @@ KWB_REPLACE += SEC_FUSE_DUMP
KWB_CFG_SEC_FUSE_DUMP = a38x KWB_CFG_SEC_FUSE_DUMP = a38x
endif endif
ifdef CONFIG_ARMADA_38X
# BootROM output is by default enabled on pre-A38x and disabled on A38x
# DEBUG flag on A38x for non-UART boot source only enable BootROM output and nothing more
KWB_REPLACE += DEBUG
KWB_CFG_DEBUG = 1
endif
quiet_cmd_kwbcfg = KWBCFG $@
cmd_kwbcfg = sed -ne '$(foreach V,$(KWB_REPLACE),s/\#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \
<$< >$(dir $@)$(@F)
$(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \ $(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
include/config/auto.conf include/config/auto.conf
$(Q)sed -ne '$(foreach V,$(KWB_REPLACE),s/^#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \ $(call cmd,kwbcfg)
<$< >$(dir $@)$(@F)
endif # CONFIG_SPL_BUILD endif # CONFIG_SPL_BUILD
obj-y += gpio.o obj-y += gpio.o

View File

@ -74,10 +74,11 @@ enum {
/* /*
* Default Device Address MAP BAR values * Default Device Address MAP BAR values
*/ */
#define MBUS_PCI_MAX_PORTS 6
#define MBUS_PCI_MEM_BASE MVEBU_SDRAM_SIZE_MAX #define MBUS_PCI_MEM_BASE MVEBU_SDRAM_SIZE_MAX
#define MBUS_PCI_MEM_SIZE (128 << 20) #define MBUS_PCI_MEM_SIZE ((MBUS_PCI_MAX_PORTS * 128) << 20)
#define MBUS_PCI_IO_BASE 0xF1100000 #define MBUS_PCI_IO_BASE 0xF1100000
#define MBUS_PCI_IO_SIZE (64 << 10) #define MBUS_PCI_IO_SIZE ((MBUS_PCI_MAX_PORTS * 64) << 10)
#define MBUS_SPI_BASE 0xF4000000 #define MBUS_SPI_BASE 0xF4000000
#define MBUS_SPI_SIZE (8 << 20) #define MBUS_SPI_SIZE (8 << 20)
#define MBUS_DFX_BASE 0xF6000000 #define MBUS_DFX_BASE 0xF6000000

View File

@ -5,8 +5,14 @@
# Armada 38x uses version 1 image format # Armada 38x uses version 1 image format
VERSION 1 VERSION 1
# Type of the CPU core
#@CPU
# Boot Media configurations # Boot Media configurations
#@BOOT_FROM #@BOOT_FROM
# Binary Header (bin_hdr) with DDR3 training code # Enable BootROM output via DEBUG flag on SoCs which require it
BINARY spl/u-boot-spl.bin #@DEBUG
# Include U-Boot SPL with DDR3 training code into Binary Header
BINARY spl/u-boot-spl.bin #@LOAD_ADDRESS

View File

@ -1,6 +1,5 @@
# SPDX-License-Identifier: GPL-2.0+ # SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_SPL_BUILD) = ctrl_pex.o
obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec.o obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec.o
obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec-38x.o obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec-38x.o
obj-$(CONFIG_SPL_BUILD) += seq_exec.o obj-$(CONFIG_SPL_BUILD) += seq_exec.o

View File

@ -1,64 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*/
#include <common.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include "ctrl_pex.h"
#include "sys_env_lib.h"
__weak void board_pex_config(void)
{
/* nothing in this weak default implementation */
}
int hws_pex_config(const struct serdes_map *serdes_map, u8 count)
{
enum serdes_type serdes_type;
u32 idx, tmp;
DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n");
tmp = reg_read(SOC_CONTROL_REG1);
tmp &= ~0x03;
for (idx = 0; idx < count; idx++) {
serdes_type = serdes_map[idx].serdes_type;
if ((serdes_type != PEX0) &&
((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
(serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
/* for PEX by4 - relevant for the first port only */
continue;
}
switch (serdes_type) {
case PEX0:
tmp |= 0x1 << PCIE0_ENABLE_OFFS;
break;
case PEX1:
tmp |= 0x1 << PCIE1_ENABLE_OFFS;
break;
case PEX2:
tmp |= 0x1 << PCIE2_ENABLE_OFFS;
break;
case PEX3:
tmp |= 0x1 << PCIE3_ENABLE_OFFS;
break;
default:
break;
}
}
reg_write(SOC_CONTROL_REG1, tmp);
board_pex_config();
return MV_OK;
}

View File

@ -1,28 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*/
#ifndef _CTRL_PEX_H
#define _CTRL_PEX_H
#include <pci.h>
#include "high_speed_env_spec.h"
/* Direct access to PEX0 Root Port's PCIe Capability structure */
#define PEX0_RP_PCIE_CFG_OFFSET (0x00080000 + 0x60)
/* SOC_CONTROL_REG1 fields */
#define PCIE0_ENABLE_OFFS 0
#define PCIE0_ENABLE_MASK (0x1 << PCIE0_ENABLE_OFFS)
#define PCIE1_ENABLE_OFFS 1
#define PCIE1_ENABLE_MASK (0x1 << PCIE1_ENABLE_OFFS)
#define PCIE2_ENABLE_OFFS 2
#define PCIE2_ENABLE_MASK (0x1 << PCIE2_ENABLE_OFFS)
#define PCIE3_ENABLE_OFFS 3
#define PCIE4_ENABLE_MASK (0x1 << PCIE3_ENABLE_OFFS)
int hws_pex_config(const struct serdes_map *serdes_map, u8 count);
void board_pex_config(void);
#endif

View File

@ -12,7 +12,6 @@
#include "high_speed_env_spec.h" #include "high_speed_env_spec.h"
#include "sys_env_lib.h" #include "sys_env_lib.h"
#include "ctrl_pex.h"
/* /*
* serdes_seq_db - holds all serdes sequences, their size and the * serdes_seq_db - holds all serdes sequences, their size and the
@ -1555,9 +1554,6 @@ int hws_power_up_serdes_lanes(struct serdes_map *serdes_map, u8 count)
After finish the Power_up sequence for all lanes, After finish the Power_up sequence for all lanes,
the lanes should be released from reset state. */ the lanes should be released from reset state. */
CHECK_STATUS(hws_pex_tx_config_seq(serdes_map, count)); CHECK_STATUS(hws_pex_tx_config_seq(serdes_map, count));
/* PEX configuration */
CHECK_STATUS(hws_pex_config(serdes_map, count));
} }
/* USB2 configuration */ /* USB2 configuration */
@ -1743,21 +1739,6 @@ int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up,
else else
reg_data &= ~0x4000; reg_data &= ~0x4000;
reg_write(SOC_CONTROL_REG1, reg_data); reg_write(SOC_CONTROL_REG1, reg_data);
/*
* Set Maximum Link Width to X1 or X4 in Root
* Port's PCIe Link Capability register.
* This register is read-only but if is not set
* correctly then access to PCI config space of
* endpoint card behind this Root Port does not
* work.
*/
reg_data = reg_read(PEX0_RP_PCIE_CFG_OFFSET +
PCI_EXP_LNKCAP);
reg_data &= ~PCI_EXP_LNKCAP_MLW;
reg_data |= (is_pex_by1 ? 1 : 4) << 4;
reg_write(PEX0_RP_PCIE_CFG_OFFSET +
PCI_EXP_LNKCAP, reg_data);
} }
CHECK_STATUS(mv_seq_exec(serdes_num, PEX_POWER_UP_SEQ)); CHECK_STATUS(mv_seq_exec(serdes_num, PEX_POWER_UP_SEQ));

View File

@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0+
// (C) 2021 Pali Rohár <pali@kernel.org>
#include <common.h>
#include <dm.h>
#include <reset-uclass.h>
#include <asm/io.h>
#define MVEBU_SOC_CONTROL_1_REG 0x4
#define MVEBU_PCIE_ID 0
struct mvebu_reset_data {
void *base;
};
static int mvebu_reset_of_xlate(struct reset_ctl *rst,
struct ofnode_phandle_args *args)
{
if (args->args_count < 2)
return -EINVAL;
rst->id = args->args[0];
rst->data = args->args[1];
/* Currently only PCIe is implemented */
if (rst->id != MVEBU_PCIE_ID)
return -EINVAL;
/* Four PCIe enable bits are shared across more PCIe links */
if (!(rst->data >= 0 && rst->data <= 3))
return -EINVAL;
return 0;
}
static int mvebu_reset_request(struct reset_ctl *rst)
{
return 0;
}
static int mvebu_reset_free(struct reset_ctl *rst)
{
return 0;
}
static int mvebu_reset_assert(struct reset_ctl *rst)
{
struct mvebu_reset_data *data = dev_get_priv(rst->dev);
clrbits_32(data->base + MVEBU_SOC_CONTROL_1_REG, BIT(rst->data));
return 0;
}
static int mvebu_reset_deassert(struct reset_ctl *rst)
{
struct mvebu_reset_data *data = dev_get_priv(rst->dev);
setbits_32(data->base + MVEBU_SOC_CONTROL_1_REG, BIT(rst->data));
return 0;
}
static int mvebu_reset_status(struct reset_ctl *rst)
{
struct mvebu_reset_data *data = dev_get_priv(rst->dev);
return !(readl(data->base + MVEBU_SOC_CONTROL_1_REG) & BIT(rst->data));
}
static int mvebu_reset_of_to_plat(struct udevice *dev)
{
struct mvebu_reset_data *data = dev_get_priv(dev);
data->base = (void *)dev_read_addr(dev);
if ((fdt_addr_t)data->base == FDT_ADDR_T_NONE)
return -EINVAL;
return 0;
}
static const struct udevice_id mvebu_reset_of_match[] = {
{ .compatible = "marvell,armada-370-xp-system-controller" },
{ .compatible = "marvell,armada-375-system-controller" },
{ .compatible = "marvell,armada-380-system-controller" },
{ .compatible = "marvell,armada-390-system-controller" },
{ },
};
static struct reset_ops mvebu_reset_ops = {
.of_xlate = mvebu_reset_of_xlate,
.request = mvebu_reset_request,
.rfree = mvebu_reset_free,
.rst_assert = mvebu_reset_assert,
.rst_deassert = mvebu_reset_deassert,
.rst_status = mvebu_reset_status,
};
U_BOOT_DRIVER(mvebu_reset) = {
.name = "mvebu-reset",
.id = UCLASS_RESET,
.of_match = mvebu_reset_of_match,
.of_to_plat = mvebu_reset_of_to_plat,
.priv_auto = sizeof(struct mvebu_reset_data),
.ops = &mvebu_reset_ops,
};

View File

@ -1,5 +1,4 @@
A38X BOARD A38X BOARD
M: Dirk Eibach <dirk.eibach@gdsys.cc>
M: Mario Six <mario.six@gdsys.cc> M: Mario Six <mario.six@gdsys.cc>
S: Maintained S: Maintained
F: board/gdsys/a38x/ F: board/gdsys/a38x/

View File

@ -94,12 +94,16 @@ int hws_board_topology_load(struct serdes_map **serdes_map_array, u8 *count)
return 0; return 0;
} }
void board_pex_config(void) void spl_board_init(void)
{ {
#ifdef CONFIG_SPL_BUILD #ifdef CONFIG_SPL_BUILD
uint k; uint k;
struct gpio_desc gpio = {}; struct gpio_desc gpio = {};
/* Enable PCIe link 2 */
setbits_32(MVEBU_REGISTER(0x18204), BIT(2));
mdelay(10);
if (!request_gpio_by_name(&gpio, "pca9698@22", 31, "fpga-program-gpio")) { if (!request_gpio_by_name(&gpio, "pca9698@22", 31, "fpga-program-gpio")) {
/* prepare FPGA reconfiguration */ /* prepare FPGA reconfiguration */
dm_gpio_set_dir_flags(&gpio, GPIOD_IS_OUT); dm_gpio_set_dir_flags(&gpio, GPIOD_IS_OUT);

View File

@ -1,5 +1,5 @@
MPC8308 BOARD MPC8308 BOARD
M: Dirk Eibach <dirk.eibach@gdsys.cc> M: Mario Six <mario.six@gdsys.cc>
S: Maintained S: Maintained
F: board/gdsys/mpc8308/ F: board/gdsys/mpc8308/
F: include/configs/gazerbeam.h F: include/configs/gazerbeam.h

View File

@ -1,4 +1,5 @@
ICONNECT BOARD ICONNECT BOARD
M: Tony Dinh <mibodhi@gmail.com>
M: Luka Perkov <luka@openwrt.org> M: Luka Perkov <luka@openwrt.org>
S: Maintained S: Maintained
F: board/iomega/iconnect/ F: board/iomega/iconnect/

View File

@ -92,3 +92,10 @@ int board_init(void)
return 0; return 0;
} }
int board_late_init(void)
{
/* Do late init to ensure successful enumeration of PCIe devices */
pci_init();
return 0;
}

View File

@ -33,6 +33,7 @@ CONFIG_SYS_CONSOLE_INFO_QUIET=y
CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_BOARD_LATE_INIT=y CONFIG_BOARD_LATE_INIT=y
CONFIG_LAST_STAGE_INIT=y CONFIG_LAST_STAGE_INIT=y
CONFIG_SPL_BOARD_INIT=y
CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_I2C=y CONFIG_SPL_I2C=y
CONFIG_HUSH_PARSER=y CONFIG_HUSH_PARSER=y

View File

@ -11,7 +11,7 @@ CONFIG_ENV_SIZE=0x10000
CONFIG_ENV_OFFSET=0x100000 CONFIG_ENV_OFFSET=0x100000
CONFIG_ENV_SECT_SIZE=0x10000 CONFIG_ENV_SECT_SIZE=0x10000
CONFIG_DEFAULT_DEVICE_TREE="armada-375-db" CONFIG_DEFAULT_DEVICE_TREE="armada-375-db"
CONFIG_SPL_TEXT_BASE=0x40004030 CONFIG_SPL_TEXT_BASE=0x40000030
CONFIG_SPL_SERIAL=y CONFIG_SPL_SERIAL=y
CONFIG_SPL=y CONFIG_SPL=y
CONFIG_DEBUG_UART_BASE=0xf1012000 CONFIG_DEBUG_UART_BASE=0xf1012000

View File

@ -2,6 +2,7 @@ CONFIG_ARM=y
CONFIG_SKIP_LOWLEVEL_INIT=y CONFIG_SKIP_LOWLEVEL_INIT=y
CONFIG_SYS_DCACHE_OFF=y CONFIG_SYS_DCACHE_OFF=y
CONFIG_ARCH_CPU_INIT=y CONFIG_ARCH_CPU_INIT=y
CONFIG_SYS_THUMB_BUILD=y
CONFIG_ARCH_KIRKWOOD=y CONFIG_ARCH_KIRKWOOD=y
CONFIG_SYS_KWD_CONFIG="board/iomega/iconnect/kwbimage.cfg" CONFIG_SYS_KWD_CONFIG="board/iomega/iconnect/kwbimage.cfg"
CONFIG_SYS_TEXT_BASE=0x600000 CONFIG_SYS_TEXT_BASE=0x600000
@ -18,9 +19,11 @@ CONFIG_USE_BOOTCOMMAND=y
CONFIG_BOOTCOMMAND="setenv bootargs ${console} ${mtdparts} ${bootargs_root}; ubi part rootfs; ubifsmount ubi:rootfs; ubifsload 0x800000 ${kernel}; bootm 0x800000" CONFIG_BOOTCOMMAND="setenv bootargs ${console} ${mtdparts} ${bootargs_root}; ubi part rootfs; ubifsmount ubi:rootfs; ubifsload 0x800000 ${kernel}; bootm 0x800000"
CONFIG_USE_PREBOOT=y CONFIG_USE_PREBOOT=y
# CONFIG_DISPLAY_BOARDINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set
CONFIG_BOARD_LATE_INIT=y
CONFIG_SYS_PROMPT="iconnect => " CONFIG_SYS_PROMPT="iconnect => "
# CONFIG_CMD_FLASH is not set # CONFIG_CMD_FLASH is not set
CONFIG_CMD_NAND=y CONFIG_CMD_NAND=y
CONFIG_CMD_PCI=y
CONFIG_CMD_USB=y CONFIG_CMD_USB=y
# CONFIG_CMD_SETEXPR is not set # CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_MII=y CONFIG_CMD_MII=y
@ -43,6 +46,8 @@ CONFIG_MTD=y
CONFIG_MTD_RAW_NAND=y CONFIG_MTD_RAW_NAND=y
CONFIG_MVGBE=y CONFIG_MVGBE=y
CONFIG_MII=y CONFIG_MII=y
CONFIG_PCI=y
CONFIG_PCI_MVEBU=y
CONFIG_SYS_NS16550=y CONFIG_SYS_NS16550=y
CONFIG_USB=y CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD=y

View File

@ -55,6 +55,7 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode)
enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM]; enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM];
u32 if_id, pattern_id, bit_id; u32 if_id, pattern_id, bit_id;
u8 bus_id; u8 bus_id;
u8 current_byte_status;
u8 cur_start_win[BUS_WIDTH_IN_BITS]; u8 cur_start_win[BUS_WIDTH_IN_BITS];
u8 centralization_result[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS]; u8 centralization_result[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS];
u8 cur_end_win[BUS_WIDTH_IN_BITS]; u8 cur_end_win[BUS_WIDTH_IN_BITS];
@ -166,6 +167,10 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode)
result[search_dir_id][7])); result[search_dir_id][7]));
} }
current_byte_status =
mv_ddr_tip_sub_phy_byte_status_get(if_id,
bus_id);
for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS; for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS;
bit_id++) { bit_id++) {
/* check if this code is valid for 2 edge, probably not :( */ /* check if this code is valid for 2 edge, probably not :( */
@ -174,11 +179,32 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode)
[HWS_LOW2HIGH] [HWS_LOW2HIGH]
[bit_id], [bit_id],
EDGE_1); EDGE_1);
if (current_byte_status &
BYTE_SPLIT_OUT_MIX) {
if (cur_start_win[bit_id] >= 64)
cur_start_win[bit_id] -= 64;
else
cur_start_win[bit_id] = 0;
DEBUG_CENTRALIZATION_ENGINE
(DEBUG_LEVEL_INFO,
("pattern %d IF %d pup %d bit %d subtract 64 adll from start\n",
pattern_id, if_id, bus_id, bit_id));
}
cur_end_win[bit_id] = cur_end_win[bit_id] =
GET_TAP_RESULT(result GET_TAP_RESULT(result
[HWS_HIGH2LOW] [HWS_HIGH2LOW]
[bit_id], [bit_id],
EDGE_1); EDGE_1);
if (cur_end_win[bit_id] >= 64 &&
(current_byte_status &
BYTE_SPLIT_OUT_MIX)) {
cur_end_win[bit_id] -= 64;
DEBUG_CENTRALIZATION_ENGINE
(DEBUG_LEVEL_INFO,
("pattern %d IF %d pup %d bit %d subtract 64 adll from end\n",
pattern_id, if_id, bus_id, bit_id));
}
/* window length */ /* window length */
current_window[bit_id] = current_window[bit_id] =
cur_end_win[bit_id] - cur_end_win[bit_id] -

View File

@ -167,8 +167,6 @@ static u16 a38x_vco_freq_per_sar_ref_clk_40_mhz[] = {
}; };
static u32 async_mode_at_tf;
static u32 dq_bit_map_2_phy_pin[] = { static u32 dq_bit_map_2_phy_pin[] = {
1, 0, 2, 6, 9, 8, 3, 7, /* 0 */ 1, 0, 2, 6, 9, 8, 3, 7, /* 0 */
8, 9, 1, 7, 2, 6, 3, 0, /* 1 */ 8, 9, 1, 7, 2, 6, 3, 0, /* 1 */
@ -734,7 +732,8 @@ static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id,
u32 divider = 0; u32 divider = 0;
u32 sar_val, ref_clk_satr; u32 sar_val, ref_clk_satr;
u32 async_val; u32 async_val;
u32 freq = mv_ddr_freq_get(frequency); u32 cpu_freq;
u32 ddr_freq = mv_ddr_freq_get(frequency);
if (if_id != 0) { if (if_id != 0) {
DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR, DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR,
@ -751,11 +750,14 @@ static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id,
ref_clk_satr = reg_read(DEVICE_SAMPLE_AT_RESET2_REG); ref_clk_satr = reg_read(DEVICE_SAMPLE_AT_RESET2_REG);
if (((ref_clk_satr >> DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_OFFSET) & 0x1) == if (((ref_clk_satr >> DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_OFFSET) & 0x1) ==
DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_25MHZ) DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_25MHZ)
divider = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val] / freq; cpu_freq = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val];
else else
divider = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val] / freq; cpu_freq = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val];
if ((async_mode_at_tf == 1) && (freq > 400)) { divider = cpu_freq / ddr_freq;
if (((cpu_freq % ddr_freq != 0) || (divider != 2 && divider != 3)) &&
(ddr_freq > 400)) {
/* Set async mode */ /* Set async mode */
dunit_write(0x20220, 0x1000, 0x1000); dunit_write(0x20220, 0x1000, 0x1000);
dunit_write(0xe42f4, 0x200, 0x200); dunit_write(0xe42f4, 0x200, 0x200);
@ -869,8 +871,6 @@ int ddr3_tip_ext_write(u32 dev_num, u32 if_id, u32 reg_addr,
int mv_ddr_early_init(void) int mv_ddr_early_init(void)
{ {
struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
/* FIXME: change this configuration per ddr type /* FIXME: change this configuration per ddr type
* configure a380 and a390 to work with receiver odt timing * configure a380 and a390 to work with receiver odt timing
* the odt_config is defined: * the odt_config is defined:
@ -882,9 +882,6 @@ int mv_ddr_early_init(void)
mv_ddr_sw_db_init(0, 0); mv_ddr_sw_db_init(0, 0);
if (tm->interface_params[0].memory_freq != MV_DDR_FREQ_SAR)
async_mode_at_tf = 1;
return MV_OK; return MV_OK;
} }

View File

@ -1862,10 +1862,10 @@ static int pxa3xx_nand_probe_dt(struct udevice *dev, struct pxa3xx_nand_info *in
return -EINVAL; return -EINVAL;
} }
if (dev_read_bool(dev, "nand-enable-arbiter")) if (dev_read_bool(dev, "marvell,nand-enable-arbiter"))
pdata->enable_arbiter = 1; pdata->enable_arbiter = 1;
if (dev_read_bool(dev, "nand-keep-config")) if (dev_read_bool(dev, "marvell,nand-keep-config"))
pdata->keep_config = 1; pdata->keep_config = 1;
/* /*

View File

@ -265,6 +265,7 @@ config PCI_MVEBU
bool "Enable Armada XP/38x PCIe driver" bool "Enable Armada XP/38x PCIe driver"
depends on ARCH_MVEBU depends on ARCH_MVEBU
select MISC select MISC
select DM_RESET
help help
Say Y here if you want to enable PCIe controller support on Say Y here if you want to enable PCIe controller support on
Armada XP/38x SoCs. Armada XP/38x SoCs.

View File

@ -18,13 +18,16 @@
#include <dm/lists.h> #include <dm/lists.h>
#include <dm/of_access.h> #include <dm/of_access.h>
#include <pci.h> #include <pci.h>
#include <reset.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/arch/cpu.h> #include <asm/arch/cpu.h>
#include <asm/arch/soc.h> #include <asm/arch/soc.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/mbus.h> #include <linux/mbus.h>
#include <linux/sizes.h>
/* PCIe unit register offsets */ /* PCIe unit register offsets */
#define SELECT(x, n) ((x >> n) & 1UL) #define SELECT(x, n) ((x >> n) & 1UL)
@ -59,6 +62,9 @@
#define PCIE_DEBUG_CTRL 0x1a60 #define PCIE_DEBUG_CTRL 0x1a60
#define PCIE_DEBUG_SOFT_RESET BIT(20) #define PCIE_DEBUG_SOFT_RESET BIT(20)
#define LINK_WAIT_RETRIES 100
#define LINK_WAIT_TIMEOUT 1000
struct mvebu_pcie { struct mvebu_pcie {
struct pci_controller hose; struct pci_controller hose;
void __iomem *base; void __iomem *base;
@ -66,8 +72,10 @@ struct mvebu_pcie {
struct resource mem; struct resource mem;
void __iomem *iobase; void __iomem *iobase;
struct resource io; struct resource io;
u32 intregs;
u32 port; u32 port;
u32 lane; u32 lane;
bool is_x4;
int devfn; int devfn;
u32 lane_mask; u32 lane_mask;
int first_busno; int first_busno;
@ -80,14 +88,6 @@ struct mvebu_pcie {
u32 cfgcache[(0x3c - 0x10) / 4]; u32 cfgcache[(0x3c - 0x10) / 4];
}; };
/*
* MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
* into SoCs address space. Each controller will map 128M of MEM
* and 64K of I/O space when registered.
*/
static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE;
static void __iomem *mvebu_pcie_iobase = (void __iomem *)MBUS_PCI_IO_BASE;
static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie) static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
{ {
u32 val; u32 val;
@ -95,6 +95,23 @@ static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
return !(val & PCIE_STAT_LINK_DOWN); return !(val & PCIE_STAT_LINK_DOWN);
} }
static void mvebu_pcie_wait_for_link(struct mvebu_pcie *pcie)
{
int retries;
/* check if the link is up or not */
for (retries = 0; retries < LINK_WAIT_RETRIES; retries++) {
if (mvebu_pcie_link_up(pcie)) {
printf("%s: Link up\n", pcie->name);
return;
}
udelay(LINK_WAIT_TIMEOUT);
}
printf("%s: Link down\n", pcie->name);
}
static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno) static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno)
{ {
u32 stat; u32 stat;
@ -357,10 +374,63 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
pcie->base + PCIE_BAR_CTRL_OFF(1)); pcie->base + PCIE_BAR_CTRL_OFF(1));
/* Setup BAR[0] to internal registers. */ /* Setup BAR[0] to internal registers. */
writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0)); writel(pcie->intregs, pcie->base + PCIE_BAR_LO_OFF(0));
writel(0, pcie->base + PCIE_BAR_HI_OFF(0)); writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
} }
/* Only enable PCIe link, do not setup it */
static int mvebu_pcie_enable_link(struct mvebu_pcie *pcie, ofnode node)
{
struct reset_ctl rst;
int ret;
ret = reset_get_by_index_nodev(node, 0, &rst);
if (ret == -ENOENT) {
return 0;
} else if (ret < 0) {
printf("%s: cannot get reset controller: %d\n", pcie->name, ret);
return ret;
}
ret = reset_request(&rst);
if (ret) {
printf("%s: cannot request reset controller: %d\n", pcie->name, ret);
return ret;
}
ret = reset_deassert(&rst);
reset_free(&rst);
if (ret) {
printf("%s: cannot enable PCIe port: %d\n", pcie->name, ret);
return ret;
}
return 0;
}
/* Setup PCIe link but do not enable it */
static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie)
{
u32 reg;
/* Setup PCIe controller to Root Complex mode */
reg = readl(pcie->base + PCIE_CTRL_OFF);
reg |= PCIE_CTRL_RC_MODE;
writel(reg, pcie->base + PCIE_CTRL_OFF);
/*
* Set Maximum Link Width to X1 or X4 in Root Port's PCIe Link
* Capability register. This register is defined by PCIe specification
* as read-only but this mvebu controller has it as read-write and must
* be set to number of SerDes PCIe lanes (1 or 4). If this register is
* not set correctly then link with endpoint card is not established.
*/
reg = readl(pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP);
reg &= ~PCI_EXP_LNKCAP_MLW;
reg |= (pcie->is_x4 ? 4 : 1) << 4;
writel(reg, pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP);
}
static int mvebu_pcie_probe(struct udevice *dev) static int mvebu_pcie_probe(struct udevice *dev)
{ {
struct mvebu_pcie *pcie = dev_get_plat(dev); struct mvebu_pcie *pcie = dev_get_plat(dev);
@ -368,11 +438,6 @@ static int mvebu_pcie_probe(struct udevice *dev)
struct pci_controller *hose = dev_get_uclass_priv(ctlr); struct pci_controller *hose = dev_get_uclass_priv(ctlr);
u32 reg; u32 reg;
/* Setup PCIe controller to Root Complex mode */
reg = readl(pcie->base + PCIE_CTRL_OFF);
reg |= PCIE_CTRL_RC_MODE;
writel(reg, pcie->base + PCIE_CTRL_OFF);
/* /*
* Change Class Code of PCI Bridge device to PCI Bridge (0x600400) * Change Class Code of PCI Bridge device to PCI Bridge (0x600400)
* because default value is Memory controller (0x508000) which * because default value is Memory controller (0x508000) which
@ -433,26 +498,26 @@ static int mvebu_pcie_probe(struct udevice *dev)
mvebu_pcie_set_local_bus_nr(pcie, 0); mvebu_pcie_set_local_bus_nr(pcie, 0);
mvebu_pcie_set_local_dev_nr(pcie, 1); mvebu_pcie_set_local_dev_nr(pcie, 1);
pcie->mem.start = (u32)mvebu_pcie_membase; if (resource_size(&pcie->mem) &&
pcie->mem.end = pcie->mem.start + MBUS_PCI_MEM_SIZE - 1; mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
mvebu_pcie_membase += MBUS_PCI_MEM_SIZE;
if (mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
(phys_addr_t)pcie->mem.start, (phys_addr_t)pcie->mem.start,
resource_size(&pcie->mem))) { resource_size(&pcie->mem))) {
printf("PCIe unable to add mbus window for mem at %08x+%08x\n", printf("%s: unable to add mbus window for mem at %08x+%08x\n",
pcie->name,
(u32)pcie->mem.start, (unsigned)resource_size(&pcie->mem)); (u32)pcie->mem.start, (unsigned)resource_size(&pcie->mem));
pcie->mem.start = 0;
pcie->mem.end = -1;
} }
pcie->io.start = (u32)mvebu_pcie_iobase; if (resource_size(&pcie->io) &&
pcie->io.end = pcie->io.start + MBUS_PCI_IO_SIZE - 1; mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
mvebu_pcie_iobase += MBUS_PCI_IO_SIZE;
if (mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
(phys_addr_t)pcie->io.start, (phys_addr_t)pcie->io.start,
resource_size(&pcie->io))) { resource_size(&pcie->io))) {
printf("PCIe unable to add mbus window for IO at %08x+%08x\n", printf("%s: unable to add mbus window for IO at %08x+%08x\n",
pcie->name,
(u32)pcie->io.start, (unsigned)resource_size(&pcie->io)); (u32)pcie->io.start, (unsigned)resource_size(&pcie->io));
pcie->io.start = 0;
pcie->io.end = -1;
} }
/* Setup windows and configure host bridge */ /* Setup windows and configure host bridge */
@ -461,13 +526,23 @@ static int mvebu_pcie_probe(struct udevice *dev)
/* PCI memory space */ /* PCI memory space */
pci_set_region(hose->regions + 0, pcie->mem.start, pci_set_region(hose->regions + 0, pcie->mem.start,
pcie->mem.start, resource_size(&pcie->mem), PCI_REGION_MEM); pcie->mem.start, resource_size(&pcie->mem), PCI_REGION_MEM);
pci_set_region(hose->regions + 1, hose->region_count = 1;
0, 0,
gd->ram_size, if (resource_size(&pcie->mem)) {
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); pci_set_region(hose->regions + hose->region_count,
pci_set_region(hose->regions + 2, pcie->io.start, pcie->mem.start, pcie->mem.start,
pcie->io.start, resource_size(&pcie->io), PCI_REGION_IO); resource_size(&pcie->mem),
hose->region_count = 3; PCI_REGION_MEM);
hose->region_count++;
}
if (resource_size(&pcie->io)) {
pci_set_region(hose->regions + hose->region_count,
pcie->io.start, pcie->io.start,
resource_size(&pcie->io),
PCI_REGION_IO);
hose->region_count++;
}
/* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */ /* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */
pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] = pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] =
@ -475,21 +550,7 @@ static int mvebu_pcie_probe(struct udevice *dev)
pcie->cfgcache[(PCI_PREF_MEMORY_BASE - 0x10) / 4] = pcie->cfgcache[(PCI_PREF_MEMORY_BASE - 0x10) / 4] =
PCI_PREF_RANGE_TYPE_64 | (PCI_PREF_RANGE_TYPE_64 << 16); PCI_PREF_RANGE_TYPE_64 | (PCI_PREF_RANGE_TYPE_64 << 16);
return 0; mvebu_pcie_wait_for_link(pcie);
}
static int mvebu_pcie_port_parse_dt(ofnode node, struct mvebu_pcie *pcie)
{
const u32 *addr;
int len;
addr = ofnode_get_property(node, "assigned-addresses", &len);
if (!addr) {
pr_err("property \"assigned-addresses\" not found");
return -FDT_ERR_NOTFOUND;
}
pcie->base = (void *)(fdt32_to_cpu(addr[2]) + SOC_REGS_PHY_BASE);
return 0; return 0;
} }
@ -554,31 +615,38 @@ static int mvebu_get_tgt_attr(ofnode node, int devfn,
return -ENOENT; return -ENOENT;
} }
static int mvebu_pcie_of_to_plat(struct udevice *dev) static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pcie *pcie)
{ {
struct mvebu_pcie *pcie = dev_get_plat(dev); struct fdt_pci_addr pci_addr;
const u32 *addr;
u32 num_lanes;
int ret = 0; int ret = 0;
int len;
/* Get port number, lane number and memory target / attr */ /* Get port number, lane number and memory target / attr */
if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port", if (ofnode_read_u32(node, "marvell,pcie-port",
&pcie->port)) { &pcie->port)) {
ret = -ENODEV; ret = -ENODEV;
goto err; goto err;
} }
if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-lane", &pcie->lane)) if (ofnode_read_u32(node, "marvell,pcie-lane", &pcie->lane))
pcie->lane = 0; pcie->lane = 0;
sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane); sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane);
/* pci_get_devfn() returns devfn in bits 15..8, see PCI_DEV usage */ if (!ofnode_read_u32(node, "num-lanes", &num_lanes) && num_lanes == 4)
pcie->devfn = pci_get_devfn(dev); pcie->is_x4 = true;
if (pcie->devfn < 0) {
ret = -ENODEV; /* devfn is in bits [15:8], see PCI_DEV usage */
ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr);
if (ret < 0) {
printf("%s: property \"reg\" is invalid\n", pcie->name);
goto err; goto err;
} }
pcie->devfn = pci_addr.phys_hi & 0xff00;
ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn, ret = mvebu_get_tgt_attr(parent, pcie->devfn,
IORESOURCE_MEM, IORESOURCE_MEM,
&pcie->mem_target, &pcie->mem_attr); &pcie->mem_target, &pcie->mem_attr);
if (ret < 0) { if (ret < 0) {
@ -586,7 +654,7 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev)
goto err; goto err;
} }
ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn, ret = mvebu_get_tgt_attr(parent, pcie->devfn,
IORESOURCE_IO, IORESOURCE_IO,
&pcie->io_target, &pcie->io_attr); &pcie->io_target, &pcie->io_attr);
if (ret < 0) { if (ret < 0) {
@ -595,9 +663,15 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev)
} }
/* Parse PCIe controller register base from DT */ /* Parse PCIe controller register base from DT */
ret = mvebu_pcie_port_parse_dt(dev_ofnode(dev), pcie); addr = ofnode_get_property(node, "assigned-addresses", &len);
if (ret < 0) if (!addr) {
printf("%s: property \"assigned-addresses\" not found\n", pcie->name);
ret = -FDT_ERR_NOTFOUND;
goto err; goto err;
}
pcie->base = (void *)(u32)ofnode_translate_address(node, addr);
pcie->intregs = (u32)pcie->base - fdt32_to_cpu(addr[2]);
return 0; return 0;
@ -615,7 +689,6 @@ static struct driver pcie_mvebu_drv = {
.id = UCLASS_PCI, .id = UCLASS_PCI,
.ops = &mvebu_pcie_ops, .ops = &mvebu_pcie_ops,
.probe = mvebu_pcie_probe, .probe = mvebu_pcie_probe,
.of_to_plat = mvebu_pcie_of_to_plat,
.plat_auto = sizeof(struct mvebu_pcie), .plat_auto = sizeof(struct mvebu_pcie),
}; };
@ -625,9 +698,14 @@ static struct driver pcie_mvebu_drv = {
*/ */
static int mvebu_pcie_bind(struct udevice *parent) static int mvebu_pcie_bind(struct udevice *parent)
{ {
struct mvebu_pcie **ports_pcie;
struct mvebu_pcie *pcie; struct mvebu_pcie *pcie;
struct uclass_driver *drv; struct uclass_driver *drv;
struct udevice *dev; struct udevice *dev;
struct resource mem;
struct resource io;
int ports_count, i;
ofnode *ports_nodes;
ofnode subnode; ofnode subnode;
/* Lookup pci driver */ /* Lookup pci driver */
@ -637,19 +715,94 @@ static int mvebu_pcie_bind(struct udevice *parent)
return -ENOENT; return -ENOENT;
} }
ports_count = ofnode_get_child_count(dev_ofnode(parent));
ports_pcie = calloc(ports_count, sizeof(*ports_pcie));
ports_nodes = calloc(ports_count, sizeof(*ports_nodes));
if (!ports_pcie || !ports_nodes) {
free(ports_pcie);
free(ports_nodes);
return -ENOMEM;
}
ports_count = 0;
mem.start = MBUS_PCI_MEM_BASE;
mem.end = MBUS_PCI_MEM_BASE + MBUS_PCI_MEM_SIZE - 1;
io.start = MBUS_PCI_IO_BASE;
io.end = MBUS_PCI_IO_BASE + MBUS_PCI_IO_SIZE - 1;
/* First phase: Fill mvebu_pcie struct for each port */
ofnode_for_each_subnode(subnode, dev_ofnode(parent)) { ofnode_for_each_subnode(subnode, dev_ofnode(parent)) {
if (!ofnode_is_available(subnode)) if (!ofnode_is_available(subnode))
continue; continue;
pcie = calloc(1, sizeof(*pcie)); pcie = calloc(1, sizeof(*pcie));
if (!pcie) if (!pcie)
return -ENOMEM; continue;
if (mvebu_pcie_port_parse_dt(subnode, dev_ofnode(parent), pcie) < 0) {
free(pcie);
continue;
}
/*
* MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
* into SoCs address space. Each controller will map 128M of MEM
* and 64K of I/O space when registered.
*/
if (resource_size(&mem) >= SZ_128M) {
pcie->mem.start = mem.start;
pcie->mem.end = mem.start + SZ_128M - 1;
mem.start += SZ_128M;
} else {
printf("%s: unable to assign mbus window for mem\n", pcie->name);
pcie->mem.start = 0;
pcie->mem.end = -1;
}
if (resource_size(&io) >= SZ_64K) {
pcie->io.start = io.start;
pcie->io.end = io.start + SZ_64K - 1;
io.start += SZ_64K;
} else {
printf("%s: unable to assign mbus window for io\n", pcie->name);
pcie->io.start = 0;
pcie->io.end = -1;
}
ports_pcie[ports_count] = pcie;
ports_nodes[ports_count] = subnode;
ports_count++;
}
/* Second phase: Setup all PCIe links (do not enable them yet) */
for (i = 0; i < ports_count; i++)
mvebu_pcie_setup_link(ports_pcie[i]);
/* Third phase: Enable all PCIe links and create for each UCLASS_PCI device */
for (i = 0; i < ports_count; i++) {
pcie = ports_pcie[i];
subnode = ports_nodes[i];
/*
* PCIe link can be enabled only after all PCIe links were
* properly configured. This is because more PCIe links shares
* one enable bit and some PCIe links cannot be enabled
* individually.
*/
if (mvebu_pcie_enable_link(pcie, subnode) < 0) {
free(pcie);
continue;
}
/* Create child device UCLASS_PCI and bind it */ /* Create child device UCLASS_PCI and bind it */
device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode, device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode,
&dev); &dev);
} }
free(ports_pcie);
free(ports_nodes);
return 0; return 0;
} }

View File

@ -53,7 +53,7 @@
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_SIZE (140 << 10) #define CONFIG_SPL_SIZE (140 << 10)
#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) #define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE)
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -32,22 +32,9 @@
*/ */
#include "mv-common.h" #include "mv-common.h"
/*
* Memory layout while starting into the bin_hdr via the
* BootROM:
*
* 0x4000.4000 - 0x4003.4000 headers space (192KiB)
* 0x4000.4030 bin_hdr start address
* 0x4003.4000 - 0x4004.7c00 BootROM memory allocations (15KiB)
* 0x4007.fffc BootROM stack top
*
* The address space between 0x4007.fffc and 0x400f.fff is not locked in
* L2 cache thus cannot be used.
*/
/* SPL */ /* SPL */
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x4030) #define CONFIG_SPL_MAX_SIZE ((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10))
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -41,7 +41,7 @@
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_SIZE (140 << 10) #define CONFIG_SPL_SIZE (140 << 10)
#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) #define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE)
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -50,7 +50,7 @@
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_SIZE (140 << 10) #define CONFIG_SPL_SIZE (140 << 10)
#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) #define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE)
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -59,7 +59,7 @@
/* SPL */ /* SPL */
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x4030) #define CONFIG_SPL_MAX_SIZE ((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10))
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -45,7 +45,7 @@
/* SPL */ /* SPL */
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x4030) #define CONFIG_SPL_MAX_SIZE ((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10))
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -53,7 +53,7 @@
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_SIZE (140 << 10) #define CONFIG_SPL_SIZE (140 << 10)
#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) #define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE)
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -48,7 +48,7 @@
/* SPL */ /* SPL */
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x4030) #define CONFIG_SPL_MAX_SIZE ((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10))
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -77,7 +77,7 @@
/* SPL */ /* SPL */
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x4030) #define CONFIG_SPL_MAX_SIZE ((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10))
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -28,7 +28,7 @@
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_SIZE (140 << 10) #define CONFIG_SPL_SIZE (140 << 10)
#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) #define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE)
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -68,7 +68,7 @@
/* Defines for SPL */ /* Defines for SPL */
#define CONFIG_SPL_SIZE (140 << 10) #define CONFIG_SPL_SIZE (140 << 10)
#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) #define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE)
#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)

View File

@ -99,6 +99,7 @@ enum image_cfg_type {
IMAGE_CFG_NAND_BADBLK_LOCATION, IMAGE_CFG_NAND_BADBLK_LOCATION,
IMAGE_CFG_NAND_ECC_MODE, IMAGE_CFG_NAND_ECC_MODE,
IMAGE_CFG_NAND_PAGESZ, IMAGE_CFG_NAND_PAGESZ,
IMAGE_CFG_CPU,
IMAGE_CFG_BINARY, IMAGE_CFG_BINARY,
IMAGE_CFG_DATA, IMAGE_CFG_DATA,
IMAGE_CFG_DATA_DELAY, IMAGE_CFG_DATA_DELAY,
@ -129,6 +130,7 @@ static const char * const id_strs[] = {
[IMAGE_CFG_NAND_BADBLK_LOCATION] = "NAND_BADBLK_LOCATION", [IMAGE_CFG_NAND_BADBLK_LOCATION] = "NAND_BADBLK_LOCATION",
[IMAGE_CFG_NAND_ECC_MODE] = "NAND_ECC_MODE", [IMAGE_CFG_NAND_ECC_MODE] = "NAND_ECC_MODE",
[IMAGE_CFG_NAND_PAGESZ] = "NAND_PAGE_SIZE", [IMAGE_CFG_NAND_PAGESZ] = "NAND_PAGE_SIZE",
[IMAGE_CFG_CPU] = "CPU",
[IMAGE_CFG_BINARY] = "BINARY", [IMAGE_CFG_BINARY] = "BINARY",
[IMAGE_CFG_DATA] = "DATA", [IMAGE_CFG_DATA] = "DATA",
[IMAGE_CFG_DATA_DELAY] = "DATA_DELAY", [IMAGE_CFG_DATA_DELAY] = "DATA_DELAY",
@ -152,9 +154,11 @@ struct image_cfg_element {
enum image_cfg_type type; enum image_cfg_type type;
union { union {
unsigned int version; unsigned int version;
unsigned int cpu_sheeva;
unsigned int bootfrom; unsigned int bootfrom;
struct { struct {
const char *file; const char *file;
unsigned int loadaddr;
unsigned int args[BINARY_MAX_ARGS]; unsigned int args[BINARY_MAX_ARGS];
unsigned int nargs; unsigned int nargs;
} binary; } binary;
@ -199,7 +203,7 @@ static const char *image_boot_mode_name(unsigned int id)
return NULL; return NULL;
} }
int image_boot_mode_id(const char *boot_mode_name) static int image_boot_mode_id(const char *boot_mode_name)
{ {
int i; int i;
@ -210,7 +214,18 @@ int image_boot_mode_id(const char *boot_mode_name)
return -1; return -1;
} }
int image_nand_ecc_mode_id(const char *nand_ecc_mode_name) static const char *image_nand_ecc_mode_name(unsigned int id)
{
int i;
for (i = 0; nand_ecc_modes[i].name; i++)
if (nand_ecc_modes[i].id == id)
return nand_ecc_modes[i].name;
return NULL;
}
static int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
{ {
int i; int i;
@ -280,6 +295,17 @@ static int image_get_bootfrom(void)
return e->bootfrom; return e->bootfrom;
} }
static int image_is_cpu_sheeva(void)
{
struct image_cfg_element *e;
e = image_find_option(IMAGE_CFG_CPU);
if (!e)
return 0;
return e->cpu_sheeva;
}
/* /*
* Compute a 8-bit checksum of a memory area. This algorithm follows * Compute a 8-bit checksum of a memory area. This algorithm follows
* the requirements of the Marvell SoC BootROM specifications. * the requirements of the Marvell SoC BootROM specifications.
@ -344,6 +370,29 @@ static uint32_t image_checksum32(void *start, uint32_t len)
return csum; return csum;
} }
static unsigned int options_to_baudrate(uint8_t options)
{
switch (options & 0x7) {
case MAIN_HDR_V1_OPT_BAUD_2400:
return 2400;
case MAIN_HDR_V1_OPT_BAUD_4800:
return 4800;
case MAIN_HDR_V1_OPT_BAUD_9600:
return 9600;
case MAIN_HDR_V1_OPT_BAUD_19200:
return 19200;
case MAIN_HDR_V1_OPT_BAUD_38400:
return 38400;
case MAIN_HDR_V1_OPT_BAUD_57600:
return 57600;
case MAIN_HDR_V1_OPT_BAUD_115200:
return 115200;
case MAIN_HDR_V1_OPT_BAUD_DEFAULT:
default:
return 0;
}
}
static uint8_t baudrate_to_option(unsigned int baudrate) static uint8_t baudrate_to_option(unsigned int baudrate)
{ {
switch (baudrate) { switch (baudrate) {
@ -602,7 +651,8 @@ static int kwb_export_pubkey(RSA *key, struct pubkey_der_v1 *dst, FILE *hashf,
return 0; return 0;
} }
int kwb_sign(RSA *key, void *data, int datasz, struct sig_v1 *sig, char *signame) static int kwb_sign(RSA *key, void *data, int datasz, struct sig_v1 *sig,
char *signame)
{ {
EVP_PKEY *evp_key; EVP_PKEY *evp_key;
EVP_MD_CTX *ctx; EVP_MD_CTX *ctx;
@ -662,7 +712,7 @@ err_key:
return ret; return ret;
} }
int kwb_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig, static int kwb_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig,
char *signame) char *signame)
{ {
EVP_PKEY *evp_key; EVP_PKEY *evp_key;
@ -722,8 +772,8 @@ err_key:
return ret; return ret;
} }
int kwb_sign_and_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig, static int kwb_sign_and_verify(RSA *key, void *data, int datasz,
char *signame) struct sig_v1 *sig, char *signame)
{ {
if (kwb_sign(key, data, datasz, sig, signame) < 0) if (kwb_sign(key, data, datasz, sig, signame) < 0)
return -1; return -1;
@ -735,7 +785,7 @@ int kwb_sign_and_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig,
} }
int kwb_dump_fuse_cmds_38x(FILE *out, struct secure_hdr_v1 *sec_hdr) static int kwb_dump_fuse_cmds_38x(FILE *out, struct secure_hdr_v1 *sec_hdr)
{ {
struct hash_v1 kak_pub_hash; struct hash_v1 kak_pub_hash;
struct image_cfg_element *e; struct image_cfg_element *e;
@ -992,10 +1042,13 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
static size_t image_headersz_v1(int *hasext) static size_t image_headersz_v1(int *hasext)
{ {
struct image_cfg_element *binarye; struct image_cfg_element *e;
unsigned int count; unsigned int count;
size_t headersz; size_t headersz;
int cpu_sheeva;
struct stat s;
int cfgi; int cfgi;
int ret;
/* /*
* Calculate the size of the header and the size of the * Calculate the size of the header and the size of the
@ -1009,19 +1062,25 @@ static size_t image_headersz_v1(int *hasext)
*hasext = 1; *hasext = 1;
} }
count = image_count_options(IMAGE_CFG_DATA); cpu_sheeva = image_is_cpu_sheeva();
if (count > 0)
headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4;
count = 0;
for (cfgi = 0; cfgi < cfgn; cfgi++) { for (cfgi = 0; cfgi < cfgn; cfgi++) {
int ret; e = &image_cfg[cfgi];
struct stat s;
binarye = &image_cfg[cfgi]; if (e->type == IMAGE_CFG_DATA)
if (binarye->type != IMAGE_CFG_BINARY) count++;
if (e->type == IMAGE_CFG_DATA_DELAY ||
(e->type == IMAGE_CFG_BINARY && count > 0)) {
headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4;
count = 0;
}
if (e->type != IMAGE_CFG_BINARY)
continue; continue;
ret = stat(binarye->binary.file, &s); ret = stat(e->binary.file, &s);
if (ret < 0) { if (ret < 0) {
char cwd[PATH_MAX]; char cwd[PATH_MAX];
char *dir = cwd; char *dir = cwd;
@ -1036,30 +1095,74 @@ static size_t image_headersz_v1(int *hasext)
"Didn't find the file '%s' in '%s' which is mandatory to generate the image\n" "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
"This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n" "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
"image for your board. Use 'dumpimage -T kwbimage -p 0' to extract it from an existing image.\n", "image for your board. Use 'dumpimage -T kwbimage -p 0' to extract it from an existing image.\n",
binarye->binary.file, dir); e->binary.file, dir);
return 0; return 0;
} }
headersz += sizeof(struct opt_hdr_v1) + sizeof(uint32_t) + headersz += sizeof(struct opt_hdr_v1) + sizeof(uint32_t) +
(binarye->binary.nargs) * sizeof(uint32_t); (e->binary.nargs) * sizeof(uint32_t);
if (e->binary.loadaddr) {
/*
* BootROM loads kwbimage header (in which the
* executable code is also stored) to address
* 0x40004000 or 0x40000000. Thus there is
* restriction for the load address of the N-th
* BINARY image.
*/
unsigned int base_addr, low_addr, high_addr;
base_addr = cpu_sheeva ? 0x40004000 : 0x40000000;
low_addr = base_addr + headersz;
high_addr = low_addr +
(BINARY_MAX_ARGS - e->binary.nargs) * sizeof(uint32_t);
if (cpu_sheeva && e->binary.loadaddr % 16) {
fprintf(stderr,
"Invalid LOAD_ADDRESS 0x%08x for BINARY %s with %d args.\n"
"Address for CPU SHEEVA must be 16-byte aligned.\n",
e->binary.loadaddr, e->binary.file, e->binary.nargs);
return 0;
}
if (e->binary.loadaddr % 4 || e->binary.loadaddr < low_addr ||
e->binary.loadaddr > high_addr) {
fprintf(stderr,
"Invalid LOAD_ADDRESS 0x%08x for BINARY %s with %d args.\n"
"Address must be 4-byte aligned and in range 0x%08x-0x%08x.\n",
e->binary.loadaddr, e->binary.file,
e->binary.nargs, low_addr, high_addr);
return 0;
}
headersz = e->binary.loadaddr - base_addr;
} else if (cpu_sheeva) {
headersz = ALIGN(headersz, 16); headersz = ALIGN(headersz, 16);
} else {
headersz = ALIGN(headersz, 4);
}
headersz += ALIGN(s.st_size, 4) + sizeof(uint32_t); headersz += ALIGN(s.st_size, 4) + sizeof(uint32_t);
if (hasext) if (hasext)
*hasext = 1; *hasext = 1;
} }
if (count > 0)
headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4;
return image_headersz_align(headersz, image_get_bootfrom()); return image_headersz_align(headersz, image_get_bootfrom());
} }
int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, static int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext,
struct image_cfg_element *binarye, struct image_cfg_element *binarye,
struct main_hdr_v1 *main_hdr) struct main_hdr_v1 *main_hdr)
{ {
struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)*cur; struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)*cur;
uint32_t base_addr;
uint32_t add_args; uint32_t add_args;
uint32_t offset; uint32_t offset;
uint32_t *args; uint32_t *args;
size_t binhdrsz; size_t binhdrsz;
int cpu_sheeva;
struct stat s; struct stat s;
int argi; int argi;
FILE *bin; FILE *bin;
@ -1091,13 +1194,22 @@ int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext,
*cur += (binarye->binary.nargs + 1) * sizeof(uint32_t); *cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
/* /*
* ARM executable code inside the BIN header on some mvebu platforms * ARM executable code inside the BIN header on platforms with Sheeva
* (e.g. A370, AXP) must always be aligned with the 128-bit boundary. * CPU (A370 and AXP) must always be aligned with the 128-bit boundary.
* In the case when this code is not position independent (e.g. ARM
* SPL), it must be placed at fixed load and execute address.
* This requirement can be met by inserting dummy arguments into * This requirement can be met by inserting dummy arguments into
* BIN header, if needed. * BIN header, if needed.
*/ */
cpu_sheeva = image_is_cpu_sheeva();
base_addr = cpu_sheeva ? 0x40004000 : 0x40000000;
offset = *cur - (uint8_t *)main_hdr; offset = *cur - (uint8_t *)main_hdr;
if (binarye->binary.loadaddr)
add_args = (binarye->binary.loadaddr - base_addr - offset) / sizeof(uint32_t);
else if (cpu_sheeva)
add_args = ((16 - offset % 16) % 16) / sizeof(uint32_t); add_args = ((16 - offset % 16) % 16) / sizeof(uint32_t);
else
add_args = 0;
if (add_args) { if (add_args) {
*(args - 1) = cpu_to_le32(binarye->binary.nargs + add_args); *(args - 1) = cpu_to_le32(binarye->binary.nargs + add_args);
*cur += add_args * sizeof(uint32_t); *cur += add_args * sizeof(uint32_t);
@ -1135,7 +1247,7 @@ err_close:
return -1; return -1;
} }
int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr) static int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr)
{ {
FILE *hashf; FILE *hashf;
int res; int res;
@ -1154,7 +1266,7 @@ int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr)
return res < 0 ? 1 : 0; return res < 0 ? 1 : 0;
} }
int kwb_sign_csk_with_kak(struct image_tool_params *params, static int kwb_sign_csk_with_kak(struct image_tool_params *params,
struct secure_hdr_v1 *secure_hdr, RSA *csk) struct secure_hdr_v1 *secure_hdr, RSA *csk)
{ {
RSA *kak = NULL; RSA *kak = NULL;
@ -1196,7 +1308,7 @@ int kwb_sign_csk_with_kak(struct image_tool_params *params,
return 0; return 0;
} }
int add_secure_header_v1(struct image_tool_params *params, uint8_t *ptr, static int add_secure_header_v1(struct image_tool_params *params, uint8_t *ptr,
int payloadsz, size_t headersz, uint8_t *image, int payloadsz, size_t headersz, uint8_t *image,
struct secure_hdr_v1 *secure_hdr) struct secure_hdr_v1 *secure_hdr)
{ {
@ -1248,6 +1360,22 @@ int add_secure_header_v1(struct image_tool_params *params, uint8_t *ptr,
return 0; return 0;
} }
static void finish_register_set_header_v1(uint8_t **cur, uint8_t **next_ext,
struct register_set_hdr_v1 *register_set_hdr,
int *datai, uint8_t delay)
{
int size = sizeof(struct register_set_hdr_v1) + 8 * (*datai) + 4;
register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE;
register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF);
register_set_hdr->headersz_msb = size >> 16;
register_set_hdr->data[*datai].last_entry.delay = delay;
*cur += size;
**next_ext = 1;
*next_ext = &register_set_hdr->data[*datai].last_entry.next;
*datai = 0;
}
static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
uint8_t *ptr, int payloadsz) uint8_t *ptr, int payloadsz)
{ {
@ -1260,7 +1388,8 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
uint8_t *image, *cur; uint8_t *image, *cur;
int hasext = 0; int hasext = 0;
uint8_t *next_ext = NULL; uint8_t *next_ext = NULL;
int cfgi, datai, size; int cfgi, datai;
uint8_t delay;
/* /*
* Calculate the size of the header and the size of the * Calculate the size of the header and the size of the
@ -1351,50 +1480,54 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
} }
datai = 0; datai = 0;
register_set_hdr = (struct register_set_hdr_v1 *)cur;
for (cfgi = 0; cfgi < cfgn; cfgi++) { for (cfgi = 0; cfgi < cfgn; cfgi++) {
e = &image_cfg[cfgi]; e = &image_cfg[cfgi];
if (e->type != IMAGE_CFG_DATA && if (e->type != IMAGE_CFG_DATA &&
e->type != IMAGE_CFG_DATA_DELAY) e->type != IMAGE_CFG_DATA_DELAY &&
e->type != IMAGE_CFG_BINARY)
continue; continue;
if (e->type == IMAGE_CFG_DATA_DELAY) {
size = sizeof(struct register_set_hdr_v1) + 8 * datai + 4; if (datai == 0)
register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE; register_set_hdr = (struct register_set_hdr_v1 *)cur;
register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF);
register_set_hdr->headersz_msb = size >> 16; /* If delay is not specified, use the smallest possible value. */
register_set_hdr->data[datai].last_entry.delay = e->regdata_delay; if (e->type == IMAGE_CFG_DATA_DELAY)
cur += size; delay = e->regdata_delay;
*next_ext = 1; else
next_ext = &register_set_hdr->data[datai].last_entry.next; delay = REGISTER_SET_HDR_OPT_DELAY_MS(0);
datai = 0;
continue; /*
} * DATA_DELAY command is the last entry in the register set
* header and BINARY command inserts new binary header.
* Therefore BINARY command requires to finish register set
* header if some DATA command was specified. And DATA_DELAY
* command automatically finish register set header even when
* there was no DATA command.
*/
if (e->type == IMAGE_CFG_DATA_DELAY ||
(e->type == IMAGE_CFG_BINARY && datai != 0))
finish_register_set_header_v1(&cur, &next_ext, register_set_hdr,
&datai, delay);
if (e->type == IMAGE_CFG_DATA) {
register_set_hdr->data[datai].entry.address = register_set_hdr->data[datai].entry.address =
cpu_to_le32(e->regdata.raddr); cpu_to_le32(e->regdata.raddr);
register_set_hdr->data[datai].entry.value = register_set_hdr->data[datai].entry.value =
cpu_to_le32(e->regdata.rdata); cpu_to_le32(e->regdata.rdata);
datai++; datai++;
} }
if (datai != 0) {
size = sizeof(struct register_set_hdr_v1) + 8 * datai + 4;
register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE;
register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF);
register_set_hdr->headersz_msb = size >> 16;
/* Set delay to the smallest possible value 1ms. */
register_set_hdr->data[datai].last_entry.delay = 1;
cur += size;
*next_ext = 1;
next_ext = &register_set_hdr->data[datai].last_entry.next;
}
for (cfgi = 0; cfgi < cfgn; cfgi++) {
e = &image_cfg[cfgi];
if (e->type != IMAGE_CFG_BINARY)
continue;
if (e->type == IMAGE_CFG_BINARY) {
if (add_binary_header_v1(&cur, &next_ext, e, main_hdr)) if (add_binary_header_v1(&cur, &next_ext, e, main_hdr))
return NULL; return NULL;
} }
}
if (datai != 0) {
/* Set delay to the smallest possible value. */
delay = REGISTER_SET_HDR_OPT_DELAY_MS(0);
finish_register_set_header_v1(&cur, &next_ext, register_set_hdr,
&datai, delay);
}
if (secure_hdr && add_secure_header_v1(params, ptr, payloadsz + headersz, if (secure_hdr && add_secure_header_v1(params, ptr, payloadsz + headersz,
headersz, image, secure_hdr)) headersz, image, secure_hdr))
@ -1415,7 +1548,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
return image; return image;
} }
int recognize_keyword(char *keyword) static int recognize_keyword(char *keyword)
{ {
int kw_id; int kw_id;
@ -1455,6 +1588,18 @@ static int image_create_config_parse_oneline(char *line,
case IMAGE_CFG_VERSION: case IMAGE_CFG_VERSION:
el->version = atoi(value1); el->version = atoi(value1);
break; break;
case IMAGE_CFG_CPU:
if (strcmp(value1, "FEROCEON") == 0)
el->cpu_sheeva = 0;
else if (strcmp(value1, "SHEEVA") == 0)
el->cpu_sheeva = 1;
else if (strcmp(value1, "A9") == 0)
el->cpu_sheeva = 0;
else {
fprintf(stderr, "Invalid CPU %s\n", value1);
return -1;
}
break;
case IMAGE_CFG_BOOT_FROM: case IMAGE_CFG_BOOT_FROM:
ret = image_boot_mode_id(value1); ret = image_boot_mode_id(value1);
@ -1488,10 +1633,40 @@ static int image_create_config_parse_oneline(char *line,
el->binary.file = strdup(value1); el->binary.file = strdup(value1);
while (1) { while (1) {
char *value = strtok_r(NULL, delimiters, &saveptr); char *value = strtok_r(NULL, delimiters, &saveptr);
char *endptr;
if (!value) if (!value)
break; break;
el->binary.args[argi] = strtoul(value, NULL, 16);
if (!strcmp(value, "LOAD_ADDRESS")) {
value = strtok_r(NULL, delimiters, &saveptr);
if (!value) {
fprintf(stderr,
"Missing address argument for BINARY LOAD_ADDRESS\n");
return -1;
}
el->binary.loadaddr = strtoul(value, &endptr, 16);
if (*endptr) {
fprintf(stderr,
"Invalid argument '%s' for BINARY LOAD_ADDRESS\n",
value);
return -1;
}
value = strtok_r(NULL, delimiters, &saveptr);
if (value) {
fprintf(stderr,
"Unexpected argument '%s' after BINARY LOAD_ADDRESS\n",
value);
return -1;
}
break;
}
el->binary.args[argi] = strtoul(value, &endptr, 16);
if (*endptr) {
fprintf(stderr, "Invalid argument '%s' for BINARY\n", value);
return -1;
}
argi++; argi++;
if (argi >= BINARY_MAX_ARGS) { if (argi >= BINARY_MAX_ARGS) {
fprintf(stderr, fprintf(stderr,
@ -1518,6 +1693,10 @@ static int image_create_config_parse_oneline(char *line,
el->regdata_delay = REGISTER_SET_HDR_OPT_DELAY_SDRAM_SETUP; el->regdata_delay = REGISTER_SET_HDR_OPT_DELAY_SDRAM_SETUP;
else else
el->regdata_delay = REGISTER_SET_HDR_OPT_DELAY_MS(strtoul(value1, NULL, 10)); el->regdata_delay = REGISTER_SET_HDR_OPT_DELAY_MS(strtoul(value1, NULL, 10));
if (el->regdata_delay > 255) {
fprintf(stderr, "Maximal DATA_DELAY is 255\n");
return -1;
}
break; break;
case IMAGE_CFG_BAUDRATE: case IMAGE_CFG_BAUDRATE:
el->baudrate = strtoul(value1, NULL, 10); el->baudrate = strtoul(value1, NULL, 10);
@ -1727,9 +1906,12 @@ static void kwbimage_print_header(const void *ptr)
for_each_opt_hdr_v1 (ohdr, mhdr) { for_each_opt_hdr_v1 (ohdr, mhdr) {
if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) { if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
printf("BIN Hdr Size: "); printf("BIN Img Size: ");
genimg_print_size(opt_hdr_v1_size(ohdr) - 12 - genimg_print_size(opt_hdr_v1_size(ohdr) - 12 -
4 * ohdr->data[0]); 4 * ohdr->data[0]);
printf("BIN Img Offs: %08x\n",
(unsigned)((uint8_t *)ohdr - (uint8_t *)mhdr) +
8 + 4 * ohdr->data[0]);
} }
} }
@ -1766,7 +1948,7 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size,
if (kwbimage_version(ptr) == 0) { if (kwbimage_version(ptr) == 0) {
struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr; struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
if (mhdr->ext & 0x1) { if (mhdr->ext) {
struct ext_hdr_v0 *ext_hdr = (void *)(mhdr + 1); struct ext_hdr_v0 *ext_hdr = (void *)(mhdr + 1);
csum = image_checksum8(ext_hdr, sizeof(*ext_hdr) - 1); csum = image_checksum8(ext_hdr, sizeof(*ext_hdr) - 1);
@ -1892,6 +2074,15 @@ static int kwbimage_generate(struct image_tool_params *params,
case 1: case 1:
alloc_len = image_headersz_v1(NULL); alloc_len = image_headersz_v1(NULL);
if (!alloc_len) {
free(image_cfg);
exit(EXIT_FAILURE);
}
if (alloc_len > 192*1024) {
fprintf(stderr, "Header is too big (%u bytes), maximal kwbimage header size is %u bytes\n", alloc_len, 192*1024);
free(image_cfg);
exit(EXIT_FAILURE);
}
break; break;
default: default:
@ -1931,35 +2122,164 @@ static int kwbimage_generate(struct image_tool_params *params,
return 4 + (4 - s.st_size % 4) % 4; return 4 + (4 - s.st_size % 4) % 4;
} }
static int kwbimage_generate_config(void *ptr, struct image_tool_params *params)
{
struct main_hdr_v0 *mhdr0 = (struct main_hdr_v0 *)ptr;
struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
size_t header_size = kwbheader_size(ptr);
struct register_set_hdr_v1 *regset_hdr;
struct ext_hdr_v0_reg *regdata;
struct ext_hdr_v0 *ehdr0;
struct opt_hdr_v1 *ohdr;
unsigned offset;
int cur_idx;
int version;
FILE *f;
int i;
f = fopen(params->outfile, "w");
if (!f) {
fprintf(stderr, "Can't open \"%s\": %s\n", params->outfile, strerror(errno));
return -1;
}
version = kwbimage_version(ptr);
if (version != 0)
fprintf(f, "VERSION %d\n", version);
fprintf(f, "BOOT_FROM %s\n", image_boot_mode_name(mhdr->blockid) ?: "<unknown>");
if (version == 0 && mhdr->blockid == IBR_HDR_NAND_ID)
fprintf(f, "NAND_ECC_MODE %s\n", image_nand_ecc_mode_name(mhdr0->nandeccmode));
if (mhdr->blockid == IBR_HDR_NAND_ID)
fprintf(f, "NAND_PAGE_SIZE 0x%x\n", (unsigned)mhdr->nandpagesize);
if (version != 0 && mhdr->blockid == IBR_HDR_NAND_ID) {
fprintf(f, "NAND_BLKSZ 0x%x\n", (unsigned)mhdr->nandblocksize);
fprintf(f, "NAND_BADBLK_LOCATION 0x%x\n", (unsigned)mhdr->nandbadblklocation);
}
if (version == 0 && mhdr->blockid == IBR_HDR_SATA_ID)
fprintf(f, "SATA_PIO_MODE %u\n", (unsigned)mhdr0->satapiomode);
/*
* Addresses and sizes which are specified by mkimage command line
* arguments and not in kwbimage config file
*/
if (version != 0)
fprintf(f, "#HEADER_SIZE 0x%x\n",
((unsigned)mhdr->headersz_msb << 8) | le16_to_cpu(mhdr->headersz_lsb));
fprintf(f, "#SRC_ADDRESS 0x%x\n", le32_to_cpu(mhdr->srcaddr));
fprintf(f, "#BLOCK_SIZE 0x%x\n", le32_to_cpu(mhdr->blocksize));
fprintf(f, "#DEST_ADDRESS 0x%08x\n", le32_to_cpu(mhdr->destaddr));
fprintf(f, "#EXEC_ADDRESS 0x%08x\n", le32_to_cpu(mhdr->execaddr));
if (version != 0) {
if (options_to_baudrate(mhdr->options))
fprintf(f, "BAUDRATE %u\n", options_to_baudrate(mhdr->options));
if (options_to_baudrate(mhdr->options) ||
((mhdr->options >> 3) & 0x3) || ((mhdr->options >> 5) & 0x7)) {
fprintf(f, "UART_PORT %u\n", (unsigned)((mhdr->options >> 3) & 0x3));
fprintf(f, "UART_MPP 0x%x\n", (unsigned)((mhdr->options >> 5) & 0x7));
}
if (mhdr->flags & 0x1)
fprintf(f, "DEBUG 1\n");
}
cur_idx = 1;
for_each_opt_hdr_v1(ohdr, ptr) {
if (ohdr->headertype == OPT_HDR_V1_SECURE_TYPE) {
fprintf(f, "#SECURE_HEADER\n");
} else if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
fprintf(f, "BINARY binary%d.bin", cur_idx);
for (i = 0; i < ohdr->data[0]; i++)
fprintf(f, " 0x%x", le32_to_cpu(((uint32_t *)ohdr->data)[i + 1]));
offset = (unsigned)((uint8_t *)ohdr - (uint8_t *)mhdr) + 8 + 4 * ohdr->data[0];
fprintf(f, " LOAD_ADDRESS 0x%08x\n", 0x40000000 + offset);
fprintf(f, " # for CPU SHEEVA: LOAD_ADDRESS 0x%08x\n", 0x40004000 + offset);
cur_idx++;
} else if (ohdr->headertype == OPT_HDR_V1_REGISTER_TYPE) {
regset_hdr = (struct register_set_hdr_v1 *)ohdr;
for (i = 0;
i < opt_hdr_v1_size(ohdr) - sizeof(struct opt_hdr_v1) -
sizeof(regset_hdr->data[0].last_entry);
i++)
fprintf(f, "DATA 0x%08x 0x%08x\n",
le32_to_cpu(regset_hdr->data[i].entry.address),
le32_to_cpu(regset_hdr->data[i].entry.value));
if (opt_hdr_v1_size(ohdr) - sizeof(struct opt_hdr_v1) >=
sizeof(regset_hdr->data[0].last_entry)) {
if (regset_hdr->data[0].last_entry.delay)
fprintf(f, "DATA_DELAY %u\n",
(unsigned)regset_hdr->data[0].last_entry.delay);
else
fprintf(f, "DATA_DELAY SDRAM_SETUP\n");
}
}
}
if (version == 0 && mhdr0->ext) {
ehdr0 = (struct ext_hdr_v0 *)(mhdr0 + 1);
if (ehdr0->offset) {
for (regdata = (struct ext_hdr_v0_reg *)((uint8_t *)ptr + ehdr0->offset);
(uint8_t *)regdata < (uint8_t *)ptr + header_size && regdata->raddr &&
regdata->rdata;
regdata++)
fprintf(f, "DATA 0x%08x 0x%08x\n", le32_to_cpu(regdata->raddr),
le32_to_cpu(regdata->rdata));
}
}
if (version == 0 && le16_to_cpu(mhdr0->ddrinitdelay))
fprintf(f, "DDR_INIT_DELAY %u\n", (unsigned)le16_to_cpu(mhdr0->ddrinitdelay));
/* Undocumented reserved fields */
if (version == 0 && (mhdr0->rsvd1[0] || mhdr0->rsvd1[1] || mhdr0->rsvd1[2]))
fprintf(f, "#RSVD1 0x%x 0x%x 0x%x\n", (unsigned)mhdr0->rsvd1[0],
(unsigned)mhdr0->rsvd1[1], (unsigned)mhdr0->rsvd1[2]);
if (version == 0 && mhdr0->rsvd3)
fprintf(f, "#RSVD3 0x%x\n", (unsigned)mhdr0->rsvd3);
if (version == 0 && le16_to_cpu(mhdr0->rsvd2))
fprintf(f, "#RSVD2 0x%x\n", (unsigned)le16_to_cpu(mhdr0->rsvd2));
if (version != 0 && mhdr->reserved4)
fprintf(f, "#RESERVED4 0x%x\n", (unsigned)mhdr->reserved4);
if (version != 0 && mhdr->reserved5)
fprintf(f, "#RESERVED5 0x%x\n", (unsigned)le16_to_cpu(mhdr->reserved5));
fclose(f);
return 0;
}
static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params) static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params)
{ {
struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr; struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
size_t header_size = kwbheader_size(ptr); size_t header_size = kwbheader_size(ptr);
struct opt_hdr_v1 *ohdr; struct opt_hdr_v1 *ohdr;
int idx = params->pflag; int idx = params->pflag;
int cur_idx = 0; int cur_idx;
uint32_t offset; uint32_t offset;
ulong image; ulong image;
ulong size; ulong size;
for_each_opt_hdr_v1 (ohdr, ptr) { /* Generate kwbimage config file when '-p -1' is specified */
if (ohdr->headertype != OPT_HDR_V1_BINARY_TYPE) if (idx == -1)
continue; return kwbimage_generate_config(ptr, params);
if (idx == cur_idx) { image = 0;
image = (ulong)&ohdr->data[4 + 4 * ohdr->data[0]]; size = 0;
size = opt_hdr_v1_size(ohdr) - 12 - 4 * ohdr->data[0];
goto extract;
}
++cur_idx;
}
if (idx != cur_idx) {
printf("Image %d is not present\n", idx);
return -1;
}
if (idx == 0) {
/* Extract data image when -p is not specified or when '-p 0' is specified */
offset = le32_to_cpu(mhdr->srcaddr); offset = le32_to_cpu(mhdr->srcaddr);
if (mhdr->blockid == IBR_HDR_SATA_ID) { if (mhdr->blockid == IBR_HDR_SATA_ID) {
@ -1975,8 +2295,34 @@ static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params
image = (ulong)((uint8_t *)ptr + offset); image = (ulong)((uint8_t *)ptr + offset);
size = le32_to_cpu(mhdr->blocksize) - 4; size = le32_to_cpu(mhdr->blocksize) - 4;
} else {
/* Extract N-th binary header executabe image when other '-p N' is specified */
cur_idx = 1;
for_each_opt_hdr_v1(ohdr, ptr) {
if (ohdr->headertype != OPT_HDR_V1_BINARY_TYPE)
continue;
if (idx == cur_idx) {
image = (ulong)&ohdr->data[4 + 4 * ohdr->data[0]];
size = opt_hdr_v1_size(ohdr) - 12 - 4 * ohdr->data[0];
break;
}
++cur_idx;
}
if (!image) {
fprintf(stderr, "Argument -p %d is invalid\n", idx);
fprintf(stderr, "Available subimages:\n");
fprintf(stderr, " -p -1 - kwbimage config file\n");
fprintf(stderr, " -p 0 - data image\n");
if (cur_idx - 1 > 0)
fprintf(stderr, " -p N - Nth binary header image (totally: %d)\n",
cur_idx - 1);
return -1;
}
}
extract:
return imagetool_save_subimage(params->outfile, image, size); return imagetool_save_subimage(params->outfile, image, size);
} }
@ -1985,7 +2331,8 @@ extract:
*/ */
static int kwbimage_check_params(struct image_tool_params *params) static int kwbimage_check_params(struct image_tool_params *params)
{ {
if (!params->iflag && (!params->imagename || !strlen(params->imagename))) { if (!params->lflag && !params->iflag &&
(!params->imagename || !strlen(params->imagename))) {
char *msg = "Configuration file for kwbimage creation omitted"; char *msg = "Configuration file for kwbimage creation omitted";
fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg); fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg);

View File

@ -208,7 +208,7 @@ static inline size_t kwbheader_size(const void *header)
const struct main_hdr_v0 *hdr = header; const struct main_hdr_v0 *hdr = header;
return sizeof(*hdr) + return sizeof(*hdr) +
(hdr->ext & 0x1) ? sizeof(struct ext_hdr_v0) : 0; hdr->ext ? sizeof(struct ext_hdr_v0) : 0;
} else { } else {
const struct main_hdr_v1 *hdr = header; const struct main_hdr_v1 *hdr = header;
@ -235,11 +235,11 @@ static inline int opt_hdr_v1_valid_size(const struct opt_hdr_v1 *ohdr,
{ {
uint32_t ohdr_size; uint32_t ohdr_size;
if ((void *)(ohdr + 1) > mhdr_end) if ((const void *)(ohdr + 1) > mhdr_end)
return 0; return 0;
ohdr_size = opt_hdr_v1_size(ohdr); ohdr_size = opt_hdr_v1_size(ohdr);
if (ohdr_size < 8 || (void *)((uint8_t *)ohdr + ohdr_size) > mhdr_end) if (ohdr_size < 8 || (const void *)((const uint8_t *)ohdr + ohdr_size) > mhdr_end)
return 0; return 0;
return 1; return 1;
@ -252,7 +252,7 @@ static inline struct opt_hdr_v1 *opt_hdr_v1_first(void *img) {
return NULL; return NULL;
mhdr = img; mhdr = img;
if (mhdr->ext & 0x1) if (mhdr->ext)
return (struct opt_hdr_v1 *)(mhdr + 1); return (struct opt_hdr_v1 *)(mhdr + 1);
else else
return NULL; return NULL;
@ -272,7 +272,7 @@ static inline struct opt_hdr_v1 *_opt_hdr_v1_next(struct opt_hdr_v1 *cur)
static inline struct opt_hdr_v1 *opt_hdr_v1_next(struct opt_hdr_v1 *cur) static inline struct opt_hdr_v1 *opt_hdr_v1_next(struct opt_hdr_v1 *cur)
{ {
if (*opt_hdr_v1_ext(cur) & 0x1) if (*opt_hdr_v1_ext(cur))
return _opt_hdr_v1_next(cur); return _opt_hdr_v1_next(cur);
else else
return NULL; return NULL;

View File

@ -1398,7 +1398,7 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz)
uint32_t ohdrsz; uint32_t ohdrsz;
uint8_t *prev_ext; uint8_t *prev_ext;
if (hdr->ext & 0x1) { if (hdr->ext) {
for_each_opt_hdr_v1 (ohdr, img) for_each_opt_hdr_v1 (ohdr, img)
if (opt_hdr_v1_next(ohdr) == NULL) if (opt_hdr_v1_next(ohdr) == NULL)
break; break;
@ -1422,7 +1422,7 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz)
ohdrsz = sizeof(*ohdr) + 4 + 4 * num_args + binsz + 4; ohdrsz = sizeof(*ohdr) + 4 + 4 * num_args + binsz + 4;
kwboot_img_grow_hdr(hdr, size, ohdrsz); kwboot_img_grow_hdr(hdr, size, ohdrsz);
*prev_ext |= 1; *prev_ext = 1;
ohdr->headertype = OPT_HDR_V1_BINARY_TYPE; ohdr->headertype = OPT_HDR_V1_BINARY_TYPE;
ohdr->headersz_msb = ohdrsz >> 16; ohdr->headersz_msb = ohdrsz >> 16;