mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-17 01:54:22 +00:00

In Armada 8K DB boards, PCIe initialization can be executed only once because PCIe reset performed during chip power on and it cannot be executed via GPIO later. This means that power on can be executed only once, when it's called from the bootloader. Power on: Read bit 21 of the mode, it marks if the caller is the bootloader or the Linux Kernel. Power off: Check if the comphy was already configured to PCIe, if yes, check if the caller is bootloader, if both conditions are true (PCIe mode and called by Linux) - skip the power-off. In addition, fix incorrect documentation describing mode fields - PCIe width is 3 bits, not 2. NOTE: with this patch, please use LK4.14.76 (LK4.4.120 may not work with it). Change-Id: I4b929011f97a0a1869a51ba378687e78b3eca4ff Signed-off-by: Igal Liberman <igall@marvell.com> Reviewed-by: Grzegorz Jaszczyk <jaz@semihalf.com> Reviewed-by: Kostya Porotchkin <kostap@marvell.com>
2484 lines
87 KiB
C
2484 lines
87 KiB
C
/*
|
|
* Copyright (C) 2018 Marvell International Ltd.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
* https://spdx.org/licenses
|
|
*/
|
|
|
|
/* Marvell CP110 SoC COMPHY unit driver */
|
|
|
|
#include <debug.h>
|
|
#include <delay_timer.h>
|
|
#include <errno.h>
|
|
#include <mmio.h>
|
|
#include <mvebu_def.h>
|
|
#include <spinlock.h>
|
|
#include "mvebu.h"
|
|
#include "comphy-cp110.h"
|
|
#include "phy-comphy-cp110.h"
|
|
#include "phy-comphy-common.h"
|
|
|
|
#if __has_include("phy-porting-layer.h")
|
|
#include "phy-porting-layer.h"
|
|
#else
|
|
#include "phy-default-porting-layer.h"
|
|
#endif
|
|
|
|
/* COMPHY speed macro */
|
|
#define COMPHY_SPEED_1_25G 0 /* SGMII 1G */
|
|
#define COMPHY_SPEED_2_5G 1
|
|
#define COMPHY_SPEED_3_125G 2 /* SGMII 2.5G */
|
|
#define COMPHY_SPEED_5G 3
|
|
#define COMPHY_SPEED_5_15625G 4 /* XFI 5G */
|
|
#define COMPHY_SPEED_6G 5
|
|
#define COMPHY_SPEED_10_3125G 6 /* XFI 10G */
|
|
#define COMPHY_SPEED_MAX 0x3F
|
|
/* The default speed for IO with fixed known speed */
|
|
#define COMPHY_SPEED_DEFAULT COMPHY_SPEED_MAX
|
|
|
|
/* Commands for comphy driver */
|
|
#define COMPHY_COMMAND_DIGITAL_PWR_OFF 0x00000001
|
|
#define COMPHY_COMMAND_DIGITAL_PWR_ON 0x00000002
|
|
|
|
#define COMPHY_PIPE_FROM_COMPHY_ADDR(x) ((x & ~0xffffff) + 0x120000)
|
|
|
|
/* System controller registers */
|
|
#define PCIE_MAC_RESET_MASK_PORT0 BIT(13)
|
|
#define PCIE_MAC_RESET_MASK_PORT1 BIT(11)
|
|
#define PCIE_MAC_RESET_MASK_PORT2 BIT(12)
|
|
#define SYS_CTRL_UINIT_SOFT_RESET_REG 0x268
|
|
#define SYS_CTRL_FROM_COMPHY_ADDR(x) ((x & ~0xffffff) + 0x440000)
|
|
|
|
/* DFX register spaces */
|
|
#define SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET (0)
|
|
#define SAR_RST_PCIE0_CLOCK_CONFIG_CP1_MASK (0x1 << \
|
|
SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET)
|
|
#define SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET (1)
|
|
#define SAR_RST_PCIE1_CLOCK_CONFIG_CP1_MASK (0x1 << \
|
|
SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET)
|
|
#define SAR_STATUS_0_REG 200
|
|
#define DFX_FROM_COMPHY_ADDR(x) ((x & ~0xffffff) + DFX_BASE)
|
|
|
|
/* The same Units Soft Reset Config register are accessed in all PCIe ports
|
|
* initialization, so a spin lock is defined in case when more than 1 CPUs
|
|
* resets PCIe MAC and need to access the register in the same time. The spin
|
|
* lock is shared by all CP110 units.
|
|
*/
|
|
spinlock_t cp110_mac_reset_lock;
|
|
|
|
/* These values come from the PCI Express Spec */
|
|
enum pcie_link_width {
|
|
PCIE_LNK_WIDTH_RESRV = 0x00,
|
|
PCIE_LNK_X1 = 0x01,
|
|
PCIE_LNK_X2 = 0x02,
|
|
PCIE_LNK_X4 = 0x04,
|
|
PCIE_LNK_X8 = 0x08,
|
|
PCIE_LNK_X12 = 0x0C,
|
|
PCIE_LNK_X16 = 0x10,
|
|
PCIE_LNK_X32 = 0x20,
|
|
PCIE_LNK_WIDTH_UNKNOWN = 0xFF,
|
|
};
|
|
|
|
_Bool rx_trainng_done[AP_NUM][CP_NUM][MAX_LANE_NR] = {0};
|
|
|
|
static void mvebu_cp110_get_ap_and_cp_nr(uint8_t *ap_nr, uint8_t *cp_nr,
|
|
uint64_t comphy_base)
|
|
{
|
|
#if (AP_NUM == 1)
|
|
*ap_nr = 0;
|
|
#else
|
|
*ap_nr = (((comphy_base & ~0xffffff) - MVEBU_AP_IO_BASE(0)) /
|
|
AP_IO_OFFSET);
|
|
#endif
|
|
|
|
*cp_nr = (((comphy_base & ~0xffffff) - MVEBU_AP_IO_BASE(*ap_nr)) /
|
|
MVEBU_CP_OFFSET);
|
|
|
|
debug("cp_base 0x%llx, ap_io_base 0x%lx, cp_offset 0x%lx\n",
|
|
comphy_base, (unsigned long)MVEBU_AP_IO_BASE(*ap_nr),
|
|
(unsigned long)MVEBU_CP_OFFSET);
|
|
}
|
|
|
|
/* Clear PIPE selector - avoid collision with previous configuration */
|
|
static void mvebu_cp110_comphy_clr_pipe_selector(uint64_t comphy_base,
|
|
uint8_t comphy_index)
|
|
{
|
|
uint32_t reg, mask, field;
|
|
uint32_t comphy_offset =
|
|
COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
|
|
|
|
mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset;
|
|
reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET);
|
|
field = reg & mask;
|
|
|
|
if (field) {
|
|
reg &= ~mask;
|
|
mmio_write_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET,
|
|
reg);
|
|
}
|
|
}
|
|
|
|
/* Clear PHY selector - avoid collision with previous configuration */
|
|
static void mvebu_cp110_comphy_clr_phy_selector(uint64_t comphy_base,
|
|
uint8_t comphy_index)
|
|
{
|
|
uint32_t reg, mask, field;
|
|
uint32_t comphy_offset =
|
|
COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
|
|
|
|
mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset;
|
|
reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET);
|
|
field = reg & mask;
|
|
|
|
/* Clear comphy selector - if it was already configured.
|
|
* (might be that this comphy was configured as PCIe/USB,
|
|
* in such case, no need to clear comphy selector because PCIe/USB
|
|
* are controlled by hpipe selector).
|
|
*/
|
|
if (field) {
|
|
reg &= ~mask;
|
|
mmio_write_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET,
|
|
reg);
|
|
}
|
|
}
|
|
|
|
/* PHY selector configures SATA and Network modes */
|
|
static void mvebu_cp110_comphy_set_phy_selector(uint64_t comphy_base,
|
|
uint8_t comphy_index, uint32_t comphy_mode)
|
|
{
|
|
uint32_t reg, mask;
|
|
uint32_t comphy_offset =
|
|
COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
|
|
int mode;
|
|
|
|
/* If phy selector is used the pipe selector should be marked as
|
|
* unconnected.
|
|
*/
|
|
mvebu_cp110_comphy_clr_pipe_selector(comphy_base, comphy_index);
|
|
|
|
/* Comphy mode (compound of the IO mode and id). Here, only the IO mode
|
|
* is required to distinguish between SATA and network modes.
|
|
*/
|
|
mode = COMPHY_GET_MODE(comphy_mode);
|
|
|
|
mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset;
|
|
reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET);
|
|
reg &= ~mask;
|
|
|
|
/* SATA port 0/1 require the same configuration */
|
|
if (mode == COMPHY_SATA_MODE) {
|
|
/* SATA selector values is always 4 */
|
|
reg |= COMMON_SELECTOR_COMPHYN_SATA << comphy_offset;
|
|
} else {
|
|
switch (comphy_index) {
|
|
case(0):
|
|
case(1):
|
|
case(2):
|
|
/* For comphy 0,1, and 2:
|
|
* Network selector value is always 1.
|
|
*/
|
|
reg |= COMMON_SELECTOR_COMPHY0_1_2_NETWORK <<
|
|
comphy_offset;
|
|
break;
|
|
case(3):
|
|
/* For comphy 3:
|
|
* 0x1 = RXAUI_Lane1
|
|
* 0x2 = SGMII/HS-SGMII Port1
|
|
*/
|
|
if (mode == COMPHY_RXAUI_MODE)
|
|
reg |= COMMON_SELECTOR_COMPHY3_RXAUI <<
|
|
comphy_offset;
|
|
else
|
|
reg |= COMMON_SELECTOR_COMPHY3_SGMII <<
|
|
comphy_offset;
|
|
break;
|
|
case(4):
|
|
/* For comphy 4:
|
|
* 0x1 = SGMII/HS-SGMII Port1, XFI1/SFI1
|
|
* 0x2 = SGMII/HS-SGMII Port0: XFI0/SFI0, RXAUI_Lane0
|
|
*
|
|
* We want to check if SGMII1/HS_SGMII1 is the
|
|
* requested mode in order to determine which value
|
|
* should be set (all other modes use the same value)
|
|
* so we need to strip the mode, and check the ID
|
|
* because we might handle SGMII0/HS_SGMII0 too.
|
|
*/
|
|
/* TODO: need to distinguish between CP110 and CP115
|
|
* as SFI1/XFI1 available only for CP115.
|
|
*/
|
|
if ((mode == COMPHY_SGMII_MODE ||
|
|
mode == COMPHY_HS_SGMII_MODE ||
|
|
mode == COMPHY_SFI_MODE || mode == COMPHY_XFI_MODE)
|
|
&& COMPHY_GET_ID(comphy_mode) == 1)
|
|
reg |= COMMON_SELECTOR_COMPHY4_PORT1 <<
|
|
comphy_offset;
|
|
else
|
|
reg |= COMMON_SELECTOR_COMPHY4_ALL_OTHERS <<
|
|
comphy_offset;
|
|
break;
|
|
case(5):
|
|
/* For comphy 5:
|
|
* 0x1 = SGMII/HS-SGMII Port2
|
|
* 0x2 = RXAUI Lane1
|
|
*/
|
|
if (mode == COMPHY_RXAUI_MODE)
|
|
reg |= COMMON_SELECTOR_COMPHY5_RXAUI <<
|
|
comphy_offset;
|
|
else
|
|
reg |= COMMON_SELECTOR_COMPHY5_SGMII <<
|
|
comphy_offset;
|
|
break;
|
|
}
|
|
}
|
|
|
|
mmio_write_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET, reg);
|
|
}
|
|
|
|
/* PIPE selector configures for PCIe, USB 3.0 Host, and USB 3.0 Device mode */
|
|
static void mvebu_cp110_comphy_set_pipe_selector(uint64_t comphy_base,
|
|
uint8_t comphy_index, uint32_t comphy_mode)
|
|
{
|
|
uint32_t reg;
|
|
uint32_t shift = COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
|
|
int mode = COMPHY_GET_MODE(comphy_mode);
|
|
uint32_t mask = COMMON_SELECTOR_COMPHY_MASK << shift;
|
|
uint32_t pipe_sel = 0x0;
|
|
|
|
/* If pipe selector is used the phy selector should be marked as
|
|
* unconnected.
|
|
*/
|
|
mvebu_cp110_comphy_clr_phy_selector(comphy_base, comphy_index);
|
|
|
|
reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET);
|
|
reg &= ~mask;
|
|
|
|
switch (mode) {
|
|
case (COMPHY_PCIE_MODE):
|
|
/* For lanes support PCIE, selector value are all same */
|
|
pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_PCIE;
|
|
break;
|
|
|
|
case (COMPHY_USB3H_MODE):
|
|
/* Only lane 1-4 support USB host, selector value is same */
|
|
if (comphy_index == COMPHY_LANE0 ||
|
|
comphy_index == COMPHY_LANE5)
|
|
ERROR("COMPHY[%d] mode[%d] is invalid\n",
|
|
comphy_index, mode);
|
|
else
|
|
pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_USBH;
|
|
break;
|
|
|
|
case (COMPHY_USB3D_MODE):
|
|
/* Lane 1 and 4 support USB device, selector value is same */
|
|
if (comphy_index == COMPHY_LANE1 ||
|
|
comphy_index == COMPHY_LANE4)
|
|
pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_USBD;
|
|
else
|
|
ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index,
|
|
mode);
|
|
break;
|
|
|
|
default:
|
|
ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode);
|
|
break;
|
|
}
|
|
|
|
mmio_write_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET, reg |
|
|
(pipe_sel << shift));
|
|
}
|
|
|
|
int mvebu_cp110_comphy_is_pll_locked(uint64_t comphy_base, uint8_t comphy_index)
|
|
{
|
|
uintptr_t sd_ip_addr, addr;
|
|
uint32_t mask, data;
|
|
int ret = 0;
|
|
|
|
debug_enter();
|
|
|
|
sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
|
|
addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
|
|
data = SD_EXTERNAL_STATUS0_PLL_TX_MASK &
|
|
SD_EXTERNAL_STATUS0_PLL_RX_MASK;
|
|
mask = data;
|
|
data = polling_with_timeout(addr, data, mask,
|
|
PLL_LOCK_TIMEOUT, REG_32BIT);
|
|
if (data != 0) {
|
|
if (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK)
|
|
ERROR("RX PLL is not locked\n");
|
|
if (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)
|
|
ERROR("TX PLL is not locked\n");
|
|
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
|
|
debug_exit();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mvebu_cp110_comphy_sata_power_on(uint64_t comphy_base,
|
|
uint8_t comphy_index, uint32_t comphy_mode)
|
|
{
|
|
uintptr_t hpipe_addr, sd_ip_addr, comphy_addr;
|
|
uint32_t mask, data;
|
|
uint8_t ap_nr, cp_nr;
|
|
int ret = 0;
|
|
|
|
debug_enter();
|
|
|
|
mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
|
|
|
|
const struct sata_params *sata_static_values =
|
|
&sata_static_values_tab[ap_nr][cp_nr][comphy_index];
|
|
|
|
|
|
/* configure phy selector for SATA */
|
|
mvebu_cp110_comphy_set_phy_selector(comphy_base,
|
|
comphy_index, comphy_mode);
|
|
|
|
hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
|
|
|
|
debug(" add hpipe 0x%lx, sd 0x%lx, comphy 0x%lx\n",
|
|
hpipe_addr, sd_ip_addr, comphy_addr);
|
|
debug("stage: RFU configurations - hard reset comphy\n");
|
|
/* RFU configurations - hard reset comphy */
|
|
mask = COMMON_PHY_CFG1_PWR_UP_MASK;
|
|
data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
|
|
|
|
/* Set select data width 40Bit - SATA mode only */
|
|
reg_set(comphy_addr + COMMON_PHY_CFG6_REG,
|
|
0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET,
|
|
COMMON_PHY_CFG6_IF_40_SEL_MASK);
|
|
|
|
/* release from hard reset in SD external */
|
|
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
/* Wait 1ms - until band gap and ref clock ready */
|
|
mdelay(1);
|
|
|
|
debug("stage: Comphy configuration\n");
|
|
/* Start comphy Configuration */
|
|
/* Set reference clock to comes from group 1 - choose 25Mhz */
|
|
reg_set(hpipe_addr + HPIPE_MISC_REG,
|
|
0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
|
|
HPIPE_MISC_REFCLK_SEL_MASK);
|
|
/* Reference frequency select set 1 (for SATA = 25Mhz) */
|
|
mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
|
|
data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
|
|
/* PHY mode select (set SATA = 0x0 */
|
|
mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
|
|
data |= 0x0 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
|
|
/* Set max PHY generation setting - 6Gbps */
|
|
reg_set(hpipe_addr + HPIPE_INTERFACE_REG,
|
|
0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET,
|
|
HPIPE_INTERFACE_GEN_MAX_MASK);
|
|
/* Set select data width 40Bit (SEL_BITS[2:0]) */
|
|
reg_set(hpipe_addr + HPIPE_LOOPBACK_REG,
|
|
0x2 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK);
|
|
|
|
debug("stage: Analog parameters from ETP(HW)\n");
|
|
/* G1 settings */
|
|
mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
|
|
data = sata_static_values->g1_rx_selmupi <<
|
|
HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK;
|
|
data |= sata_static_values->g1_rx_selmupf <<
|
|
HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK;
|
|
data |= sata_static_values->g1_rx_selmufi <<
|
|
HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK;
|
|
data |= sata_static_values->g1_rx_selmuff <<
|
|
HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK;
|
|
data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
|
|
|
|
mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
|
|
data = 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
|
|
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
|
|
data |= 0x2 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
|
|
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
|
|
data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
|
|
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_MASK;
|
|
data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET;
|
|
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_MASK;
|
|
data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
|
|
|
|
/* G2 settings */
|
|
mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK;
|
|
data = sata_static_values->g2_rx_selmupi <<
|
|
HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET;
|
|
mask |= HPIPE_G2_SET_1_G2_RX_SELMUPF_MASK;
|
|
data |= sata_static_values->g2_rx_selmupf <<
|
|
HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET;
|
|
mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK;
|
|
data |= sata_static_values->g2_rx_selmufi <<
|
|
HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET;
|
|
mask |= HPIPE_G2_SET_1_G2_RX_SELMUFF_MASK;
|
|
data |= sata_static_values->g2_rx_selmuff <<
|
|
HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET;
|
|
mask |= HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_MASK;
|
|
data |= 0x1 << HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask);
|
|
|
|
/* G3 settings */
|
|
mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK;
|
|
data = sata_static_values->g3_rx_selmupi <<
|
|
HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET;
|
|
mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK;
|
|
data |= sata_static_values->g3_rx_selmupf <<
|
|
HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET;
|
|
mask |= HPIPE_G3_SET_1_G3_RX_SELMUFI_MASK;
|
|
data |= sata_static_values->g3_rx_selmufi <<
|
|
HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET;
|
|
mask |= HPIPE_G3_SET_1_G3_RX_SELMUFF_MASK;
|
|
data |= sata_static_values->g3_rx_selmuff <<
|
|
HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET;
|
|
mask |= HPIPE_G3_SET_1_G3_RX_DFE_EN_MASK;
|
|
data |= 0x1 << HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET;
|
|
mask |= HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_MASK;
|
|
data |= 0x2 << HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET;
|
|
mask |= HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK;
|
|
data |= 0x0 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G3_SET_1_REG, data, mask);
|
|
|
|
/* DTL Control */
|
|
mask = HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK;
|
|
data = 0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET;
|
|
mask |= HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK;
|
|
data |= 0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET;
|
|
mask |= HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
|
|
data |= 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
|
|
mask |= HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK;
|
|
data |= 0x1 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET;
|
|
mask |= HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK;
|
|
data |= 0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET;
|
|
mask |= HPIPE_PWR_CTR_DTL_CLK_MODE_MASK;
|
|
data |= 0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET;
|
|
mask |= HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK;
|
|
data |= 0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
|
|
|
|
/* Trigger sampler enable pulse */
|
|
mask = HPIPE_SMAPLER_MASK;
|
|
data = 0x1 << HPIPE_SMAPLER_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
|
|
mask = HPIPE_SMAPLER_MASK;
|
|
data = 0x0 << HPIPE_SMAPLER_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
|
|
|
|
/* VDD Calibration Control 3 */
|
|
mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
|
|
data = 0x10 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
|
|
|
|
/* DFE Resolution Control */
|
|
mask = HPIPE_DFE_RES_FORCE_MASK;
|
|
data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
|
|
|
|
/* DFE F3-F5 Coefficient Control */
|
|
mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
|
|
data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
|
|
mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK;
|
|
data = 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask);
|
|
|
|
/* G3 Setting 3 */
|
|
mask = HPIPE_G3_FFE_CAP_SEL_MASK;
|
|
data = sata_static_values->g3_ffe_cap_sel <<
|
|
HPIPE_G3_FFE_CAP_SEL_OFFSET;
|
|
mask |= HPIPE_G3_FFE_RES_SEL_MASK;
|
|
data |= sata_static_values->g3_ffe_res_sel <<
|
|
HPIPE_G3_FFE_RES_SEL_OFFSET;
|
|
mask |= HPIPE_G3_FFE_SETTING_FORCE_MASK;
|
|
data |= 0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET;
|
|
mask |= HPIPE_G3_FFE_DEG_RES_LEVEL_MASK;
|
|
data |= 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET;
|
|
mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK;
|
|
data |= 0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask);
|
|
|
|
/* G3 Setting 4 */
|
|
mask = HPIPE_G3_DFE_RES_MASK;
|
|
data = sata_static_values->g3_dfe_res << HPIPE_G3_DFE_RES_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask);
|
|
|
|
/* Offset Phase Control */
|
|
mask = HPIPE_OS_PH_OFFSET_MASK;
|
|
data = sata_static_values->align90 << HPIPE_OS_PH_OFFSET_OFFSET;
|
|
mask |= HPIPE_OS_PH_OFFSET_FORCE_MASK;
|
|
data |= 0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET;
|
|
mask |= HPIPE_OS_PH_VALID_MASK;
|
|
data |= 0x0 << HPIPE_OS_PH_VALID_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
|
|
mask = HPIPE_OS_PH_VALID_MASK;
|
|
data = 0x1 << HPIPE_OS_PH_VALID_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
|
|
mask = HPIPE_OS_PH_VALID_MASK;
|
|
data = 0x0 << HPIPE_OS_PH_VALID_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
|
|
|
|
/* Set G1 TX amplitude and TX post emphasis value */
|
|
mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
|
|
data = sata_static_values->g1_amp << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
|
|
mask |= HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK;
|
|
data |= sata_static_values->g1_tx_amp_adj <<
|
|
HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET;
|
|
mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
|
|
data |= sata_static_values->g1_emph <<
|
|
HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
|
|
mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK;
|
|
data |= sata_static_values->g1_emph_en <<
|
|
HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask);
|
|
|
|
/* Set G1 emph */
|
|
mask = HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK;
|
|
data = sata_static_values->g1_tx_emph_en <<
|
|
HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET;
|
|
mask |= HPIPE_G1_SET_2_G1_TX_EMPH0_MASK;
|
|
data |= sata_static_values->g1_tx_emph <<
|
|
HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SET_2_REG, data, mask);
|
|
|
|
/* Set G2 TX amplitude and TX post emphasis value */
|
|
mask = HPIPE_G2_SET_0_G2_TX_AMP_MASK;
|
|
data = sata_static_values->g2_amp << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET;
|
|
mask |= HPIPE_G2_SET_0_G2_TX_AMP_ADJ_MASK;
|
|
data |= sata_static_values->g2_tx_amp_adj <<
|
|
HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET;
|
|
mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_MASK;
|
|
data |= sata_static_values->g2_emph <<
|
|
HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET;
|
|
mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_EN_MASK;
|
|
data |= sata_static_values->g2_emph_en <<
|
|
HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G2_SET_0_REG, data, mask);
|
|
|
|
/* Set G2 emph */
|
|
mask = HPIPE_G2_SET_2_G2_TX_EMPH0_EN_MASK;
|
|
data = sata_static_values->g2_tx_emph_en <<
|
|
HPIPE_G2_SET_2_G2_TX_EMPH0_EN_OFFSET;
|
|
mask |= HPIPE_G2_SET_2_G2_TX_EMPH0_MASK;
|
|
data |= sata_static_values->g2_tx_emph <<
|
|
HPIPE_G2_SET_2_G2_TX_EMPH0_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G2_SET_2_REG, data, mask);
|
|
|
|
/* Set G3 TX amplitude and TX post emphasis value */
|
|
mask = HPIPE_G3_SET_0_G3_TX_AMP_MASK;
|
|
data = sata_static_values->g3_amp << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET;
|
|
mask |= HPIPE_G3_SET_0_G3_TX_AMP_ADJ_MASK;
|
|
data |= sata_static_values->g3_tx_amp_adj <<
|
|
HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET;
|
|
mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_MASK;
|
|
data |= sata_static_values->g3_emph <<
|
|
HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET;
|
|
mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_EN_MASK;
|
|
data |= sata_static_values->g3_emph_en <<
|
|
HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET;
|
|
mask |= HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_MASK;
|
|
data |= 0x4 << HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET;
|
|
mask |= HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_MASK;
|
|
data |= 0x0 << HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G3_SET_0_REG, data, mask);
|
|
|
|
/* Set G3 emph */
|
|
mask = HPIPE_G3_SET_2_G3_TX_EMPH0_EN_MASK;
|
|
data = sata_static_values->g3_tx_emph_en <<
|
|
HPIPE_G3_SET_2_G3_TX_EMPH0_EN_OFFSET;
|
|
mask |= HPIPE_G3_SET_2_G3_TX_EMPH0_MASK;
|
|
data |= sata_static_values->g3_tx_emph <<
|
|
HPIPE_G3_SET_2_G3_TX_EMPH0_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G3_SET_2_REG, data, mask);
|
|
|
|
/* SERDES External Configuration 2 register */
|
|
mask = SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, data, mask);
|
|
|
|
/* DFE reset sequence */
|
|
reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
|
|
0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET,
|
|
HPIPE_PWR_CTR_RST_DFE_MASK);
|
|
reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
|
|
0x0 << HPIPE_PWR_CTR_RST_DFE_OFFSET,
|
|
HPIPE_PWR_CTR_RST_DFE_MASK);
|
|
/* SW reset for interrupt logic */
|
|
reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
|
|
0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET,
|
|
HPIPE_PWR_CTR_SFT_RST_MASK);
|
|
reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
|
|
0x0 << HPIPE_PWR_CTR_SFT_RST_OFFSET,
|
|
HPIPE_PWR_CTR_SFT_RST_MASK);
|
|
|
|
debug_exit();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mvebu_cp110_comphy_sgmii_power_on(uint64_t comphy_base,
|
|
uint8_t comphy_index, uint32_t comphy_mode)
|
|
{
|
|
uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr;
|
|
uint32_t mask, data, sgmii_speed = COMPHY_GET_SPEED(comphy_mode);
|
|
int ret = 0;
|
|
|
|
debug_enter();
|
|
|
|
hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
|
|
|
|
/* configure phy selector for SGMII */
|
|
mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index,
|
|
comphy_mode);
|
|
|
|
/* Confiugre the lane */
|
|
debug("stage: RFU configurations - hard reset comphy\n");
|
|
/* RFU configurations - hard reset comphy */
|
|
mask = COMMON_PHY_CFG1_PWR_UP_MASK;
|
|
data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
|
|
|
|
/* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
|
|
mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK;
|
|
|
|
if (sgmii_speed == COMPHY_SPEED_1_25G) {
|
|
/* SGMII 1G, SerDes speed 1.25G */
|
|
data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
|
|
data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
|
|
} else if (sgmii_speed == COMPHY_SPEED_3_125G) {
|
|
/* HS SGMII (2.5G), SerDes speed 3.125G */
|
|
data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
|
|
data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
|
|
} else {
|
|
/* Other rates are not supported */
|
|
ERROR("unsupported SGMII speed on comphy%d\n", comphy_index);
|
|
return -EINVAL;
|
|
}
|
|
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
|
|
data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
|
|
data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
|
|
data |= 1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
|
|
|
|
/* Set hard reset */
|
|
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
/* Release hard reset */
|
|
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
/* Wait 1ms - until band gap and ref clock ready */
|
|
mdelay(1);
|
|
|
|
/* Make sure that 40 data bits is disabled
|
|
* This bit is not cleared by reset
|
|
*/
|
|
mask = COMMON_PHY_CFG6_IF_40_SEL_MASK;
|
|
data = 0 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG6_REG, data, mask);
|
|
|
|
/* Start comphy Configuration */
|
|
debug("stage: Comphy configuration\n");
|
|
/* set reference clock */
|
|
mask = HPIPE_MISC_REFCLK_SEL_MASK;
|
|
data = 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
|
|
/* Power and PLL Control */
|
|
mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
|
|
data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
|
|
mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
|
|
data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
|
|
/* Loopback register */
|
|
mask = HPIPE_LOOPBACK_SEL_MASK;
|
|
data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask);
|
|
/* rx control 1 */
|
|
mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK;
|
|
data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET;
|
|
mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK;
|
|
data |= 0x0 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask);
|
|
/* DTL Control */
|
|
mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
|
|
data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
|
|
|
|
/* Set analog parameters from ETP(HW) - for now use the default data */
|
|
debug("stage: Analog parameters from ETP(HW)\n");
|
|
|
|
reg_set(hpipe_addr + HPIPE_G1_SET_0_REG,
|
|
0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET,
|
|
HPIPE_G1_SET_0_G1_TX_EMPH1_MASK);
|
|
|
|
debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n");
|
|
/* SERDES External Configuration */
|
|
mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
|
|
|
|
ret = mvebu_cp110_comphy_is_pll_locked(comphy_base, comphy_index);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* RX init */
|
|
mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
/* check that RX init done */
|
|
addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
|
|
data = SD_EXTERNAL_STATUS0_RX_INIT_MASK;
|
|
mask = data;
|
|
data = polling_with_timeout(addr, data, mask, 100, REG_32BIT);
|
|
if (data != 0) {
|
|
ERROR("RX init failed\n");
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
|
|
debug("stage: RF Reset\n");
|
|
/* RF Reset */
|
|
mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
debug_exit();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mvebu_cp110_comphy_xfi_power_on(uint64_t comphy_base,
|
|
uint8_t comphy_index,
|
|
uint32_t comphy_mode)
|
|
{
|
|
uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr;
|
|
uint32_t mask, data, speed = COMPHY_GET_SPEED(comphy_mode);
|
|
int ret = 0;
|
|
uint8_t ap_nr, cp_nr;
|
|
|
|
debug_enter();
|
|
|
|
mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
|
|
|
|
if (rx_trainng_done[ap_nr][cp_nr][comphy_index]) {
|
|
debug("Skip %s for comphy[%d][%d][%d], due to rx training\n",
|
|
__func__, ap_nr, cp_nr, comphy_index);
|
|
return 0;
|
|
}
|
|
|
|
const struct xfi_params *xfi_static_values =
|
|
&xfi_static_values_tab[ap_nr][cp_nr][comphy_index];
|
|
|
|
debug("%s: the ap_nr = %d, cp_nr = %d, comphy_index %d\n",
|
|
__func__, ap_nr, cp_nr, comphy_index);
|
|
|
|
debug("g1_ffe_cap_sel= 0x%x, g1_ffe_res_sel= 0x%x, g1_dfe_res= 0x%x\n",
|
|
xfi_static_values->g1_ffe_cap_sel,
|
|
xfi_static_values->g1_ffe_res_sel,
|
|
xfi_static_values->g1_dfe_res);
|
|
|
|
if (!xfi_static_values->valid) {
|
|
ERROR("[ap%d][cp[%d][comphy:%d]: Has no valid static params\n",
|
|
ap_nr, cp_nr, comphy_index);
|
|
ERROR("[ap%d][cp[%d][comphy:%d]: porting layer needs update\n",
|
|
ap_nr, cp_nr, comphy_index);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((speed != COMPHY_SPEED_5_15625G) &&
|
|
(speed != COMPHY_SPEED_10_3125G) &&
|
|
(speed != COMPHY_SPEED_DEFAULT)) {
|
|
ERROR("comphy:%d: unsupported sfi/xfi speed\n", comphy_index);
|
|
return -EINVAL;
|
|
}
|
|
|
|
hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
|
|
|
|
/* configure phy selector for XFI/SFI */
|
|
mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index,
|
|
comphy_mode);
|
|
|
|
debug("stage: RFU configurations - hard reset comphy\n");
|
|
/* RFU configurations - hard reset comphy */
|
|
mask = COMMON_PHY_CFG1_PWR_UP_MASK;
|
|
data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
|
|
|
|
/* Make sure that 40 data bits is disabled
|
|
* This bit is not cleared by reset
|
|
*/
|
|
mask = COMMON_PHY_CFG6_IF_40_SEL_MASK;
|
|
data = 0 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG6_REG, data, mask);
|
|
|
|
/* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
|
|
mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK;
|
|
data |= 0xE << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK;
|
|
data |= 0xE << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
|
|
data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
|
|
data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
|
|
data |= 0 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
|
|
|
|
/* release from hard reset */
|
|
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
/* Wait 1ms - until band gap and ref clock ready */
|
|
mdelay(1);
|
|
|
|
/* Start comphy Configuration */
|
|
debug("stage: Comphy configuration\n");
|
|
/* set reference clock */
|
|
mask = HPIPE_MISC_ICP_FORCE_MASK;
|
|
data = (speed == COMPHY_SPEED_5_15625G) ?
|
|
(0x0 << HPIPE_MISC_ICP_FORCE_OFFSET) :
|
|
(0x1 << HPIPE_MISC_ICP_FORCE_OFFSET);
|
|
mask |= HPIPE_MISC_REFCLK_SEL_MASK;
|
|
data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
|
|
/* Power and PLL Control */
|
|
mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
|
|
data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
|
|
mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
|
|
data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
|
|
/* Loopback register */
|
|
mask = HPIPE_LOOPBACK_SEL_MASK;
|
|
data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask);
|
|
/* rx control 1 */
|
|
mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK;
|
|
data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET;
|
|
mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK;
|
|
data |= 0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask);
|
|
/* DTL Control */
|
|
mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
|
|
data = 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
|
|
|
|
/* Transmitter/Receiver Speed Divider Force */
|
|
if (speed == COMPHY_SPEED_5_15625G) {
|
|
mask = HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK;
|
|
data = 1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET;
|
|
mask |= HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK;
|
|
data |= 1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET;
|
|
mask |= HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK;
|
|
data |= 1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET;
|
|
mask |= HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK;
|
|
data |= 1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET;
|
|
} else {
|
|
mask = HPIPE_TXDIGCK_DIV_FORCE_MASK;
|
|
data = 0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET;
|
|
}
|
|
reg_set(hpipe_addr + HPIPE_SPD_DIV_FORCE_REG, data, mask);
|
|
|
|
/* Set analog parameters from ETP(HW) */
|
|
debug("stage: Analog parameters from ETP(HW)\n");
|
|
/* SERDES External Configuration 2 */
|
|
mask = SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, data, mask);
|
|
/* 0x7-DFE Resolution control */
|
|
mask = HPIPE_DFE_RES_FORCE_MASK;
|
|
data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
|
|
/* 0xd-G1_Setting_0 */
|
|
if (speed == COMPHY_SPEED_5_15625G) {
|
|
mask = HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
|
|
data = 0x6 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
|
|
} else {
|
|
mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
|
|
data = xfi_static_values->g1_amp <<
|
|
HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
|
|
mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
|
|
data |= xfi_static_values->g1_emph <<
|
|
HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
|
|
|
|
mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK;
|
|
data |= xfi_static_values->g1_emph_en <<
|
|
HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET;
|
|
mask |= HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK;
|
|
data |= xfi_static_values->g1_tx_amp_adj <<
|
|
HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET;
|
|
}
|
|
reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask);
|
|
/* Genration 1 setting 2 (G1_Setting_2) */
|
|
mask = HPIPE_G1_SET_2_G1_TX_EMPH0_MASK;
|
|
data = xfi_static_values->g1_tx_emph <<
|
|
HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET;
|
|
mask |= HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK;
|
|
data |= xfi_static_values->g1_tx_emph_en <<
|
|
HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SET_2_REG, data, mask);
|
|
/* Transmitter Slew Rate Control register (tx_reg1) */
|
|
mask = HPIPE_TX_REG1_TX_EMPH_RES_MASK;
|
|
data = 0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET;
|
|
mask |= HPIPE_TX_REG1_SLC_EN_MASK;
|
|
data |= 0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_REG1_REG, data, mask);
|
|
/* Impedance Calibration Control register (cal_reg1) */
|
|
mask = HPIPE_CAL_REG_1_EXT_TXIMP_MASK;
|
|
data = 0xe << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET;
|
|
mask |= HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK;
|
|
data |= 0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_CAL_REG1_REG, data, mask);
|
|
/* Generation 1 Setting 5 (g1_setting_5) */
|
|
mask = HPIPE_G1_SETTING_5_G1_ICP_MASK;
|
|
data = 0 << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTING_5_REG, data, mask);
|
|
|
|
/* 0xE-G1_Setting_1 */
|
|
mask = HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK;
|
|
data = 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET;
|
|
if (speed == COMPHY_SPEED_5_15625G) {
|
|
mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
|
|
data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK;
|
|
data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
|
|
} else {
|
|
mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
|
|
data |= xfi_static_values->g1_rx_selmupi <<
|
|
HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK;
|
|
data |= xfi_static_values->g1_rx_selmupf <<
|
|
HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK;
|
|
data |= xfi_static_values->g1_rx_selmufi <<
|
|
HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK;
|
|
data |= xfi_static_values->g1_rx_selmuff <<
|
|
HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK;
|
|
data |= 0x3 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET;
|
|
}
|
|
reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
|
|
|
|
/* 0xA-DFE_Reg3 */
|
|
mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
|
|
data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
|
|
mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK;
|
|
data |= 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask);
|
|
|
|
/* 0x111-G1_Setting_4 */
|
|
mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
|
|
data = 0x1 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
|
|
/* Genration 1 setting 3 (G1_Setting_3) */
|
|
mask = HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK;
|
|
data = 0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET;
|
|
if (speed == COMPHY_SPEED_5_15625G) {
|
|
/* Force FFE (Feed Forward Equalization) to 5G */
|
|
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
|
|
data |= 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
|
|
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
|
|
data |= 0x4 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
|
|
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
|
|
data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
|
|
} else {
|
|
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
|
|
data |= xfi_static_values->g1_ffe_cap_sel <<
|
|
HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
|
|
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
|
|
data |= xfi_static_values->g1_ffe_res_sel <<
|
|
HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
|
|
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
|
|
data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
|
|
|
|
/* Use the value from CAL_OS_PH_EXT */
|
|
mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK;
|
|
data = 1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET;
|
|
reg_set(hpipe_addr +
|
|
HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
|
|
data, mask);
|
|
|
|
/* Update align90 */
|
|
mask = HPIPE_CAL_OS_PH_EXT_MASK;
|
|
data = xfi_static_values->align90 << HPIPE_CAL_OS_PH_EXT_OFFSET;
|
|
reg_set(hpipe_addr +
|
|
HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
|
|
data, mask);
|
|
|
|
/* Force DFE resolution (use gen table value) */
|
|
mask = HPIPE_DFE_RES_FORCE_MASK;
|
|
data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
|
|
|
|
/* 0x111-G1 DFE_Setting_4 */
|
|
mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
|
|
data = xfi_static_values->g1_dfe_res <<
|
|
HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
|
|
}
|
|
|
|
/* Connfigure RX training timer */
|
|
mask = HPIPE_RX_TRAIN_TIMER_MASK;
|
|
data = 0x13 << HPIPE_RX_TRAIN_TIMER_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask);
|
|
|
|
/* Enable TX train peak to peak hold */
|
|
mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK;
|
|
data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask);
|
|
|
|
/* Configure TX preset index */
|
|
mask = HPIPE_TX_PRESET_INDEX_MASK;
|
|
data = 0x2 << HPIPE_TX_PRESET_INDEX_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_PRESET_INDEX_REG, data, mask);
|
|
|
|
/* Disable pattern lock lost timeout */
|
|
mask = HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK;
|
|
data = 0x0 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_3_REG, data, mask);
|
|
|
|
/* Configure TX training pattern and TX training 16bit auto */
|
|
mask = HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK;
|
|
data = 0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET;
|
|
mask |= HPIPE_TX_TRAIN_PAT_SEL_MASK;
|
|
data |= 0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask);
|
|
|
|
/* Configure Training patten number */
|
|
mask = HPIPE_TRAIN_PAT_NUM_MASK;
|
|
data = 0x88 << HPIPE_TRAIN_PAT_NUM_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_0_REG, data, mask);
|
|
|
|
/* Configure differencial manchester encoter to ethernet mode */
|
|
mask = HPIPE_DME_ETHERNET_MODE_MASK;
|
|
data = 0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DME_REG, data, mask);
|
|
|
|
/* Configure VDD Continuous Calibration */
|
|
mask = HPIPE_CAL_VDD_CONT_MODE_MASK;
|
|
data = 0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_VDD_CAL_0_REG, data, mask);
|
|
|
|
/* Trigger sampler enable pulse (by toggleing the bit) */
|
|
mask = HPIPE_RX_SAMPLER_OS_GAIN_MASK;
|
|
data = 0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET;
|
|
mask |= HPIPE_SMAPLER_MASK;
|
|
data |= 0x1 << HPIPE_SMAPLER_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
|
|
mask = HPIPE_SMAPLER_MASK;
|
|
data = 0x0 << HPIPE_SMAPLER_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
|
|
|
|
/* Set External RX Regulator Control */
|
|
mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
|
|
data = 0x1A << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
|
|
|
|
debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n");
|
|
/* SERDES External Configuration */
|
|
mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
|
|
|
|
/* check PLL rx & tx ready */
|
|
addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
|
|
data = SD_EXTERNAL_STATUS0_PLL_RX_MASK |
|
|
SD_EXTERNAL_STATUS0_PLL_TX_MASK;
|
|
mask = data;
|
|
data = polling_with_timeout(addr, data, mask,
|
|
PLL_LOCK_TIMEOUT, REG_32BIT);
|
|
if (data != 0) {
|
|
if (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK)
|
|
ERROR("RX PLL is not locked\n");
|
|
if (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)
|
|
ERROR("TX PLL is not locked\n");
|
|
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
|
|
/* RX init */
|
|
mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
/* check that RX init done */
|
|
addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
|
|
data = SD_EXTERNAL_STATUS0_RX_INIT_MASK;
|
|
mask = data;
|
|
data = polling_with_timeout(addr, data, mask, 100, REG_32BIT);
|
|
if (data != 0) {
|
|
ERROR("RX init failed\n");
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
|
|
debug("stage: RF Reset\n");
|
|
/* RF Reset */
|
|
mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
debug_exit();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mvebu_cp110_comphy_pcie_power_on(uint64_t comphy_base,
|
|
uint8_t comphy_index, uint32_t comphy_mode)
|
|
{
|
|
int ret = 0;
|
|
uint32_t reg, mask, data, pcie_width;
|
|
uint32_t clk_dir;
|
|
uintptr_t hpipe_addr, comphy_addr, addr;
|
|
_Bool clk_src = COMPHY_GET_CLK_SRC(comphy_mode);
|
|
_Bool called_from_uboot = COMPHY_GET_CALLER(comphy_mode);
|
|
|
|
/* In Armada 8K DB boards, PCIe initialization can be executed
|
|
* only once (PCIe reset performed during chip power on and
|
|
* it cannot be executed via GPIO later).
|
|
* This means that power on can be executed only once, so let's
|
|
* mark if the caller is bootloader or Linux.
|
|
* If bootloader -> run power on.
|
|
* If Linux -> exit.
|
|
*
|
|
* TODO: In MacciatoBIN, PCIe reset is connected via GPIO,
|
|
* so after GPIO reset is added to Linux Kernel, it can be
|
|
* powered-on by Linux.
|
|
*/
|
|
if (!called_from_uboot)
|
|
return ret;
|
|
|
|
hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
|
|
pcie_width = COMPHY_GET_PCIE_WIDTH(comphy_mode);
|
|
|
|
debug_enter();
|
|
|
|
spin_lock(&cp110_mac_reset_lock);
|
|
|
|
reg = mmio_read_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
|
|
SYS_CTRL_UINIT_SOFT_RESET_REG);
|
|
switch (comphy_index) {
|
|
case COMPHY_LANE0:
|
|
reg |= PCIE_MAC_RESET_MASK_PORT0;
|
|
break;
|
|
case COMPHY_LANE4:
|
|
reg |= PCIE_MAC_RESET_MASK_PORT1;
|
|
break;
|
|
case COMPHY_LANE5:
|
|
reg |= PCIE_MAC_RESET_MASK_PORT2;
|
|
break;
|
|
}
|
|
|
|
mmio_write_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
|
|
SYS_CTRL_UINIT_SOFT_RESET_REG, reg);
|
|
spin_unlock(&cp110_mac_reset_lock);
|
|
|
|
/* Configure PIPE selector for PCIE */
|
|
mvebu_cp110_comphy_set_pipe_selector(comphy_base, comphy_index,
|
|
comphy_mode);
|
|
|
|
/*
|
|
* Read SAR (Sample-At-Reset) configuration for the PCIe clock
|
|
* direction.
|
|
*
|
|
* SerDes Lane 4/5 got the PCIe ref-clock #1,
|
|
* and SerDes Lane 0 got PCIe ref-clock #0
|
|
*/
|
|
reg = mmio_read_32(DFX_FROM_COMPHY_ADDR(comphy_base) +
|
|
SAR_STATUS_0_REG);
|
|
if (comphy_index == COMPHY_LANE4 || comphy_index == COMPHY_LANE5)
|
|
clk_dir = (reg & SAR_RST_PCIE1_CLOCK_CONFIG_CP1_MASK) >>
|
|
SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET;
|
|
else
|
|
clk_dir = (reg & SAR_RST_PCIE0_CLOCK_CONFIG_CP1_MASK) >>
|
|
SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET;
|
|
|
|
debug("On lane %d\n", comphy_index);
|
|
debug("PCIe clock direction = %x\n", clk_dir);
|
|
debug("PCIe Width = %d\n", pcie_width);
|
|
|
|
/* enable PCIe X4 and X2 */
|
|
if (comphy_index == COMPHY_LANE0) {
|
|
if (pcie_width == PCIE_LNK_X4) {
|
|
data = 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET;
|
|
mask = COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK;
|
|
reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
|
|
data, mask);
|
|
} else if (pcie_width == PCIE_LNK_X2) {
|
|
data = 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET;
|
|
mask = COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK;
|
|
reg_set(comphy_base + COMMON_PHY_SD_CTRL1, data, mask);
|
|
}
|
|
}
|
|
|
|
/* If PCIe clock is output and clock source from SerDes lane 5,
|
|
* need to configure the clock-source MUX.
|
|
* By default, the clock source is from lane 4
|
|
*/
|
|
if (clk_dir && clk_src && (comphy_index == COMPHY_LANE5)) {
|
|
data = DFX_DEV_GEN_PCIE_CLK_SRC_MUX <<
|
|
DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET;
|
|
mask = DFX_DEV_GEN_PCIE_CLK_SRC_MASK;
|
|
reg_set(DFX_FROM_COMPHY_ADDR(comphy_base) +
|
|
DFX_DEV_GEN_CTRL12_REG, data, mask);
|
|
}
|
|
|
|
debug("stage: RFU configurations - hard reset comphy\n");
|
|
/* RFU configurations - hard reset comphy */
|
|
mask = COMMON_PHY_CFG1_PWR_UP_MASK;
|
|
data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
|
|
data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
|
|
mask |= COMMON_PHY_PHY_MODE_MASK;
|
|
data |= 0x0 << COMMON_PHY_PHY_MODE_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
|
|
|
|
/* release from hard reset */
|
|
mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
|
|
data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
|
|
data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
|
|
|
|
/* Wait 1ms - until band gap and ref clock ready */
|
|
mdelay(1);
|
|
/* Start comphy Configuration */
|
|
debug("stage: Comphy configuration\n");
|
|
/* Set PIPE soft reset */
|
|
mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK;
|
|
data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET;
|
|
/* Set PHY datapath width mode for V0 */
|
|
mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK;
|
|
data |= 0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET;
|
|
/* Set Data bus width USB mode for V0 */
|
|
mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK;
|
|
data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET;
|
|
/* Set CORE_CLK output frequency for 250Mhz */
|
|
mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK;
|
|
data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask);
|
|
/* Set PLL ready delay for 0x2 */
|
|
data = 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET;
|
|
mask = HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK;
|
|
if (pcie_width != PCIE_LNK_X1) {
|
|
data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET;
|
|
mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK;
|
|
data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET;
|
|
mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK;
|
|
}
|
|
reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG, data, mask);
|
|
|
|
/* Set PIPE mode interface to PCIe3 - 0x1 & set lane order */
|
|
data = 0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET;
|
|
mask = HPIPE_CLK_SRC_HI_MODE_PIPE_MASK;
|
|
if (pcie_width != PCIE_LNK_X1) {
|
|
mask |= HPIPE_CLK_SRC_HI_LANE_STRT_MASK;
|
|
mask |= HPIPE_CLK_SRC_HI_LANE_MASTER_MASK;
|
|
mask |= HPIPE_CLK_SRC_HI_LANE_BREAK_MASK;
|
|
if (comphy_index == 0) {
|
|
data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET;
|
|
data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET;
|
|
} else if (comphy_index == (pcie_width - 1)) {
|
|
data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET;
|
|
}
|
|
}
|
|
reg_set(hpipe_addr + HPIPE_CLK_SRC_HI_REG, data, mask);
|
|
/* Config update polarity equalization */
|
|
data = 0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET;
|
|
mask = HPIPE_CFG_UPDATE_POLARITY_MASK;
|
|
reg_set(hpipe_addr + HPIPE_LANE_EQ_CFG1_REG, data, mask);
|
|
/* Set PIPE version 4 to mode enable */
|
|
data = 0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET;
|
|
mask = HPIPE_DFE_CTRL_28_PIPE4_MASK;
|
|
reg_set(hpipe_addr + HPIPE_DFE_CTRL_28_REG, data, mask);
|
|
/* TODO: check if pcie clock is output/input - for bringup use input*/
|
|
/* Enable PIN clock 100M_125M */
|
|
mask = 0;
|
|
data = 0;
|
|
/* Only if clock is output, configure the clock-source mux */
|
|
if (clk_dir) {
|
|
mask |= HPIPE_MISC_CLK100M_125M_MASK;
|
|
data |= 0x1 << HPIPE_MISC_CLK100M_125M_OFFSET;
|
|
}
|
|
/* Set PIN_TXDCLK_2X Clock Freq. Selection for outputs 500MHz clock */
|
|
mask |= HPIPE_MISC_TXDCLK_2X_MASK;
|
|
data |= 0x0 << HPIPE_MISC_TXDCLK_2X_OFFSET;
|
|
/* Enable 500MHz Clock */
|
|
mask |= HPIPE_MISC_CLK500_EN_MASK;
|
|
data |= 0x1 << HPIPE_MISC_CLK500_EN_OFFSET;
|
|
if (clk_dir) { /* output */
|
|
/* Set reference clock comes from group 1 */
|
|
mask |= HPIPE_MISC_REFCLK_SEL_MASK;
|
|
data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
|
|
} else {
|
|
/* Set reference clock comes from group 2 */
|
|
mask |= HPIPE_MISC_REFCLK_SEL_MASK;
|
|
data |= 0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET;
|
|
}
|
|
mask |= HPIPE_MISC_ICP_FORCE_MASK;
|
|
data |= 0x1 << HPIPE_MISC_ICP_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
|
|
if (clk_dir) { /* output */
|
|
/* Set reference frequcency select - 0x2 for 25MHz*/
|
|
mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
|
|
data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
|
|
} else {
|
|
/* Set reference frequcency select - 0x0 for 100MHz*/
|
|
mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
|
|
data = 0x0 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
|
|
}
|
|
/* Set PHY mode to PCIe */
|
|
mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
|
|
data |= 0x3 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
|
|
|
|
/* ref clock alignment */
|
|
if (pcie_width != PCIE_LNK_X1) {
|
|
mask = HPIPE_LANE_ALIGN_OFF_MASK;
|
|
data = 0x0 << HPIPE_LANE_ALIGN_OFF_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_LANE_ALIGN_REG, data, mask);
|
|
}
|
|
|
|
/* Set the amount of time spent in the LoZ state - set for 0x7 only if
|
|
* the PCIe clock is output
|
|
*/
|
|
if (clk_dir)
|
|
reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL,
|
|
0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET,
|
|
HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK);
|
|
|
|
/* Set Maximal PHY Generation Setting(8Gbps) */
|
|
mask = HPIPE_INTERFACE_GEN_MAX_MASK;
|
|
data = 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET;
|
|
/* Bypass frame detection and sync detection for RX DATA */
|
|
mask |= HPIPE_INTERFACE_DET_BYPASS_MASK;
|
|
data |= 0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET;
|
|
/* Set Link Train Mode (Tx training control pins are used) */
|
|
mask |= HPIPE_INTERFACE_LINK_TRAIN_MASK;
|
|
data |= 0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_INTERFACE_REG, data, mask);
|
|
|
|
/* Set Idle_sync enable */
|
|
mask = HPIPE_PCIE_IDLE_SYNC_MASK;
|
|
data = 0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET;
|
|
/* Select bits for PCIE Gen3(32bit) */
|
|
mask |= HPIPE_PCIE_SEL_BITS_MASK;
|
|
data |= 0x2 << HPIPE_PCIE_SEL_BITS_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PCIE_REG0, data, mask);
|
|
|
|
/* Enable Tx_adapt_g1 */
|
|
mask = HPIPE_TX_TRAIN_CTRL_G1_MASK;
|
|
data = 0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET;
|
|
/* Enable Tx_adapt_gn1 */
|
|
mask |= HPIPE_TX_TRAIN_CTRL_GN1_MASK;
|
|
data |= 0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET;
|
|
/* Disable Tx_adapt_g0 */
|
|
mask |= HPIPE_TX_TRAIN_CTRL_G0_MASK;
|
|
data |= 0x0 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask);
|
|
|
|
/* Set reg_tx_train_chk_init */
|
|
mask = HPIPE_TX_TRAIN_CHK_INIT_MASK;
|
|
data = 0x0 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET;
|
|
/* Enable TX_COE_FM_PIN_PCIE3_EN */
|
|
mask |= HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK;
|
|
data |= 0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask);
|
|
|
|
debug("stage: TRx training parameters\n");
|
|
/* Set Preset sweep configurations */
|
|
mask = HPIPE_TX_TX_STATUS_CHECK_MODE_MASK;
|
|
data = 0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET;
|
|
mask |= HPIPE_TX_NUM_OF_PRESET_MASK;
|
|
data |= 0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET;
|
|
mask |= HPIPE_TX_SWEEP_PRESET_EN_MASK;
|
|
data |= 0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_11_REG, data, mask);
|
|
|
|
/* Tx train start configuration */
|
|
mask = HPIPE_TX_TRAIN_START_SQ_EN_MASK;
|
|
data = 0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET;
|
|
mask |= HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK;
|
|
data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET;
|
|
mask |= HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK;
|
|
data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET;
|
|
mask |= HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK;
|
|
data |= 0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask);
|
|
|
|
/* Enable Tx train P2P */
|
|
mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK;
|
|
data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask);
|
|
|
|
/* Configure Tx train timeout */
|
|
mask = HPIPE_TRX_TRAIN_TIMER_MASK;
|
|
data = 0x17 << HPIPE_TRX_TRAIN_TIMER_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_4_REG, data, mask);
|
|
|
|
/* Disable G0/G1/GN1 adaptation */
|
|
mask = HPIPE_TX_TRAIN_CTRL_G1_MASK | HPIPE_TX_TRAIN_CTRL_GN1_MASK
|
|
| HPIPE_TX_TRAIN_CTRL_G0_OFFSET;
|
|
data = 0;
|
|
reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask);
|
|
|
|
/* Disable DTL frequency loop */
|
|
mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
|
|
data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
|
|
|
|
/* Configure G3 DFE */
|
|
mask = HPIPE_G3_DFE_RES_MASK;
|
|
data = 0x3 << HPIPE_G3_DFE_RES_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask);
|
|
|
|
/* Use TX/RX training result for DFE */
|
|
mask = HPIPE_DFE_RES_FORCE_MASK;
|
|
data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
|
|
|
|
/* Configure initial and final coefficient value for receiver */
|
|
mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK;
|
|
data = 0x1 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET;
|
|
|
|
mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK;
|
|
data |= 0x1 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET;
|
|
|
|
mask |= HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK;
|
|
data |= 0x0 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G3_SET_1_REG, data, mask);
|
|
|
|
/* Trigger sampler enable pulse */
|
|
mask = HPIPE_SMAPLER_MASK;
|
|
data = 0x1 << HPIPE_SMAPLER_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
|
|
udelay(5);
|
|
reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, 0, mask);
|
|
|
|
/* FFE resistor tuning for different bandwidth */
|
|
mask = HPIPE_G3_FFE_DEG_RES_LEVEL_MASK;
|
|
data = 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET;
|
|
mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK;
|
|
data |= 0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask);
|
|
|
|
/* Pattern lock lost timeout disable */
|
|
mask = HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK;
|
|
data = 0x0 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_3_REG, data, mask);
|
|
|
|
/* Configure DFE adaptations */
|
|
mask = HPIPE_CDR_RX_MAX_DFE_ADAPT_0_MASK;
|
|
data = 0x0 << HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET;
|
|
mask |= HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK;
|
|
data |= 0x0 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET;
|
|
mask |= HPIPE_CDR_MAX_DFE_ADAPT_0_MASK;
|
|
data |= 0x0 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET;
|
|
mask |= HPIPE_CDR_MAX_DFE_ADAPT_1_MASK;
|
|
data |= 0x1 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_CDR_CONTROL_REG, data, mask);
|
|
|
|
mask = HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK;
|
|
data = 0x0 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DFE_CONTROL_REG, data, mask);
|
|
|
|
/* Genration 2 setting 1*/
|
|
mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK;
|
|
data = 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET;
|
|
mask |= HPIPE_G2_SET_1_G2_RX_SELMUPF_MASK;
|
|
data |= 0x1 << HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET;
|
|
mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK;
|
|
data |= 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask);
|
|
|
|
/* DFE enable */
|
|
mask = HPIPE_G2_DFE_RES_MASK;
|
|
data = 0x3 << HPIPE_G2_DFE_RES_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G2_SETTINGS_4_REG, data, mask);
|
|
|
|
/* Configure DFE Resolution */
|
|
mask = HPIPE_LANE_CFG4_DFE_EN_SEL_MASK;
|
|
data = 0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask);
|
|
|
|
/* VDD calibration control */
|
|
mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
|
|
data = 0x16 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
|
|
|
|
/* Set PLL Charge-pump Current Control */
|
|
mask = HPIPE_G3_SETTING_5_G3_ICP_MASK;
|
|
data = 0x4 << HPIPE_G3_SETTING_5_G3_ICP_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G3_SETTING_5_REG, data, mask);
|
|
|
|
/* Set lane rqualization remote setting */
|
|
mask = HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK;
|
|
data = 0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET;
|
|
mask |= HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK;
|
|
data |= 0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET;
|
|
mask |= HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK;
|
|
data |= 0x6 << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_LANE_EQ_REMOTE_SETTING_REG, data, mask);
|
|
|
|
mask = HPIPE_CFG_EQ_BUNDLE_DIS_MASK;
|
|
data = 0x1 << HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_LANE_EQ_CFG2_REG, data, mask);
|
|
|
|
debug("stage: Comphy power up\n");
|
|
|
|
/* For PCIe X4 or X2:
|
|
* release from reset only after finish to configure all lanes
|
|
*/
|
|
if ((pcie_width == PCIE_LNK_X1) || (comphy_index == (pcie_width - 1))) {
|
|
uint32_t i, start_lane, end_lane;
|
|
|
|
if (pcie_width != PCIE_LNK_X1) {
|
|
/* allows writing to all lanes in one write */
|
|
data = 0x0;
|
|
if (pcie_width == PCIE_LNK_X2)
|
|
mask = COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK;
|
|
else if (pcie_width == PCIE_LNK_X4)
|
|
mask = COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK;
|
|
reg_set(comphy_base + COMMON_PHY_SD_CTRL1, data, mask);
|
|
start_lane = 0;
|
|
end_lane = pcie_width;
|
|
|
|
/* Release from PIPE soft reset
|
|
* For PCIe by4 or by2:
|
|
* release from soft reset all lanes - can't use
|
|
* read modify write
|
|
*/
|
|
reg_set(HPIPE_ADDR(
|
|
COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), 0) +
|
|
HPIPE_RST_CLK_CTRL_REG, 0x24, 0xffffffff);
|
|
} else {
|
|
start_lane = comphy_index;
|
|
end_lane = comphy_index + 1;
|
|
|
|
/* Release from PIPE soft reset
|
|
* for PCIe by4 or by2:
|
|
* release from soft reset all lanes
|
|
*/
|
|
reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG,
|
|
0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET,
|
|
HPIPE_RST_CLK_CTRL_PIPE_RST_MASK);
|
|
}
|
|
|
|
if (pcie_width != PCIE_LNK_X1) {
|
|
/* disable writing to all lanes with one write */
|
|
if (pcie_width == PCIE_LNK_X2) {
|
|
data = (COMPHY_LANE0 <<
|
|
COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET) |
|
|
(COMPHY_LANE1 <<
|
|
COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET);
|
|
mask = COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK;
|
|
} else if (pcie_width == PCIE_LNK_X4) {
|
|
data = (COMPHY_LANE0 <<
|
|
COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET) |
|
|
(COMPHY_LANE1 <<
|
|
COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET) |
|
|
(COMPHY_LANE2 <<
|
|
COMMON_PHY_SD_CTRL1_COMPHY_2_PORT_OFFSET) |
|
|
(COMPHY_LANE3 <<
|
|
COMMON_PHY_SD_CTRL1_COMPHY_3_PORT_OFFSET);
|
|
mask = COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK;
|
|
}
|
|
reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
|
|
data, mask);
|
|
}
|
|
|
|
debug("stage: Check PLL\n");
|
|
/* Read lane status */
|
|
for (i = start_lane; i < end_lane; i++) {
|
|
addr = HPIPE_ADDR(
|
|
COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), i) +
|
|
HPIPE_LANE_STATUS1_REG;
|
|
data = HPIPE_LANE_STATUS1_PCLK_EN_MASK;
|
|
mask = data;
|
|
ret = polling_with_timeout(addr, data, mask,
|
|
PLL_LOCK_TIMEOUT,
|
|
REG_32BIT);
|
|
if (ret)
|
|
ERROR("Failed to lock PCIE PLL\n");
|
|
}
|
|
}
|
|
|
|
debug_exit();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mvebu_cp110_comphy_rxaui_power_on(uint64_t comphy_base,
|
|
uint8_t comphy_index, uint32_t comphy_mode)
|
|
{
|
|
uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr;
|
|
uint32_t mask, data;
|
|
int ret = 0;
|
|
|
|
debug_enter();
|
|
|
|
hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
|
|
sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
|
|
/* configure phy selector for RXAUI */
|
|
mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index,
|
|
comphy_mode);
|
|
|
|
/* RFU configurations - hard reset comphy */
|
|
mask = COMMON_PHY_CFG1_PWR_UP_MASK;
|
|
data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
|
|
|
|
if (comphy_index == 2) {
|
|
reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
|
|
0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET,
|
|
COMMON_PHY_SD_CTRL1_RXAUI0_MASK);
|
|
}
|
|
if (comphy_index == 4) {
|
|
reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
|
|
0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET,
|
|
COMMON_PHY_SD_CTRL1_RXAUI1_MASK);
|
|
}
|
|
|
|
/* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
|
|
mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK;
|
|
data |= 0xB << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK;
|
|
data |= 0xB << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
|
|
|
|
/* release from hard reset */
|
|
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
/* Wait 1ms - until band gap and ref clock ready */
|
|
mdelay(1);
|
|
|
|
/* Start comphy Configuration */
|
|
debug("stage: Comphy configuration\n");
|
|
/* set reference clock */
|
|
reg_set(hpipe_addr + HPIPE_MISC_REG,
|
|
0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
|
|
HPIPE_MISC_REFCLK_SEL_MASK);
|
|
/* Power and PLL Control */
|
|
mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
|
|
data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
|
|
mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
|
|
data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
|
|
/* Loopback register */
|
|
reg_set(hpipe_addr + HPIPE_LOOPBACK_REG,
|
|
0x1 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK);
|
|
/* rx control 1 */
|
|
mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK;
|
|
data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET;
|
|
mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK;
|
|
data |= 0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask);
|
|
/* DTL Control */
|
|
reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG,
|
|
0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET,
|
|
HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK);
|
|
|
|
/* Set analog parameters from ETP(HW) */
|
|
debug("stage: Analog parameters from ETP(HW)\n");
|
|
/* SERDES External Configuration 2 */
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG,
|
|
0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET,
|
|
SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK);
|
|
/* 0x7-DFE Resolution control */
|
|
reg_set(hpipe_addr + HPIPE_DFE_REG0, 0x1 << HPIPE_DFE_RES_FORCE_OFFSET,
|
|
HPIPE_DFE_RES_FORCE_MASK);
|
|
/* 0xd-G1_Setting_0 */
|
|
reg_set(hpipe_addr + HPIPE_G1_SET_0_REG,
|
|
0xd << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET,
|
|
HPIPE_G1_SET_0_G1_TX_EMPH1_MASK);
|
|
/* 0xE-G1_Setting_1 */
|
|
mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
|
|
data = 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK;
|
|
data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
|
|
mask |= HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK;
|
|
data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
|
|
/* 0xA-DFE_Reg3 */
|
|
mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
|
|
data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
|
|
mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK;
|
|
data |= 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask);
|
|
|
|
/* 0x111-G1_Setting_4 */
|
|
mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
|
|
data = 0x1 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
|
|
|
|
debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n");
|
|
/* SERDES External Configuration */
|
|
mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
|
|
|
|
|
|
/* check PLL rx & tx ready */
|
|
addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
|
|
data = SD_EXTERNAL_STATUS0_PLL_RX_MASK |
|
|
SD_EXTERNAL_STATUS0_PLL_TX_MASK;
|
|
mask = data;
|
|
data = polling_with_timeout(addr, data, mask, 15000, REG_32BIT);
|
|
if (data != 0) {
|
|
debug("Read from reg = %lx - value = 0x%x\n",
|
|
sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data);
|
|
ERROR("SD_EXTERNAL_STATUS0_PLL_RX is %d, -\"-_PLL_TX is %d\n",
|
|
(data & SD_EXTERNAL_STATUS0_PLL_RX_MASK),
|
|
(data & SD_EXTERNAL_STATUS0_PLL_TX_MASK));
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
|
|
/* RX init */
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG,
|
|
0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET,
|
|
SD_EXTERNAL_CONFIG1_RX_INIT_MASK);
|
|
|
|
/* check that RX init done */
|
|
addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
|
|
data = SD_EXTERNAL_STATUS0_RX_INIT_MASK;
|
|
mask = data;
|
|
data = polling_with_timeout(addr, data, mask, 100, REG_32BIT);
|
|
if (data != 0) {
|
|
debug("Read from reg = %lx - value = 0x%x\n",
|
|
sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data);
|
|
ERROR("SD_EXTERNAL_STATUS0_RX_INIT is 0\n");
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
|
|
debug("stage: RF Reset\n");
|
|
/* RF Reset */
|
|
mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
debug_exit();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mvebu_cp110_comphy_usb3_power_on(uint64_t comphy_base,
|
|
uint8_t comphy_index, uint32_t comphy_mode)
|
|
{
|
|
uintptr_t hpipe_addr, comphy_addr, addr;
|
|
uint32_t mask, data;
|
|
int ret = 0;
|
|
|
|
debug_enter();
|
|
|
|
/* Configure PIPE selector for USB3 */
|
|
mvebu_cp110_comphy_set_pipe_selector(comphy_base, comphy_index,
|
|
comphy_mode);
|
|
|
|
hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
|
|
|
|
debug("stage: RFU configurations - hard reset comphy\n");
|
|
/* RFU configurations - hard reset comphy */
|
|
mask = COMMON_PHY_CFG1_PWR_UP_MASK;
|
|
data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
|
|
data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
|
|
mask |= COMMON_PHY_PHY_MODE_MASK;
|
|
data |= 0x1 << COMMON_PHY_PHY_MODE_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
|
|
|
|
/* release from hard reset */
|
|
mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
|
|
data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
|
|
data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
|
|
|
|
/* Wait 1ms - until band gap and ref clock ready */
|
|
mdelay(1);
|
|
|
|
/* Start comphy Configuration */
|
|
debug("stage: Comphy configuration\n");
|
|
/* Set PIPE soft reset */
|
|
mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK;
|
|
data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET;
|
|
/* Set PHY datapath width mode for V0 */
|
|
mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK;
|
|
data |= 0x0 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET;
|
|
/* Set Data bus width USB mode for V0 */
|
|
mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK;
|
|
data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET;
|
|
/* Set CORE_CLK output frequency for 250Mhz */
|
|
mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK;
|
|
data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask);
|
|
/* Set PLL ready delay for 0x2 */
|
|
reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG,
|
|
0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET,
|
|
HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK);
|
|
/* Set reference clock to come from group 1 - 25Mhz */
|
|
reg_set(hpipe_addr + HPIPE_MISC_REG,
|
|
0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
|
|
HPIPE_MISC_REFCLK_SEL_MASK);
|
|
/* Set reference frequcency select - 0x2 */
|
|
mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
|
|
data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
|
|
/* Set PHY mode to USB - 0x5 */
|
|
mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
|
|
data |= 0x5 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
|
|
/* Set the amount of time spent in the LoZ state - set for 0x7 */
|
|
reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL,
|
|
0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET,
|
|
HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK);
|
|
/* Set max PHY generation setting - 5Gbps */
|
|
reg_set(hpipe_addr + HPIPE_INTERFACE_REG,
|
|
0x1 << HPIPE_INTERFACE_GEN_MAX_OFFSET,
|
|
HPIPE_INTERFACE_GEN_MAX_MASK);
|
|
/* Set select data width 20Bit (SEL_BITS[2:0]) */
|
|
reg_set(hpipe_addr + HPIPE_LOOPBACK_REG,
|
|
0x1 << HPIPE_LOOPBACK_SEL_OFFSET,
|
|
HPIPE_LOOPBACK_SEL_MASK);
|
|
/* select de-emphasize 3.5db */
|
|
reg_set(hpipe_addr + HPIPE_LANE_CONFIG0_REG,
|
|
0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET,
|
|
HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK);
|
|
/* override tx margining from the MAC */
|
|
reg_set(hpipe_addr + HPIPE_TST_MODE_CTRL_REG,
|
|
0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET,
|
|
HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK);
|
|
|
|
/* Start analog parameters from ETP(HW) */
|
|
debug("stage: Analog parameters from ETP(HW)\n");
|
|
/* Set Pin DFE_PAT_DIS -> Bit[1]: PIN_DFE_PAT_DIS = 0x0 */
|
|
mask = HPIPE_LANE_CFG4_DFE_CTRL_MASK;
|
|
data = 0x1 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET;
|
|
/* Set Override PHY DFE control pins for 0x1 */
|
|
mask |= HPIPE_LANE_CFG4_DFE_OVER_MASK;
|
|
data |= 0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET;
|
|
/* Set Spread Spectrum Clock Enable fot 0x1 */
|
|
mask |= HPIPE_LANE_CFG4_SSC_CTRL_MASK;
|
|
data |= 0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask);
|
|
/* Confifure SSC amplitude */
|
|
mask = HPIPE_G2_TX_SSC_AMP_MASK;
|
|
data = 0x1f << HPIPE_G2_TX_SSC_AMP_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G2_SET_2_REG, data, mask);
|
|
/* End of analog parameters */
|
|
|
|
debug("stage: Comphy power up\n");
|
|
/* Release from PIPE soft reset */
|
|
reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG,
|
|
0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET,
|
|
HPIPE_RST_CLK_CTRL_PIPE_RST_MASK);
|
|
|
|
/* wait 15ms - for comphy calibration done */
|
|
debug("stage: Check PLL\n");
|
|
/* Read lane status */
|
|
addr = hpipe_addr + HPIPE_LANE_STATUS1_REG;
|
|
data = HPIPE_LANE_STATUS1_PCLK_EN_MASK;
|
|
mask = data;
|
|
data = polling_with_timeout(addr, data, mask, 15000, REG_32BIT);
|
|
if (data != 0) {
|
|
debug("Read from reg = %lx - value = 0x%x\n",
|
|
hpipe_addr + HPIPE_LANE_STATUS1_REG, data);
|
|
ERROR("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n");
|
|
ret = -ETIMEDOUT;
|
|
}
|
|
|
|
debug_exit();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mvebu_cp110_comphy_xfi_rx_training(uint64_t comphy_base,
|
|
uint8_t comphy_index)
|
|
{
|
|
uint32_t mask, data, timeout;
|
|
uint32_t g1_ffe_cap_sel, g1_ffe_res_sel, align90, g1_dfe_res;
|
|
uintptr_t hpipe_addr, sd_ip_addr;
|
|
|
|
uint8_t ap_nr, cp_nr;
|
|
|
|
mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
|
|
|
|
hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
|
|
debug_enter();
|
|
|
|
debug("stage: RF Reset\n");
|
|
|
|
/* Release from hard reset */
|
|
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
|
|
data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
|
|
data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
/* Wait 50ms - until band gap and ref clock ready */
|
|
mdelay(50);
|
|
|
|
debug("Preparation for rx_training\n\n");
|
|
|
|
/* Use the FFE table */
|
|
mask = HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
|
|
data = 0 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
|
|
|
|
/* Use auto-calibration value */
|
|
mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK;
|
|
data = 0 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
|
|
data, mask);
|
|
|
|
/* Use Tx/Rx training results */
|
|
mask = HPIPE_DFE_RES_FORCE_MASK;
|
|
data = 0 << HPIPE_DFE_RES_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
|
|
|
|
debug("PRBS31 loppback\n\n");
|
|
|
|
/* Configure PRBS counters */
|
|
mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
|
|
data = 0xe << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
|
|
|
|
mask = HPIPE_PHY_TEST_DATA_MASK;
|
|
data = 0xc4 << HPIPE_PHY_TEST_DATA_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHY_TEST_DATA_REG, data, mask);
|
|
|
|
mask = HPIPE_PHY_TEST_EN_MASK;
|
|
data = 0x1 << HPIPE_PHY_TEST_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
|
|
|
|
mdelay(10);
|
|
debug("Enable TX/RX training\n\n");
|
|
|
|
mask = HPIPE_TRX_RX_TRAIN_EN_MASK;
|
|
data = 0x1 << HPIPE_TRX_RX_TRAIN_EN_OFFSET;
|
|
mask |= HPIPE_TRX_RX_ANA_IF_CLK_ENE_MASK;
|
|
data |= 0x1 << HPIPE_TRX_RX_ANA_IF_CLK_ENE_OFFSET;
|
|
mask |= HPIPE_TRX_TX_CTRL_CLK_EN_MASK;
|
|
data |= 0x1 << HPIPE_TRX_TX_CTRL_CLK_EN_OFFSET;
|
|
mask |= HPIPE_TRX_UPDATE_THEN_HOLD_MASK;
|
|
data |= 0x1 << HPIPE_TRX_UPDATE_THEN_HOLD_OFFSET;
|
|
mask |= HPIPE_TRX_TX_F0T_EO_BASED_MASK;
|
|
data |= 0x1 << HPIPE_TRX_TX_F0T_EO_BASED_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TRX_TRAIN_CTRL_0_REG, data, mask);
|
|
|
|
/* Check the result of RX training */
|
|
timeout = RX_TRAINING_TIMEOUT;
|
|
mask = HPIPE_INTERRUPT_TRX_TRAIN_DONE_OFFSET |
|
|
HPIPE_INTERRUPT_DFE_DONE_INT_OFFSET |
|
|
HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_MASK;
|
|
while (timeout) {
|
|
data = mmio_read_32(hpipe_addr + HPIPE_INTERRUPT_1_REGISTER);
|
|
if (data & mask)
|
|
break;
|
|
mdelay(1);
|
|
timeout--;
|
|
}
|
|
|
|
debug("RX training result: interrupt reg 0x%lx = 0x%x\n\n",
|
|
hpipe_addr + HPIPE_INTERRUPT_1_REGISTER, data);
|
|
|
|
if (timeout == 0 || data & HPIPE_TRX_TRAIN_TIME_OUT_INT_MASK) {
|
|
ERROR("Rx training timeout...\n");
|
|
return -ETIMEDOUT;
|
|
}
|
|
|
|
if (data & HPIPE_TRX_TRAIN_FAILED_MASK) {
|
|
ERROR("Rx training failed...\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
mask = HPIPE_TRX_RX_TRAIN_EN_MASK;
|
|
data = 0x0 << HPIPE_TRX_RX_TRAIN_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_TRX_TRAIN_CTRL_0_REG, data, mask);
|
|
|
|
debug("Training done, reading results...\n\n");
|
|
|
|
mask = HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_MASK;
|
|
g1_ffe_res_sel = ((mmio_read_32(hpipe_addr +
|
|
HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG)
|
|
& mask) >> HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_OFFSET);
|
|
|
|
mask = HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_MASK;
|
|
g1_ffe_cap_sel = ((mmio_read_32(hpipe_addr +
|
|
HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG)
|
|
& mask) >> HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_OFFSET);
|
|
|
|
mask = HPIPE_DATA_PHASE_ADAPTED_OS_PH_MASK;
|
|
align90 = ((mmio_read_32(hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG)
|
|
& mask) >> HPIPE_DATA_PHASE_ADAPTED_OS_PH_OFFSET);
|
|
|
|
mask = HPIPE_ADAPTED_DFE_RES_MASK;
|
|
g1_dfe_res = ((mmio_read_32(hpipe_addr +
|
|
HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG)
|
|
& mask) >> HPIPE_ADAPTED_DFE_RES_OFFSET);
|
|
|
|
debug("================================================\n");
|
|
debug("Switching to static configuration:\n");
|
|
debug("FFE_RES = 0x%x FFE_CAP = 0x%x align90 = 0x%x g1_dfe_res 0x%x\n",
|
|
g1_ffe_res_sel, g1_ffe_cap_sel, align90, g1_dfe_res);
|
|
debug("Result after training: 0x%lx= 0x%x, 0x%lx= 0x%x, 0x%lx = 0x%x\n",
|
|
(hpipe_addr + HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG),
|
|
mmio_read_32(hpipe_addr +
|
|
HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG),
|
|
(hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG),
|
|
mmio_read_32(hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG),
|
|
(hpipe_addr + HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG),
|
|
mmio_read_32(hpipe_addr + HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG));
|
|
debug("================================================\n");
|
|
|
|
/* Update FFE_RES */
|
|
mask = HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
|
|
data = g1_ffe_res_sel << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
|
|
|
|
/* Update FFE_CAP */
|
|
mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
|
|
data = g1_ffe_cap_sel << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
|
|
|
|
/* Bypass the FFE table settings and use the FFE settings directly from
|
|
* registers FFE_RES_SEL and FFE_CAP_SEL
|
|
*/
|
|
mask = HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
|
|
data = 1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
|
|
|
|
/* Use the value from CAL_OS_PH_EXT */
|
|
mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK;
|
|
data = 1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
|
|
data, mask);
|
|
|
|
/* Update align90 */
|
|
mask = HPIPE_CAL_OS_PH_EXT_MASK;
|
|
data = align90 << HPIPE_CAL_OS_PH_EXT_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
|
|
data, mask);
|
|
|
|
/* Force DFE resolution (use gen table value) */
|
|
mask = HPIPE_DFE_RES_FORCE_MASK;
|
|
data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
|
|
|
|
/* 0x111-G1 DFE_Setting_4 */
|
|
mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
|
|
data = g1_dfe_res << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
|
|
|
|
debug("PRBS31 loppback\n\n");
|
|
|
|
mask = HPIPE_PHY_TEST_PT_TESTMODE_MASK;
|
|
data = 0x1 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHY_TEST_OOB_0_REGISTER, data, mask);
|
|
|
|
/* Configure PRBS counters */
|
|
mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
|
|
data = 0xe << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
|
|
|
|
mask = HPIPE_PHY_TEST_DATA_MASK;
|
|
data = 0xc4 << HPIPE_PHY_TEST_DATA_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHY_TEST_DATA_REG, data, mask);
|
|
|
|
mask = HPIPE_PHY_TEST_EN_MASK;
|
|
data = 0x1 << HPIPE_PHY_TEST_EN_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
|
|
|
|
/* Reset PRBS error counter */
|
|
mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
|
|
data = 0x1 << HPIPE_PHY_TEST_RESET_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
|
|
|
|
mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
|
|
data = 0x0 << HPIPE_PHY_TEST_RESET_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
|
|
|
|
mask = HPIPE_PHY_TEST_PT_TESTMODE_MASK;
|
|
data = 0x1 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET;
|
|
reg_set(hpipe_addr + HPIPE_PHY_TEST_OOB_0_REGISTER, data, mask);
|
|
|
|
printf("########################################################\n");
|
|
printf("# To use trained values update the ATF sources:\n");
|
|
printf("# plat/marvell/a8k/<board_type>/board/phy-porting-layer.h ");
|
|
printf("file\n# with new values as below (for appropriate AP nr %d",
|
|
ap_nr);
|
|
printf("and CP nr: %d comphy_index %d\n\n",
|
|
cp_nr, comphy_index);
|
|
printf("static struct xfi_params xfi_static_values_tab[AP_NUM]");
|
|
printf("[CP_NUM][MAX_LANE_NR] = {\n");
|
|
printf("\t...\n");
|
|
printf("\t.g1_ffe_res_sel = 0x%x,\n", g1_ffe_res_sel);
|
|
printf("\t.g1_ffe_cap_sel = 0x%x,\n", g1_ffe_cap_sel);
|
|
printf("\t.align90 = 0x%x,\n", align90);
|
|
printf("\t.g1_dfe_res = 0x%x\n", g1_dfe_res);
|
|
printf("\t...\n");
|
|
printf("};\n\n");
|
|
printf("########################################################\n");
|
|
|
|
/* check */
|
|
debug("PRBS error counter[0x%lx] 0x%x\n\n",
|
|
hpipe_addr + HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG,
|
|
mmio_read_32(hpipe_addr +
|
|
HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG));
|
|
|
|
rx_trainng_done[ap_nr][cp_nr][comphy_index] = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* During AP the proper mode is auto-negotiated and the mac, pcs and serdes
|
|
* configuration are done by the firmware loaded to the MG's CM3 for appropriate
|
|
* negotiated mode. Therefore there is no need to configure the mac, pcs and
|
|
* serdes from u-boot. The only thing that need to be setup is powering up
|
|
* the comphy, which is done through Common PHY<n> Configuration 1 Register
|
|
* (CP0: 0xF2441000, CP1: 0xF4441000). This step can't be done by MG's CM3,
|
|
* since it doesn't have an access to this register-set (but it has access to
|
|
* the network registers like: MG, AP, MAC, PCS, Serdes etc.)
|
|
*/
|
|
static int mvebu_cp110_comphy_ap_power_on(uint64_t comphy_base,
|
|
uint8_t comphy_index)
|
|
{
|
|
uint32_t mask, data;
|
|
uintptr_t comphy_addr = comphy_addr =
|
|
COMPHY_ADDR(comphy_base, comphy_index);
|
|
|
|
debug_enter();
|
|
debug("stage: RFU configurations - hard reset comphy\n");
|
|
/* RFU configurations - hard reset comphy */
|
|
mask = COMMON_PHY_CFG1_PWR_UP_MASK;
|
|
data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
|
|
reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
|
|
debug_exit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* This function allows to reset the digital synchronizers between
|
|
* the MAC and the PHY, it is required when the MAC changes its state.
|
|
*/
|
|
int mvebu_cp110_comphy_digital_reset(uint64_t comphy_base,
|
|
uint8_t comphy_index,
|
|
uint32_t comphy_mode, uint32_t command)
|
|
{
|
|
int mode = COMPHY_GET_MODE(comphy_mode);
|
|
uintptr_t sd_ip_addr;
|
|
uint32_t mask, data;
|
|
|
|
sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
|
|
switch (mode) {
|
|
case (COMPHY_SGMII_MODE):
|
|
case (COMPHY_HS_SGMII_MODE):
|
|
case (COMPHY_XFI_MODE):
|
|
case (COMPHY_SFI_MODE):
|
|
case (COMPHY_RXAUI_MODE):
|
|
mask = SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
|
|
data = ((command == COMPHY_COMMAND_DIGITAL_PWR_OFF) ?
|
|
0x0 : 0x1) << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
break;
|
|
default:
|
|
ERROR("comphy%d: Digital PWR ON/OFF is not supported\n",
|
|
comphy_index);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mvebu_cp110_comphy_power_on(uint64_t comphy_base, uint8_t comphy_index,
|
|
uint64_t comphy_mode)
|
|
{
|
|
int mode = COMPHY_GET_MODE(comphy_mode);
|
|
int err = 0;
|
|
|
|
debug_enter();
|
|
|
|
switch (mode) {
|
|
case(COMPHY_SATA_MODE):
|
|
err = mvebu_cp110_comphy_sata_power_on(comphy_base,
|
|
comphy_index,
|
|
comphy_mode);
|
|
break;
|
|
case(COMPHY_SGMII_MODE):
|
|
case(COMPHY_HS_SGMII_MODE):
|
|
err = mvebu_cp110_comphy_sgmii_power_on(comphy_base,
|
|
comphy_index,
|
|
comphy_mode);
|
|
break;
|
|
/* From comphy perspective, XFI and SFI are the same */
|
|
case (COMPHY_XFI_MODE):
|
|
case (COMPHY_SFI_MODE):
|
|
err = mvebu_cp110_comphy_xfi_power_on(comphy_base,
|
|
comphy_index,
|
|
comphy_mode);
|
|
break;
|
|
case (COMPHY_PCIE_MODE):
|
|
err = mvebu_cp110_comphy_pcie_power_on(comphy_base,
|
|
comphy_index,
|
|
comphy_mode);
|
|
break;
|
|
case (COMPHY_RXAUI_MODE):
|
|
err = mvebu_cp110_comphy_rxaui_power_on(comphy_base,
|
|
comphy_index,
|
|
comphy_mode);
|
|
break;
|
|
case (COMPHY_USB3H_MODE):
|
|
case (COMPHY_USB3D_MODE):
|
|
err = mvebu_cp110_comphy_usb3_power_on(comphy_base,
|
|
comphy_index,
|
|
comphy_mode);
|
|
break;
|
|
case (COMPHY_AP_MODE):
|
|
err = mvebu_cp110_comphy_ap_power_on(comphy_base, comphy_index);
|
|
break;
|
|
default:
|
|
ERROR("comphy%d: unsupported comphy mode\n", comphy_index);
|
|
err = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
debug_exit();
|
|
|
|
return err;
|
|
}
|
|
|
|
int mvebu_cp110_comphy_power_off(uint64_t comphy_base, uint8_t comphy_index,
|
|
uint64_t comphy_mode)
|
|
{
|
|
uintptr_t sd_ip_addr, comphy_ip_addr;
|
|
uint32_t mask, data;
|
|
uint8_t ap_nr, cp_nr;
|
|
_Bool called_from_uboot = COMPHY_GET_CALLER(comphy_mode);
|
|
|
|
debug_enter();
|
|
|
|
/* Power-off might happen because of 2 things:
|
|
* 1. Bootloader turns off unconnected lanes
|
|
* 2. Linux turns off all lanes during boot
|
|
* (and then reconfigure it).
|
|
*
|
|
* For PCIe, there's a problem:
|
|
* In Armada 8K DB boards, PCIe initialization can be executed
|
|
* only once (PCIe reset performed during chip power on and
|
|
* it cannot be executed via GPIO later) so a lane configured to
|
|
* PCIe should not be powered off by Linux.
|
|
*
|
|
* So, check 2 things:
|
|
* 1. Is Linux called for power-off?
|
|
* 2. Is the comphy configured to PCIe?
|
|
* If the answer is YES for both 1 and 2, skip the power-off.
|
|
*
|
|
* TODO: In MacciatoBIN, PCIe reset is connected via GPIO,
|
|
* so after GPIO reset is added to Linux Kernel, it can be
|
|
* powered-off.
|
|
*/
|
|
if (!called_from_uboot) {
|
|
data = mmio_read_32(comphy_base +
|
|
COMMON_SELECTOR_PIPE_REG_OFFSET);
|
|
data >>= (COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index);
|
|
data &= COMMON_SELECTOR_COMPHY_MASK;
|
|
if (data == COMMON_SELECTOR_PIPE_COMPHY_PCIE)
|
|
return 0;
|
|
}
|
|
|
|
mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
|
|
|
|
if (rx_trainng_done[ap_nr][cp_nr][comphy_index]) {
|
|
debug("Skip %s for comphy[%d][%d][%d], due to rx training\n",
|
|
__func__, ap_nr, cp_nr, comphy_index);
|
|
return 0;
|
|
}
|
|
|
|
sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
|
|
comphy_index);
|
|
comphy_ip_addr = COMPHY_ADDR(comphy_base, comphy_index);
|
|
|
|
/* Hard reset the comphy, for Ethernet modes and Sata */
|
|
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
|
|
data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
|
|
mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
|
|
data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
|
|
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
|
|
|
|
/* PCIe reset */
|
|
spin_lock(&cp110_mac_reset_lock);
|
|
|
|
/* The mvebu_cp110_comphy_power_off will be called only from Linux (to
|
|
* override settings done by bootloader) and it will be relevant only
|
|
* to PCIe (called before check if to skip pcie power off or not).
|
|
*/
|
|
data = mmio_read_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
|
|
SYS_CTRL_UINIT_SOFT_RESET_REG);
|
|
switch (comphy_index) {
|
|
case COMPHY_LANE0:
|
|
data &= ~PCIE_MAC_RESET_MASK_PORT0;
|
|
break;
|
|
case COMPHY_LANE4:
|
|
data &= ~PCIE_MAC_RESET_MASK_PORT1;
|
|
break;
|
|
case COMPHY_LANE5:
|
|
data &= ~PCIE_MAC_RESET_MASK_PORT2;
|
|
break;
|
|
}
|
|
|
|
mmio_write_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
|
|
SYS_CTRL_UINIT_SOFT_RESET_REG, data);
|
|
spin_unlock(&cp110_mac_reset_lock);
|
|
|
|
/* Hard reset the comphy, for PCIe and usb3 */
|
|
mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
|
|
data = 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
|
|
mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
|
|
data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
|
|
reg_set(comphy_ip_addr + COMMON_PHY_CFG1_REG, data, mask);
|
|
|
|
/* Clear comphy PHY and PIPE selector, can't rely on previous config. */
|
|
mvebu_cp110_comphy_clr_phy_selector(comphy_base, comphy_index);
|
|
mvebu_cp110_comphy_clr_pipe_selector(comphy_base, comphy_index);
|
|
|
|
debug_exit();
|
|
|
|
return 0;
|
|
}
|