469 lines
11 KiB
C
Executable File
469 lines
11 KiB
C
Executable File
/*
|
|
* Copyright (C) 2015 Stefan Roese <sr@denx.de>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
#define 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 <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>
|
|
|
|
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(7) | BIT(19) | BIT(21))) /* 1=Input, default input */
|
|
|
|
#define GPP_OUT_ENA_MID (~(BIT(9) | BIT(12)))
|
|
|
|
#define GPP_OUT_VAL_LOW (BIT(21))
|
|
#define GPP_OUT_VAL_MID (BIT(9))
|
|
#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 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;
|
|
}
|
|
|
|
static inline int __maybe_unused read_eeprom(void)
|
|
{
|
|
return _bd_init();
|
|
}
|
|
|
|
|
|
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();
|
|
|
|
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 get board ID.\n");
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(board_serdes_map); i++) {
|
|
enum serdes_type 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;
|
|
if (i==1) {
|
|
/* Polarity of SERDES1 (SGMII0 to switch extension seems
|
|
to be inverted. */
|
|
board_serdes_map[i].swap_rx = 1;
|
|
board_serdes_map[i].swap_tx = 1;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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(NULL);
|
|
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 bootpart */
|
|
mmcp->part_config |= (1 << 3);
|
|
debug("Partition switched to boot0\n");
|
|
}
|
|
|
|
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 = env_get("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), "env_set bootargs $bootargs %s\n", hw_versions);
|
|
}
|
|
|
|
env_set("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_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;
|
|
init_console();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int misc_init_r(void)
|
|
{
|
|
/* Because U-Boot is buggy, we need to call this funktion again
|
|
* it will print the pre console buffer */
|
|
console_init_f();
|
|
|
|
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);
|
|
|
|
set_mac_addresses(3);
|
|
|
|
/* Take phy out of reset after FPGA was loaded */
|
|
gpio_set_value(21, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int board_network_enable(struct mii_dev *bus)
|
|
{
|
|
|
|
set_phy_fast_blink_mode(0);
|
|
set_phy_fast_blink_mode(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-v1"
|
|
#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;
|
|
}
|
|
}
|