diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 46e0d096f5..89b7f63632 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -86,6 +86,7 @@ dtb-$(CONFIG_ARCH_MVEBU) += \ armada-385-hw14.dtb \ armada-385-hw18.dtb \ armada-385-hw17.dtb \ + armada-385-hw29.dtb \ armada-3720-db.dtb \ armada-3720-espressobin.dtb \ armada-375-db.dtb \ diff --git a/arch/arm/dts/armada-385-hw29-common.dtsi b/arch/arm/dts/armada-385-hw29-common.dtsi new file mode 100644 index 0000000000..745f82ddd1 --- /dev/null +++ b/arch/arm/dts/armada-385-hw29-common.dtsi @@ -0,0 +1,244 @@ +/* + * Device Tree file for the NetModule NBHW17 (NB2800) + * + * Copyright (C) 2016 NetModule + * + * Stefan Eichenberger + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include "armada-385.dtsi" +#include + +/ { + model = "NetModule Router HW29 with Armada A385"; + compatible = "marvell,aramda385-nbhw29", "marvell,armada385", "marvell,armada380"; + + aliases { + /* So that mvebu u-boot can update the MAC addresses */ + ethernet0 = ð0; + ethernet1 = ð1; + ethernet2 = ð2; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x40000000>; /* 1 GB */ + }; + + soc { + ranges = ; /* FPGA */ + + gpiofpga: gpio@fd0000000 { + compatible = "nm,nbhw-fpga"; + reg = ; /* This translates to 0xfd000000 */ + ngpios = <8500>; + gpio-controller; + gpio-bank-name = "FPGA"; + #gpio-cells = <2>; + spi-ss = <&gpio1 5 0>; /* SS */ + spi-sdo = <&gpio1 6 0>; /* SDO slave data out */ + spi-sck = <&gpio1 7 0>; /* SCK */ + spi-sdi = <&gpio1 8 0>; /* SDI slave data in */ + fpga-reset = <&gpio0 19 0>; /* FPGA reset */ + fpga-reset-logic = <&gpio1 12 0>; /* FPGA reset logic (after load)*/ + }; + + fpga_conf: fpgaconf@0 { + compatible = "nm,nbhw29-fpga-config"; + leds = <&gpiofpga 256 0>, <&gpiofpga 257 0>, <&gpiofpga 258 0>, + <&gpiofpga 259 0>, <&gpiofpga 260 0>, <&gpiofpga 261 0>, + <&gpiofpga 262 0>, <&gpiofpga 263 0>, <&gpiofpga 264 0>, + <&gpiofpga 265 0>, <&gpiofpga 266 0>, <&gpiofpga 267 0>, + <&gpiofpga 268 0>, <&gpiofpga 269 0>, <&gpiofpga 270 0>, + <&gpiofpga 271 0>; + + misc@0 { + #gpio-cells = <4>; + // gpio controller, gpio number, low/high_active, default value + sd-card-enable = <&gpiofpga 65 GPIO_ACTIVE_HIGH 1>; + rs232-enable = <&gpiofpga 288 GPIO_ACTIVE_HIGH 1>; + }; + + // pcie slot 0 + pcieslot@0 { + reset = <&gpiofpga 384 GPIO_ACTIVE_HIGH 1>; + power = <&gpiofpga 400 GPIO_ACTIVE_HIGH 0>; + power-3v8 = <&gpiofpga 464 GPIO_ACTIVE_HIGH 0>; + wdis-out = <&gpiofpga 2053 GPIO_ACTIVE_HIGH 1>; + wdis = <&gpiofpga 2069 GPIO_ACTIVE_LOW 1>; + clk = <&gpiofpga 416 GPIO_ACTIVE_HIGH 1>; + reset-1v8 = <&gpiofpga 2496 GPIO_ACTIVE_HIGH 0>; + reset-3v3 = <&gpiofpga 2497 GPIO_ACTIVE_HIGH 0>; + wdis-1v8 = <&gpiofpga 2498 GPIO_ACTIVE_HIGH 0>; + wdis-3v3 = <&gpiofpga 2499 GPIO_ACTIVE_HIGH 0>; + }; + + // pcie slot 1 + pcieslot@1 { + reset = <&gpiofpga 385 GPIO_ACTIVE_HIGH 1>; + power = <&gpiofpga 401 GPIO_ACTIVE_HIGH 0>; + power-3v8 = <&gpiofpga 465 GPIO_ACTIVE_HIGH 0>; + wdis-out = <&gpiofpga 4101 GPIO_ACTIVE_HIGH 1>; + wdis = <&gpiofpga 4117 GPIO_ACTIVE_LOW 1>; + clk = <&gpiofpga 417 GPIO_ACTIVE_HIGH 1>; + reset-1v8 = <&gpiofpga 4544 GPIO_ACTIVE_HIGH 0>; + reset-3v3 = <&gpiofpga 4545 GPIO_ACTIVE_HIGH 0>; + wdis-1v8 = <&gpiofpga 4546 GPIO_ACTIVE_HIGH 0>; + wdis-3v3 = <&gpiofpga 4547 GPIO_ACTIVE_HIGH 0>; + }; + + // extension slot (ethernet switch) + pcieslot@2 { + reset = <&gpiofpga 386 GPIO_ACTIVE_HIGH 1>; + power = <&gpiofpga 402 GPIO_ACTIVE_HIGH 0>; + power-3v8 = <&gpiofpga 466 GPIO_ACTIVE_HIGH 0>; + wdis-out = <&gpiofpga 6149 GPIO_ACTIVE_HIGH 1>; + wdis = <&gpiofpga 6165 GPIO_ACTIVE_LOW 1>; + clk = <&gpiofpga 418 GPIO_ACTIVE_HIGH 0>; + reset-1v8 = <&gpiofpga 6592 GPIO_ACTIVE_HIGH 0>; + reset-3v3 = <&gpiofpga 6593 GPIO_ACTIVE_HIGH 0>; + wdis-1v8 = <&gpiofpga 6594 GPIO_ACTIVE_HIGH 0>; + wdis-3v3 = <&gpiofpga 6595 GPIO_ACTIVE_HIGH 0>; + }; + + // low end extension 0 (mapped in fpga as a pcie slot) + pcieslot@3 { + reset = <&gpiofpga 387 GPIO_ACTIVE_HIGH 1>; + power = <&gpiofpga 403 GPIO_ACTIVE_HIGH 0>; + power-3v8 = <&gpiofpga 467 GPIO_ACTIVE_HIGH 0>; + wdis-out = <&gpiofpga 8197 GPIO_ACTIVE_HIGH 1>; + wdis = <&gpiofpga 8213 GPIO_ACTIVE_LOW 1>; + reset-1v8 = <&gpiofpga 8640 GPIO_ACTIVE_HIGH 0>; + reset-3v3 = <&gpiofpga 8641 GPIO_ACTIVE_HIGH 0>; + wdis-1v8 = <&gpiofpga 8642 GPIO_ACTIVE_HIGH 0>; + wdis-3v3 = <&gpiofpga 8643 GPIO_ACTIVE_HIGH 0>; + }; + + // low end extension 1 (mapped in fpga as a pcie slot) + pcieslot@4 { + reset = <&gpiofpga 388 GPIO_ACTIVE_HIGH 1>; + power = <&gpiofpga 404 GPIO_ACTIVE_HIGH 0>; + power-3v8 = <&gpiofpga 468 GPIO_ACTIVE_HIGH 0>; + wdis-out = <&gpiofpga 10245 GPIO_ACTIVE_HIGH 1>; + wdis = <&gpiofpga 10261 GPIO_ACTIVE_LOW 1>; + reset-1v8 = <&gpiofpga 10688 GPIO_ACTIVE_HIGH 0>; + reset-3v3 = <&gpiofpga 10689 GPIO_ACTIVE_HIGH 0>; + wdis-1v8 = <&gpiofpga 10690 GPIO_ACTIVE_HIGH 0>; + wdis-3v3 = <&gpiofpga 10691 GPIO_ACTIVE_HIGH 0>; + }; + + // sfp (mapped in fpga also as a pcie slot) + sfp@0 { + power = <&gpiofpga 405 GPIO_ACTIVE_HIGH 1>; + reset = <&gpiofpga 389 GPIO_ACTIVE_HIGH 0>; + }; + }; + + internal-regs { + + i2c0: i2c@11000 { + status = "okay"; + clock-frequency = <100000>; + }; + + i2c1: i2c@11100 { + status = "disabled"; + }; + + sata@a8000 { + status = "disabled"; + }; + + // Never ever enable this SATA controller on A385/A380 ! + sata@e0000 { + status = "disabled"; + }; + + sdhci@d8000 { + broken-cd; + wp-inverted; + no-1-8-v; + bus-width = <8>; + status = "okay"; + }; + + serial@12000 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; + }; + + serial@12100 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + status = "okay"; + }; + + usb@58000 { + status = "okay"; + }; + }; + + pcie-controller { + status = "okay"; + /* + * The two PCIe units are accessible through + * standard PCIe slots on the board. + */ + pcie@3,0 { + /* Port 2, Lane 0 */ + status = "okay"; + }; + pcie@4,0 { + /* Port 3, Lane 0 */ + status = "okay"; + }; + }; + }; + +}; + +ð0 { + status = "disabled"; + phy-mode = "sgmii"; + phy = <&phy1>; +}; + +ð1 { + status = "disabled"; + phy-mode = "sgmii"; +}; + +ð2 { + status = "disabled"; + phy-mode = "sgmii"; + phy = <&phy0>; +}; + +&mdio { + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&mdio_pins>; + + phy0: ethernet-phy@0 { + marvell,reg-init = <3 16 0 0x101e>; + reg = <0>; + }; + + phy1: ethernet-phy@1 { + marvell,reg-init = <3 16 0 0x101e>; + reg = <1>; + }; +}; + + diff --git a/arch/arm/dts/armada-385-hw29-spl.dts b/arch/arm/dts/armada-385-hw29-spl.dts new file mode 100644 index 0000000000..4db399df01 --- /dev/null +++ b/arch/arm/dts/armada-385-hw29-spl.dts @@ -0,0 +1,48 @@ +/* + * Device Tree file for the NetModule NBHW18 (NB1800) base variant + * + * Copyright (C) 2016 NetModule + * + * Stefan Eichenberger + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/dts-v1/; +#include "armada-385-hw29-common.dtsi" + +/ { + model = "NetModule Router HW29 with Armada A385 (NG1850)"; + chosen { + stdout-path = "serial0:115200n8"; + }; + + + soc { + internal-regs { + serial@12000 { + u-boot,dm-spl; + }; + }; + }; +}; + +ð0 { + status = "okay"; +}; + +// SFP-Port +ð1 { + status = "disabled"; + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +ð2 { + status = "okay"; +}; + diff --git a/arch/arm/dts/armada-385-hw29.dts b/arch/arm/dts/armada-385-hw29.dts new file mode 100644 index 0000000000..76a4f420b2 --- /dev/null +++ b/arch/arm/dts/armada-385-hw29.dts @@ -0,0 +1,54 @@ +/* + * Device Tree file for the NetModule HW29 (NG1850) base variant + * + * Copyright (C) 2016 NetModule + * + * Stefan Eichenberger + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/dts-v1/; +#include "armada-385-hw29-common.dtsi" + +/ { + model = "NetModule Router HW29 with Armada A385 (NG1850)"; + + soc { + gpiofpga: gpio@fd0000000 { + fpga-cinit = <&gpio0 13 0>; /* FPGA cinit */ + fpga-cdone = <&gpio0 21 0>; /* FPGA cdone */ + }; + }; +}; + +// LAN1 or SWITCH +// In U-Boot we only support the configuration with two separate eth phys +// without eth switch. This ensures that U-Boot initializes both eth phys +// properly by calling drivers/net/phy/marvel.c:m88e1518_config(..) which +// executes some quirks to work around some MV88E1512 phy erratas. Because +// the linux kernel does not apply those quirks, the phys would otherwise +// not work later in Linux, if they were not initialized by U-Boot. +// (To use the ethernet switch in U-Boot, eth0/LAN1 would have to be +// configured as fixed link like eth1. Then the switch would work in U-Boot, +// but the phy for eth0/LAN1 would not be initialized.) +ð0 { + status = "okay"; +}; + +// SFP-Port +ð1 { + status = "disabled"; + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +// LAN0 +ð2 { + status = "okay"; +}; + diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index ada14c7bae..ee38629552 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -100,6 +100,10 @@ config TARGET_NM_HW17 bool "Support HW17" select 88F6820 +config TARGET_NM_HW29 + bool "Support HW29" + select 88F6820 + config TARGET_TURRIS_OMNIA bool "Support Turris Omnia" select 88F6820 @@ -157,6 +161,7 @@ config SYS_BOARD default "hw14" if TARGET_NM_HW14 default "hw18" if TARGET_NM_HW18 default "hw17" if TARGET_NM_HW17 + default "hw29" if TARGET_NM_HW29 config SYS_CONFIG_NAME default "clearfog" if TARGET_CLEARFOG @@ -173,6 +178,7 @@ config SYS_CONFIG_NAME default "armada-385-hw14" if TARGET_NM_HW14 default "armada-385-hw18" if TARGET_NM_HW18 default "armada-385-hw17" if TARGET_NM_HW17 + default "armada-385-hw29" if TARGET_NM_HW29 config SYS_VENDOR default "Marvell" if TARGET_DB_MV784MP_GP @@ -187,6 +193,7 @@ config SYS_VENDOR default "nm" if TARGET_NM_HW14 default "nm" if TARGET_NM_HW18 default "nm" if TARGET_NM_HW17 + default "nm" if TARGET_NM_HW29 config SYS_SOC default "mvebu" diff --git a/board/nm/common/da9063.h b/board/nm/common/da9063.h index decd99e07a..65c01541ff 100644 --- a/board/nm/common/da9063.h +++ b/board/nm/common/da9063.h @@ -20,6 +20,8 @@ #define PMIC_REG_GPIO_MODE0_7 0x1D /* Control register for GPIOs 0..7 */ #define PMIC_REG_GPIO_MODE8_15 0x1E /* Control register for GPIOs 8..15 */ +#define PMIC_REG_LDO6_CONT 0x2B + #define PMIC_REG_BBAT_CONT 0xC5 /* Control register for backup battery */ #define PMIC_REG_BUCK_ILIM_A 0x9A diff --git a/board/nm/hw29/MAINTAINERS b/board/nm/hw29/MAINTAINERS new file mode 100644 index 0000000000..f5649400ec --- /dev/null +++ b/board/nm/hw29/MAINTAINERS @@ -0,0 +1,6 @@ +DB_88F6820_GP BOARD +M: Stefan Roese +S: Maintained +F: board/Marvell/db-88f6820-gp/ +F: include/configs/db-88f6820-gp.h +F: configs/db-88f6820-gp_defconfig diff --git a/board/nm/hw29/Makefile b/board/nm/hw29/Makefile new file mode 100644 index 0000000000..6a924b173c --- /dev/null +++ b/board/nm/hw29/Makefile @@ -0,0 +1,35 @@ +# +# Copyright (C) 2015 Stefan Roese +# +# SPDX-License-Identifier: GPL-2.0+ +# + +commonobj = ../common/bdparser.o \ + ../common/nbhw_bd.o \ + ../common/nbhw_env.o \ + ../common/nbhw_init.o \ + ../common/nbhw_fileaccess.o \ + ../common/nbhw_fpga_gpio.o \ + ../common/nbhw_partitions.o \ + ../common/nbhw_pcie_fixup.o + +ccflags-y := -I../common + +ifndef CONFIG_SPL_BUILD +obj-y := board.o nbhw_gpio.o nbhw_fpga_config.o \ + ../common/nbhw_sim.o nbhw_sim.o \ + ../common/da9063.o \ + ../common/lattice/core.o \ + ../common/lattice/hardware.o \ + ../common/lattice/intrface.o \ + ../common/lattice/SSPIEm.o \ + ../common/lattice/util.o $(commonobj) +else +obj-y := board.o nbhw_gpio.o \ + ../common/da9063.o \ + ../common/nbhw_bd.o \ + ../common/nbhw_partitions.o \ + ../common/bdparser.o \ + ../common/nbhw_bd.o +endif + diff --git a/board/nm/hw29/README b/board/nm/hw29/README new file mode 100644 index 0000000000..9bea5b35cb --- /dev/null +++ b/board/nm/hw29/README @@ -0,0 +1,18 @@ +Update from original Marvell U-Boot to mainline U-Boot: +------------------------------------------------------- + +The resulting image including the SPL binary with the +full DDR setup is "u-boot-spl.kwb". + +To update the SPI NOR flash, please use the following +command: + +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ +sf update 2000000 0 60000 + +Note that the original Marvell U-Boot seems to have +problems with the "sf update" command. This does not +work reliable. So here this command should be used: + +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ +sf erase 0 60000;sf write 2000000 0 60000 diff --git a/board/nm/hw29/board.c b/board/nm/hw29/board.c new file mode 100644 index 0000000000..ce22b7c994 --- /dev/null +++ b/board/nm/hw29/board.c @@ -0,0 +1,822 @@ +/* + * Copyright (C) 2015 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* ctrlc */ + +#include + +#include "nbhw_gpio.h" + +#include "../common/nbhw_init.h" +#include "../common/nbhw_env.h" +#include "../common/nbhw_bd.h" +#include "../common/da9063.h" + +#include "../drivers/ddr/marvell/a38x/ddr3_init.h" +#include <../serdes/a38x/high_speed_env_spec.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Those values and defines are taken from the Marvell U-Boot version + * "u-boot-2013.01-2014_T3.0" + */ +#define GPP_OUT_ENA_LOW (~(BIT(6) | BIT(19) | BIT(29))) /* 1=Input, default input */ + +#define GPP_OUT_ENA_MID (~(BIT(12) | BIT(15))) + +#define GPP_OUT_VAL_LOW (BIT(29)) +#define GPP_OUT_VAL_MID (BIT(15)) +#define GPP_POL_LOW 0x0 +#define GPP_POL_MID 0x0 + +#define BD_EEPROM_ADDR (0x50) /* CPU BD EEPROM (8kByte) is at 50 (A0) */ +#define BD_ADDRESS (0x0000) /* Board descriptor at beginning of EEPROM */ +#define PD_ADDRESS (0x0200) /* Product descriptor */ +#define PARTITION_ADDRESS (0x0600) /* Partition Table */ +#define SERDES_CONFIG_ADDRESS (0x0800) /* SERDES config address */ + +#define DEV_CS0_BASE 0xfd000000 + +/* Default serdes configuration */ +static struct serdes_map board_serdes_map[] = { + { SGMII0, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0 }, /* ETH port 2 (same as HW18) */ + { PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0 }, /* NVMe slot (was extension connetor on HW18) */ + { PEX1, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0 }, /* PCIe for M.2 slot (was SFP on HW18) */ + { PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0 }, /* Serdes for mPCIe slot (can be PEX3 or USB3_HOST1) (was first mPCIe slot on HW18) */ + { USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0 }, /* USB3 for M.2 slot (was Serdes for second mPCIe slot on HW18) */ + { SGMII2, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0 } /* ETH port 1 (same as HW18) */ +}; + +enum serdes_type get_serdes_type(int index) +{ + if ((index>=0) && (index =sizeof(eeprom_serdes_config.serdes_cfg))) return 0xff; + return eeprom_serdes_config.serdes_cfg[serdes_index]; +} + + +static inline int __maybe_unused read_eeprom(void) +{ + int res = _bd_init(); + + read_eeprom_serdes_config(); + + return res; +} + +/* TODO: Create DA9063 Accessor Module */ +#define CONFIG_PMIC_I2C_BUS 0 +#define CONFIG_PMIC_I2C_ADDR 0x58 /* Pages 0 and 1, Pages 2 and 3 -> 0x59 */ + +#define RESET_REASON_SHM_LOCATION (0x3ffff000) + +extern int console_init_f(void); + +static int init_console(void) +{ + int ret; + struct udevice *dev; + char *consoledev; + char buf[16] = "serial@12100"; + + debug("init console\n"); + + /* Make sure all devices are probed, it seems + * that this stuff is buggy in U-Boot */ + ret = uclass_first_device(UCLASS_SERIAL, &dev); + if (ret) { + printf("Could not find any serial device\n"); + return ret; + } + + while (list_is_last(&dev->uclass_node, &dev->uclass->dev_head) == 0) { + uclass_next_device(&dev); + } + + set_console(); + + /* Don't use external console, if we have no FPGA, + as it cannot work then. -> Switch to internal console then. */ +// if (readw(0xfd000000)!=0x012f) { /* Check for correct FPGA signature */ + printf("FPGA not ready. Forcing console to ttyS0\n"); + env_set("defaultconsole", "ttyS0"); + env_set("consoledev", "ttyS0"); +// } + + consoledev = env_get("consoledev"); + if (strncmp(consoledev, "ttyS0", 5) == 0) { + strncpy(buf, "serial@12000", sizeof(buf)); + } + + env_set("stdin", buf); + env_set("stdout", buf); + env_set("stderr", buf); + + return 0; +} + +int hws_board_topology_load(struct serdes_map **serdes_map_array, u8 *count) +{ + int i, j; + int bd_config_is_broken = 0; + + if (read_eeprom() < 0){ + /* If we do not have a board descriptor use the default + serdes configuration defined in board_serdes_map */ + puts("Could not read board descriptor using default serdes config.\n"); + } else { + /* Check for broken serdes config in BD -> If multiple serdes lines are + configured for the same function something is obviously broken. */ + for (i = 0; i Ignoring BD serdes config\n"); + } + + for (i = 0; i < ARRAY_SIZE(board_serdes_map); i++) { + enum serdes_type type; + uint8_t user_config = get_eeprom_serdes_config(i); + + if (user_config != 0xff) { + /* if we have a user config we use that one */ + type = (enum serdes_type)user_config; + } else { + /* otherwise we use the config from the bd if it is not broken */ + if (bd_config_is_broken) { + type = LAST_SERDES_TYPE; + } else { + type = bd_get_serdes_type(i); + } + } + + /* LAST_SERDES_TYPE means use compiled in default */ + if (type < LAST_SERDES_TYPE) { + if ((type >= SGMII0) && (type <= SGMII2)) { + board_serdes_map[i].serdes_speed = SERDES_SPEED_1_25_GBPS; + board_serdes_map[i].serdes_mode = SERDES_DEFAULT_MODE; + } + else if ((type >= PEX0) && (type <= PEX3)) { + board_serdes_map[i].serdes_speed = SERDES_SPEED_5_GBPS; + board_serdes_map[i].serdes_mode = PEX_ROOT_COMPLEX_X1; + } + else if ((type >= USB3_HOST0) && (type <= USB3_HOST1)) { + board_serdes_map[i].serdes_speed = SERDES_SPEED_5_GBPS; + board_serdes_map[i].serdes_mode = PEX_ROOT_COMPLEX_X1; + } + else if ((type >= SATA0) && (type <= SATA3)) { + board_serdes_map[i].serdes_speed = SERDES_SPEED_3_GBPS; + board_serdes_map[i].serdes_mode = SERDES_DEFAULT_MODE; + } + else if ((type == DEFAULT_SERDES)) { + board_serdes_map[i].serdes_speed = SERDES_SPEED_1_25_GBPS; + board_serdes_map[i].serdes_mode = SERDES_DEFAULT_MODE; + } else { + printf("SERDES Type %d not supported\n", type); + /* Keep default serdes configuration */ + type = board_serdes_map[i].serdes_type; + } + + if (i==3) { + /* On V2 TX line for PCIe slot1 is inverted*/ + board_serdes_map[i].swap_tx = 1; + } + + debug("Configure SERDES %d to %d\n", i, type); + + board_serdes_map[i].serdes_type = type; + } + } + } + + *serdes_map_array = board_serdes_map; + *count = ARRAY_SIZE(board_serdes_map); + return 0; +} + +/* + * 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 mv_ddr_topology_map board_topology_map = { + DEBUG_LEVEL_ERROR, + 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 */ + MV_DDR_DEV_WIDTH_16BIT, /* sdram device width */ + MV_DDR_DIE_CAP_4GBIT, /* die capacity */ + MV_DDR_FREQ_667, /* frequency */ + 0, 0, /* cas_l cas_wl */ + MV_DDR_TEMP_HIGH} }, /* temperature */ + BUS_MASK_32BIT, /* subphys mask */ + MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ + { {0} }, /* raw spd data */ + {0} /* timing parameters */ +}; + +struct mv_ddr_topology_map *mv_ddr_topology_map_get(void) +{ + /* Return the board topology as defined in the board code */ + return &board_topology_map; +} + +#if defined(CONFIG_WATCHDOG) + +void watchdog_init(void) +{ + /* NOTE: Global watchdog counter register is at 0xf1020334 + Could not find this in the manual. */ + if (uclass_get_device(UCLASS_WDT, 0, (struct udevice **)&(gd->watchdog))) { + puts("Cannot enable watchdog!\n"); + } else { + puts("Enabling watchdog\n"); + wdt_start(gd->watchdog, (u32) 25000000 * 150, 0); /* Timer runs at 25 MHz */ + } +} + +/* Called by macro WATCHDOG_RESET */ +void watchdog_reset(void) +{ + static ulong next_reset = 0; + ulong now; + + if (!(gd->watchdog)) return; + + now = timer_get_us(); + + /* Do not reset the watchdog too often */ + if (now > next_reset) { + wdt_reset(gd->watchdog); + next_reset = now + 1000000; + } +} +#endif + +int board_early_init_f(void) +{ + /* Configure MPP */ + writel(0x00111111, MVEBU_MPP_BASE + 0x00); + writel(0x40000000, MVEBU_MPP_BASE + 0x04); + writel(0x55000444, MVEBU_MPP_BASE + 0x08); + writel(0x55053350, MVEBU_MPP_BASE + 0x0c); + writel(0x55555555, MVEBU_MPP_BASE + 0x10); + writel(0x06605505, MVEBU_MPP_BASE + 0x14); + writel(0x55550555, MVEBU_MPP_BASE + 0x18); + writel(0x00005551, MVEBU_MPP_BASE + 0x1c); + + /* Set GPP Out value */ + writel(GPP_OUT_VAL_LOW, MVEBU_GPIO0_BASE + 0x00); + writel(GPP_OUT_VAL_MID, MVEBU_GPIO1_BASE + 0x00); + + /* Set GPP Polarity */ + writel(GPP_POL_LOW, MVEBU_GPIO0_BASE + 0x0c); + writel(GPP_POL_MID, MVEBU_GPIO1_BASE + 0x0c); + + /* Set GPP Out Enable */ + writel(GPP_OUT_ENA_LOW, MVEBU_GPIO0_BASE + 0x04); + writel(GPP_OUT_ENA_MID, MVEBU_GPIO1_BASE + 0x04); + + return 0; +} + +u32 spl_boot_mode(const u32 boot_device) +{ + return MMCSD_MODE_EMMCBOOT; +} + +void spl_board_init(void) +{ + int err; + struct mmc *mmcp; + + da9063_init(CONFIG_PMIC_I2C_BUS); + + // FB 57727 Use synchronous mode for buck converters + // This solves the occasional rail lock up problem + da9063_set_reg(PMIC_REG_BCORE1_CONF, 0x81); + da9063_set_reg(PMIC_REG_BCORE2_CONF, 0x81); + da9063_set_reg(PMIC_REG_BIO_CONF, 0x81); + da9063_set_reg(PMIC_REG_BMEM_CONF, 0x81); + da9063_set_reg(PMIC_REG_BPERI_CONF, 0x81); + + /* Enable LDO6 used for GNSS */ + da9063_set_reg(PMIC_REG_LDO6_CONT, 0x81); + + da9063_reset_reason_update(RESET_REASON_SHM_LOCATION); + + err = mmc_initialize(0); + if (err) + return; + + debug("SPL: select partition\n"); + mmcp = find_mmc_device(0); + mmc_init(mmcp); + printf("Partition found: %p\n", mmcp); + /* select boot0 as first boot partition */ + mmcp->part_config &= ~(PART_ACCESS_MASK << 3); + mmcp->part_config |= (1 << 3); + debug("Boot partition set to boot0\n"); +} + +static void set_gpios(void) +{ + init_gpios(); +} + +#if !defined(CONFIG_SPL_BUILD) + +static void pass_hw_rev(void) +{ + int hw_ver = 0, hw_rev = 0; + char *old_env; + char hw_versions[128]; + char new_env[256]; + + bd_get_hw_version(&hw_ver, &hw_rev); + + snprintf(hw_versions, sizeof(hw_versions), "CP=%d.%d", + hw_ver, hw_rev); + + old_env = env_get("add_version_bootargs"); + + /* Normaly add_version_bootargs should already be set (see board include file) */ + if (old_env != 0) { + snprintf(new_env, sizeof(new_env), "%s %s", old_env, hw_versions); + } + else { + snprintf(new_env, sizeof(new_env), "env_set bootargs $bootargs %s\n", hw_versions); + } + + env_set("add_version_bootargs", new_env); +} + +#endif + +int board_init(void) +{ +#if defined(CONFIG_WATCHDOG) + watchdog_init(); +#endif + + /* adress of boot parameters */ + gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100; + + /* Setup the MBUS mapping for Devicebus CS0 */ + mbus_dt_setup_win(&mbus_state, DEV_CS0_BASE, 16 << 20, + CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_DEV_CS0); + + if (read_eeprom() < 0) + puts("Could not get board ID.\n"); + + set_gpios(); + + /* @@se: With this call we disable a debug feature, that allows one to read out the memory + * over i2c at slave address 0x64. This feature is for some undocumented reasons enabled by default + * the default value is 0x00370010, according to the documentation it should be 0x00330010. If we set + * it back to this value address 0x64 is unused again. This is necessary because atsha204 uses 0x64 as + * slave address. + */ + writel(0x00330010, SOC_REGS_PHY_BASE + 0x0001108c); + + return 0; +} + +int board_early_init_r(void) +{ + /* We need to force mmc_initialization here, so that + * we have mmc available for read of /boot/consoledev */ + mmc_initialize(gd->bd); + /* We need to force the env relocation so that it won't overwritte the + * serial devices that we set in init_console */ + env_relocate(); + gd->env_valid = ENV_VALID; + + return 0; +} + +#if !defined(CONFIG_SPL_BUILD) + +static bool get_button_state(void) +{ + u8 state = 0x00; + + (void)da9063_get_reg(PMIC_REG_STATUS_A, &state); + + return (state & 0x01) == 0x01; +} + +static int check_reset_button(void) +{ + int counter = 0; + + /* Check how long button is pressed */ + do { + if (!get_button_state()) + break; + + udelay(100*1000); /* 100ms */ + counter += 100; + + if (counter == 2000) { + /* Indicate factory reset threshold */ + + /* let all green LEDs blink up */ + set_led(LED0_GREEN, 1); + set_led(LED1_GREEN, 1); + set_led(LED2_GREEN, 1); + set_led(LED3_GREEN, 1); + set_led(LED4_GREEN, 1); + set_led(LED5_GREEN, 1); + udelay(400000); /* 400ms */ + set_led(LED1_GREEN, 0); + set_led(LED2_GREEN, 0); + set_led(LED3_GREEN, 0); + set_led(LED4_GREEN, 0); + set_led(LED5_GREEN, 0); + } else if (counter == 12000) { + /* Indicate recovery boot threshold */ + + /* let all red LEDs blink up */ + set_led(LED0_GREEN, 0); + set_led(LED0_RED, 1); + set_led(LED1_RED, 1); + set_led(LED2_RED, 1); + set_led(LED3_RED, 1); + set_led(LED4_RED, 1); + set_led(LED5_RED, 1); + udelay(400000); /* 400ms */ + set_led(LED0_RED, 0); + set_led(LED1_RED, 0); + set_led(LED2_RED, 0); + set_led(LED3_RED, 0); + set_led(LED4_RED, 0); + set_led(LED5_RED, 0); + set_led(LED0_GREEN, 1); + } + } while (counter < 12000); + + if (counter < 2000) { + /* Don't do anything for duration < 2s */ + } + else if (counter < 12000) + { + /* Do factory reset for duration between 2s and 12s */ + char new_bootargs[512]; + char *bootargs = env_get("bootargs"); + + if (bootargs == 0) bootargs=""; + + printf("Do factory reset during boot...\n"); + + strncpy(new_bootargs, bootargs, sizeof(new_bootargs)); + strncat(new_bootargs, " factory-reset", sizeof(new_bootargs)); + + env_set("bootargs", new_bootargs); + return 1; + } + else + { + /* Boot into recovery for duration > 12s */ + + printf("Booting recovery image...\n"); + + /* Set bootcmd to run recovery */ + env_set("bootcmd", "run recovery"); + + return 0; + } + + return 0; +} + +#ifdef CONFIG_CMD_NB_TEST +/* + * Perform a hardware reset test. The complete test loops until + * interrupted by ctrl-c or by pressed the RESET button. + */ +int do_hwreset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int gpio_cpu_value = 0; + + printf(" Press RESET button for testing or ctrl-c to abort\n"); + + while (gpio_cpu_value == 0) { + gpio_cpu_value = get_button_state() ? 1 : 0; + + printf("RESET_BTN = %d\n",gpio_cpu_value); + if (ctrlc()) { + putc ('\n'); + return 1; + } + udelay(20*1000); + } + + return 1; +} +#endif /* CONFIG_CMD_NB_TEST */ + +#endif /* !defined(CONFIG_SPL_BUILD) */ + +int misc_init_r(void) +{ + struct serdes_map* sm; + u8 sm_count; + + /* Because U-Boot is buggy, we need to call this funktion again + * it will print the pre console buffer */ + + /* TODO: Moved following two lines to board_late_init because ttyS1 is currently not working without loaded bitstream */ +// init_console(); +// console_init_f(); + + /* Configure PMIC */ + +#if !defined(CONFIG_SPL_BUILD) + + /* Enable PMIC LED */ + da9063_set_reg(0x1e, 0x08); + + /* Enable PMIC RTC backup charger (charge with 6mA to 3.1V) */ + da9063_set_reg(PMIC_REG_BBAT_CONT, 0xff); +#endif + + /* Determine SERDES configuration */ + hws_board_topology_load(&sm, &sm_count); + + return 0; +} + +static void set_phy_page(const char *miidev, int phy_addr, int page) +{ + miiphy_write(miidev, phy_addr, 22, page); +} + +static void set_phy_fast_blink_mode(int phy_addr) +{ + const char *miidev = miiphy_get_current_dev(); + debug ("miidev: %s\n", miidev); + + set_phy_page(miidev, phy_addr, 3); + miiphy_write(miidev, phy_addr, 16, 0x1032); + miiphy_write(miidev, phy_addr, 17, 0x4405); + miiphy_write(miidev, phy_addr, 18, 0x4A08); + set_phy_page(miidev, phy_addr, 0); +} + +#if !defined(CONFIG_SPL_BUILD) + +static void set_devicetree_name(void) +{ + char devicetreename[64]; + + if (bd_get_devicetree(devicetreename, sizeof(devicetreename)) != 0) { + printf("Devicetree name not found, use legacy name\n"); + strcpy(devicetreename, "armada-385-hw29-prod1.dtb"); + } + + env_set("fdt_image", devicetreename); +} + +#endif + +int board_late_init(void) +{ +#if !defined(CONFIG_SPL_BUILD) + gpio_request(29, "RST_ETH_PHY_N"); + gpio_direction_output(29, 0); + + find_and_set_active_partition(); + pass_hw_rev(); + + run_command("run load_fpga", CMD_FLAG_ENV); +#endif + + /* TODO: Move the following two lines up to misc_init_r when ttyS1 works without FPGA again */ + init_console(); + console_init_f(); + +#if !defined(CONFIG_SPL_BUILD) + + check_reset_button(); + + set_devicetree_name(); + + set_mac_address(0, 0); + set_mac_address(1, 1); + set_mac_address(2, 2); + + /* Take phy out of reset after FPGA was loaded */ + gpio_set_value(29, 1); +#endif + + return 0; +} + +int board_network_enable(struct mii_dev *bus) +{ + static int NETWORK_ENABLED = 0; + + if (!NETWORK_ENABLED) { + set_phy_fast_blink_mode(0); + set_phy_fast_blink_mode(1); + + NETWORK_ENABLED = 1; + } + + return 0; +} + +int checkboard(void) +{ + debug("Board: NetModule NBHW29\n"); + + return 0; +} + +int board_fit_config_name_match(const char *name) +{ +#ifdef CONFIG_SPL_BUILD + /* SPL has enabled serial0 per default and will output everything + * independend of /boot/consoledev */ +#define DEFAULT_DTB_NAME "armada-385-hw29-spl" +#else + /* U-Boot will read /boot/consoledev and based on that it + * enables its own serial console */ +#define DEFAULT_DTB_NAME "armada-385-hw29" +#endif + + /* Check if name fits our dts */ + return strcmp(DEFAULT_DTB_NAME, name); +} + +#ifdef CONFIG_OF_BOARD_FIXUP + + +int fdt_enable_by_ofname(void *rw_fdt_blob, char *ofname) +{ + int offset = fdt_path_offset(rw_fdt_blob, ofname); + + return fdt_status_okay(rw_fdt_blob, offset); +} + +int board_fix_fdt(void *fdt_blob) +{ + return 0; +} + +#endif + +int pcie_lane_by_slot(int slot) +{ + int serdes; + switch (slot) { + case 0 : + serdes = 3; + break; + case 1 : + serdes = 4; + break; + case 2 : + serdes = 1; + break; + default : + serdes = -1; + break; + } + + if ((serdes<0) || serdes>=ARRAY_SIZE(board_serdes_map)) + return -1; + + switch (board_serdes_map[serdes].serdes_type) + { + case PEX0 : + return 0; + case PEX1 : + return 1; + case PEX2 : + return 2; + case PEX3 : + return 3; + default : + return -1; + } +} +/* +static void ft_enable_node(void* blob, const char* name) +{ + int node_ofs = -1; + + node_ofs = fdt_path_offset(blob, name); + if (node_ofs >= 0) { + fdt_setprop_string(blob, node_ofs, "status", "okay"); + } +} +*/ +int ft_board_setup(void *blob, bd_t *bd) +{ + /* Enabled all components in dts depending on + current serdes configuration */ + + return 0; +} + diff --git a/board/nm/hw29/kwbimage.cfg b/board/nm/hw29/kwbimage.cfg new file mode 100644 index 0000000000..a705a795c0 --- /dev/null +++ b/board/nm/hw29/kwbimage.cfg @@ -0,0 +1,12 @@ +# +# Copyright (C) 2014 Stefan Roese +# + +# Armada XP uses version 1 image format +VERSION 1 + +# Boot Media configurations +BOOT_FROM sdio + +# Binary Header (bin_hdr) with DDR3 training code +BINARY spl/u-boot-spl-dtb.bin 0000005b 00000068 diff --git a/board/nm/hw29/nbhw_fpga_config.c b/board/nm/hw29/nbhw_fpga_config.c new file mode 100644 index 0000000000..e1d893d7a1 --- /dev/null +++ b/board/nm/hw29/nbhw_fpga_config.c @@ -0,0 +1,393 @@ +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include +#include "../common/nbhw_bd.h" +#include "../common/nbhw_sim.h" + +DECLARE_GLOBAL_DATA_PTR; + +struct gpio_desc leds[16]; +struct udevice *driver_dev; + +struct config_priv { + u32 led_count; +} priv; + +typedef enum { + TYPE_USB, + TYPE_USB3, + TYPE_PCIE, +} slot_type_t; + +struct pcie_slot_gpios { + struct gpio_desc reset; + struct gpio_desc power; + struct gpio_desc wdis_out; + struct gpio_desc wdis; + struct gpio_desc clk; + struct gpio_desc power_3v8; + struct gpio_desc reset_1v8; + struct gpio_desc reset_3v3; + struct gpio_desc wdis_1v8; + struct gpio_desc wdis_3v3; +}; + +struct sfp_gpios { + struct gpio_desc reset; + struct gpio_desc power; +}; + +#define PCIE_SLOT_COUNT 8 +static struct pcie_slot_gpios pcie_slots[PCIE_SLOT_COUNT]; +static struct sfp_gpios sfps; + +static int pcie_slot_count = 0; + +static int request_and_set_gpio_by_name(ofnode fdt, + const char *name, struct gpio_desc *desc) +{ + int default_value = 0; + u32 gpio_array[4]; + debug("%s\n", __func__); + + /* Request the gpio described by the property */ + if (gpio_request_by_name_nodev(fdt, name, 0, desc, + GPIOD_IS_OUT)) + { + debug("Could not request gpio %s\n", name); + return -1; + } + + /* Get the gpio array, to find out its default value (4 index) */ + if (ofnode_read_u32_array(fdt, name, gpio_array, 4)) { + printf("Could not request gpio array %s\n", name); + return -1; + + } + + default_value = gpio_array[3]; + debug("Set GPIO %s to %d\n", name, default_value); + dm_gpio_set_value(desc, default_value); + return 0; +} + +static int add_sfp(ofnode fdt) +{ + debug("%s\n", __func__); + + request_and_set_gpio_by_name(fdt, "power", + &sfps.power); + + request_and_set_gpio_by_name(fdt, "reset", + &sfps.reset); + + return 0; +} + +static int add_pcie_slot(ofnode fdt) +{ + debug("%s\n", __func__); + + request_and_set_gpio_by_name(fdt, "power", + &pcie_slots[pcie_slot_count].power); + + request_and_set_gpio_by_name(fdt, "reset", + &pcie_slots[pcie_slot_count].reset); + + request_and_set_gpio_by_name(fdt, "wdis-out", + &pcie_slots[pcie_slot_count].wdis_out); + + request_and_set_gpio_by_name(fdt, "wdis", + &pcie_slots[pcie_slot_count].wdis); + + request_and_set_gpio_by_name(fdt, "clk", + &pcie_slots[pcie_slot_count].clk); + + request_and_set_gpio_by_name(fdt, "power-3v8", + &pcie_slots[pcie_slot_count].power_3v8); + + request_and_set_gpio_by_name(fdt, "reset-1v8", + &pcie_slots[pcie_slot_count].reset_1v8); + + request_and_set_gpio_by_name(fdt, "reset-3v3", + &pcie_slots[pcie_slot_count].reset_3v3); + + request_and_set_gpio_by_name(fdt, "wdis-1v8", + &pcie_slots[pcie_slot_count].wdis_1v8); + + request_and_set_gpio_by_name(fdt, "wdis-3v3", + &pcie_slots[pcie_slot_count].wdis_3v3); + + pcie_slot_count++; + return 0; +} + +static int has_slot_wlan(int slot) +{ + int module; + char slotDescr[20]; + char pdValue[200]; + + sprintf(slotDescr, "slot=%d", slot); + for (module=0; module<4; module++) { + strcpy(pdValue, "" ); /*init with an empty string*/ + if (bd_get_pd_module(module, pdValue, sizeof(pdValue))==0) { + /* Wifi module needs PCIe */ + if ((strstr(pdValue, slotDescr)) && (strstr(pdValue, "wlan-"))) + return 1; + } + } + + return 0; +} + +static int configure_pcie_slots(void) +{ + int i, res; + char volt[10]; + + configure_sim_slots(4); + + udelay(1200000); /* 1.2 s */ + + for (i = 0; i < 5; i++) { + /* Set supply voltage of PCIe slots */ + if ((bd_get_slot_supply_volt(i, volt, sizeof(volt)) == 0) && + (strncmp(volt, "3v8", 3)==0)) { + dm_gpio_set_value(&pcie_slots[i].power_3v8, 1); + } else { + /* Default is 3v3 */ + dm_gpio_set_value(&pcie_slots[i].power_3v8, 0); + } + + /* Set reset signal voltage of PCIe slots */ + res = bd_get_slot_perst_volt(i, volt, sizeof(volt)); + if ((res == 0) && (strncmp(volt, "off", 3)==0)) { + /* No pull up */ + dm_gpio_set_value(&pcie_slots[i].reset_1v8, 0); + dm_gpio_set_value(&pcie_slots[i].reset_3v3, 0); + } else if ((res == 0) && (strncmp(volt, "1v8", 3)==0)) { + dm_gpio_set_value(&pcie_slots[i].reset_1v8, 1); + dm_gpio_set_value(&pcie_slots[i].reset_3v3, 0); + } else { + /* Default is 3v3 */ + dm_gpio_set_value(&pcie_slots[i].reset_1v8, 0); + dm_gpio_set_value(&pcie_slots[i].reset_3v3, 1); + } + + /* Set wdis signal voltage of PCIe slots */ + res = bd_get_slot_wdis_volt(i, volt, sizeof(volt)); + if ((res == 0) && (strncmp(volt, "off", 3)==0)) { + /* No pull up */ + dm_gpio_set_value(&pcie_slots[i].wdis_1v8, 0); + dm_gpio_set_value(&pcie_slots[i].wdis_3v3, 0); + } else if ((res == 0) && (strncmp(volt, "1v8", 3)==0)) { + dm_gpio_set_value(&pcie_slots[i].wdis_1v8, 1); + dm_gpio_set_value(&pcie_slots[i].wdis_3v3, 0); + } else { + /* Default is 3v3 */ + dm_gpio_set_value(&pcie_slots[i].wdis_1v8, 0); + dm_gpio_set_value(&pcie_slots[i].wdis_3v3, 1); + } + } + + /* Apply power to all PCIe slots */ + for (i = 0; i < pcie_slot_count; i++) { + dm_gpio_set_value(&pcie_slots[i].power, 1); + udelay(200000); /* 200 ms */ + } + + /* Assert reset after power is enabled */ + for (i = 0; i < pcie_slot_count; i++) { + dm_gpio_set_value(&pcie_slots[i].reset, 1); + } + + /* Enable PCIe clock Note: Slot 1 has always clock. Slot 0 & extension + slot cannot have clock at same time. */ + for (i = 0; i < 2; i ++) { + if (has_slot_wlan(i)) { + /* Only enable PCIe clock on WiFi modules as it confuses some LTE modems */ + dm_gpio_set_value(&pcie_slots[i].clk, 1); + } + } + + /* Deactivate WDIS */ + for (i = 0; i < pcie_slot_count; i++) { + dm_gpio_set_value(&pcie_slots[i].wdis_out, 1); + dm_gpio_set_value(&pcie_slots[i].wdis, 0); + udelay(2000); /* 2 ms needed by Reyax module as regulator is enabled by WDIS~*/ + } + + udelay(12000); /* 12 ms */ + + /* Deassert reset */ + for (i = 0; i < pcie_slot_count; i++) { + dm_gpio_set_value(&pcie_slots[i].reset, 0); + } + + pci_init_board(); + + return 0; +} + +static int configure_leds(void) +{ + int i; + int led_count; + + led_count = gpio_request_list_by_name(driver_dev, "leds", leds, + ARRAY_SIZE(leds), GPIOD_IS_OUT); + + dm_gpio_set_value(&leds[0], 1); + for (i = 1; i < ARRAY_SIZE(leds); i++) { + dm_gpio_set_value(&leds[i], 0); + } + + priv.led_count = led_count; + + return 0; +} + +void set_led(int index, int value) +{ + if ((index<0) || (index>=priv.led_count)) return; + + dm_gpio_set_value(&leds[index], value); +} + +static int request_and_set_gpios(ofnode fdt, + struct gpio_desc *gpios, u32 max_gpios) +{ + int i = 0; + int default_value = 0; + int offset = 0; + + + for (offset = fdt_first_property_offset(gd->fdt_blob, ofnode_to_offset(fdt)); + offset >= 0; + offset = fdt_next_property_offset(gd->fdt_blob, offset)) { + u32 gpio_array[4]; + const char *name; + const struct fdt_property *prop; + + + if (i >= max_gpios) { + printf("Too many gpio entries (max %d)\n", max_gpios); + break; + } + + prop = fdt_get_property_by_offset(gd->fdt_blob, offset, NULL); + + name = fdt_string(gd->fdt_blob, fdt32_to_cpu(prop->nameoff)); + debug("Name: %s\n", name); + if (name[0] == '#') { + continue; + } + + /* Request the gpio descriped by the property */ + if (gpio_request_by_name_nodev(fdt, name, 0, &gpios[i], + GPIOD_IS_OUT)) + { + printf("Could not request gpio %s\n", name); + return -1; + } + + /* Get the gpio array, to find out its default value (4 index) */ + if (ofnode_read_u32_array(fdt, name, + gpio_array, 4)) { + printf("Could not request gpio array %s\n", name); + return -1; + + } + default_value = gpio_array[3]; + debug("Set GPIO %s to %d\n", name, default_value); + dm_gpio_set_value(&gpios[i], default_value); + + i++; + } + + debug("leave %s with %d gpios\n", __func__, i); + return i; +} + + +static int configure_misc(ofnode fdt) +{ + struct gpio_desc misc_gpios[16]; + int gpio_count; + debug("%s\n", __func__); + + gpio_count = request_and_set_gpios(fdt, + misc_gpios, ARRAY_SIZE(misc_gpios)); + if (gpio_count < 1) { + return -1; + } + + debug("Free gpios\n"); + /* Free gpios so that we could use them via gpio subsystem */ + gpio_free_list_nodev(misc_gpios, gpio_count); + debug("return %s\n", __func__); + + return 0; +} + +int nbhw_fpga_configure(void) +{ + ofnode subnode; + ofnode node = driver_dev->node; + debug("%s\n", __func__); + + ofnode_for_each_subnode(subnode, node) { + const char *name; + + name = ofnode_get_name(subnode); + + debug("Try to configure %s\n", name); + if (!strncmp("misc", name, 4)) { + configure_misc(subnode); + } + + if (!strncmp("pcieslot", name, 8)) { + add_pcie_slot(subnode); + } + + if (!strncmp("sfp", name, 3)) { + add_sfp(subnode); + } + } + + if (configure_leds()) + return -1; + + if (configure_pcie_slots()) { + return -1; + } + + return 0; +} + +static int nbhw_fpga_config_bind(struct udevice *dev) +{ + debug("%s\n", __func__); + + driver_dev = dev; + return 0; +} + +static const struct udevice_id nbhw_fpga_config_ids[] = { + { .compatible = "nm,nbhw29-fpga-config" }, + { } +}; + +U_BOOT_DRIVER(gpio_nbhw_fpga_config) = { + .name = "nbhw29_fpga_config", + .id = UCLASS_ROOT, + .of_match = nbhw_fpga_config_ids, + .bind = nbhw_fpga_config_bind, +}; + diff --git a/board/nm/hw29/nbhw_gpio.c b/board/nm/hw29/nbhw_gpio.c new file mode 100644 index 0000000000..7fd4147db2 --- /dev/null +++ b/board/nm/hw29/nbhw_gpio.c @@ -0,0 +1,37 @@ +#include +#include + +#define GPIO_RESET_BUTTON (14) + +void init_gpios(void) +{ + gpio_request(GPIO_RESET_BUTTON, "GPIO_RESET_BUTTON"); + gpio_direction_input(GPIO_RESET_BUTTON); +} + +void out_usb_power(int enable) +{ +// SET_LOGIC(enable, 1, BIT9); +} + +void out_watchdog(int enable) +{ +// SET_LOGIC(enable, 0, BIT19); +} + +void out_fpga_logic_reset(int enable) +{ +// SET_LOGIC(enable, 1, BIT12); +} + +void out_ext_reset_en(int enable) +{ +// SET_LOGIC(enable, 0, BIT7); +} + +int in_reset_button(void) +{ + return gpio_get_value(GPIO_RESET_BUTTON); +} + + diff --git a/board/nm/hw29/nbhw_gpio.h b/board/nm/hw29/nbhw_gpio.h new file mode 100644 index 0000000000..dd1a087e0a --- /dev/null +++ b/board/nm/hw29/nbhw_gpio.h @@ -0,0 +1,28 @@ +#ifndef NBHW29_GPIO_H +#define NBHW29_GPIO_H +#include "../common/nbhw_gpio.h" + +void init_gpios(void); + +void out_usb_power(int enable); +void out_watchdog(int enable); +void out_fpga_logic_reset(int enable); + +int in_fpga_cdone(void); + +#define LED0_GREEN 0 +#define LED0_RED 1 +#define LED1_GREEN 2 +#define LED1_RED 3 +#define LED2_GREEN 4 +#define LED2_RED 5 +#define LED3_GREEN 6 +#define LED3_RED 7 +#define LED4_GREEN 8 +#define LED4_RED 9 +#define LED5_GREEN 10 +#define LED5_RED 11 + +void set_led(int index, int value); + +#endif diff --git a/board/nm/hw29/nbhw_sim.c b/board/nm/hw29/nbhw_sim.c new file mode 100644 index 0000000000..be143ffd64 --- /dev/null +++ b/board/nm/hw29/nbhw_sim.c @@ -0,0 +1,34 @@ +#include +#include "../common/nbhw_fpga_prog.h" + +#define SIM_CTRL (0x0040) + +void connect_sim_to_slot(int sim, int slot) { + uint16_t sim_ctrl; + uint16_t sim_shift; + uint16_t slot_sel; + + if (sim > 1) { + printf("Invalid sim %d selected, can't connect slot %d\n", sim, slot); + return; + } + + if (slot < 0) + slot_sel = 0; + else if (slot <= 4) { + slot_sel = slot + 1; + } + else { + printf("Invalid slot %d selected, can't connect sim %d\n", slot, sim); + return; + } + + sim_shift = sim * 4; + + sim_ctrl = FPGA_REG(SIM_CTRL); + + sim_ctrl &= ~(0xF << sim_shift); + sim_ctrl |= slot_sel << sim_shift; + + FPGA_REG(SIM_CTRL) = sim_ctrl; +} diff --git a/configs/armada-385-hw29_defconfig b/configs/armada-385-hw29_defconfig new file mode 100644 index 0000000000..83f65dc759 --- /dev/null +++ b/configs/armada-385-hw29_defconfig @@ -0,0 +1,75 @@ +CONFIG_ARM=y +CONFIG_ARCH_MVEBU=y +CONFIG_SPL_LIBCOMMON_SUPPORT=y +CONFIG_SPL_LIBGENERIC_SUPPORT=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_TARGET_NM_HW29=y +CONFIG_SPL_MMC_SUPPORT=y +CONFIG_SPL_SERIAL_SUPPORT=y +CONFIG_SPL_LIBDISK_SUPPORT=y +CONFIG_DEFAULT_DEVICE_TREE="armada-385-hw29-spl" +CONFIG_SMBIOS_PRODUCT_NAME="hw29" +CONFIG_FIT=y +CONFIG_FIT_ENABLE_SHA256_SUPPORT=y +CONFIG_BOOTDELAY=3 +CONFIG_BOOTSTAGE_STASH_SIZE=4096 +CONFIG_PRE_CONSOLE_BUFFER=y +CONFIG_SYS_CONSOLE_IS_IN_ENV=y +CONFIG_PRE_CON_BUF_SZ=4096 +CONFIG_PRE_CON_BUF_ADDR=0x04000000 +# CONFIG_CONSOLE_MUX is not set +CONFIG_DEFAULT_FDT_FILE="armada-385-hw29-spl" +# CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_SPL=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x190 +CONFIG_SPL_I2C_SUPPORT=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_BOOTZ=y +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_NB_TEST=y +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_USB=y +# 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_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_EFI_PARTITION=y +# CONFIG_PARTITION_UUIDS is not set +# CONFIG_SPL_PARTITION_UUIDS is not set +CONFIG_OF_BOARD_FIXUP=y +CONFIG_SPL_OF_TRANSLATE=y +CONFIG_OF_LIST="armada-385-hw29-spl armada-385-hw29" +CONFIG_MULTI_DTB_FIT=y +CONFIG_FPGA_LATTICE_SSPI=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_SDMA=y +CONFIG_MMC_SDHCI_MV=y +CONFIG_SPI_FLASH=y +CONFIG_MVNETA=y +CONFIG_PCI=y +# CONFIG_DEBUG_UART is not set +# CONFIG_REQUIRE_SERIAL_CONSOLE is not set +CONFIG_SYS_NS16550=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_MARVELL=y +CONFIG_USB_STORAGE=y +CONFIG_MVEBU_GPIO=y +CONFIG_DM_GPIO=y +CONFIG_CMD_EEPROM=y +CONFIG_ENV_IS_IN_EEPROM=y +CONFIG_WDT=y +CONFIG_WDT_ORION=y diff --git a/include/configs/armada-385-hw29.h b/include/configs/armada-385-hw29.h new file mode 100644 index 0000000000..131dd9466f --- /dev/null +++ b/include/configs/armada-385-hw29.h @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2014 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _CONFIG_DB_88F6820_GP_H +#define _CONFIG_DB_88F6820_GP_H + +/* + * High Level Configuration Options (easy to change) + */ + +#define CONFIG_DISPLAY_BOARDINFO_LATE + +/* + * 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 */ + +/* + * Commands configuration + */ +#define CONFIG_CMD_PCI + +/* I2C */ +#define CONFIG_SYS_I2C +#define CONFIG_SYS_I2C_MVTWSI +#define CONFIG_I2C_MVTWSI_BASE0 MVEBU_TWSI_BASE +#define CONFIG_SYS_I2C_SLAVE 0x0 +#define CONFIG_SYS_I2C_SPEED 100000 + +/* + * SDIO/MMC Card Configuration + */ +#define CONFIG_SYS_MMC_BASE MVEBU_SDIO_BASE + +/* Partition support */ + +/* USB/EHCI configuration */ +#define CONFIG_EHCI_IS_TDI + +/* Environment in I2C EEPROM */ +/** + * Layout on the NBHW08 Board: + * Offset Size Description + * 0x0000 0x200 The NetModule Boarddescriptor + * 0x0200 0x200 The NetModule Productdescriptor + * 0x0400 0x200 The NetModule License Descriptor + * 0x0600 0x400 The NetModule Parition table + * 0x0A00 0x600 reserved + * 0x1000 0xA00 The U-Boot environment + * 0x1A00 0x600 reserved + */ +#define CONFIG_ENV_OFFSET (0x1000) /* The Environment is located at 4k */ +#define CONFIG_ENV_SIZE (0xA00) /* 64KiB */ +#define CONFIG_ENV_SECT_SIZE (256 << 10) /* 256KiB sectors */ + +#define CONFIG_ENV_EEPROM_IS_ON_I2C +#define CONFIG_SYS_I2C_EEPROM_ADDR 0x50 /* Main EEPROM */ +#define CONFIG_SYS_DEF_EEPROM_ADDR 0x50 +#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN (2) +#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 5 +#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 70 + +#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_MVEBU +#define CONFIG_PCI_SCAN_SHOW +#endif + +#if !defined(UBOOT_USER_BUILD) && !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT_ORION) +#define CONFIG_WATCHDOG +#endif + +#define CONFIG_OF_BOARD_SETUP + +#define CONFIG_SYS_ALT_MEMTEST + +#ifndef CONFIG_SPL_BUILD + +#define CONFIG_NM_LOGIN +#define CONFIG_CRYPT +#define CONFIG_SUPPORT_EMMC_RPMB + +#define KERNEL_ADDR "0x01000000" +#define LOAD_ADDR "0x03000000" +#define FDT_ADDR "0x02000000" +#define PXE_ADDR "0x02800000" +#define CONFIG_EXTRA_ENV_SETTINGS \ + "fdt_high=0x12000000\0" \ + "initrd_high=0x13000000\0" \ + "kernel_image=kernel.bin\0" \ + "fdt_image=armada-385-hw29-prod1.dtb\0" \ + "modeboot=sdboot\0" \ + "fdt_addr=" FDT_ADDR "\0" \ + "kernel_addr=" KERNEL_ADDR "\0" \ + "load_addr=" LOAD_ADDR "\0" \ + "root_part=1\0" /* Default root partition, overwritte in board file */ \ + "eth1addr=00:11:22:33:44:55\0" \ + "eth2addr=00:11:22:33:44:56\0" \ + "eth3addr=00:11:22:33:44:57\0" \ + "ethact=ethernet@34000\0" \ + "add_sd_bootargs=setenv bootargs $bootargs root=/dev/mmcblk0p$root_part rootfstype=ext4 rootwait nvme_core.default_ps_max_latency_us=0 loglevel=4; run set_console_dev\0" \ + "add_version_bootargs=setenv bootargs $bootargs\0" \ + "fdt_skip_update=yes\0" \ + "sdbringup=echo Try bringup boot && ext4load mmc 0:$root_part $kernel_addr /boot/zImage && " \ + "ext4load mmc 0:$root_part $fdt_addr /boot/$fdt_image && setenv bootargs $bootargs rw;\0" \ + "sdprod=ext4load mmc 0:$root_part $kernel_addr /boot/$kernel_image && " \ + "ext4load mmc 0:$root_part $fdt_addr /boot/$fdt_image && setenv bootargs $bootargs ro;\0" \ + "sdboot=if mmc dev 0; then nbhw_wlan_fixup &&" \ + "echo Copying Linux from SD to RAM...; "\ + "if test -e mmc 0:$root_part /boot/$kernel_image; then run sdprod; " \ + "else run sdbringup; fi; " \ + "run add_sd_bootargs; run add_version_bootargs; " \ + "bootz $kernel_addr - $fdt_addr; fi\0" \ + "bootcmd=run sdboot\0" \ + "ipaddr=192.168.1.1\0" \ + "serverip=192.168.1.254\0" \ + "pxefile_addr_r=" PXE_ADDR "\0" \ + "fdt_addr_r=" FDT_ADDR "\0" \ + "kernel_addr_r=" KERNEL_ADDR "\0" \ + "ramdisk_addr_r=" LOAD_ADDR "\0" \ + "bootpretryperiod=1000\0" \ + "tftptimeout=2000\0" \ + "tftptimeoutcountmax=5\0" \ + "bootpretryperiod=2000\0" \ + "autoload=false\0" \ + "defaultconsole=ttyS1\0" \ + "set_console_dev=if test -n ${consoledev}; then setenv bootargs $bootargs console=$consoledev,115200; fi; true\0" \ + "tftp_recovery=tftpboot $kernel_addr recovery-image; tftpboot $fdt_addr recovery-dtb; setenv bootargs rdinit=/etc/preinit console=$defaultconsole,115200 debug; bootz $kernel_addr - $fdt_addr\0" \ + "pxe_recovery=sleep 3 && dhcp && pxe get && pxe boot\0" \ + "load_fpga=ext4load mmc 0:$root_part $kernel_addr /logic/LG00000000 && nbhw_fpga program lattice-sspi 0xffffffff $kernel_addr $filesize && nbhw_fpga configure\0" \ + "recovery=run pxe_recovery || setenv ipaddr $ipaddr; setenv serverip $serverip; run tftp_recovery\0" /* setenv ipaddr and serverip is necessary, because dhclient can destroy the IPs inernally */ + +#endif + + +/* 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_SDIO_MMC_CARD + +/* Defines for SPL */ +#define CONFIG_SPL_FRAMEWORK +#define CONFIG_SPL_SIZE (180 << 10) +#define CONFIG_SPL_TEXT_BASE 0x40000030 +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) + +#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 +#define CONFIG_OF_STDOUT_VIA_ALIAS +#endif + +#define CONFIG_SPL_STACK (0x40000000 + ((192 - 16) << 10)) +#define CONFIG_SPL_BOOTROM_SAVE (CONFIG_SPL_STACK + 4) + +#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 0x24000 +#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_SYS_MMC_U_BOOT_OFFS (200 << 10) +#define CONFIG_SYS_U_BOOT_OFFS CONFIG_SYS_MMC_U_BOOT_OFFS +#ifdef CONFIG_SPL_BUILD +#define CONFIG_FIXED_SDHCI_ALIGNED_BUFFER 0x00180000 /* in SDRAM */ +#endif +#define CONFIG_SPL_BOARD_INIT +#endif + +/* + * mv-common.h should be defined after CMD configs since it used them + * to enable certain macros + */ +#include "mv-common.h" + +/* + * NBHW needs md5 support + */ +#ifndef CONFIG_MD5 +#define CONFIG_MD5 +#endif + +/* + * We need some functions to be called after environment setup + */ +#define CONFIG_BOARD_LATE_INIT + +#define CONFIG_AUTOBOOT_KEYED 1 +#define CONFIG_AUTOBOOT_PROMPT \ + "Press s to abort autoboot in %d seconds\n" +#undef CONFIG_AUTOBOOT_DELAY_STR +#define CONFIG_AUTOBOOT_STOP_STR "s" + +#ifndef CONFIG_SPL_BUILD +#undef CONFIG_REQUIRE_SERIAL_CONSOLE +/* Wee need early init r to actually print the pre console buffer + * because u-boot is buggy */ +#define CONFIG_BOARD_EARLY_INIT_R +#define CONFIG_MISC_INIT_R +#endif + +#endif /* _CONFIG_DB_88F6820_GP_H */