Merge git://www.denx.de/git/u-boot-marvell

This mainly adds support for some new boards, like the ARMv8 community
boards MACCHIATOBin and ESPRESSBin
This commit is contained in:
Tom Rini 2017-03-24 07:21:57 -04:00
commit c1daa40773
51 changed files with 3921 additions and 175 deletions

View file

@ -1284,6 +1284,7 @@ source "board/freescale/mx53evk/Kconfig"
source "board/freescale/mx53loco/Kconfig" source "board/freescale/mx53loco/Kconfig"
source "board/freescale/mx53smd/Kconfig" source "board/freescale/mx53smd/Kconfig"
source "board/freescale/s32v234evb/Kconfig" source "board/freescale/s32v234evb/Kconfig"
source "board/gdsys/a38x/Kconfig"
source "board/grinn/chiliboard/Kconfig" source "board/grinn/chiliboard/Kconfig"
source "board/gumstix/pepper/Kconfig" source "board/gumstix/pepper/Kconfig"
source "board/h2200/Kconfig" source "board/h2200/Kconfig"

View file

@ -71,16 +71,19 @@ dtb-$(CONFIG_TEGRA) += tegra20-harmony.dtb \
dtb-$(CONFIG_ARCH_MVEBU) += \ dtb-$(CONFIG_ARCH_MVEBU) += \
armada-3720-db.dtb \ armada-3720-db.dtb \
armada-3720-espressobin.dtb \
armada-375-db.dtb \ armada-375-db.dtb \
armada-388-clearfog.dtb \ armada-388-clearfog.dtb \
armada-388-gp.dtb \ armada-388-gp.dtb \
armada-385-amc.dtb \ armada-385-amc.dtb \
armada-7040-db.dtb \ armada-7040-db.dtb \
armada-8040-db.dtb \ armada-8040-db.dtb \
armada-8040-mcbin.dtb \
armada-xp-gp.dtb \ armada-xp-gp.dtb \
armada-xp-maxbcm.dtb \ armada-xp-maxbcm.dtb \
armada-xp-synology-ds414.dtb \ armada-xp-synology-ds414.dtb \
armada-xp-theadorable.dtb armada-xp-theadorable.dtb \
armada-38x-controlcenterdc.dtb
dtb-$(CONFIG_ARCH_UNIPHIER_LD11) += \ dtb-$(CONFIG_ARCH_UNIPHIER_LD11) += \
uniphier-ld11-ref.dtb uniphier-ld11-ref.dtb

View file

@ -0,0 +1,135 @@
/*
* Device Tree file for Marvell Armada 3720 community board
* (ESPRESSOBin)
* Copyright (C) 2016 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Konstantin Porotchkin <kostap@marvell.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
* licensing only applies to this file, and not this project as a
* whole.
*
* a) This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Or, alternatively
*
* b) Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
#include "armada-372x.dtsi"
/ {
model = "Marvell Armada 3720 Community Board ESPRESSOBin";
compatible = "marvell,armada-3720-espressobin", "marvell,armada3720", "marvell,armada3710";
chosen {
stdout-path = "serial0:115200n8";
};
aliases {
ethernet0 = &eth0;
i2c0 = &i2c0;
spi0 = &spi0;
};
memory {
device_type = "memory";
reg = <0x00000000 0x00000000 0x00000000 0x20000000>;
};
};
&comphy {
max-lanes = <3>;
phy0 {
phy-type = <PHY_TYPE_PEX0>;
phy-speed = <PHY_SPEED_2_5G>;
};
phy1 {
phy-type = <PHY_TYPE_USB3_HOST0>;
phy-speed = <PHY_SPEED_5G>;
};
phy2 {
phy-type = <PHY_TYPE_SATA0>;
phy-speed = <PHY_SPEED_5G>;
};
};
&eth0 {
status = "okay";
phy-mode = "rgmii";
phy_addr = <0x1>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
&i2c0 {
status = "okay";
};
/* CON3 */
&sata {
status = "okay";
};
&spi0 {
status = "okay";
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "st,m25p128", "spi-flash";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <50000000>;
m25p,fast-read;
};
};
/* Exported on the micro USB connector CON32 through an FTDI */
&uart0 {
status = "okay";
};
/* CON29 */
&usb2 {
status = "okay";
};
/* CON31 */
&usb3 {
status = "okay";
};

View file

