+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) Marvell International Ltd. and its affiliates
- *
- * SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
-#include <i2c.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
+#include <linux/delay.h>
#include "high_speed_env_spec.h"
-#include "high_speed_topology_spec.h"
#include "sys_env_lib.h"
#include "ctrl_pex.h"
#error "No device is defined"
#endif
-/*
- * The board topology map, initialized in the beginning of
- * ctrl_high_speed_serdes_phy_config
- */
-struct serdes_map serdes_configuration_map[MAX_SERDES_LANES];
/*
* serdes_seq_db - holds all serdes sequences, their size and the
*/
struct cfg_seq serdes_seq_db[SERDES_LAST_SEQ];
-#define SERDES_VERION "2.0"
+#define SERDES_VERSION "2.0"
#define ENDED_OK "High speed PHY - Ended Successfully\n"
#define LINK_WAIT_CNTR 100
struct op_params pex_by4_config_params[] = {
/* unit_base_reg, unit_offset, mask, data, wait_time, num_of_loops */
{GLOBAL_CLK_SRC_HI, 0x800, 0x7, {0x5, 0x0, 0x0, 0x2}, 0, 0},
- /* Lane Alignement enable */
+ /* Lane Alignment enable */
{LANE_ALIGN_REG0, 0x800, 0x1000, {0x0, 0x0, 0x0, 0x0}, 0, 0},
/* Max PLL phy config */
{CALIBRATION_CTRL_REG, 0x800, 0x1000, {0x1000, 0x1000, 0x1000, 0x1000},
{LANE_CFG4_REG, 0x800, 0x8, {0x8}, 0, 0},
/* tximpcal_th and rximpcal_th */
{VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0},
+ /* Force receiver detected */
+ {LANE_CFG0_REG, 0x800, 0x8000, {0x8000}, 0, 0},
};
/* PEX - configuration seq for REF_CLOCK_25MHz */
{0xc200c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0},
/* Phy0 register 3 - TX Channel control 0 */
{0xc400c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0},
- /* check PLLCAL_DONE is set and IMPCAL_DONE is set */
+ /* Decrease the amplitude of the low speed eye to meet the spec */
+ {0xc000c, 0x0 /*NA*/, 0xf000, {0x1000}, 0, 0},
+ {0xc200c, 0x0 /*NA*/, 0xf000, {0x1000}, 0, 0},
+ {0xc400c, 0x0 /*NA*/, 0xf000, {0x1000}, 0, 0},
+ /* Change the High speed impedance threshold */
+ {0xc0008, 0x0 /*NA*/, 0x700, {CONFIG_ARMADA_38X_HS_IMPEDANCE_THRESH << 8}, 0, 0},
+ {0xc2008, 0x0 /*NA*/, 0x700, {CONFIG_ARMADA_38X_HS_IMPEDANCE_THRESH << 8}, 0, 0},
+ {0xc4008, 0x0 /*NA*/, 0x700, {CONFIG_ARMADA_38X_HS_IMPEDANCE_THRESH << 8}, 0, 0},
+ /* Change the squelch level of the receiver to meet the receiver electrical measurements (squelch and receiver sensitivity tests) */
+ {0xc0014, 0x0 /*NA*/, 0xf, {0x8}, 0, 0},
+ {0xc2014, 0x0 /*NA*/, 0xf, {0x8}, 0, 0},
+ {0xc4014, 0x0 /*NA*/, 0xf, {0x8}, 0, 0},
+ /* Check PLLCAL_DONE is set and IMPCAL_DONE is set */
{0xc0008, 0x0 /*NA*/, 0x80800000, {0x80800000}, 1, 1000},
- /* check REG_SQCAL_DONE is set */
+ /* Check REG_SQCAL_DONE is set */
{0xc0018, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000},
- /* check PLL_READY is set */
- {0xc0000, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000}
+ /* Check PLL_READY is set */
+ {0xc0000, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000},
+ /* Start calibrate of high seed impedance */
+ {0xc0008, 0x0 /*NA*/, 0x2000, {0x2000}, 0, 0},
+ {0x0, 0x0 /*NA*/, 0x0, {0x0}, 10, 0},
+ /* De-assert the calibration signal */
+ {0xc0008, 0x0 /*NA*/, 0x2000, {0x0}, 0, 0},
};
/*
}
} else {
test_result = SERDES_ALREADY_IN_USE;
- if (test_result == SERDES_ALREADY_IN_USE) {
- printf("%s: Error: serdes lane %d is configured to type %s: type already in use\n",
- __func__, serdes_id,
- serdes_type_to_string[serdes_type]);
- return MV_FAIL;
- } else if (test_result == WRONG_NUMBER_OF_UNITS) {
- printf("%s: Warning: serdes lane %d is set to type %s.\n",
- __func__, serdes_id,
- serdes_type_to_string[serdes_type]);
- printf("%s: Maximum supported lanes are already set to this type (limit = %d)\n",
- __func__, serd_max_num);
- return MV_FAIL;
- } else if (test_result == UNIT_NUMBER_VIOLATION) {
- printf("%s: Warning: serdes lane %d type is %s: current device support only %d units of this type.\n",
- __func__, serdes_id,
- serdes_type_to_string[serdes_type],
- serd_max_num);
- return MV_FAIL;
- }
+ }
+
+ if (test_result == SERDES_ALREADY_IN_USE) {
+ printf("%s: Error: serdes lane %d is configured to type %s: type already in use\n",
+ __func__, serdes_id,
+ serdes_type_to_string[serdes_type]);
+ return MV_FAIL;
+ } else if (test_result == WRONG_NUMBER_OF_UNITS) {
+ printf("%s: Warning: serdes lane %d is set to type %s.\n",
+ __func__, serdes_id,
+ serdes_type_to_string[serdes_type]);
+ printf("%s: Maximum supported lanes are already set to this type (limit = %d)\n",
+ __func__, serd_max_num);
+ return MV_FAIL;
+ } else if (test_result == UNIT_NUMBER_VIOLATION) {
+ printf("%s: Warning: serdes lane %d type is %s: current device support only %d units of this type.\n",
+ __func__, serdes_id,
+ serdes_type_to_string[serdes_type],
+ serd_max_num);
+ return MV_FAIL;
}
return MV_OK;
return seq_id;
}
-/*
- * This is the weak default function for the Marvell evaluation or
- * development boarrds. Like the DB-88F6820-GP and others.
- * Custom boards should define this function in their board
- * code (board directory). And overwrite this default function
- * with this custom specific code.
- */
-__weak int hws_board_topology_load(struct serdes_map *serdes_map_array)
-{
- u32 board_id = mv_board_id_get();
- u32 board_id_index = mv_board_id_index_get(board_id);
-
- DEBUG_INIT_FULL_S("\n### hws_board_topology_load ###\n");
- /* getting board topology according to the board id */
- DEBUG_INIT_FULL_S("Getting board topology according to the board id\n");
-
- CHECK_STATUS(load_topology_func_arr[board_id_index] (serdes_map_array));
-
- return MV_OK;
-}
-
-void print_topology_details(struct serdes_map *serdes_map_array)
+static void print_topology_details(const struct serdes_map *serdes_map,
+ u8 count)
{
u32 lane_num;
DEBUG_INIT_S("board SerDes lanes topology details:\n");
- DEBUG_INIT_S(" | Lane # | Speed | Type |\n");
+ DEBUG_INIT_S(" | Lane # | Speed | Type |\n");
DEBUG_INIT_S(" --------------------------------\n");
- for (lane_num = 0; lane_num < hws_serdes_get_max_lane(); lane_num++) {
- if (serdes_map_array[lane_num].serdes_type == DEFAULT_SERDES)
+ for (lane_num = 0; lane_num < count; lane_num++) {
+ if (serdes_map[lane_num].serdes_type == DEFAULT_SERDES)
continue;
DEBUG_INIT_S(" | ");
DEBUG_INIT_D(hws_get_physical_serdes_num(lane_num), 1);
- DEBUG_INIT_S(" | ");
- DEBUG_INIT_D(serdes_map_array[lane_num].serdes_speed, 2);
- DEBUG_INIT_S(" | ");
+ DEBUG_INIT_S(" | ");
+ DEBUG_INIT_D(serdes_map[lane_num].serdes_speed, 2);
+ DEBUG_INIT_S(" | ");
DEBUG_INIT_S((char *)
- serdes_type_to_string[serdes_map_array[lane_num].
+ serdes_type_to_string[serdes_map[lane_num].
serdes_type]);
DEBUG_INIT_S("\t|\n");
}
int serdes_phy_config(void)
{
+ struct serdes_map *serdes_map;
+ u8 serdes_count;
+
DEBUG_INIT_FULL_S("\n### ctrl_high_speed_serdes_phy_config ###\n");
DEBUG_INIT_S("High speed PHY - Version: ");
- DEBUG_INIT_S(SERDES_VERION);
+ DEBUG_INIT_S(SERDES_VERSION);
DEBUG_INIT_S("\n");
/* Init serdes sequences DB */
return MV_FAIL;
}
- /* I2C init */
- i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
-
/* Board topology load */
DEBUG_INIT_FULL_S
("ctrl_high_speed_serdes_phy_config: Loading board topology..\n");
- CHECK_STATUS(hws_board_topology_load(serdes_configuration_map));
+ CHECK_STATUS(hws_board_topology_load(&serdes_map, &serdes_count));
+ if (serdes_count > hws_serdes_get_max_lane()) {
+ printf("Error: too many serdes lanes specified by board\n");
+ return MV_FAIL;
+ }
/* print topology */
- print_topology_details(serdes_configuration_map);
+ print_topology_details(serdes_map, serdes_count);
CHECK_STATUS(hws_pre_serdes_init_config());
/* Power-Up sequence */
DEBUG_INIT_FULL_S
("ctrl_high_speed_serdes_phy_config: Starting serdes power up sequence\n");
- CHECK_STATUS(hws_power_up_serdes_lanes(serdes_configuration_map));
+ CHECK_STATUS(hws_power_up_serdes_lanes(serdes_map, serdes_count));
DEBUG_INIT_FULL_S
("\n### ctrl_high_speed_serdes_phy_config ended successfully ###\n");
return MV_OK;
}
-int hws_power_up_serdes_lanes(struct serdes_map *serdes_config_map)
+int hws_power_up_serdes_lanes(struct serdes_map *serdes_map, u8 count)
{
u32 serdes_id, serdes_lane_num;
enum ref_clock ref_clock;
/* COMMON PHYS SELECTORS register configuration */
DEBUG_INIT_FULL_S
("hws_power_up_serdes_lanes: Updating COMMON PHYS SELECTORS reg\n");
- CHECK_STATUS(hws_update_serdes_phy_selectors(serdes_configuration_map));
+ CHECK_STATUS(hws_update_serdes_phy_selectors(serdes_map, count));
/* per Serdes Power Up */
- for (serdes_id = 0; serdes_id < hws_serdes_get_max_lane();
- serdes_id++) {
+ for (serdes_id = 0; serdes_id < count; serdes_id++) {
DEBUG_INIT_FULL_S
("calling serdes_power_up_ctrl: serdes lane number ");
DEBUG_INIT_FULL_D_10(serdes_lane_num, 1);
DEBUG_INIT_FULL_S("\n");
serdes_lane_num = hws_get_physical_serdes_num(serdes_id);
- serdes_type = serdes_config_map[serdes_id].serdes_type;
- serdes_speed = serdes_config_map[serdes_id].serdes_speed;
- serdes_mode = serdes_config_map[serdes_id].serdes_mode;
- serdes_rx_polarity_swap = serdes_config_map[serdes_id].swap_rx;
- serdes_tx_polarity_swap = serdes_config_map[serdes_id].swap_tx;
+ serdes_type = serdes_map[serdes_id].serdes_type;
+ serdes_speed = serdes_map[serdes_id].serdes_speed;
+ serdes_mode = serdes_map[serdes_id].serdes_mode;
+ serdes_rx_polarity_swap = serdes_map[serdes_id].swap_rx;
+ serdes_tx_polarity_swap = serdes_map[serdes_id].swap_tx;
/* serdes lane is not in use */
if (serdes_type == DEFAULT_SERDES)
/* Set PEX_TX_CONFIG_SEQ sequence for PEXx4 mode.
After finish the Power_up sequence for all lanes,
the lanes should be released from reset state. */
- CHECK_STATUS(hws_pex_tx_config_seq(serdes_config_map));
+ CHECK_STATUS(hws_pex_tx_config_seq(serdes_map, count));
/* PEX configuration */
- CHECK_STATUS(hws_pex_config(serdes_config_map));
+ CHECK_STATUS(hws_pex_config(serdes_map, count));
}
/* USB2 configuration */
return MV_OK;
}
-int hws_update_serdes_phy_selectors(struct serdes_map *serdes_config_map)
+int hws_update_serdes_phy_selectors(struct serdes_map *serdes_map, u8 count)
{
u32 lane_data, idx, serdes_lane_hw_num, reg_data = 0;
enum serdes_type serdes_type;
* Updating bits 0-17 in the COMMON PHYS SELECTORS register
* according to the serdes types
*/
- for (idx = 0; idx < hws_serdes_get_max_lane();
- idx++) {
- serdes_type = serdes_config_map[idx].serdes_type;
- serdes_mode = serdes_config_map[idx].serdes_mode;
+ for (idx = 0; idx < count; idx++) {
+ serdes_type = serdes_map[idx].serdes_type;
+ serdes_mode = serdes_map[idx].serdes_mode;
serdes_lane_hw_num = hws_get_physical_serdes_num(idx);
lane_data =
if (hws_serdes_topology_verify
(serdes_type, idx, serdes_mode) != MV_OK) {
- serdes_config_map[idx].serdes_type =
+ serdes_map[idx].serdes_type =
DEFAULT_SERDES;
printf("%s: SerDes lane #%d is disabled\n", __func__,
serdes_lane_hw_num);
printf
("%s: Warning: SerDes lane #%d and type %d are not supported together\n",
__func__, serdes_lane_hw_num, serdes_mode);
- serdes_config_map[idx].serdes_type =
- DEFAULT_SERDES;
+ serdes_map[idx].serdes_type = DEFAULT_SERDES;
printf("%s: SerDes lane #%d is disabled\n", __func__,
serdes_lane_hw_num);
continue;
/* Print topology */
if (updated_topology_print)
- print_topology_details(serdes_config_map);
+ print_topology_details(serdes_map, count);
/*
* Updating the PEXx4 Enable bit in the COMMON PHYS SELECTORS
* RETURNS: MV_OK - for success
* MV_BAD_PARAM - for fail
*/
-int hws_pex_tx_config_seq(struct serdes_map *serdes_map)
+int hws_pex_tx_config_seq(const struct serdes_map *serdes_map, u8 count)
{
enum serdes_mode serdes_mode;
u32 serdes_lane_id, serdes_lane_hw_num;
*/
/* relese pipe soft reset for all lanes */
- for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
- serdes_lane_id++) {
+ for (serdes_lane_id = 0; serdes_lane_id < count; serdes_lane_id++) {
serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
serdes_lane_hw_num =
hws_get_physical_serdes_num(serdes_lane_id);
}
/* set phy soft reset for all lanes */
- for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
- serdes_lane_id++) {
+ for (serdes_lane_id = 0; serdes_lane_id < count; serdes_lane_id++) {
serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
serdes_lane_hw_num =
hws_get_physical_serdes_num(serdes_lane_id);
}
/* set phy soft reset for all lanes */
- for (serdes_lane_id = 0; serdes_lane_id < hws_serdes_get_max_lane();
- serdes_lane_id++) {
+ for (serdes_lane_id = 0; serdes_lane_id < count; serdes_lane_id++) {
serdes_mode = serdes_map[serdes_lane_id].serdes_mode;
serdes_lane_hw_num =
hws_get_physical_serdes_num(serdes_lane_id);