mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-26 13:03:40 +00:00
1a048cd656
Till now we have had cases where we had one phy device per dpmac. Now, with the upcoming products (LX2160AQDS), we have cases, where there are sometimes two phy devices for one dpmac. One phy for TX lanes and one phy for RX lanes. to handle such cases, add the support for multiple phys in ethernet driver. The ethernet link is up if all the phy devices connected to one dpmac report link up. also the link capabilities are limited by the weakest phy device. i.e. say if there are two phys for one dpmac. one operates at 10G without autoneg and other operate at 1G with autoneg. Then the ethernet interface will operate at 1G without autoneg. Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com> Acked-by: Joe Hershberger <joe.hershberger@ni.com>
923 lines
22 KiB
C
923 lines
22 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright 2015 Freescale Semiconductor, Inc.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <netdev.h>
|
|
#include <asm/io.h>
|
|
#include <asm/arch/fsl_serdes.h>
|
|
#include <hwconfig.h>
|
|
#include <fsl_mdio.h>
|
|
#include <malloc.h>
|
|
#include <fm_eth.h>
|
|
#include <i2c.h>
|
|
#include <miiphy.h>
|
|
#include <fsl-mc/fsl_mc.h>
|
|
#include <fsl-mc/ldpaa_wriop.h>
|
|
|
|
#include "../common/qixis.h"
|
|
|
|
#include "ls2080aqds_qixis.h"
|
|
|
|
#define MC_BOOT_ENV_VAR "mcinitcmd"
|
|
|
|
#if defined(CONFIG_FSL_MC_ENET) && !defined(CONFIG_SPL_BUILD)
|
|
/* - In LS2080A there are only 16 SERDES lanes, spread across 2 SERDES banks.
|
|
* Bank 1 -> Lanes A, B, C, D, E, F, G, H
|
|
* Bank 2 -> Lanes A,B, C, D, E, F, G, H
|
|
*/
|
|
|
|
/* Mapping of 16 SERDES lanes to LS2080A QDS board slots. A value of '0' here
|
|
* means that the mapping must be determined dynamically, or that the lane
|
|
* maps to something other than a board slot.
|
|
*/
|
|
|
|
static u8 lane_to_slot_fsm1[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0
|
|
};
|
|
|
|
static u8 lane_to_slot_fsm2[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0
|
|
};
|
|
|
|
/* On the Vitesse VSC8234XHG SGMII riser card there are 4 SGMII PHYs
|
|
* housed.
|
|
*/
|
|
|
|
static int xqsgii_riser_phy_addr[] = {
|
|
XQSGMII_CARD_PHY1_PORT0_ADDR,
|
|
XQSGMII_CARD_PHY2_PORT0_ADDR,
|
|
XQSGMII_CARD_PHY3_PORT0_ADDR,
|
|
XQSGMII_CARD_PHY4_PORT0_ADDR,
|
|
XQSGMII_CARD_PHY3_PORT2_ADDR,
|
|
XQSGMII_CARD_PHY1_PORT2_ADDR,
|
|
XQSGMII_CARD_PHY4_PORT2_ADDR,
|
|
XQSGMII_CARD_PHY2_PORT2_ADDR,
|
|
};
|
|
|
|
static int sgmii_riser_phy_addr[] = {
|
|
SGMII_CARD_PORT1_PHY_ADDR,
|
|
SGMII_CARD_PORT2_PHY_ADDR,
|
|
SGMII_CARD_PORT3_PHY_ADDR,
|
|
SGMII_CARD_PORT4_PHY_ADDR,
|
|
};
|
|
|
|
/* Slot2 does not have EMI connections */
|
|
#define EMI_NONE 0xFF
|
|
#define EMI1_SLOT1 0
|
|
#define EMI1_SLOT2 1
|
|
#define EMI1_SLOT3 2
|
|
#define EMI1_SLOT4 3
|
|
#define EMI1_SLOT5 4
|
|
#define EMI1_SLOT6 5
|
|
#define EMI2 6
|
|
#define SFP_TX 0
|
|
|
|
static const char * const mdio_names[] = {
|
|
"LS2080A_QDS_MDIO0",
|
|
"LS2080A_QDS_MDIO1",
|
|
"LS2080A_QDS_MDIO2",
|
|
"LS2080A_QDS_MDIO3",
|
|
"LS2080A_QDS_MDIO4",
|
|
"LS2080A_QDS_MDIO5",
|
|
DEFAULT_WRIOP_MDIO2_NAME,
|
|
};
|
|
|
|
struct ls2080a_qds_mdio {
|
|
u8 muxval;
|
|
struct mii_dev *realbus;
|
|
};
|
|
|
|
static void sgmii_configure_repeater(int serdes_port)
|
|
{
|
|
struct mii_dev *bus;
|
|
uint8_t a = 0xf;
|
|
int i, j, ret;
|
|
int dpmac_id = 0, dpmac, mii_bus = 0;
|
|
unsigned short value;
|
|
char dev[2][20] = {"LS2080A_QDS_MDIO0", "LS2080A_QDS_MDIO3"};
|
|
uint8_t i2c_addr[] = {0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5f, 0x60};
|
|
|
|
uint8_t ch_a_eq[] = {0x1, 0x2, 0x3, 0x7};
|
|
uint8_t ch_a_ctl2[] = {0x81, 0x82, 0x83, 0x84};
|
|
uint8_t ch_b_eq[] = {0x1, 0x2, 0x3, 0x7};
|
|
uint8_t ch_b_ctl2[] = {0x81, 0x82, 0x83, 0x84};
|
|
|
|
int *riser_phy_addr = &xqsgii_riser_phy_addr[0];
|
|
|
|
/* Set I2c to Slot 1 */
|
|
i2c_write(0x77, 0, 0, &a, 1);
|
|
|
|
for (dpmac = 0; dpmac < 8; dpmac++) {
|
|
/* Check the PHY status */
|
|
switch (serdes_port) {
|
|
case 1:
|
|
mii_bus = 0;
|
|
dpmac_id = dpmac + 1;
|
|
break;
|
|
case 2:
|
|
mii_bus = 1;
|
|
dpmac_id = dpmac + 9;
|
|
a = 0xb;
|
|
i2c_write(0x76, 0, 0, &a, 1);
|
|
break;
|
|
}
|
|
|
|
ret = miiphy_set_current_dev(dev[mii_bus]);
|
|
if (ret > 0)
|
|
goto error;
|
|
|
|
bus = mdio_get_current_dev();
|
|
debug("Reading from bus %s\n", bus->name);
|
|
|
|
ret = miiphy_write(dev[mii_bus], riser_phy_addr[dpmac], 0x1f,
|
|
3);
|
|
if (ret > 0)
|
|
goto error;
|
|
|
|
mdelay(10);
|
|
ret = miiphy_read(dev[mii_bus], riser_phy_addr[dpmac], 0x11,
|
|
&value);
|
|
if (ret > 0)
|
|
goto error;
|
|
|
|
mdelay(10);
|
|
|
|
if ((value & 0xfff) == 0x401) {
|
|
printf("DPMAC %d:PHY is ..... Configured\n", dpmac_id);
|
|
miiphy_write(dev[mii_bus], riser_phy_addr[dpmac],
|
|
0x1f, 0);
|
|
continue;
|
|
}
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
for (j = 0; j < 4; j++) {
|
|
a = 0x18;
|
|
i2c_write(i2c_addr[dpmac], 6, 1, &a, 1);
|
|
a = 0x38;
|
|
i2c_write(i2c_addr[dpmac], 4, 1, &a, 1);
|
|
a = 0x4;
|
|
i2c_write(i2c_addr[dpmac], 8, 1, &a, 1);
|
|
|
|
i2c_write(i2c_addr[dpmac], 0xf, 1,
|
|
&ch_a_eq[i], 1);
|
|
i2c_write(i2c_addr[dpmac], 0x11, 1,
|
|
&ch_a_ctl2[j], 1);
|
|
|
|
i2c_write(i2c_addr[dpmac], 0x16, 1,
|
|
&ch_b_eq[i], 1);
|
|
i2c_write(i2c_addr[dpmac], 0x18, 1,
|
|
&ch_b_ctl2[j], 1);
|
|
|
|
a = 0x14;
|
|
i2c_write(i2c_addr[dpmac], 0x23, 1, &a, 1);
|
|
a = 0xb5;
|
|
i2c_write(i2c_addr[dpmac], 0x2d, 1, &a, 1);
|
|
a = 0x20;
|
|
i2c_write(i2c_addr[dpmac], 4, 1, &a, 1);
|
|
mdelay(100);
|
|
ret = miiphy_read(dev[mii_bus],
|
|
riser_phy_addr[dpmac],
|
|
0x11, &value);
|
|
if (ret > 0)
|
|
goto error;
|
|
|
|
mdelay(100);
|
|
ret = miiphy_read(dev[mii_bus],
|
|
riser_phy_addr[dpmac],
|
|
0x11, &value);
|
|
if (ret > 0)
|
|
goto error;
|
|
|
|
if ((value & 0xfff) == 0x401) {
|
|
printf("DPMAC %d :PHY is configured ",
|
|
dpmac_id);
|
|
printf("after setting repeater 0x%x\n",
|
|
value);
|
|
i = 5;
|
|
j = 5;
|
|
} else {
|
|
printf("DPMAC %d :PHY is failed to ",
|
|
dpmac_id);
|
|
printf("configure the repeater 0x%x\n",
|
|
value);
|
|
}
|
|
}
|
|
}
|
|
miiphy_write(dev[mii_bus], riser_phy_addr[dpmac], 0x1f, 0);
|
|
}
|
|
error:
|
|
if (ret)
|
|
printf("DPMAC %d ..... FAILED to configure PHY\n", dpmac_id);
|
|
return;
|
|
}
|
|
|
|
static void qsgmii_configure_repeater(int dpmac)
|
|
{
|
|
uint8_t a = 0xf;
|
|
int i, j;
|
|
int i2c_phy_addr = 0;
|
|
int phy_addr = 0;
|
|
int i2c_addr[] = {0x58, 0x59, 0x5a, 0x5b};
|
|
|
|
uint8_t ch_a_eq[] = {0x1, 0x2, 0x3, 0x7};
|
|
uint8_t ch_a_ctl2[] = {0x81, 0x82, 0x83, 0x84};
|
|
uint8_t ch_b_eq[] = {0x1, 0x2, 0x3, 0x7};
|
|
uint8_t ch_b_ctl2[] = {0x81, 0x82, 0x83, 0x84};
|
|
|
|
const char *dev = "LS2080A_QDS_MDIO0";
|
|
int ret = 0;
|
|
unsigned short value;
|
|
|
|
/* Set I2c to Slot 1 */
|
|
i2c_write(0x77, 0, 0, &a, 1);
|
|
|
|
switch (dpmac) {
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
i2c_phy_addr = i2c_addr[0];
|
|
phy_addr = 0;
|
|
break;
|
|
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
i2c_phy_addr = i2c_addr[1];
|
|
phy_addr = 4;
|
|
break;
|
|
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
i2c_phy_addr = i2c_addr[2];
|
|
phy_addr = 8;
|
|
break;
|
|
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
case 16:
|
|
i2c_phy_addr = i2c_addr[3];
|
|
phy_addr = 0xc;
|
|
break;
|
|
}
|
|
|
|
/* Check the PHY status */
|
|
ret = miiphy_set_current_dev(dev);
|
|
ret = miiphy_write(dev, phy_addr, 0x1f, 3);
|
|
mdelay(10);
|
|
ret = miiphy_read(dev, phy_addr, 0x11, &value);
|
|
mdelay(10);
|
|
ret = miiphy_read(dev, phy_addr, 0x11, &value);
|
|
mdelay(10);
|
|
if ((value & 0xf) == 0xf) {
|
|
printf("DPMAC %d :PHY is ..... Configured\n", dpmac);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
for (j = 0; j < 4; j++) {
|
|
a = 0x18;
|
|
i2c_write(i2c_phy_addr, 6, 1, &a, 1);
|
|
a = 0x38;
|
|
i2c_write(i2c_phy_addr, 4, 1, &a, 1);
|
|
a = 0x4;
|
|
i2c_write(i2c_phy_addr, 8, 1, &a, 1);
|
|
|
|
i2c_write(i2c_phy_addr, 0xf, 1, &ch_a_eq[i], 1);
|
|
i2c_write(i2c_phy_addr, 0x11, 1, &ch_a_ctl2[j], 1);
|
|
|
|
i2c_write(i2c_phy_addr, 0x16, 1, &ch_b_eq[i], 1);
|
|
i2c_write(i2c_phy_addr, 0x18, 1, &ch_b_ctl2[j], 1);
|
|
|
|
a = 0x14;
|
|
i2c_write(i2c_phy_addr, 0x23, 1, &a, 1);
|
|
a = 0xb5;
|
|
i2c_write(i2c_phy_addr, 0x2d, 1, &a, 1);
|
|
a = 0x20;
|
|
i2c_write(i2c_phy_addr, 4, 1, &a, 1);
|
|
mdelay(100);
|
|
ret = miiphy_read(dev, phy_addr, 0x11, &value);
|
|
if (ret > 0)
|
|
goto error;
|
|
mdelay(1);
|
|
ret = miiphy_read(dev, phy_addr, 0x11, &value);
|
|
if (ret > 0)
|
|
goto error;
|
|
mdelay(10);
|
|
if ((value & 0xf) == 0xf) {
|
|
printf("DPMAC %d :PHY is ..... Configured\n",
|
|
dpmac);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
error:
|
|
printf("DPMAC %d :PHY ..... FAILED to configure PHY\n", dpmac);
|
|
return;
|
|
}
|
|
|
|
static const char *ls2080a_qds_mdio_name_for_muxval(u8 muxval)
|
|
{
|
|
return mdio_names[muxval];
|
|
}
|
|
|
|
struct mii_dev *mii_dev_for_muxval(u8 muxval)
|
|
{
|
|
struct mii_dev *bus;
|
|
const char *name = ls2080a_qds_mdio_name_for_muxval(muxval);
|
|
|
|
if (!name) {
|
|
printf("No bus for muxval %x\n", muxval);
|
|
return NULL;
|
|
}
|
|
|
|
bus = miiphy_get_dev_by_name(name);
|
|
|
|
if (!bus) {
|
|
printf("No bus by name %s\n", name);
|
|
return NULL;
|
|
}
|
|
|
|
return bus;
|
|
}
|
|
|
|
static void ls2080a_qds_enable_SFP_TX(u8 muxval)
|
|
{
|
|
u8 brdcfg9;
|
|
|
|
brdcfg9 = QIXIS_READ(brdcfg[9]);
|
|
brdcfg9 &= ~BRDCFG9_SFPTX_MASK;
|
|
brdcfg9 |= (muxval << BRDCFG9_SFPTX_SHIFT);
|
|
QIXIS_WRITE(brdcfg[9], brdcfg9);
|
|
}
|
|
|
|
static void ls2080a_qds_mux_mdio(u8 muxval)
|
|
{
|
|
u8 brdcfg4;
|
|
|
|
if (muxval <= 5) {
|
|
brdcfg4 = QIXIS_READ(brdcfg[4]);
|
|
brdcfg4 &= ~BRDCFG4_EMISEL_MASK;
|
|
brdcfg4 |= (muxval << BRDCFG4_EMISEL_SHIFT);
|
|
QIXIS_WRITE(brdcfg[4], brdcfg4);
|
|
}
|
|
}
|
|
|
|
static int ls2080a_qds_mdio_read(struct mii_dev *bus, int addr,
|
|
int devad, int regnum)
|
|
{
|
|
struct ls2080a_qds_mdio *priv = bus->priv;
|
|
|
|
ls2080a_qds_mux_mdio(priv->muxval);
|
|
|
|
return priv->realbus->read(priv->realbus, addr, devad, regnum);
|
|
}
|
|
|
|
static int ls2080a_qds_mdio_write(struct mii_dev *bus, int addr, int devad,
|
|
int regnum, u16 value)
|
|
{
|
|
struct ls2080a_qds_mdio *priv = bus->priv;
|
|
|
|
ls2080a_qds_mux_mdio(priv->muxval);
|
|
|
|
return priv->realbus->write(priv->realbus, addr, devad, regnum, value);
|
|
}
|
|
|
|
static int ls2080a_qds_mdio_reset(struct mii_dev *bus)
|
|
{
|
|
struct ls2080a_qds_mdio *priv = bus->priv;
|
|
|
|
return priv->realbus->reset(priv->realbus);
|
|
}
|
|
|
|
static int ls2080a_qds_mdio_init(char *realbusname, u8 muxval)
|
|
{
|
|
struct ls2080a_qds_mdio *pmdio;
|
|
struct mii_dev *bus = mdio_alloc();
|
|
|
|
if (!bus) {
|
|
printf("Failed to allocate ls2080a_qds MDIO bus\n");
|
|
return -1;
|
|
}
|
|
|
|
pmdio = malloc(sizeof(*pmdio));
|
|
if (!pmdio) {
|
|
printf("Failed to allocate ls2080a_qds private data\n");
|
|
free(bus);
|
|
return -1;
|
|
}
|
|
|
|
bus->read = ls2080a_qds_mdio_read;
|
|
bus->write = ls2080a_qds_mdio_write;
|
|
bus->reset = ls2080a_qds_mdio_reset;
|
|
strcpy(bus->name, ls2080a_qds_mdio_name_for_muxval(muxval));
|
|
|
|
pmdio->realbus = miiphy_get_dev_by_name(realbusname);
|
|
|
|
if (!pmdio->realbus) {
|
|
printf("No bus with name %s\n", realbusname);
|
|
free(bus);
|
|
free(pmdio);
|
|
return -1;
|
|
}
|
|
|
|
pmdio->muxval = muxval;
|
|
bus->priv = pmdio;
|
|
|
|
return mdio_register(bus);
|
|
}
|
|
|
|
/*
|
|
* Initialize the dpmac_info array.
|
|
*
|
|
*/
|
|
static void initialize_dpmac_to_slot(void)
|
|
{
|
|
struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
|
|
int serdes1_prtcl = (in_le32(&gur->rcwsr[28]) &
|
|
FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK)
|
|
>> FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT;
|
|
int serdes2_prtcl = (in_le32(&gur->rcwsr[28]) &
|
|
FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK)
|
|
>> FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT;
|
|
|
|
char *env_hwconfig;
|
|
env_hwconfig = env_get("hwconfig");
|
|
|
|
switch (serdes1_prtcl) {
|
|
case 0x07:
|
|
case 0x09:
|
|
case 0x33:
|
|
printf("qds: WRIOP: Supported SerDes1 Protocol 0x%02x\n",
|
|
serdes1_prtcl);
|
|
lane_to_slot_fsm1[0] = EMI1_SLOT1;
|
|
lane_to_slot_fsm1[1] = EMI1_SLOT1;
|
|
lane_to_slot_fsm1[2] = EMI1_SLOT1;
|
|
lane_to_slot_fsm1[3] = EMI1_SLOT1;
|
|
if (hwconfig_f("xqsgmii", env_hwconfig)) {
|
|
lane_to_slot_fsm1[4] = EMI1_SLOT1;
|
|
lane_to_slot_fsm1[5] = EMI1_SLOT1;
|
|
lane_to_slot_fsm1[6] = EMI1_SLOT1;
|
|
lane_to_slot_fsm1[7] = EMI1_SLOT1;
|
|
} else {
|
|
lane_to_slot_fsm1[4] = EMI1_SLOT2;
|
|
lane_to_slot_fsm1[5] = EMI1_SLOT2;
|
|
lane_to_slot_fsm1[6] = EMI1_SLOT2;
|
|
lane_to_slot_fsm1[7] = EMI1_SLOT2;
|
|
}
|
|
break;
|
|
|
|
case 0x39:
|
|
printf("qds: WRIOP: Supported SerDes1 Protocol 0x%02x\n",
|
|
serdes1_prtcl);
|
|
if (hwconfig_f("xqsgmii", env_hwconfig)) {
|
|
lane_to_slot_fsm1[0] = EMI1_SLOT3;
|
|
lane_to_slot_fsm1[1] = EMI1_SLOT3;
|
|
lane_to_slot_fsm1[2] = EMI1_SLOT3;
|
|
lane_to_slot_fsm1[3] = EMI_NONE;
|
|
} else {
|
|
lane_to_slot_fsm1[0] = EMI_NONE;
|
|
lane_to_slot_fsm1[1] = EMI_NONE;
|
|
lane_to_slot_fsm1[2] = EMI_NONE;
|
|
lane_to_slot_fsm1[3] = EMI_NONE;
|
|
}
|
|
lane_to_slot_fsm1[4] = EMI1_SLOT3;
|
|
lane_to_slot_fsm1[5] = EMI1_SLOT3;
|
|
lane_to_slot_fsm1[6] = EMI1_SLOT3;
|
|
lane_to_slot_fsm1[7] = EMI_NONE;
|
|
break;
|
|
|
|
case 0x4D:
|
|
printf("qds: WRIOP: Supported SerDes1 Protocol 0x%02x\n",
|
|
serdes1_prtcl);
|
|
if (hwconfig_f("xqsgmii", env_hwconfig)) {
|
|
lane_to_slot_fsm1[0] = EMI1_SLOT3;
|
|
lane_to_slot_fsm1[1] = EMI1_SLOT3;
|
|
lane_to_slot_fsm1[2] = EMI_NONE;
|
|
lane_to_slot_fsm1[3] = EMI_NONE;
|
|
} else {
|
|
lane_to_slot_fsm1[0] = EMI_NONE;
|
|
lane_to_slot_fsm1[1] = EMI_NONE;
|
|
lane_to_slot_fsm1[2] = EMI_NONE;
|
|
lane_to_slot_fsm1[3] = EMI_NONE;
|
|
}
|
|
lane_to_slot_fsm1[4] = EMI1_SLOT3;
|
|
lane_to_slot_fsm1[5] = EMI1_SLOT3;
|
|
lane_to_slot_fsm1[6] = EMI_NONE;
|
|
lane_to_slot_fsm1[7] = EMI_NONE;
|
|
break;
|
|
|
|
case 0x2A:
|
|
case 0x4B:
|
|
case 0x4C:
|
|
printf("qds: WRIOP: Supported SerDes1 Protocol 0x%02x\n",
|
|
serdes1_prtcl);
|
|
break;
|
|
default:
|
|
printf("%s qds: WRIOP: Unsupported SerDes1 Protocol 0x%02x\n",
|
|
__func__, serdes1_prtcl);
|
|
break;
|
|
}
|
|
|
|
switch (serdes2_prtcl) {
|
|
case 0x07:
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x49:
|
|
printf("qds: WRIOP: Supported SerDes2 Protocol 0x%02x\n",
|
|
serdes2_prtcl);
|
|
lane_to_slot_fsm2[0] = EMI1_SLOT4;
|
|
lane_to_slot_fsm2[1] = EMI1_SLOT4;
|
|
lane_to_slot_fsm2[2] = EMI1_SLOT4;
|
|
lane_to_slot_fsm2[3] = EMI1_SLOT4;
|
|
|
|
if (hwconfig_f("xqsgmii", env_hwconfig)) {
|
|
lane_to_slot_fsm2[4] = EMI1_SLOT4;
|
|
lane_to_slot_fsm2[5] = EMI1_SLOT4;
|
|
lane_to_slot_fsm2[6] = EMI1_SLOT4;
|
|
lane_to_slot_fsm2[7] = EMI1_SLOT4;
|
|
} else {
|
|
/* No MDIO physical connection */
|
|
lane_to_slot_fsm2[4] = EMI1_SLOT6;
|
|
lane_to_slot_fsm2[5] = EMI1_SLOT6;
|
|
lane_to_slot_fsm2[6] = EMI1_SLOT6;
|
|
lane_to_slot_fsm2[7] = EMI1_SLOT6;
|
|
}
|
|
break;
|
|
|
|
case 0x47:
|
|
printf("qds: WRIOP: Supported SerDes2 Protocol 0x%02x\n",
|
|
serdes2_prtcl);
|
|
lane_to_slot_fsm2[0] = EMI_NONE;
|
|
lane_to_slot_fsm2[1] = EMI1_SLOT5;
|
|
lane_to_slot_fsm2[2] = EMI1_SLOT5;
|
|
lane_to_slot_fsm2[3] = EMI1_SLOT5;
|
|
|
|
if (hwconfig_f("xqsgmii", env_hwconfig)) {
|
|
lane_to_slot_fsm2[4] = EMI_NONE;
|
|
lane_to_slot_fsm2[5] = EMI1_SLOT5;
|
|
lane_to_slot_fsm2[6] = EMI1_SLOT5;
|
|
lane_to_slot_fsm2[7] = EMI1_SLOT5;
|
|
}
|
|
break;
|
|
|
|
case 0x57:
|
|
printf("qds: WRIOP: Supported SerDes2 Protocol 0x%02x\n",
|
|
serdes2_prtcl);
|
|
if (hwconfig_f("xqsgmii", env_hwconfig)) {
|
|
lane_to_slot_fsm2[0] = EMI_NONE;
|
|
lane_to_slot_fsm2[1] = EMI_NONE;
|
|
lane_to_slot_fsm2[2] = EMI_NONE;
|
|
lane_to_slot_fsm2[3] = EMI_NONE;
|
|
}
|
|
lane_to_slot_fsm2[4] = EMI_NONE;
|
|
lane_to_slot_fsm2[5] = EMI_NONE;
|
|
lane_to_slot_fsm2[6] = EMI1_SLOT5;
|
|
lane_to_slot_fsm2[7] = EMI1_SLOT5;
|
|
break;
|
|
|
|
default:
|
|
printf(" %s qds: WRIOP: Unsupported SerDes2 Protocol 0x%02x\n",
|
|
__func__ , serdes2_prtcl);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ls2080a_handle_phy_interface_sgmii(int dpmac_id)
|
|
{
|
|
int lane, slot;
|
|
struct mii_dev *bus;
|
|
struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
|
|
int serdes1_prtcl = (in_le32(&gur->rcwsr[28]) &
|
|
FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK)
|
|
>> FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT;
|
|
int serdes2_prtcl = (in_le32(&gur->rcwsr[28]) &
|
|
FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK)
|
|
>> FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT;
|
|
|
|
int *riser_phy_addr;
|
|
char *env_hwconfig = env_get("hwconfig");
|
|
|
|
if (hwconfig_f("xqsgmii", env_hwconfig))
|
|
riser_phy_addr = &xqsgii_riser_phy_addr[0];
|
|
else
|
|
riser_phy_addr = &sgmii_riser_phy_addr[0];
|
|
|
|
if (dpmac_id > WRIOP1_DPMAC9)
|
|
goto serdes2;
|
|
|
|
switch (serdes1_prtcl) {
|
|
case 0x07:
|
|
case 0x39:
|
|
case 0x4D:
|
|
lane = serdes_get_first_lane(FSL_SRDS_1, SGMII1 + dpmac_id - 1);
|
|
|
|
slot = lane_to_slot_fsm1[lane];
|
|
|
|
switch (++slot) {
|
|
case 1:
|
|
/* Slot housing a SGMII riser card? */
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 1]);
|
|
dpmac_info[dpmac_id].board_mux = EMI1_SLOT1;
|
|
bus = mii_dev_for_muxval(EMI1_SLOT1);
|
|
wriop_set_mdio(dpmac_id, bus);
|
|
break;
|
|
case 2:
|
|
/* Slot housing a SGMII riser card? */
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 1]);
|
|
dpmac_info[dpmac_id].board_mux = EMI1_SLOT2;
|
|
bus = mii_dev_for_muxval(EMI1_SLOT2);
|
|
wriop_set_mdio(dpmac_id, bus);
|
|
break;
|
|
case 3:
|
|
if (slot == EMI_NONE)
|
|
return;
|
|
if (serdes1_prtcl == 0x39) {
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 2]);
|
|
if (dpmac_id >= 6 && hwconfig_f("xqsgmii",
|
|
env_hwconfig))
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 3]);
|
|
} else {
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 2]);
|
|
if (dpmac_id >= 7 && hwconfig_f("xqsgmii",
|
|
env_hwconfig))
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 3]);
|
|
}
|
|
dpmac_info[dpmac_id].board_mux = EMI1_SLOT3;
|
|
bus = mii_dev_for_muxval(EMI1_SLOT3);
|
|
wriop_set_mdio(dpmac_id, bus);
|
|
break;
|
|
case 4:
|
|
break;
|
|
case 5:
|
|
break;
|
|
case 6:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
printf("%s qds: WRIOP: Unsupported SerDes1 Protocol 0x%02x\n",
|
|
__func__ , serdes1_prtcl);
|
|
break;
|
|
}
|
|
|
|
serdes2:
|
|
switch (serdes2_prtcl) {
|
|
case 0x07:
|
|
case 0x08:
|
|
case 0x49:
|
|
case 0x47:
|
|
case 0x57:
|
|
lane = serdes_get_first_lane(FSL_SRDS_2, SGMII9 +
|
|
(dpmac_id - 9));
|
|
slot = lane_to_slot_fsm2[lane];
|
|
|
|
switch (++slot) {
|
|
case 1:
|
|
break;
|
|
case 3:
|
|
break;
|
|
case 4:
|
|
/* Slot housing a SGMII riser card? */
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 9]);
|
|
dpmac_info[dpmac_id].board_mux = EMI1_SLOT4;
|
|
bus = mii_dev_for_muxval(EMI1_SLOT4);
|
|
wriop_set_mdio(dpmac_id, bus);
|
|
break;
|
|
case 5:
|
|
if (slot == EMI_NONE)
|
|
return;
|
|
if (serdes2_prtcl == 0x47) {
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 10]);
|
|
if (dpmac_id >= 14 && hwconfig_f("xqsgmii",
|
|
env_hwconfig))
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 11]);
|
|
} else {
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 11]);
|
|
}
|
|
dpmac_info[dpmac_id].board_mux = EMI1_SLOT5;
|
|
bus = mii_dev_for_muxval(EMI1_SLOT5);
|
|
wriop_set_mdio(dpmac_id, bus);
|
|
break;
|
|
case 6:
|
|
/* Slot housing a SGMII riser card? */
|
|
wriop_set_phy_address(dpmac_id, 0,
|
|
riser_phy_addr[dpmac_id - 13]);
|
|
dpmac_info[dpmac_id].board_mux = EMI1_SLOT6;
|
|
bus = mii_dev_for_muxval(EMI1_SLOT6);
|
|
wriop_set_mdio(dpmac_id, bus);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
printf("%s qds: WRIOP: Unsupported SerDes2 Protocol 0x%02x\n",
|
|
__func__, serdes2_prtcl);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ls2080a_handle_phy_interface_qsgmii(int dpmac_id)
|
|
{
|
|
int lane = 0, slot;
|
|
struct mii_dev *bus;
|
|
struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
|
|
int serdes1_prtcl = (in_le32(&gur->rcwsr[28]) &
|
|
FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK)
|
|
>> FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT;
|
|
|
|
switch (serdes1_prtcl) {
|
|
case 0x33:
|
|
switch (dpmac_id) {
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
lane = serdes_get_first_lane(FSL_SRDS_1, QSGMII_A);
|
|
break;
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
lane = serdes_get_first_lane(FSL_SRDS_1, QSGMII_B);
|
|
break;
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
lane = serdes_get_first_lane(FSL_SRDS_1, QSGMII_C);
|
|
break;
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
case 16:
|
|
lane = serdes_get_first_lane(FSL_SRDS_1, QSGMII_D);
|
|
break;
|
|
}
|
|
|
|
slot = lane_to_slot_fsm1[lane];
|
|
|
|
switch (++slot) {
|
|
case 1:
|
|
/* Slot housing a QSGMII riser card? */
|
|
wriop_set_phy_address(dpmac_id, 0, dpmac_id - 1);
|
|
dpmac_info[dpmac_id].board_mux = EMI1_SLOT1;
|
|
bus = mii_dev_for_muxval(EMI1_SLOT1);
|
|
wriop_set_mdio(dpmac_id, bus);
|
|
break;
|
|
case 3:
|
|
break;
|
|
case 4:
|
|
break;
|
|
case 5:
|
|
break;
|
|
case 6:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
printf("qds: WRIOP: Unsupported SerDes Protocol 0x%02x\n",
|
|
serdes1_prtcl);
|
|
break;
|
|
}
|
|
|
|
qsgmii_configure_repeater(dpmac_id);
|
|
}
|
|
|
|
void ls2080a_handle_phy_interface_xsgmii(int i)
|
|
{
|
|
struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
|
|
int serdes1_prtcl = (in_le32(&gur->rcwsr[28]) &
|
|
FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK)
|
|
>> FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT;
|
|
|
|
switch (serdes1_prtcl) {
|
|
case 0x2A:
|
|
case 0x4B:
|
|
case 0x4C:
|
|
/*
|
|
* XFI does not need a PHY to work, but to avoid U-Boot use
|
|
* default PHY address which is zero to a MAC when it found
|
|
* a MAC has no PHY address, we give a PHY address to XFI
|
|
* MAC, and should not use a real XAUI PHY address, since
|
|
* MDIO can access it successfully, and then MDIO thinks
|
|
* the XAUI card is used for the XFI MAC, which will cause
|
|
* error.
|
|
*/
|
|
wriop_set_phy_address(i, 0, i + 4);
|
|
ls2080a_qds_enable_SFP_TX(SFP_TX);
|
|
|
|
break;
|
|
default:
|
|
printf("qds: WRIOP: Unsupported SerDes Protocol 0x%02x\n",
|
|
serdes1_prtcl);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int board_eth_init(bd_t *bis)
|
|
{
|
|
int error;
|
|
#if defined(CONFIG_FSL_MC_ENET) && !defined(CONFIG_SPL_BUILD)
|
|
struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
|
|
int serdes1_prtcl = (in_le32(&gur->rcwsr[28]) &
|
|
FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK)
|
|
>> FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT;
|
|
int serdes2_prtcl = (in_le32(&gur->rcwsr[28]) &
|
|
FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK)
|
|
>> FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT;
|
|
|
|
struct memac_mdio_info *memac_mdio0_info;
|
|
struct memac_mdio_info *memac_mdio1_info;
|
|
unsigned int i;
|
|
char *env_hwconfig;
|
|
|
|
env_hwconfig = env_get("hwconfig");
|
|
|
|
initialize_dpmac_to_slot();
|
|
|
|
memac_mdio0_info = (struct memac_mdio_info *)malloc(
|
|
sizeof(struct memac_mdio_info));
|
|
memac_mdio0_info->regs =
|
|
(struct memac_mdio_controller *)
|
|
CONFIG_SYS_FSL_WRIOP1_MDIO1;
|
|
memac_mdio0_info->name = DEFAULT_WRIOP_MDIO1_NAME;
|
|
|
|
/* Register the real MDIO1 bus */
|
|
fm_memac_mdio_init(bis, memac_mdio0_info);
|
|
|
|
memac_mdio1_info = (struct memac_mdio_info *)malloc(
|
|
sizeof(struct memac_mdio_info));
|
|
memac_mdio1_info->regs =
|
|
(struct memac_mdio_controller *)
|
|
CONFIG_SYS_FSL_WRIOP1_MDIO2;
|
|
memac_mdio1_info->name = DEFAULT_WRIOP_MDIO2_NAME;
|
|
|
|
/* Register the real MDIO2 bus */
|
|
fm_memac_mdio_init(bis, memac_mdio1_info);
|
|
|
|
/* Register the muxing front-ends to the MDIO buses */
|
|
ls2080a_qds_mdio_init(DEFAULT_WRIOP_MDIO1_NAME, EMI1_SLOT1);
|
|
ls2080a_qds_mdio_init(DEFAULT_WRIOP_MDIO1_NAME, EMI1_SLOT2);
|
|
ls2080a_qds_mdio_init(DEFAULT_WRIOP_MDIO1_NAME, EMI1_SLOT3);
|
|
ls2080a_qds_mdio_init(DEFAULT_WRIOP_MDIO1_NAME, EMI1_SLOT4);
|
|
ls2080a_qds_mdio_init(DEFAULT_WRIOP_MDIO1_NAME, EMI1_SLOT5);
|
|
ls2080a_qds_mdio_init(DEFAULT_WRIOP_MDIO1_NAME, EMI1_SLOT6);
|
|
|
|
ls2080a_qds_mdio_init(DEFAULT_WRIOP_MDIO2_NAME, EMI2);
|
|
|
|
for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++) {
|
|
switch (wriop_get_enet_if(i)) {
|
|
case PHY_INTERFACE_MODE_QSGMII:
|
|
ls2080a_handle_phy_interface_qsgmii(i);
|
|
break;
|
|
case PHY_INTERFACE_MODE_SGMII:
|
|
ls2080a_handle_phy_interface_sgmii(i);
|
|
break;
|
|
case PHY_INTERFACE_MODE_XGMII:
|
|
ls2080a_handle_phy_interface_xsgmii(i);
|
|
break;
|
|
default:
|
|
break;
|
|
|
|
if (i == 16)
|
|
i = NUM_WRIOP_PORTS;
|
|
}
|
|
}
|
|
|
|
error = cpu_eth_init(bis);
|
|
|
|
if (hwconfig_f("xqsgmii", env_hwconfig)) {
|
|
if (serdes1_prtcl == 0x7)
|
|
sgmii_configure_repeater(1);
|
|
if (serdes2_prtcl == 0x7 || serdes2_prtcl == 0x8 ||
|
|
serdes2_prtcl == 0x49)
|
|
sgmii_configure_repeater(2);
|
|
}
|
|
#endif
|
|
error = pci_eth_init(bis);
|
|
return error;
|
|
}
|
|
|
|
#if defined(CONFIG_RESET_PHY_R)
|
|
void reset_phy(void)
|
|
{
|
|
mc_env_boot();
|
|
}
|
|
#endif /* CONFIG_RESET_PHY_R */
|