@ -193,6 +193,20 @@
status = "disabled"; status = "disabled";
}; };
pinctl0: pinctl@13830 { /* north bridge */
compatible = "marvell,armada-3700-pinctl";
bank-name = "armada-3700-nb";
reg = <0x13830 0x4>;
pin-count = <36>;
};
pinctl1: pinctl@18830 { /* south bridge */
compatible = "marvell,armada-3700-pinctl";
bank-name = "armada-3700-sb";
reg = <0x18830 0x4>;
pin-count = <30>;
};
comphy: comphy@18300 { comphy: comphy@18300 {
compatible = "marvell,mvebu-comphy", "marvell,comphy-armada-3700"; compatible = "marvell,mvebu-comphy", "marvell,comphy-armada-3700";
reg = <0x18300 0x28>, reg = <0x18300 0x28>,

View file

@ -0,0 +1,589 @@
/*
* Device Tree file for the Guntermann & Drunck ControlCenter-Compact board
*
* Copyright (C) 2016 Mario Six <mario.six@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.petazzoni@free-electrons.com>
*
* 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 = &eth0;
ethernet2 = &eth2;
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>;
};
};
};
leds {
compatible = "gpio-leds";
finder_led {
label = "finder-led";
gpios = <&PCA22 25 0>;
};
status_led {
label = "status-led";
gpios = <&gpio0 29 0>;
};
};
};

View file

@ -45,6 +45,7 @@
* one CP110. * one CP110.
*/ */
#include <dt-bindings/gpio/gpio.h>
#include "armada-ap806-quad.dtsi" #include "armada-ap806-quad.dtsi"
#include "armada-cp110-master.dtsi" #include "armada-cp110-master.dtsi"

View file

@ -0,0 +1,293 @@
/*
* Copyright (C) 2016 Marvell International Ltd.
*
* SPDX-License-Identifier: GPL-2.0
* https://spdx.org/licenses
*/
#include "armada-8040.dtsi" /* include SoC device tree */
/ {
model = "MACCHIATOBin-8040";
compatible = "marvell,armada8040-mcbin",
"marvell,armada8040";
chosen {
stdout-path = "serial0:115200n8";
};
aliases {
i2c0 = &cpm_i2c0;
i2c1 = &cpm_i2c1;
spi0 = &cps_spi1;
gpio0 = &ap_gpio0;
gpio1 = &cpm_gpio0;
gpio2 = &cpm_gpio1;
};
memory@00000000 {
device_type = "memory";
reg = <0x0 0x0 0x0 0x80000000>;
};
simple-bus {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <0>;
reg_usb3h0_vbus: usb3-vbus0 {
compatible = "regulator-fixed";
pinctrl-names = "default";
pinctrl-0 = <&cpm_xhci_vbus_pins>;
regulator-name = "reg-usb3h0-vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
startup-delay-us = <500000>;
enable-active-high;
regulator-always-on;
regulator-boot-on;
gpio = <&cpm_gpio1 15 GPIO_ACTIVE_HIGH>; /* GPIO[47] */
};
};
};
/* Accessible over the mini-USB CON9 connector on the main board */
&uart0 {
status = "okay";
};
&ap_pinctl {
/*
* MPP Bus:
* eMMC [0-10]
* UART0 [11,19]
*/
/* 0 1 2 3 4 5 6 7 8 9 */
pin-func = < 1 1 1 1 1 1 1 1 1 1
1 3 0 0 0 0 0 0 0 3 >;
};
/* on-board eMMC */
&ap_sdhci0 {
pinctrl-names = "default";
pinctrl-0 = <&ap_emmc_pins>;
bus-width= <8>;
status = "okay";
};
&cpm_pinctl {
/*
* MPP Bus:
* [0-31] = 0xff: Keep default CP0_shared_pins:
* [11] CLKOUT_MPP_11 (out)
* [23] LINK_RD_IN_CP2CP (in)
* [25] CLKOUT_MPP_25 (out)
* [29] AVS_FB_IN_CP2CP (in)
* [32,34] SMI
* [33] MSS power down
* [35-38] CP0 I2C1 and I2C0
* [39] MSS CKE Enable
* [40,41] CP0 UART1 TX/RX
* [42,43] XSMI (controls two 10G phys)
* [47] USB VBUS EN
* [48] FAN PWM
* [49] 10G port 1 interrupt
* [50] 10G port 0 interrupt
* [51] 2.5G SFP TX fault
* [52] PCIe reset out
* [53] 2.5G SFP mode
* [54] 2.5G SFP LOS
* [55] Micro SD card detect
* [56-61] Micro SD
* [62] CP1 KR SFP FAULT
*/
/* 0 1 2 3 4 5 6 7 8 9 */
pin-func = < 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
0xff 0 7 0xa 7 2 2 2 2 0xa
7 7 8 8 0 0 0 0 0 0
0 0 0 0 0 0 0xe 0xe 0xe 0xe
0xe 0xe 0 >;
cpm_xhci_vbus_pins: cpm-xhci-vbus-pins {
marvell,pins = < 47 >;
marvell,function = <0>;
};
cpm_pcie_reset_pins: cpm-pcie-reset-pins {
marvell,pins = < 52 >;
marvell,function = <0>;
};
};
/* uSD slot */
&cpm_sdhci0 {
pinctrl-names = "default";
pinctrl-0 = <&cpm_sdhci_pins>;
bus-width= <4>;
status = "okay";
};
/* PCIe x4 */
&cpm_pcie0 {
num-lanes = <4>;
pinctrl-names = "default";
pinctrl-0 = <&cpm_pcie_reset_pins>;
marvell,reset-gpio = <&cpm_gpio1 20 GPIO_ACTIVE_HIGH>; /* GPIO[52] */
status = "okay";
};
&cpm_i2c0 {
pinctrl-names = "default";
pinctrl-0 = <&cpm_i2c0_pins>;
status = "okay";
clock-frequency = <100000>;
};
&cpm_i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&cpm_i2c1_pins>;
status = "okay";
clock-frequency = <100000>;
};
&cpm_sata0 {
status = "okay";
};
&cpm_comphy {
/*
* CP0 Serdes Configuration:
* Lane 0: PCIe0 (x4)
* Lane 1: PCIe0 (x4)
* Lane 2: PCIe0 (x4)
* Lane 3: PCIe0 (x4)
* Lane 4: KR (10G)
* Lane 5: SATA1
*/
phy0 {
phy-type = <PHY_TYPE_PEX0>;
};
phy1 {
phy-type = <PHY_TYPE_PEX0>;
};
phy2 {
phy-type = <PHY_TYPE_PEX0>;
};
phy3 {
phy-type = <PHY_TYPE_PEX0>;
};
phy4 {
phy-type = <PHY_TYPE_KR>;
};
phy5 {
phy-type = <PHY_TYPE_SATA1>;
};
};
&cps_sata0 {
status = "okay";
};
&cps_usb3_0 {
vbus-supply = <&reg_usb3h0_vbus>;
status = "okay";
};
&cps_utmi0 {
status = "okay";
};
&cps_pinctl {
/*
* MPP Bus:
* [0-5] TDM
* [6,7] CP1_UART 0
* [8] CP1 10G SFP LOS
* [9] CP1 10G PHY RESET
* [10] CP1 10G SFP TX Disable
* [11] CP1 10G SFP Mode
* [12] SPI1 CS1n
* [13] SPI1 MISO (TDM and SPI ROM shared)
* [14] SPI1 CS0n
* [15] SPI1 MOSI (TDM and SPI ROM shared)
* [16] SPI1 CLK (TDM and SPI ROM shared)
* [24] CP1 2.5G SFP TX Disable
* [26] CP0 10G SFP TX Fault
* [27] CP0 10G SFP Mode
* [28] CP0 10G SFP LOS
* [29] CP0 10G SFP TX Disable
* [30] USB Over current indication
* [31] 10G Port 0 phy reset
* [32-62] = 0xff: Keep default CP1_shared_pins:
*/
/* 0 1 2 3 4 5 6 7 8 9 */
pin-func = < 0x4 0x4 0x4 0x4 0x4 0x4 0x8 0x8 0x0 0x0
0x0 0x0 0x3 0x3 0x3 0x3 0x3 0xff 0xff 0xff
0xff 0xff 0xff 0xff 0x0 0xff 0x0 0x0 0x0 0x0
0x0 0x0 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
0xff 0xff 0xff>;
};
&cps_spi1 {
pinctrl-names = "default";
pinctrl-0 = <&cps_spi1_pins>;
status = "okay";
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <10000000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "U-Boot";
reg = <0 0x200000>;
};
partition@400000 {
label = "Filesystem";
reg = <0x200000 0xce0000>;
};
};
};
};
&cps_comphy {
/*
* CP1 Serdes Configuration:
* Lane 0: SGMII2
* Lane 1: SATA 0
* Lane 2: USB HOST 0
* Lane 3: SATA1
* Lane 4: KR (10G)
* Lane 5: SGMII3
*/
phy0 {
phy-type = <PHY_TYPE_SGMII2>;
phy-speed = <PHY_SPEED_1_25G>;
};
phy1 {
phy-type = <PHY_TYPE_SATA0>;
};
phy2 {
phy-type = <PHY_TYPE_USB3_HOST0>;
};
phy3 {
phy-type = <PHY_TYPE_SATA1>;
};
phy4 {
phy-type = <PHY_TYPE_KR>;
};
phy5 {
phy-type = <PHY_TYPE_SGMII3>;
};
};

View file

@ -45,6 +45,7 @@
* two CP110. * two CP110.
*/ */
#include <dt-bindings/gpio/gpio.h>
#include "armada-ap806-quad.dtsi" #include "armada-ap806-quad.dtsi"
#include "armada-cp110-master.dtsi" #include "armada-cp110-master.dtsi"
#include "armada-cp110-slave.dtsi" #include "armada-cp110-slave.dtsi"

View file

