From: Dirk Eibach Date: Wed, 22 Feb 2017 15:07:23 +0000 (+0100) Subject: arm: mvebu: Add gdsys ControlCenter-Compact board X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=60083261a1b33b492ddb5335c125f1223087068b;p=u-boot.git arm: mvebu: Add gdsys ControlCenter-Compact board The gdsys ControlCenter Digital board is based on a Marvell Armada 38x SOC. It boots from SPI-Flash but can be configured to boot from SD-card for factory programming and testing. On board peripherals include: - 2 x GbE - Xilinx Kintex-7 FPGA connected via PCIe - mSATA - USB3 host - Atmel TPM Signed-off-by: Dirk Eibach Signed-off-by: Mario Six Signed-off-by: Stefan Roese --- diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1eb373f3df..dacfe9a13f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1284,6 +1284,7 @@ source "board/freescale/mx53evk/Kconfig" source "board/freescale/mx53loco/Kconfig" source "board/freescale/mx53smd/Kconfig" source "board/freescale/s32v234evb/Kconfig" +source "board/gdsys/a38x/Kconfig" source "board/grinn/chiliboard/Kconfig" source "board/gumstix/pepper/Kconfig" source "board/h2200/Kconfig" diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 5f1df2ac44..0fbbb9b8b4 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -82,7 +82,8 @@ dtb-$(CONFIG_ARCH_MVEBU) += \ armada-xp-gp.dtb \ armada-xp-maxbcm.dtb \ armada-xp-synology-ds414.dtb \ - armada-xp-theadorable.dtb + armada-xp-theadorable.dtb \ + armada-38x-controlcenterdc.dtb dtb-$(CONFIG_ARCH_UNIPHIER_LD11) += \ uniphier-ld11-ref.dtb diff --git a/arch/arm/dts/armada-38x-controlcenterdc.dts b/arch/arm/dts/armada-38x-controlcenterdc.dts new file mode 100644 index 0000000000..d183fd7502 --- /dev/null +++ b/arch/arm/dts/armada-38x-controlcenterdc.dts @@ -0,0 +1,589 @@ +/* + * Device Tree file for the Guntermann & Drunck ControlCenter-Compact board + * + * Copyright (C) 2016 Mario Six + * + * based on the Device Tree file for Marvell Armada 388 evaluation board + * (DB-88F6820), which is + * + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +#include "armada-388.dtsi" + +&gpio0 { + u-boot,dm-pre-reloc; +}; + +&gpio1 { + u-boot,dm-pre-reloc; +}; + +&uart0 { + u-boot,dm-pre-reloc; +}; + +&uart1 { + u-boot,dm-pre-reloc; +}; + +/ { + model = "Controlcenter Digital Compact"; + compatible = "marvell,a385-db", "marvell,armada388", + "marvell,armada385", "marvell,armada380"; + + chosen { + bootargs = "console=ttyS1,115200 earlyprintk"; + stdout-path = "/soc/internal-regs/serial@12100"; + }; + + aliases { + ethernet0 = ð0; + ethernet2 = ð2; + mdio-gpio0 = &MDIO0; + mdio-gpio1 = &MDIO1; + mdio-gpio2 = &MDIO2; + spi0 = &spi0; + spi1 = &spi1; + i2c0 = &I2C0; + i2c1 = &I2C1; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; /* 256 MB */ + }; + + clocks { + sc16isclk: sc16isclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <11059200>; + }; + }; + + soc { + ranges = ; + + internal-regs { + spi0: spi@10600 { + status = "okay"; + sc16is741: sc16is741@0 { + compatible = "nxp,sc16is741"; + reg = <0>; + clocks = <&sc16isclk>; + spi-max-frequency = <4000000>; + interrupt-parent = <&gpio0>; + interrupts = <11 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + spi1: spi@10680 { + status = "okay"; + u-boot,dm-pre-reloc; + spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q016a"; + reg = <0>; /* Chip select 0 */ + spi-max-frequency = <108000000>; + }; + spi-flash@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q128a11"; + reg = <1>; /* Chip select 1 */ + spi-max-frequency = <108000000>; + u-boot,dm-pre-reloc; + }; + }; + + I2C0: i2c@11000 { + status = "okay"; + clock-frequency = <1000000>; + u-boot,dm-pre-reloc; + PCA21: pca9698@21 { + compatible = "nxp,pca9698"; + reg = <0x21>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA22: pca9698@22 { + compatible = "nxp,pca9698"; + u-boot,dm-pre-reloc; + reg = <0x22>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA23: pca9698@23 { + compatible = "nxp,pca9698"; + reg = <0x23>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA24: pca9698@24 { + compatible = "nxp,pca9698"; + reg = <0x24>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA25: pca9698@25 { + compatible = "nxp,pca9698"; + reg = <0x25>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA26: pca9698@26 { + compatible = "nxp,pca9698"; + reg = <0x26>; + #gpio-cells = <2>; + gpio-controller; + }; + }; + + I2C1: i2c@11100 { + status = "okay"; + clock-frequency = <400000>; + at97sc3205t@29 { + compatible = "atmel,at97sc3204t"; + reg = <0x29>; + u-boot,i2c-offset-len = <0>; + }; + emc2305@2d { + compatible = "smsc,emc2305"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2d>; + fan@0 { + reg = <0>; + }; + fan@1 { + reg = <1>; + }; + fan@2 { + reg = <2>; + }; + fan@3 { + reg = <3>; + }; + fan@4 { + reg = <4>; + }; + }; + lm77@48 { + compatible = "national,lm77"; + reg = <0x48>; + }; + ads1015@49 { + compatible = "ti,ads1015"; + reg = <0x49>; + }; + lm77@4a { + compatible = "national,lm77"; + reg = <0x4a>; + }; + ads1015@4b { + compatible = "ti,ads1015"; + reg = <0x4b>; + }; + emc2305@4c { + compatible = "smsc,emc2305"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4c>; + fan@0 { + reg = <0>; + }; + fan@1 { + reg = <1>; + }; + fan@2 { + reg = <2>; + }; + fan@3 { + reg = <3>; + }; + fan@4 { + reg = <4>; + }; + }; + at24c512@54 { + compatible = "atmel,24c512"; + reg = <0x54>; + u-boot,i2c-offset-len = <2>; + }; + ds1339@68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + }; + }; + + serial@12000 { + status = "okay"; + }; + + serial@12100 { + status = "okay"; + }; + + ethernet@34000 { + status = "okay"; + phy = <&phy1>; + phy-mode = "sgmii"; + }; + + usb@58000 { + status = "ok"; + }; + + ethernet@70000 { + status = "okay"; + phy = <&phy0>; + phy-mode = "sgmii"; + }; + + mdio@72004 { + phy0: ethernet-phy@0 { + reg = <1>; + }; + + phy1: ethernet-phy@1 { + reg = <0>; + }; + }; + + sata@a8000 { + status = "okay"; + }; + + sdhci@d8000 { + broken-cd; + wp-inverted; + bus-width = <4>; + status = "okay"; + no-1-8-v; + }; + + usb3@f0000 { + status = "okay"; + }; + }; + + pcie-controller { + status = "okay"; + /* + * The two PCIe units are accessible through + * standard PCIe slots on the board. + */ + pcie@3,0 { + /* Port 0, Lane 0 */ + status = "okay"; + }; + }; + + MDIO0: mdio0 { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = < /*MDC*/ &gpio0 13 0 + /*MDIO*/ &gpio0 14 0>; + mv88e1240@0 { + reg = <0x0>; + }; + mv88e1240@1 { + reg = <0x1>; + }; + mv88e1240@2 { + reg = <0x2>; + }; + mv88e1240@3 { + reg = <0x3>; + }; + mv88e1240@4 { + reg = <0x4>; + }; + mv88e1240@5 { + reg = <0x5>; + }; + mv88e1240@6 { + reg = <0x6>; + }; + mv88e1240@7 { + reg = <0x7>; + }; + mv88e1240@8 { + reg = <0x8>; + }; + mv88e1240@9 { + reg = <0x9>; + }; + mv88e1240@a { + reg = <0xa>; + }; + mv88e1240@b { + reg = <0xb>; + }; + mv88e1240@c { + reg = <0xc>; + }; + mv88e1240@d { + reg = <0xd>; + }; + mv88e1240@e { + reg = <0xe>; + }; + mv88e1240@f { + reg = <0xf>; + }; + mv88e1240@10 { + reg = <0x10>; + }; + mv88e1240@11 { + reg = <0x11>; + }; + mv88e1240@12 { + reg = <0x12>; + }; + mv88e1240@13 { + reg = <0x13>; + }; + mv88e1240@14 { + reg = <0x14>; + }; + mv88e1240@15 { + reg = <0x15>; + }; + mv88e1240@16 { + reg = <0x16>; + }; + mv88e1240@17 { + reg = <0x17>; + }; + mv88e1240@18 { + reg = <0x18>; + }; + mv88e1240@19 { + reg = <0x19>; + }; + mv88e1240@1a { + reg = <0x1a>; + }; + mv88e1240@1b { + reg = <0x1b>; + }; + mv88e1240@1c { + reg = <0x1c>; + }; + mv88e1240@1d { + reg = <0x1d>; + }; + mv88e1240@1e { + reg = <0x1e>; + }; + mv88e1240@1f { + reg = <0x1f>; + }; + }; + + MDIO1: mdio1 { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = < /*MDC*/ &gpio0 25 0 + /*MDIO*/ &gpio1 13 0>; + mv88e1240@0 { + reg = <0x0>; + }; + mv88e1240@1 { + reg = <0x1>; + }; + mv88e1240@2 { + reg = <0x2>; + }; + mv88e1240@3 { + reg = <0x3>; + }; + mv88e1240@4 { + reg = <0x4>; + }; + mv88e1240@5 { + reg = <0x5>; + }; + mv88e1240@6 { + reg = <0x6>; + }; + mv88e1240@7 { + reg = <0x7>; + }; + mv88e1240@8 { + reg = <0x8>; + }; + mv88e1240@9 { + reg = <0x9>; + }; + mv88e1240@a { + reg = <0xa>; + }; + mv88e1240@b { + reg = <0xb>; + }; + mv88e1240@c { + reg = <0xc>; + }; + mv88e1240@d { + reg = <0xd>; + }; + mv88e1240@e { + reg = <0xe>; + }; + mv88e1240@f { + reg = <0xf>; + }; + mv88e1240@10 { + reg = <0x10>; + }; + mv88e1240@11 { + reg = <0x11>; + }; + mv88e1240@12 { + reg = <0x12>; + }; + mv88e1240@13 { + reg = <0x13>; + }; + mv88e1240@14 { + reg = <0x14>; + }; + mv88e1240@15 { + reg = <0x15>; + }; + mv88e1240@16 { + reg = <0x16>; + }; + mv88e1240@17 { + reg = <0x17>; + }; + mv88e1240@18 { + reg = <0x18>; + }; + mv88e1240@19 { + reg = <0x19>; + }; + mv88e1240@1a { + reg = <0x1a>; + }; + mv88e1240@1b { + reg = <0x1b>; + }; + mv88e1240@1c { + reg = <0x1c>; + }; + mv88e1240@1d { + reg = <0x1d>; + }; + mv88e1240@1e { + reg = <0x1e>; + }; + mv88e1240@1f { + reg = <0x1f>; + }; + }; + + MDIO2: mdio2 { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = < /*MDC*/ &gpio1 14 0 + /*MDIO*/ &gpio0 24 0>; + mv88e1240@0 { + reg = <0x0>; + }; + mv88e1240@1 { + reg = <0x1>; + }; + mv88e1240@2 { + reg = <0x2>; + }; + mv88e1240@3 { + reg = <0x3>; + }; + mv88e1240@4 { + reg = <0x4>; + }; + mv88e1240@5 { + reg = <0x5>; + }; + mv88e1240@6 { + reg = <0x6>; + }; + mv88e1240@7 { + reg = <0x7>; + }; + mv88e1240@8 { + reg = <0x8>; + }; + mv88e1240@9 { + reg = <0x9>; + }; + mv88e1240@a { + reg = <0xa>; + }; + mv88e1240@b { + reg = <0xb>; + }; + mv88e1240@c { + reg = <0xc>; + }; + mv88e1240@d { + reg = <0xd>; + }; + mv88e1240@e { + reg = <0xe>; + }; + mv88e1240@f { + reg = <0xf>; + }; + mv88e1240@10 { + reg = <0x10>; + }; + mv88e1240@11 { + reg = <0x11>; + }; + mv88e1240@12 { + reg = <0x12>; + }; + mv88e1240@13 { + reg = <0x13>; + }; + mv88e1240@14 { + reg = <0x14>; + }; + mv88e1240@15 { + reg = <0x15>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + finder_led { + label = "finder-led"; + gpios = <&PCA22 25 0>; + }; + + status_led { + label = "status-led"; + gpios = <&gpio0 29 0>; + }; + }; +}; diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index a256c2fb77..6ae54ef46a 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -112,6 +112,10 @@ config TARGET_THEADORABLE select BOARD_LATE_INIT if USB select MV78260 +config TARGET_CONTROLCENTERDC + bool "Support CONTROLCENTERDC" + select 88F6820 + endchoice config SYS_BOARD diff --git a/board/gdsys/a38x/.gitignore b/board/gdsys/a38x/.gitignore new file mode 100644 index 0000000000..775b9346b8 --- /dev/null +++ b/board/gdsys/a38x/.gitignore @@ -0,0 +1 @@ +kwbimage.cfg diff --git a/board/gdsys/a38x/Kconfig b/board/gdsys/a38x/Kconfig new file mode 100644 index 0000000000..3fdef64b59 --- /dev/null +++ b/board/gdsys/a38x/Kconfig @@ -0,0 +1,36 @@ +if TARGET_CONTROLCENTERDC + +config SYS_BOARD + default "a38x" + +config SYS_VENDOR + default "gdsys" + +config SYS_SOC + default "mvebu" + +config SYS_CONFIG_NAME + default "controlcenterdc" + +menu "Controlcenter DC board options" + +choice + prompt "Select boot method" + +config SPL_BOOT_DEVICE_SPI + bool "SPI" + +config SPL_BOOT_DEVICE_MMC + bool "MMC" + select SPL_LIBDISK_SUPPORT + +endchoice + +#config SPL_BOOT_DEVICE +# int +# default 1 if SPL_BOOT_DEVICE_SPI +# default 2 if SPL_BOOT_DEVICE_MMC + +endmenu + +endif diff --git a/board/gdsys/a38x/MAINTAINERS b/board/gdsys/a38x/MAINTAINERS new file mode 100644 index 0000000000..3cb9b63ff0 --- /dev/null +++ b/board/gdsys/a38x/MAINTAINERS @@ -0,0 +1,7 @@ +A38X BOARD +M: Dirk Eibach +M: Mario Six +S: Maintained +F: board/gdsys/a38x/ +F: include/configs/controlcenterdc.h +F: configs/controlcenterdc_defconfig diff --git a/board/gdsys/a38x/Makefile b/board/gdsys/a38x/Makefile new file mode 100644 index 0000000000..e1f0bd8433 --- /dev/null +++ b/board/gdsys/a38x/Makefile @@ -0,0 +1,44 @@ +# +# Copyright (C) 2015 Stefan Roese +# Copyright (C) 2015 Reinhard Pfau +# Copyright (C) 2016 Mario Six +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_TARGET_CONTROLCENTERDC) += controlcenterdc.o hre.o spl.o keyprogram.o dt_helpers.o + +ifeq ($(CONFIG_SPL_BUILD),) + +obj-$(CONFIG_TARGET_CONTROLCENTERDC) += hydra.o ihs_phys.o + +extra-$(CONFIG_TARGET_CONTROLCENTERDC) += kwbimage.cfg + +KWB_REPLACE += BOOT_FROM +ifneq ($(CONFIG_SPL_BOOT_DEVICE_SPI),) + KWB_CFG_BOOT_FROM=spi +endif +ifneq ($(CONFIG_SPL_BOOT_DEVICE_MMC),) + KWB_CFG_BOOT_FROM=sdio +endif + +ifneq ($(CONFIG_SECURED_MODE_IMAGE),) +KWB_REPLACE += CSK_INDEX +KWB_CFG_CSK_INDEX = $(CONFIG_SECURED_MODE_CSK_INDEX) + +KWB_REPLACE += SEC_BOOT_DEV +KWB_CFG_SEC_BOOT_DEV=$(patsubst "%",%, \ + $(if $(findstring BOOT_SPI_NOR_FLASH,$(CONFIG_SPL_BOOT_DEVICE)),0x34) \ + $(if $(findstring BOOT_SDIO_MMC_CARD,$(CONFIG_SPL_BOOT_DEVICE)),0x31) \ + ) + +KWB_REPLACE += SEC_FUSE_DUMP +KWB_CFG_SEC_FUSE_DUMP = a38x +endif + +$(src)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \ + include/config/auto.conf + $(Q)sed -ne '$(foreach V,$(KWB_REPLACE),s/^#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \ + <$< >$(dir $<)$(@F) + +endif diff --git a/board/gdsys/a38x/controlcenterdc.c b/board/gdsys/a38x/controlcenterdc.c new file mode 100644 index 0000000000..f0efb53447 --- /dev/null +++ b/board/gdsys/a38x/controlcenterdc.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2015 Stefan Roese + * Copyright (C) 2016 Mario Six + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../drivers/ddr/marvell/a38x/ddr3_a38x_topology.h" +#include "../arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h" + +#include "keyprogram.h" +#include "dt_helpers.h" +#include "hydra.h" +#include "ihs_phys.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define ETH_PHY_CTRL_REG 0 +#define ETH_PHY_CTRL_POWER_DOWN_BIT 11 +#define ETH_PHY_CTRL_POWER_DOWN_MASK (1 << ETH_PHY_CTRL_POWER_DOWN_BIT) + +#define DB_GP_88F68XX_GPP_OUT_ENA_LOW 0x7fffffff +#define DB_GP_88F68XX_GPP_OUT_ENA_MID 0xffffefff + +#define DB_GP_88F68XX_GPP_OUT_VAL_LOW 0x0 +#define DB_GP_88F68XX_GPP_OUT_VAL_MID 0x00001000 +#define DB_GP_88F68XX_GPP_POL_LOW 0x0 +#define DB_GP_88F68XX_GPP_POL_MID 0x0 + +/* + * Define the DDR layout / topology here in the board file. This will + * be used by the DDR3 init code in the SPL U-Boot version to configure + * the DDR3 controller. + */ +static struct hws_topology_map ddr_topology_map = { + 0x1, /* active interfaces */ + /* cs_mask, mirror, dqs_swap, ck_swap X PUPs */ + { { { {0x1, 0, 0, 0}, + {0x1, 0, 0, 0}, + {0x1, 0, 0, 0}, + {0x1, 0, 0, 0}, + {0x1, 0, 0, 0} }, + SPEED_BIN_DDR_1600K, /* speed_bin */ + BUS_WIDTH_16, /* memory_width */ + MEM_4G, /* mem_size */ + DDR_FREQ_533, /* frequency */ + 0, 0, /* cas_l cas_wl */ + HWS_TEMP_LOW} }, /* temperature */ + 5, /* Num Of Bus Per Interface*/ + BUS_MASK_32BIT /* Busses mask */ +}; + +static struct serdes_map serdes_topology_map[] = { + {SGMII0, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + /* SATA tx polarity is inverted */ + {SATA1, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 1}, + {SGMII2, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {DEFAULT_SERDES, SERDES_SPEED_3_GBPS, SERDES_DEFAULT_MODE, 0, 0}, + {PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0} +}; + +int hws_board_topology_load(struct serdes_map **serdes_map_array, u8 *count) +{ + *serdes_map_array = serdes_topology_map; + *count = ARRAY_SIZE(serdes_topology_map); + return 0; +} + +void board_pex_config(void) +{ +#ifdef CONFIG_SPL_BUILD + uint k; + struct gpio_desc gpio = {}; + + if (!request_gpio_by_name(&gpio, "pca9698@22", 31, "fpga-program-gpio")) { + /* prepare FPGA reconfiguration */ + dm_gpio_set_dir_flags(&gpio, GPIOD_IS_OUT); + dm_gpio_set_value(&gpio, 0); + + /* give lunatic PCIe clock some time to stabilize */ + mdelay(500); + + /* start FPGA reconfiguration */ + dm_gpio_set_dir_flags(&gpio, GPIOD_IS_IN); + } + + /* wait for FPGA done */ + if (!request_gpio_by_name(&gpio, "pca9698@22", 19, "fpga-done-gpio")) { + for (k = 0; k < 20; ++k) { + if (dm_gpio_get_value(&gpio)) { + printf("FPGA done after %u rounds\n", k); + break; + } + mdelay(100); + } + } + + /* disable FPGA reset */ + if (!request_gpio_by_name(&gpio, "gpio@18100", 6, "cpu-to-fpga-reset")) { + dm_gpio_set_dir_flags(&gpio, GPIOD_IS_OUT); + dm_gpio_set_value(&gpio, 1); + } + + /* wait for FPGA ready */ + if (!request_gpio_by_name(&gpio, "pca9698@22", 27, "fpga-ready-gpio")) { + for (k = 0; k < 2; ++k) { + if (!dm_gpio_get_value(&gpio)) + break; + mdelay(100); + } + } +#endif +} + +struct hws_topology_map *ddr3_get_topology_map(void) +{ + return &ddr_topology_map; +} + +int board_early_init_f(void) +{ +#ifdef CONFIG_SPL_BUILD + /* Configure MPP */ + writel(0x00111111, MVEBU_MPP_BASE + 0x00); + writel(0x40040000, MVEBU_MPP_BASE + 0x04); + writel(0x00466444, MVEBU_MPP_BASE + 0x08); + writel(0x00043300, MVEBU_MPP_BASE + 0x0c); + writel(0x44400000, MVEBU_MPP_BASE + 0x10); + writel(0x20000334, MVEBU_MPP_BASE + 0x14); + writel(0x40000000, MVEBU_MPP_BASE + 0x18); + writel(0x00004444, MVEBU_MPP_BASE + 0x1c); + + /* Set GPP Out value */ + writel(DB_GP_88F68XX_GPP_OUT_VAL_LOW, MVEBU_GPIO0_BASE + 0x00); + writel(DB_GP_88F68XX_GPP_OUT_VAL_MID, MVEBU_GPIO1_BASE + 0x00); + + /* Set GPP Polarity */ + writel(DB_GP_88F68XX_GPP_POL_LOW, MVEBU_GPIO0_BASE + 0x0c); + writel(DB_GP_88F68XX_GPP_POL_MID, MVEBU_GPIO1_BASE + 0x0c); + + /* Set GPP Out Enable */ + writel(DB_GP_88F68XX_GPP_OUT_ENA_LOW, MVEBU_GPIO0_BASE + 0x04); + writel(DB_GP_88F68XX_GPP_OUT_ENA_MID, MVEBU_GPIO1_BASE + 0x04); +#endif + + return 0; +} + +int board_init(void) +{ + /* Address of boot parameters */ + gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100; + + return 0; +} + +#ifndef CONFIG_SPL_BUILD +void init_host_phys(struct mii_dev *bus) +{ + uint k; + + for (k = 0; k < 2; ++k) { + struct phy_device *phydev; + + phydev = phy_find_by_mask(bus, 1 << k, + PHY_INTERFACE_MODE_SGMII); + + if (phydev) + phy_config(phydev); + } +} + +int ccdc_eth_init(void) +{ + uint k; + uint octo_phy_mask = 0; + int ret; + struct mii_dev *bus; + + /* Init SoC's phys */ + bus = miiphy_get_dev_by_name("ethernet@34000"); + + if (bus) + init_host_phys(bus); + + bus = miiphy_get_dev_by_name("ethernet@70000"); + + if (bus) + init_host_phys(bus); + + /* Init octo phys */ + octo_phy_mask = calculate_octo_phy_mask(); + + printf("IHS PHYS: %08x", octo_phy_mask); + + ret = init_octo_phys(octo_phy_mask); + + if (ret) + return ret; + + printf("\n"); + + if (!get_fpga()) { + puts("fpga was NULL\n"); + return 1; + } + + /* reset all FPGA-QSGMII instances */ + for (k = 0; k < 80; ++k) + writel(1 << 31, get_fpga()->qsgmii_port_state[k]); + + udelay(100); + + for (k = 0; k < 80; ++k) + writel(0, get_fpga()->qsgmii_port_state[k]); + return 0; +} + +#endif + +int board_late_init(void) +{ +#ifndef CONFIG_SPL_BUILD + hydra_initialize(); +#endif + return 0; +} + +int board_fix_fdt(void *rw_fdt_blob) +{ + struct udevice *bus = NULL; + uint k; + char name[64]; + int err; + + err = uclass_get_device_by_name(UCLASS_I2C, "i2c@11000", &bus); + + if (err) { + printf("Could not get I2C bus.\n"); + return err; + } + + for (k = 0x21; k <= 0x26; k++) { + snprintf(name, 64, + "/soc/internal-regs/i2c@11000/pca9698@%02x", k); + + if (!dm_i2c_simple_probe(bus, k)) + fdt_disable_by_ofname(rw_fdt_blob, name); + } + + return 0; +} + +int last_stage_init(void) +{ +#ifndef CONFIG_SPL_BUILD + ccdc_eth_init(); +#endif + if (tpm_init() || tpm_startup(TPM_ST_CLEAR) || + tpm_continue_self_test()) { + return 1; + } + + mdelay(37); + + flush_keys(); + load_and_run_keyprog(); + + return 0; +} diff --git a/board/gdsys/a38x/dt_helpers.c b/board/gdsys/a38x/dt_helpers.c new file mode 100644 index 0000000000..759d82a728 --- /dev/null +++ b/board/gdsys/a38x/dt_helpers.c @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2016 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +int fdt_disable_by_ofname(void *rw_fdt_blob, char *ofname) +{ + int offset = fdt_path_offset(rw_fdt_blob, ofname); + + return fdt_status_disabled(rw_fdt_blob, offset); +} + +bool dm_i2c_simple_probe(struct udevice *bus, uint chip_addr) +{ + struct udevice *dev; + + return !dm_i2c_probe(bus, chip_addr, DM_I2C_CHIP_RD_ADDRESS | + DM_I2C_CHIP_WR_ADDRESS, &dev); +} + +int request_gpio_by_name(struct gpio_desc *gpio, const char *gpio_dev_name, + uint offset, char *gpio_name) +{ + struct udevice *gpio_dev = NULL; + + if (uclass_get_device_by_name(UCLASS_GPIO, gpio_dev_name, &gpio_dev)) + return 1; + + gpio->dev = gpio_dev; + gpio->offset = offset; + gpio->flags = 0; + + return dm_gpio_request(gpio, gpio_name); +} + diff --git a/board/gdsys/a38x/dt_helpers.h b/board/gdsys/a38x/dt_helpers.h new file mode 100644 index 0000000000..1b95262c51 --- /dev/null +++ b/board/gdsys/a38x/dt_helpers.h @@ -0,0 +1,16 @@ +/* + * (C) Copyright 2016 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __DT_HELPERS_H +#define __DT_HELPERS_H + +int fdt_disable_by_ofname(void *rw_fdt_blob, char *ofname); +bool dm_i2c_simple_probe(struct udevice *bus, uint chip_addr); +int request_gpio_by_name(struct gpio_desc *gpio, const char *gpio_dev_name, + uint offset, char *gpio_name); + +#endif /* __DT_HELPERS_H */ diff --git a/board/gdsys/a38x/hre.c b/board/gdsys/a38x/hre.c new file mode 100644 index 0000000000..1689d44db6 --- /dev/null +++ b/board/gdsys/a38x/hre.c @@ -0,0 +1,516 @@ +/* + * (C) Copyright 2013 + * Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hre.h" + +/* other constants */ +enum { + ESDHC_BOOT_IMAGE_SIG_OFS = 0x40, + ESDHC_BOOT_IMAGE_SIZE_OFS = 0x48, + ESDHC_BOOT_IMAGE_ADDR_OFS = 0x50, + ESDHC_BOOT_IMAGE_TARGET_OFS = 0x58, + ESDHC_BOOT_IMAGE_ENTRY_OFS = 0x60, +}; + +enum { + I2C_SOC_0 = 0, + I2C_SOC_1 = 1, +}; + +enum access_mode { + HREG_NONE = 0, + HREG_RD = 1, + HREG_WR = 2, + HREG_RDWR = 3, +}; + +/* register constants */ +enum { + FIX_HREG_DEVICE_ID_HASH = 0, + FIX_HREG_UNUSED1 = 1, + FIX_HREG_UNUSED2 = 2, + FIX_HREG_VENDOR = 3, + COUNT_FIX_HREGS +}; + +static struct h_reg pcr_hregs[24]; +static struct h_reg fix_hregs[COUNT_FIX_HREGS]; +static struct h_reg var_hregs[8]; + +/* hre opcodes */ +enum { + /* opcodes w/o data */ + HRE_NOP = 0x00, + HRE_SYNC = HRE_NOP, + HRE_CHECK0 = 0x01, + /* opcodes w/o data, w/ sync dst */ + /* opcodes w/ data */ + HRE_LOAD = 0x81, + /* opcodes w/data, w/sync dst */ + HRE_XOR = 0xC1, + HRE_AND = 0xC2, + HRE_OR = 0xC3, + HRE_EXTEND = 0xC4, + HRE_LOADKEY = 0xC5, +}; + +/* hre errors */ +enum { + HRE_E_OK = 0, + HRE_E_TPM_FAILURE, + HRE_E_INVALID_HREG, +}; + +static uint64_t device_id; +static uint64_t device_cl; +static uint64_t device_type; + +static uint32_t platform_key_handle; + +static uint32_t hre_tpm_err; +static int hre_err = HRE_E_OK; + +#define IS_PCR_HREG(spec) ((spec) & 0x20) +#define IS_FIX_HREG(spec) (((spec) & 0x38) == 0x08) +#define IS_VAR_HREG(spec) (((spec) & 0x38) == 0x10) +#define HREG_IDX(spec) ((spec) & (IS_PCR_HREG(spec) ? 0x1f : 0x7)) + +static const uint8_t vendor[] = "Guntermann & Drunck"; + +/** + * @brief get the size of a given (TPM) NV area + * @param index NV index of the area to get size for + * @param size pointer to the size + * @return 0 on success, != 0 on error + */ +static int get_tpm_nv_size(uint32_t index, uint32_t *size) +{ + uint32_t err; + uint8_t info[72]; + uint8_t *ptr; + uint16_t v16; + + err = tpm_get_capability(TPM_CAP_NV_INDEX, index, + info, sizeof(info)); + if (err) { + printf("tpm_get_capability(CAP_NV_INDEX, %08x) failed: %u\n", + index, err); + return 1; + } + + /* skip tag and nvIndex */ + ptr = info + 6; + /* skip 2 pcr info fields */ + v16 = get_unaligned_be16(ptr); + ptr += 2 + v16 + 1 + 20; + v16 = get_unaligned_be16(ptr); + ptr += 2 + v16 + 1 + 20; + /* skip permission and flags */ + ptr += 6 + 3; + + *size = get_unaligned_be32(ptr); + return 0; +} + +/** + * @brief search for a key by usage auth and pub key hash. + * @param auth usage auth of the key to search for + * @param pubkey_digest (SHA1) hash of the pub key structure of the key + * @param[out] handle the handle of the key iff found + * @return 0 if key was found in TPM; != 0 if not. + */ +static int find_key(const uint8_t auth[20], const uint8_t pubkey_digest[20], + uint32_t *handle) +{ + uint16_t key_count; + uint32_t key_handles[10]; + uint8_t buf[288]; + uint8_t *ptr; + uint32_t err; + uint8_t digest[20]; + size_t buf_len; + unsigned int i; + + /* fetch list of already loaded keys in the TPM */ + err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf)); + if (err) + return -1; + key_count = get_unaligned_be16(buf); + ptr = buf + 2; + for (i = 0; i < key_count; ++i, ptr += 4) + key_handles[i] = get_unaligned_be32(ptr); + + /* now search a(/ the) key which we can access with the given auth */ + for (i = 0; i < key_count; ++i) { + buf_len = sizeof(buf); + err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len); + if (err && err != TPM_AUTHFAIL) + return -1; + if (err) + continue; + sha1_csum(buf, buf_len, digest); + if (!memcmp(digest, pubkey_digest, 20)) { + *handle = key_handles[i]; + return 0; + } + } + return 1; +} + +/** + * @brief read CCDM common data from TPM NV + * @return 0 if CCDM common data was found and read, !=0 if something failed. + */ +static int read_common_data(void) +{ + uint32_t size = 0; + uint32_t err; + uint8_t buf[256]; + sha1_context ctx; + + if (get_tpm_nv_size(NV_COMMON_DATA_INDEX, &size) || + size < NV_COMMON_DATA_MIN_SIZE) + return 1; + err = tpm_nv_read_value(NV_COMMON_DATA_INDEX, + buf, min(sizeof(buf), size)); + if (err) { + printf("tpm_nv_read_value() failed: %u\n", err); + return 1; + } + + device_id = get_unaligned_be64(buf); + device_cl = get_unaligned_be64(buf + 8); + device_type = get_unaligned_be64(buf + 16); + + sha1_starts(&ctx); + sha1_update(&ctx, buf, 24); + sha1_finish(&ctx, fix_hregs[FIX_HREG_DEVICE_ID_HASH].digest); + fix_hregs[FIX_HREG_DEVICE_ID_HASH].valid = true; + + platform_key_handle = get_unaligned_be32(buf + 24); + + return 0; +} + +/** + * @brief get pointer to hash register by specification + * @param spec specification of a hash register + * @return pointer to hash register or NULL if @a spec does not qualify a + * valid hash register; NULL else. + */ +static struct h_reg *get_hreg(uint8_t spec) +{ + uint8_t idx; + + idx = HREG_IDX(spec); + if (IS_FIX_HREG(spec)) { + if (idx < ARRAY_SIZE(fix_hregs)) + return fix_hregs + idx; + hre_err = HRE_E_INVALID_HREG; + } else if (IS_PCR_HREG(spec)) { + if (idx < ARRAY_SIZE(pcr_hregs)) + return pcr_hregs + idx; + hre_err = HRE_E_INVALID_HREG; + } else if (IS_VAR_HREG(spec)) { + if (idx < ARRAY_SIZE(var_hregs)) + return var_hregs + idx; + hre_err = HRE_E_INVALID_HREG; + } + return NULL; +} + +/** + * @brief get pointer of a hash register by specification and usage. + * @param spec specification of a hash register + * @param mode access mode (read or write or read/write) + * @return pointer to hash register if found and valid; NULL else. + * + * This func uses @a get_reg() to determine the hash register for a given spec. + * If a register is found it is validated according to the desired access mode. + * The value of automatic registers (PCR register and fixed registers) is + * loaded or computed on read access. + */ +static struct h_reg *access_hreg(uint8_t spec, enum access_mode mode) +{ + struct h_reg *result; + + result = get_hreg(spec); + if (!result) + return NULL; + + if (mode & HREG_WR) { + if (IS_FIX_HREG(spec)) { + hre_err = HRE_E_INVALID_HREG; + return NULL; + } + } + if (mode & HREG_RD) { + if (!result->valid) { + if (IS_PCR_HREG(spec)) { + hre_tpm_err = tpm_pcr_read(HREG_IDX(spec), + result->digest, 20); + result->valid = (hre_tpm_err == TPM_SUCCESS); + } else if (IS_FIX_HREG(spec)) { + switch (HREG_IDX(spec)) { + case FIX_HREG_DEVICE_ID_HASH: + read_common_data(); + break; + case FIX_HREG_VENDOR: + memcpy(result->digest, vendor, 20); + result->valid = true; + break; + } + } else { + result->valid = true; + } + } + if (!result->valid) { + hre_err = HRE_E_INVALID_HREG; + return NULL; + } + } + + return result; +} + +static void *compute_and(void *_dst, const void *_src, size_t n) +{ + uint8_t *dst = _dst; + const uint8_t *src = _src; + size_t i; + + for (i = n; i-- > 0; ) + *dst++ &= *src++; + + return _dst; +} + +static void *compute_or(void *_dst, const void *_src, size_t n) +{ + uint8_t *dst = _dst; + const uint8_t *src = _src; + size_t i; + + for (i = n; i-- > 0; ) + *dst++ |= *src++; + + return _dst; +} + +static void *compute_xor(void *_dst, const void *_src, size_t n) +{ + uint8_t *dst = _dst; + const uint8_t *src = _src; + size_t i; + + for (i = n; i-- > 0; ) + *dst++ ^= *src++; + + return _dst; +} + +static void *compute_extend(void *_dst, const void *_src, size_t n) +{ + uint8_t digest[20]; + sha1_context ctx; + + sha1_starts(&ctx); + sha1_update(&ctx, _dst, n); + sha1_update(&ctx, _src, n); + sha1_finish(&ctx, digest); + memcpy(_dst, digest, min(n, sizeof(digest))); + + return _dst; +} + +static int hre_op_loadkey(struct h_reg *src_reg, struct h_reg *dst_reg, + const void *key, size_t key_size) +{ + uint32_t parent_handle; + uint32_t key_handle; + + if (!src_reg || !dst_reg || !src_reg->valid || !dst_reg->valid) + return -1; + if (find_key(src_reg->digest, dst_reg->digest, &parent_handle)) + return -1; + hre_tpm_err = tpm_load_key2_oiap(parent_handle, key, key_size, + src_reg->digest, &key_handle); + if (hre_tpm_err) { + hre_err = HRE_E_TPM_FAILURE; + return -1; + } + + return 0; +} + +/** + * @brief executes the next opcode on the hash register engine. + * @param[in,out] ip pointer to the opcode (instruction pointer) + * @param[in,out] code_size (remaining) size of the code + * @return new instruction pointer on success, NULL on error. + */ +static const uint8_t *hre_execute_op(const uint8_t **ip, size_t *code_size) +{ + bool dst_modified = false; + uint32_t ins; + uint8_t opcode; + uint8_t src_spec; + uint8_t dst_spec; + uint16_t data_size; + struct h_reg *src_reg, *dst_reg; + uint8_t buf[20]; + const uint8_t *src_buf, *data; + uint8_t *ptr; + int i; + void * (*bin_func)(void *, const void *, size_t); + + if (*code_size < 4) + return NULL; + + ins = get_unaligned_be32(*ip); + opcode = **ip; + data = *ip + 4; + src_spec = (ins >> 18) & 0x3f; + dst_spec = (ins >> 12) & 0x3f; + data_size = (ins & 0x7ff); + + debug("HRE: ins=%08x (op=%02x, s=%02x, d=%02x, L=%d)\n", ins, + opcode, src_spec, dst_spec, data_size); + + if ((opcode & 0x80) && (data_size + 4) > *code_size) + return NULL; + + src_reg = access_hreg(src_spec, HREG_RD); + if (hre_err || hre_tpm_err) + return NULL; + dst_reg = access_hreg(dst_spec, (opcode & 0x40) ? HREG_RDWR : HREG_WR); + if (hre_err || hre_tpm_err) + return NULL; + + switch (opcode) { + case HRE_NOP: + goto end; + case HRE_CHECK0: + if (src_reg) { + for (i = 0; i < 20; ++i) { + if (src_reg->digest[i]) + return NULL; + } + } + break; + case HRE_LOAD: + bin_func = memcpy; + goto do_bin_func; + case HRE_XOR: + bin_func = compute_xor; + goto do_bin_func; + case HRE_AND: + bin_func = compute_and; + goto do_bin_func; + case HRE_OR: + bin_func = compute_or; + goto do_bin_func; + case HRE_EXTEND: + bin_func = compute_extend; +do_bin_func: + if (!dst_reg) + return NULL; + if (src_reg) { + src_buf = src_reg->digest; + } else { + if (!data_size) { + memset(buf, 0, 20); + src_buf = buf; + } else if (data_size == 1) { + memset(buf, *data, 20); + src_buf = buf; + } else if (data_size >= 20) { + src_buf = data; + } else { + src_buf = buf; + for (ptr = (uint8_t *)src_buf, i = 20; i > 0; + i -= data_size, ptr += data_size) + memcpy(ptr, data, + min_t(size_t, i, data_size)); + } + } + bin_func(dst_reg->digest, src_buf, 20); + dst_reg->valid = true; + dst_modified = true; + break; + case HRE_LOADKEY: + if (hre_op_loadkey(src_reg, dst_reg, data, data_size)) + return NULL; + break; + default: + return NULL; + } + + if (dst_reg && dst_modified && IS_PCR_HREG(dst_spec)) { + hre_tpm_err = tpm_extend(HREG_IDX(dst_spec), dst_reg->digest, + dst_reg->digest); + if (hre_tpm_err) { + hre_err = HRE_E_TPM_FAILURE; + return NULL; + } + } +end: + *ip += 4; + *code_size -= 4; + if (opcode & 0x80) { + *ip += data_size; + *code_size -= data_size; + } + + return *ip; +} + +/** + * @brief runs a program on the hash register engine. + * @param code pointer to the (HRE) code. + * @param code_size size of the code (in bytes). + * @return 0 on success, != 0 on failure. + */ +int hre_run_program(const uint8_t *code, size_t code_size) +{ + size_t code_left; + const uint8_t *ip = code; + + code_left = code_size; + hre_tpm_err = 0; + hre_err = HRE_E_OK; + while (code_left > 0) + if (!hre_execute_op(&ip, &code_left)) + return -1; + + return hre_err; +} + +int hre_verify_program(struct key_program *prg) +{ + uint32_t crc; + + crc = crc32(0, prg->code, prg->code_size); + + if (crc != prg->code_crc) { + printf("HRC crc mismatch: %08x != %08x\n", + crc, prg->code_crc); + return 1; + } + return 0; +} diff --git a/board/gdsys/a38x/hre.h b/board/gdsys/a38x/hre.h new file mode 100644 index 0000000000..84ce2794fa --- /dev/null +++ b/board/gdsys/a38x/hre.h @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2013 + * Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __HRE_H +#define __HRE_H + +struct key_program { + uint32_t magic; + uint32_t code_crc; + uint32_t code_size; + uint8_t code[]; +}; + +struct h_reg { + bool valid; + uint8_t digest[20]; +}; + +/* CCDM specific contants */ +enum { + /* NV indices */ + NV_COMMON_DATA_INDEX = 0x40000001, + /* magics for key blob chains */ + MAGIC_KEY_PROGRAM = 0x68726500, + MAGIC_HMAC = 0x68616300, + MAGIC_END_OF_CHAIN = 0x00000000, + /* sizes */ + NV_COMMON_DATA_MIN_SIZE = 3 * sizeof(uint64_t) + 2 * sizeof(uint16_t), +}; + +int hre_verify_program(struct key_program *prg); +int hre_run_program(const uint8_t *code, size_t code_size); + +#endif /* __HRE_H */ diff --git a/board/gdsys/a38x/hydra.c b/board/gdsys/a38x/hydra.c new file mode 100644 index 0000000000..fa50ad2830 --- /dev/null +++ b/board/gdsys/a38x/hydra.c @@ -0,0 +1,138 @@ +#include +#include /* ctrlc */ +#include + +#include "hydra.h" + +enum { + HWVER_100 = 0, + HWVER_110 = 1, + HWVER_120 = 2, +}; + +static struct pci_device_id hydra_supported[] = { + { 0x6d5e, 0xcdc1 }, + {} +}; + +static struct ihs_fpga *fpga; + +struct ihs_fpga *get_fpga(void) +{ + return fpga; +} + +void print_hydra_version(uint index) +{ + u32 versions = readl(&fpga->versions); + u32 fpga_version = readl(&fpga->fpga_version); + + uint hardware_version = versions & 0xf; + + printf("FPGA%u: mapped to %p\n ", index, fpga); + + switch (hardware_version) { + case HWVER_100: + printf("HW-Ver 1.00\n"); + break; + + case HWVER_110: + printf("HW-Ver 1.10\n"); + break; + + case HWVER_120: + printf("HW-Ver 1.20\n"); + break; + + default: + printf("HW-Ver %d(not supported)\n", + hardware_version); + break; + } + + printf(" FPGA V %d.%02d\n", + fpga_version / 100, fpga_version % 100); +} + +void hydra_initialize(void) +{ + uint i; + pci_dev_t devno; + + /* Find and probe all the matching PCI devices */ + for (i = 0; (devno = pci_find_devices(hydra_supported, i)) >= 0; i++) { + u32 val; + + /* Try to enable I/O accesses and bus-mastering */ + val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + pci_write_config_dword(devno, PCI_COMMAND, val); + + /* Make sure it worked */ + pci_read_config_dword(devno, PCI_COMMAND, &val); + if (!(val & PCI_COMMAND_MEMORY)) { + puts("Can't enable I/O memory\n"); + continue; + } + if (!(val & PCI_COMMAND_MASTER)) { + puts("Can't enable bus-mastering\n"); + continue; + } + + /* read FPGA details */ + fpga = pci_map_bar(devno, PCI_BASE_ADDRESS_0, + PCI_REGION_MEM); + + print_hydra_version(i); + } +} + +#define REFL_PATTERN (0xdededede) +#define REFL_PATTERN_INV (~REFL_PATTERN) + +int do_hydrate(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + uint k = 0; + void __iomem *pcie2_base = (void __iomem *)(MVEBU_REG_PCIE_BASE + + 0x4000); + + if (!fpga) + return -1; + + while (1) { + u32 res; + + writel(REFL_PATTERN, &fpga->reflection_low); + res = readl(&fpga->reflection_low); + if (res != REFL_PATTERN_INV) + printf("round %u: read %08x, expected %08x\n", + k, res, REFL_PATTERN_INV); + writel(REFL_PATTERN_INV, &fpga->reflection_low); + res = readl(&fpga->reflection_low); + if (res != REFL_PATTERN) + printf("round %u: read %08x, expected %08x\n", + k, res, REFL_PATTERN); + + res = readl(pcie2_base + 0x118) & 0x1f; + if (res) + printf("FrstErrPtr %u\n", res); + res = readl(pcie2_base + 0x104); + if (res) { + printf("Uncorrectable Error Status 0x%08x\n", res); + writel(res, pcie2_base + 0x104); + } + + if (!(++k % 10000)) + printf("round %u\n", k); + + if (ctrlc()) + break; + } + + return 0; +} + +U_BOOT_CMD( + hydrate, 1, 0, do_hydrate, + "hydra reflection test", + "hydra reflection test" +); diff --git a/board/gdsys/a38x/hydra.h b/board/gdsys/a38x/hydra.h new file mode 100644 index 0000000000..26562a560a --- /dev/null +++ b/board/gdsys/a38x/hydra.h @@ -0,0 +1,14 @@ +struct ihs_fpga { + u32 reflection_low; /* 0x0000 */ + u32 versions; /* 0x0004 */ + u32 fpga_version; /* 0x0008 */ + u32 fpga_features; /* 0x000c */ + u32 reserved0[4]; /* 0x0010 */ + u32 control; /* 0x0020 */ + u32 reserved1[375]; /* 0x0024 */ + u32 qsgmii_port_state[80]; /* 0x0600 */ +}; + +void print_hydra_version(uint index); +void hydra_initialize(void); +struct ihs_fpga *get_fpga(void); diff --git a/board/gdsys/a38x/ihs_phys.c b/board/gdsys/a38x/ihs_phys.c new file mode 100644 index 0000000000..494de18f86 --- /dev/null +++ b/board/gdsys/a38x/ihs_phys.c @@ -0,0 +1,355 @@ +#include +#include +#include +#include + +#include "ihs_phys.h" +#include "dt_helpers.h" + +enum { + PORTTYPE_MAIN_CAT, + PORTTYPE_TOP_CAT, + PORTTYPE_16C_16F, + PORTTYPE_UNKNOWN +}; + +static struct porttype { + bool phy_invert_in_pol; + bool phy_invert_out_pol; +} porttypes[] = { + { true, false }, + { false, true }, + { false, false }, +}; + +static void ihs_phy_config(struct phy_device *phydev, bool qinpn, bool qoutpn) +{ + u16 reg; + + phy_config(phydev); + + /* enable QSGMII autonegotiation with flow control */ + phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0004); + reg = phy_read(phydev, MDIO_DEVAD_NONE, 16); + reg |= (3 << 6); + phy_write(phydev, MDIO_DEVAD_NONE, 16, reg); + + /* + * invert QSGMII Q_INP/N and Q_OUTP/N if required + * and perform global reset + */ + reg = phy_read(phydev, MDIO_DEVAD_NONE, 26); + if (qinpn) + reg |= (1 << 13); + if (qoutpn) + reg |= (1 << 12); + reg |= (1 << 15); + phy_write(phydev, MDIO_DEVAD_NONE, 26, reg); + + /* advertise 1000BASE-T full-duplex only */ + phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000); + reg = phy_read(phydev, MDIO_DEVAD_NONE, 4); + reg &= ~0x1e0; + phy_write(phydev, MDIO_DEVAD_NONE, 4, reg); + reg = phy_read(phydev, MDIO_DEVAD_NONE, 9); + reg = (reg & ~0x300) | 0x200; + phy_write(phydev, MDIO_DEVAD_NONE, 9, reg); + + /* copper power up */ + reg = phy_read(phydev, MDIO_DEVAD_NONE, 16); + reg &= ~0x0004; + phy_write(phydev, MDIO_DEVAD_NONE, 16, reg); +} + +uint calculate_octo_phy_mask(void) +{ + uint k; + uint octo_phy_mask = 0; + struct gpio_desc gpio = {}; + char gpio_name[64]; + static const char * const dev_name[] = {"pca9698@23", "pca9698@21", + "pca9698@24", "pca9698@25", + "pca9698@26"}; + + /* mark all octo phys that should be present */ + for (k = 0; k < 5; ++k) { + snprintf(gpio_name, 64, "cat-gpio-%u", k); + + if (request_gpio_by_name(&gpio, dev_name[k], 0x20, gpio_name)) + continue; + + /* check CAT flag */ + if (dm_gpio_get_value(&gpio)) + octo_phy_mask |= (1 << (k * 2)); + else + /* If CAT == 0, there's no second octo phy -> skip */ + continue; + + snprintf(gpio_name, 64, "second-octo-gpio-%u", k); + + if (request_gpio_by_name(&gpio, dev_name[k], 0x27, gpio_name)) { + /* default: second octo phy is present */ + octo_phy_mask |= (1 << (k * 2 + 1)); + continue; + } + + if (dm_gpio_get_value(&gpio) == 0) + octo_phy_mask |= (1 << (k * 2 + 1)); + } + + return octo_phy_mask; +} + +int register_miiphy_bus(uint k, struct mii_dev **bus) +{ + int retval; + struct mii_dev *mdiodev = mdio_alloc(); + char *name = bb_miiphy_buses[k].name; + + if (!mdiodev) + return -ENOMEM; + strncpy(mdiodev->name, + name, + MDIO_NAME_LEN); + mdiodev->read = bb_miiphy_read; + mdiodev->write = bb_miiphy_write; + + retval = mdio_register(mdiodev); + if (retval < 0) + return retval; + *bus = miiphy_get_dev_by_name(name); + + return 0; +} + +struct porttype *get_porttype(uint octo_phy_mask, uint k) +{ + uint octo_index = k * 4; + + if (!k) { + if (octo_phy_mask & 0x01) + return &porttypes[PORTTYPE_MAIN_CAT]; + else if (!(octo_phy_mask & 0x03)) + return &porttypes[PORTTYPE_16C_16F]; + } else { + if (octo_phy_mask & (1 << octo_index)) + return &porttypes[PORTTYPE_TOP_CAT]; + } + + return NULL; +} + +int init_single_phy(struct porttype *porttype, struct mii_dev *bus, + uint bus_idx, uint m, uint phy_idx) +{ + struct phy_device *phydev = phy_find_by_mask( + bus, 1 << (m * 8 + phy_idx), + PHY_INTERFACE_MODE_MII); + + printf(" %u", bus_idx * 32 + m * 8 + phy_idx); + + if (!phydev) + puts("!"); + else + ihs_phy_config(phydev, porttype->phy_invert_in_pol, + porttype->phy_invert_out_pol); + + return 0; +} + +int init_octo_phys(uint octo_phy_mask) +{ + uint bus_idx; + + /* there are up to four octo-phys on each mdio bus */ + for (bus_idx = 0; bus_idx < bb_miiphy_buses_num; ++bus_idx) { + uint m; + uint octo_index = bus_idx * 4; + struct mii_dev *bus = NULL; + struct porttype *porttype = NULL; + int ret; + + porttype = get_porttype(octo_phy_mask, bus_idx); + + if (!porttype) + continue; + + for (m = 0; m < 4; ++m) { + uint phy_idx; + + /** + * Register a bus device if there is at least one phy + * on the current bus + */ + if (!m && octo_phy_mask & (0xf << octo_index)) { + ret = register_miiphy_bus(bus_idx, &bus); + if (ret) + return ret; + } + + if (!(octo_phy_mask & BIT(octo_index + m))) + continue; + + for (phy_idx = 0; phy_idx < 8; ++phy_idx) + init_single_phy(porttype, bus, bus_idx, m, + phy_idx); + } + } + + return 0; +} + +/* + * MII GPIO bitbang implementation + * MDC MDIO bus + * 13 14 PHY1-4 + * 25 45 PHY5-8 + * 46 24 PHY9-10 + */ + +struct gpio_mii { + int index; + struct gpio_desc mdc_gpio; + struct gpio_desc mdio_gpio; + int mdc_num; + int mdio_num; + int mdio_value; +} gpio_mii_set[] = { + { 0, {}, {}, 13, 14, 1 }, + { 1, {}, {}, 25, 45, 1 }, + { 2, {}, {}, 46, 24, 1 }, +}; + +static int mii_mdio_init(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + char name[32] = {}; + struct udevice *gpio_dev1 = NULL; + struct udevice *gpio_dev2 = NULL; + + if (uclass_get_device_by_name(UCLASS_GPIO, "gpio@18100", &gpio_dev1) || + uclass_get_device_by_name(UCLASS_GPIO, "gpio@18140", &gpio_dev2)) { + printf("Could not get GPIO device.\n"); + return 1; + } + + if (gpio_mii->mdc_num > 31) { + gpio_mii->mdc_gpio.dev = gpio_dev2; + gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num - 32; + } else { + gpio_mii->mdc_gpio.dev = gpio_dev1; + gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num; + } + gpio_mii->mdc_gpio.flags = 0; + snprintf(name, 32, "bb_miiphy_bus-%d-mdc", gpio_mii->index); + dm_gpio_request(&gpio_mii->mdc_gpio, name); + + if (gpio_mii->mdio_num > 31) { + gpio_mii->mdio_gpio.dev = gpio_dev2; + gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num - 32; + } else { + gpio_mii->mdio_gpio.dev = gpio_dev1; + gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num; + } + gpio_mii->mdio_gpio.flags = 0; + snprintf(name, 32, "bb_miiphy_bus-%d-mdio", gpio_mii->index); + dm_gpio_request(&gpio_mii->mdio_gpio, name); + + dm_gpio_set_dir_flags(&gpio_mii->mdc_gpio, GPIOD_IS_OUT); + dm_gpio_set_value(&gpio_mii->mdc_gpio, 1); + + return 0; +} + +static int mii_mdio_active(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + + dm_gpio_set_value(&gpio_mii->mdc_gpio, gpio_mii->mdio_value); + + return 0; +} + +static int mii_mdio_tristate(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + + dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN); + + return 0; +} + +static int mii_set_mdio(struct bb_miiphy_bus *bus, int v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_OUT); + dm_gpio_set_value(&gpio_mii->mdio_gpio, v); + gpio_mii->mdio_value = v; + + return 0; +} + +static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN); + *v = (dm_gpio_get_value(&gpio_mii->mdio_gpio)); + + return 0; +} + +static int mii_set_mdc(struct bb_miiphy_bus *bus, int v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + dm_gpio_set_value(&gpio_mii->mdc_gpio, v); + + return 0; +} + +static int mii_delay(struct bb_miiphy_bus *bus) +{ + udelay(1); + + return 0; +} + +struct bb_miiphy_bus bb_miiphy_buses[] = { + { + .name = "ihs0", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[0], + }, + { + .name = "ihs1", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[1], + }, + { + .name = "ihs2", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[2], + }, +}; + +int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses); diff --git a/board/gdsys/a38x/ihs_phys.h b/board/gdsys/a38x/ihs_phys.h new file mode 100644 index 0000000000..c4bec4d46c --- /dev/null +++ b/board/gdsys/a38x/ihs_phys.h @@ -0,0 +1,2 @@ +uint calculate_octo_phy_mask(void); +int init_octo_phys(uint octo_phy_mask); diff --git a/board/gdsys/a38x/keyprogram.c b/board/gdsys/a38x/keyprogram.c new file mode 100644 index 0000000000..a4a6f1cca5 --- /dev/null +++ b/board/gdsys/a38x/keyprogram.c @@ -0,0 +1,158 @@ +/* + * (C) Copyright 2016 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#include "hre.h" + +int flush_keys(void) +{ + u16 key_count; + u8 buf[288]; + u8 *ptr; + u32 err; + uint i; + + /* fetch list of already loaded keys in the TPM */ + err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf)); + if (err) + return -1; + key_count = get_unaligned_be16(buf); + ptr = buf + 2; + for (i = 0; i < key_count; ++i, ptr += 4) { + err = tpm_flush_specific(get_unaligned_be32(ptr), TPM_RT_KEY); + if (err && err != TPM_KEY_OWNER_CONTROL) + return err; + } + + return 0; +} + +int decode_hexstr(char *hexstr, u8 **result) +{ + int len = strlen(hexstr); + int bytes = len / 2; + int i; + u8 acc = 0; + + if (len % 2 == 1) + return 1; + + *result = (u8 *)malloc(bytes); + + for (i = 0; i < len; i++) { + char cur = tolower(hexstr[i]); + u8 val; + + if ((cur >= 'a' && cur <= 'f') || (cur >= '0' && cur <= '9')) { + val = cur - (cur > '9' ? 87 : 48); + + if (i % 2 == 0) + acc = 16 * val; + else + (*result)[i / 2] = acc + val; + } else { + free(*result); + return 1; + } + } + + return 0; +} + +int extract_subprogram(u8 **progdata, u32 expected_magic, + struct key_program **result) +{ + struct key_program *prog = *result; + u32 magic, code_crc, code_size; + + magic = get_unaligned_be32(*progdata); + code_crc = get_unaligned_be32(*progdata + 4); + code_size = get_unaligned_be32(*progdata + 8); + + *progdata += 12; + + if (magic != expected_magic) + return -1; + + *result = malloc(sizeof(struct key_program) + code_size); + + if (!*result) + return -1; + + prog->magic = magic; + prog->code_crc = code_crc; + prog->code_size = code_size; + memcpy(prog->code, *progdata, code_size); + + *progdata += code_size; + + if (hre_verify_program(prog)) { + free(prog); + return -1; + } + + return 0; +} + +struct key_program *parse_and_check_keyprog(u8 *progdata) +{ + struct key_program *result = NULL, *hmac = NULL; + + /* Part 1: Load key program */ + + if (extract_subprogram(&progdata, MAGIC_KEY_PROGRAM, &result)) + return NULL; + + /* Part 2: Load hmac program */ + + if (extract_subprogram(&progdata, MAGIC_HMAC, &hmac)) + return NULL; + + free(hmac); + + return result; +} + +int load_and_run_keyprog(void) +{ + char *cmd = NULL; + u8 *binprog = NULL; + char *hexprog; + struct key_program *prog; + + cmd = getenv("loadkeyprogram"); + + if (!cmd || run_command(cmd, 0)) + return 1; + + hexprog = getenv("keyprogram"); + + if (decode_hexstr(hexprog, &binprog)) + return 1; + + prog = parse_and_check_keyprog(binprog); + free(binprog); + + if (!prog) + return 1; + + if (hre_run_program(prog->code, prog->code_size)) { + free(prog); + return 1; + } + + printf("\nSD code ran successfully\n"); + + free(prog); + + return 0; +} diff --git a/board/gdsys/a38x/keyprogram.h b/board/gdsys/a38x/keyprogram.h new file mode 100644 index 0000000000..a5ea7d3137 --- /dev/null +++ b/board/gdsys/a38x/keyprogram.h @@ -0,0 +1,14 @@ +/* + * (C) Copyright 2016 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __KEYPROGRAM_H +#define __KEYPROGRAM_H + +int load_and_run_keyprog(void); +int flush_keys(void); + +#endif /* __KEYPROGRAM_H */ diff --git a/board/gdsys/a38x/kwbimage.cfg.in b/board/gdsys/a38x/kwbimage.cfg.in new file mode 100644 index 0000000000..72e67d75c3 --- /dev/null +++ b/board/gdsys/a38x/kwbimage.cfg.in @@ -0,0 +1,12 @@ +# +# Copyright (C) 2014 Stefan Roese +# + +# Armada 38x uses version 1 image format +VERSION 1 + +# Boot Media configurations +#@BOOT_FROM + +# Binary Header (bin_hdr) with DDR3 training code +BINARY spl/u-boot-spl.bin 0000005b 00000068 diff --git a/board/gdsys/a38x/spl.c b/board/gdsys/a38x/spl.c new file mode 100644 index 0000000000..2d05a9c98a --- /dev/null +++ b/board/gdsys/a38x/spl.c @@ -0,0 +1,21 @@ +/* + * (C) Copyright 2016 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +void spl_board_init(void) +{ +#if CONFIG_SPL_BOOT_DEVICE == SPL_BOOT_SPI_NOR_FLASH + u32 *bootrom_save = (u32 *)CONFIG_SPL_BOOTROM_SAVE; + u32 *regs = (u32 *)(*bootrom_save); + + printf("Returning to BootROM (return address %08x)...\n", regs[13]); + return_to_bootrom(); +#endif +} diff --git a/configs/controlcenterdc_defconfig b/configs/controlcenterdc_defconfig new file mode 100644 index 0000000000..e1c4f0c999 --- /dev/null +++ b/configs/controlcenterdc_defconfig @@ -0,0 +1,58 @@ +CONFIG_ARM=y +CONFIG_ARCH_MVEBU=y +CONFIG_SPL_GPIO_SUPPORT=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_TARGET_CONTROLCENTERDC=y +CONFIG_SPL_SPI_FLASH_SUPPORT=y +CONFIG_SPL_SPI_SUPPORT=y +CONFIG_DEFAULT_DEVICE_TREE="armada-38x-controlcenterdc" +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_FIT_VERBOSE=y +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_SPL=y +CONFIG_SPL_SYS_MALLOC_SIMPLE=y +CONFIG_HUSH_PARSER=y +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_GO is not set +# CONFIG_CMD_IMLS is not set +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y +CONFIG_CMD_USB=y +CONFIG_CMD_GPIO=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TPM=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_EFI_PARTITION=y +CONFIG_OF_BOARD_FIXUP=y +CONFIG_SPL_OF_TRANSLATE=y +CONFIG_DM_GPIO=y +CONFIG_DM_PCA953X=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_MVTWSI=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_MV=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_BASE=0xd0012000 +CONFIG_DEBUG_UART_CLOCK=250000000 +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_SYS_NS16550=y +CONFIG_TPM_ATMEL_TWI=y +CONFIG_TPM_AUTH_SESSIONS=y +CONFIG_TPM_FLUSH_RESOURCES=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_TPM=y +# CONFIG_EFI_LOADER is not set diff --git a/include/configs/controlcenterdc.h b/include/configs/controlcenterdc.h new file mode 100644 index 0000000000..add5f90cc2 --- /dev/null +++ b/include/configs/controlcenterdc.h @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2014 Stefan Roese + * Copyright (C) 2016 Mario Six + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _CONFIG_CONTROLCENTERDC_H +#define _CONFIG_CONTROLCENTERDC_H + +/* + * High Level Configuration Options (easy to change) + */ +#define CONFIG_CUSTOMER_BOARD_SUPPORT + +#define CONFIG_SKIP_LOWLEVEL_INIT /* disable board lowlevel_init */ +#define CONFIG_DISPLAY_BOARDINFO_LATE +#define CONFIG_BOARD_LATE_INIT +#define CONFIG_LAST_STAGE_INIT +#define CONFIG_SPL_BOARD_INIT + +/* + * TEXT_BASE needs to be below 16MiB, since this area is scrubbed + * for DDR ECC byte filling in the SPL before loading the main + * U-Boot into it. + */ +#define CONFIG_SYS_TEXT_BASE 0x00800000 + +#define CONFIG_SYS_TCLK 250000000 /* 250MHz */ + +#define CONFIG_LOADADDR 1000000 + +/* + * Commands configuration + */ +#define CONFIG_CMD_ENV +#define CONFIG_CMD_I2C +#define CONFIG_CMD_PCI +#define CONFIG_CMD_SCSI +#define CONFIG_CMD_SPI + +/* SPI NOR flash default params, used by sf commands */ +#define CONFIG_SF_DEFAULT_BUS 1 +#define CONFIG_SF_DEFAULT_SPEED 1000000 +#define CONFIG_SF_DEFAULT_MODE SPI_MODE_3 + +/* + * SDIO/MMC Card Configuration + */ +#define CONFIG_SYS_MMC_BASE MVEBU_SDIO_BASE + +/* + * SATA/SCSI/AHCI configuration + */ +#define CONFIG_LIBATA +#define CONFIG_SCSI +#define CONFIG_SCSI_AHCI +#define CONFIG_SCSI_AHCI_PLAT +#define CONFIG_SYS_SCSI_MAX_SCSI_ID 2 +#define CONFIG_SYS_SCSI_MAX_LUN 1 +#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ + CONFIG_SYS_SCSI_MAX_LUN) + +/* Additional FS support/configuration */ +#define CONFIG_SUPPORT_VFAT + +/* USB/EHCI configuration */ +#define CONFIG_EHCI_IS_TDI + +/* Environment in SPI NOR flash */ +#define CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_SPI_BUS 1 +#define CONFIG_ENV_OFFSET (1 << 20) /* 1MiB in */ +#define CONFIG_ENV_SIZE (64 << 10) /* 64KiB */ +#define CONFIG_ENV_SECT_SIZE (256 << 10) /* 256KiB sectors */ + +#define CONFIG_PHY_MARVELL /* there is a marvell phy */ +#define PHY_ANEG_TIMEOUT 8000 /* PHY needs a longer aneg time */ + +/* PCIe support */ +#ifndef CONFIG_SPL_BUILD +#define CONFIG_PCI +#define CONFIG_PCI_MVEBU +#define CONFIG_PCI_PNP +#define CONFIG_PCI_SCAN_SHOW +#endif + +#define CONFIG_SYS_ALT_MEMTEST + +/* + * Software (bit-bang) MII driver configuration + */ +#define CONFIG_BITBANGMII /* bit-bang MII PHY management */ +#define CONFIG_BITBANGMII_MULTI + +/* SPL */ +/* + * Select the boot device here + * + * Currently supported are: + * SPL_BOOT_SPI_NOR_FLASH - Booting via SPI NOR flash + * SPL_BOOT_SDIO_MMC_CARD - Booting via SDIO/MMC card (partition 1) + */ +#define SPL_BOOT_SPI_NOR_FLASH 1 +#define SPL_BOOT_SDIO_MMC_CARD 2 +#define CONFIG_SPL_BOOT_DEVICE SPL_BOOT_SPI_NOR_FLASH + +/* Defines for SPL */ +#define CONFIG_SPL_FRAMEWORK +#define CONFIG_SPL_SIZE (160 << 10) + +#if defined(CONFIG_SECURED_MODE_IMAGE) +#define CONFIG_SPL_TEXT_BASE 0x40002614 +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x2614) +#else +#define CONFIG_SPL_TEXT_BASE 0x40000030 +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x30) +#endif + +#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) +#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) + +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_MALLOC_SIMPLE +#endif + +#define CONFIG_SPL_STACK (0x40000000 + ((212 - 16) << 10)) +#define CONFIG_SPL_BOOTROM_SAVE (CONFIG_SPL_STACK + 4) + +#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_I2C_SUPPORT + +#if CONFIG_SPL_BOOT_DEVICE == SPL_BOOT_SPI_NOR_FLASH +/* SPL related SPI defines */ +#define CONFIG_SPL_SPI_LOAD +#define CONFIG_SYS_SPI_U_BOOT_OFFS 0x30000 +#define CONFIG_SYS_U_BOOT_OFFS CONFIG_SYS_SPI_U_BOOT_OFFS +#endif + +#if CONFIG_SPL_BOOT_DEVICE == SPL_BOOT_SDIO_MMC_CARD +/* SPL related MMC defines */ +#define CONFIG_SPL_MMC_SUPPORT +#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 1 +#define CONFIG_SYS_MMC_U_BOOT_OFFS (168 << 10) +#define CONFIG_SYS_U_BOOT_OFFS CONFIG_SYS_MMC_U_BOOT_OFFS +#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR (CONFIG_SYS_U_BOOT_OFFS / 512) +#ifdef CONFIG_SPL_BUILD +#define CONFIG_FIXED_SDHCI_ALIGNED_BUFFER 0x00180000 /* in SDRAM */ +#endif +#endif + +/* + * Environment Configuration + */ +#define CONFIG_ENV_OVERWRITE + +#define CONFIG_BAUDRATE 115200 + +#define CONFIG_HOSTNAME ccdc +#define CONFIG_ROOTPATH "/opt/nfsroot" +#define CONFIG_BOOTFILE "ccdc.img" + +#define CONFIG_PREBOOT /* enable preboot variable */ + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "netdev=eth1\0" \ + "consoledev=ttyS1\0" \ + "u-boot=u-boot.bin\0" \ + "bootfile_addr=1000000\0" \ + "keyprogram_addr=3000000\0" \ + "keyprogram_file=keyprogram.img\0" \ + "fdtfile=controlcenterdc.dtb\0" \ + "load=tftpboot ${loadaddr} ${u-boot}\0" \ + "mmcdev=0:2\0" \ + "update=sf probe 1:0;" \ + " sf erase 0 +${filesize};" \ + " sf write ${fileaddr} 0 ${filesize}\0" \ + "upd=run load update\0" \ + "fdt_high=0x10000000\0" \ + "initrd_high=0x10000000\0" \ + "loadkeyprogram=tpm flush_keys;" \ + " mmc rescan;" \ + " ext4load mmc ${mmcdev} ${keyprogram_addr} ${keyprogram_file};"\ + " source ${keyprogram_addr}:script@1\0" \ + "gpio1=gpio@22_25\0" \ + "gpio2=A29\0" \ + "blinkseq='0 0 0 0 2 0 2 2 3 1 3 1 0 0 2 2 3 1 3 3 2 0 2 2 3 1 1 1 " \ + "2 0 2 2 3 1 3 1 0 0 2 0 3 3 3 1 2 0 0 0 3 1 1 1 0 0 0 0'\0" \ + "bootfail=for i in ${blinkseq}; do" \ + " if test $i -eq 0; then" \ + " gpio clear ${gpio1}; gpio set ${gpio2};" \ + " elif test $i -eq 1; then" \ + " gpio clear ${gpio1}; gpio clear ${gpio2};" \ + " elif test $i -eq 2; then" \ + " gpio set ${gpio1}; gpio set ${gpio2};" \ + " else;" \ + " gpio clear ${gpio1}; gpio set ${gpio2};" \ + " fi; sleep 0.12; done\0" + +#define CONFIG_NFSBOOTCOMMAND \ + "setenv bootargs root=/dev/nfs rw " \ + "nfsroot=${serverip}:${rootpath} " \ + "ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off " \ + "console=${consoledev},${baudrate} ${othbootargs}; " \ + "tftpboot ${bootfile_addr} ${bootfile}; " \ + "bootm ${bootfile_addr}" + +#define CONFIG_MMCBOOTCOMMAND \ + "setenv bootargs root=/dev/mmcblk0p3 rw rootwait " \ + "console=${consoledev},${baudrate} ${othbootargs}; " \ + "ext2load mmc 0:2 ${bootfile_addr} ${bootfile}; " \ + "bootm ${bootfile_addr}" + +#define CONFIG_BOOTCOMMAND \ + "if env exists keyprogram; then;" \ + " setenv keyprogram; run nfsboot;" \ + " fi;" \ + " run dobootfail" + +/* + * mv-common.h should be defined after CMD configs since it used them + * to enable certain macros + */ +#include "mv-common.h" + +#endif /* _CONFIG_CONTROLCENTERDC_H */