| /* |
| * Copyright (C) 2018 Marvell International Ltd. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| * https://spdx.org/licenses |
| */ |
| |
| /* Marvell CP110 SoC COMPHY unit driver */ |
| |
| #include <errno.h> |
| #include <inttypes.h> |
| #include <stdint.h> |
| |
| #include <common/debug.h> |
| #include <drivers/delay_timer.h> |
| #include <mg_conf_cm3/mg_conf_cm3.h> |
| #include <lib/mmio.h> |
| #include <lib/spinlock.h> |
| |
| #include <mvebu_def.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 /* 2500Base-X */ |
| #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_CP0_OFFSET (30) |
| #define SAR_RST_PCIE0_CLOCK_CONFIG_CP0_MASK (0x1UL << \ |
| SAR_RST_PCIE0_CLOCK_CONFIG_CP0_OFFSET) |
| #define SAR_RST_PCIE1_CLOCK_CONFIG_CP0_OFFSET (31) |
| #define SAR_RST_PCIE1_CLOCK_CONFIG_CP0_MASK (0x1UL << \ |
| SAR_RST_PCIE1_CLOCK_CONFIG_CP0_OFFSET) |
| #define SAR_STATUS_0_REG 0x40600 |
| #define DFX_FROM_COMPHY_ADDR(x) ((x & ~0xffffff) + DFX_BASE) |
| /* Common Phy training */ |
| #define COMPHY_TRX_TRAIN_COMPHY_OFFS 0x1000 |
| #define COMPHY_TRX_TRAIN_RX_TRAIN_ENABLE 0x1 |
| #define COMPHY_TRX_RELATIVE_ADDR(comphy_index) (comphy_train_base + \ |
| (comphy_index) * COMPHY_TRX_TRAIN_COMPHY_OFFS) |
| |
| /* 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%" PRIx64 ", 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/Base-X 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/Base-X Port1, XFI1/SFI1 |
| * 0x2 = SGMII/Base-X Port0: XFI0/SFI0, RXAUI_Lane0 |
| * |
| * We want to check if 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 too. |
| */ |
| /* TODO: need to distinguish between CP110 and CP115 |
| * as SFI1/XFI1 available only for CP115. |
| */ |
| if ((mode == COMPHY_SGMII_MODE || |
| mode == COMPHY_2500BASEX_MODE || |
| mode == COMPHY_SFI_MODE || |
| mode == COMPHY_XFI_MODE || |
| mode == COMPHY_AP_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/Base-X 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 void mvebu_cp110_polarity_invert(uintptr_t addr, uint8_t phy_polarity_invert) |
| { |
| uint32_t mask, data; |
| |
| /* Set RX / TX polarity */ |
| data = mask = 0x0U; |
| if ((phy_polarity_invert & COMPHY_POLARITY_TXD_INVERT) != 0) { |
| data |= (1 << HPIPE_SYNC_PATTERN_TXD_INV_OFFSET); |
| mask |= HPIPE_SYNC_PATTERN_TXD_INV_MASK; |
| debug("%s: inverting TX polarity\n", __func__); |
| } |
| |
| if ((phy_polarity_invert & COMPHY_POLARITY_RXD_INVERT) != 0) { |
| data |= (1 << HPIPE_SYNC_PATTERN_RXD_INV_OFFSET); |
| mask |= HPIPE_SYNC_PATTERN_RXD_INV_MASK; |
| debug("%s: inverting RX polarity\n", __func__); |
| } |
| |
| reg_set(addr, data, mask); |
| } |
| |
| 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, phy_polarity_invert; |
| 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]; |
| |
| phy_polarity_invert = sata_static_values->polarity_invert; |
| |
| /* 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); |
| |
| if (phy_polarity_invert != 0) |
| mvebu_cp110_polarity_invert(hpipe_addr + HPIPE_SYNC_PATTERN_REG, |
| phy_polarity_invert); |
| |
| /* 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) { |
| /* 2500Base-X, 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, |
| uint64_t comphy_train_base) |
| { |
| 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; |
| mask |= SD_EXTERNAL_CONFIG1_TX_IDLE_MASK; |
| data |= 0x1 << SD_EXTERNAL_CONFIG1_TX_IDLE_OFFSET; |
| reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); |
| |
| /* Wait 1ms - until band gap and ref clock ready */ |
| mdelay(1); |
| |
| /* |
| * Erratum IPCE_COMPHY-1353: toggle TX_IDLE bit in |
| * addition to the PHY reset |
| */ |
| mask = SD_EXTERNAL_CONFIG1_TX_IDLE_MASK; |
| data = 0x0U; |
| reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); |
| |
| /* 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); |
| |
| /* Force rx training on 10G port */ |
| data = mmio_read_32(COMPHY_TRX_RELATIVE_ADDR(comphy_index)); |
| data |= COMPHY_TRX_TRAIN_RX_TRAIN_ENABLE; |
| mmio_write_32(COMPHY_TRX_RELATIVE_ADDR(comphy_index), data); |
| mdelay(200); |
| data &= ~COMPHY_TRX_TRAIN_RX_TRAIN_ENABLE; |
| mmio_write_32(COMPHY_TRX_RELATIVE_ADDR(comphy_index), data); |
| |
| 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_CP0_MASK) >> |
| SAR_RST_PCIE1_CLOCK_CONFIG_CP0_OFFSET; |
| else |
| clk_dir = (reg & SAR_RST_PCIE0_CLOCK_CONFIG_CP0_MASK) >> |
| SAR_RST_PCIE0_CLOCK_CONFIG_CP0_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; |
| data = polling_with_timeout(addr, data, mask, |
| PLL_LOCK_TIMEOUT, |
| REG_32BIT); |
| if (data) { |
| ERROR("Failed to lock PCIE PLL\n"); |
| ret = -ETIMEDOUT; |
| } |
| } |
| } |
| |
| 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; |
| uint8_t ap_nr, cp_nr, phy_polarity_invert; |
| int ret = 0; |
| |
| debug_enter(); |
| |
| /* Configure PIPE selector for USB3 */ |
| mvebu_cp110_comphy_set_pipe_selector(comphy_base, comphy_index, |
| comphy_mode); |
| |
| mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base); |
| |
| const struct usb_params *usb_static_values = |
| &usb_static_values_tab[ap_nr][cp_nr][comphy_index]; |
| |
| phy_polarity_invert = usb_static_values->polarity_invert; |
| |
| 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); |
| |
| /* The polarity inversion for USB was not tested due to lack of hw |
| * design which requires it. Support is added for customer needs. |
| */ |
| if (phy_polarity_invert) |
| mvebu_cp110_polarity_invert(hpipe_addr + HPIPE_SYNC_PATTERN_REG, |
| phy_polarity_invert); |
| |
| /* 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); |
| /* Configure 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; |
| } |
| |
| static void rx_pre_train(uint64_t comphy_base, uint8_t comphy_index) |
| { |
| uintptr_t hpipe_addr; |
| uint32_t mask, data; |
| |
| hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), |
| comphy_index); |
| |
| debug("rx_training preparation\n\n"); |
| |
| mask = HPIPE_TRX0_GAIN_TRAIN_WITH_C_MASK; |
| data = (0x1 << HPIPE_TRX0_GAIN_TRAIN_WITH_C_OFF); |
| mask |= HPIPE_TRX0_GAIN_TRAIN_WITH_SAMPLER_MASK; |
| data |= (0x0 << HPIPE_TRX0_GAIN_TRAIN_WITH_SAMPLER_OFF); |
| reg_set(hpipe_addr + HPIPE_TRX0_REG, data, mask); |
| |
| |
| mask = HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_MASK; |
| data = (0x1e << HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_OFF); |
| mask |= HPIPE_TRX_REG2_SUMF_BOOST_TARGET_K_MASK; |
| data |= (0x0 << HPIPE_TRX_REG2_SUMF_BOOST_TARGET_K_OFF); |
| reg_set(hpipe_addr + HPIPE_TRX_REG2, data, mask); |
| |
| mask = HPIPE_TRX_REG1_MIN_BOOST_MODE_MASK; |
| data = (0x1 << HPIPE_TRX_REG1_MIN_BOOST_MODE_OFF); |
| reg_set(hpipe_addr + HPIPE_TRX_REG1, data, mask); |
| |
| mask = HPIPE_CRD2_CRD_MIDPOINT_SMALL_THRES_K_MASK; |
| data = (0x8 << HPIPE_CRD2_CRD_MIDPOINT_SMALL_THRES_K_OFF); |
| reg_set(hpipe_addr + HPIPE_CDR_CONTROL1_REG, data, mask); |
| |
| mask = HPIPE_CRD2_CRD_MIDPOINT_LARGE_THRES_K_MASK; |
| data = (0x8 << HPIPE_CRD2_CRD_MIDPOINT_LARGE_THRES_K_OFF); |
| reg_set(hpipe_addr + HPIPE_CDR_CONTROL2_REG, data, mask); |
| |
| mask = HPIPE_CRD_MIDPOINT_PHASE_OS_MASK; |
| data = (0x0 << HPIPE_CRD_MIDPOINT_PHASE_OS_OFFSET); |
| reg_set(hpipe_addr + HPIPE_CDR_CONTROL_REG, data, mask); |
| |
| mask = HPIPE_TRX_REG1_SUMFTAP_EN_MASK; |
| data = (0x38 << HPIPE_TRX_REG1_SUMFTAP_EN_OFF); |
| mask |= HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_MASK; |
| data |= (0x1e << HPIPE_TRX_REG2_SUMF_BOOST_TARGET_C_OFF); |
| reg_set(hpipe_addr + HPIPE_TRX_REG1, data, mask); |
| } |
| |
| 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; |
| |
| 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); |
| |
| debug_enter(); |
| |
| rx_pre_train(comphy_base, comphy_index); |
| |
| 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("Enable RX training\n\n"); |
| |
| mask = HPIPE_TRX_RX_TRAIN_EN_MASK; |
| data = 0x1 << HPIPE_TRX_RX_TRAIN_EN_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); |
| |
| /* Force DFE resolution (use gen table value) */ |
| mask = HPIPE_DFE_RES_FORCE_MASK; |
| data = 0x1 << 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); |
| |
| printf("########################################################\n"); |
| printf("# To use trained values update the ATF sources:\n"); |
| printf("# plat/marvell/armada/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"); |
| |
| 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 comphy_mode) |
| { |
| uint32_t mask, data; |
| uintptr_t comphy_addr = 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_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(); |
| |
| #if MSS_SUPPORT |
| do { |
| uint8_t ap_nr, cp_nr; |
| |
| /* start ap fw */ |
| mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base); |
| mg_start_ap_fw(cp_nr, comphy_index); |
| |
| } while (0); |
| #endif |
| 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_2500BASEX_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, |
| uint64_t comphy_train_base) |
| { |
| 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_2500BASEX_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, |
| comphy_train_base); |
| 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, |
| comphy_mode); |
| 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; |
| } |