| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) Marvell International Ltd. and its affiliates |
| */ |
| |
| #include <common.h> |
| #include <spl.h> |
| #include <asm/io.h> |
| #include <asm/arch/cpu.h> |
| #include <asm/arch/soc.h> |
| |
| #include "high_speed_env_spec.h" |
| #include "sys_env_lib.h" |
| #include "ctrl_pex.h" |
| |
| #if defined(CONFIG_ARMADA_38X) |
| #elif defined(CONFIG_ARMADA_39X) |
| #else |
| #error "No device is defined" |
| #endif |
| |
| |
| /* |
| * serdes_seq_db - holds all serdes sequences, their size and the |
| * relevant index in the data array initialized in serdes_seq_init |
| */ |
| struct cfg_seq serdes_seq_db[SERDES_LAST_SEQ]; |
| |
| #define SERDES_VERSION "2.0" |
| #define ENDED_OK "High speed PHY - Ended Successfully\n" |
| |
| #define LINK_WAIT_CNTR 100 |
| #define LINK_WAIT_SLEEP 100 |
| |
| #define MAX_UNIT_NUMB 4 |
| #define TOPOLOGY_TEST_OK 0 |
| #define WRONG_NUMBER_OF_UNITS 1 |
| #define SERDES_ALREADY_IN_USE 2 |
| #define UNIT_NUMBER_VIOLATION 3 |
| |
| /* |
| * serdes_lane_in_use_count contains the exact amount of serdes lanes |
| * needed per type |
| */ |
| u8 serdes_lane_in_use_count[MAX_UNITS_ID][MAX_UNIT_NUMB] = { |
| /* 0 1 2 3 */ |
| { 1, 1, 1, 1 }, /* PEX */ |
| { 1, 1, 1, 1 }, /* ETH_GIG */ |
| { 1, 1, 0, 0 }, /* USB3H */ |
| { 1, 1, 1, 0 }, /* USB3D */ |
| { 1, 1, 1, 1 }, /* SATA */ |
| { 1, 0, 0, 0 }, /* QSGMII */ |
| { 4, 0, 0, 0 }, /* XAUI */ |
| { 2, 0, 0, 0 } /* RXAUI */ |
| }; |
| |
| /* |
| * serdes_unit_count count unit number. |
| * (i.e a single XAUI is counted as 1 unit) |
| */ |
| u8 serdes_unit_count[MAX_UNITS_ID] = { 0 }; |
| |
| /* Selector mapping for A380-A0 and A390-Z1 */ |
| u8 selectors_serdes_rev2_map[LAST_SERDES_TYPE][MAX_SERDES_LANES] = { |
| /* 0 1 2 3 4 5 6 */ |
| { 0x1, 0x1, NA, NA, NA, NA, NA }, /* PEX0 */ |
| { NA, NA, 0x1, NA, 0x1, NA, 0x1 }, /* PEX1 */ |
| { NA, NA, NA, NA, 0x7, 0x1, NA }, /* PEX2 */ |
| { NA, NA, NA, 0x1, NA, NA, NA }, /* PEX3 */ |
| { 0x2, 0x3, NA, NA, NA, NA, NA }, /* SATA0 */ |
| { NA, NA, 0x3, NA, NA, NA, NA }, /* SATA1 */ |
| { NA, NA, NA, NA, 0x6, 0x2, NA }, /* SATA2 */ |
| { NA, NA, NA, 0x3, NA, NA, NA }, /* SATA3 */ |
| { 0x3, 0x4, NA, NA, NA, NA, NA }, /* SGMII0 */ |
| { NA, 0x5, 0x4, NA, 0x3, NA, NA }, /* SGMII1 */ |
| { NA, NA, NA, 0x4, NA, 0x3, NA }, /* SGMII2 */ |
| { NA, 0x7, NA, NA, NA, NA, NA }, /* QSGMII */ |
| { NA, 0x6, NA, NA, 0x4, NA, NA }, /* USB3_HOST0 */ |
| { NA, NA, NA, 0x5, NA, 0x4, NA }, /* USB3_HOST1 */ |
| { NA, NA, NA, 0x6, 0x5, 0x5, NA }, /* USB3_DEVICE */ |
| #ifdef CONFIG_ARMADA_39X |
| { NA, NA, 0x5, NA, 0x8, NA, 0x2 }, /* SGMII3 */ |
| { NA, NA, NA, 0x8, 0x9, 0x8, 0x4 }, /* XAUI */ |
| { NA, NA, NA, NA, NA, 0x8, 0x4 }, /* RXAUI */ |
| #endif |
| { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, NA } /* DEFAULT_SERDES */ |
| }; |
| |
| /* Selector mapping for PEX by 4 confiuration */ |
| u8 common_phys_selectors_pex_by4_lanes[] = { 0x1, 0x2, 0x2, 0x2 }; |
| |
| static const char *const serdes_type_to_string[] = { |
| "PCIe0", |
| "PCIe1", |
| "PCIe2", |
| "PCIe3", |
| "SATA0", |
| "SATA1", |
| "SATA2", |
| "SATA3", |
| "SGMII0", |
| "SGMII1", |
| "SGMII2", |
| "QSGMII", |
| "USB3 HOST0", |
| "USB3 HOST1", |
| "USB3 DEVICE", |
| "SGMII3", |
| "XAUI", |
| "RXAUI", |
| "DEFAULT SERDES", |
| "LAST_SERDES_TYPE" |
| }; |
| |
| struct serdes_unit_data { |
| u8 serdes_unit_id; |
| u8 serdes_unit_num; |
| }; |
| |
| static struct serdes_unit_data serdes_type_to_unit_info[] = { |
| {PEX_UNIT_ID, 0,}, |
| {PEX_UNIT_ID, 1,}, |
| {PEX_UNIT_ID, 2,}, |
| {PEX_UNIT_ID, 3,}, |
| {SATA_UNIT_ID, 0,}, |
| {SATA_UNIT_ID, 1,}, |
| {SATA_UNIT_ID, 2,}, |
| {SATA_UNIT_ID, 3,}, |
| {ETH_GIG_UNIT_ID, 0,}, |
| {ETH_GIG_UNIT_ID, 1,}, |
| {ETH_GIG_UNIT_ID, 2,}, |
| {QSGMII_UNIT_ID, 0,}, |
| {USB3H_UNIT_ID, 0,}, |
| {USB3H_UNIT_ID, 1,}, |
| {USB3D_UNIT_ID, 0,}, |
| {ETH_GIG_UNIT_ID, 3,}, |
| {XAUI_UNIT_ID, 0,}, |
| {RXAUI_UNIT_ID, 0,}, |
| }; |
| |
| /* Sequences DB */ |
| |
| /* |
| * SATA and SGMII |
| */ |
| |
| struct op_params sata_port0_power_up_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SATA data, wait_time, |
| * num_of_loops |
| */ |
| /* Access to reg 0x48(OOB param 1) */ |
| {SATA_VENDOR_PORT_0_REG_ADDR, 0x38000, 0xffffffff, {0x48,}, 0, 0}, |
| /* OOB Com_wake and Com_reset spacing upper limit data */ |
| {SATA_VENDOR_PORT_0_REG_DATA, 0x38000, 0xf03f, {0x6018,}, 0, 0}, |
| /* Access to reg 0xa(PHY Control) */ |
| {SATA_VENDOR_PORT_0_REG_ADDR, 0x38000, 0xffffffff, {0xa,}, 0, 0}, |
| /* Rx clk and Tx clk select non-inverted mode */ |
| {SATA_VENDOR_PORT_0_REG_DATA, 0x38000, 0x3000, {0x0,}, 0, 0}, |
| /* Power Down Sata addr */ |
| {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0,}, 0, 0}, |
| /* Power Down Sata Port 0 */ |
| {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffff00ff, {0xc40040,}, 0, 0}, |
| }; |
| |
| struct op_params sata_port1_power_up_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SATA data, wait_time, |
| * num_of_loops |
| */ |
| /* Access to reg 0x48(OOB param 1) */ |
| {SATA_VENDOR_PORT_1_REG_ADDR, 0x38000, 0xffffffff, {0x48,}, 0, 0}, |
| /* OOB Com_wake and Com_reset spacing upper limit data */ |
| {SATA_VENDOR_PORT_1_REG_DATA, 0x38000, 0xf03f, {0x6018,}, 0, 0}, |
| /* Access to reg 0xa(PHY Control) */ |
| {SATA_VENDOR_PORT_1_REG_ADDR, 0x38000, 0xffffffff, {0xa,}, 0, 0}, |
| /* Rx clk and Tx clk select non-inverted mode */ |
| {SATA_VENDOR_PORT_1_REG_DATA, 0x38000, 0x3000, {0x0,}, 0, 0}, |
| /* Power Down Sata addr */ |
| {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0,}, 0, 0}, |
| /* Power Down Sata Port 1 */ |
| {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffff00, {0xc44000,}, 0, 0}, |
| }; |
| |
| /* SATA and SGMII - power up seq */ |
| struct op_params sata_and_sgmii_power_up_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SATA data, SGMII data, |
| * wait_time, num_of_loops |
| */ |
| /* Power Up */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x90006, {0x80002, 0x80002}, |
| 0, 0}, |
| /* Unreset */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0x6000}, 0, 0}, |
| /* Phy Selector */ |
| {POWER_AND_PLL_CTRL_REG, 0x800, 0x0e0, {0x0, 0x80}, 0, 0}, |
| /* Ref clock source select */ |
| {MISC_REG, 0x800, 0x440, {0x440, 0x400}, 0, 0} |
| }; |
| |
| /* SATA and SGMII - speed config seq */ |
| struct op_params sata_and_sgmii_speed_config_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SATA data, |
| * SGMII (1.25G), SGMII (3.125G), wait_time, num_of_loops |
| */ |
| /* Baud Rate */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc00000, |
| {0x8800000, 0x19800000, 0x22000000}, 0, 0}, |
| /* Select Baud Rate for SATA only */ |
| {INTERFACE_REG, 0x800, 0xc00, {0x800, NO_DATA, NO_DATA}, 0, 0}, |
| /* Phy Gen RX and TX */ |
| {ISOLATE_REG, 0x800, 0xff, {NO_DATA, 0x66, 0x66}, 0, 0}, |
| /* Bus Width */ |
| {LOOPBACK_REG, 0x800, 0xe, {0x4, 0x2, 0x2}, 0, 0} |
| }; |
| |
| /* SATA and SGMII - TX config seq */ |
| struct op_params sata_and_sgmii_tx_config_params1[] = { |
| /* |
| * unitunit_base_reg, unit_offset, mask, SATA data, SGMII data, |
| * wait_time, num_of_loops |
| */ |
| {GLUE_REG, 0x800, 0x1800, {NO_DATA, 0x800}, 0, 0}, |
| /* Sft Reset pulse */ |
| {RESET_DFE_REG, 0x800, 0x401, {0x401, 0x401}, 0, 0}, |
| /* Sft Reset pulse */ |
| {RESET_DFE_REG, 0x800, 0x401, {0x0, 0x0}, 0, 0}, |
| /* Power up PLL, RX and TX */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0xf0000, {0x70000, 0x70000}, |
| 0, 0} |
| }; |
| |
| struct op_params sata_port0_tx_config_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SATA data, wait_time, |
| * num_of_loops |
| */ |
| /* Power Down Sata addr */ |
| {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0}, 0, 0}, |
| /* Power Down Sata Port 0 */ |
| {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffff00ff, {0xc40000}, 0, 0}, |
| /* Regret bit addr */ |
| {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x4}, 0, 0}, |
| /* Regret bit data */ |
| {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffffff, {0x80}, 0, 0} |
| }; |
| |
| struct op_params sata_port1_tx_config_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SATA data, wait_time, |
| * num_of_loops |
| */ |
| /* Power Down Sata addr */ |
| {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x0}, 0, 0}, |
| /* Power Down Sata Port 1 */ |
| {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffff00, {0xc40000}, 0, 0}, |
| /* Regret bit addr */ |
| {SATA_CTRL_REG_IND_ADDR, 0x38000, 0xffffffff, {0x4}, 0, 0}, |
| /* Regret bit data */ |
| {SATA_CTRL_REG_IND_DATA, 0x38000, 0xffffffff, {0x80}, 0, 0} |
| }; |
| |
| struct op_params sata_and_sgmii_tx_config_serdes_rev1_params2[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SATA data, SGMII data, |
| * wait_time, num_of_loops |
| */ |
| /* Wait for PHY power up sequence to finish */ |
| {COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc, 0xc}, 10, 1000}, |
| /* Wait for PHY power up sequence to finish */ |
| {COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1, 0x1}, 1, 1000} |
| }; |
| |
| struct op_params sata_and_sgmii_tx_config_serdes_rev2_params2[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SATA data, SGMII data, |
| * wait_time, num_of_loops |
| */ |
| /* Wait for PHY power up sequence to finish */ |
| {COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc, 0xc}, 10, 1000}, |
| /* Assert Rx Init for SGMII */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {NA, 0x40000000}, |
| 0, 0}, |
| /* Assert Rx Init for SATA */ |
| {ISOLATE_REG, 0x800, 0x400, {0x400, NA}, 0, 0}, |
| /* Wait for PHY power up sequence to finish */ |
| {COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1, 0x1}, 1, 1000}, |
| /* De-assert Rx Init for SGMII */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {NA, 0x0}, 0, 0}, |
| /* De-assert Rx Init for SATA */ |
| {ISOLATE_REG, 0x800, 0x400, {0x0, NA}, 0, 0}, |
| /* os_ph_offset_force (align 90) */ |
| {RX_REG3, 0x800, 0xff, {0xde, NO_DATA}, 0, 0}, |
| /* Set os_ph_valid */ |
| {RX_REG3, 0x800, 0x100, {0x100, NO_DATA}, 0, 0}, |
| /* Unset os_ph_valid */ |
| {RX_REG3, 0x800, 0x100, {0x0, NO_DATA}, 0, 0}, |
| }; |
| |
| struct op_params sata_electrical_config_serdes_rev1_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SATA data, wait_time, |
| * num_of_loops |
| */ |
| /* enable SSC and DFE update enable */ |
| {COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x400008, {0x400000,}, 0, 0}, |
| /* tximpcal_th and rximpcal_th */ |
| {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000,}, 0, 0}, |
| /* SQ_THRESH and FFE Setting */ |
| {SQUELCH_FFE_SETTING_REG, 0x800, 0xfff, {0x6cf,}, 0, 0}, |
| /* G1_TX SLEW, EMPH1 and AMP */ |
| {G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8a32,}, 0, 0}, |
| /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9,}, 0, 0}, |
| /* G2_TX SLEW, EMPH1 and AMP */ |
| {G2_SETTINGS_0_REG, 0x800, 0xffff, {0x8b5c,}, 0, 0}, |
| /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2,}, 0, 0}, |
| /* G3_TX SLEW, EMPH1 and AMP */ |
| {G3_SETTINGS_0_REG, 0x800, 0xffff, {0xe6e,}, 0, 0}, |
| /* G3_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G3_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2,}, 0, 0}, |
| /* Cal rxclkalign90 ext enable and Cal os ph ext */ |
| {CAL_REG6, 0x800, 0xff00, {0xdd00,}, 0, 0}, |
| /* Dtl Clamping disable and Dtl clamping Sel(6000ppm) */ |
| {RX_REG2, 0x800, 0xf0, {0x70,}, 0, 0}, |
| }; |
| |
| struct op_params sata_electrical_config_serdes_rev2_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SATA data, wait_time, |
| * num_of_loops |
| */ |
| /* SQ_THRESH and FFE Setting */ |
| {SQUELCH_FFE_SETTING_REG, 0x800, 0xf00, {0x600}, 0, 0}, |
| /* enable SSC and DFE update enable */ |
| {COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x400008, {0x400000}, 0, 0}, |
| /* G1_TX SLEW, EMPH1 and AMP */ |
| {G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8a32}, 0, 0}, |
| /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0}, |
| /* G2_TX SLEW, EMPH1 and AMP */ |
| {G2_SETTINGS_0_REG, 0x800, 0xffff, {0x8b5c}, 0, 0}, |
| /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0}, |
| /* G3_TX SLEW, EMPH1 and AMP */ |
| {G3_SETTINGS_0_REG, 0x800, 0xffff, {0xe6e}, 0, 0}, |
| /* |
| * G3_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI & DFE_En Gen3, |
| * DC wander calibration dis |
| */ |
| {G3_SETTINGS_1_REG, 0x800, 0x47ff, {0x7d2}, 0, 0}, |
| /* Bit[12]=0x0 idle_sync_en */ |
| {PCIE_REG0, 0x800, 0x1000, {0x0}, 0, 0}, |
| /* Dtl Clamping disable and Dtl clamping Sel(6000ppm) */ |
| {RX_REG2, 0x800, 0xf0, {0x70,}, 0, 0}, |
| /* tximpcal_th and rximpcal_th */ |
| {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0}, |
| /* DFE_STEP_FINE_FX[3:0] =0xa */ |
| {DFE_REG0, 0x800, 0xa00f, {0x800a}, 0, 0}, |
| /* DFE_EN and Dis Update control from pin disable */ |
| {DFE_REG3, 0x800, 0xc000, {0x0}, 0, 0}, |
| /* FFE Force FFE_REs and cap settings for Gen1 */ |
| {G1_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0}, |
| /* FFE Force FFE_REs and cap settings for Gen2 */ |
| {G2_SETTINGS_3_REG, 0x800, 0xff, {0xbf}, 0, 0}, |
| /* FE Force FFE_REs=4 and cap settings for Gen3n */ |
| {G3_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0}, |
| /* Set DFE Gen 3 Resolution to 3 */ |
| {G3_SETTINGS_4_REG, 0x800, 0x300, {0x300}, 0, 0}, |
| }; |
| |
| struct op_params sgmii_electrical_config_serdes_rev1_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SGMII (1.25G), SGMII (3.125G), |
| * wait_time, num_of_loops |
| */ |
| /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9, 0x3c9}, 0, 0}, |
| /* SQ_THRESH and FFE Setting */ |
| {SQUELCH_FFE_SETTING_REG, 0x800, 0xfff, {0x8f, 0xbf}, 0, 0}, |
| /* tximpcal_th and rximpcal_th */ |
| {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000, 0x4000}, 0, 0}, |
| }; |
| |
| struct op_params sgmii_electrical_config_serdes_rev2_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, SGMII (1.25G), SGMII (3.125G), |
| * wait_time, num_of_loops |
| */ |
| /* Set Slew_rate, Emph and Amp */ |
| {G1_SETTINGS_0_REG, 0x800, 0xffff, {0x8fa, 0x8fa}, 0, 0}, |
| /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9, 0x3c9}, 0, 0}, |
| /* DTL_FLOOP_EN */ |
| {RX_REG2, 0x800, 0x4, {0x0, 0x0}, 0, 0}, |
| /* G1 FFE Setting Force, RES and CAP */ |
| {G1_SETTINGS_3_REG, 0x800, 0xff, {0x8f, 0xbf}, 0, 0}, |
| /* tximpcal_th and rximpcal_th */ |
| {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000, 0x3000}, 0, 0}, |
| }; |
| |
| /* |
| * PEX and USB3 |
| */ |
| |
| /* PEX and USB3 - power up seq for Serdes Rev 1.2 */ |
| struct op_params pex_and_usb3_power_up_serdes_rev1_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, USB3 data, |
| * wait_time, num_of_loops |
| */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc7f806, |
| {0x4471804, 0x4479804}, 0, 0}, |
| {COMMON_PHY_CONFIGURATION2_REG, 0x28, 0x5c, {0x58, 0x58}, 0, 0}, |
| {COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x3, {0x1, 0x1}, 0, 0}, |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0xe000}, 0, 0}, |
| {GLOBAL_CLK_CTRL, 0x800, 0xd, {0x5, 0x1}, 0, 0}, |
| /* Ref clock source select */ |
| {MISC_REG, 0x800, 0x4c0, {0x80, 0x4c0}, 0, 0} |
| }; |
| |
| /* PEX and USB3 - power up seq for Serdes Rev 2.1 */ |
| struct op_params pex_and_usb3_power_up_serdes_rev2_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, USB3 data, |
| * wait_time, num_of_loops |
| */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc7f806, |
| {0x4471804, 0x4479804}, 0, 0}, |
| {COMMON_PHY_CONFIGURATION2_REG, 0x28, 0x5c, {0x58, 0x58}, 0, 0}, |
| {COMMON_PHY_CONFIGURATION4_REG, 0x28, 0x3, {0x1, 0x1}, 0, 0}, |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000, 0xe000}, 0, 0}, |
| {GLOBAL_CLK_CTRL, 0x800, 0xd, {0x5, 0x1}, 0, 0}, |
| {GLOBAL_MISC_CTRL, 0x800, 0xc0, {0x0, NO_DATA}, 0, 0}, |
| /* Ref clock source select */ |
| {MISC_REG, 0x800, 0x4c0, {0x80, 0x4c0}, 0, 0} |
| }; |
| |
| /* PEX and USB3 - speed config seq */ |
| struct op_params pex_and_usb3_speed_config_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, USB3 data, |
| * wait_time, num_of_loops |
| */ |
| /* Maximal PHY Generation Setting */ |
| {INTERFACE_REG, 0x800, 0xc00, {0x400, 0x400, 0x400, 0x400, 0x400}, |
| 0, 0}, |
| }; |
| |
| struct op_params usb3_electrical_config_serdes_rev1_params[] = { |
| /* Spread Spectrum Clock Enable */ |
| {LANE_CFG4_REG, 0x800, 0x80, {0x80}, 0, 0}, |
| /* G2_TX_SSC_AMP[6:0]=4.5k_p_pM and TX emphasis mode=m_v */ |
| {G2_SETTINGS_2_REG, 0x800, 0xfe40, {0x4440}, 0, 0}, |
| /* tximpcal_th and rximpcal_th */ |
| {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x4000}, 0, 0}, |
| /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0}, |
| /* FFE Setting Force, RES and CAP */ |
| {SQUELCH_FFE_SETTING_REG, 0x800, 0xff, {0xef}, 0, 0}, |
| /* Dtl Clamping disable and Dtl-clamping-Sel(6000ppm) */ |
| {RX_REG2, 0x800, 0xf0, {0x70}, 0, 0}, |
| /* cal_rxclkalign90_ext_en and cal_os_ph_ext */ |
| {CAL_REG6, 0x800, 0xff00, {0xd500}, 0, 0}, |
| /* vco_cal_vth_sel */ |
| {REF_REG0, 0x800, 0x38, {0x20}, 0, 0}, |
| }; |
| |
| struct op_params usb3_electrical_config_serdes_rev2_params[] = { |
| /* Spread Spectrum Clock Enable */ |
| {LANE_CFG4_REG, 0x800, 0x80, {0x80}, 0, 0}, |
| /* G2_TX_SSC_AMP[6:0]=4.5k_p_pM and TX emphasis mode=m_v */ |
| {G2_SETTINGS_2_REG, 0x800, 0xfe40, {0x4440}, 0, 0}, |
| /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3d2}, 0, 0}, |
| /* Dtl Clamping disable and Dtl-clamping-Sel(6000ppm) */ |
| {RX_REG2, 0x800, 0xf0, {0x70}, 0, 0}, |
| /* vco_cal_vth_sel */ |
| {REF_REG0, 0x800, 0x38, {0x20}, 0, 0}, |
| /* Spread Spectrum Clock Enable */ |
| {LANE_CFG5_REG, 0x800, 0x4, {0x4}, 0, 0}, |
| }; |
| |
| /* PEX and USB3 - TX config seq */ |
| |
| /* |
| * For PEXx1: the pex_and_usb3_tx_config_params1/2/3 configurations should run |
| * one by one on the lane. |
| * For PEXx4: the pex_and_usb3_tx_config_params1/2/3 configurations should run |
| * by setting each sequence for all 4 lanes. |
| */ |
| struct op_params pex_and_usb3_tx_config_params1[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, USB3 data, |
| * wait_time, num_of_loops |
| */ |
| {GLOBAL_CLK_CTRL, 0x800, 0x1, {0x0, 0x0}, 0, 0}, |
| /* 10ms delay */ |
| {0x0, 0x0, 0x0, {0x0, 0x0}, 10, 0}, |
| /* os_ph_offset_force (align 90) */ |
| {RX_REG3, 0x800, 0xff, {0xdc, NO_DATA}, 0, 0}, |
| /* Set os_ph_valid */ |
| {RX_REG3, 0x800, 0x100, {0x100, NO_DATA}, 0, 0}, |
| /* Unset os_ph_valid */ |
| {RX_REG3, 0x800, 0x100, {0x0, NO_DATA}, 0, 0}, |
| }; |
| |
| struct op_params pex_and_usb3_tx_config_params2[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, USB3 data, |
| * wait_time, num_of_loops |
| */ |
| /* Sft Reset pulse */ |
| {RESET_DFE_REG, 0x800, 0x401, {0x401, 0x401}, 0, 0}, |
| }; |
| |
| struct op_params pex_and_usb3_tx_config_params3[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, USB3 data, |
| * wait_time, num_of_loops |
| */ |
| /* Sft Reset pulse */ |
| {RESET_DFE_REG, 0x800, 0x401, {0x0, 0x0}, 0, 0}, |
| /* 10ms delay */ |
| {0x0, 0x0, 0x0, {0x0, 0x0}, 10, 0} |
| }; |
| |
| /* PEX by 4 config seq */ |
| 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_ALIGN_REG0, 0x800, 0x1000, {0x0, 0x0, 0x0, 0x0}, 0, 0}, |
| /* Max PLL phy config */ |
| {CALIBRATION_CTRL_REG, 0x800, 0x1000, {0x1000, 0x1000, 0x1000, 0x1000}, |
| 0, 0}, |
| /* Max PLL pipe config */ |
| {LANE_CFG1_REG, 0x800, 0x600, {0x600, 0x600, 0x600, 0x600}, 0, 0}, |
| }; |
| |
| /* USB3 device donfig seq */ |
| struct op_params usb3_device_config_params[] = { |
| /* unit_base_reg, unit_offset, mask, data, wait_time, num_of_loops */ |
| {LANE_CFG4_REG, 0x800, 0x200, {0x200}, 0, 0} |
| }; |
| |
| /* PEX - electrical configuration seq Rev 1.2 */ |
| struct op_params pex_electrical_config_serdes_rev1_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, wait_time, |
| * num_of_loops |
| */ |
| /* G1_TX_SLEW_CTRL_EN and G1_TX_SLEW_RATE */ |
| {G1_SETTINGS_0_REG, 0x800, 0xf000, {0xb000}, 0, 0}, |
| /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0}, |
| /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0}, |
| /* CFG_DFE_EN_SEL */ |
| {LANE_CFG4_REG, 0x800, 0x8, {0x8}, 0, 0}, |
| /* FFE Setting Force, RES and CAP */ |
| {SQUELCH_FFE_SETTING_REG, 0x800, 0xff, {0xaf}, 0, 0}, |
| /* tximpcal_th and rximpcal_th */ |
| {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0}, |
| /* cal_rxclkalign90_ext_en and cal_os_ph_ext */ |
| {CAL_REG6, 0x800, 0xff00, {0xdc00}, 0, 0}, |
| }; |
| |
| /* PEX - electrical configuration seq Rev 2.1 */ |
| struct op_params pex_electrical_config_serdes_rev2_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, wait_time, |
| * num_of_loops |
| */ |
| /* G1_TX_SLEW_CTRL_EN and G1_TX_SLEW_RATE */ |
| {G1_SETTINGS_0_REG, 0x800, 0xf000, {0xb000}, 0, 0}, |
| /* G1_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G1_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0}, |
| /* G1 FFE Setting Force, RES and CAP */ |
| {G1_SETTINGS_3_REG, 0x800, 0xff, {0xcf}, 0, 0}, |
| /* G2_RX SELMUFF, SELMUFI, SELMUPF and SELMUPI */ |
| {G2_SETTINGS_1_REG, 0x800, 0x3ff, {0x3c9}, 0, 0}, |
| /* G2 FFE Setting Force, RES and CAP */ |
| {G2_SETTINGS_3_REG, 0x800, 0xff, {0xaf}, 0, 0}, |
| /* G2 DFE resolution value */ |
| {G2_SETTINGS_4_REG, 0x800, 0x300, {0x300}, 0, 0}, |
| /* DFE resolution force */ |
| {DFE_REG0, 0x800, 0x8000, {0x8000}, 0, 0}, |
| /* Tx amplitude for Tx Margin 0 */ |
| {PCIE_REG1, 0x800, 0xf80, {0xd00}, 0, 0}, |
| /* Tx_Emph value for -3.5d_b and -6d_b */ |
| {PCIE_REG3, 0x800, 0xff00, {0xaf00}, 0, 0}, |
| /* CFG_DFE_EN_SEL */ |
| {LANE_CFG4_REG, 0x800, 0x8, {0x8}, 0, 0}, |
| /* tximpcal_th and rximpcal_th */ |
| {VTHIMPCAL_CTRL_REG, 0x800, 0xff00, {0x3000}, 0, 0}, |
| }; |
| |
| /* PEX - configuration seq for REF_CLOCK_25MHz */ |
| struct op_params pex_config_ref_clock25_m_hz[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, wait_time, |
| * num_of_loops |
| */ |
| /* Bits[4:0]=0x2 - REF_FREF_SEL */ |
| {POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x2}, 0, 0}, |
| /* Bit[10]=0x1 - REFCLK_SEL */ |
| {MISC_REG, 0x800, 0x400, {0x400}, 0, 0}, |
| /* Bits[7:0]=0x7 - CFG_PM_RXDLOZ_WAIT */ |
| {GLOBAL_PM_CTRL, 0x800, 0xff, {0x7}, 0, 0}, |
| }; |
| |
| /* PEX - configuration seq for REF_CLOCK_40MHz */ |
| struct op_params pex_config_ref_clock40_m_hz[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, wait_time, |
| * num_of_loops |
| */ |
| /* Bits[4:0]=0x3 - REF_FREF_SEL */ |
| {POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x3}, 0, 0}, |
| /* Bits[10]=0x1 - REFCLK_SEL */ |
| {MISC_REG, 0x800, 0x400, {0x400}, 0, 0}, |
| /* Bits[7:0]=0xc - CFG_PM_RXDLOZ_WAIT */ |
| {GLOBAL_PM_CTRL, 0x800, 0xff, {0xc}, 0, 0}, |
| }; |
| |
| /* PEX - configuration seq for REF_CLOCK_100MHz */ |
| struct op_params pex_config_ref_clock100_m_hz[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, PEX data, wait_time, |
| * num_of_loops |
| */ |
| /* Bits[4:0]=0x0 - REF_FREF_SEL */ |
| {POWER_AND_PLL_CTRL_REG, 0x800, 0x1f, {0x0}, 0, 0}, |
| /* Bit[10]=0x0 - REFCLK_SEL */ |
| {MISC_REG, 0x800, 0x400, {0x0}, 0, 0}, |
| /* Bits[7:0]=0x1e - CFG_PM_RXDLOZ_WAIT */ |
| {GLOBAL_PM_CTRL, 0x800, 0xff, {0x1e}, 0, 0}, |
| }; |
| |
| /* |
| * USB2 |
| */ |
| |
| struct op_params usb2_power_up_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, USB2 data, wait_time, |
| * num_of_loops |
| */ |
| /* Init phy 0 */ |
| {0x18440, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0}, |
| /* Init phy 1 */ |
| {0x18444, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0}, |
| /* Init phy 2 */ |
| {0x18448, 0x0 /*NA*/, 0xffffffff, {0x62}, 0, 0}, |
| /* Phy offset 0x0 - PLL_CONTROL0 */ |
| {0xc0000, 0x0 /*NA*/, 0xffffffff, {0x40605205}, 0, 0}, |
| {0xc001c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0}, |
| {0xc201c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0}, |
| {0xc401c, 0x0 /*NA*/, 0xffffffff, {0x39f16ce}, 0, 0}, |
| /* Phy offset 0x1 - PLL_CONTROL1 */ |
| {0xc0004, 0x0 /*NA*/, 0x1, {0x1}, 0, 0}, |
| /* Phy0 register 3 - TX Channel control 0 */ |
| {0xc000c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0}, |
| /* Phy0 register 3 - TX Channel control 0 */ |
| {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 */ |
| {0xc0008, 0x0 /*NA*/, 0x80800000, {0x80800000}, 1, 1000}, |
| /* 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} |
| }; |
| |
| /* |
| * QSGMII |
| */ |
| |
| /* QSGMII - power up seq */ |
| struct op_params qsgmii_port_power_up_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, QSGMII data, wait_time, |
| * num_of_loops |
| */ |
| /* Connect the QSGMII to Gigabit Ethernet units */ |
| {QSGMII_CONTROL_REG1, 0x0, 0x40000000, {0x40000000}, 0, 0}, |
| /* Power Up */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0xf0006, {0x80002}, 0, 0}, |
| /* Unreset */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x7800, {0x6000}, 0, 0}, |
| /* Phy Selector */ |
| {POWER_AND_PLL_CTRL_REG, 0x800, 0xff, {0xfc81}, 0, 0}, |
| /* Ref clock source select */ |
| {MISC_REG, 0x800, 0x4c0, {0x480}, 0, 0} |
| }; |
| |
| /* QSGMII - speed config seq */ |
| struct op_params qsgmii_port_speed_config_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, QSGMII data, wait_time, |
| * num_of_loops |
| */ |
| /* Baud Rate */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x3fc00000, {0xcc00000}, 0, 0}, |
| /* Phy Gen RX and TX */ |
| {ISOLATE_REG, 0x800, 0xff, {0x33}, 0, 0}, |
| /* Bus Width */ |
| {LOOPBACK_REG, 0x800, 0xe, {0x2}, 0, 0} |
| }; |
| |
| /* QSGMII - Select electrical param seq */ |
| struct op_params qsgmii_port_electrical_config_params[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, QSGMII data, wait_time, |
| * num_of_loops |
| */ |
| /* Slew rate and emphasis */ |
| {G1_SETTINGS_0_REG, 0x800, 0x8000, {0x0}, 0, 0} |
| }; |
| |
| /* QSGMII - TX config seq */ |
| struct op_params qsgmii_port_tx_config_params1[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, QSGMII data, wait_time, |
| * num_of_loops |
| */ |
| {GLUE_REG, 0x800, 0x1800, {0x800}, 0, 0}, |
| /* Sft Reset pulse */ |
| {RESET_DFE_REG, 0x800, 0x401, {0x401}, 0, 0}, |
| /* Sft Reset pulse */ |
| {RESET_DFE_REG, 0x800, 0x401, {0x0}, 0, 0}, |
| /* Lane align */ |
| {LANE_ALIGN_REG0, 0x800, 0x1000, {0x1000}, 0, 0}, |
| /* Power up PLL, RX and TX */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x70000, {0x70000}, 0, 0}, |
| /* Tx driver output idle */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x80000, {0x80000}, 0, 0} |
| }; |
| |
| struct op_params qsgmii_port_tx_config_params2[] = { |
| /* |
| * unit_base_reg, unit_offset, mask, QSGMII data, wait_time, |
| * num_of_loops |
| */ |
| /* Wait for PHY power up sequence to finish */ |
| {COMMON_PHY_STATUS1_REG, 0x28, 0xc, {0xc}, 10, 1000}, |
| /* Assert Rx Init and Tx driver output valid */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40080000, {0x40000000}, 0, 0}, |
| /* Wait for PHY power up sequence to finish */ |
| {COMMON_PHY_STATUS1_REG, 0x28, 0x1, {0x1}, 1, 1000}, |
| /* De-assert Rx Init */ |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, 0x40000000, {0x0}, 0, 0} |
| }; |
| |
| /* SERDES_POWER_DOWN */ |
| struct op_params serdes_power_down_params[] = { |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, (0xf << 11), {(0x3 << 11)}, |
| 0, 0}, |
| {COMMON_PHY_CONFIGURATION1_REG, 0x28, (0x7 << 16), {0}, 0, 0} |
| }; |
| |
| /* |
| * hws_ctrl_serdes_rev_get |
| * |
| * DESCRIPTION: Get the Serdes revision number |
| * |
| * INPUT: config_field - Field description enum |
| * |
| * OUTPUT: None |
| * |
| * RETURN: |
| * 8bit Serdes revision number |
| */ |
| u8 hws_ctrl_serdes_rev_get(void) |
| { |
| #ifdef CONFIG_ARMADA_38X |
| /* for A38x-Z1 */ |
| if (sys_env_device_rev_get() == MV_88F68XX_Z1_ID) |
| return MV_SERDES_REV_1_2; |
| #endif |
| |
| /* for A39x-Z1, A38x-A0 */ |
| return MV_SERDES_REV_2_1; |
| } |
| |
| u32 hws_serdes_topology_verify(enum serdes_type serdes_type, u32 serdes_id, |
| enum serdes_mode serdes_mode) |
| { |
| u32 test_result = 0; |
| u8 serd_max_num, unit_numb; |
| enum unit_id unit_id; |
| |
| if (serdes_type > RXAUI) { |
| printf("%s: Warning: Wrong serdes type %s serdes#%d\n", |
| __func__, serdes_type_to_string[serdes_type], serdes_id); |
| return MV_FAIL; |
| } |
| |
| unit_id = serdes_type_to_unit_info[serdes_type].serdes_unit_id; |
| unit_numb = serdes_type_to_unit_info[serdes_type].serdes_unit_num; |
| serd_max_num = sys_env_unit_max_num_get(unit_id); |
| |
| /* if didn't exceed amount of required Serdes lanes for current type */ |
| if (serdes_lane_in_use_count[unit_id][unit_numb] != 0) { |
| /* update amount of required Serdes lanes for current type */ |
| serdes_lane_in_use_count[unit_id][unit_numb]--; |
| |
| /* |
| * If reached the exact amount of required Serdes lanes for |
| * current type |
| */ |
| if (serdes_lane_in_use_count[unit_id][unit_numb] == 0) { |
| if (((serdes_type <= PEX3)) && |
| ((serdes_mode == PEX_END_POINT_X4) || |
| (serdes_mode == PEX_ROOT_COMPLEX_X4))) { |
| /* PCiex4 uses 2 SerDes */ |
| serdes_unit_count[PEX_UNIT_ID] += 2; |
| } else { |
| serdes_unit_count[unit_id]++; |
| } |
| |
| /* test SoC unit count limitation */ |
| if (serdes_unit_count[unit_id] > serd_max_num) { |
| test_result = WRONG_NUMBER_OF_UNITS; |
| } else if (unit_numb >= serd_max_num) { |
| /* test SoC unit number limitation */ |
| test_result = UNIT_NUMBER_VIOLATION; |
| } |
| } |
| } 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; |
| } |
| |
| return MV_OK; |
| } |
| |
| void hws_serdes_xaui_topology_verify(void) |
| { |
| /* |
| * If XAUI is in use - serdes_lane_in_use_count has to be = 0; |
| * if it is not in use hast be = 4 |
| */ |
| if ((serdes_lane_in_use_count[XAUI_UNIT_ID][0] != 0) && |
| (serdes_lane_in_use_count[XAUI_UNIT_ID][0] != 4)) { |
| printf("%s: Warning: wrong number of lanes is set to XAUI - %d\n", |
| __func__, serdes_lane_in_use_count[XAUI_UNIT_ID][0]); |
| printf("%s: XAUI has to be defined on 4 lanes\n", __func__); |
| } |
| |
| /* |
| * If RXAUI is in use - serdes_lane_in_use_count has to be = 0; |
| * if it is not in use hast be = 2 |
| */ |
| if ((serdes_lane_in_use_count[RXAUI_UNIT_ID][0] != 0) && |
| (serdes_lane_in_use_count[RXAUI_UNIT_ID][0] != 2)) { |
| printf("%s: Warning: wrong number of lanes is set to RXAUI - %d\n", |
| __func__, serdes_lane_in_use_count[RXAUI_UNIT_ID][0]); |
| printf("%s: RXAUI has to be defined on 2 lanes\n", __func__); |
| } |
| } |
| |
| int hws_serdes_seq_db_init(void) |
| { |
| u8 serdes_rev = hws_ctrl_serdes_rev_get(); |
| |
| DEBUG_INIT_FULL_S("\n### serdes_seq38x_init ###\n"); |
| |
| if (serdes_rev == MV_SERDES_REV_NA) { |
| printf("hws_serdes_seq_db_init: serdes revision number is not supported\n"); |
| return MV_NOT_SUPPORTED; |
| } |
| |
| /* SATA_PORT_0_ONLY_POWER_UP_SEQ sequence init */ |
| serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].op_params_ptr = |
| sata_port0_power_up_params; |
| serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].cfg_seq_size = |
| sizeof(sata_port0_power_up_params) / sizeof(struct op_params); |
| serdes_seq_db[SATA_PORT_0_ONLY_POWER_UP_SEQ].data_arr_idx = SATA; |
| |
| /* SATA_PORT_1_ONLY_POWER_UP_SEQ sequence init */ |
| serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].op_params_ptr = |
| sata_port1_power_up_params; |
| serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].cfg_seq_size = |
| sizeof(sata_port1_power_up_params) / sizeof(struct op_params); |
| serdes_seq_db[SATA_PORT_1_ONLY_POWER_UP_SEQ].data_arr_idx = SATA; |
| |
| /* SATA_POWER_UP_SEQ sequence init */ |
| serdes_seq_db[SATA_POWER_UP_SEQ].op_params_ptr = |
| sata_and_sgmii_power_up_params; |
| serdes_seq_db[SATA_POWER_UP_SEQ].cfg_seq_size = |
| sizeof(sata_and_sgmii_power_up_params) / sizeof(struct op_params); |
| serdes_seq_db[SATA_POWER_UP_SEQ].data_arr_idx = SATA; |
| |
| /* SATA_1_5_SPEED_CONFIG_SEQ sequence init */ |
| serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].op_params_ptr = |
| sata_and_sgmii_speed_config_params; |
| serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sata_and_sgmii_speed_config_params) / |
| sizeof(struct op_params); |
| serdes_seq_db[SATA_1_5_SPEED_CONFIG_SEQ].data_arr_idx = SATA; |
| |
| /* SATA_3_SPEED_CONFIG_SEQ sequence init */ |
| serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].op_params_ptr = |
| sata_and_sgmii_speed_config_params; |
| serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sata_and_sgmii_speed_config_params) / |
| sizeof(struct op_params); |
| serdes_seq_db[SATA_3_SPEED_CONFIG_SEQ].data_arr_idx = SATA; |
| |
| /* SATA_6_SPEED_CONFIG_SEQ sequence init */ |
| serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].op_params_ptr = |
| sata_and_sgmii_speed_config_params; |
| serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sata_and_sgmii_speed_config_params) / |
| sizeof(struct op_params); |
| serdes_seq_db[SATA_6_SPEED_CONFIG_SEQ].data_arr_idx = SATA; |
| |
| /* SATA_ELECTRICAL_CONFIG_SEQ seq sequence init */ |
| if (serdes_rev == MV_SERDES_REV_1_2) { |
| serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].op_params_ptr = |
| sata_electrical_config_serdes_rev1_params; |
| serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sata_electrical_config_serdes_rev1_params) / |
| sizeof(struct op_params); |
| } else { |
| serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].op_params_ptr = |
| sata_electrical_config_serdes_rev2_params; |
| serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sata_electrical_config_serdes_rev2_params) / |
| sizeof(struct op_params); |
| } |
| serdes_seq_db[SATA_ELECTRICAL_CONFIG_SEQ].data_arr_idx = SATA; |
| |
| /* SATA_TX_CONFIG_SEQ sequence init */ |
| serdes_seq_db[SATA_TX_CONFIG_SEQ1].op_params_ptr = |
| sata_and_sgmii_tx_config_params1; |
| serdes_seq_db[SATA_TX_CONFIG_SEQ1].cfg_seq_size = |
| sizeof(sata_and_sgmii_tx_config_params1) / sizeof(struct op_params); |
| serdes_seq_db[SATA_TX_CONFIG_SEQ1].data_arr_idx = SATA; |
| |
| /* SATA_PORT_0_ONLY_TX_CONFIG_SEQ sequence init */ |
| serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].op_params_ptr = |
| sata_port0_tx_config_params; |
| serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sata_port0_tx_config_params) / sizeof(struct op_params); |
| serdes_seq_db[SATA_PORT_0_ONLY_TX_CONFIG_SEQ].data_arr_idx = SATA; |
| |
| /* SATA_PORT_1_ONLY_TX_CONFIG_SEQ sequence init */ |
| serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].op_params_ptr = |
| sata_port1_tx_config_params; |
| serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sata_port1_tx_config_params) / sizeof(struct op_params); |
| serdes_seq_db[SATA_PORT_1_ONLY_TX_CONFIG_SEQ].data_arr_idx = SATA; |
| |
| /* SATA_TX_CONFIG_SEQ2 sequence init */ |
| if (serdes_rev == MV_SERDES_REV_1_2) { |
| serdes_seq_db[SATA_TX_CONFIG_SEQ2].op_params_ptr = |
| sata_and_sgmii_tx_config_serdes_rev1_params2; |
| serdes_seq_db[SATA_TX_CONFIG_SEQ2].cfg_seq_size = |
| sizeof(sata_and_sgmii_tx_config_serdes_rev1_params2) / |
| sizeof(struct op_params); |
| } else { |
| serdes_seq_db[SATA_TX_CONFIG_SEQ2].op_params_ptr = |
| sata_and_sgmii_tx_config_serdes_rev2_params2; |
| serdes_seq_db[SATA_TX_CONFIG_SEQ2].cfg_seq_size = |
| sizeof(sata_and_sgmii_tx_config_serdes_rev2_params2) / |
| sizeof(struct op_params); |
| } |
| serdes_seq_db[SATA_TX_CONFIG_SEQ2].data_arr_idx = SATA; |
| |
| /* SGMII_POWER_UP_SEQ sequence init */ |
| serdes_seq_db[SGMII_POWER_UP_SEQ].op_params_ptr = |
| sata_and_sgmii_power_up_params; |
| serdes_seq_db[SGMII_POWER_UP_SEQ].cfg_seq_size = |
| sizeof(sata_and_sgmii_power_up_params) / sizeof(struct op_params); |
| serdes_seq_db[SGMII_POWER_UP_SEQ].data_arr_idx = SGMII; |
| |
| /* SGMII_1_25_SPEED_CONFIG_SEQ sequence init */ |
| serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].op_params_ptr = |
| sata_and_sgmii_speed_config_params; |
| serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sata_and_sgmii_speed_config_params) / |
| sizeof(struct op_params); |
| serdes_seq_db[SGMII_1_25_SPEED_CONFIG_SEQ].data_arr_idx = SGMII; |
| |
| /* SGMII_3_125_SPEED_CONFIG_SEQ sequence init */ |
| serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].op_params_ptr = |
| sata_and_sgmii_speed_config_params; |
| serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sata_and_sgmii_speed_config_params) / |
| sizeof(struct op_params); |
| serdes_seq_db[SGMII_3_125_SPEED_CONFIG_SEQ].data_arr_idx = SGMII_3_125; |
| |
| /* SGMII_ELECTRICAL_CONFIG_SEQ seq sequence init */ |
| if (serdes_rev == MV_SERDES_REV_1_2) { |
| serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr = |
| sgmii_electrical_config_serdes_rev1_params; |
| serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sgmii_electrical_config_serdes_rev1_params) / |
| sizeof(struct op_params); |
| } else { |
| serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr = |
| sgmii_electrical_config_serdes_rev2_params; |
| serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = |
| sizeof(sgmii_electrical_config_serdes_rev2_params) / |
| sizeof(struct op_params); |
| } |
| serdes_seq_db[SGMII_ELECTRICAL_CONFIG_SEQ].data_arr_idx = SGMII; |
| |
| /* SGMII_TX_CONFIG_SEQ sequence init */ |
| serdes_seq_db[SGMII_TX_CONFIG_SEQ1].op_params_ptr = |
| sata_and_sgmii_tx_config_params1; |
| serdes_seq_db[SGMII_TX_CONFIG_SEQ1].cfg_seq_size = |
| sizeof(sata_and_sgmii_tx_config_params1) / sizeof(struct op_params); |
| serdes_seq_db[SGMII_TX_CONFIG_SEQ1].data_arr_idx = SGMII; |
| |
| /* SGMII_TX_CONFIG_SEQ sequence init */ |
| if (serdes_rev == MV_SERDES_REV_1_2) { |
| serdes_seq_db[SGMII_TX_CONFIG_SEQ2].op_params_ptr = |
| sata_and_sgmii_tx_config_serdes_rev1_params2; |
| serdes_seq_db[SGMII_TX_CONFIG_SEQ2].cfg_seq_size = |
| sizeof(sata_and_sgmii_tx_config_serdes_rev1_params2) / |
| sizeof(struct op_params); |
| } else { |
| serdes_seq_db[SGMII_TX_CONFIG_SEQ2].op_params_ptr = |
| sata_and_sgmii_tx_config_serdes_rev2_params2; |
| serdes_seq_db[SGMII_TX_CONFIG_SEQ2].cfg_seq_size = |
| sizeof(sata_and_sgmii_tx_config_serdes_rev2_params2) / |
| sizeof(struct op_params); |
| } |
| serdes_seq_db[SGMII_TX_CONFIG_SEQ2].data_arr_idx = SGMII; |
| |
| /* PEX_POWER_UP_SEQ sequence init */ |
| if (serdes_rev == MV_SERDES_REV_1_2) { |
| serdes_seq_db[PEX_POWER_UP_SEQ].op_params_ptr = |
| pex_and_usb3_power_up_serdes_rev1_params; |
| serdes_seq_db[PEX_POWER_UP_SEQ].cfg_seq_size = |
| sizeof(pex_and_usb3_power_up_serdes_rev1_params) / |
| sizeof(struct op_params); |
| } else { |
| serdes_seq_db[PEX_POWER_UP_SEQ].op_params_ptr = |
| pex_and_usb3_power_up_serdes_rev2_params; |
| serdes_seq_db[PEX_POWER_UP_SEQ].cfg_seq_size = |
| sizeof(pex_and_usb3_power_up_serdes_rev2_params) / |
| sizeof(struct op_params); |
| } |
| serdes_seq_db[PEX_POWER_UP_SEQ].data_arr_idx = PEX; |
| |
| /* PEX_2_5_SPEED_CONFIG_SEQ sequence init */ |
| serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].op_params_ptr = |
| pex_and_usb3_speed_config_params; |
| serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].cfg_seq_size = |
| sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params); |
| serdes_seq_db[PEX_2_5_SPEED_CONFIG_SEQ].data_arr_idx = |
| PEXSERDES_SPEED_2_5_GBPS; |
| |
| /* PEX_5_SPEED_CONFIG_SEQ sequence init */ |
| serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].op_params_ptr = |
| pex_and_usb3_speed_config_params; |
| serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].cfg_seq_size = |
| sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params); |
| serdes_seq_db[PEX_5_SPEED_CONFIG_SEQ].data_arr_idx = |
| PEXSERDES_SPEED_5_GBPS; |
| |
| /* PEX_ELECTRICAL_CONFIG_SEQ seq sequence init */ |
| if (serdes_rev == MV_SERDES_REV_1_2) { |
| serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].op_params_ptr = |
| pex_electrical_config_serdes_rev1_params; |
| serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = |
| sizeof(pex_electrical_config_serdes_rev1_params) / |
| sizeof(struct op_params); |
| } else { |
| serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].op_params_ptr = |
| pex_electrical_config_serdes_rev2_params; |
| serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = |
| sizeof(pex_electrical_config_serdes_rev2_params) / |
| sizeof(struct op_params); |
| } |
| serdes_seq_db[PEX_ELECTRICAL_CONFIG_SEQ].data_arr_idx = PEX; |
| |
| /* PEX_TX_CONFIG_SEQ1 sequence init */ |
| serdes_seq_db[PEX_TX_CONFIG_SEQ1].op_params_ptr = |
| pex_and_usb3_tx_config_params1; |
| serdes_seq_db[PEX_TX_CONFIG_SEQ1].cfg_seq_size = |
| sizeof(pex_and_usb3_tx_config_params1) / sizeof(struct op_params); |
| serdes_seq_db[PEX_TX_CONFIG_SEQ1].data_arr_idx = PEX; |
| |
| /* PEX_TX_CONFIG_SEQ2 sequence init */ |
| serdes_seq_db[PEX_TX_CONFIG_SEQ2].op_params_ptr = |
| pex_and_usb3_tx_config_params2; |
| serdes_seq_db[PEX_TX_CONFIG_SEQ2].cfg_seq_size = |
| sizeof(pex_and_usb3_tx_config_params2) / sizeof(struct op_params); |
| serdes_seq_db[PEX_TX_CONFIG_SEQ2].data_arr_idx = PEX; |
| |
| /* PEX_TX_CONFIG_SEQ3 sequence init */ |
| serdes_seq_db[PEX_TX_CONFIG_SEQ3].op_params_ptr = |
| pex_and_usb3_tx_config_params3; |
| serdes_seq_db[PEX_TX_CONFIG_SEQ3].cfg_seq_size = |
| sizeof(pex_and_usb3_tx_config_params3) / sizeof(struct op_params); |
| serdes_seq_db[PEX_TX_CONFIG_SEQ3].data_arr_idx = PEX; |
| |
| /* PEX_BY_4_CONFIG_SEQ sequence init */ |
| serdes_seq_db[PEX_BY_4_CONFIG_SEQ].op_params_ptr = |
| pex_by4_config_params; |
| serdes_seq_db[PEX_BY_4_CONFIG_SEQ].cfg_seq_size = |
| sizeof(pex_by4_config_params) / sizeof(struct op_params); |
| serdes_seq_db[PEX_BY_4_CONFIG_SEQ].data_arr_idx = PEX; |
| |
| /* PEX_CONFIG_REF_CLOCK_25MHZ_SEQ sequence init */ |
| serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].op_params_ptr = |
| pex_config_ref_clock25_m_hz; |
| serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].cfg_seq_size = |
| sizeof(pex_config_ref_clock25_m_hz) / sizeof(struct op_params); |
| serdes_seq_db[PEX_CONFIG_REF_CLOCK_25MHZ_SEQ].data_arr_idx = PEX; |
| |
| /* PEX_ELECTRICAL_CONFIG_REF_CLOCK_40MHZ_SEQ sequence init */ |
| serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].op_params_ptr = |
| pex_config_ref_clock40_m_hz; |
| serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].cfg_seq_size = |
| sizeof(pex_config_ref_clock40_m_hz) / sizeof(struct op_params); |
| serdes_seq_db[PEX_CONFIG_REF_CLOCK_40MHZ_SEQ].data_arr_idx = PEX; |
| |
| /* PEX_CONFIG_REF_CLOCK_100MHZ_SEQ sequence init */ |
| serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].op_params_ptr = |
| pex_config_ref_clock100_m_hz; |
| serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].cfg_seq_size = |
| sizeof(pex_config_ref_clock100_m_hz) / sizeof(struct op_params); |
| serdes_seq_db[PEX_CONFIG_REF_CLOCK_100MHZ_SEQ].data_arr_idx = PEX; |
| |
| /* USB3_POWER_UP_SEQ sequence init */ |
| if (serdes_rev == MV_SERDES_REV_1_2) { |
| serdes_seq_db[USB3_POWER_UP_SEQ].op_params_ptr = |
| pex_and_usb3_power_up_serdes_rev1_params; |
| serdes_seq_db[USB3_POWER_UP_SEQ].cfg_seq_size = |
| sizeof(pex_and_usb3_power_up_serdes_rev1_params) / |
| sizeof(struct op_params); |
| } else { |
| serdes_seq_db[USB3_POWER_UP_SEQ].op_params_ptr = |
| pex_and_usb3_power_up_serdes_rev2_params; |
| serdes_seq_db[USB3_POWER_UP_SEQ].cfg_seq_size = |
| sizeof(pex_and_usb3_power_up_serdes_rev2_params) / |
| sizeof(struct op_params); |
| } |
| serdes_seq_db[USB3_POWER_UP_SEQ].data_arr_idx = USB3; |
| |
| /* USB3_HOST_SPEED_CONFIG_SEQ sequence init */ |
| serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].op_params_ptr = |
| pex_and_usb3_speed_config_params; |
| serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].cfg_seq_size = |
| sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params); |
| serdes_seq_db[USB3_HOST_SPEED_CONFIG_SEQ].data_arr_idx = |
| USB3SERDES_SPEED_5_GBPS_HOST; |
| |
| /* USB3_DEVICE_SPEED_CONFIG_SEQ sequence init */ |
| serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].op_params_ptr = |
| pex_and_usb3_speed_config_params; |
| serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].cfg_seq_size = |
| sizeof(pex_and_usb3_speed_config_params) / sizeof(struct op_params); |
| serdes_seq_db[USB3_DEVICE_SPEED_CONFIG_SEQ].data_arr_idx = |
| USB3SERDES_SPEED_5_GBPS_DEVICE; |
| |
| /* USB3_ELECTRICAL_CONFIG_SEQ seq sequence init */ |
| if (serdes_rev == MV_SERDES_REV_1_2) { |
| serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].op_params_ptr = |
| usb3_electrical_config_serdes_rev1_params; |
| serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = |
| sizeof(usb3_electrical_config_serdes_rev1_params) / |
| sizeof(struct op_params); |
| } else { |
| serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].op_params_ptr = |
| usb3_electrical_config_serdes_rev2_params; |
| serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = |
| sizeof(usb3_electrical_config_serdes_rev2_params) / |
| sizeof(struct op_params); |
| } |
| serdes_seq_db[USB3_ELECTRICAL_CONFIG_SEQ].data_arr_idx = USB3; |
| |
| /* USB3_TX_CONFIG_SEQ sequence init */ |
| serdes_seq_db[USB3_TX_CONFIG_SEQ1].op_params_ptr = |
| pex_and_usb3_tx_config_params1; |
| serdes_seq_db[USB3_TX_CONFIG_SEQ1].cfg_seq_size = |
| sizeof(pex_and_usb3_tx_config_params1) / sizeof(struct op_params); |
| serdes_seq_db[USB3_TX_CONFIG_SEQ1].data_arr_idx = USB3; |
| |
| /* USB3_TX_CONFIG_SEQ sequence init */ |
| serdes_seq_db[USB3_TX_CONFIG_SEQ2].op_params_ptr = |
| pex_and_usb3_tx_config_params2; |
| serdes_seq_db[USB3_TX_CONFIG_SEQ2].cfg_seq_size = |
| sizeof(pex_and_usb3_tx_config_params2) / sizeof(struct op_params); |
| serdes_seq_db[USB3_TX_CONFIG_SEQ2].data_arr_idx = USB3; |
| |
| /* USB3_TX_CONFIG_SEQ sequence init */ |
| serdes_seq_db[USB3_TX_CONFIG_SEQ3].op_params_ptr = |
| pex_and_usb3_tx_config_params3; |
| serdes_seq_db[USB3_TX_CONFIG_SEQ3].cfg_seq_size = |
| sizeof(pex_and_usb3_tx_config_params3) / sizeof(struct op_params); |
| serdes_seq_db[USB3_TX_CONFIG_SEQ3].data_arr_idx = USB3; |
| |
| /* USB2_POWER_UP_SEQ sequence init */ |
| serdes_seq_db[USB2_POWER_UP_SEQ].op_params_ptr = usb2_power_up_params; |
| serdes_seq_db[USB2_POWER_UP_SEQ].cfg_seq_size = |
| sizeof(usb2_power_up_params) / sizeof(struct op_params); |
| serdes_seq_db[USB2_POWER_UP_SEQ].data_arr_idx = 0; |
| |
| /* USB3_DEVICE_CONFIG_SEQ sequence init */ |
| serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].op_params_ptr = |
| usb3_device_config_params; |
| serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].cfg_seq_size = |
| sizeof(usb3_device_config_params) / sizeof(struct op_params); |
| serdes_seq_db[USB3_DEVICE_CONFIG_SEQ].data_arr_idx = 0; /* Not relevant */ |
| |
| /* SERDES_POWER_DOWN_SEQ sequence init */ |
| serdes_seq_db[SERDES_POWER_DOWN_SEQ].op_params_ptr = |
| serdes_power_down_params; |
| serdes_seq_db[SERDES_POWER_DOWN_SEQ].cfg_seq_size = |
| sizeof(serdes_power_down_params) / |
| sizeof(struct op_params); |
| serdes_seq_db[SERDES_POWER_DOWN_SEQ].data_arr_idx = FIRST_CELL; |
| |
| if (serdes_rev == MV_SERDES_REV_2_1) { |
| /* QSGMII_POWER_UP_SEQ sequence init */ |
| serdes_seq_db[QSGMII_POWER_UP_SEQ].op_params_ptr = |
| qsgmii_port_power_up_params; |
| serdes_seq_db[QSGMII_POWER_UP_SEQ].cfg_seq_size = |
| sizeof(qsgmii_port_power_up_params) / |
| sizeof(struct op_params); |
| serdes_seq_db[QSGMII_POWER_UP_SEQ].data_arr_idx = |
| QSGMII_SEQ_IDX; |
| |
| /* QSGMII_5_SPEED_CONFIG_SEQ sequence init */ |
| serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].op_params_ptr = |
| qsgmii_port_speed_config_params; |
| serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].cfg_seq_size = |
| sizeof(qsgmii_port_speed_config_params) / |
| sizeof(struct op_params); |
| serdes_seq_db[QSGMII_5_SPEED_CONFIG_SEQ].data_arr_idx = |
| QSGMII_SEQ_IDX; |
| |
| /* QSGMII_ELECTRICAL_CONFIG_SEQ seq sequence init */ |
| serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].op_params_ptr = |
| qsgmii_port_electrical_config_params; |
| serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].cfg_seq_size = |
| sizeof(qsgmii_port_electrical_config_params) / |
| sizeof(struct op_params); |
| serdes_seq_db[QSGMII_ELECTRICAL_CONFIG_SEQ].data_arr_idx = |
| QSGMII_SEQ_IDX; |
| |
| /* QSGMII_TX_CONFIG_SEQ sequence init */ |
| serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].op_params_ptr = |
| qsgmii_port_tx_config_params1; |
| serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].cfg_seq_size = |
| sizeof(qsgmii_port_tx_config_params1) / |
| sizeof(struct op_params); |
| serdes_seq_db[QSGMII_TX_CONFIG_SEQ1].data_arr_idx = |
| QSGMII_SEQ_IDX; |
| |
| /* QSGMII_TX_CONFIG_SEQ sequence init */ |
| serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].op_params_ptr = |
| qsgmii_port_tx_config_params2; |
| serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].cfg_seq_size = |
| sizeof(qsgmii_port_tx_config_params2) / |
| sizeof(struct op_params); |
| serdes_seq_db[QSGMII_TX_CONFIG_SEQ2].data_arr_idx = |
| QSGMII_SEQ_IDX; |
| } |
| |
| return MV_OK; |
| } |
| |
| enum serdes_seq serdes_type_and_speed_to_speed_seq(enum serdes_type serdes_type, |
| enum serdes_speed baud_rate) |
| { |
| enum serdes_seq seq_id = SERDES_LAST_SEQ; |
| |
| DEBUG_INIT_FULL_S("\n### serdes_type_and_speed_to_speed_seq ###\n"); |
| switch (serdes_type) { |
| case PEX0: |
| case PEX1: |
| case PEX2: |
| case PEX3: |
| if (baud_rate == SERDES_SPEED_2_5_GBPS) |
| seq_id = PEX_2_5_SPEED_CONFIG_SEQ; |
| else if (baud_rate == SERDES_SPEED_5_GBPS) |
| seq_id = PEX_5_SPEED_CONFIG_SEQ; |
| break; |
| case USB3_HOST0: |
| case USB3_HOST1: |
| if (baud_rate == SERDES_SPEED_5_GBPS) |
| seq_id = USB3_HOST_SPEED_CONFIG_SEQ; |
| break; |
| case USB3_DEVICE: |
| if (baud_rate == SERDES_SPEED_5_GBPS) |
| seq_id = USB3_DEVICE_SPEED_CONFIG_SEQ; |
| break; |
| case SATA0: |
| case SATA1: |
| case SATA2: |
| case SATA3: |
| if (baud_rate == SERDES_SPEED_1_5_GBPS) |
| seq_id = SATA_1_5_SPEED_CONFIG_SEQ; |
| else if (baud_rate == SERDES_SPEED_3_GBPS) |
| seq_id = SATA_3_SPEED_CONFIG_SEQ; |
| else if (baud_rate == SERDES_SPEED_6_GBPS) |
| seq_id = SATA_6_SPEED_CONFIG_SEQ; |
| break; |
| case SGMII0: |
| case SGMII1: |
| case SGMII2: |
| #ifdef CONFIG_ARMADA_39X |
| case SGMII3: |
| #endif |
| if (baud_rate == SERDES_SPEED_1_25_GBPS) |
| seq_id = SGMII_1_25_SPEED_CONFIG_SEQ; |
| else if (baud_rate == SERDES_SPEED_3_125_GBPS) |
| seq_id = SGMII_3_125_SPEED_CONFIG_SEQ; |
| break; |
| case QSGMII: |
| seq_id = QSGMII_5_SPEED_CONFIG_SEQ; |
| break; |
| #ifdef CONFIG_ARMADA_39X |
| case XAUI: |
| seq_id = XAUI_3_125_SPEED_CONFIG_SEQ; |
| break; |
| case RXAUI: |
| seq_id = RXAUI_6_25_SPEED_CONFIG_SEQ; |
| break; |
| #endif |
| default: |
| return SERDES_LAST_SEQ; |
| } |
| |
| return seq_id; |
| } |
| |
| 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(" --------------------------------\n"); |
| 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[lane_num].serdes_speed, 2); |
| DEBUG_INIT_S(" | "); |
| DEBUG_INIT_S((char *) |
| serdes_type_to_string[serdes_map[lane_num]. |
| serdes_type]); |
| DEBUG_INIT_S("\t|\n"); |
| } |
| DEBUG_INIT_S(" --------------------------------\n"); |
| } |
| |
| int hws_pre_serdes_init_config(void) |
| { |
| u32 data; |
| |
| /* |
| * Configure Core PLL |
| */ |
| /* |
| * set PLL parameters |
| * bits[2:0] =0x3 (Core-PLL Kdiv) |
| * bits[20:12]=0x9f (Core-PLL Ndiv) |
| * bits[24:21]=0x7(Core-PLL VCO Band) |
| * bits[28:25]=0x1(Core-PLL Rlf) |
| * bits[31:29]=0x2(Core-PLL charge-pump adjust) |
| */ |
| reg_write(CORE_PLL_PARAMETERS_REG, 0x42e9f003); |
| |
| /* Enable PLL Configuration */ |
| data = reg_read(CORE_PLL_CONFIG_REG); |
| data = SET_BIT(data, 9); |
| reg_write(CORE_PLL_CONFIG_REG, data); |
| |
| return MV_OK; |
| } |
| |
| 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_VERSION); |
| DEBUG_INIT_S("\n"); |
| |
| /* Init serdes sequences DB */ |
| if (hws_serdes_seq_init() != MV_OK) { |
| printf("hws_ctrl_high_speed_serdes_phy_config: Error: Serdes initialization fail\n"); |
| return MV_FAIL; |
| } |
| |
| /* Board topology load */ |
| DEBUG_INIT_FULL_S |
| ("ctrl_high_speed_serdes_phy_config: Loading board topology..\n"); |
| 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_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_map, serdes_count)); |
| |
| DEBUG_INIT_FULL_S |
| ("\n### ctrl_high_speed_serdes_phy_config ended successfully ###\n"); |
| |
| DEBUG_INIT_S(ENDED_OK); |
| |
| return MV_OK; |
| } |
| |
| int serdes_polarity_config(u32 serdes_num, int is_rx) |
| { |
| u32 data; |
| u32 reg_addr; |
| u8 bit_off = (is_rx) ? 11 : 10; |
| |
| reg_addr = SERDES_REGS_LANE_BASE_OFFSET(serdes_num) + SYNC_PATTERN_REG; |
| data = reg_read(reg_addr); |
| data = SET_BIT(data, bit_off); |
| reg_write(reg_addr, data); |
| |
| return MV_OK; |
| } |
| |
| int hws_power_up_serdes_lanes(struct serdes_map *serdes_map, u8 count) |
| { |
| u32 serdes_id, serdes_lane_num; |
| enum ref_clock ref_clock; |
| enum serdes_type serdes_type; |
| enum serdes_speed serdes_speed; |
| enum serdes_mode serdes_mode; |
| int serdes_rx_polarity_swap; |
| int serdes_tx_polarity_swap; |
| int is_pex_enabled = 0; |
| |
| /* |
| * is_pex_enabled: |
| * Flag which indicates that one of the Serdes is of PEX. |
| * In this case, PEX unit will be initialized after Serdes power-up |
| */ |
| |
| DEBUG_INIT_FULL_S("\n### hws_power_up_serdes_lanes ###\n"); |
| |
| /* 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_map, count)); |
| |
| /* per Serdes Power Up */ |
| 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_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) |
| continue; |
| else if (serdes_type <= PEX3) /* PEX type */ |
| is_pex_enabled = 1; |
| |
| ref_clock = hws_serdes_get_ref_clock_val(serdes_type); |
| if (ref_clock == REF_CLOCK_UNSUPPORTED) { |
| DEBUG_INIT_S |
| ("hws_power_up_serdes_lanes: unsupported ref clock\n"); |
| return MV_NOT_SUPPORTED; |
| } |
| CHECK_STATUS(serdes_power_up_ctrl(serdes_lane_num, |
| 1, |
| serdes_type, |
| serdes_speed, |
| serdes_mode, ref_clock)); |
| |
| /* RX Polarity config */ |
| if (serdes_rx_polarity_swap) |
| CHECK_STATUS(serdes_polarity_config |
| (serdes_lane_num, 1)); |
| |
| /* TX Polarity config */ |
| if (serdes_tx_polarity_swap) |
| CHECK_STATUS(serdes_polarity_config |
| (serdes_lane_num, 0)); |
| } |
| |
| if (is_pex_enabled) { |
| /* 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_map, count)); |
| |
| /* PEX configuration */ |
| CHECK_STATUS(hws_pex_config(serdes_map, count)); |
| } |
| |
| /* USB2 configuration */ |
| DEBUG_INIT_FULL_S("hws_power_up_serdes_lanes: init USB2 Phys\n"); |
| CHECK_STATUS(mv_seq_exec(0 /* not relevant */ , USB2_POWER_UP_SEQ)); |
| |
| DEBUG_INIT_FULL_S |
| ("### hws_power_up_serdes_lanes ended successfully ###\n"); |
| |
| return MV_OK; |
| } |
| |
| int ctrl_high_speed_serdes_phy_config(void) |
| { |
| return hws_ctrl_high_speed_serdes_phy_config(); |
| } |
| |
| static int serdes_pex_usb3_pipe_delay_w_a(u32 serdes_num, u8 serdes_type) |
| { |
| u32 reg_data; |
| |
| /* WA for A380 Z1 relevant for lanes 3,4,5 only */ |
| if (serdes_num >= 3) { |
| reg_data = reg_read(GENERAL_PURPOSE_RESERVED0_REG); |
| /* set delay on pipe - |
| * When lane 3 is connected to a MAC of Pex -> set bit 7 to 1. |
| * When lane 3 is connected to a MAC of USB3 -> set bit 7 to 0. |
| * When lane 4 is connected to a MAC of Pex -> set bit 8 to 1. |
| * When lane 4 is connected to a MAC of USB3 -> set bit 8 to 0. |
| * When lane 5 is connected to a MAC of Pex -> set bit 8 to 1. |
| * When lane 5 is connected to a MAC of USB3 -> set bit 8 to 0. |
| */ |
| if (serdes_type == PEX) |
| reg_data |= 1 << (7 + (serdes_num - 3)); |
| if (serdes_type == USB3) { |
| /* USB3 */ |
| reg_data &= ~(1 << (7 + (serdes_num - 3))); |
| } |
| reg_write(GENERAL_PURPOSE_RESERVED0_REG, reg_data); |
| } |
| |
| return MV_OK; |
| } |
| |
| /* |
| * hws_serdes_pex_ref_clock_satr_get - |
| * |
| * DESCRIPTION: Get the reference clock value from DEVICE_SAMPLE_AT_RESET1_REG |
| * and check: |
| * bit[2] for PEX#0, bit[3] for PEX#1, bit[30] for PEX#2, bit[31] |
| * for PEX#3. |
| * If bit=0 --> REF_CLOCK_100MHz |
| * If bit=1 && DEVICE_SAMPLE_AT_RESET2_REG bit[0]=0 |
| * --> REF_CLOCK_25MHz |
| * If bit=1 && DEVICE_SAMPLE_AT_RESET2_REG bit[0]=1 |
| * --> REF_CLOCK_40MHz |
| * |
| * INPUT: serdes_type - Type of Serdes |
| * |
| * OUTPUT: pex_satr - Return the REF_CLOCK value: |
| * REF_CLOCK_25MHz, REF_CLOCK_40MHz or REF_CLOCK_100MHz |
| * |
| * RETURNS: MV_OK - for success |
| * MV_BAD_PARAM - for fail |
| */ |
| int hws_serdes_pex_ref_clock_satr_get(enum serdes_type serdes_type, u32 *pex_satr) |
| { |
| u32 data, reg_satr1; |
| |
| reg_satr1 = reg_read(DEVICE_SAMPLE_AT_RESET1_REG); |
| |
| switch (serdes_type) { |
| case PEX0: |
| data = REF_CLK_SELECTOR_VAL_PEX0(reg_satr1); |
| break; |
| case PEX1: |
| data = REF_CLK_SELECTOR_VAL_PEX1(reg_satr1); |
| break; |
| case PEX2: |
| data = REF_CLK_SELECTOR_VAL_PEX2(reg_satr1); |
| break; |
| case PEX3: |
| data = REF_CLK_SELECTOR_VAL_PEX3(reg_satr1); |
| break; |
| default: |
| printf("%s: Error: SerDes type %d is not supported\n", |
| __func__, serdes_type); |
| return MV_BAD_PARAM; |
| } |
| |
| *pex_satr = data; |
| |
| return MV_OK; |
| } |
| |
| u32 hws_serdes_get_ref_clock_val(enum serdes_type serdes_type) |
| { |
| u32 pex_satr; |
| enum ref_clock ref_clock; |
| |
| DEBUG_INIT_FULL_S("\n### hws_serdes_get_ref_clock_val ###\n"); |
| |
| if (serdes_type >= LAST_SERDES_TYPE) |
| return REF_CLOCK_UNSUPPORTED; |
| |
| /* read ref clock from S@R */ |
| ref_clock = hws_serdes_silicon_ref_clock_get(); |
| |
| if (serdes_type > PEX3) { |
| /* for all Serdes types but PCIe */ |
| return ref_clock; |
| } |
| |
| /* for PCIe, need also to check PCIe S@R */ |
| CHECK_STATUS(hws_serdes_pex_ref_clock_satr_get |
| (serdes_type, &pex_satr)); |
| |
| if (pex_satr == 0) { |
| return REF_CLOCK_100MHZ; |
| } else if (pex_satr == 1) { |
| /* value of 1 means we can use ref clock from SoC (as other Serdes types) */ |
| return ref_clock; |
| } else { |
| printf |
| ("%s: Error: REF_CLK_SELECTOR_VAL for SerDes type %d is wrong\n", |
| __func__, serdes_type); |
| return REF_CLOCK_UNSUPPORTED; |
| } |
| } |
| |
| int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up, |
| enum serdes_type serdes_type, |
| enum serdes_speed baud_rate, |
| enum serdes_mode serdes_mode, enum ref_clock ref_clock) |
| { |
| u32 sata_idx, pex_idx, sata_port; |
| enum serdes_seq speed_seq_id; |
| u32 reg_data; |
| int is_pex_by1; |
| |
| DEBUG_INIT_FULL_S("\n### serdes_power_up_ctrl ###\n"); |
| |
| if (serdes_power_up == 1) { /* Serdes power up */ |
| DEBUG_INIT_FULL_S |
| ("serdes_power_up_ctrl: executing power up.. "); |
| DEBUG_INIT_FULL_C("serdes num = ", serdes_num, 2); |
| DEBUG_INIT_FULL_C("serdes type = ", serdes_type, 2); |
| |
| DEBUG_INIT_FULL_S("Going access 1"); |
| |
| /* Getting the Speed Select sequence id */ |
| speed_seq_id = |
| serdes_type_and_speed_to_speed_seq(serdes_type, |
| baud_rate); |
| if (speed_seq_id == SERDES_LAST_SEQ) { |
| printf |
| ("serdes_power_up_ctrl: serdes type %d and speed %d are not supported together\n", |
| serdes_type, baud_rate); |
| |
| return MV_BAD_PARAM; |
| } |
| |
| /* Executing power up, ref clock set, speed config and TX config */ |
| switch (serdes_type) { |
| case PEX0: |
| case PEX1: |
| case PEX2: |
| case PEX3: |
| if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) { |
| CHECK_STATUS(serdes_pex_usb3_pipe_delay_w_a |
| (serdes_num, PEX)); |
| } |
| |
| is_pex_by1 = (serdes_mode == PEX_ROOT_COMPLEX_X1) || |
| (serdes_mode == PEX_END_POINT_X1); |
| pex_idx = serdes_type - PEX0; |
| |
| if ((is_pex_by1 == 1) || (serdes_type == PEX0)) { |
| /* For PEX by 4, init only the PEX 0 */ |
| reg_data = reg_read(SOC_CONTROL_REG1); |
| if (is_pex_by1 == 1) |
| reg_data |= 0x4000; |
| else |
| reg_data &= ~0x4000; |
| reg_write(SOC_CONTROL_REG1, reg_data); |
| |
| reg_data = |
| reg_read(((PEX_IF_REGS_BASE(pex_idx)) + |
| 0x6c)); |
| reg_data &= ~0x3f0; |
| if (is_pex_by1 == 1) |
| reg_data |= 0x10; |
| else |
| reg_data |= 0x40; |
| reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c), |
| reg_data); |
| |
| reg_data = |
| reg_read(((PEX_IF_REGS_BASE(pex_idx)) + |
| 0x6c)); |
| reg_data &= ~0xf; |
| reg_data |= 0x2; |
| reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c), |
| reg_data); |
| |
| reg_data = |
| reg_read(((PEX_IF_REGS_BASE(pex_idx)) + |
| 0x70)); |
| reg_data &= ~0x40; |
| reg_data |= 0x40; |
| reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x70), |
| reg_data); |
| } |
| |
| CHECK_STATUS(mv_seq_exec(serdes_num, PEX_POWER_UP_SEQ)); |
| if (is_pex_by1 == 0) { |
| /* |
| * for PEX by 4 - use the PEX index as the |
| * seq array index |
| */ |
| serdes_seq_db[PEX_BY_4_CONFIG_SEQ]. |
| data_arr_idx = pex_idx; |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, PEX_BY_4_CONFIG_SEQ)); |
| } |
| |
| CHECK_STATUS(hws_ref_clock_set |
| (serdes_num, serdes_type, ref_clock)); |
| CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, PEX_ELECTRICAL_CONFIG_SEQ)); |
| |
| if (is_pex_by1 == 1) { |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, PEX_TX_CONFIG_SEQ2)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, PEX_TX_CONFIG_SEQ3)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, PEX_TX_CONFIG_SEQ1)); |
| } |
| udelay(20); |
| |
| break; |
| case USB3_HOST0: |
| case USB3_HOST1: |
| case USB3_DEVICE: |
| if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) { |
| CHECK_STATUS(serdes_pex_usb3_pipe_delay_w_a |
| (serdes_num, USB3)); |
| } |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, USB3_POWER_UP_SEQ)); |
| CHECK_STATUS(hws_ref_clock_set |
| (serdes_num, serdes_type, ref_clock)); |
| CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id)); |
| if (serdes_type == USB3_DEVICE) { |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, |
| USB3_DEVICE_CONFIG_SEQ)); |
| } |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, USB3_ELECTRICAL_CONFIG_SEQ)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, USB3_TX_CONFIG_SEQ1)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, USB3_TX_CONFIG_SEQ2)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, USB3_TX_CONFIG_SEQ3)); |
| |
| udelay(10000); |
| break; |
| case SATA0: |
| case SATA1: |
| case SATA2: |
| case SATA3: |
| sata_idx = ((serdes_type == SATA0) || |
| (serdes_type == SATA1)) ? 0 : 1; |
| sata_port = ((serdes_type == SATA0) || |
| (serdes_type == SATA2)) ? 0 : 1; |
| |
| CHECK_STATUS(mv_seq_exec |
| (sata_idx, (sata_port == 0) ? |
| SATA_PORT_0_ONLY_POWER_UP_SEQ : |
| SATA_PORT_1_ONLY_POWER_UP_SEQ)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, SATA_POWER_UP_SEQ)); |
| CHECK_STATUS(hws_ref_clock_set |
| (serdes_num, serdes_type, ref_clock)); |
| CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, SATA_ELECTRICAL_CONFIG_SEQ)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, SATA_TX_CONFIG_SEQ1)); |
| CHECK_STATUS(mv_seq_exec |
| (sata_idx, (sata_port == 0) ? |
| SATA_PORT_0_ONLY_TX_CONFIG_SEQ : |
| SATA_PORT_1_ONLY_TX_CONFIG_SEQ)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, SATA_TX_CONFIG_SEQ2)); |
| |
| udelay(10000); |
| break; |
| case SGMII0: |
| case SGMII1: |
| case SGMII2: |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, SGMII_POWER_UP_SEQ)); |
| CHECK_STATUS(hws_ref_clock_set |
| (serdes_num, serdes_type, ref_clock)); |
| CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, SGMII_ELECTRICAL_CONFIG_SEQ)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, SGMII_TX_CONFIG_SEQ1)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, SGMII_TX_CONFIG_SEQ2)); |
| |
| /* GBE configuration */ |
| reg_data = reg_read(GBE_CONFIGURATION_REG); |
| /* write the SGMII index */ |
| reg_data |= 0x1 << (serdes_type - SGMII0); |
| reg_write(GBE_CONFIGURATION_REG, reg_data); |
| |
| break; |
| case QSGMII: |
| if (hws_ctrl_serdes_rev_get() < MV_SERDES_REV_2_1) |
| return MV_NOT_SUPPORTED; |
| |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, QSGMII_POWER_UP_SEQ)); |
| CHECK_STATUS(hws_ref_clock_set |
| (serdes_num, serdes_type, ref_clock)); |
| CHECK_STATUS(mv_seq_exec(serdes_num, speed_seq_id)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, |
| QSGMII_ELECTRICAL_CONFIG_SEQ)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, QSGMII_TX_CONFIG_SEQ1)); |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, QSGMII_TX_CONFIG_SEQ2)); |
| break; |
| case SGMII3: |
| case XAUI: |
| case RXAUI: |
| CHECK_STATUS(serdes_power_up_ctrl_ext |
| (serdes_num, serdes_power_up, serdes_type, |
| baud_rate, serdes_mode, ref_clock)); |
| break; |
| default: |
| DEBUG_INIT_S |
| ("serdes_power_up_ctrl: bad serdes_type parameter\n"); |
| return MV_BAD_PARAM; |
| } |
| } else { /* Serdes power down */ |
| DEBUG_INIT_FULL_S("serdes_power_up: executing power down.. "); |
| DEBUG_INIT_FULL_C("serdes num = ", serdes_num, 1); |
| |
| CHECK_STATUS(mv_seq_exec(serdes_num, SERDES_POWER_DOWN_SEQ)); |
| } |
| |
| DEBUG_INIT_FULL_C( |
| "serdes_power_up_ctrl ended successfully for serdes ", |
| serdes_num, 2); |
| |
| return MV_OK; |
| } |
| |
| 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; |
| enum serdes_mode serdes_mode; |
| u8 select_bit_off; |
| int is_pex_x4 = 0; |
| int updated_topology_print = 0; |
| |
| DEBUG_INIT_FULL_S("\n### hws_update_serdes_phy_selectors ###\n"); |
| DEBUG_INIT_FULL_S |
| ("Updating the COMMON PHYS SELECTORS register with the serdes types\n"); |
| |
| if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) |
| select_bit_off = 3; |
| else |
| select_bit_off = 4; |
| |
| /* |
| * Updating bits 0-17 in the COMMON PHYS SELECTORS register |
| * according to the serdes types |
| */ |
| 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 = |
| hws_serdes_get_phy_selector_val(serdes_lane_hw_num, |
| serdes_type); |
| |
| if (serdes_type == DEFAULT_SERDES) |
| continue; |
| |
| if (hws_serdes_topology_verify |
| (serdes_type, idx, serdes_mode) != MV_OK) { |
| serdes_map[idx].serdes_type = |
| DEFAULT_SERDES; |
| printf("%s: SerDes lane #%d is disabled\n", __func__, |
| serdes_lane_hw_num); |
| updated_topology_print = 1; |
| continue; |
| } |
| |
| /* |
| * Checking if the board topology configuration includes |
| * PEXx4 - for the next step |
| */ |
| if ((serdes_mode == PEX_END_POINT_X4) || |
| (serdes_mode == PEX_ROOT_COMPLEX_X4)) { |
| /* update lane data to the 3 next SERDES lanes */ |
| lane_data = |
| common_phys_selectors_pex_by4_lanes |
| [serdes_lane_hw_num]; |
| if (serdes_type == PEX0) |
| is_pex_x4 = 1; |
| } |
| |
| if (lane_data == NA) { |
| printf |
| ("%s: Warning: SerDes lane #%d and type %d are not supported together\n", |
| __func__, serdes_lane_hw_num, serdes_mode); |
| serdes_map[idx].serdes_type = DEFAULT_SERDES; |
| printf("%s: SerDes lane #%d is disabled\n", __func__, |
| serdes_lane_hw_num); |
| continue; |
| } |
| |
| /* |
| * Updating the data that will be written to |
| * COMMON_PHYS_SELECTORS_REG |
| */ |
| reg_data |= (lane_data << |
| (select_bit_off * serdes_lane_hw_num)); |
| } |
| |
| /* |
| * Check that number of used lanes for XAUI and RXAUI |
| * (if used) is right |
| */ |
| hws_serdes_xaui_topology_verify(); |
| |
| /* Print topology */ |
| if (updated_topology_print) |
| print_topology_details(serdes_map, count); |
| |
| /* |
| * Updating the PEXx4 Enable bit in the COMMON PHYS SELECTORS |
| * register for PEXx4 mode |
| */ |
| reg_data |= (is_pex_x4 == 1) ? (0x1 << PEX_X4_ENABLE_OFFS) : 0; |
| |
| /* Updating the COMMON PHYS SELECTORS register */ |
| reg_write(COMMON_PHYS_SELECTORS_REG, reg_data); |
| |
| return MV_OK; |
| } |
| |
| int hws_ref_clock_set(u32 serdes_num, enum serdes_type serdes_type, |
| enum ref_clock ref_clock) |
| { |
| u32 data1 = 0, data2 = 0, data3 = 0, reg_data; |
| |
| DEBUG_INIT_FULL_S("\n### hws_ref_clock_set ###\n"); |
| |
| if (hws_is_serdes_active(serdes_num) != 1) { |
| printf("%s: SerDes lane #%d is not Active\n", __func__, |
| serdes_num); |
| return MV_BAD_PARAM; |
| } |
| |
| switch (serdes_type) { |
| case PEX0: |
| case PEX1: |
| case PEX2: |
| case PEX3: |
| switch (ref_clock) { |
| case REF_CLOCK_25MHZ: |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, |
| PEX_CONFIG_REF_CLOCK_25MHZ_SEQ)); |
| return MV_OK; |
| case REF_CLOCK_100MHZ: |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, |
| PEX_CONFIG_REF_CLOCK_100MHZ_SEQ)); |
| return MV_OK; |
| #ifdef CONFIG_ARMADA_39X |
| case REF_CLOCK_40MHZ: |
| CHECK_STATUS(mv_seq_exec |
| (serdes_num, |
| PEX_CONFIG_REF_CLOCK_40MHZ_SEQ)); |
| return MV_OK; |
| #endif |
| default: |
| printf |
| ("%s: Error: ref_clock %d for SerDes lane #%d, type %d is not supported\n", |
| __func__, ref_clock, serdes_num, serdes_type); |
| return MV_BAD_PARAM; |
| } |
| case USB3_HOST0: |
| case USB3_HOST1: |
| case USB3_DEVICE: |
| if (ref_clock == REF_CLOCK_25MHZ) { |
| data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_2; |
| data2 = GLOBAL_PM_CTRL_REG_25MHZ_VAL; |
| data3 = LANE_CFG4_REG_25MHZ_VAL; |
| } else if (ref_clock == REF_CLOCK_40MHZ) { |
| data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL; |
| data2 = GLOBAL_PM_CTRL_REG_40MHZ_VAL; |
| data3 = LANE_CFG4_REG_40MHZ_VAL; |
| } else { |
| printf |
| ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n", |
| serdes_type); |
| return MV_BAD_PARAM; |
| } |
| break; |
| case SATA0: |
| case SATA1: |
| case SATA2: |
| case SATA3: |
| case SGMII0: |
| case SGMII1: |
| case SGMII2: |
| case QSGMII: |
| if (ref_clock == REF_CLOCK_25MHZ) { |
| data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1; |
| } else if (ref_clock == REF_CLOCK_40MHZ) { |
| data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL; |
| } else { |
| printf |
| ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n", |
| serdes_type); |
| return MV_BAD_PARAM; |
| } |
| break; |
| #ifdef CONFIG_ARMADA_39X |
| case SGMII3: |
| case XAUI: |
| case RXAUI: |
| if (ref_clock == REF_CLOCK_25MHZ) { |
| data1 = POWER_AND_PLL_CTRL_REG_25MHZ_VAL_1; |
| } else if (ref_clock == REF_CLOCK_40MHZ) { |
| data1 = POWER_AND_PLL_CTRL_REG_40MHZ_VAL; |
| } else { |
| printf |
| ("hws_ref_clock_set: ref clock is not valid for serdes type %d\n", |
| serdes_type); |
| return MV_BAD_PARAM; |
| } |
| break; |
| #endif |
| default: |
| DEBUG_INIT_S("hws_ref_clock_set: not supported serdes type\n"); |
| return MV_BAD_PARAM; |
| } |
| |
| /* |
| * Write the ref_clock to relevant SELECT_REF_CLOCK_REG bits and |
| * offset |
| */ |
| reg_data = reg_read(POWER_AND_PLL_CTRL_REG + |
| SERDES_REGS_LANE_BASE_OFFSET(serdes_num)); |
| reg_data &= POWER_AND_PLL_CTRL_REG_MASK; |
| reg_data |= data1; |
| reg_write(POWER_AND_PLL_CTRL_REG + |
| SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data); |
| |
| if ((serdes_type == USB3_HOST0) || (serdes_type == USB3_HOST1) || |
| (serdes_type == USB3_DEVICE)) { |
| reg_data = reg_read(GLOBAL_PM_CTRL + |
| SERDES_REGS_LANE_BASE_OFFSET(serdes_num)); |
| reg_data &= GLOBAL_PM_CTRL_REG_MASK; |
| reg_data |= data2; |
| reg_write(GLOBAL_PM_CTRL + |
| SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data); |
| |
| reg_data = reg_read(LANE_CFG4_REG + |
| SERDES_REGS_LANE_BASE_OFFSET(serdes_num)); |
| reg_data &= LANE_CFG4_REG_MASK; |
| reg_data |= data3; |
| reg_write(LANE_CFG4_REG + |
| SERDES_REGS_LANE_BASE_OFFSET(serdes_num), reg_data); |
| } |
| |
| return MV_OK; |
| } |
| |
| /* |
| * hws_pex_tx_config_seq - |
| * |
| * DESCRIPTION: Set PEX_TX_CONFIG_SEQ sequence init for PEXx4 mode |
| * INPUT: serdes_map - The board topology map |
| * OUTPUT: None |
| * RETURNS: MV_OK - for success |
| * MV_BAD_PARAM - for fail |
| */ |
| 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; |
| |
| DEBUG_INIT_FULL_S("\n### hws_pex_tx_config_seq ###\n"); |
| |
| /* |
| * For PEXx4: the pex_and_usb3_tx_config_params1/2/3 |
| * configurations should run by setting each sequence for |
| * all 4 lanes. |
| */ |
| |
| /* relese pipe soft reset for all lanes */ |
| 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); |
| |
| if ((serdes_mode == PEX_ROOT_COMPLEX_X4) || |
| (serdes_mode == PEX_END_POINT_X4)) { |
| CHECK_STATUS(mv_seq_exec |
| (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ1)); |
| } |
| } |
| |
| /* set phy soft reset for all lanes */ |
| 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); |
| if ((serdes_mode == PEX_ROOT_COMPLEX_X4) || |
| (serdes_mode == PEX_END_POINT_X4)) { |
| CHECK_STATUS(mv_seq_exec |
| (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ2)); |
| } |
| } |
| |
| /* set phy soft reset for all lanes */ |
| 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); |
| if ((serdes_mode == PEX_ROOT_COMPLEX_X4) || |
| (serdes_mode == PEX_END_POINT_X4)) { |
| CHECK_STATUS(mv_seq_exec |
| (serdes_lane_hw_num, PEX_TX_CONFIG_SEQ3)); |
| } |
| } |
| |
| return MV_OK; |
| } |