@ -158,6 +158,14 @@
}; };
}; };
ap_gpio0: gpio@6F5040 {
compatible = "marvell,orion-gpio";
reg = <0x6F5040 0x40>;
ngpios = <20>;
gpio-controller;
#gpio-cells = <2>;
};
xor@400000 { xor@400000 {
compatible = "marvell,mv-xor-v2"; compatible = "marvell,mv-xor-v2";
reg = <0x400000 0x1000>, reg = <0x400000 0x1000>,

View file

@ -94,6 +94,10 @@
marvell,pins = < 37 38 >; marvell,pins = < 37 38 >;
marvell,function = <2>; marvell,function = <2>;
}; };
cpm_i2c1_pins: cpm-i2c-pins-1 {
marvell,pins = < 35 36 >;
marvell,function = <2>;
};
cpm_ge2_rgmii_pins: cpm-ge-rgmii-pins-0 { cpm_ge2_rgmii_pins: cpm-ge-rgmii-pins-0 {
marvell,pins = < 44 45 46 47 48 49 50 51 marvell,pins = < 44 45 46 47 48 49 50 51
52 53 54 55 >; 52 53 54 55 >;
@ -113,6 +117,24 @@
}; };
}; };
cpm_gpio0: gpio@440100 {
compatible = "marvell,orion-gpio";
reg = <0x440100 0x40>;
ngpios = <32>;
gpiobase = <20>;
gpio-controller;
#gpio-cells = <2>;
};
cpm_gpio1: gpio@440140 {
compatible = "marvell,orion-gpio";
reg = <0x440140 0x40>;
ngpios = <31>;
gpiobase = <52>;
gpio-controller;
#gpio-cells = <2>;
};
cpm_sata0: sata@540000 { cpm_sata0: sata@540000 {
compatible = "marvell,armada-8k-ahci"; compatible = "marvell,armada-8k-ahci";
reg = <0x540000 0x30000>; reg = <0x540000 0x30000>;

View file

@ -100,6 +100,24 @@
}; };
}; };
cps_gpio0: gpio@440100 {
compatible = "marvell,orion-gpio";
reg = <0x440100 0x40>;
ngpios = <32>;
gpiobase = <20>;
gpio-controller;
#gpio-cells = <2>;
};
cps_gpio1: gpio@440140 {
compatible = "marvell,orion-gpio";
reg = <0x440140 0x40>;
ngpios = <31>;
gpiobase = <52>;
gpio-controller;
#gpio-cells = <2>;
};
cps_sata0: sata@540000 { cps_sata0: sata@540000 {
compatible = "marvell,armada-8k-ahci"; compatible = "marvell,armada-8k-ahci";
reg = <0x540000 0x30000>; reg = <0x540000 0x30000>;

View file

@ -74,8 +74,8 @@ config TARGET_CLEARFOG
bool "Support ClearFog" bool "Support ClearFog"
select 88F6820 select 88F6820
config TARGET_MVEBU_DB_88F3720 config TARGET_MVEBU_ARMADA_37XX
bool "Support DB-88F3720 Armada 3720" bool "Support Armada 37xx platforms"
select ARMADA_3700 select ARMADA_3700
config TARGET_DB_88F6720 config TARGET_DB_88F6720
@ -112,11 +112,15 @@ config TARGET_THEADORABLE
select BOARD_LATE_INIT if USB select BOARD_LATE_INIT if USB
select MV78260 select MV78260
config TARGET_CONTROLCENTERDC
bool "Support CONTROLCENTERDC"
select 88F6820
endchoice endchoice
config SYS_BOARD config SYS_BOARD
default "clearfog" if TARGET_CLEARFOG default "clearfog" if TARGET_CLEARFOG
default "mvebu_db-88f3720" if TARGET_MVEBU_DB_88F3720 default "mvebu_armada-37xx" if TARGET_MVEBU_ARMADA_37XX
default "db-88f6720" if TARGET_DB_88F6720 default "db-88f6720" if TARGET_DB_88F6720
default "db-88f6820-gp" if TARGET_DB_88F6820_GP default "db-88f6820-gp" if TARGET_DB_88F6820_GP
default "db-88f6820-amc" if TARGET_DB_88F6820_AMC default "db-88f6820-amc" if TARGET_DB_88F6820_AMC
@ -128,7 +132,7 @@ config SYS_BOARD
config SYS_CONFIG_NAME config SYS_CONFIG_NAME
default "clearfog" if TARGET_CLEARFOG default "clearfog" if TARGET_CLEARFOG
default "mvebu_db-88f3720" if TARGET_MVEBU_DB_88F3720 default "mvebu_armada-37xx" if TARGET_MVEBU_ARMADA_37XX
default "db-88f6720" if TARGET_DB_88F6720 default "db-88f6720" if TARGET_DB_88F6720
default "db-88f6820-gp" if TARGET_DB_88F6820_GP default "db-88f6820-gp" if TARGET_DB_88F6820_GP
default "db-88f6820-amc" if TARGET_DB_88F6820_AMC default "db-88f6820-amc" if TARGET_DB_88F6820_AMC
@ -140,7 +144,7 @@ config SYS_CONFIG_NAME
config SYS_VENDOR config SYS_VENDOR
default "Marvell" if TARGET_DB_MV784MP_GP default "Marvell" if TARGET_DB_MV784MP_GP
default "Marvell" if TARGET_MVEBU_DB_88F3720 default "Marvell" if TARGET_MVEBU_ARMADA_37XX
default "Marvell" if TARGET_DB_88F6720 default "Marvell" if TARGET_DB_88F6720
default "Marvell" if TARGET_DB_88F6820_GP default "Marvell" if TARGET_DB_88F6820_GP
default "Marvell" if TARGET_DB_88F6820_AMC default "Marvell" if TARGET_DB_88F6820_AMC

View file

@ -230,6 +230,20 @@ static int serdes_max_lines_get(void)
return 0; return 0;
} }
/*
* Tests have shown that on some boards the default width of the
* configuration pulse for the PEX link detection might lead to
* non-established PCIe links (link down). Especially under certain
* conditions (higher temperature) and with specific PCIe devices.
* To enable a board-specific detection pulse width this weak
* array "serdes_pex_pulse_width[4]" is introduced which can be
* overwritten if needed by a board-specific version. If the board
* code does not provide a non-weak version of this variable, the
* default value will be used. So nothing is changed from the
* current setup on the supported board.
*/
__weak u8 serdes_pex_pulse_width[4] = { 2, 2, 2, 2 };
int serdes_phy_config(void) int serdes_phy_config(void)
{ {
int status = MV_OK; int status = MV_OK;
@ -891,6 +905,23 @@ int serdes_phy_config(void)
pex_unit = line_num >> 2; pex_unit = line_num >> 2;
pex_line_num = line_num % 4; pex_line_num = line_num % 4;
if (0 == pex_line_num) { if (0 == pex_line_num) {
/*
* Configure the detection pulse with before
* the reset is deasserted
*/
/* Read the old value (indirect access) */
reg_write(PEX_PHY_ACCESS_REG(pex_unit),
(0x48 << 16) | (1 << 31) |
(pex_line_num << 24));
tmp = reg_read(PEX_PHY_ACCESS_REG(pex_unit));
tmp &= ~(1 << 31); /* Clear read */
tmp &= ~(3 << 6); /* Mask width */
/* Insert new detection pulse width */
tmp |= serdes_pex_pulse_width[pex_unit] << 6;
/* Write value back */
reg_write(PEX_PHY_ACCESS_REG(pex_unit), tmp);
reg_write(PEX_PHY_ACCESS_REG(pex_unit), reg_write(PEX_PHY_ACCESS_REG(pex_unit),
(0xC1 << 16) | 0x24); (0xC1 << 16) | 0x24);
DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit), DEBUG_WR_REG(PEX_PHY_ACCESS_REG(pex_unit),

View file

@ -1,6 +1,6 @@
MVEBU_DB_88F3720 BOARD MVEBU_DB_88F3720 BOARD
M: Stefan Roese <sr@denx.de> M: Stefan Roese <sr@denx.de>
S: Maintained S: Maintained
F: board/Marvell/mvebu_db-88f3720/ F: board/Marvell/mvebu_armada-37xx/
F: include/configs/mvebu_db-88f3720.h F: include/configs/mvebu_armada-37xx.h
F: configs/mvebu_db-88f3720_defconfig F: configs/mvebu_db-88f3720_defconfig

View file

@ -0,0 +1,258 @@
/*
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <phy.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
DECLARE_GLOBAL_DATA_PTR;
/* IO expander I2C device */
#define I2C_IO_EXP_ADDR 0x22
#define I2C_IO_CFG_REG_0 0x6
#define I2C_IO_DATA_OUT_REG_0 0x2
#define I2C_IO_REG_0_SATA_OFF 2
#define I2C_IO_REG_0_USB_H_OFF 1
/* The pin control values are the same for DB and Espressobin */
#define PINCTRL_NB_REG_VALUE 0x000173fa
#define PINCTRL_SB_REG_VALUE 0x00007a23
/* Ethernet switch registers */
/* SMI addresses for multi-chip mode */
#define MVEBU_PORT_CTRL_SMI_ADDR(p) (16 + (p))
#define MVEBU_SW_G2_SMI_ADDR (28)
/* Multi-chip mode */
#define MVEBU_SW_SMI_DATA_REG (1)
#define MVEBU_SW_SMI_CMD_REG (0)
#define SW_SMI_CMD_REG_ADDR_OFF 0
#define SW_SMI_CMD_DEV_ADDR_OFF 5
#define SW_SMI_CMD_SMI_OP_OFF 10
#define SW_SMI_CMD_SMI_MODE_OFF 12
#define SW_SMI_CMD_SMI_BUSY_OFF 15
/* Single-chip mode */
/* Switch Port Registers */
#define MVEBU_SW_LINK_CTRL_REG (1)
#define MVEBU_SW_PORT_CTRL_REG (4)
/* Global 2 Registers */
#define MVEBU_G2_SMI_PHY_CMD_REG (24)
#define MVEBU_G2_SMI_PHY_DATA_REG (25)
int board_early_init_f(void)
{
const void *blob = gd->fdt_blob;
const char *bank_name;
const char *compat = "marvell,armada-3700-pinctl";
int off, len;
void __iomem *addr;
/* FIXME
* Temporary WA for setting correct pin control values
* until the real pin control driver is awailable.
*/
off = fdt_node_offset_by_compatible(blob, -1, compat);
while (off != -FDT_ERR_NOTFOUND) {
bank_name = fdt_getprop(blob, off, "bank-name", &len);
addr = (void __iomem *)fdtdec_get_addr_size_auto_noparent(
blob, off, "reg", 0, NULL, true);
if (!strncmp(bank_name, "armada-3700-nb", len))
writel(PINCTRL_NB_REG_VALUE, addr);
else if (!strncmp(bank_name, "armada-3700-sb", len))
writel(PINCTRL_SB_REG_VALUE, addr);
off = fdt_node_offset_by_compatible(blob, off, compat);
}
return 0;
}
int board_init(void)
{
/* adress of boot parameters */
gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
return 0;
}
/* Board specific AHCI / SATA enable code */
int board_ahci_enable(void)
{
struct udevice *dev;
int ret;
u8 buf[8];
/* Only DB requres this configuration */
if (!of_machine_is_compatible("marvell,armada-3720-db"))
return 0;
/* Configure IO exander PCA9555: 7bit address 0x22 */
ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
if (ret) {
printf("Cannot find PCA9555: %d\n", ret);
return 0;
}
ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
if (ret) {
printf("Failed to read IO expander value via I2C\n");
return -EIO;
}
/*
* Enable SATA power via IO expander connected via I2C by setting
* the corresponding bit to output mode to enable power for SATA
*/
buf[0] &= ~(1 << I2C_IO_REG_0_SATA_OFF);
ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
if (ret) {
printf("Failed to set IO expander via I2C\n");
return -EIO;
}
return 0;
}
/* Board specific xHCI enable code */
int board_xhci_enable(void)
{
struct udevice *dev;
int ret;
u8 buf[8];
/* Only DB requres this configuration */
if (!of_machine_is_compatible("marvell,armada-3720-db"))
return 0;
/* Configure IO exander PCA9555: 7bit address 0x22 */
ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
if (ret) {
printf("Cannot find PCA9555: %d\n", ret);
return 0;
}
printf("Enable USB VBUS\n");
/*
* Read configuration (direction) and set VBUS pin as output
* (reset pin = output)
*/
ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
if (ret) {
printf("Failed to read IO expander value via I2C\n");
return -EIO;
}
buf[0] &= ~(1 << I2C_IO_REG_0_USB_H_OFF);
ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
if (ret) {
printf("Failed to set IO expander via I2C\n");
return -EIO;
}
/* Read VBUS output value and disable it */
ret = dm_i2c_read(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
if (ret) {
printf("Failed to read IO expander value via I2C\n");
return -EIO;
}
buf[0] &= ~(1 << I2C_IO_REG_0_USB_H_OFF);
ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
if (ret) {
printf("Failed to set IO expander via I2C\n");
return -EIO;
}
/*
* Required delay for configuration to settle - must wait for
* power on port is disabled in case VBUS signal was high,
* required 3 seconds delay to let VBUS signal fully settle down
*/
mdelay(3000);
/* Enable VBUS power: Set output value of VBUS pin as enabled */
buf[0] |= (1 << I2C_IO_REG_0_USB_H_OFF);
ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
if (ret) {
printf("Failed to set IO expander via I2C\n");
return -EIO;
}
mdelay(500); /* required delay to let output value settle */
return 0;
}
/* Helper function for accessing switch devices in multi-chip connection mode */
static int mii_multi_chip_mode_write(struct mii_dev *bus, int dev_smi_addr,
int smi_addr, int reg, u16 value)
{
u16 smi_cmd = 0;
if (bus->write(bus, dev_smi_addr, 0,
MVEBU_SW_SMI_DATA_REG, value) != 0) {
printf("Error writing to the PHY addr=%02x reg=%02x\n",
smi_addr, reg);
return -EFAULT;
}
smi_cmd = (1 << SW_SMI_CMD_SMI_BUSY_OFF) |
(1 << SW_SMI_CMD_SMI_MODE_OFF) |
(1 << SW_SMI_CMD_SMI_OP_OFF) |
(smi_addr << SW_SMI_CMD_DEV_ADDR_OFF) |
(reg << SW_SMI_CMD_REG_ADDR_OFF);
if (bus->write(bus, dev_smi_addr, 0,
MVEBU_SW_SMI_CMD_REG, smi_cmd) != 0) {
printf("Error writing to the PHY addr=%02x reg=%02x\n",
smi_addr, reg);
return -EFAULT;
}
return 0;
}
/* Bring-up board-specific network stuff */
int board_network_enable(struct mii_dev *bus)
{
if (!of_machine_is_compatible("marvell,armada-3720-espressobin"))
return 0;
/*
* FIXME: remove this code once Topaz driver gets available
* A3720 Community Board Only
* Configure Topaz switch (88E6341)
* Set port 0,1,2,3 to forwarding Mode (through Switch Port registers)
*/
mii_multi_chip_mode_write(bus, 1, MVEBU_PORT_CTRL_SMI_ADDR(0),
MVEBU_SW_PORT_CTRL_REG, 0x7f);
mii_multi_chip_mode_write(bus, 1, MVEBU_PORT_CTRL_SMI_ADDR(1),
MVEBU_SW_PORT_CTRL_REG, 0x7f);
mii_multi_chip_mode_write(bus, 1, MVEBU_PORT_CTRL_SMI_ADDR(2),
MVEBU_SW_PORT_CTRL_REG, 0x7f);
mii_multi_chip_mode_write(bus, 1, MVEBU_PORT_CTRL_SMI_ADDR(3),
MVEBU_SW_PORT_CTRL_REG, 0x7f);
/* RGMII Delay on Port 0 (CPU port), force link to 1000Mbps */
mii_multi_chip_mode_write(bus, 1, MVEBU_PORT_CTRL_SMI_ADDR(0),
MVEBU_SW_LINK_CTRL_REG, 0xe002);
/* Power up PHY 1, 2, 3 (through Global 2 registers) */
mii_multi_chip_mode_write(bus, 1, MVEBU_SW_G2_SMI_ADDR,
MVEBU_G2_SMI_PHY_DATA_REG, 0x1140);
mii_multi_chip_mode_write(bus, 1, MVEBU_SW_G2_SMI_ADDR,
MVEBU_G2_SMI_PHY_CMD_REG, 0x9620);
mii_multi_chip_mode_write(bus, 1, MVEBU_SW_G2_SMI_ADDR,
MVEBU_G2_SMI_PHY_CMD_REG, 0x9640);
mii_multi_chip_mode_write(bus, 1, MVEBU_SW_G2_SMI_ADDR,
MVEBU_G2_SMI_PHY_CMD_REG, 0x9660);
return 0;
}

View file

@ -1,134 +0,0 @@
/*
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <i2c.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
DECLARE_GLOBAL_DATA_PTR;
/* IO expander I2C device */
#define I2C_IO_EXP_ADDR 0x22
#define I2C_IO_CFG_REG_0 0x6
#define I2C_IO_DATA_OUT_REG_0 0x2
#define I2C_IO_REG_0_SATA_OFF 2
#define I2C_IO_REG_0_USB_H_OFF 1
int board_early_init_f(void)
{
/* Nothing to do (yet), perhaps later some pin-muxing etc */
return 0;
}
int board_init(void)
{
/* adress of boot parameters */
gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
return 0;
}
/* Board specific AHCI / SATA enable code */
int board_ahci_enable(void)
{
struct udevice *dev;
int ret;
u8 buf[8];
/* Configure IO exander PCA9555: 7bit address 0x22 */
ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
if (ret) {
printf("Cannot find PCA9555: %d\n", ret);
return 0;
}
ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
if (ret) {
printf("Failed to read IO expander value via I2C\n");
return -EIO;
}
/*
* Enable SATA power via IO expander connected via I2C by setting
* the corresponding bit to output mode to enable power for SATA
*/
buf[0] &= ~(1 << I2C_IO_REG_0_SATA_OFF);
ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
if (ret) {
printf("Failed to set IO expander via I2C\n");
return -EIO;
}
return 0;
}
/* Board specific xHCI enable code */
int board_xhci_enable(void)
{
struct udevice *dev;
int ret;
u8 buf[8];
/* Configure IO exander PCA9555: 7bit address 0x22 */
ret = i2c_get_chip_for_busnum(0, I2C_IO_EXP_ADDR, 1, &dev);
if (ret) {
printf("Cannot find PCA9555: %d\n", ret);
return 0;
}
printf("Enable USB VBUS\n");
/*
* Read configuration (direction) and set VBUS pin as output
* (reset pin = output)
*/
ret = dm_i2c_read(dev, I2C_IO_CFG_REG_0, buf, 1);
if (ret) {
printf("Failed to read IO expander value via I2C\n");
return -EIO;
}
buf[0] &= ~(1 << I2C_IO_REG_0_USB_H_OFF);
ret = dm_i2c_write(dev, I2C_IO_CFG_REG_0, buf, 1);
if (ret) {
printf("Failed to set IO expander via I2C\n");
return -EIO;
}
/* Read VBUS output value and disable it */
ret = dm_i2c_read(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
if (ret) {
printf("Failed to read IO expander value via I2C\n");
return -EIO;
}
buf[0] &= ~(1 << I2C_IO_REG_0_USB_H_OFF);
ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
if (ret) {
printf("Failed to set IO expander via I2C\n");
return -EIO;
}
/*
* Required delay for configuration to settle - must wait for
* power on port is disabled in case VBUS signal was high,
* required 3 seconds delay to let VBUS signal fully settle down
*/
mdelay(3000);
/* Enable VBUS power: Set output value of VBUS pin as enabled */
buf[0] |= (1 << I2C_IO_REG_0_USB_H_OFF);
ret = dm_i2c_write(dev, I2C_IO_DATA_OUT_REG_0, buf, 1);
if (ret) {
printf("Failed to set IO expander via I2C\n");
return -EIO;
}
mdelay(500); /* required delay to let output value settle */
return 0;
}

1
board/gdsys/a38x/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
kwbimage.cfg

36
board/gdsys/a38x/Kconfig Normal file
View file

@ -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

View file

@ -0,0 +1,7 @@
A38X BOARD
M: Dirk Eibach <eibach@gdsys.cc>
M: Mario Six <six@gdsys.de>
S: Maintained
F: board/gdsys/a38x/
F: include/configs/controlcenterdc.h
F: configs/controlcenterdc_defconfig

44
board/gdsys/a38x/Makefile Normal file
View file

@ -0,0 +1,44 @@
#
# Copyright (C) 2015 Stefan Roese <sr@denx.de>
# Copyright (C) 2015 Reinhard Pfau <reinhard.pfau@gdsys.cc>
# Copyright (C) 2016 Mario Six <mario.six@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),)
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

View file

@ -0,0 +1,279 @@
/*
* Copyright (C) 2015 Stefan Roese <sr@denx.de>
* Copyright (C) 2016 Mario Six <mario.six@gdsys.cc>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <miiphy.h>
#include <tpm.h>
#include <asm/io.h>
#include <asm/arch/cpu.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"
#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;
}

View file

@ -0,0 +1,43 @@
/*
* (C) Copyright 2016
* Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <i2c.h>
#include <fdt_support.h>
#include <asm-generic/gpio.h>
#include <dm.h>
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);
}

View file

@ -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 */

516
board/gdsys/a38x/hre.c Normal file
View file

@ -0,0 +1,516 @@
/*
* (C) Copyright 2013
* Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau@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;
}
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;
}

38
board/gdsys/a38x/hre.h Normal file
View file

@ -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 */

138
board/gdsys/a38x/hydra.c Normal file
View file

@ -0,0 +1,138 @@
#include <common.h>
#include <console.h> /* ctrlc */
#include <asm/io.h>
#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"
);

14
board/gdsys/a38x/hydra.h Normal file
View file

@ -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);

355
board/gdsys/a38x/ihs_phys.c Normal file
View file

@ -0,0 +1,355 @@
#include <common.h>
#include <dm.h>
#include <miiphy.h>
#include <asm-generic/gpio.h>
#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);

View file

@ -0,0 +1,2 @@
uint calculate_octo_phy_mask(void);
int init_octo_phys(uint octo_phy_mask);

View file

@ -0,0 +1,158 @@
/*
* (C) Copyright 2016
* Mario Six, Guntermann & Drunck GmbH, mario.six@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;
}

View file

@ -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 */

View file

@ -0,0 +1,12 @@
#
# Copyright (C) 2014 Stefan Roese <sr@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

21
board/gdsys/a38x/spl.c Normal file
View file

@ -0,0 +1,21 @@
/*
* (C) Copyright 2016
* Mario Six, Guntermann & Drunck GmbH, mario.six@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
}

View file

@ -115,6 +115,13 @@ MV_BIN_SERDES_CFG theadorable_serdes_cfg[] = {
}, },
}; };
/*
* Define a board-specific detection pulse-width array for the SerDes PCIe
* interfaces. If not defined in the board code, the default of currently 2
* is used. Values from 0...3 are possible (2 bits).
*/
u8 serdes_pex_pulse_width[4] = { 0, 2, 2, 2 };
MV_DRAM_MODES *ddr3_get_static_ddr_mode(void) MV_DRAM_MODES *ddr3_get_static_ddr_mode(void)
{ {
/* Only one mode supported for this board */ /* Only one mode supported for this board */
@ -287,3 +294,44 @@ int board_late_init(void)
return 0; return 0;
} }
#endif #endif
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_PCI)
int do_pcie_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
pci_dev_t bdf;
u16 ven_id, dev_id;
if (argc != 3)
return cmd_usage(cmdtp);
ven_id = simple_strtoul(argv[1], NULL, 16);
dev_id = simple_strtoul(argv[2], NULL, 16);
printf("Checking for PCIe device: VendorID 0x%04x, DeviceId 0x%04x\n",
ven_id, dev_id);
/*
* Check if the PCIe device is detected (somtimes its not available
* on the PCIe bus)
*/
bdf = pci_find_device(ven_id, dev_id, 0);
if (bdf == -1) {
/* PCIe device not found! */
printf("Failed to find PCIe device\n");
} else {
/* PCIe device found! */
printf("PCIe device found, resetting board...\n");
/* default handling: SOFT reset */
do_reset(NULL, 0, 0, NULL);
}
return 0;
}
U_BOOT_CMD(
pcie, 3, 0, do_pcie_test,
"Test for presence of a PCIe device",
"<VendorID> <DeviceID>"
);
#endif

View file

@ -751,6 +751,13 @@ static int setup_reloc(void)
return 0; return 0;
} }
#ifdef CONFIG_OF_BOARD_FIXUP
static int fix_fdt(void)
{
return board_fix_fdt((void *)gd->fdt_blob);
}
#endif
/* ARM calls relocate_code from its crt0.S */ /* ARM calls relocate_code from its crt0.S */
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \ #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
!CONFIG_IS_ENABLED(X86_64) !CONFIG_IS_ENABLED(X86_64)
@ -1011,6 +1018,9 @@ static const init_fnc_t init_sequence_f[] = {
display_new_sp, display_new_sp,
#ifdef CONFIG_SYS_EXTBDINFO #ifdef CONFIG_SYS_EXTBDINFO
setup_board_extra, setup_board_extra,
#endif
#ifdef CONFIG_OF_BOARD_FIXUP
fix_fdt,
#endif #endif
INIT_FUNC_WATCHDOG_RESET INIT_FUNC_WATCHDOG_RESET
reloc_fdt, reloc_fdt,

View file

@ -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

View file

@ -1,7 +1,7 @@
CONFIG_ARM=y CONFIG_ARM=y
CONFIG_ARCH_MVEBU=y CONFIG_ARCH_MVEBU=y
CONFIG_SYS_MALLOC_F_LEN=0x2000 CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_TARGET_MVEBU_DB_88F3720=y CONFIG_TARGET_MVEBU_ARMADA_37XX=y
CONFIG_DEFAULT_DEVICE_TREE="armada-3720-db" CONFIG_DEFAULT_DEVICE_TREE="armada-3720-db"
CONFIG_AHCI=y CONFIG_AHCI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
@ -33,9 +33,11 @@ CONFIG_CMD_FS_GENERIC=y
CONFIG_MAC_PARTITION=y CONFIG_MAC_PARTITION=y
CONFIG_ISO_PARTITION=y CONFIG_ISO_PARTITION=y
CONFIG_EFI_PARTITION=y CONFIG_EFI_PARTITION=y
CONFIG_CMD_MVEBU_BUBT=y
CONFIG_SHA1=y
CONFIG_SHA256=y
CONFIG_BLOCK_CACHE=y CONFIG_BLOCK_CACHE=y
CONFIG_DM_I2C=y CONFIG_DM_I2C=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_MISC=y CONFIG_MISC=y
CONFIG_DM_MMC=y CONFIG_DM_MMC=y
CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI=y

View file

@ -0,0 +1,66 @@
CONFIG_ARM=y
CONFIG_ARCH_MVEBU=y
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_TARGET_MVEBU_ARMADA_37XX=y
CONFIG_DEFAULT_DEVICE_TREE="armada-3720-espressobin"
CONFIG_AHCI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SYS_CONSOLE_INFO_QUIET=y
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
CONFIG_ARCH_EARLY_INIT_R=y
CONFIG_BOARD_EARLY_INIT_F=y
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_MMC=y
CONFIG_CMD_PART=y
CONFIG_CMD_SF=y
CONFIG_CMD_SPI=y
CONFIG_CMD_I2C=y
CONFIG_CMD_USB=y
# CONFIG_CMD_FPGA is not set
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_TFTPPUT=y
CONFIG_CMD_DHCP=y
CONFIG_CMD_MII=y
CONFIG_CMD_PING=y
CONFIG_CMD_CACHE=y
CONFIG_CMD_TIME=y
CONFIG_CMD_EXT4=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_MAC_PARTITION=y
CONFIG_ISO_PARTITION=y
CONFIG_EFI_PARTITION=y
CONFIG_CMD_MVEBU_BUBT=y
CONFIG_SHA1=y
CONFIG_SHA256=y
CONFIG_BLOCK_CACHE=y
CONFIG_DM_I2C=y
CONFIG_MISC=y
CONFIG_DM_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_SDMA=y
CONFIG_MMC_SDHCI_XENON=y
CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_MACRONIX=y
CONFIG_SPI_FLASH_SPANSION=y
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_PHYLIB=y
CONFIG_MVEBU_COMPHY_SUPPORT=y
# CONFIG_SPL_SERIAL_PRESENT is not set
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_MVEBU_A3700_UART=y
CONFIG_DEBUG_UART_BASE=0xd0012000
CONFIG_DEBUG_UART_CLOCK=25804800
CONFIG_DEBUG_UART_SHIFT=2
CONFIG_DEBUG_UART_ANNOUNCE=y
CONFIG_MVEBU_A3700_UART=y
CONFIG_MVEBU_A3700_SPI=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_STORAGE=y

View file

@ -0,0 +1,74 @@
CONFIG_ARM=y
CONFIG_ARCH_MVEBU=y
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_TARGET_MVEBU_ARMADA_8K=y
CONFIG_DEFAULT_DEVICE_TREE="armada-8040-mcbin"
CONFIG_SMBIOS_PRODUCT_NAME=""
CONFIG_AHCI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SYS_CONSOLE_INFO_QUIET=y
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
CONFIG_ARCH_EARLY_INIT_R=y
CONFIG_BOARD_EARLY_INIT_F=y
CONFIG_HUSH_PARSER=y
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_MMC=y
CONFIG_CMD_PART=y
CONFIG_CMD_SF=y
CONFIG_CMD_SPI=y
CONFIG_CMD_I2C=y
CONFIG_CMD_USB=y
# CONFIG_CMD_FPGA is not set
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_TFTPPUT=y
CONFIG_CMD_DHCP=y
CONFIG_CMD_MII=y
CONFIG_CMD_PING=y
CONFIG_CMD_CACHE=y
CONFIG_CMD_TIME=y
CONFIG_CMD_MVEBU_BUBT=y
CONFIG_CMD_EXT4=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_MAC_PARTITION=y
CONFIG_ISO_PARTITION=y
CONFIG_EFI_PARTITION=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_REGULATOR=y
CONFIG_BLOCK_CACHE=y
CONFIG_DM_I2C=y
CONFIG_SYS_I2C_MVTWSI=y
CONFIG_DM_GPIO=y
CONFIG_MVEBU_GPIO=y
CONFIG_DM_REGULATOR_FIXED=y
CONFIG_MISC=y
CONFIG_DM_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_XENON=y
CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_MACRONIX=y
CONFIG_SPI_FLASH_SPANSION=y
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_PHYLIB=y
CONFIG_PCI=y
CONFIG_DM_PCI=y
CONFIG_PCIE_DW_MVEBU=y
CONFIG_MVEBU_COMPHY_SUPPORT=y
CONFIG_PINCTRL=y
# CONFIG_SPL_SERIAL_PRESENT is not set
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_BASE=0xf0512000
CONFIG_DEBUG_UART_CLOCK=200000000
CONFIG_DEBUG_UART_SHIFT=2
CONFIG_DEBUG_UART_ANNOUNCE=y
CONFIG_SYS_NS16550=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_SMBIOS_MANUFACTURER=""

View file

@ -0,0 +1,49 @@
Armada-8K PCIe DT details:
==========================
Armada-8k uses synopsis designware PCIe controller.
Required properties:
- compatible : should be "marvell,armada8k-pcie", "snps,dw-pcie".
- reg: base addresses and lengths of the pcie control and global control registers.
"ctrl" registers points to the global control registers, while the "config" space
points to the pcie configuration registers as mentioned in dw-pcie dt bindings in the link below.
- interrupt-map-mask and interrupt-map, standard PCI properties to
define the mapping of the PCIe interface to interrupt numbers.
- All other definitions as per generic PCI bindings
See Linux kernel documentation:
"Documentation/devicetree/bindings/pci/designware-pcie.txt"
Optional properties:
PHY support is still not supported for armada-8k, once it will, the following parameters can be used:
- phys : phandle to phy node associated with pcie controller.
- phy-names : must be "pcie-phy"
- marvell,reset-gpio : specifies a gpio that needs to be activated for plug-in
card reset signal release.
Example:
cpm_pcie0: pcie@f2600000 {
compatible = "marvell,armada8k-pcie", "snps,dw-pcie";
reg = <0 0xf2600000 0 0x10000>,
<0 0xf6f00000 0 0x80000>;
reg-names = "ctrl", "config";
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
device_type = "pci";
dma-coherent;
bus-range = <0 0xff>;
ranges =
/* downstream I/O */
<0x81000000 0 0xf9000000 0 0xf9000000 0 0x10000
/* non-prefetchable memory */
0x82000000 0 0xf6000000 0 0xf6000000 0 0xf00000>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
num-lanes = <1>;
clocks = <&cpm_syscon0 1 13>;
marvell,reset-gpio = <&cpm_gpio1 20 GPIO_ACTIVE_HIGH>;
status = "disabled";
};

View file

@ -0,0 +1,28 @@
Marvell SOC USB controllers
This controller is integrated in Armada 3700/8K.
It uses the same properties as a generic XHCI host controller
Required properties :
- compatible: should be one or more of:
- "marvell,armada3700-xhci", "generic-xhci" for Armada 37xx SoCs
- "marvell,armada-8k-xhci", "generic-xhci" for Armada A8K SoCs
- reg: should contain address and length of the standard XHCI
register set for the device.
- interrupts: one XHCI interrupt should be described here.
Optional properties:
- clocks: phandle to system controller clock driving this unit
- vbus-supply : If present, specifies the fixed regulator to be turned on
for providing power to the USB VBUS rail.
Example:
cpm_usb3_0: usb3@500000 {
compatible = "marvell,armada-8k-xhci",
"generic-xhci";
reg = <0x500000 0x4000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpm_syscon0 1 22>;
vbus-supply = <&reg_usb3h0_vbus>;
status = "disabled";
};

View file

@ -0,0 +1,132 @@
Pre-relocation device tree manipulation
=======================================
Contents:
1. Purpose
2. Implementation
3. Example
4. Work to be done
1. Purpose
----------
In certain markets, it is beneficial for manufacturers of embedded devices to
offer certain ranges of products, where the functionality of the devices within
one series either don't differ greatly from another, or can be thought of as
"extensions" of each other, where one device only differs from another in the
addition of a small number of features (e.g. an additional output connector).
To realize this in hardware, one method is to have a motherboard, and several
possible daughter boards that can be attached to this mother board. Different
daughter boards then either offer the slightly different functionality, or the
addition of the daughter board to the device realizes the "extension" of
functionality to the device described previously.
For the software, we obviously want to reuse components for all these
variations of the device. This means that the software somehow needs to cope
with the situation that certain ICs may or may not be present on any given
system, depending on which daughter boards are connected to the motherboard.
In the Linux kernel, one possible solution to this problem is to employ the
device tree overlay mechanism: There exists one "base" device tree, which
features only the components guaranteed to exist in all varieties of the
device. At the start of the kernel, the presence and type of the daughter
boards is then detected, and the corresponding device tree overlays are applied
to support the components on the daughter boards.
Note that the components present on every variety of the board must, of course,
provide a way to find out if and which daughter boards are installed for this
mechanism to work.
In the U-Boot boot loader, support for device tree overlays has recently been
integrated, and is used on some boards to alter the device tree that is later
passed to Linux. But since U-Boot's driver model, which is device tree-based as
well, is being used in more and more drivers, the same problem of altering the
device tree starts cropping up in U-Boot itself as well.
An additional problem with the device tree in U-Boot is that it is read-only,
and the current mechanisms don't allow easy manipulation of the device tree
after the driver model has been initialized. While migrating to a live device
tree (at least after the relocation) would greatly simplify the solution of
this problem, it is a non-negligible task to implement it, an a interim
solution is needed to address the problem at least in the medium-term.
Hence, we propose a solution to this problem by offering a board-specific
call-back function, which is passed a writeable pointer to the device tree.
This function is called before the device tree is relocated, and specifically
before the main U-Boot's driver model is instantiated, hence the main U-Boot
"sees" all modifications to the device tree made in this function. Furthermore,
we have the pre-relocation driver model at our disposal at this stage, which
means that we can query the hardware for the existence and variety of the
components easily.
2. Implementation
-----------------
To take advantage of the pre-relocation device tree manipulation mechanism,
boards have to implement the function board_fix_fdt, which has the following
signature:
int board_fix_fdt (void *rw_fdt_blob)
The passed-in void pointer is a writeable pointer to the device tree, which can
be used to manipulate the device tree using e.g. functions from
include/fdt_support.h. The return value should either be 0 in case of
successful execution of the device tree manipulation or something else for a
failure. Note that returning a non-null value from the function will
unrecoverably halt the boot process, as with any function from init_sequence_f
(in common/board_f.c).
Furthermore, the Kconfig option OF_BOARD_FIXUP has to be set for the function
to be called:
Device Tree Control
-> [*] Board-specific manipulation of Device Tree
+----------------------------------------------------------+
| WARNING: The actual manipulation of the device tree has |
| to be the _last_ set of operations in board_fix_fdt! |
| Since the pre-relocation driver model does not adapt to |
| changes made to the device tree either, its references |
| into the device tree will be invalid after manipulating |
| it, and unpredictable behavior might occur when |
| functions that rely on them are executed! |
+----------------------------------------------------------+
Hence, the recommended layout of the board_fixup_fdt call-back function is the
following:
int board_fix_fdt(void *rw_fdt_blob)
{
/* Collect information about device's hardware and store them in e.g.
local variables */
/* Do device tree manipulation using the values previously collected */
/* Return 0 on successful manipulation and non-zero otherwise */
}
If this convention is kept, both an "additive" approach, meaning that nodes for
detected components are added to the device tree, as well as a "subtractive"
approach, meaning that nodes for absent components are removed from the tree,
as well as a combination of both approaches should work.
3. Example
----------
The controlcenterdc board (board/gdsys/a38x/controlcenterdc.c) features a
board_fix_fdt function, in which six GPIO expanders (which might be present or
not, since they are on daughter boards) on a I2C bus are queried for, and
subsequently deactivated in the device tree if they are not present.
Note that the dm_i2c_simple_probe function does not use the device tree, hence
it is safe to call it after the tree has already been manipulated.
4. Work to be done
------------------
* The application of device tree overlay should be possible in board_fixup_fdt,
but has not been tested at this stage.
2017-01-06, Mario Six <mario.six@gdsys.cc>

View file

@ -191,11 +191,16 @@ DECLARE_GLOBAL_DATA_PTR;
#define MVNETA_GMAC_AUTONEG_CONFIG 0x2c0c #define MVNETA_GMAC_AUTONEG_CONFIG 0x2c0c
#define MVNETA_GMAC_FORCE_LINK_DOWN BIT(0) #define MVNETA_GMAC_FORCE_LINK_DOWN BIT(0)
#define MVNETA_GMAC_FORCE_LINK_PASS BIT(1) #define MVNETA_GMAC_FORCE_LINK_PASS BIT(1)
#define MVNETA_GMAC_FORCE_LINK_UP (BIT(0) | BIT(1))
#define MVNETA_GMAC_IB_BYPASS_AN_EN BIT(3)
#define MVNETA_GMAC_CONFIG_MII_SPEED BIT(5) #define MVNETA_GMAC_CONFIG_MII_SPEED BIT(5)
#define MVNETA_GMAC_CONFIG_GMII_SPEED BIT(6) #define MVNETA_GMAC_CONFIG_GMII_SPEED BIT(6)
#define MVNETA_GMAC_AN_SPEED_EN BIT(7) #define MVNETA_GMAC_AN_SPEED_EN BIT(7)
#define MVNETA_GMAC_SET_FC_EN BIT(8)
#define MVNETA_GMAC_ADVERT_FC_EN BIT(9)
#define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12) #define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12)
#define MVNETA_GMAC_AN_DUPLEX_EN BIT(13) #define MVNETA_GMAC_AN_DUPLEX_EN BIT(13)
#define MVNETA_GMAC_SAMPLE_TX_CFG_EN BIT(15)
#define MVNETA_MIB_COUNTERS_BASE 0x3080 #define MVNETA_MIB_COUNTERS_BASE 0x3080
#define MVNETA_MIB_LATE_COLLISION 0x7c #define MVNETA_MIB_LATE_COLLISION 0x7c
#define MVNETA_DA_FILT_SPEC_MCAST 0x3400 #define MVNETA_DA_FILT_SPEC_MCAST 0x3400
@ -404,6 +409,15 @@ static struct buffer_location buffer_loc;
*/ */
#define BD_SPACE (1 << 20) #define BD_SPACE (1 << 20)
/*
* Dummy implementation that can be overwritten by a board
* specific function
*/
__weak int board_network_enable(struct mii_dev *bus)
{
return 0;
}
/* Utility/helper methods */ /* Utility/helper methods */
/* Write helper method */ /* Write helper method */
@ -557,6 +571,13 @@ static void mvneta_rxq_buf_size_set(struct mvneta_port *pp,
mvreg_write(pp, MVNETA_RXQ_SIZE_REG(rxq->id), val); mvreg_write(pp, MVNETA_RXQ_SIZE_REG(rxq->id), val);
} }
static int mvneta_port_is_fixed_link(struct mvneta_port *pp)
{
/* phy_addr is set to invalid value for fixed link */
return pp->phyaddr > PHY_MAX_ADDR;
}
/* Start the Ethernet port RX and TX activity */ /* Start the Ethernet port RX and TX activity */
static void mvneta_port_up(struct mvneta_port *pp) static void mvneta_port_up(struct mvneta_port *pp)
{ {
@ -807,10 +828,12 @@ static void mvneta_defaults_set(struct mvneta_port *pp)
/* Assign port SDMA configuration */ /* Assign port SDMA configuration */
mvreg_write(pp, MVNETA_SDMA_CONFIG, val); mvreg_write(pp, MVNETA_SDMA_CONFIG, val);
/* Enable PHY polling in hardware for U-Boot */ /* Enable PHY polling in hardware if not in fixed-link mode */
val = mvreg_read(pp, MVNETA_UNIT_CONTROL); if (!mvneta_port_is_fixed_link(pp)) {
val |= MVNETA_PHY_POLLING_ENABLE; val = mvreg_read(pp, MVNETA_UNIT_CONTROL);
mvreg_write(pp, MVNETA_UNIT_CONTROL, val); val |= MVNETA_PHY_POLLING_ENABLE;
mvreg_write(pp, MVNETA_UNIT_CONTROL, val);
}
mvneta_set_ucast_table(pp, -1); mvneta_set_ucast_table(pp, -1);
mvneta_set_special_mcast_table(pp, -1); mvneta_set_special_mcast_table(pp, -1);
@ -1128,6 +1151,11 @@ static void mvneta_adjust_link(struct udevice *dev)
struct phy_device *phydev = pp->phydev; struct phy_device *phydev = pp->phydev;
int status_change = 0; int status_change = 0;
if (mvneta_port_is_fixed_link(pp)) {
debug("Using fixed link, skip link adjust\n");
return;
}
if (phydev->link) { if (phydev->link) {
if ((pp->speed != phydev->speed) || if ((pp->speed != phydev->speed) ||
(pp->duplex != phydev->duplex)) { (pp->duplex != phydev->duplex)) {
@ -1498,28 +1526,54 @@ static int mvneta_start(struct udevice *dev)
mvneta_port_power_up(pp, pp->phy_interface); mvneta_port_power_up(pp, pp->phy_interface);
if (!pp->init || pp->link == 0) { if (!pp->init || pp->link == 0) {
/* Set phy address of the port */ if (mvneta_port_is_fixed_link(pp)) {
mvreg_write(pp, MVNETA_PHY_ADDR, pp->phyaddr); u32 val;
phydev = phy_connect(pp->bus, pp->phyaddr, dev,
pp->phy_interface);
pp->phydev = phydev; pp->init = 1;
phy_config(phydev); pp->link = 1;
phy_startup(phydev); mvneta_init(dev);
if (!phydev->link) {
printf("%s: No link.\n", phydev->dev->name); val = MVNETA_GMAC_FORCE_LINK_UP |
return -1; MVNETA_GMAC_IB_BYPASS_AN_EN |
MVNETA_GMAC_SET_FC_EN |
MVNETA_GMAC_ADVERT_FC_EN |
MVNETA_GMAC_SAMPLE_TX_CFG_EN;
if (pp->duplex)
val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX;
if (pp->speed == SPEED_1000)
val |= MVNETA_GMAC_CONFIG_GMII_SPEED;
else if (pp->speed == SPEED_100)
val |= MVNETA_GMAC_CONFIG_MII_SPEED;
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
} else {
/* Set phy address of the port */
mvreg_write(pp, MVNETA_PHY_ADDR, pp->phyaddr);
phydev = phy_connect(pp->bus, pp->phyaddr, dev,
pp->phy_interface);
pp->phydev = phydev;
phy_config(phydev);
phy_startup(phydev);
if (!phydev->link) {
printf("%s: No link.\n", phydev->dev->name);
return -1;
}
/* Full init on first call */
mvneta_init(dev);
pp->init = 1;
return 0;
} }
/* Full init on first call */
mvneta_init(dev);
pp->init = 1;
} else {
/* Upon all following calls, this is enough */
mvneta_port_up(pp);
mvneta_port_enable(pp);
} }
/* Upon all following calls, this is enough */
mvneta_port_up(pp);
mvneta_port_enable(pp);
return 0; return 0;
} }
@ -1615,6 +1669,8 @@ static int mvneta_probe(struct udevice *dev)
struct mii_dev *bus; struct mii_dev *bus;
unsigned long addr; unsigned long addr;
void *bd_space; void *bd_space;
int ret;
int fl_node;
/* /*
* Allocate buffer area for descs and rx_buffers. This is only * Allocate buffer area for descs and rx_buffers. This is only
@ -1647,10 +1703,19 @@ static int mvneta_probe(struct udevice *dev)
/* PHY interface is already decoded in mvneta_ofdata_to_platdata() */ /* PHY interface is already decoded in mvneta_ofdata_to_platdata() */
pp->phy_interface = pdata->phy_interface; pp->phy_interface = pdata->phy_interface;
/* Now read phyaddr from DT */ /* fetch 'fixed-link' property from 'neta' node */
addr = fdtdec_get_int(blob, node, "phy", 0); fl_node = fdt_subnode_offset(blob, node, "fixed-link");
addr = fdt_node_offset_by_phandle(blob, addr); if (fl_node != -FDT_ERR_NOTFOUND) {
pp->phyaddr = fdtdec_get_int(blob, addr, "reg", 0); /* set phy_addr to invalid value for fixed link */
pp->phyaddr = PHY_MAX_ADDR + 1;
pp->duplex = fdtdec_get_bool(blob, fl_node, "full-duplex");
pp->speed = fdtdec_get_int(blob, fl_node, "speed", 0);
} else {
/* Now read phyaddr from DT */
addr = fdtdec_get_int(blob, node, "phy", 0);
addr = fdt_node_offset_by_phandle(blob, addr);
pp->phyaddr = fdtdec_get_int(blob, addr, "reg", 0);
}
bus = mdio_alloc(); bus = mdio_alloc();
if (!bus) { if (!bus) {
@ -1664,7 +1729,11 @@ static int mvneta_probe(struct udevice *dev)
bus->priv = (void *)pp; bus->priv = (void *)pp;
pp->bus = bus; pp->bus = bus;
return mdio_register(bus); ret = mdio_register(bus);
if (ret)
return ret;
return board_network_enable(bus);
} }
static void mvneta_stop(struct udevice *dev) static void mvneta_stop(struct udevice *dev)

View file

@ -15,6 +15,7 @@
#include <dm.h> #include <dm.h>
#include <pci.h> #include <pci.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm-generic/gpio.h>
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
@ -461,6 +462,25 @@ static int pcie_dw_mvebu_probe(struct udevice *dev)
struct pcie_dw_mvebu *pcie = dev_get_priv(dev); struct pcie_dw_mvebu *pcie = dev_get_priv(dev);
struct udevice *ctlr = pci_get_controller(dev); struct udevice *ctlr = pci_get_controller(dev);
struct pci_controller *hose = dev_get_uclass_priv(ctlr); struct pci_controller *hose = dev_get_uclass_priv(ctlr);
#ifdef CONFIG_DM_GPIO
struct gpio_desc reset_gpio;
gpio_request_by_name(dev, "marvell,reset-gpio", 0, &reset_gpio,
GPIOD_IS_OUT);
/*
* Issue reset to add-in card trough the dedicated GPIO.
* Some boards are connecting the card reset pin to common system
* reset wire and others are using separate GPIO port.
* In the last case we have to release a reset of the addon card
* using this GPIO.
*/
if (dm_gpio_is_valid(&reset_gpio)) {
dm_gpio_set_value(&reset_gpio, 1);
mdelay(200);
}
#else
debug("PCIE Reset on GPIO support is missing\n");
#endif /* CONFIG_DM_GPIO */
pcie->first_busno = dev->seq; pcie->first_busno = dev->seq;

View file

@ -25,6 +25,7 @@ config USB_XHCI_MVEBU
bool "MVEBU USB 3.0 support" bool "MVEBU USB 3.0 support"
default y default y
depends on ARCH_MVEBU depends on ARCH_MVEBU
select DM_REGULATOR
help help
Choose this option to add support for USB 3.0 driver on mvebu Choose this option to add support for USB 3.0 driver on mvebu
SoCs, which includes Armada8K, Armada3700 and other Armada SoCs, which includes Armada8K, Armada3700 and other Armada

View file

@ -10,6 +10,7 @@
#include <dm.h> #include <dm.h>
#include <fdtdec.h> #include <fdtdec.h>
#include <usb.h> #include <usb.h>
#include <power/regulator.h>
#include <asm/gpio.h> #include <asm/gpio.h>
#include "xhci.h" #include "xhci.h"
@ -44,12 +45,22 @@ static int xhci_usb_probe(struct udevice *dev)
struct mvebu_xhci_platdata *plat = dev_get_platdata(dev); struct mvebu_xhci_platdata *plat = dev_get_platdata(dev);
struct mvebu_xhci *ctx = dev_get_priv(dev); struct mvebu_xhci *ctx = dev_get_priv(dev);
struct xhci_hcor *hcor; struct xhci_hcor *hcor;
int len; int len, ret;
struct udevice *regulator;
ctx->hcd = (struct xhci_hccr *)plat->hcd_base; ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase)); len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase));
hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len); hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len);
ret = device_get_supply_regulator(dev, "vbus-supply", &regulator);
if (!ret) {
ret = regulator_set_enable(regulator, true);
if (ret) {
printf("Failed to turn ON the VBUS regulator\n");
return ret;
}
}
/* Enable USB xHCI (VBUS, reset etc) in board specific code */ /* Enable USB xHCI (VBUS, reset etc) in board specific code */
board_xhci_enable(); board_xhci_enable();

