On 23.11.2016 16:12, Mario Six wrote: > From: Dirk Eibach <dirk.eib...@gdsys.cc> > > 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 <dirk.eib...@gdsys.cc> > Signed-off-by: Mario Six <mario....@gdsys.cc> > --- > arch/arm/Kconfig | 1 + > arch/arm/dts/Makefile | 3 +- > arch/arm/dts/controlcenterdc.dts | 629 +++++++++++++++++++++++++++++++++
Could you perhaps rename this file (and board name as well?) to something like "armada-38x-controlcenterdc*" instead? Its much easier to match the files to the architecture this way. And until now, all Armada XP / 38x (etc) files match this rule. > arch/arm/mach-mvebu/Kconfig | 4 + > board/gdsys/38x/.gitignore | 1 + Perhaps better s/38x/a38x for "Armada"? > board/gdsys/38x/Kconfig | 42 +++ > board/gdsys/38x/MAINTAINERS | 7 + > board/gdsys/38x/Makefile | 30 ++ > board/gdsys/38x/README | 18 + > board/gdsys/38x/controlcenterdc.c | 717 > ++++++++++++++++++++++++++++++++++++++ > board/gdsys/38x/dt_helpers.c | 60 ++++ > board/gdsys/38x/dt_helpers.h | 16 + > board/gdsys/38x/hre.c | 517 +++++++++++++++++++++++++++ > board/gdsys/38x/hre.h | 38 ++ > board/gdsys/38x/keyprogram.c | 158 +++++++++ > board/gdsys/38x/keyprogram.h | 14 + > board/gdsys/38x/kwbimage.cfg.in | 12 + > board/gdsys/38x/spl.c | 21 ++ > configs/controlcenterdc_defconfig | 54 +++ > include/configs/controlcenterdc.h | 244 +++++++++++++ > 20 files changed, 2585 insertions(+), 1 deletion(-) > create mode 100644 arch/arm/dts/controlcenterdc.dts > create mode 100644 board/gdsys/38x/.gitignore > create mode 100644 board/gdsys/38x/Kconfig > create mode 100644 board/gdsys/38x/MAINTAINERS > create mode 100644 board/gdsys/38x/Makefile > create mode 100644 board/gdsys/38x/README > create mode 100644 board/gdsys/38x/controlcenterdc.c > create mode 100644 board/gdsys/38x/dt_helpers.c > create mode 100644 board/gdsys/38x/dt_helpers.h > create mode 100644 board/gdsys/38x/hre.c > create mode 100644 board/gdsys/38x/hre.h > create mode 100644 board/gdsys/38x/keyprogram.c > create mode 100644 board/gdsys/38x/keyprogram.h > create mode 100644 board/gdsys/38x/kwbimage.cfg.in > create mode 100644 board/gdsys/38x/spl.c > create mode 100644 configs/controlcenterdc_defconfig > create mode 100644 include/configs/controlcenterdc.h > > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig > index acd689b..f4c236b 100644 > --- a/arch/arm/Kconfig > +++ b/arch/arm/Kconfig > @@ -970,6 +970,7 @@ source "board/freescale/mx53loco/Kconfig" > source "board/freescale/mx53smd/Kconfig" > source "board/freescale/s32v234evb/Kconfig" > source "board/freescale/vf610twr/Kconfig" > +source "board/gdsys/38x/Kconfig" > source "board/gumstix/pepper/Kconfig" > source "board/h2200/Kconfig" > source "board/hisilicon/hikey/Kconfig" > diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile > index 2c5b2f2..b0bd507 100644 > --- a/arch/arm/dts/Makefile > +++ b/arch/arm/dts/Makefile > @@ -76,7 +76,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 \ > + controlcenterdc.dtb > > dtb-$(CONFIG_ARCH_UNIPHIER) += \ > uniphier-ld11-ref.dtb \ > diff --git a/arch/arm/dts/controlcenterdc.dts > b/arch/arm/dts/controlcenterdc.dts > new file mode 100644 > index 0000000..baf0171 > --- /dev/null > +++ b/arch/arm/dts/controlcenterdc.dts > @@ -0,0 +1,629 @@ > +/* > + * Device Tree file for the Guntermann & Drunck ControlCenter-Compact board > + * > + * Copyright (C) 2016 Mario Six <mario....@gdsys.cc> > + * > + * based on the Device Tree file for Marvell Armada 388 evaluation board > + * (DB-88F6820), which is > + * > + * Copyright (C) 2014 Marvell > + * > + * Thomas Petazzoni <thomas.petazz...@free-electrons.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +/dts-v1/; > + > +#include "armada-388.dtsi" > + > +&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 = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000 > + MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>; > + > + 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>; > + }; > + }; > + }; > + > + cat_gpio_0 { > + compatible = "generic,cat-gpio-0"; > + gpios = <&PCA23 0x20 0x0>; > + }; > + > + cat_gpio_1 { > + compatible = "generic,cat-gpio-1"; > + gpios = <&PCA21 0x20 0x0>; > + }; > + > + cat_gpio_2 { > + compatible = "generic,cat-gpio-2"; > + gpios = <&PCA24 0x20 0x0>; > + }; > + > + cat_gpio_3 { > + compatible = "generic,cat-gpio-3"; > + gpios = <&PCA25 0x20 0x0>; > + }; > + > + cat_gpio_4 { > + compatible = "generic,cat-gpio-4"; > + gpios = <&PCA26 0x20 0x0>; > + }; > + > + second_octo_gpio_0 { > + compatible = "generic,second-octo-gpio-0"; > + gpios = <&PCA23 0x27 0x0>; > + }; > + > + fpga_program_gpio { > + compatible = "generic,fpga-program-gpio"; > + u-boot,dm-pre-reloc; > + gpios = <&PCA22 31 0>; > + }; > + > + fpga_done_gpio { > + compatible = "generic,fpga-done-gpio"; > + u-boot,dm-pre-reloc; > + gpios = <&PCA22 19 0>; > + }; > + > + fpga_ready_gpio { > + compatible = "generic,fpga-ready-gpio"; > + u-boot,dm-pre-reloc; > + gpios = <&PCA22 27 0>; > + }; > + > + 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 1ca7b52..ac36894 100644 > --- a/arch/arm/mach-mvebu/Kconfig > +++ b/arch/arm/mach-mvebu/Kconfig > @@ -102,6 +102,10 @@ config TARGET_THEADORABLE > bool "Support theadorable Armada XP" > select MV78260 > > +config TARGET_CONTROLCENTERDC > + bool "Support CONTROLCENTERDC" > + select 88F6820 > + > endchoice > > config SYS_BOARD > diff --git a/board/gdsys/38x/.gitignore b/board/gdsys/38x/.gitignore > new file mode 100644 > index 0000000..775b934 > --- /dev/null > +++ b/board/gdsys/38x/.gitignore > @@ -0,0 +1 @@ > +kwbimage.cfg > diff --git a/board/gdsys/38x/Kconfig b/board/gdsys/38x/Kconfig > new file mode 100644 > index 0000000..dd99ac5 > --- /dev/null > +++ b/board/gdsys/38x/Kconfig > @@ -0,0 +1,42 @@ > +if TARGET_CONTROLCENTERDC > + > +config SYS_BOARD > + default "38x" > + > +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 > + > +config SYS_BOOTIMAGE_DEST_ADDR > + hex "Boot image destination address" > + default 0x007fffc0 > + help > + Blah Hmmm, the help text is not really "helpful". ;) This option is also not referenced, so perhaps you can remove it? > + > +endmenu > + > +endif > diff --git a/board/gdsys/38x/MAINTAINERS b/board/gdsys/38x/MAINTAINERS > new file mode 100644 > index 0000000..5dbc6ec > --- /dev/null > +++ b/board/gdsys/38x/MAINTAINERS > @@ -0,0 +1,7 @@ > +38X BOARD > +M: Dirk Eibach <eib...@gdsys.cc> > +M: Mario Six <s...@gdsys.de> > +S: Maintained > +F: board/gdsys/38x/ > +F: include/configs/controlcenterdc.h > +F: configs/controlcenterdc_defconfig > diff --git a/board/gdsys/38x/Makefile b/board/gdsys/38x/Makefile > new file mode 100644 > index 0000000..6d17196 > --- /dev/null > +++ b/board/gdsys/38x/Makefile > @@ -0,0 +1,30 @@ > +# > +# Copyright (C) 2015 Stefan Roese <s...@denx.de> > +# Copyright (C) 2015 Reinhard Pfau <reinhard.p...@gdsys.cc> > +# Copyright (C) 2016 Mario Six <mario....@gdsys.cc> > +# > +# 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),) > + > +extra-$(CONFIG_TARGET_CONTROLCENTERDC) += kwbimage.cfg > + > +ifneq ($(CONFIG_TARGET_CONTROLCENTERDC),) > +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 > +endif Do you have multiple build targets for this directory? Do you need to have this check with CONFIG_TARGET_CONTROLCENTERDC? > + > +$(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' \ > + <$< >$@ > + > +endif > diff --git a/board/gdsys/38x/README b/board/gdsys/38x/README > new file mode 100644 > index 0000000..9bea5b3 > --- /dev/null > +++ b/board/gdsys/38x/README > @@ -0,0 +1,18 @@ > +Update from original Marvell U-Boot to mainline U-Boot: > +------------------------------------------------------- > + > +The resulting image including the SPL binary with the > +full DDR setup is "u-boot-spl.kwb". > + > +To update the SPI NOR flash, please use the following > +command: > + > +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ > +sf update 2000000 0 60000 > + > +Note that the original Marvell U-Boot seems to have > +problems with the "sf update" command. This does not > +work reliable. So here this command should be used: > + > +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ > +sf erase 0 60000;sf write 2000000 0 60000 You copied this file from the Marvell directory. Does it really make sense to add it here as well? I suggest to just remove it. > diff --git a/board/gdsys/38x/controlcenterdc.c > b/board/gdsys/38x/controlcenterdc.c > new file mode 100644 > index 0000000..f151265 > --- /dev/null > +++ b/board/gdsys/38x/controlcenterdc.c > @@ -0,0 +1,717 @@ > +/* > + * Copyright (C) 2015 Stefan Roese <s...@denx.de> > + * Copyright (C) 2016 Mario Six <mario....@gdsys.cc> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <console.h> /* disable_ctrlc */ > +#include <miiphy.h> > +#include <tpm.h> > +#include <asm/io.h> > +#include <asm/arch/cpu.h> > +#include <asm/arch/gpio.h> > +#include <asm-generic/gpio.h> > + > +#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" > + > +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 > + > +#ifndef CONFIG_SPL_BUILD > +enum { > + HWVER_100 = 0, > + HWVER_110 = 1, > + HWVER_120 = 2, > +}; > + > +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 }, > +}; > + > +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 */ > +}; > + > +static struct ihs_fpga *fpga; > + > +static struct pci_device_id hydra_supported[] = { > + { 0x6d5e, 0xcdc1 }, > + {} > +}; > +#endif > + > +/* > + * 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 (get_gpio("generic,fpga-program-gpio", &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 (get_gpio("generic,fpga-done-gpio", &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 */ > + kw_gpio_set_valid(6, GPIO_OUTPUT_OK); > + kw_gpio_direction_output(6, 1); Ah, here you use the "old" GPIO infrastucture. Please move to the DM GPIO driver and use the generic API instead. > + > + /* wait for FPGA ready */ > + if (get_gpio("generic,fpga-ready-gpio", &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) > +{ > + /* adress of boot parameters */ > + gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100; > + > + return 0; > +} > + > +int checkboard(void) > +{ > + puts("Board: Controlcenter Digital Compact\n"); > + > + return 0; > +} With DT support you should already get the board model printed from the DT. Do yo need this line here as well? > + > +#ifndef CONFIG_SPL_BUILD > +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); > +} > + > +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); > + } > +} > + > +uint calculate_octo_phy_mask(void) > +{ > + uint k; > + uint octo_phy_mask = 0; > + struct gpio_desc gpio = {}; > + char name[64]; > + > + /* mark all octo phys that should be present */ > + for (k = 0; k < 5; ++k) { > + snprintf(name, 64, "generic,cat-gpio-%u", k); > + > + if (!get_gpio(name, &gpio)) > + 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(name, 64, "generic,second-octo-gpio-%u", k); > + > + if (!get_gpio(name, &gpio)) { > + /* 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; I'm wondering how this works if "bb_miiphy_buses" is defined later in this file and you have no header file. > + > + 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_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 > + */ Multiline comment style please. > + if (!m && octo_phy_mask & (0xf << octo_index)) { > + ret = register_miiphy_bus(bus_idx, &bus); > + if (ret) > + return ret; > + } > + > + if (!(octo_phy_mask & (1 << (octo_index + m)))) > + continue; > + > + for (phy_idx = 0; phy_idx < 8; ++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); > + > + ihs_phy_config(phydev, > + porttype->phy_invert_in_pol, > + porttype->phy_invert_out_pol); > + } > + } > + } > + > + return 0; > +} > + > +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"); > + > + /* reset all FPGA-QSGMII instances */ > + for (k = 0; k < 80; ++k) > + writel(1 << 31, &fpga->qsgmii_port_state[k]); > + > + udelay(100); > + > + for (k = 0; k < 80; ++k) > + writel(0, &fpga->qsgmii_port_state[k]); > + return 0; > +} > + > +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); > +} > + > +static 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); > + } > +} > +#endif > + > +int board_late_init(void) > +{ > +#ifndef CONFIG_SPL_BUILD > + hydra_initialize(); > +#endif > + return 0; > +} > + > +int board_fix_fdt(void) > +{ > + struct udevice *bus; > + uint k; > + char name[64]; > + > + bus = dev_get_by_ofname("/soc/internal-regs/i2c@11000"); > + > + 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(name); > + } > + > + return 0; > +} > + > +int last_stage_init(void) > +{ > + disable_ctrlc(1); > + > +#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; > +} > + > +#ifndef CONFIG_SPL_BUILD > + > +#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" > +); > + > +/* > + * MII GPIO bitbang implementation > + * MDC MDIO bus > + * 13 14 PHY1-4 > + * 25 45 PHY5-8 > + * 46 24 PHY9-10 > + */ > + > +struct gpio_mii { > + int mdc; > + int mdio; > + int mdio_value; > +} gpio_mii_set[] = { > + { 13, 14, 1 }, > + { 25, 45, 1 }, > + { 46, 24, 1 }, > +}; > + > +static int mii_mdio_init(struct bb_miiphy_bus *bus) > +{ > + struct gpio_mii *gpio_mii = bus->priv; > + > + kw_gpio_set_valid(gpio_mii->mdc, GPIO_OUTPUT_OK); > + kw_gpio_set_valid(gpio_mii->mdio, GPIO_INPUT_OK | GPIO_OUTPUT_OK); > + kw_gpio_direction_output(gpio_mii->mdc, 1); > + > + return 0; > +} > + > +static int mii_mdio_active(struct bb_miiphy_bus *bus) > +{ > + struct gpio_mii *gpio_mii = bus->priv; > + > + kw_gpio_direction_output(gpio_mii->mdio, gpio_mii->mdio_value); > + > + return 0; > +} > + > +static int mii_mdio_tristate(struct bb_miiphy_bus *bus) > +{ > + struct gpio_mii *gpio_mii = bus->priv; > + > + kw_gpio_direction_input(gpio_mii->mdio); > + > + return 0; > +} > + > +static int mii_set_mdio(struct bb_miiphy_bus *bus, int v) > +{ > + struct gpio_mii *gpio_mii = bus->priv; > + > + kw_gpio_set_value(gpio_mii->mdio, 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; > + > + *v = (kw_gpio_get_value(gpio_mii->mdio) != 0); > + > + return 0; > +} > + > +static int mii_set_mdc(struct bb_miiphy_bus *bus, int v) > +{ > + struct gpio_mii *gpio_mii = bus->priv; > + > + kw_gpio_set_value(gpio_mii->mdc, 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 = sizeof(bb_miiphy_buses) / > + sizeof(bb_miiphy_buses[0]); static? And can you use ARRAY_SIZE()? > +#endif Perhaps its also a good idea to move at least some of this code (especiall the command and perhaps some MDIO stuff) into separate files that are only compiled for non-SPL U-Boot. This will remove some of the #ifdefs as well. > diff --git a/board/gdsys/38x/dt_helpers.c b/board/gdsys/38x/dt_helpers.c > new file mode 100644 > index 0000000..dedd048 > --- /dev/null > +++ b/board/gdsys/38x/dt_helpers.c > @@ -0,0 +1,60 @@ > +/* > + * (C) Copyright 2016 > + * Mario Six, Guntermann & Drunck GmbH, mario....@gdsys.cc > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <i2c.h> > +#include <dm.h> > +#include <fdt_support.h> > +#include <asm-generic/gpio.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +bool get_gpio(char *name, struct gpio_desc *gpio) > +{ > + int node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, name); > + int ret; > + > + if (node < 0) > + return false; > + > + ret = gpio_request_by_name_nodev(gd->fdt_blob, node, "gpios", 0, gpio, > + 0); > + > + if (ret < 0) > + return false; > + > + return dm_gpio_is_valid(gpio); > +} > + > +int fdt_disable_by_ofname(char *ofname) > +{ > + void *blob = gd->fdt_blob; > + int offset; > + > + offset = fdt_path_offset(blob, ofname); > + return fdt_status_disabled(blob, offset); > +} > + > +struct udevice *dev_get_by_ofname(char *ofname) > +{ > + void *blob = gd->fdt_blob; > + int offset; > + struct udevice *dev; > + > + offset = fdt_path_offset(blob, ofname); > + device_get_global_by_of_offset(offset, &dev); > + > + return dev; > +} > + > +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); > +} At least some of this might be very helpful as common U-Boot functions available for all boards. > diff --git a/board/gdsys/38x/dt_helpers.h b/board/gdsys/38x/dt_helpers.h > new file mode 100644 > index 0000000..8052b94 > --- /dev/null > +++ b/board/gdsys/38x/dt_helpers.h > @@ -0,0 +1,16 @@ > +/* > + * (C) Copyright 2016 > + * Mario Six, Guntermann & Drunck GmbH, mario....@gdsys.cc > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#ifndef __DT_HELPERS_H > +#define __DT_HELPERS_H > + > +bool get_gpio(char *name, struct gpio_desc *gpio); > +int fdt_disable_by_ofname(char *ofname); > +struct udevice *dev_get_by_ofname(char *ofname); > +bool dm_i2c_simple_probe(struct udevice *bus, uint chip_addr); > + > +#endif /* __DT_HELPERS_H */ > diff --git a/board/gdsys/38x/hre.c b/board/gdsys/38x/hre.c > new file mode 100644 > index 0000000..10bf1a0 > --- /dev/null > +++ b/board/gdsys/38x/hre.c > @@ -0,0 +1,517 @@ > +/* > + * (C) Copyright 2013 > + * Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.p...@gdsys.cc > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <malloc.h> > +#include <fs.h> > +#include <i2c.h> > +#include <mmc.h> > +#include <tpm.h> > +#include <u-boot/sha1.h> > +#include <asm/byteorder.h> > +#include <asm/unaligned.h> > +#include <pca9698.h> > + > +#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; > + } > + /* TODO remember key handle somehow? */ Is this comment still valid? > + > + 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/38x/hre.h b/board/gdsys/38x/hre.h > new file mode 100644 > index 0000000..84ce279 > --- /dev/null > +++ b/board/gdsys/38x/hre.h > @@ -0,0 +1,38 @@ > +/* > + * (C) Copyright 2013 > + * Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.p...@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/38x/keyprogram.c b/board/gdsys/38x/keyprogram.c > new file mode 100644 > index 0000000..a4a6f1c > --- /dev/null > +++ b/board/gdsys/38x/keyprogram.c > @@ -0,0 +1,158 @@ > +/* > + * (C) Copyright 2016 > + * Mario Six, Guntermann & Drunck GmbH, mario....@gdsys.cc > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <tpm.h> > +#include <malloc.h> > +#include <linux/ctype.h> > +#include <asm/unaligned.h> > + > +#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/38x/keyprogram.h b/board/gdsys/38x/keyprogram.h > new file mode 100644 > index 0000000..a5ea7d3 > --- /dev/null > +++ b/board/gdsys/38x/keyprogram.h > @@ -0,0 +1,14 @@ > +/* > + * (C) Copyright 2016 > + * Mario Six, Guntermann & Drunck GmbH, mario....@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/38x/kwbimage.cfg.in b/board/gdsys/38x/kwbimage.cfg.in > new file mode 100644 > index 0000000..72e67d7 > --- /dev/null > +++ b/board/gdsys/38x/kwbimage.cfg.in > @@ -0,0 +1,12 @@ > +# > +# Copyright (C) 2014 Stefan Roese <s...@denx.de> > +# > + > +# 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/38x/spl.c b/board/gdsys/38x/spl.c > new file mode 100644 > index 0000000..2d05a9c > --- /dev/null > +++ b/board/gdsys/38x/spl.c > @@ -0,0 +1,21 @@ > +/* > + * (C) Copyright 2016 > + * Mario Six, Guntermann & Drunck GmbH, mario....@gdsys.cc > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <config.h> > +#include <asm/arch/cpu.h> > + > +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 0000000..ee06c84 > --- /dev/null > +++ b/configs/controlcenterdc_defconfig > @@ -0,0 +1,54 @@ > +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="controlcenterdc" > +CONFIG_FIT=y > +CONFIG_FIT_VERBOSE=y > +CONFIG_FIT_SIGNATURE=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_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_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_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 0000000..9097dce > --- /dev/null > +++ b/include/configs/controlcenterdc.h > @@ -0,0 +1,244 @@ > +/* > + * Copyright (C) 2014 Stefan Roese <s...@denx.de> > + * Copyright (C) 2016 Mario Six <mario....@gdsys.cc> > + * > + * 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 > + > +#define CONFIG_SYS_NO_FLASH /* Declare no flash (NOR/SPI) */ > + > +/* > + * 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_MMC > +#define CONFIG_GENERIC_MMC > +#define CONFIG_SDHCI > +#define CONFIG_MV_SDHCI > +#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) > + > +/* Partition support */ > +#define CONFIG_DOS_PARTITION > +#define CONFIG_EFI_PARTITION > + > +/* 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 > + > +/* > + * GPIO > + */ > +#define CONFIG_KIRKWOOD_GPIO > + > +/* 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) > +#define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS ((512 << 10) / 512) /* 512KiB */ > +#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 */ > Thanks, Stefan _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot