u-boot/board/nm/nbhw18_v2/board.c

922 lines
22 KiB
C
Executable File

/*
* Copyright (C) 2015 Stefan Roese <sr@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#undef DEBUG
#include <common.h>
#include <i2c.h>
#include <miiphy.h>
#include <netdev.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include <mmc.h>
#include <spl.h>
#include <linux/mbus.h>
#include <environment.h>
#include <fdt_support.h>
#include <dm.h>
#include <wdt.h>
#include <asm/gpio.h>
#include "nbhw_gpio.h"
#include "../common/nbhw_init.h"
#include "../common/nbhw_env.h"
#include "../common/nbhw_bd.h"
#include "../drivers/ddr/marvell/a38x/ddr3_a38x_topology.h"
#include <../serdes/a38x/high_speed_env_spec.h>
#include "da9063.h"
DECLARE_GLOBAL_DATA_PTR;
/*
* Those values and defines are taken from the Marvell U-Boot version
* "u-boot-2013.01-2014_T3.0"
*/
#define GPP_OUT_ENA_LOW (~(BIT(6) | BIT(19) | BIT(29))) /* 1=Input, default input */
#define GPP_OUT_ENA_MID (~(BIT(12) | BIT(15)))
#define GPP_OUT_VAL_LOW (BIT(29))
#define GPP_OUT_VAL_MID (BIT(15))
#define GPP_POL_LOW 0x0
#define GPP_POL_MID 0x0
#define BD_EEPROM_ADDR (0x50) /* CPU BD EEPROM (8kByte) is at 50 (A0) */
#define BD_ADDRESS (0x0000) /* Board descriptor at beginning of EEPROM */
#define PD_ADDRESS (0x0200) /* Product descriptor */
#define PARTITION_ADDRESS (0x0600) /* Partition Table */
#define SERDES_CONFIG_ADDRESS (0x0800) /* SERDES config address */
#define DEV_CS0_BASE 0xfd000000
static struct serdes_map board_serdes_map[] = {
{ SGMII0, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0 },
{ USB3_HOST0, SERDES_SPEED_5_GBPS, SERDES_DEFAULT_MODE, 0, 0 },
{ SGMII1, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0 },
{ PEX3, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0 },
{ PEX2, SERDES_SPEED_5_GBPS, PEX_ROOT_COMPLEX_X1, 0, 0 },
{ SGMII2, SERDES_SPEED_1_25_GBPS, SERDES_DEFAULT_MODE, 0, 0 }
};
enum serdes_type get_serdes_type(int index)
{
if ((index>=0) && (index <ARRAY_SIZE(board_serdes_map)))
{
return board_serdes_map[index].serdes_type;
} else {
return LAST_SERDES_TYPE;
}
}
static BD_Context bdctx[3]; /* The descriptor context */
static int _bd_init(void)
{
if (bd_get_context(&bdctx[0], BD_EEPROM_ADDR, BD_ADDRESS) != 0) {
printf("%s() no valid bd found\n", __func__);
return -1;
}
if (bd_get_context(&bdctx[1], BD_EEPROM_ADDR, PD_ADDRESS) != 0) {
/* Ignore that, legacy boxes don't have a pd */
}
if (bd_get_context(&bdctx[2], BD_EEPROM_ADDR, PARTITION_ADDRESS) != 0) {
printf("%s() no valid partition table found\n", __func__);
}
bd_register_context_list(bdctx, ARRAY_SIZE(bdctx));
return 0;
}
typedef struct EEPROM_SERDES_CONFIG {
uint8_t magic[2];
uint8_t version;
uint8_t spare_0;
uint8_t serdes_cfg[6];
uint8_t spare1[2];
uint32_t crc32;
} EEPROM_SERDES_CONFIG;
static struct EEPROM_SERDES_CONFIG eeprom_serdes_config;
static void read_eeprom_serdes_config(void)
{
uint32_t crc;
if (i2c_read(BD_EEPROM_ADDR, SERDES_CONFIG_ADDRESS, 2, (uint8_t *)&eeprom_serdes_config, sizeof(eeprom_serdes_config))) {
goto fail;
}
crc = crc32(0, (uint8_t *)&eeprom_serdes_config, sizeof(eeprom_serdes_config)-4);
if ((eeprom_serdes_config.magic[0] != 0x83) ||
(eeprom_serdes_config.magic[1] != 0xfb) ||
(eeprom_serdes_config.version != 0x01) ||
(eeprom_serdes_config.crc32 != crc))
{
goto fail;
}
printf("Valid user serdes config found\n");
return;
fail:
memset(&eeprom_serdes_config, 0xff, sizeof(eeprom_serdes_config));
printf("No user serdes config found\n");
return;
}
static uint8_t get_eeprom_serdes_config(int serdes_index)
{
if ((serdes_index<0) || (serdes_index>=sizeof(eeprom_serdes_config.serdes_cfg))) return 0xff;
return eeprom_serdes_config.serdes_cfg[serdes_index];
}
static inline int __maybe_unused read_eeprom(void)
{
int res = _bd_init();
read_eeprom_serdes_config();
return res;
}
/* TODO: Create DA9063 Accessor Module */
#define CONFIG_PMIC_I2C_BUS 0
#define CONFIG_PMIC_I2C_ADDR 0x58 /* Pages 0 and 1, Pages 2 and 3 -> 0x59 */
#define PMIC_REG_GPIO_MODE0_7 0x1D /* Control register for GPIOs 0..7 */
#define PMIC_REG_GPIO_MODE8_15 0x1E /* Control register for GPIOs 8..15 */
#define PMIC_REG_BBAT_CONT 0xC5 /* Control register for backup battery */
static int da9063_i2c_bus = 0;
void da9063_init(int i2c_bus)
{
da9063_i2c_bus = i2c_bus;
}
int da9093_get_reg(int reg, u8* val)
{
int ret;
int old_bus;
u8 temp;
/* TODO: Check whether switching is required */
old_bus = i2c_get_bus_num();
i2c_set_bus_num(da9063_i2c_bus);
/* TODO: Use CONFIG_PMIC_I2C_ADDR+1 if reg > 0xFF */
*val = 0;
ret = i2c_read(CONFIG_PMIC_I2C_ADDR, reg, 1, &temp, 1);
if (ret == 0)
*val = temp;
i2c_set_bus_num(old_bus);
return ret;
}
int da9093_set_reg(int reg, u8 val)
{
int ret;
int old_bus;
/* TODO: Check whether switching is required */
old_bus = i2c_get_bus_num();
i2c_set_bus_num(da9063_i2c_bus);
/* TODO: Use CONFIG_PMIC_I2C_ADDR+1 if reg > 0xFF */
ret = i2c_write(CONFIG_PMIC_I2C_ADDR, reg, 1, &val, 1);
if (ret != 0)
puts("da9063 write error\n");
i2c_set_bus_num(old_bus);
return ret;
}
void da9063_set_gpio(unsigned bit, int state)
{
int pmic_reg;
int ret;
u8 bitmask;
u8 reg = 0x00;
if (bit <= 7) {
pmic_reg = PMIC_REG_GPIO_MODE0_7;
bitmask = 1U << (bit-0);
}
else {
pmic_reg = PMIC_REG_GPIO_MODE8_15;
bitmask = 1U << (bit-8);
}
/* printf("da9063_set_gpio %d 0x%04x\n", pmic_reg, bitmask); */
ret = da9093_get_reg(pmic_reg, &reg);
if (ret == 0) {
if (state) reg |= bitmask;
else reg &= ~bitmask;
(void)da9093_set_reg(pmic_reg, reg);
}
}
extern int console_init_f(void);
static int init_console(void)
{
int ret;
struct udevice *dev;
char *consoledev;
char buf[16] = "serial@12100";
debug("init console\n");
/* Make sure all devices are probed, it seems
* that this stuff is buggy in U-Boot */
ret = uclass_first_device(UCLASS_SERIAL, &dev);
if (ret) {
printf("Could not find any serial device\n");
return ret;
}
while (list_is_last(&dev->uclass_node, &dev->uclass->dev_head) == 0) {
uclass_next_device(&dev);
}
set_console();
/* Don't use external console, if we have no FPGA,
as it cannot work then. -> Switch to internal console then. */
if (readw(0xfd000000)!=0x012f) { /* Check for correct FPGA signature */
printf("FPGA not ready. Forcing console to ttyS0\n");
env_set("defaultconsole", "ttyS0");
env_set("consoledev", "ttyS0");
}
consoledev = env_get("consoledev");
if (strncmp(consoledev, "ttyS0", 5) == 0) {
strncpy(buf, "serial@12000", sizeof(buf));
}
env_set("stdin", buf);
env_set("stdout", buf);
env_set("stderr", buf);
return 0;
}
int hws_board_topology_load(struct serdes_map **serdes_map_array, u8 *count)
{
int i;
if (read_eeprom() < 0){
puts("Could not read board descriptor using default serdes config.\n");
board_serdes_map[0].serdes_speed = SERDES_SPEED_1_25_GBPS;
board_serdes_map[0].serdes_mode = SERDES_DEFAULT_MODE;
board_serdes_map[0].serdes_type = SGMII0;
board_serdes_map[1].serdes_speed = SERDES_SPEED_5_GBPS;
board_serdes_map[1].serdes_mode = PEX_ROOT_COMPLEX_X1;
board_serdes_map[1].serdes_type = USB3_HOST0;
board_serdes_map[2].serdes_speed = SERDES_SPEED_1_25_GBPS;
board_serdes_map[2].serdes_mode = SERDES_DEFAULT_MODE;
board_serdes_map[2].serdes_type = SGMII1;
board_serdes_map[3].serdes_speed = SERDES_SPEED_5_GBPS;
board_serdes_map[3].serdes_mode = PEX_ROOT_COMPLEX_X1;
board_serdes_map[3].serdes_type = PEX3;
board_serdes_map[4].serdes_speed = SERDES_SPEED_5_GBPS;
board_serdes_map[4].serdes_mode = PEX_ROOT_COMPLEX_X1;
board_serdes_map[4].serdes_type = PEX2;
board_serdes_map[5].serdes_speed = SERDES_SPEED_1_25_GBPS;
board_serdes_map[5].serdes_mode = SERDES_DEFAULT_MODE;
board_serdes_map[5].serdes_type = SGMII2;
} else {
for (i = 0; i < ARRAY_SIZE(board_serdes_map); i++) {
enum serdes_type type;
uint8_t user_config = get_eeprom_serdes_config(i);
if (user_config != 0xff) {
/* if we have a user config we use that one */
type = (enum serdes_type)user_config;
} else {
/* otherwise we use the config from the bd */
type = bd_get_serdes_type(i);
}
/* Do not touch serdes */
if (type < LAST_SERDES_TYPE) {
if ((type >= SGMII0) && (type <= SGMII2)) {
board_serdes_map[i].serdes_speed = SERDES_SPEED_1_25_GBPS;
board_serdes_map[i].serdes_mode = SERDES_DEFAULT_MODE;
}
else if ((type >= PEX0) && (type <= PEX3)) {
board_serdes_map[i].serdes_speed = SERDES_SPEED_5_GBPS;
board_serdes_map[i].serdes_mode = PEX_ROOT_COMPLEX_X1;
}
else if ((type >= USB3_HOST0) && (type <= USB3_HOST1)) {
board_serdes_map[i].serdes_speed = SERDES_SPEED_5_GBPS;
board_serdes_map[i].serdes_mode = PEX_ROOT_COMPLEX_X1;
} else if ((type == DEFAULT_SERDES)) {
board_serdes_map[i].serdes_speed = SERDES_SPEED_1_25_GBPS;
board_serdes_map[i].serdes_mode = SERDES_DEFAULT_MODE;
} else {
printf("SERDES Type %d not supported\n", type);
/* Keep default serdes configuration */
type = board_serdes_map[i].serdes_type;
}
if (i==3) {
/* On V2 TX line for PCIe slot1 is inverted*/
board_serdes_map[i].swap_tx = 1;
}
debug("Configure SERDES %d to %d\n", i, type);
board_serdes_map[i].serdes_type = type;
}
}
}
*serdes_map_array = board_serdes_map;
*count = ARRAY_SIZE(board_serdes_map);
return 0;
}
/*
* Define the DDR layout / topology here in the board file. This will
* be used by the DDR3 init code in the SPL U-Boot version to configure
* the DDR3 controller.
*/
static struct 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 */
5, /* Num Of Bus Per Interface*/
BUS_MASK_32BIT /* Busses mask */
};
struct hws_topology_map *ddr3_get_topology_map(void)
{
/* Return the board topology as defined in the board code */
return &board_topology_map;
}
#if defined(CONFIG_WATCHDOG)
void watchdog_init(void)
{
/* NOTE: Global watchdog counter register is at 0xf1020334
Could not find this in the manual. */
if (uclass_get_device(UCLASS_WDT, 0, (struct udevice **)&(gd->watchdog))) {
puts("Cannot enable watchdog!\n");
} else {
puts("Enabling watchdog\n");
wdt_start(gd->watchdog, (u32) 25000000 * 150, 0); /* Timer runs at 25 MHz */
}
}
/* Called by macro WATCHDOG_RESET */
void watchdog_reset(void)
{
static ulong next_reset = 0;
ulong now;
if (!(gd->watchdog)) return;
now = timer_get_us();
/* Do not reset the watchdog too often */
if (now > next_reset) {
wdt_reset(gd->watchdog);
next_reset = now + 1000000;
}
}
#endif
int board_early_init_f(void)
{
/* Configure MPP */
writel(0x00111111, MVEBU_MPP_BASE + 0x00);
writel(0x40000000, MVEBU_MPP_BASE + 0x04);
writel(0x55000444, MVEBU_MPP_BASE + 0x08);
writel(0x55053350, MVEBU_MPP_BASE + 0x0c);
writel(0x55555555, MVEBU_MPP_BASE + 0x10);
writel(0x06605505, MVEBU_MPP_BASE + 0x14);
writel(0x55550555, MVEBU_MPP_BASE + 0x18);
writel(0x00005551, MVEBU_MPP_BASE + 0x1c);
/* Set GPP Out value */
writel(GPP_OUT_VAL_LOW, MVEBU_GPIO0_BASE + 0x00);
writel(GPP_OUT_VAL_MID, MVEBU_GPIO1_BASE + 0x00);
/* Set GPP Polarity */
writel(GPP_POL_LOW, MVEBU_GPIO0_BASE + 0x0c);
writel(GPP_POL_MID, MVEBU_GPIO1_BASE + 0x0c);
/* Set GPP Out Enable */
writel(GPP_OUT_ENA_LOW, MVEBU_GPIO0_BASE + 0x04);
writel(GPP_OUT_ENA_MID, MVEBU_GPIO1_BASE + 0x04);
return 0;
}
u32 spl_boot_mode(const u32 boot_device)
{
return MMCSD_MODE_EMMCBOOT;
}
void spl_board_init(void)
{
int err;
struct mmc *mmcp;
err = mmc_initialize(0);
if (err)
return;
debug("SPL: select partition\n");
mmcp = find_mmc_device(0);
mmc_init(mmcp);
printf("Partition found: %p\n", mmcp);
/* select boot0 as first boot partition */
mmcp->part_config &= ~(PART_ACCESS_MASK << 3);
mmcp->part_config |= (1 << 3);
debug("Boot partition set to boot0\n");
}
static void set_gpios(void)
{
init_gpios();
}
#if !defined(CONFIG_SPL_BUILD)
static void pass_hw_rev(void)
{
int hw_ver = 0, hw_rev = 0;
char *old_env;
char hw_versions[128];
char new_env[256];
bd_get_hw_version(&hw_ver, &hw_rev);
snprintf(hw_versions, sizeof(hw_versions), "CP=%d.%d",
hw_ver, hw_rev);
old_env = env_get("add_version_bootargs");
/* Normaly add_version_bootargs should already be set (see board include file) */
if (old_env != 0) {
snprintf(new_env, sizeof(new_env), "%s %s", old_env, hw_versions);
}
else {
snprintf(new_env, sizeof(new_env), "env_set bootargs $bootargs %s\n", hw_versions);
}
env_set("add_version_bootargs", new_env);
}
#endif
int board_init(void)
{
#if defined(CONFIG_WATCHDOG)
watchdog_init();
#endif
/* adress of boot parameters */
gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
/* Setup the MBUS mapping for Devicebus CS0 */
mbus_dt_setup_win(&mbus_state, DEV_CS0_BASE, 16 << 20,
CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_DEV_CS0);
if (read_eeprom() < 0)
puts("Could not get board ID.\n");
set_gpios();
/* @@se: With this call we disable a debug feature, that allows one to read out the memory
* over i2c at slave address 0x64. This feature is for some undocumented reasons enabled by default
* the default value is 0x00370010, according to the documentation it should be 0x00330010. If we set
* it back to this value address 0x64 is unused again. This is necessary because atsha204 uses 0x64 as
* slave address.
*/
writel(0x00330010, INTER_REGS_BASE + 0x1108C);
return 0;
}
int board_early_init_r(void)
{
/* We need to force mmc_initialization here, so that
* we have mmc available for read of /boot/consoledev */
mmc_initialize(gd->bd);
/* We need to force the env relocation so that it won't overwritte the
* serial devices that we set in init_console */
env_relocate();
gd->env_valid = ENV_VALID;
return 0;
}
#if !defined(CONFIG_SPL_BUILD)
static bool get_button_state(void)
{
u8 state = 0x00;
(void)da9093_get_reg(PMIC_REG_STATUS_A, &state);
return (state & 0x01) == 0x01;
}
static int check_reset_button(void)
{
int counter = 0;
/* Check how long button is pressed */
do {
if (!get_button_state())
break;
udelay(100*1000); /* 100ms */
counter += 100;
if (counter == 2000) {
/* Indicate factory reset threshold */
/* let all green LEDs blink up */
set_led(LED0_GREEN, 1);
set_led(LED1_GREEN, 1);
set_led(LED2_GREEN, 1);
set_led(LED3_GREEN, 1);
set_led(LED4_GREEN, 1);
set_led(LED5_GREEN, 1);
udelay(400000); /* 400ms */
set_led(LED1_GREEN, 0);
set_led(LED2_GREEN, 0);
set_led(LED3_GREEN, 0);
set_led(LED4_GREEN, 0);
set_led(LED5_GREEN, 0);
} else if (counter == 12000) {
/* Indicate recovery boot threshold */
/* let all red LEDs blink up */
set_led(LED0_GREEN, 0);
set_led(LED0_RED, 1);
set_led(LED1_RED, 1);
set_led(LED2_RED, 1);
set_led(LED3_RED, 1);
set_led(LED4_RED, 1);
set_led(LED5_RED, 1);
udelay(400000); /* 400ms */
set_led(LED0_RED, 0);
set_led(LED1_RED, 0);
set_led(LED2_RED, 0);
set_led(LED3_RED, 0);
set_led(LED4_RED, 0);
set_led(LED5_RED, 0);
set_led(LED0_GREEN, 1);
}
} while (counter < 12000);
if (counter < 2000) {
/* Don't do anything for duration < 2s */
}
else if (counter < 12000)
{
/* Do factory reset for duration between 2s and 12s */
char new_bootargs[512];
char *bootargs = env_get("bootargs");
if (bootargs == 0) bootargs="";
printf("Do factory reset during boot...\n");
strncpy(new_bootargs, bootargs, sizeof(new_bootargs));
strncat(new_bootargs, " factory-reset", sizeof(new_bootargs));
env_set("bootargs", new_bootargs);
return 1;
}
else
{
/* Boot into recovery for duration > 12s */
printf("Booting recovery image...\n");
/* Set bootcmd to run recovery */
env_set("bootcmd", "run recovery");
return 0;
}
return 0;
}
#endif
int misc_init_r(void)
{
/* Because U-Boot is buggy, we need to call this funktion again
* it will print the pre console buffer */
/* TODO: Moved following two lines to board_late_init because ttyS1 is currently not working without loaded bitstream */
// init_console();
// console_init_f();
/* Configure PMIC */
#if !defined(CONFIG_SPL_BUILD)
/* Enable PMIC LED */
da9093_set_reg(0x1e, 0x08);
/* Enable PMIC RTC backup charger (charge with 6mA to 3.1V) */
da9093_set_reg(0xc5, 0xff);
#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);
}
#if !defined(CONFIG_SPL_BUILD)
static void set_devicetree_name(void)
{
char devicetreename[64];
/* add hardware versions to environment */
if (bd_get_devicetree(devicetreename, sizeof(devicetreename)) != 0) {
printf("Devicetree name not found, use legacy name\n");
strcpy(devicetreename, "armada-385-nbhw18-prod1.dtb");
}
env_set("fdt_image", devicetreename);
}
#endif
int board_late_init(void)
{
#if !defined(CONFIG_SPL_BUILD)
gpio_request(29, "RST_ETH_PHY_N");
gpio_direction_output(29, 0);
find_and_set_active_partition();
pass_hw_rev();
/* Todo: It seems that something with the network is wrong */
run_command("run load_fpga", CMD_FLAG_ENV);
#endif
/* TODO: Move the following two lines up to misc_init_r when ttyS1 works without FPGA again */
init_console();
console_init_f();
#if !defined(CONFIG_SPL_BUILD)
check_reset_button();
set_devicetree_name();
set_mac_addresses(3);
/* Take phy out of reset after FPGA was loaded */
gpio_set_value(29, 1);
#endif
return 0;
}
void configure_mvswitch(void);
int board_network_enable(struct mii_dev *bus)
{
static int NETWORK_ENABLED = 0;
if (!NETWORK_ENABLED) {
set_phy_fast_blink_mode(0);
set_phy_fast_blink_mode(1);
configure_mvswitch();
NETWORK_ENABLED = 1;
}
return 0;
}
int checkboard(void)
{
debug("Board: NetModule NBHW18\n");
return 0;
}
int board_fit_config_name_match(const char *name)
{
#ifdef CONFIG_SPL_BUILD
/* SPL has enabled serial0 per default and will output everything
* independend of /boot/consoledev */
#define DEFAULT_DTB_NAME "armada-385-nbhw18-spl"
#else
/* U-Boot will read /boot/consoledev and based on that it
* enables its own serial console */
#define DEFAULT_DTB_NAME "armada-385-nbhw18-v2"
#endif
/* Check if name fits our dts */
return strcmp(DEFAULT_DTB_NAME, name);
}
#ifdef CONFIG_OF_BOARD_FIXUP
int fdt_enable_by_ofname(void *rw_fdt_blob, char *ofname)
{
int offset = fdt_path_offset(rw_fdt_blob, ofname);
return fdt_status_okay(rw_fdt_blob, offset);
}
int board_fix_fdt(void *fdt_blob)
{
debug("Enable SFP Port\n");
return fdt_enable_by_ofname(fdt_blob, "/soc/internal-regs/ethernet@30000");
}
#endif
int pcie_lane_by_slot(int slot)
{
int serdes;
switch (slot) {
case 0 :
serdes = 3;
break;
case 1 :
serdes = 4;
break;
case 2 :
serdes = 1;
break;
default :
serdes = -1;
break;
}
if ((serdes<0) || serdes>=ARRAY_SIZE(board_serdes_map))
return -1;
switch (board_serdes_map[serdes].serdes_type)
{
case PEX0 :
return 0;
case PEX1 :
return 1;
case PEX2 :
return 2;
case PEX3 :
return 3;
default :
return -1;
}
}
static void ft_enable_node(void* blob, const char* name)
{
int node_ofs = -1;
node_ofs = fdt_path_offset(blob, name);
if (node_ofs >= 0) {
fdt_setprop_string(blob, node_ofs, "status", "okay");
}
}
static void ft_eth1_sgmii0(void *blob)
{
printf("FT: enable eth phy on sgmii0\n");
ft_enable_node(blob, "/soc/internal-regs/ethernet_phy@70000");
}
static void ft_dsa_sgmii0(void *blob)
{
printf("FT: enable dsa on sgmii0\n");
ft_enable_node(blob, "/soc/internal-regs/ethernet_dsa@70000");
ft_enable_node(blob, "/dsa_eth0@0");
}
static void ft_dsa_sgmii1(void *blob)
{
printf("FT: enable dsa on sgmii1\n");
ft_enable_node(blob, "/soc/internal-regs/ethernet_dsa@30000");
ft_enable_node(blob, "/dsa_eth1@0");
}
static void ft_sfp_sgmii1(void *blob)
{
/* Depending if the second ethernet port is in use
or not the sfp has a different interface name.
So enable the proper one. */
if (board_serdes_map[0].serdes_type==SGMII0) {
printf("FT: enable sfp for cfg1\n");
ft_enable_node(blob, "/soc/internal-regs/ethernet_sfp_cfg1@30000");
} else {
printf("FT: enable sfp for cfg0\n");
ft_enable_node(blob, "/soc/internal-regs/ethernet_sfp_cfg0@30000");
}
}
int ft_board_setup(void *blob, bd_t *bd)
{
struct serdes_map* sm;
u8 sm_count;
/* Enabled all components in dts depending on
current serdes configuration */
/* Determine SERDES configuration */
hws_board_topology_load(&sm, &sm_count);
/* Second ethernet port (SERDES0) can only be
connected to SGMII0. SO check, if we need to enable it. */
switch (board_serdes_map[0].serdes_type) {
case SGMII0 :
ft_eth1_sgmii0(blob);
break;
default :
break;
}
/* The PoE switch (SERDES1) can be connected either to
SGMII0 or SGMII1. So check, if we need to enable one of those. */
switch (board_serdes_map[1].serdes_type) {
case SGMII0 :
ft_dsa_sgmii0(blob);
break;
case SGMII1 :
ft_dsa_sgmii1(blob);
break;
default :
break;
}
/* SFP (SERDES2) can only be connected to SGMII1. So check,
if we need to enable it. */
switch (board_serdes_map[2].serdes_type) {
case SGMII1 :
ft_sfp_sgmii1(blob);
break;
default :
break;
}
return 0;
}