View file

@ -14,6 +14,16 @@ config OF_CONTROL
This feature provides for run-time configuration of U-Boot This feature provides for run-time configuration of U-Boot
via a flattened device tree. via a flattened device tree.
config OF_BOARD_FIXUP
bool "Board-specific manipulation of Device Tree"
help
In certain circumstances it is necessary to be able to modify
U-Boot's device tree (e.g. to delete device from it). This option
make the Device Tree writeable and provides a board-specific
"board_fix_fdt" callback (called during pre-relocation time), which
enables the board initialization to modifiy the Device Tree. The
modified copy is subsequently used by U-Boot after relocation.
config SPL_OF_CONTROL config SPL_OF_CONTROL
bool "Enable run-time configuration via Device Tree in SPL" bool "Enable run-time configuration via Device Tree in SPL"
depends on SPL && OF_CONTROL depends on SPL && OF_CONTROL

View file

@ -497,6 +497,7 @@ extern ssize_t spi_write (uchar *, int, uchar *, int);
/* $(BOARD)/$(BOARD).c */ /* $(BOARD)/$(BOARD).c */
int board_early_init_f (void); int board_early_init_f (void);
int board_fix_fdt (void *rw_fdt_blob); /* manipulate the U-Boot fdt before its relocation */
int board_late_init (void); int board_late_init (void);
int board_postclk_init (void); /* after clocks/timebase, before env/serial */ int board_postclk_init (void); /* after clocks/timebase, before env/serial */
int board_early_init_r (void); int board_early_init_r (void);

