From c2035d603344f950e745198dadd201bcf1550548 Mon Sep 17 00:00:00 2001 From: Stefan Eichenberger Date: Fri, 17 Nov 2017 13:58:30 +0100 Subject: [PATCH] nbhw17: add support for fpga loading --- arch/arm/dts/armada-385-nbhw17-common.dtsi | 87 ++- arch/arm/dts/armada-385-nbhw17-v1.dts | 15 +- board/nm/common/nbhw_bd.c | 7 +- board/nm/common/nbhw_bd.h | 8 + board/nm/common/nbhw_env.c | 1 - board/nm/common/nbhw_fpga_gpio.c | 753 +++++++++++++++++++++ board/nm/common/nbhw_fpga_prog.c | 478 ------------- board/nm/common/nbhw_init.c | 2 - board/nm/nbhw17_v1/Makefile | 10 +- board/nm/nbhw17_v1/board.c | 158 +++-- board/nm/nbhw17_v1/nbhw_fpga_config.c | 370 ++++++++-- board/nm/nbhw17_v1/nbhw_fpga_prog.c | 36 +- board/nm/nbhw17_v1/nbhw_gpio.c | 29 +- board/nm/nbhw17_v1/nbhw_gpio.h | 5 +- board/nm/nbhw17_v1/nbhw_init.c | 75 -- board/nm/nbhw17_v1/nbhw_pcie_fixup.c | 228 +++++++ drivers/gpio/gpio-uclass.c | 1 - include/configs/armada-385-nbhw17-v1.h | 25 +- net/eth-uclass.c | 24 +- net/eth_common.c | 9 - 20 files changed, 1583 insertions(+), 738 deletions(-) create mode 100644 board/nm/common/nbhw_fpga_gpio.c delete mode 100644 board/nm/common/nbhw_fpga_prog.c delete mode 100644 board/nm/nbhw17_v1/nbhw_init.c create mode 100644 board/nm/nbhw17_v1/nbhw_pcie_fixup.c diff --git a/arch/arm/dts/armada-385-nbhw17-common.dtsi b/arch/arm/dts/armada-385-nbhw17-common.dtsi index 9b5f8a06f7..fd777d0ebf 100644 --- a/arch/arm/dts/armada-385-nbhw17-common.dtsi +++ b/arch/arm/dts/armada-385-nbhw17-common.dtsi @@ -37,12 +37,75 @@ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000 MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000 /* CESA 0 SRAM */ MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000 /* CESA 1 SRAM */ - MBUS_ID(0x01, 0x3e) 0 0xfd000000 0x20000>; /* Devbus CS0 */ + MBUS_ID(0x01, 0x3e) 0 0xfd000000 0x20000>; /* FPGA */ - devbus-cs0 { - status = "okay"; - ranges = <0 MBUS_ID(0x01, 0x3e) 0 0x20000>; - devbus,keep-config; + 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 26 0>; /* FPGA reset */ + fpga-cdone = <&gpio0 29 0>; /* FPGA cdone */ + fpga-reset-logic = <&gpio1 12 0>; /* FPGA reset logic (after load)*/ + }; + + fpga_conf: fpgaconf@0 { + compatible = "nm,nbhw17-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 + hold-pwr-on = <&gpiofpga 64 0 1>; + en-gps-ant = <&gpiofpga 65 0 0>; + en-mdio-phy = <&gpiofpga 66 GPIO_ACTIVE_LOW 1>; + en-mdio-ext = <&gpiofpga 67 GPIO_ACTIVE_LOW 0>; + en-sata-pwr = <&gpiofpga 68 GPIO_ACTIVE_HIGH 1>; + serdes-sel = <&gpiofpga 69 GPIO_ACTIVE_HIGH 1>; + serdes-en = <&gpiofpga 70 GPIO_ACTIVE_LOW 0>; + rst-ext = <&gpiofpga 71 GPIO_ACTIVE_LOW 1>; + rst-ext-eth = <&gpiofpga 72 GPIO_ACTIVE_LOW 1>; + rst-ext-en = <&gpiofpga 73 GPIO_ACTIVE_HIGH 0>; + }; + + pcieslot@0 { + reset = <&gpiofpga 384 GPIO_ACTIVE_LOW 1>; + power = <&gpiofpga 400 GPIO_ACTIVE_HIGH 0>; + wdis-out = <&gpiofpga 2053 GPIO_ACTIVE_HIGH 1>; + wdis = <&gpiofpga 2068 GPIO_ACTIVE_LOW 1>; + }; + + pcieslot@1 { + reset = <&gpiofpga 385 GPIO_ACTIVE_LOW 1>; + power = <&gpiofpga 401 GPIO_ACTIVE_HIGH 0>; + wdis-out = <&gpiofpga 4101 GPIO_ACTIVE_HIGH 1>; + wdis = <&gpiofpga 4117 GPIO_ACTIVE_LOW 1>; + }; + + pcieslot@2 { + reset = <&gpiofpga 386 GPIO_ACTIVE_LOW 1>; + power = <&gpiofpga 402 GPIO_ACTIVE_HIGH 0>; + wdis-out = <&gpiofpga 6149 GPIO_ACTIVE_HIGH 1>; + wdis = <&gpiofpga 6165 GPIO_ACTIVE_LOW 1>; + }; + + pcieslot@3 { + reset = <&gpiofpga 387 GPIO_ACTIVE_LOW 1>; + power = <&gpiofpga 403 GPIO_ACTIVE_HIGH 0>; + wdis-out = <&gpiofpga 8197 GPIO_ACTIVE_HIGH 1>; + wdis = <&gpiofpga 8213 GPIO_ACTIVE_LOW 1>; + }; }; internal-regs { @@ -69,7 +132,6 @@ broken-cd; wp-inverted; no-1-8-v; - clock-freq-min-max=<0 50000000>; bus-width = <8>; status = "okay"; }; @@ -85,6 +147,7 @@ pinctrl-0 = <&uart1_pins>; u-boot,dm-pre-reloc; }; + }; pcie-controller { @@ -104,14 +167,6 @@ }; }; -// nbhw-fpga { -// compatible = "nm,nbhw-fpga"; -// status = "disabled"; -// spi-ss = <&gpio1 5 0> /* SS */ -// spi-sck = <&gpio1 6 0>; /* SCK */ -// spi-sdi = <&gpio1 7 0>; /* SDI slave data in */ -// spi-sdo = <&gpio1 8 0>; /* SDO slave data out */ -// }; }; ð0 { @@ -139,12 +194,12 @@ pinctrl-0 = <&mdio_pins>; phy0: ethernet-phy@0 { - marvell,reg-init = <3 16 0 0x101e>; + marvell,reg-init = <3 16 0 0x101e>; reg = <0>; }; phy1: ethernet-phy@1 { - marvell,reg-init = <3 16 0 0x101e>; + marvell,reg-init = <3 16 0 0x101e>; reg = <1>; }; }; diff --git a/arch/arm/dts/armada-385-nbhw17-v1.dts b/arch/arm/dts/armada-385-nbhw17-v1.dts index f5a4c62367..a78aee6bed 100644 --- a/arch/arm/dts/armada-385-nbhw17-v1.dts +++ b/arch/arm/dts/armada-385-nbhw17-v1.dts @@ -17,20 +17,15 @@ model = "NetModule Router NBHW17 with Armada A385 (NB2800)"; }; -ð0 { - status = "okay"; -}; - -// SFP-Port ð1 { - status = "okay"; - fixed-link { - speed = <1000>; - full-duplex; - }; + status = "okay"; }; ð2 { status = "okay"; }; +&gpiofpga { + status = "okay"; +}; + diff --git a/board/nm/common/nbhw_bd.c b/board/nm/common/nbhw_bd.c index 2ac7f24f56..578140c7a2 100644 --- a/board/nm/common/nbhw_bd.c +++ b/board/nm/common/nbhw_bd.c @@ -48,7 +48,7 @@ int bd_get_context(BD_Context *bdctx, uint32_t i2caddress, uint32_t offset) /* Check whether this is a valid board descriptor (or empty EEPROM) */ rc = BD_CheckHeader( bdctx, bdHeader ); if (!rc) { - printf("%s() No valid board descriptor found\n", __func__); + debug("%s() No valid board descriptor found\n", __func__); goto exit1; } @@ -271,3 +271,8 @@ int bd_get_boot_partition(void) /* If we not have a Bootpartition entry, perhaps we have a partition table */ return try_partition_read(); } + +enum serdes_type bd_get_serdes_type(int serdes) +{ + return DEFAULT_SERDES; +} diff --git a/board/nm/common/nbhw_bd.h b/board/nm/common/nbhw_bd.h index 8cb6541b10..52d3e846a6 100644 --- a/board/nm/common/nbhw_bd.h +++ b/board/nm/common/nbhw_bd.h @@ -4,6 +4,12 @@ #include "bdparser.h" /* tlv parser */ #include +#ifdef _CONFIG_DB_88F6820_GP_H +#include <../serdes/a38x/high_speed_env_spec.h> +#else +enum serdes_type {DEFAULT_SERDES, LAST_SERDES_TYPE}; +#endif + void nbhw_settings_init(void); void bd_register_context_list(const BD_Context *list, size_t count); int bd_get_context(BD_Context *bdctx, uint32_t i2caddress, uint32_t offset); @@ -16,5 +22,7 @@ int bd_get_sim_config(char* simconfig, size_t len); void bd_get_hw_version(int* ver, int* rev); int bd_get_devicetree(char* devicetreename, size_t len); int bd_get_boot_partition(void); +enum serdes_type bd_get_serdes_type(int serdes); + #endif diff --git a/board/nm/common/nbhw_env.c b/board/nm/common/nbhw_env.c index 750358f813..b6a925c879 100644 --- a/board/nm/common/nbhw_env.c +++ b/board/nm/common/nbhw_env.c @@ -18,7 +18,6 @@ void find_and_set_active_partition(void) void set_console(void) { - int len; char buf[50] = "\n"; char *defaultconsole = getenv("defaultconsole"); diff --git a/board/nm/common/nbhw_fpga_gpio.c b/board/nm/common/nbhw_fpga_gpio.c new file mode 100644 index 0000000000..299993abd2 --- /dev/null +++ b/board/nm/common/nbhw_fpga_gpio.c @@ -0,0 +1,753 @@ +/****************************************************************************** + * (c) COPYRIGHT 2015 by NetModule AG, Switzerland. All rights reserved. + * + * This program 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 program 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. + * + *****************************************************************************/ +#undef DEBUG +#include +#include +#include +#include +#include +#include + +#define DEBUG_TEST debug("%s: %d\n",__FILE__, __LINE__); + +DECLARE_GLOBAL_DATA_PTR; + +enum nbhw_fpga_type_num { + FPGA_XILINX, + FPGA_LATTICE, + FPGA_MAX +}; + +struct nbhw_fpga_type { + enum nbhw_fpga_type_num type; + const char* name; +}; + +struct nbhw_fpga_type fpga_types[] = { + { FPGA_XILINX, "xilinx"}, + { FPGA_LATTICE, "lattice"} +}; + +struct nbhw_fpga_priv { + int signature; + struct gpio_desc ss; + struct gpio_desc sck; + struct gpio_desc sdi; + struct gpio_desc sdo; + struct gpio_desc reset; + struct gpio_desc reset_logic; + struct gpio_desc cdone; + enum nbhw_fpga_type_num fpga_type; + u32 fpga_id; + void *regs; +}; + +struct udevice *fpga_dev; + +static inline void spi_write(const struct nbhw_fpga_priv *priv, u8 data) +{ + int i; + u32 data_write = 0; + + dm_gpio_set_value(&priv->sck, 1); + + for (i=0; i<8; i++) + { + data_write = (data & 0x80) ? 1 : 0; + /* Clear clk bit and put data on the line */ + dm_gpio_set_value(&priv->sck, 0); + dm_gpio_set_value(&priv->sdi, data_write); + udelay(1); + /* Read data on rising edge */ + dm_gpio_set_value(&priv->sck, 1); + data = data << 1; + udelay(1); + } +} + +static int fpga_verify(struct nbhw_fpga_priv *priv) +{ + /* Check, if the FPGA is working */ + char fpga_type[30]; + u16 signature = readw(priv->regs); + u16 fpga_version = readw(priv->regs + 0x02); + u8 fpga_major = (fpga_version >> 8) & 0xFF; + u8 fpga_minor = (fpga_version >> 0) & 0xFF; + + debug("Verify FPGA programming\n"); + + if (signature == 0xa501) + { + strcpy(fpga_type, "XC3S50A-4VQ100I top layer"); + } else if (signature == 0xa502) { + strcpy(fpga_type, "XC3S200A-4VQ100I top layer"); + } else if (signature == 0xa511) { + strcpy(fpga_type, "XC3S50A-4FTG256I bottom layer"); + } else if (signature == 0xa512) { + strcpy(fpga_type, "XC3S200A-4FTG256I bottom layer"); + } else if (signature == 0x4004) { + strcpy(fpga_type, "ICE40HX4K-CB132 NBHW17"); + } else if (signature == 0x4184) { + strcpy(fpga_type, "ICE40HX4K-CB132 NBHW18"); + } else { + priv->signature = 0; + goto abort; + } + + printf(" Detected %s FPGA (Version: %d.%d)\n", fpga_type, fpga_major, fpga_minor); + + priv->signature = signature; + + debug("Local priv: %p\n",priv); + + return 1; + +abort: + printf(" No FPGA detected! (Signature:%x)\n", signature); + return 0; +} + +static void put_in_prog_mode(const struct nbhw_fpga_priv *priv) +{ + /* Change the muxing to GPIO */ + writel(0x00055555, MVEBU_MPP_BASE + 0x10); + writel(0x06605500, MVEBU_MPP_BASE + 0x14); + + printf("Put FPGA in programming mode\n"); + dm_gpio_set_value(&priv->ss, 1); + udelay(10); + dm_gpio_set_value(&priv->ss, 0); + dm_gpio_set_value(&priv->sck, 1); + dm_gpio_set_value(&priv->reset, 1); + + udelay(1); + + /* Take FPGA out of reset */ + dm_gpio_set_value(&priv->reset, 0); + + /* Wait for at least 800 us according to lattice manual */ + udelay(800); +} + +static void clean_up_after_programming(const struct nbhw_fpga_priv *priv) +{ + /* Change the muxing back to Devbus */ + writel(0x55555555, MVEBU_MPP_BASE + 0x10); + writel(0x06605505, MVEBU_MPP_BASE + 0x14); + + dm_gpio_set_value(&priv->reset_logic, 0); + udelay(100); + dm_gpio_set_value(&priv->reset_logic, 1); + udelay(100); +} + +static int fpga_load_bitstream (const struct nbhw_fpga_priv *priv, const u8* data, int num_bytes) +{ + int i; + + printf(" Loading FPGA bitstream from 0x%p, %d bytes\n", data, num_bytes); + + put_in_prog_mode(priv); + + printf(" Sending configuration bitstream...\n"); + + for ( i=0; icdone)) { + printf("Error: Fpga does not signalize done\n"); + return -1; + } + + debug("FPGA signalizes done\n"); + + /* Send some extra clocks for startup */ + for ( i=0; i<100; i++) + { + spi_write(priv, 0); + } + + debug("Extra clocks sent\n"); + + return 1; +} + +static int fpga_check_bitstream_lattice(const struct nbhw_fpga_priv *priv, const u8* fpgadata, u8** pStartAddr, int* pSize) +{ + printf ("Checking Lattice FPGA bitstream\n"); + *pStartAddr = (u8*)fpgadata; + /* Do not touch pSize should send the whole file for now */ + + if (priv->fpga_type != FPGA_LATTICE) { + return -1; + } + + if ((priv->fpga_id != 0x00000000) && (priv->fpga_id != 0xFFFFFFFF)) { + return -1; + } + + return 0; +} + +/* Legacy Xilinx check ported from PPC, seems to work */ +static int fpga_check_bitstream_xilinx(const struct nbhw_fpga_priv *priv, const u8* fpgadata, u8** pStartAddr, int* pSize) +{ + unsigned int length; + unsigned int codesize; + char buffer[80]; + const u8* dataptr; + unsigned int i; + u32 fpgaid; + const char *p; + + printf("Checking bitstream at 0x%p\n", fpgadata); + + *pSize = 0; + *pStartAddr = NULL; + + dataptr = fpgadata; + + /* skip the first bytes of the bitsteam, their meaning is unknown */ + length = (*dataptr << 8) + *(dataptr+1); + dataptr+=2; + dataptr+=length; + + /* get design name (identifier, length, string) */ + length = (*dataptr << 8) + *(dataptr+1); + dataptr+=2; + if (*dataptr++ != 0x61) { + printf("%s: Design name identifier not recognized in bitstream\n", + __FUNCTION__ ); + return -1; + } + + length = (*dataptr << 8) + *(dataptr+1); + dataptr+=2; + memset(buffer, 0, sizeof(buffer)); + for(i=0;ifpga_id == 0xFFFFFFFF) { + return 0; + } + p = strstr(buffer, "UserID=0x"); + if (p) { + p += 9; + fpgaid = 0; + for(i = 0;i < 8; i++) { + fpgaid <<= 4; + if ((p[i] >= '0') && (p[i] <= '9')) { + fpgaid |= (u32)(p[i]-'0'); + } else if ((p[i] >= 'A') && (p[i] <= 'F')) { + fpgaid |= (u32)(p[i]-'A'+10); + } else if ((p[i] >= 'a') && (p[i] <= 'f')) { + fpgaid |= (u32)(p[i]-'a'+10); + } else { + printf("%s: User identifier not valid in bitstream\n", + __FUNCTION__ ); + return -1; + } + } + if (fpgaid != priv->fpga_id) { + printf("%s: User identifier not matched in bitstream\n", + __FUNCTION__ ); + return -1; + } + } else { + printf("%s: User identifier not found in bitstream\n", + __FUNCTION__ ); + return -1; + } + + /* get part number (identifier, length, string) */ + if (*dataptr++ != 0x62) { + printf("%s: Part number identifier not recognized in bitstream\n", + __FUNCTION__ ); + return -1; + } + + length = (*dataptr << 8) + *(dataptr+1); + dataptr+=2; + memset(buffer, 0, sizeof(buffer)); + for(i=0;iss, GPIOD_IS_OUT) != 0) { + printf("Could not request spi-gpio ss\n"); + return -1; + } + + if (gpio_request_by_name(dev, "spi-sck", 0, &priv->sck, GPIOD_IS_OUT) != 0) { + printf("Could not request spi-gpio sck\n"); + return -1; + } + + if (gpio_request_by_name(dev, "spi-sdi", 0, &priv->sdi, GPIOD_IS_OUT) != 0) { + printf("Could not request spi-gpio sdi\n"); + return -1; + } + + if (gpio_request_by_name(dev, "spi-sdo", 0, &priv->sdo, GPIOD_IS_IN) != 0) { + printf("Could not request spi-gpio sdo\n"); + return -1; + } + + if (gpio_request_by_name(dev, "fpga-reset", 0, &priv->reset, GPIOD_IS_OUT) != 0) { + printf("Could not request fpga-reset\n"); + return -1; + } + + if (gpio_request_by_name(dev, "fpga-cdone", 0, &priv->cdone, GPIOD_IS_IN) != 0) { + printf("Could not request fpga-cdone\n"); + return -1; + } + + if (gpio_request_by_name(dev, "fpga-reset-logic", 0, &priv->reset_logic, GPIOD_IS_OUT) != 0) { + printf("Could not request fpga-reset-logic\n"); + return -1; + } + + debug("%s\n", __func__); + + return 0; + +} + +static int fpga_program(struct udevice *dev, unsigned long load_addr, + unsigned long filesize) +{ + int res; + struct nbhw_fpga_priv *priv = dev_get_priv(dev); + + debug("%s\n", __func__); + if (abort_fpga_boot()) { + printf("Aborted FPGA boot\n"); + udelay(1000000); /* 1s */ + return 0; + } + + if (priv->ss.dev == NULL) { + if (request_gpios(dev)) { + return -1; + } + } + + /* NBHW_BASE_ADDRESS_FPGA points to base of FPGA registers */ + if (!fpga_boot_buffer(priv, (const u8*)load_addr, filesize)) { + printf ("Loading FPGA over SPI failed.\n"); + return -3; + } + + /* Make sure device bus works, becaus NBHW14 uses its gpios to do SPI */ + setup_device_bus(); + + + /* Verify, if FPGA is loaded successfully */ + res = fpga_verify(priv); + if (!res) + { + return -4; + } + + debug("Signature %d\n", priv->signature); + printf(" FPGA programming done\n"); + + return 0; +} + +static int nbhw_fpga_bind(struct udevice *dev) +{ + struct nbhw_fpga_priv *priv = malloc(sizeof(struct nbhw_fpga_priv)); + + if (priv == NULL) { + puts("Can't allocate memory for nbhw fpga driver\n"); + return -1; + } + + dev->priv = priv; + + /* Make priv available in the whole c file */ + fpga_dev = dev; + + debug("Priv on bind: %p\n", priv); + + /* Get memory region for fpga */ + priv->regs = (struct mvebu_gpio_regs *)dev_get_addr(dev); + printf("FPGA Regs: %p\n", priv->regs); + + return 0; +} + +static int nbhw_fpga_probe(struct udevice *dev) +{ + struct nbhw_fpga_priv *priv = dev_get_priv(dev); + /* Make priv available in the whole c file */ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + debug("dev: %p, local dev: %p\n", dev, fpga_dev); + debug("priv: %p", priv); + + debug("%s signature %d\n", __func__, priv->signature); + + uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), + "gpio-bank-name", NULL); + uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "ngpios", 1024); + debug("%s done\n", __func__); + return 0; +} + +static enum nbhw_fpga_type_num get_fpga_type(const char *name) +{ + int i; + + debug("%s\n", __func__); + + for (i = 0;i < ARRAY_SIZE(fpga_types);i++) { + if (strcmp(fpga_types[i].name, name) == 0) { + return fpga_types[i].type; + } + } + return FPGA_MAX; +} + +static int do_fpga_program (struct nbhw_fpga_priv *priv, int argc, + char * const argv[]) +{ + debug("%s\n", __func__); + + if (argc < 4) + return -1; + + priv->fpga_type = get_fpga_type(argv[0]); + priv->fpga_id = simple_strtoul(argv[1], NULL, 16); + + return fpga_program(fpga_dev, simple_strtoul(argv[2], NULL, 16), + simple_strtoul(argv[3], NULL, 16)); +} + +static int do_fpga_configure (struct nbhw_fpga_priv *priv, int argc, + char * const argv[]) +{ + debug("%s\n", __func__); + if (argc > 0) { + return -1; + } + + if (priv->signature == 0) { + puts("Please program FPGA first\n"); + return -1; + } + +extern int nbhw_fpga_configure(void); + /* Call board specific nbhw_fpga_configure, must be implemented in + * the board file */ + return nbhw_fpga_configure(); +} + +struct fpga_cmd { + const char *cmd; + int (*fpga_fun)(struct nbhw_fpga_priv *priv, int argc, + char * const argv[]); +}; + +struct fpga_cmd fpga_cmds[] = { + {"program", do_fpga_program}, + {"configure", do_fpga_configure}, +}; + +static int do_fpgacmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct nbhw_fpga_priv *priv = dev_get_priv(fpga_dev); + int i; + + debug("Argv 1: %s\n", argv[1]); + for (i = 0;i < ARRAY_SIZE(fpga_cmds); i++) { + if (strcmp(fpga_cmds[i].cmd, argv[1]) == 0) { + return fpga_cmds[i].fpga_fun(priv, argc-2, &argv[2]); + } + } + + return -1; +} + +U_BOOT_CMD( + nbhw_fpga, 6, 1, do_fpgacmd, + "NBHW FPGA control", + "program type id address filesize\n" + " type: fpga tye lattice or xilinx\n" + " id: FPGA User ID (BD) in hex, 0xFFFFFFFF for any\n" + " address: memory address where to find the fpga image\n" + " filesize: filesize of the fpga image\n" + "configure\n" + " do initial fpga configuration\n" +); + +int nbhw_fpga_get_value (struct udevice *dev, unsigned offset) +{ + struct nbhw_fpga_priv *priv = dev_get_priv(dev); + u16 bit = offset%16; + u16 reg = (offset/8)&0xFFFE; + + debug("%s\n", __func__); + + if (priv->signature == 0) { + puts("FPGA not programmed yet\n"); + return -1; + } + + return ((readw(priv->regs + reg) & (1 << bit)) == 0) ? 0 : 1; +} + +int nbhw_fpga_set_value (struct udevice *dev, unsigned offset, int value) +{ + struct nbhw_fpga_priv *priv = dev_get_priv(dev); + u16 bit = offset%16; + u16 reg = (offset/8)&0xFFFE; + u16 val; + + debug("%s\n", __func__); + + if (priv->signature == 0) { + puts("FPGA not programmed yet\n"); + return -1; + } + + /* + debug("offset is %d\n", offset); + debug("reg is %d\n", reg); + debug("Read from %p\n", priv->regs + reg); + */ + + val = readw(priv->regs + reg); + val &= ~(1 << bit); + val |= ((value > 0 ? 1 : 0) << bit); + + // debug("Write 0x%p to reg 0x%x\n", priv->regs + reg, val); + + return writew(val, priv->regs + reg); +} + +static int nbhw_fpga_direction_input(struct udevice *dev, unsigned offset) +{ + debug("%s\n", __func__); + return 0; +} + +int nbhw_fpga_direction_output (struct udevice *dev, unsigned offset, int value) +{ + debug("%s\n", __func__); + + nbhw_fpga_set_value(dev, offset, value); + return 0; +} + +static const struct dm_gpio_ops nbhw_fpga_ops = { + .direction_input = nbhw_fpga_direction_input, + .direction_output = nbhw_fpga_direction_output, + .get_value = nbhw_fpga_get_value, + .set_value = nbhw_fpga_set_value, +}; + +static const struct udevice_id nbhw_fpga_ids[] = { + { .compatible = "nm,nbhw-fpga" }, + { } +}; + +U_BOOT_DRIVER(gpio_nbhw_fpga) = { + .name = "gpio_nbhw_fpga", + .id = UCLASS_GPIO, + .of_match = nbhw_fpga_ids, + .probe = nbhw_fpga_probe, + .bind = nbhw_fpga_bind, + .ops = &nbhw_fpga_ops, +}; + diff --git a/board/nm/common/nbhw_fpga_prog.c b/board/nm/common/nbhw_fpga_prog.c deleted file mode 100644 index b1ce66434f..0000000000 --- a/board/nm/common/nbhw_fpga_prog.c +++ /dev/null @@ -1,478 +0,0 @@ -/****************************************************************************** - * (c) COPYRIGHT 2015 by NetModule AG, Switzerland. All rights reserved. - * - * This program 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 program 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. - * - *****************************************************************************/ - -#include -#include -#include -#include -#include "config.h" - -#include "nbhw_bd.h" -#include "nbhw_fpga_prog.h" -#include "nbhw_gpio.h" -#include "nbhw_fileaccess.h" - -static fpga_prog_operation *_operation = NULL; - -struct nbhw_fpga_priv { - int signature; - struct gpio_desc *ss; - struct gpio_desc *sck; - struct gpio_desc *sdi; - struct gpio_desc *sdo; - struct mvebu_gpio_regs *regs; -}; - - -static inline void spi_write(struct nbhw_fpga_priv *priv, u8 data) -{ - int i; - u32 data_write = 0; - - dm_gpio_set_value(priv->sck, 1); - - for (i=0; i<8; i++) - { - data_write = (data & 0x80) ? 1 : 0; - /* Clear clk bit and put data on the line */ - dm_gpio_set_value(priv->sck, 0); - dm_gpio_set_value(priv->sdi, data_write); - /* Read data on rising edge */ - dm_gpio_set_value(priv->sck, 1); - data = data << 1; - } -} - -static int fpga_verify(void) -{ - /* Check, if the FPGA is working */ - char fpga_type[30]; - u16 signature = *((volatile u16*)NBHW_BASE_ADDRESS_FPGA); - u16 fpga_version = FPGA_REG(0x02); - u8 fpga_major = (fpga_version >> 8) & 0xFF; - u8 fpga_minor = (fpga_version >> 0) & 0xFF; - - if (signature == 0xa501) - { - strcpy(fpga_type, "XC3S50A-4VQ100I top layer"); - } else if (signature == 0xa502) { - strcpy(fpga_type, "XC3S200A-4VQ100I top layer"); - } else if (signature == 0xa511) { - strcpy(fpga_type, "XC3S50A-4FTG256I bottom layer"); - } else if (signature == 0xa512) { - strcpy(fpga_type, "XC3S200A-4FTG256I bottom layer"); - } else if (signature == 0x4004) { - strcpy(fpga_type, "ICE40HX4K-CB132 NBHW17"); - } else if (signature == 0x4184) { - strcpy(fpga_type, "ICE40HX4K-CB132 NBHW18"); - } else { - goto abort; - } - - printf(" Detected %s FPGA (Version: %d.%d)\n", fpga_type, fpga_major, fpga_minor); - return 1; - -abort: - printf(" No FPGA detected! (Signature:%x)\n", signature); - return 0; -} - -static int fpga_load_bitstream (struct nbhw_fpga_priv *priv, const u8* data, int num_bytes) -{ - int i; - - printf(" Loading FPGA bitstream from 0x%p, %d bytes\n", data, num_bytes); - printf(" Sending configuration bitstream...\n"); - - for ( i=0; icheck_bitstream_compatibility(FPGA_TYPE_LATTICE, 0xFFFFFFFF) != 0) { - return 0; - } - - /* TODO: implement file check (e.g. UserID in comment section */ - return 1; -} - -static int fpga_check_bitstream_xilinx(const u8* fpgadata, u8** pStartAddr, int* pSize) -{ - unsigned int length; - unsigned int codesize; - char buffer[80]; - const u8* dataptr; - unsigned int i; - u32 fpgaid; - const char *p; - - printf("Checking bitstream at 0x%p\n", fpgadata); - - *pSize = 0; - *pStartAddr = NULL; - - dataptr = fpgadata; - - /* skip the first bytes of the bitsteam, their meaning is unknown */ - length = (*dataptr << 8) + *(dataptr+1); - dataptr+=2; - dataptr+=length; - - /* get design name (identifier, length, string) */ - length = (*dataptr << 8) + *(dataptr+1); - dataptr+=2; - if (*dataptr++ != 0x61) { - printf("%s: Design name identifier not recognized in bitstream\n", - __FUNCTION__ ); - return 0; - } - - length = (*dataptr << 8) + *(dataptr+1); - dataptr+=2; - memset(buffer, 0, sizeof(buffer)); - for(i=0;i= '0') && (p[i] <= '9')) { - fpgaid |= (u32)(p[i]-'0'); - } else if ((p[i] >= 'A') && (p[i] <= 'F')) { - fpgaid |= (u32)(p[i]-'A'+10); - } else if ((p[i] >= 'a') && (p[i] <= 'f')) { - fpgaid |= (u32)(p[i]-'a'+10); - } else { - printf("%s: User identifier not valid in bitstream\n", - __FUNCTION__ ); - return 0; - } - } - if (_operation->check_bitstream_compatibility(FPGA_TYPE_XILINX, fpgaid) != 0) { - printf("%s: User identifier not matched in bitstream\n", - __FUNCTION__ ); - return 0; - } - } else { - printf("%s: User identifier not found in bitstream\n", - __FUNCTION__ ); - return 0; - } - - /* get part number (identifier, length, string) */ - if (*dataptr++ != 0x62) { - printf("%s: Part number identifier not recognized in bitstream\n", - __FUNCTION__ ); - return 0; - } - - length = (*dataptr << 8) + *(dataptr+1); - dataptr+=2; - memset(buffer, 0, sizeof(buffer)); - for(i=0;iss, GPIOD_IS_OUT) != 0) { - printf("Could not request spi-gpio ss\n"); - return -1; - } - - if (gpio_request_by_name(dev, "spi-sck", 0, priv->sck, GPIOD_IS_OUT) != 0) { - printf("Could not request spi-gpio sck\n"); - return -1; - } - - if (gpio_request_by_name(dev, "spi-sdi", 0, priv->sdi, GPIOD_IS_OUT) != 0) { - printf("Could not request spi-gpio sdi\n"); - return -1; - } - - if (gpio_request_by_name(dev, "spi-sdo", 0, priv->sdo, GPIOD_IS_IN) != 0) { - printf("Could not request spi-gpio sdo\n"); - return -1; - } - - priv->regs = (struct mvebu_gpio_regs *)dev_get_addr(dev); - - return fpga_program(priv); -} - -//static const struct dm_gpio_ops nbhw_fpga_ops = { -// .direction_input = nbhw_fpga_direction_input, -// .direction_output = nbhw_fpga_direction_output, -// .get_function = nbhw_fpga_get_function, -// .get_value = nbhw_fpga_get_value, -// .set_value = nbhw_fpga_set_value, -//}; -// -//static const struct udevice_id nbhw_fpga_ids[] = { -// { .compatible = "nm,nbhw-fpga" }, -// { } -//}; -// -//U_BOOT_DRIVER(nbhw_fpga_serial) = { -// .name = "nbhw_fpga", -// .id = UCLASS_GPIO, -// .of_match = nbhw_fpga_ids, -// .probe = nbhw_fpga_probe, -// .ops = &nbhw_fpga_ops, -// .priv_auto_alloc_size = sizeof(struct nbhw_fpga_priv), -//}; -// diff --git a/board/nm/common/nbhw_init.c b/board/nm/common/nbhw_init.c index 8589d7634c..8d5a8619fa 100644 --- a/board/nm/common/nbhw_init.c +++ b/board/nm/common/nbhw_init.c @@ -33,7 +33,6 @@ static void set_mac(int interface, uint8_t macaddress[], size_t size) if (interface == 0) { /* Serial number consists of 1st MAC address */ setenv("ethaddr", macstring); - printf("Serial Number: %s\n", macstring); } /* Always set eth%daddr because newer u-boots expect it */ { @@ -42,7 +41,6 @@ static void set_mac(int interface, uint8_t macaddress[], size_t size) sprintf(ethaddr, "eth%daddr", interface); /* The other ethaddrs are set trough ethaddr1,2,3 etc. */ setenv(ethaddr, macstring); - printf("MAC%d: %s\n", interface, macstring); } } diff --git a/board/nm/nbhw17_v1/Makefile b/board/nm/nbhw17_v1/Makefile index d8f788a2d2..2be26d06d9 100644 --- a/board/nm/nbhw17_v1/Makefile +++ b/board/nm/nbhw17_v1/Makefile @@ -7,11 +7,17 @@ commonobj = ../common/bdparser.o \ ../common/nbhw_bd.o \ ../common/nbhw_env.o \ - ../common/nbhw_fpga_prog.o \ ../common/nbhw_init.o \ ../common/nbhw_fileaccess.o \ + ../common/nbhw_fpga_gpio.o \ ../common/nbhw_partitions.o ccflags-y := -I../common -obj-y := board.o $(commonobj) +ifndef CONFIG_SPL_BUILD +obj-y := board.o nbhw_gpio.o nbhw_fpga_config.o nbhw_pcie_fixup.o $(commonobj) +else +obj-y := board.o nbhw_gpio.o ../common/nbhw_bd.o ../common/nbhw_partitions.o +endif + + diff --git a/board/nm/nbhw17_v1/board.c b/board/nm/nbhw17_v1/board.c index edd2f946ff..89b344106a 100644 --- a/board/nm/nbhw17_v1/board.c +++ b/board/nm/nbhw17_v1/board.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: GPL-2.0+ */ - +#define DEBUG #include #include #include @@ -13,9 +13,13 @@ #include #include #include +#include +#include #include +#include "nbhw_gpio.h" + #include "../common/nbhw_init.h" #include "../common/nbhw_env.h" #include "../common/nbhw_bd.h" @@ -43,6 +47,8 @@ DECLARE_GLOBAL_DATA_PTR; #define PD_ADDRESS (0x0200) /* Product descriptor */ #define PARTITION_ADDRESS (0x0600) /* Partition Table */ +#define DEV_CS0_BASE 0xfd000000 + static struct serdes_map board_serdes_map[] = { { PEX0, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0 }, { SGMII1, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0 }, @@ -68,16 +74,16 @@ static struct hws_topology_map board_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_667, /* frequency */ - 7, 9, /* cas_l cas_wl */ - HWS_TEMP_HIGH} }, /* temperature */ + {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_667, /* frequency */ + 7, 9, /* cas_l cas_wl */ + HWS_TEMP_HIGH} }, /* temperature */ 5, /* Num Of Bus Per Interface*/ BUS_MASK_32BIT /* Busses mask */ }; @@ -112,32 +118,30 @@ int board_early_init_f(void) 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; + return MMCSD_MODE_EMMCBOOT; } void spl_board_init(void) { - int err; - struct mmc *mmcp; + int err; + struct mmc *mmcp; - err = mmc_initialize(NULL); - if (err) - return; + err = mmc_initialize(NULL); + if (err) + return; - puts("SPL: select partition\n"); + puts("SPL: select partition\n"); mmcp = find_mmc_device(0); - mmc_init(mmcp); - printf("Partition found: %p\n", mmcp); - /* select boot0 as bootpart */ - mmcp->part_config |= (1 << 3); - puts("Partition switched to boot0\n"); + mmc_init(mmcp); + printf("Partition found: %p\n", mmcp); + /* select boot0 as bootpart */ + mmcp->part_config |= (1 << 3); + puts("Partition switched to boot0\n"); } static BD_Context bdctx[3]; /* The descriptor context */ @@ -150,7 +154,7 @@ static int _bd_init(void) } if (bd_get_context(&bdctx[1], BD_EEPROM_ADDR, PD_ADDRESS) != 0) { - printf("%s() no valid pd found (legacy support)\n", __func__); + /* Ignore that, legacy boxes don't have a pd */ } if (bd_get_context(&bdctx[2], BD_EEPROM_ADDR, PARTITION_ADDRESS) != 0) { @@ -158,12 +162,42 @@ static int _bd_init(void) } bd_register_context_list(bdctx, ARRAY_SIZE(bdctx)); - return 0; + return 0; } static inline int __maybe_unused read_eeprom(void) { - return _bd_init(); + return _bd_init(); +} + +static void set_gpios(void) +{ + init_gpios(); +} + +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 = getenv("add_version_bootargs"); + + /* Normaly add_version_bootargs should already be set (see board include file) */ + if (old_env != NULL) { + snprintf(new_env, sizeof(new_env), "%s %s", old_env, hw_versions); + } + else { + snprintf(new_env, sizeof(new_env), "setenv bootargs $bootargs %s\n", hw_versions); + } + + setenv("add_version_bootargs", new_env); } int board_init(void) @@ -171,21 +205,62 @@ int board_init(void) /* 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_mac_addresses(2); - find_and_set_active_partition(); - set_console(); + set_console(); - gpio_request(21, "RST_ETH_PHY_N"); - gpio_direction_output(21, 1); + set_gpios(); -#if 0 - /* Init I2C IO expanders */ - for (i = 0; i < ARRAY_SIZE(io_exp); i++) - i2c_write(io_exp[i].chip, io_exp[i].addr, 1, &io_exp[i].val, 1); -#endif + 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); +} + +int board_late_init(void) +{ + + gpio_request(21, "RST_ETH_PHY_N"); + gpio_direction_output(21, 0); + + find_and_set_active_partition(); + pass_hw_rev(); + + /* Todo: It seems that something with the network is wrong */ + run_command("run load_fpga", CMD_FLAG_ENV); + + return 0; +} + +int last_stage_init(void) +{ + set_mac_addresses(2); + + /* We want ethernet available much earlier than CONFIG_CMD_NET can + * guarantee it */ + gpio_set_value(21, 1); + + set_phy_fast_blink_mode(0); + set_phy_fast_blink_mode(1); return 0; } @@ -197,8 +272,5 @@ int checkboard(void) return 0; } -int board_eth_init(bd_t *bis) -{ - cpu_eth_init(bis); /* Built in controller(s) come first */ - return pci_eth_init(bis); -} + + diff --git a/board/nm/nbhw17_v1/nbhw_fpga_config.c b/board/nm/nbhw17_v1/nbhw_fpga_config.c index cafc6d4b28..bc4adbaa7d 100644 --- a/board/nm/nbhw17_v1/nbhw_fpga_config.c +++ b/board/nm/nbhw17_v1/nbhw_fpga_config.c @@ -1,9 +1,28 @@ +#define DEBUG #include -#include +#include +#include +#include +#include +#include +#include "../common/nbhw_bd.h" -#include "../nbhw_bd.h" -#include "nbhw18_fpga_regs.h" -#include "../nbhw_sim.h" +DECLARE_GLOBAL_DATA_PTR; + +struct gpio_desc leds[16]; +struct udevice *driver_dev; + +struct pcieslot { + struct gpio_desc reset; + struct gpio_desc power; + struct gpio_desc wdis_out; + struct gpio_desc wdis; +}; + +struct config_priv { + struct pcieslot pcieslots[4]; + u32 led_count; +} priv; typedef enum { TYPE_USB, @@ -11,7 +30,7 @@ typedef enum { TYPE_PCIE, } slot_type_t; -slot_type_t get_type(const int slot) +static slot_type_t get_pcie_slot_type(const int slot) { int module; char pdValue[200]; @@ -33,73 +52,306 @@ slot_type_t get_type(const int slot) return TYPE_USB; } -void configure_pcie_slots(void) +static int serdes_en_hack(struct gpio_desc *gpio) { - /* Make sure PCIe slots have been without power for at least 1.2s */ - FPGA_REG(PCIE_POWER) = 0x0000; /* Just to be sure, should have been disabled by reset already */ - udelay(1200000); /* 1.2 s */ + slot_type_t slot_type = get_pcie_slot_type(0); - /* Apply SATA power, enable internal MDIO, enable serdes switch, - * disable external ethernet, disable hold power on */ - FPGA_REG(OUTPUT1) = OUTPUT1_RST_WLAN_MOD_N_MASK; + /* Lucky for us pcie slot1 has some muxes, to workaround buggy Sierra Wireless Modules */ + if (slot_type == TYPE_USB) { + /* Buggy Sierra Wireless Modules don't like to have USB3 enabled + * because the TX of the USB3 Lane is attached to it's system + * reset which is the default (see dts) */ + printf("Slot1: wwan\n"); + } + else if (slot_type == TYPE_PCIE) { + dm_gpio_set_value(gpio, 1); + printf("Slot1: wlan\n"); + } + else { + /* If once we would use other buggy Sierra Wireless modules, where they have + * decided to use USB3 too, then we have to enable the SERDES, the reset signal + * was moved away from this pins again (bravo!!!) */ + printf("Slot1: wwan (usb3)\n"); + } - udelay(200000); /* 200 ms */ + return 0; - /* Apply power to all PCIe slots */ - FPGA_REG(PCIE_POWER) |= PCIE_POWER_PCIE1_PWR_MASK; - udelay(200000); /* 200 ms */ - FPGA_REG(PCIE_POWER) |= PCIE_POWER_PCIE2_PWR_MASK; - udelay(200000); /* 200 ms */ - FPGA_REG(PCIE_POWER) |= PCIE_POWER_PCIE3_PWR_MASK; - udelay(200000); /* 200 ms */ - - /* Set PCIe signal directions */ - /* Inputs: COEX1, COEX2, LED_WLAN, LED_WWAN, WAKE~ */ - /* Outputs: WDISABLE~=1 */ - /* PCIe Slot 1 */ - FPGA_REG(PCIE_1_SLOT_DIR1) = PCIE_1_SLOT_DIR1_WDISABLE_N_DIR_MASK; - FPGA_REG(PCIE_1_SLOT_CTRL1) = PCIE_1_SLOT_CTRL1_WDISABLE_N_MASK; - - /* PCIe Slot 2 */ - FPGA_REG(PCIE_2_SLOT_DIR1) = PCIE_1_SLOT_DIR1_WDISABLE_N_DIR_MASK; - FPGA_REG(PCIE_2_SLOT_CTRL1) = PCIE_1_SLOT_CTRL1_WDISABLE_N_MASK; - - /* PCIe Slot 3 */ - FPGA_REG(PCIE_3_SLOT_DIR1) = PCIE_1_SLOT_DIR1_WDISABLE_N_DIR_MASK; - FPGA_REG(PCIE_3_SLOT_CTRL1) = PCIE_1_SLOT_CTRL1_WDISABLE_N_MASK; - - /* Get all PCIe slots out of reset */ - FPGA_REG(PCIE_RESET) = 0x00; - udelay(12000); /* 12 ms */ - FPGA_REG(PCIE_RESET) = - PCIE_RESET_PCIE1_RST_N_MASK | - PCIE_RESET_PCIE2_RST_N_MASK | - PCIE_RESET_PCIE3_RST_N_MASK; } -int nbhw_fgpa_init(void) +struct pcie_slot_gpios { + struct gpio_desc reset; + struct gpio_desc power; + struct gpio_desc wdis_out; + struct gpio_desc wdis; +}; + +#define PCIE_SLOT_COUNT 8 +static struct pcie_slot_gpios pcie_slots[PCIE_SLOT_COUNT]; + +static int pcie_slot_count = 0; + +static int request_and_set_gpio_by_name(int node, const void *fdt, + const char *name, struct gpio_desc *desc) { - /* Disable all interrupts from FPGA and clear flags */ - FPGA_REG(INTMASK1) = 0xFFFF; - FPGA_REG(INTMASK2) = 0xFFFF; - /* Make sure all interrupts are received */ - udelay(10000); - FPGA_REG(INTACK1) = 0xFFFF; - FPGA_REG(INTACK2) = 0xFFFF; + int offset; + int default_value = 0; + debug("%s\n", __func__); - /* Enable green LED0, disable all other LEDs */ - FPGA_REG(LED) = LED_LED0_GREEN_MASK; + fdt_for_each_property_offset(offset, fdt, node) { + u32 gpio_array[4]; + int len; + const char *entry_name; - /* Enable SIM clocks */ - FPGA_REG(PCIE_SIM_CLOCK) = 0; + /* if it's not the gpio we want (we need to iterate to get node index */ + fdt_getprop_by_offset(fdt, offset, &entry_name, &len); + if (strcmp(entry_name, name)) { + continue; + } - configure_pcie_slots(); + /* Request the gpio described by the property */ + if (gpio_request_by_name_nodev(fdt, node, name, 0, desc, + GPIOD_IS_OUT)) + { + printf("Could not request gpio %s\n", name); + return -1; + } - configure_sim_slots(4); + /* Get the gpio array, to find out its default value (4 index) */ + if (fdtdec_get_int_array(fdt, node, name, + gpio_array, 4)) { + printf("Could not request gpio array %s\n", name); + return -1; - /* Enable SFP means set disable to zero */ - FPGA_REG(SFP_CONTROL) = 0; + } + default_value = gpio_array[3]; + debug("Set GPIO %s to %d\n", name, default_value); + dm_gpio_set_value(desc, default_value); + return 0; + } + + printf("GPIO %s not found\n", name); + return -1; +} + +static int add_pcie_slot(int node, const void *fdt) +{ + debug("%s\n", __func__); + request_and_set_gpio_by_name(node, fdt, "reset", + &pcie_slots[pcie_slot_count].reset); + + request_and_set_gpio_by_name(node, fdt, "power", + &pcie_slots[pcie_slot_count].power); + + request_and_set_gpio_by_name(node, fdt, "wdis-out", + &pcie_slots[pcie_slot_count].wdis_out); + + request_and_set_gpio_by_name(node, fdt, "wdis", + &pcie_slots[pcie_slot_count].wdis); + pcie_slot_count++; + return 0; +} + +static int configure_pcie_slots(void) +{ + int i; + udelay(1200000); /* 1.2 s */ + + for (i = 0; i < pcie_slot_count;i ++) { + dm_gpio_set_value(&pcie_slots[i].reset, 1); + } + + 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(1000); /* 1 ms */ + } + + /* 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 */ + } + + 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(1000); /* 1 ms */ + } + + udelay(12000); /* 12 ms */ + for (i = 0; i < pcie_slot_count;i ++) { + dm_gpio_set_value(&pcie_slots[i].reset, 0); + } 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; +} + +struct hack_list_entry { + const char* name; + int (*fn)(struct gpio_desc *gpio); +}; + +struct hack_list_entry hack_list[] = { + {"serdes-en", serdes_en_hack} +}; + +static int exec_hack_list_fn(const char *name, struct gpio_desc *gpio) +{ + int i; + for (i = 0; i < ARRAY_SIZE(hack_list); i++) { + if (strcmp(hack_list[i]. name, name) == 0) { + if (hack_list[i].fn(gpio)) { + printf("Hack for %s failed\n", name); + return -1; + } + return 0; + } + } + + /* Not part of hacklist */ + return 0; +} + +static int request_and_set_gpios(int node, const void *fdt, + struct gpio_desc *gpios, u32 max_gpios) +{ + int offset; + int i = 0; + int default_value = 0; + debug("%s\n", __func__); + + fdt_for_each_property_offset(offset, fdt, node) { + u32 gpio_array[4]; + int len; + const char *name; + + if (i >= max_gpios) { + printf("Too many gpio entries (max %d)\n", max_gpios); + break; + } + + /* Get property at offset */ + fdt_getprop_by_offset(fdt, offset, &name, &len); + if (name[0] == '#') { + continue; + } + + /* Request the gpio descriped by the property */ + if (gpio_request_by_name_nodev(fdt, node, 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 (fdtdec_get_int_array(fdt, node, 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); + + if (exec_hack_list_fn(name, &gpios[i])) { + return -1; + } + + i++; + } + + return i; +} + + +static int configure_misc(int node, const void *fdt) +{ + struct gpio_desc misc_gpios[16]; + int gpio_count; + debug("%s\n", __func__); + + gpio_count = request_and_set_gpios(node, fdt, + misc_gpios, ARRAY_SIZE(misc_gpios)); + if (gpio_count < 1) { + return -1; + } + + gpio_free_list_nodev(misc_gpios, gpio_count); + + return 0; +} + +int nbhw_fpga_configure(void) +{ + int subnode; + int node = dev_of_offset(driver_dev); + const void *fdt = gd->fdt_blob; + debug("%s\n", __func__); + + fdt_for_each_subnode(subnode, fdt, node) { + int len; + const char *name; + + name = fdt_get_name(fdt, subnode, &len); + + debug("Try to configure %s\n", name); + if (!strncmp("misc", name, 4)) { + configure_misc(subnode, fdt); + } + + if (!strncmp("pcieslot", name, 4)) { + add_pcie_slot(subnode, fdt); + } + + } + + 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,nbhw17-fpga-config" }, + { } +}; + +U_BOOT_DRIVER(gpio_nbhw_fpga_config) = { + .name = "nbhw17_fpga_config", + .id = UCLASS_ROOT, + .of_match = nbhw_fpga_config_ids, + .bind = nbhw_fpga_config_bind, +}; + diff --git a/board/nm/nbhw17_v1/nbhw_fpga_prog.c b/board/nm/nbhw17_v1/nbhw_fpga_prog.c index 74ef2a0e7e..112b727796 100644 --- a/board/nm/nbhw17_v1/nbhw_fpga_prog.c +++ b/board/nm/nbhw17_v1/nbhw_fpga_prog.c @@ -55,26 +55,26 @@ static void write_spi_data(MV_U8 data) static void put_in_prog_mode(void) { /* Set CS firt to 1 */ - mvGppValueSet(SPI_GROUP, SS_MPP , SS_MPP); + mvGppValueSet(SPI_GROUP, SS_MPP , SS_MPP); udelay(10); - /* Set SS to 0 and SCK to 1 */ - mvGppValueSet(SPI_GROUP, SS_MPP | SCK_MPP, SCK_MPP); - /* Put FPGA in reset */ - mvGppValueSet(FPGA_RESET_GROUP, FPGA_RESET, 1); + /* Set SS to 0 and SCK to 1 */ + mvGppValueSet(SPI_GROUP, SS_MPP | SCK_MPP, SCK_MPP); + /* Put FPGA in reset */ + mvGppValueSet(FPGA_RESET_GROUP, FPGA_RESET, 1); - /* Sleep at least 200ns according to lattice manual */ - udelay(1); + /* Sleep at least 200ns according to lattice manual */ + udelay(1); - /* Take FPGA out of reset */ - mvGppValueSet(FPGA_RESET_GROUP, FPGA_RESET, 0); - /* Wait for at least 800 us according to lattice manual */ - udelay(800); + /* Take FPGA out of reset */ + mvGppValueSet(FPGA_RESET_GROUP, FPGA_RESET, 0); + /* Wait for at least 800 us according to lattice manual */ + udelay(800); } static void pre_programming(void) { - debug("NBHW18 pre programming\n"); + debug("NBHW18 pre programming\n"); MV_U32 reg_data; mpp_group_4_init_value = readl(mvCtrlMppRegGet(4)); mpp_group_5_init_value = readl(mvCtrlMppRegGet(5)); @@ -90,19 +90,19 @@ static void pre_programming(void) /* Configure outputs (default input) 0=> output */ mvGppTypeSet(SPI_GROUP, (SS_MPP | SCK_MPP | SDI_MPP), 0); - debug("NBHW18 put in progmode\n"); - put_in_prog_mode(); + debug("NBHW18 put in progmode\n"); + put_in_prog_mode(); } static void post_programming(void) { int i; - if (in_fpga_cdone()) { - printf("Error: Fpga does not signalize done\n"); - } + if (in_fpga_cdone()) { + printf("Error: Fpga does not signalize done\n"); + } - debug ("NBHW18 post programming\n"); + debug ("NBHW18 post programming\n"); /* At least 49 SPI_SCK Cycles rising edge to rising edge */ for (i = 0; i < 100; i++) { write_spi_data(0); diff --git a/board/nm/nbhw17_v1/nbhw_gpio.c b/board/nm/nbhw17_v1/nbhw_gpio.c index e9afda802c..d06c10855d 100644 --- a/board/nm/nbhw17_v1/nbhw_gpio.c +++ b/board/nm/nbhw17_v1/nbhw_gpio.c @@ -1,8 +1,5 @@ -#include -#include "board/mv_ebu/common/common/mvCommon.h" -#include "board/mv_ebu/common/mv_hal/gpp/mvGpp.h" -#include "../nbhw_gpio.h" -#include "nbhw18_fpga_regs.h" +#include +#include #define SET_LOGIC(enable,group,bit) \ if (enable) \ @@ -10,33 +7,37 @@ if (enable) \ else \ mvGppValueSet(group, bit, 0); +#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); +// SET_LOGIC(enable, 1, BIT9); } void out_watchdog(int enable) { - SET_LOGIC(enable, 0, BIT19); +// SET_LOGIC(enable, 0, BIT19); } void out_fpga_logic_reset(int enable) { - SET_LOGIC(enable, 1, BIT12); +// SET_LOGIC(enable, 1, BIT12); } void out_ext_reset_en(int enable) { - SET_LOGIC(enable, 0, BIT7); +// SET_LOGIC(enable, 0, BIT7); } int in_reset_button(void) { - return mvGppValueGet(0, BIT14); + return gpio_get_value(GPIO_RESET_BUTTON); } -int in_fpga_cdone(void) -{ - return mvGppValueGet(0, BIT29); -} diff --git a/board/nm/nbhw17_v1/nbhw_gpio.h b/board/nm/nbhw17_v1/nbhw_gpio.h index 974bda4b39..b56ae91902 100644 --- a/board/nm/nbhw17_v1/nbhw_gpio.h +++ b/board/nm/nbhw17_v1/nbhw_gpio.h @@ -1,11 +1,14 @@ #ifndef NBHW18_GPIO_H #define NBHW18_GPIO_H -#include "../nbhw_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_reset_button(void); int in_fpga_cdone(void); #endif diff --git a/board/nm/nbhw17_v1/nbhw_init.c b/board/nm/nbhw17_v1/nbhw_init.c deleted file mode 100644 index 8f32a31918..0000000000 --- a/board/nm/nbhw17_v1/nbhw_init.c +++ /dev/null @@ -1,75 +0,0 @@ -/****************************************************************************** - * (c) COPYRIGHT 2015 by NetModule AG, Switzerland. All rights reserved. - * - * This program 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 program 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. - * - *****************************************************************************/ -/* #define DEBUG */ -#include - -#include "config.h" -#include "../nbhw_init.h" -#include "../nbhw_bd.h" - -#include "board/mv_ebu/a38x/armada_38x_family/boardEnv/mvBoardEnvLib.h" -#include "board/mv_ebu/common/mv_hal/gpp/mvGpp.h" - -unsigned int CONFIG_SYS_DUART_CHAN = 0; - -extern MV_STATUS mvEthPhyRegWrite(MV_U32 phyAddr, MV_U32 regOffs, MV_U16 data); - -static void set_phy_page(int phy_addr, int page) -{ - mvEthPhyRegWrite(phy_addr, 22, page); -} - -static void set_phy_fast_blink_mode(int phy_addr) -{ - set_phy_page(phy_addr, 3); - mvEthPhyRegWrite(phy_addr, 16, 0x1032); - mvEthPhyRegWrite(phy_addr, 17, 0x4405); - mvEthPhyRegWrite(phy_addr, 18, 0x4A08); - set_phy_page(phy_addr, 0); -} - -static void configure_phys(void) -{ - set_phy_fast_blink_mode(0); - set_phy_fast_blink_mode(1); -} - -int nbhw_init(void) -{ - - printf("NBHW18\n"); - - debug("Disable watchdog\n"); - out_watchdog(1); - - debug("Enable USB Hub\n"); - out_usb_power(1); - udelay(10000); - - debug("Load environment\n"); - env_relocate_spec(); - - nbhw_settings_init(); /* Parse the board descriptor */ - - set_mac_addresses(3); - - return 0; -} - -void nbhw_phy_init(void) -{ - debug("Configure phys\n"); - configure_phys(); -} diff --git a/board/nm/nbhw17_v1/nbhw_pcie_fixup.c b/board/nm/nbhw17_v1/nbhw_pcie_fixup.c new file mode 100644 index 0000000000..3f0a8bba23 --- /dev/null +++ b/board/nm/nbhw17_v1/nbhw_pcie_fixup.c @@ -0,0 +1,228 @@ +/****************************************************************************** + * (c) COPYRIGHT 2015 by NetModule AG, Switzerland. All rights reserved. + * + * This program 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 program 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. + * + *****************************************************************************/ +/* #define DEBUG */ +#include +#include +#include +#include + +#include "config.h" +#include "../common/nbhw_bd.h" + +static void pcie_fixup_modify(u32 reg, u32 val, u32 mask) +{ + u32 regval; + regval = readl(reg); + regval &= ~mask; + regval |= (val & mask); + writel(regval, reg); +} + +/* We have a problem with the hardware during the detection phase this hack + * reduces the detection timeout from 4ns to 0ns so a minmal impulse will + * already trigger a detection. This is necessary to work with WLE600 modules. */ +static void pcie_fixup(void) +{ +/* SERDES0 PCIE0 = SLOT1 */ +#define PCIE0_USB3_CONTROL_REG 0xF10A0120 +/* SERDES4 PCIE2 = SLOT0 */ +#define PCIE2_USB3_CONTROL_REG 0xF10A2120 +#define PCIE_USB3_CONTROL_TIMING_MASK 0xC0 +#define PCIE_USB3_CONTROL_TIMING_VALUE 0x00 + + pcie_fixup_modify(PCIE0_USB3_CONTROL_REG, PCIE_USB3_CONTROL_TIMING_VALUE, PCIE_USB3_CONTROL_TIMING_MASK); + pcie_fixup_modify(PCIE2_USB3_CONTROL_REG, PCIE_USB3_CONTROL_TIMING_VALUE, PCIE_USB3_CONTROL_TIMING_MASK); +} + +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; +} + + +/* PCIE0 is on slot 1 (sw)*/ +#define PCIE0_STATUS_REG 0xF1081A04 +/* PCIE2 is on slot 0 (sw)*/ +#define PCIE2_STATUS_REG 0xF1045A04 + +#define PCIE_DL_DOWN_MASK 0x01 + +static int has_pcie_link_on_slot(int slot) +{ + /* If there is no module populated we say we have link (because we don't care) */ + switch (slot) { + case 0: + if (readw(PCIE2_STATUS_REG) & PCIE_DL_DOWN_MASK) + return 0; + break; + case 1: + if (readw(PCIE0_STATUS_REG) & PCIE_DL_DOWN_MASK) + return 0; + break; + default: + printf("Slot %d does not support PCIE\n", slot); + } + + return 1; +} + +static int check_pcie_slot_status(int slot){ + int ret = 1; + /* If WLAN on slot we need to check if we have link */ + if (has_slot_wlan(slot)) { + ret = has_pcie_link_on_slot(slot); + } + + return ret; +} + +/* The reset counter is at 256 MB, make sure it is not overlapping the address of the reset-reason mechanim, + * which is located at 1GB - 512kB. The reset reason counter is necessary to not try to reset + * the system more than 3 times */ +#define RESET_COUNTER_ADDRESS ((int *)0x10000000) +#define RESET_COUNTER_MD5 (RESET_COUNTER_ADDRESS + 4) +int get_reset_counter(void) +{ + volatile int *reset_counter = RESET_COUNTER_ADDRESS; + unsigned char reset_counter_checksum[16]; + + debug("reset_counter before inc: %d\n", *reset_counter); + + md5((unsigned char*) reset_counter, 4, reset_counter_checksum); + debug("md5 before inc: 0x%08X\n", *(unsigned int*)reset_counter_checksum); + /* Invalid checksum means it's the first boot. In this case we should see the counter + * as zero */ + if (memcmp(reset_counter_checksum, RESET_COUNTER_MD5, 16) != 0) { + *reset_counter = 0; + } + + return *reset_counter; +} + +int inc_reset_counter(void) +{ + volatile int *reset_counter = RESET_COUNTER_ADDRESS; + unsigned char reset_counter_checksum[16]; + + (*reset_counter)++; + debug("reset_counter after inc: %d\n", *reset_counter); + md5((unsigned char*) reset_counter, 4, reset_counter_checksum); + debug("md5 after inc: 0x%08X\n", *(unsigned int*)reset_counter_checksum); + memcpy(RESET_COUNTER_MD5, reset_counter_checksum, 16); + + return *reset_counter; + +} + +int reset_reset_counter(void) +{ + volatile int *reset_counter = RESET_COUNTER_ADDRESS; + + /* We don't need to do anything with the checksum, because invalid checksum = 0 */ + (*reset_counter) = 0; + + return *reset_counter; + +} + +static int is_module_check_abort(void) { + char c; + /* Check for abort */ + if (tstc()) { + c = getc(); + if (c == 'a') { + return 1; + } + } + + return 0; +} + +/* Check if pcie link is detected for wlan modules, some WLE600 modules have + * even with the pcie_fixup patch a problem that they don't appear during the first + * boot */ +static int do_wlan_fixup(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int i; +#define MAX_RESET_COUNT 6 + int reset_counter = get_reset_counter(); + int ret; + + pcie_fixup(); + + /* If we do a reboot it can happen that reset_counter is still 3, in this case + * we need to restart the counter */ + if (reset_counter >= MAX_RESET_COUNT) { + reset_counter = reset_reset_counter(); + } + + puts("Checking PCIe WLAN modules (abort with a)\n"); + + /* Try it for at least one second */ + for (i = 0; i < 100; i++) { + ret = 3; + if (check_pcie_slot_status(0)) ret &= ~1; + + if (check_pcie_slot_status(1)) ret &= ~2; + + if (is_module_check_abort()) { + puts("Abort WLAN module check\n"); + ret = 0; + } + + if (ret == 0) break; + + udelay(10000); + } + + /* One module that should have link does not have link */ + if (ret) { + reset_counter = inc_reset_counter(); + if (reset_counter >= MAX_RESET_COUNT) { + printf("WLAN Modules missing but reset counter reached %d, continue\n", reset_counter); + return 0; + } + printf ("Not all WLAN Modules from the bd came up (ret=0x%08X), reset (try %d of %d)\n", ret, reset_counter, MAX_RESET_COUNT); + printf ("Wait with reset for %ds\n", reset_counter * 10); + udelay(10000000 * reset_counter); + do_reset(NULL, 0, 0, NULL); + } + + /* Reset the counter in case of success */ + reset_reset_counter(); + + return 0; +} + +U_BOOT_CMD( + nbhw_wlan_fixup, 1, 1, do_wlan_fixup, + "NBHW WLAN fixup for some Wifi modules", + "Checks if WLAN modules have been detected correctly, or resets\n" +); + diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 9ab9df4ce7..4d48b1c9b2 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -3,7 +3,6 @@ * * SPDX-License-Identifier: GPL-2.0+ */ - #include #include #include diff --git a/include/configs/armada-385-nbhw17-v1.h b/include/configs/armada-385-nbhw17-v1.h index d35a476bac..b8bdac6dc9 100644 --- a/include/configs/armada-385-nbhw17-v1.h +++ b/include/configs/armada-385-nbhw17-v1.h @@ -76,18 +76,18 @@ "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 console=ttyS1,115200 rootwait loglevel=4\0" \ + "eth1addr=00:11:22:33:44:55\0" \ + "eth2addr=00:11:22:33:44:56\0" \ + "ethact=ethernet@30000\0" \ + "add_sd_bootargs=setenv bootargs $bootargs root=/dev/mmcblk0p$root_part rootfstype=ext4 console=ttyS1,115200 rootwait\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 echo Copying Linux from SD to RAM...; "\ + "sdboot=if mmc dev 0; then echo Load FPGA...; 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; " \ @@ -106,6 +106,7 @@ "autoload=false\0" \ "tftp_recovery=tftpboot $kernel_addr recovery-image; tftpboot $fdt_addr recovery-dtb; setenv bootargs rdinit=/etc/preinit console=ttyO1,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 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 @@ -162,4 +163,16 @@ */ #include "mv-common.h" +/* + * NBHW needs md5 support + */ +#define CONFIG_MD5 + +/* + * We need some functions to be called after environment setup + */ +#define CONFIG_BOARD_LATE_INIT + +#define CONFIG_LAST_STAGE_INIT + #endif /* _CONFIG_DB_88F6820_GP_H */ diff --git a/net/eth-uclass.c b/net/eth-uclass.c index c3cc3152a2..ac0f27c04e 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -5,7 +5,7 @@ * * SPDX-License-Identifier: GPL-2.0+ */ - +#define DEBUG #include #include #include @@ -179,22 +179,33 @@ int eth_get_dev_index(void) return -1; } + +#define PR_DEBUG debug("%s:%d\n", __FILE__, __LINE__); + static int eth_write_hwaddr(struct udevice *dev) { struct eth_pdata *pdata = dev->platdata; int ret = 0; + PR_DEBUG if (!dev || !device_active(dev)) return -EINVAL; + PR_DEBUG + + debug("%p: %d\n", eth_get_ops(dev)->write_hwaddr,eth_mac_skip(dev->seq) ); /* seq is valid since the device is active */ if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) { + PR_DEBUG if (!is_valid_ethaddr(pdata->enetaddr)) { printf("\nError: %s address %pM illegal value\n", dev->name, pdata->enetaddr); return -EINVAL; } + debug("%s set %x:%x\n", dev->name, pdata->enetaddr[0], pdata->enetaddr[1] ); + + PR_DEBUG /* * Drivers are allowed to decide not to implement this at * run-time. E.g. Some devices may use it and some may not. @@ -205,6 +216,7 @@ static int eth_write_hwaddr(struct udevice *dev) if (ret) printf("\nWarning: %s failed to set MAC address\n", dev->name); + PR_DEBUG } return ret; @@ -246,6 +258,7 @@ int eth_init(void) struct udevice *old_current; int ret = -ENODEV; + PR_DEBUG /* * When 'ethrotate' variable is set to 'no' and 'ethact' variable * is already set to an ethernet device, we should stick to 'ethact'. @@ -258,6 +271,7 @@ int eth_init(void) } } + PR_DEBUG if (!current) { current = eth_get_dev(); if (!current) { @@ -266,9 +280,11 @@ int eth_init(void) } } + PR_DEBUG old_current = current; do { if (current) { + PR_DEBUG debug("Trying %s\n", current->name); if (device_active(current)) { @@ -289,6 +305,7 @@ int eth_init(void) debug("PROBE FAIL\n"); } + PR_DEBUG /* * If ethrotate is enabled, this will change "current", * otherwise we will drop out of this while loop immediately @@ -296,6 +313,7 @@ int eth_init(void) eth_try_another(0); /* This will ensure the new "current" attempted to probe */ current = eth_get_dev(); + PR_DEBUG } while (old_current != current); return ret; @@ -387,6 +405,8 @@ int eth_initialize(void) int num_devices = 0; struct udevice *dev; + debug("%s\n", __func__); + eth_common_init(); /* @@ -417,7 +437,7 @@ int eth_initialize(void) if (num_devices) printf(", "); - printf("eth%d: %s", dev->seq, dev->name); + printf("%s", dev->name); if (ethprime && dev == prime_dev) printf(" [PRIME]"); diff --git a/net/eth_common.c b/net/eth_common.c index 0c2e584b61..e9d3c66741 100644 --- a/net/eth_common.c +++ b/net/eth_common.c @@ -26,16 +26,7 @@ void eth_parse_enetaddr(const char *addr, uchar *enetaddr) int eth_getenv_enetaddr(const char *name, uchar *enetaddr) { - printf("eth: %s\n", name); eth_parse_enetaddr(getenv(name), enetaddr); - printf("enetaddr: %x:%x:%x:%x:%x:%x\n", - enetaddr[0], - enetaddr[1], - enetaddr[2], - enetaddr[3], - enetaddr[4], - enetaddr[5]); - printf("is valid: %d\n", is_valid_ethaddr(enetaddr)); return is_valid_ethaddr(enetaddr); }