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

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