View file

@ -0,0 +1,228 @@
/*
* Copyright (C) 2014 Stefan Roese <sr@denx.de>
* Copyright (C) 2016 Mario Six <mario.six@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
/*
* 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 */

View file

@ -4,8 +4,8 @@
* SPDX-License-Identifier: GPL-2.0+ * SPDX-License-Identifier: GPL-2.0+
*/ */
#ifndef _CONFIG_MVEBU_DB_88F3720_H #ifndef _CONFIG_MVEBU_ARMADA_37XX_H
#define _CONFIG_MVEBU_DB_88F3720_H #define _CONFIG_MVEBU_ARMADA_37XX_H
/* /*
* High Level Configuration Options (easy to change) * High Level Configuration Options (easy to change)
@ -92,6 +92,7 @@
#define CONFIG_PHY_GIGE /* GbE speed/duplex detect */ #define CONFIG_PHY_GIGE /* GbE speed/duplex detect */
#define CONFIG_ARP_TIMEOUT 200 #define CONFIG_ARP_TIMEOUT 200
#define CONFIG_NET_RETRY_COUNT 50 #define CONFIG_NET_RETRY_COUNT 50
#define CONFIG_PHY_MARVELL
/* USB 2.0 */ /* USB 2.0 */
#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3 #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3
@ -126,4 +127,4 @@
#define CONFIG_SUPPORT_VFAT #define CONFIG_SUPPORT_VFAT
#endif /* _CONFIG_MVEBU_DB_88F3720_H */ #endif /* _CONFIG_MVEBU_ARMADA_37XX_H */