nbhw17: add support for fpga loading

This commit is contained in:
Stefan Eichenberger 2017-11-17 13:58:30 +01:00
parent 51120348fb
commit c2035d6033
20 changed files with 1583 additions and 738 deletions

View File

@ -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 = <MBUS_ID(0x01, 0x3e) 0 0x20000>; /* 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 */
// };
};
&eth0 {

View File

@ -17,20 +17,15 @@
model = "NetModule Router NBHW17 with Armada A385 (NB2800)";
};
&eth0 {
status = "okay";
};
// SFP-Port
&eth1 {
status = "okay";
fixed-link {
speed = <1000>;
full-duplex;
};
};
&eth2 {
status = "okay";
};
&gpiofpga {
status = "okay";
};

View File

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

View File

@ -4,6 +4,12 @@
#include "bdparser.h" /* tlv parser */
#include <linux/types.h>
#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

View File

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

View File

@ -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 <common.h>
#include <dm.h>
#include <dm/device.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <errno.h>
#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; i<num_bytes; i++ )
{
spi_write(priv, *(data++));
}
debug("Configuration sent\n");
if (dm_gpio_get_value(&priv->cdone)) {
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;i<length && i<(sizeof(buffer)-1);i++)
buffer[i] = *dataptr++;
printf(" design filename = \"%s\"\n", buffer);
/* verify fpga identifier */
if (priv->fpga_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;i<length && i<(sizeof(buffer)-1);i++)
buffer[i] = *dataptr++;
printf(" part number = \"%s\"\n", buffer);
/* get date (identifier, length, string) */
if (*dataptr++ != 0x63) {
printf("%s: Date identifier not recognized in bitstream\n",
__FUNCTION__);
return -1;
}
length = (*dataptr << 8) + *(dataptr+1);
dataptr+=2;
memset(buffer, 0, sizeof(buffer));
for(i=0;i<length && i<(sizeof(buffer)-1);i++)
buffer[i] = *dataptr++;
printf(" date = \"%s\"\n", buffer);
/* get time (identifier, length, string) */
if (*dataptr++ != 0x64) {
printf("%s: Time identifier not recognized in bitstream\n",__FUNCTION__);
return -1;
}
length = (*dataptr << 8) + *(dataptr+1);
dataptr+=2;
for(i=0;i<length;i++)
buffer[i] = *dataptr++;
printf(" time = \"%s\"\n", buffer);
/* get fpga data length (identifier, length) */
if (*dataptr++ != 0x65) {
printf("%s: Data length identifier not recognized in bitstream\n",
__FUNCTION__);
return -1;
}
codesize = ((unsigned int) *(dataptr+0) << 24) +
((unsigned int) *(dataptr+1) << 16) +
((unsigned int) *(dataptr+2) << 8) +
((unsigned int) *(dataptr+3) << 0);
dataptr+=4;
printf(" bytes in bitstream = %d\n", codesize);
printf(" headersize = %d\n", (u32)dataptr - (u32)fpgadata);
*pStartAddr = (u8*)dataptr;
*pSize = codesize;
return 0;
}
static int fpga_check_bitstream(const struct nbhw_fpga_priv *priv, const u8* fpgadata, u8** pStartAddr, int* pSize)
{
debug("check bitstream %d, %0x, %0x\n", *pSize, fpgadata[0],
fpgadata[1]);
/* Lattice header starts with 0xFF00 followed by comment */
if (fpgadata[0] == 0xFF && fpgadata[1] == 0x00) {
return fpga_check_bitstream_lattice(priv, fpgadata, pStartAddr, pSize);
}
/* Xilinx header starts with 0x00 0x09 which means header with 0x09 length */
else if(fpgadata[0] == 0x00 && fpgadata[1] == 0x09) {
return fpga_check_bitstream_xilinx(priv, fpgadata, pStartAddr, pSize);
}
printf("Unknown bitstream file format (not Xilinx nor Lattice)");
return -1;
}
static int fpga_boot_buffer(const struct nbhw_fpga_priv *priv, const u8* data, int num_bytes)
{
int res;
u8* raw_bitstream;
int raw_num_bytes;
printf("Checking FPGA bitstream...\n");
raw_num_bytes = num_bytes;
if (fpga_check_bitstream(priv, data, &raw_bitstream, &raw_num_bytes)) {
printf("Not a valid FPGA image at 0x%p\n", data);
goto abort;
}
/* Write bit stream */
res = fpga_load_bitstream(priv, raw_bitstream, raw_num_bytes);
if (!res) {
goto abort;
}
clean_up_after_programming(priv);
return 1;
abort:
printf(" FPGA programming failed\n");
return 0;
}
static int abort_fpga_boot (void)
{
int c, i;
int count = 0;
/* check for 3 stop keystrokes */
for (i = 0; i < 5; i++) {
if (tstc()) {
c = getc();
if (c == 'f') {
if (++count == 3) {
return 1;
}
} else {
return 0;
}
} else {
return 0;
}
udelay(200);
}
return 0;
}
static void setup_device_bus(void)
{
/* TODO: Use devicetree for this */
#define MV_DEV_BUS_REGS_OFFSET (0xF1010400)
/* Setup the device bus according to the FPGA implementation and
* for the polling SPI driver */
u32 val;
/* TODO: Implement a proper read write back function */
debug("%s\n", __func__);
/* Device Bus Control Interface Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0xC0);
debug("Device Bus Control Interface Regiseter (0x104C0): 0x%08X\n", val);
writel(0x5FFFF, MV_DEV_BUS_REGS_OFFSET + 0xC0);
/* Device Bus Synchronous Control Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0xC8);
debug("Device Bus Synchronous Control Register (0x104C8): 0x%08X\n", val);
writel(0x00004204, MV_DEV_BUS_REGS_OFFSET + 0xC8);
/* Device Bus Misc Timing Parameters Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0xD8);
debug("Device Bus Misc Timing Parameters Register (0x104D8): 0x%08X\n", val);
writel(0xFF80020, MV_DEV_BUS_REGS_OFFSET + 0xD8);
/* DEV_CS0 Read Parameters Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0x08);
debug("DEV_CS0 Read Parameters Register(0x10408): 0x%08X\n", val);
writel(0x441884, MV_DEV_BUS_REGS_OFFSET + 0x08);
/* DEV_CS0 Write Parameters Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0x0C);
debug("DEV_CS0 Write Parameters Register(0x1040C): 0x%08X\n", val);
writel(0x1020208, MV_DEV_BUS_REGS_OFFSET + 0x0C);
/* DEV_CS1 Read Parameters Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0x10);
debug("DEV_CS1 Read Parameters Register (0x10410): 0x%08X\n", val);
writel(0x003E07C0, MV_DEV_BUS_REGS_OFFSET + 0x10);
/* DEV_CS1 Write Parameters Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0x14);
debug("DEV_CS1 Write Parameters Register (0x10414): 0x%08X\n", val);
writel(0x00010114, MV_DEV_BUS_REGS_OFFSET + 0x14);
}
static int request_gpios(struct udevice *dev)
{
struct nbhw_fpga_priv *priv = dev_get_priv(dev);
debug("%s\n", __func__);
if (gpio_request_by_name(dev, "spi-ss", 0, &priv->ss, 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,
};

View File

@ -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 <common.h>
#include <dm/device.h>
#include <asm-generic/gpio.h>
#include <asm/io.h>
#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; i<num_bytes; i++ )
{
spi_write(priv, *(data++));
}
/* Send some extra clocks for startup */
for ( i=0; i<100; i++)
{
spi_write(priv, 0);
}
return 1;
}
static int fpga_check_bitstream_lattice(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 (_operation->check_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<length && i<(sizeof(buffer)-1);i++)
buffer[i] = *dataptr++;
printf(" design filename = \"%s\"\n", buffer);
/* verify fpga identifier */
if (bd_get_fpgainfo() == 0xFFFFFFFF) {
printf("%s: Fpga info not defined in bd\n",
__FUNCTION__ );
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 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;i<length && i<(sizeof(buffer)-1);i++)
buffer[i] = *dataptr++;
printf(" part number = \"%s\"\n", buffer);
/* get date (identifier, length, string) */
if (*dataptr++ != 0x63) {
printf("%s: Date 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<length && i<(sizeof(buffer)-1);i++)
buffer[i] = *dataptr++;
printf(" date = \"%s\"\n", buffer);
/* get time (identifier, length, string) */
if (*dataptr++ != 0x64) {
printf("%s: Time identifier not recognized in bitstream\n",__FUNCTION__);
return 0;
}
length = (*dataptr << 8) + *(dataptr+1);
dataptr+=2;
for(i=0;i<length;i++)
buffer[i] = *dataptr++;
printf(" time = \"%s\"\n", buffer);
/* get fpga data length (identifier, length) */
if (*dataptr++ != 0x65) {
printf("%s: Data length identifier not recognized in bitstream\n",
__FUNCTION__);
return 0;
}
codesize = ((unsigned int) *(dataptr+0) << 24) +
((unsigned int) *(dataptr+1) << 16) +
((unsigned int) *(dataptr+2) << 8) +
((unsigned int) *(dataptr+3) << 0);
dataptr+=4;
printf(" bytes in bitstream = %d\n", codesize);
printf(" headersize = %d\n", (u32)dataptr - (u32)fpgadata);
*pStartAddr = (u8*)dataptr;
*pSize = codesize;
return 1;
}
static int fpga_check_bitstream(const u8* fpgadata, u8** pStartAddr, int* pSize)
{
/* Lattice header starts with 0xFF00 followed by comment */
if (fpgadata[0] == 0xFF && fpgadata[1] == 0x00) {
return fpga_check_bitstream_lattice(fpgadata, pStartAddr, pSize);
}
/* Xilinx header starts with 0x00 0x09 which means header with 0x09 length */
else if(fpgadata[0] == 0x00 && fpgadata[1] == 0x09) {
return fpga_check_bitstream_xilinx(fpgadata, pStartAddr, pSize);
}
printf("Unknown bitstream file format (not Xilinx nor Lattice)");
return 0;
}
static int fpga_boot_buffer(struct nbhw_fpga_priv *priv, const u8* data, int num_bytes)
{
int res;
u8* raw_bitstream;
int raw_num_bytes;
printf("Checking FPGA bitstream...\n");
raw_num_bytes = num_bytes;
if (!fpga_check_bitstream(data, &raw_bitstream, &raw_num_bytes))
{
printf("Not a valid FPGA image at 0x%p\n", data);
goto abort;
}
/* Write bit stream */
res = fpga_load_bitstream(priv, raw_bitstream, raw_num_bytes );
if (!res)
{
goto abort;
}
/* Verify, if FPGA is loaded successfully */
res = fpga_verify();
if (!res)
{
goto abort;
}
printf(" FPGA programming done\n");
return 1;
abort:
printf(" FPGA programming failed\n");
return 0;
}
static int abort_fpga_boot (void)
{
int c, i;
int count = 0;
/* check for 3 stop keystrokes */
for (i = 0; i < 5; i++) {
if (tstc()) {
c = getc();
if (c == 'f') {
if (++count == 3) {
return 1;
}
} else {
return 0;
}
} else {
return 0;
}
udelay(200);
}
return 0;
}
static void setup_device_bus(void)
{
/* TODO: Use devicetree for this */
#define MV_DEV_BUS_REGS_OFFSET (0xF1010400)
/* Setup the device bus according to the FPGA implementation and
* for the polling SPI driver */
u32 val;
/* TODO: Implement a porper read write back function */
/* Device Bus Control Interface Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0xC0);
debug("Device Bus Control Interface Regiseter (0x104C0): 0x%08X\n", val);
writel(0x5FFFF, MV_DEV_BUS_REGS_OFFSET + 0xC0);
/* Device Bus Synchronous Control Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0xC8);
debug("Device Bus Synchronous Control Register (0x104C8): 0x%08X\n", val);
writel(0x00004204, MV_DEV_BUS_REGS_OFFSET + 0xC8);
/* Device Bus Misc Timing Parameters Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0xD8);
debug("Device Bus Misc Timing Parameters Register (0x104D8): 0x%08X\n", val);
writel(0xFF80020, MV_DEV_BUS_REGS_OFFSET + 0xD8);
/* DEV_CS0 Read Parameters Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0x08);
debug("DEV_CS0 Read Parameters Register(0x10408): 0x%08X\n", val);
writel(0x441884, MV_DEV_BUS_REGS_OFFSET + 0x08);
/* DEV_CS0 Write Parameters Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0x0C);
debug("DEV_CS0 Write Parameters Register(0x1040C): 0x%08X\n", val);
writel(0x1020208, MV_DEV_BUS_REGS_OFFSET + 0x0C);
/* DEV_CS1 Read Parameters Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0x10);
debug("DEV_CS1 Read Parameters Register (0x10410): 0x%08X\n", val);
writel(0x003E07C0, MV_DEV_BUS_REGS_OFFSET + 0x10);
/* DEV_CS1 Write Parameters Register */
val = readl(MV_DEV_BUS_REGS_OFFSET + 0x14);
debug("DEV_CS1 Write Parameters Register (0x10414): 0x%08X\n", val);
writel(0x00010114, MV_DEV_BUS_REGS_OFFSET + 0x14);
}
int fpga_program(struct nbhw_fpga_priv *priv)
{
const char *load_addr_str;
unsigned long load_addr;
int len_read;
char boot_part[8];
if (abort_fpga_boot()) {
printf("Aborted FPGA boot\n");
udelay(1000000); /* 1s */
return -1;
}
load_addr_str = getenv("loadaddr");
if (load_addr_str != NULL)
load_addr = simple_strtoul(load_addr_str, NULL, 16);
else
load_addr = CONFIG_SYS_LOAD_ADDR;
/* Get boot partiton based on active boot partition set during settings_init() */
snprintf(boot_part, sizeof(boot_part), "0:%s", getenv("root_part"));
if (fs_set_blk_dev("mmc", boot_part, FS_TYPE_EXT)) {
printf ("Can not select mmc%s for FPGA logic.\n", boot_part);
return -2;
}
len_read = read_file("/logic/LG00000000", (char*)load_addr, 0x01000000);
printf("FPGA logic file read successfully (%d Bytes)\n", len_read);
/* NBHW_BASE_ADDRESS_FPGA points to base of FPGA registers */
if (!fpga_boot_buffer(priv, (const u8*)load_addr, len_read)) {
printf ("Loading FPGA over SPI failed.\n");
return -3;
}
/* Make sure device bus works, becaus NBHW14 uses it to do SPI */
setup_device_bus();
return 0;
}
int nbhw_fpga_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct nbhw_fpga_priv *priv = dev_get_priv(dev);
if (gpio_request_by_name(dev, "spi-ss", 0, priv->ss, 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),
//};
//

View File

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

View File

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

View File

@ -3,7 +3,7 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
#define DEBUG
#include <common.h>
#include <i2c.h>
#include <miiphy.h>
@ -13,9 +13,13 @@
#include <asm/arch/soc.h>
#include <mmc.h>
#include <spl.h>
#include <linux/mbus.h>
#include <environment.h>
#include <asm/gpio.h>
#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 },
@ -112,8 +118,6 @@ 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;
}
@ -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) {
@ -166,26 +170,97 @@ static inline int __maybe_unused read_eeprom(void)
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)
{
/* 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();
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);
}

View File

@ -1,9 +1,28 @@
#define DEBUG
#include <common.h>
#include <nbhw.h>
#include <dm.h>
#include <dm/device.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <errno.h>
#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;
udelay(200000); /* 200 ms */
/* 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;
/* 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");
}
int nbhw_fgpa_init(void)
return 0;
}
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,
};

View File

@ -1,8 +1,5 @@
#include <nbhw.h>
#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 <common.h>
#include <asm/gpio.h>
#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);
}

View File

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

View File

@ -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 <environment.h>
#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();
}

View File

@ -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 <common.h>
#include <environment.h>
#include <asm/io.h>
#include <u-boot/md5.h>
#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"
);

View File

@ -3,7 +3,6 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <dt-bindings/gpio/gpio.h>

View File

@ -78,16 +78,16 @@
"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" \
"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 */

View File

@ -5,7 +5,7 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
#define DEBUG
#include <common.h>
#include <dm.h>
#include <environment.h>
@ -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]");

View File

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