From f9ad35b73a5d62494cf3e80ca85f0de49cd7483f Mon Sep 17 00:00:00 2001 From: Marcel Reichmuth Date: Fri, 31 Aug 2018 08:56:27 +0200 Subject: [PATCH] nbhw18: dynamically enable devices in dts according to current serdes config BugzID: 52859 --- board/nm/nbhw18_v2/board.c | 157 ++++++++++++++++++++++++- include/configs/armada-385-nbhw18-v2.h | 2 + 2 files changed, 156 insertions(+), 3 deletions(-) diff --git a/board/nm/nbhw18_v2/board.c b/board/nm/nbhw18_v2/board.c index 41d7dbbee3..790df1448e 100755 --- a/board/nm/nbhw18_v2/board.c +++ b/board/nm/nbhw18_v2/board.c @@ -51,6 +51,7 @@ DECLARE_GLOBAL_DATA_PTR; #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 @@ -95,9 +96,57 @@ static int _bd_init(void) 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) { - return _bd_init(); + int res = _bd_init(); + + read_eeprom_serdes_config(); + + return res; } /* TODO: Create DA9063 Accessor Module */ @@ -261,7 +310,17 @@ int hws_board_topology_load(struct serdes_map **serdes_map_array, u8 *count) board_serdes_map[5].serdes_type = SGMII2; } else { for (i = 0; i < ARRAY_SIZE(board_serdes_map); i++) { - enum serdes_type type = bd_get_serdes_type(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)) { @@ -633,7 +692,7 @@ static void set_devicetree_name(void) /* add hardware versions to environment */ if (bd_get_devicetree(devicetreename, sizeof(devicetreename)) != 0) { printf("Devicetree name not found, use legacy name\n"); - strcpy(devicetreename, "am335x-nbhw16.dtb"); + strcpy(devicetreename, "armada-385-nbhw18-prod1.dtb"); } env_set("fdt_image", devicetreename); @@ -768,3 +827,95 @@ int pcie_lane_by_slot(int slot) 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; +} + diff --git a/include/configs/armada-385-nbhw18-v2.h b/include/configs/armada-385-nbhw18-v2.h index ae1551247b..6c08dea848 100755 --- a/include/configs/armada-385-nbhw18-v2.h +++ b/include/configs/armada-385-nbhw18-v2.h @@ -84,6 +84,8 @@ #define CONFIG_WATCHDOG #endif +#define CONFIG_OF_BOARD_SETUP + #define CONFIG_SYS_ALT_MEMTEST #ifndef CONFIG_SPL_BUILD