Commit edb47025 authored by Stefan Roese's avatar Stefan Roese Committed by Luka Perkov

arm: mvebu: Add Armada 38x SERDES / PHY init code from Marvell bin_hdr

This code is ported from the Marvell bin_hdr code into mainline
SPL U-Boot. It needs to be executed very early so that the devices
connected to the serdes PHY are configured correctly.
Signed-off-by: default avatarStefan Roese <sr@denx.de>
parent 29b103c7
......@@ -20,6 +20,7 @@ obj-y += timer.o
obj-$(CONFIG_SPL_BUILD) += spl.o
obj-$(CONFIG_SPL_BUILD) += lowlevel_spl.o
obj-$(CONFIG_SYS_MVEBU_DDR_A38X) += serdes/a38x/
obj-$(CONFIG_SYS_MVEBU_DDR_AXP) += serdes/axp/
endif
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_SPL_BUILD) = ctrl_pex.o
obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec.o
obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec-38x.o
obj-$(CONFIG_SPL_BUILD) += high_speed_topology_spec-38x.o
obj-$(CONFIG_SPL_BUILD) += seq_exec.o
obj-$(CONFIG_SPL_BUILD) += sys_env_lib.o
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include "ctrl_pex.h"
#include "sys_env_lib.h"
int hws_pex_config(struct serdes_map *serdes_map)
{
u32 pex_idx, tmp, next_busno, first_busno, temp_pex_reg,
temp_reg, addr, dev_id, ctrl_mode;
enum serdes_type serdes_type;
u32 idx, max_lane_num;
DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n");
max_lane_num = hws_serdes_get_max_lane();
for (idx = 0; idx < max_lane_num; idx++) {
serdes_type = serdes_map[idx].serdes_type;
/* configuration for PEX only */
if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
(serdes_type != PEX2) && (serdes_type != PEX3))
continue;
if ((serdes_type != PEX0) &&
((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
(serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
/* for PEX by4 - relevant for the first port only */
continue;
}
pex_idx = serdes_type - PEX0;
tmp = reg_read(PEX_CAPABILITIES_REG(pex_idx));
tmp &= ~(0xf << 20);
tmp |= (0x4 << 20);
reg_write(PEX_CAPABILITIES_REG(pex_idx), tmp);
}
tmp = reg_read(SOC_CTRL_REG);
tmp &= ~0x03;
for (idx = 0; idx < max_lane_num; idx++) {
serdes_type = serdes_map[idx].serdes_type;
if ((serdes_type != PEX0) &&
((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
(serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
/* for PEX by4 - relevant for the first port only */
continue;
}
switch (serdes_type) {
case PEX0:
tmp |= 0x1 << PCIE0_ENABLE_OFFS;
break;
case PEX1:
tmp |= 0x1 << PCIE1_ENABLE_OFFS;
break;
case PEX2:
tmp |= 0x1 << PCIE2_ENABLE_OFFS;
break;
case PEX3:
tmp |= 0x1 << PCIE3_ENABLE_OFFS;
break;
default:
break;
}
}
reg_write(SOC_CTRL_REG, tmp);
/* Support gen1/gen2 */
DEBUG_INIT_FULL_S("Support gen1/gen2\n");
next_busno = 0;
mdelay(150);
for (idx = 0; idx < max_lane_num; idx++) {
serdes_type = serdes_map[idx].serdes_type;
DEBUG_INIT_FULL_S(" serdes_type=0x");
DEBUG_INIT_FULL_D(serdes_type, 8);
DEBUG_INIT_FULL_S("\n");
DEBUG_INIT_FULL_S(" idx=0x");
DEBUG_INIT_FULL_D(idx, 8);
DEBUG_INIT_FULL_S("\n");
/* Configuration for PEX only */
if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
(serdes_type != PEX2) && (serdes_type != PEX3))
continue;
if ((serdes_type != PEX0) &&
((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
(serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
/* for PEX by4 - relevant for the first port only */
continue;
}
pex_idx = serdes_type - PEX0;
tmp = reg_read(PEX_DBG_STATUS_REG(pex_idx));
first_busno = next_busno;
if ((tmp & 0x7f) != 0x7e) {
DEBUG_INIT_S("PCIe, Idx ");
DEBUG_INIT_D(pex_idx, 1);
DEBUG_INIT_S(": detected no link\n");
continue;
}
next_busno++;
temp_pex_reg = reg_read((PEX_CFG_DIRECT_ACCESS
(pex_idx, PEX_LINK_CAPABILITY_REG)));
temp_pex_reg &= 0xf;
if (temp_pex_reg != 0x2)
continue;
temp_reg = (reg_read(PEX_CFG_DIRECT_ACCESS(
pex_idx,
PEX_LINK_CTRL_STAT_REG)) &
0xf0000) >> 16;
/* Check if the link established is GEN1 */
DEBUG_INIT_FULL_S
("Checking if the link established is gen1\n");
if (temp_reg != 0x1)
continue;
pex_local_bus_num_set(pex_idx, first_busno);
pex_local_dev_num_set(pex_idx, 1);
DEBUG_INIT_FULL_S("PCIe, Idx ");
DEBUG_INIT_FULL_D(pex_idx, 1);
DEBUG_INIT_S(":** Link is Gen1, check the EP capability\n");
/* link is Gen1, check the EP capability */
addr = pex_config_read(pex_idx, first_busno, 0, 0, 0x34) & 0xff;
DEBUG_INIT_FULL_C("pex_config_read: return addr=0x%x", addr, 4);
if (addr == 0xff) {
DEBUG_INIT_FULL_C
("pex_config_read: return 0xff -->PCIe (%d): Detected No Link.",
pex_idx, 1);
continue;
}
while ((pex_config_read(pex_idx, first_busno, 0, 0, addr)
& 0xff) != 0x10) {
addr = (pex_config_read(pex_idx, first_busno, 0,
0, addr) & 0xff00) >> 8;
}
/* Check for Gen2 and above */
if ((pex_config_read(pex_idx, first_busno, 0, 0,
addr + 0xc) & 0xf) < 0x2) {
DEBUG_INIT_S("PCIe, Idx ");
DEBUG_INIT_D(pex_idx, 1);
DEBUG_INIT_S(": remains Gen1\n");
continue;
}
tmp = reg_read(PEX_LINK_CTRL_STATUS2_REG(pex_idx));
DEBUG_RD_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
tmp &= ~(BIT(0) | BIT(1));
tmp |= BIT(1);
tmp |= BIT(6); /* Select Deemphasize (-3.5d_b) */
reg_write(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
DEBUG_WR_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp);
tmp = reg_read(PEX_CTRL_REG(pex_idx));
DEBUG_RD_REG(PEX_CTRL_REG(pex_idx), tmp);
tmp |= BIT(10);
reg_write(PEX_CTRL_REG(pex_idx), tmp);
DEBUG_WR_REG(PEX_CTRL_REG(pex_idx), tmp);
/*
* We need to wait 10ms before reading the PEX_DBG_STATUS_REG
* in order not to read the status of the former state
*/
mdelay(10);
DEBUG_INIT_S("PCIe, Idx ");
DEBUG_INIT_D(pex_idx, 1);
DEBUG_INIT_S
(": Link upgraded to Gen2 based on client cpabilities\n");
}
/* Update pex DEVICE ID */
ctrl_mode = sys_env_model_get();
for (idx = 0; idx < max_lane_num; idx++) {
serdes_type = serdes_map[idx].serdes_type;
/* configuration for PEX only */
if ((serdes_type != PEX0) && (serdes_type != PEX1) &&
(serdes_type != PEX2) && (serdes_type != PEX3))
continue;
if ((serdes_type != PEX0) &&
((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
(serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
/* for PEX by4 - relevant for the first port only */
continue;
}
pex_idx = serdes_type - PEX0;
dev_id = reg_read(PEX_CFG_DIRECT_ACCESS
(pex_idx, PEX_DEVICE_AND_VENDOR_ID));
dev_id &= 0xffff;
dev_id |= ((ctrl_mode << 16) & 0xffff0000);
reg_write(PEX_CFG_DIRECT_ACCESS
(pex_idx, PEX_DEVICE_AND_VENDOR_ID), dev_id);
}
DEBUG_INIT_FULL_C("Update PEX Device ID ", ctrl_mode, 4);
return MV_OK;
}
int pex_local_bus_num_set(u32 pex_if, u32 bus_num)
{
u32 pex_status;
DEBUG_INIT_FULL_S("\n### pex_local_bus_num_set ###\n");
if (bus_num >= MAX_PEX_BUSSES) {
DEBUG_INIT_C("pex_local_bus_num_set: Illegal bus number %d\n",
bus_num, 4);
return MV_BAD_PARAM;
}
pex_status = reg_read(PEX_STATUS_REG(pex_if));
pex_status &= ~PXSR_PEX_BUS_NUM_MASK;
pex_status |=
(bus_num << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK;
reg_write(PEX_STATUS_REG(pex_if), pex_status);
return MV_OK;
}
int pex_local_dev_num_set(u32 pex_if, u32 dev_num)
{
u32 pex_status;
DEBUG_INIT_FULL_S("\n### pex_local_dev_num_set ###\n");
pex_status = reg_read(PEX_STATUS_REG(pex_if));
pex_status &= ~PXSR_PEX_DEV_NUM_MASK;
pex_status |=
(dev_num << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK;
reg_write(PEX_STATUS_REG(pex_if), pex_status);
return MV_OK;
}
/*
* pex_config_read - Read from configuration space
*
* DESCRIPTION:
* This function performs a 32 bit read from PEX configuration space.
* It supports both type 0 and type 1 of Configuration Transactions
* (local and over bridge). In order to read from local bus segment, use
* bus number retrieved from pex_local_bus_num_get(). Other bus numbers
* will result configuration transaction of type 1 (over bridge).
*
* INPUT:
* pex_if - PEX interface number.
* bus - PEX segment bus number.
* dev - PEX device number.
* func - Function number.
* reg_offs - Register offset.
*
* OUTPUT:
* None.
*
* RETURN:
* 32bit register data, 0xffffffff on error
*/
u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off)
{
u32 pex_data = 0;
u32 local_dev, local_bus;
u32 pex_status;
pex_status = reg_read(PEX_STATUS_REG(pex_if));
local_dev =
((pex_status & PXSR_PEX_DEV_NUM_MASK) >> PXSR_PEX_DEV_NUM_OFFS);
local_bus =
((pex_status & PXSR_PEX_BUS_NUM_MASK) >> PXSR_PEX_BUS_NUM_OFFS);
/*
* In PCI Express we have only one device number
* and this number is the first number we encounter
* else that the local_dev
* spec pex define return on config read/write on any device
*/
if (bus == local_bus) {
if (local_dev == 0) {
/*
* if local dev is 0 then the first number we encounter
* after 0 is 1
*/
if ((dev != 1) && (dev != local_dev))
return MV_ERROR;
} else {
/*
* if local dev is not 0 then the first number we
* encounter is 0
*/
if ((dev != 0) && (dev != local_dev))
return MV_ERROR;
}
}
/* Creating PEX address to be passed */
pex_data = (bus << PXCAR_BUS_NUM_OFFS);
pex_data |= (dev << PXCAR_DEVICE_NUM_OFFS);
pex_data |= (func << PXCAR_FUNC_NUM_OFFS);
/* Legacy register space */
pex_data |= (reg_off & PXCAR_REG_NUM_MASK);
/* Extended register space */
pex_data |= (((reg_off & PXCAR_REAL_EXT_REG_NUM_MASK) >>
PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS);
pex_data |= PXCAR_CONFIG_EN;
/* Write the address to the PEX configuration address register */
reg_write(PEX_CFG_ADDR_REG(pex_if), pex_data);
/*
* In order to let the PEX controller absorbed the address
* of the read transaction we perform a validity check that
* the address was written
*/
if (pex_data != reg_read(PEX_CFG_ADDR_REG(pex_if)))
return MV_ERROR;
/* Cleaning Master Abort */
reg_bit_set(PEX_CFG_DIRECT_ACCESS(pex_if, PEX_STATUS_AND_COMMAND),
PXSAC_MABORT);
/* Read the Data returned in the PEX Data register */
pex_data = reg_read(PEX_CFG_DATA_REG(pex_if));
DEBUG_INIT_FULL_C(" --> ", pex_data, 4);
return pex_data;
}
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#ifndef _CTRL_PEX_H
#define _CTRL_PEX_H
#include "high_speed_env_spec.h"
/* Sample at Reset */
#define MPP_SAMPLE_AT_RESET(id) (0xe4200 + (id * 4))
/* PCI Express Control and Status Registers */
#define MAX_PEX_BUSSES 256
#define MISC_REGS_OFFSET 0x18200
#define MV_MISC_REGS_BASE MISC_REGS_OFFSET
#define SOC_CTRL_REG (MV_MISC_REGS_BASE + 0x4)
#define PEX_CAPABILITIES_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x60)
#define PEX_LINK_CTRL_STATUS2_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x90)
#define PEX_CTRL_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a00)
#define PEX_STATUS_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a04)
#define PEX_DBG_STATUS_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a64)
#define PEX_LINK_CAPABILITY_REG 0x6c
#define PEX_LINK_CTRL_STAT_REG 0x70
#define PXSR_PEX_DEV_NUM_OFFS 16 /* Device Number Indication */
#define PXSR_PEX_DEV_NUM_MASK (0x1f << PXSR_PEX_DEV_NUM_OFFS)
#define PXSR_PEX_BUS_NUM_OFFS 8 /* Bus Number Indication */
#define PXSR_PEX_BUS_NUM_MASK (0xff << PXSR_PEX_BUS_NUM_OFFS)
/* PEX_CAPABILITIES_REG fields */
#define PCIE0_ENABLE_OFFS 0
#define PCIE0_ENABLE_MASK (0x1 << PCIE0_ENABLE_OFFS)
#define PCIE1_ENABLE_OFFS 1
#define PCIE1_ENABLE_MASK (0x1 << PCIE1_ENABLE_OFFS)
#define PCIE2_ENABLE_OFFS 2
#define PCIE2_ENABLE_MASK (0x1 << PCIE2_ENABLE_OFFS)
#define PCIE3_ENABLE_OFFS 3
#define PCIE4_ENABLE_MASK (0x1 << PCIE3_ENABLE_OFFS)
/* Controller revision info */
#define PEX_DEVICE_AND_VENDOR_ID 0x000
/* PCI Express Configuration Address Register */
#define PXCAR_REG_NUM_OFFS 2
#define PXCAR_REG_NUM_MAX 0x3f
#define PXCAR_REG_NUM_MASK (PXCAR_REG_NUM_MAX << \
PXCAR_REG_NUM_OFFS)
#define PXCAR_FUNC_NUM_OFFS 8
#define PXCAR_FUNC_NUM_MAX 0x7
#define PXCAR_FUNC_NUM_MASK (PXCAR_FUNC_NUM_MAX << \
PXCAR_FUNC_NUM_OFFS)
#define PXCAR_DEVICE_NUM_OFFS 11
#define PXCAR_DEVICE_NUM_MAX 0x1f
#define PXCAR_DEVICE_NUM_MASK (PXCAR_DEVICE_NUM_MAX << \
PXCAR_DEVICE_NUM_OFFS)
#define PXCAR_BUS_NUM_OFFS 16
#define PXCAR_BUS_NUM_MAX 0xff
#define PXCAR_BUS_NUM_MASK (PXCAR_BUS_NUM_MAX << \
PXCAR_BUS_NUM_OFFS)
#define PXCAR_EXT_REG_NUM_OFFS 24
#define PXCAR_EXT_REG_NUM_MAX 0xf
#define PEX_CFG_ADDR_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x18f8)
#define PEX_CFG_DATA_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x18fc)
#define PXCAR_REAL_EXT_REG_NUM_OFFS 8
#define PXCAR_REAL_EXT_REG_NUM_MASK (0xf << PXCAR_REAL_EXT_REG_NUM_OFFS)
#define PXCAR_CONFIG_EN BIT(31)
#define PEX_STATUS_AND_COMMAND 0x004
#define PXSAC_MABORT BIT(29) /* Recieved Master Abort */
int hws_pex_config(struct serdes_map *serdes_map);
int pex_local_bus_num_set(u32 pex_if, u32 bus_num);
int pex_local_dev_num_set(u32 pex_if, u32 dev_num);
u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off);
#endif
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <i2c.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include "high_speed_env_spec.h"
#include "sys_env_lib.h"
#define SERDES_VERION "2.0"
u8 selectors_serdes_rev1_map[LAST_SERDES_TYPE][MAX_SERDES_LANES] = {
/* 0 1 2 3 4 5 */
{0x1, 0x1, NA, NA, NA, NA}, /* PEX0 */
{NA, 0x2, 0x1, NA, 0x1, NA}, /* PEX1 */
{NA, NA, 0x2, NA, NA, 0x1}, /* PEX2 */
{NA, NA, NA, 0x1, NA, NA}, /* PEX3 */
{0x2, 0x3, NA, NA, NA, NA}, /* SATA0 */
{NA, NA, 0x3, NA, 0x2, NA}, /* SATA1 */
{NA, NA, NA, NA, 0x6, 0x2}, /* SATA2 */
{NA, NA, NA, 0x3, NA, NA}, /* SATA3 */
{0x3, 0x4, NA, NA, NA, NA}, /* SGMII0 */
{NA, 0x5, 0x4, NA, 0x3, NA}, /* SGMII1 */
{NA, NA, NA, 0x4, NA, 0x3}, /* SGMII2 */
{NA, 0x7, NA, NA, NA, NA}, /* QSGMII */
{NA, 0x6, NA, NA, 0x4, NA}, /* USB3_HOST0 */
{NA, NA, NA, 0x5, NA, 0x4}, /* USB3_HOST1 */
{NA, NA, NA, 0x6, 0x5, 0x5}, /* USB3_DEVICE */
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0} /* DEFAULT_SERDES */
};
int hws_serdes_seq_init(void)
{
DEBUG_INIT_FULL_S("\n### serdes_seq_init ###\n");
if (hws_serdes_seq_db_init() != MV_OK) {
printf("hws_serdes_seq_init: Error: Serdes initialization fail\n");
return MV_FAIL;
}
return MV_OK;
}
int serdes_power_up_ctrl_ext(u32 serdes_num, int serdes_power_up,
enum serdes_type serdes_type,
enum serdes_speed baud_rate,
enum serdes_mode serdes_mode,
enum ref_clock ref_clock)
{
return MV_NOT_SUPPORTED;
}
u32 hws_serdes_silicon_ref_clock_get(void)
{
DEBUG_INIT_FULL_S("\n### hws_serdes_silicon_ref_clock_get ###\n");
return REF_CLOCK_25MHZ;
}
u32 hws_serdes_get_max_lane(void)
{
switch (sys_env_device_id_get()) {
case MV_6811: /* A381/A3282: 6811/6821: single/dual cpu */
return 4;
case MV_6810:
return 5;
case MV_6820:
case MV_6828:
return 6;
default: /* not the right module */
printf("%s: Device ID Error, using 4 SerDes lanes\n",
__func__);
return 4;
}
return 6;
}
int hws_is_serdes_active(u8 lane_num)
{
int ret = 1;
/* Maximum lane count for A388 (6828) is 6 */
if (lane_num > 6)
ret = 0;
/* 4th Lane (#4 on Device 6810 is not Active */
if (sys_env_device_id_get() == MV_6810 && lane_num == 4) {
printf("%s: Error: Lane#4 on Device 6810 is not Active.\n",
__func__);
return 0;
}
/*
* 6th Lane (#5) on Device 6810 is Active, even though 6810
* has only 5 lanes
*/
if (sys_env_device_id_get() == MV_6810 && lane_num == 5)
return 1;
if (lane_num >= hws_serdes_get_max_lane())
ret = 0;
return ret;
}
int hws_get_ext_base_addr(u32 serdes_num, u32 base_addr, u32 unit_base_offset,
u32 *unit_base_reg, u32 *unit_offset)
{
*unit_base_reg = base_addr;
*unit_offset = unit_base_offset;
return MV_OK;
}
/*
* hws_serdes_get_phy_selector_val
*
* DESCRIPTION: Get the mapping of Serdes Selector values according to the
* Serdes revision number
* INPUT: serdes_num - Serdes number
* serdes_type - Serdes type
* OUTPUT: None
* RETURN:
* Mapping of Serdes Selector values
*/
u32 hws_serdes_get_phy_selector_val(int serdes_num,
enum serdes_type serdes_type)
{
if (serdes_type >= LAST_SERDES_TYPE)
return 0xff;
if (hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2) {
return selectors_serdes_rev1_map
[serdes_type][serdes_num];
} else
return selectors_serdes_rev2_map
[serdes_type][serdes_num];
}
u32 hws_get_physical_serdes_num(u32 serdes_num)
{
if ((serdes_num == 4) && (sys_env_device_id_get() == MV_6810)) {
/*
* For 6810, there are 5 Serdes and Serdes Num 4 doesn't
* exist. Instead Serdes Num 5 is connected.
*/
return 5;
} else {
return serdes_num;
}
}
This diff is collapsed.
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*
* SPDX-License-Identifier: GPL-2.0
*/
#ifndef _HIGH_SPEED_ENV_SPEC_H
#define _HIGH_SPEED_ENV_SPEC_H
#include "seq_exec.h"
/*
* For setting or clearing a certain bit (bit is a number between 0 and 31)
* in the data
*/
#define SET_BIT(data, bit) ((data) | (0x1 << (bit)))
#define CLEAR_BIT(data, bit) ((data) & (~(0x1 << (bit))))
#define MAX_SERDES_LANES 7 /* as in a39x */
/* Serdes revision */
/* Serdes revision 1.2 (for A38x-Z1) */
#define MV_SERDES_REV_1_2 0x0
/* Serdes revision 2.1 (for A39x-Z1, A38x-A0) */
#define MV_SERDES_REV_2_1 0x1
#define MV_SERDES_REV_NA 0xff
#define SERDES_REGS_LANE_BASE_OFFSET(lane) (0x800 * (lane))
#define PEX_X4_ENABLE_OFFS \
(hws_ctrl_serdes_rev_get() == MV_SERDES_REV_1_2 ? 18 : 31)
/* Serdes lane types */
enum serdes_type {
PEX0,
PEX1,
PEX2,
PEX3,
SATA0,
SATA1,
SATA2,
SATA3,
SGMII0,
SGMII1,
SGMII2,
QSGMII,
USB3_HOST0,
USB3_HOST1,
USB3_DEVICE,
SGMII3,
XAUI,
RXAUI,
DEFAULT_SERDES,
LAST_SERDES_TYPE
};
/* Serdes baud rates */
enum serdes_speed {
SERDES_SPEED_1_25_GBPS,
SERDES_SPEED_1_5_GBPS,
SERDES_SPEED_2_5_GBPS,
SERDES_SPEED_3_GBPS,
SERDES_SPEED_3_125_GBPS,
SERDES_SPEED_5_GBPS,
SERDES_SPEED_6_GBPS,
SERDES_SPEED_6_25_GBPS,
LAST_SERDES_SPEED
};
/* Serdes modes */
enum serdes_mode {
PEX_ROOT_COMPLEX_X1,
PEX_ROOT_COMPLEX_X4,
PEX_END_POINT_X1,
PEX_END_POINT_X4,
SERDES_DEFAULT_MODE, /* not pex */
SERDES_LAST_MODE
};
struct serdes_map {
enum serdes_type serdes_type;
enum serdes_speed serdes_speed;
enum serdes_mode serdes_mode;
int swap_rx;
int swap_tx;
};
/* Serdes ref clock options */
enum ref_clock {
REF_CLOCK_25MHZ,
REF_CLOCK_100MHZ,
REF_CLOCK_40MHZ,
REF_CLOCK_UNSUPPORTED
};
/* Serdes sequences */
enum serdes_seq {
SATA_PORT_0_ONLY_POWER_UP_SEQ,
SATA_PORT_1_ONLY_POWER_UP_SEQ,
SATA_POWER_UP_SEQ,
SATA_1_5_SPEED_CONFIG_SEQ,
SATA_3_SPEED_CONFIG_SEQ,
SATA_6_SPEED_CONFIG_SEQ,
SATA_ELECTRICAL_CONFIG_SEQ,
SATA_TX_CONFIG_SEQ1,
SATA_PORT_0_ONLY_TX_CONFIG_SEQ,
SATA_PORT_1_ONLY_TX_CONFIG_SEQ,
SATA_TX_CONFIG_SEQ2,
SGMII_POWER_UP_SEQ,