aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/axgbe/xgbe-mdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/axgbe/xgbe-mdio.c')
-rw-r--r--sys/dev/axgbe/xgbe-mdio.c1466
1 files changed, 963 insertions, 503 deletions
diff --git a/sys/dev/axgbe/xgbe-mdio.c b/sys/dev/axgbe/xgbe-mdio.c
index 850a58e04107..a716c1a7b797 100644
--- a/sys/dev/axgbe/xgbe-mdio.c
+++ b/sys/dev/axgbe/xgbe-mdio.c
@@ -1,13 +1,13 @@
/*
* AMD 10Gb Ethernet driver
*
+ * Copyright (c) 2014-2016,2020 Advanced Micro Devices, Inc.
+ *
* This file is available to you under your choice of the following two
* licenses:
*
* License 1: GPLv2
*
- * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
- *
* This file is free software; you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or (at
@@ -56,9 +56,6 @@
*
* License 2: Modified BSD
*
- * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
- * All rights reserved.
- *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
@@ -117,305 +114,274 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/param.h>
-#include <sys/kernel.h>
-
#include "xgbe.h"
#include "xgbe-common.h"
static void xgbe_an_state_machine(struct xgbe_prv_data *pdata);
-static void xgbe_an_enable_kr_training(struct xgbe_prv_data *pdata)
+static void
+xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata)
{
- unsigned int reg;
-
- reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
+ int reg;
- reg |= XGBE_KR_TRAINING_ENABLE;
- XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
+ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
+ reg &= ~XGBE_AN_CL37_INT_MASK;
+ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
}
-static void xgbe_an_disable_kr_training(struct xgbe_prv_data *pdata)
+static void
+xgbe_an37_disable_interrupts(struct xgbe_prv_data *pdata)
{
- unsigned int reg;
+ int reg;
- reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
+ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
+ reg &= ~XGBE_AN_CL37_INT_MASK;
+ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
- reg &= ~XGBE_KR_TRAINING_ENABLE;
- XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
+ reg &= ~XGBE_PCS_CL37_BP;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
}
-static void xgbe_pcs_power_cycle(struct xgbe_prv_data *pdata)
+static void
+xgbe_an37_enable_interrupts(struct xgbe_prv_data *pdata)
{
- unsigned int reg;
-
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
+ int reg;
- reg |= MDIO_CTRL1_LPOWER;
- XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
+ reg |= XGBE_PCS_CL37_BP;
+ XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
- DELAY(75);
-
- reg &= ~MDIO_CTRL1_LPOWER;
- XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
+ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
+ reg |= XGBE_AN_CL37_INT_MASK;
+ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
}
-static void xgbe_serdes_start_ratechange(struct xgbe_prv_data *pdata)
+static void
+xgbe_an73_clear_interrupts(struct xgbe_prv_data *pdata)
{
- /* Assert Rx and Tx ratechange */
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 1);
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
}
-static void xgbe_serdes_complete_ratechange(struct xgbe_prv_data *pdata)
+static void
+xgbe_an73_disable_interrupts(struct xgbe_prv_data *pdata)
{
- unsigned int wait;
- u16 status;
-
- /* Release Rx and Tx ratechange */
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, RATECHANGE, 0);
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
+}
- /* Wait for Rx and Tx ready */
- wait = XGBE_RATECHANGE_COUNT;
- while (wait--) {
- DELAY(50);
+static void
+xgbe_an73_enable_interrupts(struct xgbe_prv_data *pdata)
+{
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_CL73_INT_MASK);
+}
- status = XSIR0_IOREAD(pdata, SIR0_STATUS);
- if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) &&
- XSIR_GET_BITS(status, SIR0_STATUS, TX_READY))
- goto rx_reset;
+static void
+xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata)
+{
+ switch (pdata->an_mode) {
+ case XGBE_AN_MODE_CL73:
+ case XGBE_AN_MODE_CL73_REDRV:
+ xgbe_an73_enable_interrupts(pdata);
+ break;
+ case XGBE_AN_MODE_CL37:
+ case XGBE_AN_MODE_CL37_SGMII:
+ xgbe_an37_enable_interrupts(pdata);
+ break;
+ default:
+ break;
}
-
-rx_reset:
- /* Perform Rx reset for the DFE changes */
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 0);
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG6, RESETB_RXD, 1);
}
-static void xgbe_xgmii_mode(struct xgbe_prv_data *pdata)
+static void
+xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata)
{
- unsigned int reg;
-
- /* Enable KR training */
- xgbe_an_enable_kr_training(pdata);
+ xgbe_an73_clear_interrupts(pdata);
+ xgbe_an37_clear_interrupts(pdata);
+}
+static void
+xgbe_kr_mode(struct xgbe_prv_data *pdata)
+{
/* Set MAC to 10G speed */
- pdata->hw_if.set_xgmii_speed(pdata);
-
- /* Set PCS to KR/10G speed */
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2);
- reg &= ~MDIO_PCS_CTRL2_TYPE;
- reg |= MDIO_PCS_CTRL2_10GBR;
- XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg);
+ pdata->hw_if.set_speed(pdata, SPEED_10000);
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
- reg &= ~MDIO_CTRL1_SPEEDSEL;
- reg |= MDIO_CTRL1_SPEED10G;
- XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
-
- xgbe_pcs_power_cycle(pdata);
-
- /* Set SerDes to 10G speed */
- xgbe_serdes_start_ratechange(pdata);
-
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_10000_RATE);
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_10000_WORD);
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_10000_PLL);
-
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE,
- pdata->serdes_cdr_rate[XGBE_SPEED_10000]);
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP,
- pdata->serdes_tx_amp[XGBE_SPEED_10000]);
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA,
- pdata->serdes_blwc[XGBE_SPEED_10000]);
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG,
- pdata->serdes_pq_skew[XGBE_SPEED_10000]);
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG,
- pdata->serdes_dfe_tap_cfg[XGBE_SPEED_10000]);
- XRXTX_IOWRITE(pdata, RXTX_REG22,
- pdata->serdes_dfe_tap_ena[XGBE_SPEED_10000]);
-
- xgbe_serdes_complete_ratechange(pdata);
+ /* Call PHY implementation support to complete rate change */
+ pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KR);
}
-static void xgbe_gmii_2500_mode(struct xgbe_prv_data *pdata)
+static void
+xgbe_kx_2500_mode(struct xgbe_prv_data *pdata)
{
- unsigned int reg;
-
- /* Disable KR training */
- xgbe_an_disable_kr_training(pdata);
-
/* Set MAC to 2.5G speed */
- pdata->hw_if.set_gmii_2500_speed(pdata);
-
- /* Set PCS to KX/1G speed */
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2);
- reg &= ~MDIO_PCS_CTRL2_TYPE;
- reg |= MDIO_PCS_CTRL2_10GBX;
- XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg);
+ pdata->hw_if.set_speed(pdata, SPEED_2500);
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
- reg &= ~MDIO_CTRL1_SPEEDSEL;
- reg |= MDIO_CTRL1_SPEED1G;
- XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
+ /* Call PHY implementation support to complete rate change */
+ pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_2500);
+}
- xgbe_pcs_power_cycle(pdata);
+static void
+xgbe_kx_1000_mode(struct xgbe_prv_data *pdata)
+{
+ /* Set MAC to 1G speed */
+ pdata->hw_if.set_speed(pdata, SPEED_1000);
- /* Set SerDes to 2.5G speed */
- xgbe_serdes_start_ratechange(pdata);
+ /* Call PHY implementation support to complete rate change */
+ pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000);
+}
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_2500_RATE);
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_2500_WORD);
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_2500_PLL);
+static void
+xgbe_sfi_mode(struct xgbe_prv_data *pdata)
+{
+ /* If a KR re-driver is present, change to KR mode instead */
+ if (pdata->kr_redrv)
+ return (xgbe_kr_mode(pdata));
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE,
- pdata->serdes_cdr_rate[XGBE_SPEED_2500]);
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP,
- pdata->serdes_tx_amp[XGBE_SPEED_2500]);
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA,
- pdata->serdes_blwc[XGBE_SPEED_2500]);
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG,
- pdata->serdes_pq_skew[XGBE_SPEED_2500]);
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG,
- pdata->serdes_dfe_tap_cfg[XGBE_SPEED_2500]);
- XRXTX_IOWRITE(pdata, RXTX_REG22,
- pdata->serdes_dfe_tap_ena[XGBE_SPEED_2500]);
+ /* Set MAC to 10G speed */
+ pdata->hw_if.set_speed(pdata, SPEED_10000);
- xgbe_serdes_complete_ratechange(pdata);
+ /* Call PHY implementation support to complete rate change */
+ pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SFI);
}
-static void xgbe_gmii_mode(struct xgbe_prv_data *pdata)
+static void
+xgbe_x_mode(struct xgbe_prv_data *pdata)
{
- unsigned int reg;
-
- /* Disable KR training */
- xgbe_an_disable_kr_training(pdata);
-
/* Set MAC to 1G speed */
- pdata->hw_if.set_gmii_speed(pdata);
+ pdata->hw_if.set_speed(pdata, SPEED_1000);
- /* Set PCS to KX/1G speed */
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2);
- reg &= ~MDIO_PCS_CTRL2_TYPE;
- reg |= MDIO_PCS_CTRL2_10GBX;
- XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg);
+ /* Call PHY implementation support to complete rate change */
+ pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_X);
+}
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
- reg &= ~MDIO_CTRL1_SPEEDSEL;
- reg |= MDIO_CTRL1_SPEED1G;
- XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
+static void
+xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata)
+{
+ /* Set MAC to 1G speed */
+ pdata->hw_if.set_speed(pdata, SPEED_1000);
- xgbe_pcs_power_cycle(pdata);
+ /* Call PHY implementation support to complete rate change */
+ pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000);
+}
- /* Set SerDes to 1G speed */
- xgbe_serdes_start_ratechange(pdata);
+static void
+xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata)
+{
+ /* Set MAC to 1G speed */
+ pdata->hw_if.set_speed(pdata, SPEED_1000);
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_1000_RATE);
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_1000_WORD);
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_1000_PLL);
+ /* Call PHY implementation support to complete rate change */
+ pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_100);
+}
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE,
- pdata->serdes_cdr_rate[XGBE_SPEED_1000]);
- XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP,
- pdata->serdes_tx_amp[XGBE_SPEED_1000]);
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA,
- pdata->serdes_blwc[XGBE_SPEED_1000]);
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG,
- pdata->serdes_pq_skew[XGBE_SPEED_1000]);
- XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG,
- pdata->serdes_dfe_tap_cfg[XGBE_SPEED_1000]);
- XRXTX_IOWRITE(pdata, RXTX_REG22,
- pdata->serdes_dfe_tap_ena[XGBE_SPEED_1000]);
+static enum xgbe_mode
+xgbe_cur_mode(struct xgbe_prv_data *pdata)
+{
+ return (pdata->phy_if.phy_impl.cur_mode(pdata));
+}
- xgbe_serdes_complete_ratechange(pdata);
+static bool
+xgbe_in_kr_mode(struct xgbe_prv_data *pdata)
+{
+ return (xgbe_cur_mode(pdata) == XGBE_MODE_KR);
}
-static void xgbe_cur_mode(struct xgbe_prv_data *pdata,
- enum xgbe_mode *mode)
+static void
+xgbe_change_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
{
- unsigned int reg;
+ switch (mode) {
+ case XGBE_MODE_KX_1000:
+ xgbe_kx_1000_mode(pdata);
+ break;
+ case XGBE_MODE_KX_2500:
+ xgbe_kx_2500_mode(pdata);
+ break;
+ case XGBE_MODE_KR:
+ xgbe_kr_mode(pdata);
+ break;
+ case XGBE_MODE_SGMII_100:
+ xgbe_sgmii_100_mode(pdata);
+ break;
+ case XGBE_MODE_SGMII_1000:
+ xgbe_sgmii_1000_mode(pdata);
+ break;
+ case XGBE_MODE_X:
+ xgbe_x_mode(pdata);
+ break;
+ case XGBE_MODE_SFI:
+ xgbe_sfi_mode(pdata);
+ break;
+ case XGBE_MODE_UNKNOWN:
+ break;
+ default:
+ axgbe_error("invalid operation mode requested (%u)\n", mode);
+ }
+}
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2);
- if ((reg & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
- *mode = XGBE_MODE_KR;
- else
- *mode = XGBE_MODE_KX;
+static void
+xgbe_switch_mode(struct xgbe_prv_data *pdata)
+{
+ xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));
}
-static bool xgbe_in_kr_mode(struct xgbe_prv_data *pdata)
+static bool
+xgbe_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
{
- enum xgbe_mode mode;
+ if (mode == xgbe_cur_mode(pdata))
+ return (false);
- xgbe_cur_mode(pdata, &mode);
+ xgbe_change_mode(pdata, mode);
- return (mode == XGBE_MODE_KR);
+ return (true);
}
-static void xgbe_switch_mode(struct xgbe_prv_data *pdata)
+static bool
+xgbe_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
{
- /* If we are in KR switch to KX, and vice-versa */
- if (xgbe_in_kr_mode(pdata)) {
- if (pdata->speed_set == XGBE_SPEEDSET_1000_10000)
- xgbe_gmii_mode(pdata);
- else
- xgbe_gmii_2500_mode(pdata);
- } else {
- xgbe_xgmii_mode(pdata);
- }
+ return (pdata->phy_if.phy_impl.use_mode(pdata, mode));
}
-static void xgbe_set_mode(struct xgbe_prv_data *pdata,
- enum xgbe_mode mode)
+static void
+xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable, bool restart)
{
- enum xgbe_mode cur_mode;
+ unsigned int reg;
- xgbe_cur_mode(pdata, &cur_mode);
- if (mode != cur_mode)
- xgbe_switch_mode(pdata);
-}
+ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1);
+ reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE;
-static bool xgbe_use_xgmii_mode(struct xgbe_prv_data *pdata)
-{
- if (pdata->phy.autoneg == AUTONEG_ENABLE) {
- if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
- return true;
- } else {
- if (pdata->phy.speed == SPEED_10000)
- return true;
- }
+ if (enable)
+ reg |= MDIO_VEND2_CTRL1_AN_ENABLE;
- return false;
+ if (restart)
+ reg |= MDIO_VEND2_CTRL1_AN_RESTART;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
}
-static bool xgbe_use_gmii_2500_mode(struct xgbe_prv_data *pdata)
+static void
+xgbe_an37_restart(struct xgbe_prv_data *pdata)
{
- if (pdata->phy.autoneg == AUTONEG_ENABLE) {
- if (pdata->phy.advertising & ADVERTISED_2500baseX_Full)
- return true;
- } else {
- if (pdata->phy.speed == SPEED_2500)
- return true;
- }
-
- return false;
+ xgbe_an37_enable_interrupts(pdata);
+ xgbe_an37_set(pdata, true, true);
}
-static bool xgbe_use_gmii_mode(struct xgbe_prv_data *pdata)
+static void
+xgbe_an37_disable(struct xgbe_prv_data *pdata)
{
- if (pdata->phy.autoneg == AUTONEG_ENABLE) {
- if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full)
- return true;
- } else {
- if (pdata->phy.speed == SPEED_1000)
- return true;
- }
-
- return false;
+ xgbe_an37_set(pdata, false, false);
+ xgbe_an37_disable_interrupts(pdata);
}
-static void xgbe_set_an(struct xgbe_prv_data *pdata, bool enable, bool restart)
+static void
+xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable, bool restart)
{
unsigned int reg;
+ /* Disable KR training for now */
+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
+ reg &= ~XGBE_KR_TRAINING_ENABLE;
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
+
+ /* Update AN settings */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1);
reg &= ~MDIO_AN_CTRL1_ENABLE;
@@ -428,18 +394,71 @@ static void xgbe_set_an(struct xgbe_prv_data *pdata, bool enable, bool restart)
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg);
}
-static void xgbe_restart_an(struct xgbe_prv_data *pdata)
+static void
+xgbe_an73_restart(struct xgbe_prv_data *pdata)
{
- xgbe_set_an(pdata, true, true);
+ xgbe_an73_enable_interrupts(pdata);
+ xgbe_an73_set(pdata, true, true);
}
-static void xgbe_disable_an(struct xgbe_prv_data *pdata)
+static void
+xgbe_an73_disable(struct xgbe_prv_data *pdata)
{
- xgbe_set_an(pdata, false, false);
+ xgbe_an73_set(pdata, false, false);
+ xgbe_an73_disable_interrupts(pdata);
+
+ pdata->an_start = 0;
}
-static enum xgbe_an xgbe_an_tx_training(struct xgbe_prv_data *pdata,
- enum xgbe_rx *state)
+static void
+xgbe_an_restart(struct xgbe_prv_data *pdata)
+{
+ if (pdata->phy_if.phy_impl.an_pre)
+ pdata->phy_if.phy_impl.an_pre(pdata);
+
+ switch (pdata->an_mode) {
+ case XGBE_AN_MODE_CL73:
+ case XGBE_AN_MODE_CL73_REDRV:
+ xgbe_an73_restart(pdata);
+ break;
+ case XGBE_AN_MODE_CL37:
+ case XGBE_AN_MODE_CL37_SGMII:
+ xgbe_an37_restart(pdata);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+xgbe_an_disable(struct xgbe_prv_data *pdata)
+{
+ if (pdata->phy_if.phy_impl.an_post)
+ pdata->phy_if.phy_impl.an_post(pdata);
+
+ switch (pdata->an_mode) {
+ case XGBE_AN_MODE_CL73:
+ case XGBE_AN_MODE_CL73_REDRV:
+ xgbe_an73_disable(pdata);
+ break;
+ case XGBE_AN_MODE_CL37:
+ case XGBE_AN_MODE_CL37_SGMII:
+ xgbe_an37_disable(pdata);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+xgbe_an_disable_all(struct xgbe_prv_data *pdata)
+{
+ xgbe_an73_disable(pdata);
+ xgbe_an37_disable(pdata);
+}
+
+static enum xgbe_an
+xgbe_an73_tx_training(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
{
unsigned int ad_reg, lp_reg, reg;
@@ -447,7 +466,7 @@ static enum xgbe_an xgbe_an_tx_training(struct xgbe_prv_data *pdata,
/* If we're not in KR mode then we're done */
if (!xgbe_in_kr_mode(pdata))
- return XGBE_AN_PAGE_RECEIVED;
+ return (XGBE_AN_PAGE_RECEIVED);
/* Enable/Disable FEC */
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
@@ -461,24 +480,25 @@ static enum xgbe_an xgbe_an_tx_training(struct xgbe_prv_data *pdata,
XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg);
/* Start KR training */
- reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
- if (reg & XGBE_KR_TRAINING_ENABLE) {
- XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 1);
+ if (pdata->phy_if.phy_impl.kr_training_pre)
+ pdata->phy_if.phy_impl.kr_training_pre(pdata);
- reg |= XGBE_KR_TRAINING_START;
- XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
- reg);
+ /* Start KR training */
+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
+ reg |= XGBE_KR_TRAINING_ENABLE;
+ reg |= XGBE_KR_TRAINING_START;
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
- XSIR0_IOWRITE_BITS(pdata, SIR0_KR_RT_1, RESET, 0);
- }
+ if (pdata->phy_if.phy_impl.kr_training_post)
+ pdata->phy_if.phy_impl.kr_training_post(pdata);
- return XGBE_AN_PAGE_RECEIVED;
+ return (XGBE_AN_PAGE_RECEIVED);
}
-static enum xgbe_an xgbe_an_tx_xnp(struct xgbe_prv_data *pdata,
- enum xgbe_rx *state)
+static enum xgbe_an
+xgbe_an73_tx_xnp(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
{
- u16 msg;
+ uint16_t msg;
*state = XGBE_RX_XNP;
@@ -489,11 +509,11 @@ static enum xgbe_an xgbe_an_tx_xnp(struct xgbe_prv_data *pdata,
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg);
- return XGBE_AN_PAGE_RECEIVED;
+ return (XGBE_AN_PAGE_RECEIVED);
}
-static enum xgbe_an xgbe_an_rx_bpa(struct xgbe_prv_data *pdata,
- enum xgbe_rx *state)
+static enum xgbe_an
+xgbe_an73_rx_bpa(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
{
unsigned int link_support;
unsigned int reg, ad_reg, lp_reg;
@@ -504,20 +524,20 @@ static enum xgbe_an xgbe_an_rx_bpa(struct xgbe_prv_data *pdata,
/* Check for a supported mode, otherwise restart in a different one */
link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20;
if (!(reg & link_support))
- return XGBE_AN_INCOMPAT_LINK;
+ return (XGBE_AN_INCOMPAT_LINK);
/* Check Extended Next Page support */
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
- return ((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
+ return (((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
(lp_reg & XGBE_XNP_NP_EXCHANGE))
- ? xgbe_an_tx_xnp(pdata, state)
- : xgbe_an_tx_training(pdata, state);
+ ? xgbe_an73_tx_xnp(pdata, state)
+ : xgbe_an73_tx_training(pdata, state));
}
-static enum xgbe_an xgbe_an_rx_xnp(struct xgbe_prv_data *pdata,
- enum xgbe_rx *state)
+static enum xgbe_an
+xgbe_an73_rx_xnp(struct xgbe_prv_data *pdata, enum xgbe_rx *state)
{
unsigned int ad_reg, lp_reg;
@@ -525,13 +545,14 @@ static enum xgbe_an xgbe_an_rx_xnp(struct xgbe_prv_data *pdata,
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX);
- return ((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
+ return (((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
(lp_reg & XGBE_XNP_NP_EXCHANGE))
- ? xgbe_an_tx_xnp(pdata, state)
- : xgbe_an_tx_training(pdata, state);
+ ? xgbe_an73_tx_xnp(pdata, state)
+ : xgbe_an73_tx_training(pdata, state));
}
-static enum xgbe_an xgbe_an_page_received(struct xgbe_prv_data *pdata)
+static enum xgbe_an
+xgbe_an73_page_received(struct xgbe_prv_data *pdata)
{
enum xgbe_rx *state;
unsigned long an_timeout;
@@ -548,65 +569,95 @@ static enum xgbe_an xgbe_an_page_received(struct xgbe_prv_data *pdata)
pdata->kx_state = XGBE_RX_BPA;
pdata->an_start = ticks;
+
+ axgbe_printf(2, "CL73 AN timed out, resetting state\n");
}
}
- state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state
- : &pdata->kx_state;
+ state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state : &pdata->kx_state;
switch (*state) {
case XGBE_RX_BPA:
- ret = xgbe_an_rx_bpa(pdata, state);
+ ret = xgbe_an73_rx_bpa(pdata, state);
break;
case XGBE_RX_XNP:
- ret = xgbe_an_rx_xnp(pdata, state);
+ ret = xgbe_an73_rx_xnp(pdata, state);
break;
default:
ret = XGBE_AN_ERROR;
}
- return ret;
+ return (ret);
}
-static enum xgbe_an xgbe_an_incompat_link(struct xgbe_prv_data *pdata)
+static enum xgbe_an
+xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
{
/* Be sure we aren't looping trying to negotiate */
if (xgbe_in_kr_mode(pdata)) {
pdata->kr_state = XGBE_RX_ERROR;
- if (!(pdata->phy.advertising & ADVERTISED_1000baseKX_Full) &&
- !(pdata->phy.advertising & ADVERTISED_2500baseX_Full))
- return XGBE_AN_NO_LINK;
+ if (!(XGBE_ADV(&pdata->phy, 1000baseKX_Full)) &&
+ !(XGBE_ADV(&pdata->phy, 2500baseX_Full)))
+ return (XGBE_AN_NO_LINK);
if (pdata->kx_state != XGBE_RX_BPA)
- return XGBE_AN_NO_LINK;
+ return (XGBE_AN_NO_LINK);
} else {
pdata->kx_state = XGBE_RX_ERROR;
- if (!(pdata->phy.advertising & ADVERTISED_10000baseKR_Full))
- return XGBE_AN_NO_LINK;
+ if (!(XGBE_ADV(&pdata->phy, 10000baseKR_Full)))
+ return (XGBE_AN_NO_LINK);
if (pdata->kr_state != XGBE_RX_BPA)
- return XGBE_AN_NO_LINK;
+ return (XGBE_AN_NO_LINK);
}
- xgbe_disable_an(pdata);
+ xgbe_an_disable(pdata);
xgbe_switch_mode(pdata);
- xgbe_restart_an(pdata);
+ xgbe_an_restart(pdata);
- return XGBE_AN_INCOMPAT_LINK;
+ return (XGBE_AN_INCOMPAT_LINK);
}
-static void xgbe_an_isr(void *data)
+static void
+xgbe_an37_isr(struct xgbe_prv_data *pdata)
{
- struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
+ unsigned int reg;
/* Disable AN interrupts */
- XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
+ xgbe_an37_disable_interrupts(pdata);
+
+ /* Save the interrupt(s) that fired */
+ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
+ pdata->an_int = reg & XGBE_AN_CL37_INT_MASK;
+ pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK;
+
+ if (pdata->an_int) {
+ /* Clear the interrupt(s) that fired and process them */
+ reg &= ~XGBE_AN_CL37_INT_MASK;
+ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
+
+ xgbe_an_state_machine(pdata);
+ } else {
+ /* Enable AN interrupts */
+ xgbe_an37_enable_interrupts(pdata);
+
+ /* Reissue interrupt if status is not clear */
+ if (pdata->vdata->irq_reissue_support)
+ XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
+ }
+}
+
+static void
+xgbe_an73_isr(struct xgbe_prv_data *pdata)
+{
+ /* Disable AN interrupts */
+ xgbe_an73_disable_interrupts(pdata);
/* Save the interrupt(s) that fired */
pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
@@ -618,37 +669,152 @@ static void xgbe_an_isr(void *data)
xgbe_an_state_machine(pdata);
} else {
/* Enable AN interrupts */
- XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK,
- XGBE_AN_INT_MASK);
+ xgbe_an73_enable_interrupts(pdata);
+
+ /* Reissue interrupt if status is not clear */
+ if (pdata->vdata->irq_reissue_support)
+ XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
+ }
+}
+
+static void
+xgbe_an_isr_task(unsigned long data)
+{
+ struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
+
+ axgbe_printf(2, "AN interrupt received\n");
+
+ switch (pdata->an_mode) {
+ case XGBE_AN_MODE_CL73:
+ case XGBE_AN_MODE_CL73_REDRV:
+ xgbe_an73_isr(pdata);
+ break;
+ case XGBE_AN_MODE_CL37:
+ case XGBE_AN_MODE_CL37_SGMII:
+ xgbe_an37_isr(pdata);
+ break;
+ default:
+ break;
}
}
-static void xgbe_an_state_machine(struct xgbe_prv_data *pdata)
+static void
+xgbe_an_combined_isr(struct xgbe_prv_data *pdata)
+{
+ xgbe_an_isr_task((unsigned long)pdata);
+}
+
+static const char *
+xgbe_state_as_string(enum xgbe_an state)
+{
+ switch (state) {
+ case XGBE_AN_READY:
+ return ("Ready");
+ case XGBE_AN_PAGE_RECEIVED:
+ return ("Page-Received");
+ case XGBE_AN_INCOMPAT_LINK:
+ return ("Incompatible-Link");
+ case XGBE_AN_COMPLETE:
+ return ("Complete");
+ case XGBE_AN_NO_LINK:
+ return ("No-Link");
+ case XGBE_AN_ERROR:
+ return ("Error");
+ default:
+ return ("Undefined");
+ }
+}
+
+static void
+xgbe_an37_state_machine(struct xgbe_prv_data *pdata)
{
enum xgbe_an cur_state = pdata->an_state;
- sx_xlock(&pdata->an_mutex);
+ if (!pdata->an_int)
+ return;
+
+ if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) {
+ pdata->an_state = XGBE_AN_COMPLETE;
+ pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT;
+
+ /* If SGMII is enabled, check the link status */
+ if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) &&
+ !(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS))
+ pdata->an_state = XGBE_AN_NO_LINK;
+ }
+
+ axgbe_printf(2, "%s: CL37 AN %s\n", __func__,
+ xgbe_state_as_string(pdata->an_state));
+
+ cur_state = pdata->an_state;
+
+ switch (pdata->an_state) {
+ case XGBE_AN_READY:
+ break;
+
+ case XGBE_AN_COMPLETE:
+ axgbe_printf(2, "Auto negotiation successful\n");
+ break;
+
+ case XGBE_AN_NO_LINK:
+ break;
+
+ default:
+ pdata->an_state = XGBE_AN_ERROR;
+ }
+
+ if (pdata->an_state == XGBE_AN_ERROR) {
+ axgbe_printf(2, "error during auto-negotiation, state=%u\n",
+ cur_state);
+
+ pdata->an_int = 0;
+ xgbe_an37_clear_interrupts(pdata);
+ }
+
+ if (pdata->an_state >= XGBE_AN_COMPLETE) {
+ pdata->an_result = pdata->an_state;
+ pdata->an_state = XGBE_AN_READY;
+
+ if (pdata->phy_if.phy_impl.an_post)
+ pdata->phy_if.phy_impl.an_post(pdata);
+
+ axgbe_printf(2, "CL37 AN result: %s\n",
+ xgbe_state_as_string(pdata->an_result));
+ }
+
+ axgbe_printf(2, "%s: an_state %d an_int %d an_mode %d an_status %d\n",
+ __func__, pdata->an_state, pdata->an_int, pdata->an_mode,
+ pdata->an_status);
+
+ xgbe_an37_enable_interrupts(pdata);
+}
+
+static void
+xgbe_an73_state_machine(struct xgbe_prv_data *pdata)
+{
+ enum xgbe_an cur_state = pdata->an_state;
if (!pdata->an_int)
goto out;
next_int:
- if (pdata->an_int & XGBE_AN_PG_RCV) {
+ if (pdata->an_int & XGBE_AN_CL73_PG_RCV) {
pdata->an_state = XGBE_AN_PAGE_RECEIVED;
- pdata->an_int &= ~XGBE_AN_PG_RCV;
- } else if (pdata->an_int & XGBE_AN_INC_LINK) {
+ pdata->an_int &= ~XGBE_AN_CL73_PG_RCV;
+ } else if (pdata->an_int & XGBE_AN_CL73_INC_LINK) {
pdata->an_state = XGBE_AN_INCOMPAT_LINK;
- pdata->an_int &= ~XGBE_AN_INC_LINK;
- } else if (pdata->an_int & XGBE_AN_INT_CMPLT) {
+ pdata->an_int &= ~XGBE_AN_CL73_INC_LINK;
+ } else if (pdata->an_int & XGBE_AN_CL73_INT_CMPLT) {
pdata->an_state = XGBE_AN_COMPLETE;
- pdata->an_int &= ~XGBE_AN_INT_CMPLT;
+ pdata->an_int &= ~XGBE_AN_CL73_INT_CMPLT;
} else {
pdata->an_state = XGBE_AN_ERROR;
}
- pdata->an_result = pdata->an_state;
-
again:
+ axgbe_printf(2, "CL73 AN %s\n",
+ xgbe_state_as_string(pdata->an_state));
+
cur_state = pdata->an_state;
switch (pdata->an_state) {
@@ -657,18 +823,21 @@ again:
break;
case XGBE_AN_PAGE_RECEIVED:
- pdata->an_state = xgbe_an_page_received(pdata);
+ pdata->an_state = xgbe_an73_page_received(pdata);
pdata->an_supported++;
break;
case XGBE_AN_INCOMPAT_LINK:
pdata->an_supported = 0;
pdata->parallel_detect = 0;
- pdata->an_state = xgbe_an_incompat_link(pdata);
+ pdata->an_state = xgbe_an73_incompat_link(pdata);
break;
case XGBE_AN_COMPLETE:
pdata->parallel_detect = pdata->an_supported ? 0 : 1;
+ axgbe_printf(2, "%s successful\n",
+ pdata->an_supported ? "Auto negotiation"
+ : "Parallel detection");
break;
case XGBE_AN_NO_LINK:
@@ -680,10 +849,14 @@ again:
if (pdata->an_state == XGBE_AN_NO_LINK) {
pdata->an_int = 0;
- XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ xgbe_an73_clear_interrupts(pdata);
} else if (pdata->an_state == XGBE_AN_ERROR) {
+ axgbe_printf(2,
+ "error during auto-negotiation, state=%u\n",
+ cur_state);
+
pdata->an_int = 0;
- XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ xgbe_an73_clear_interrupts(pdata);
}
if (pdata->an_state >= XGBE_AN_COMPLETE) {
@@ -692,6 +865,12 @@ again:
pdata->kr_state = XGBE_RX_BPA;
pdata->kx_state = XGBE_RX_BPA;
pdata->an_start = 0;
+
+ if (pdata->phy_if.phy_impl.an_post)
+ pdata->phy_if.phy_impl.an_post(pdata);
+
+ axgbe_printf(2, "CL73 AN result: %s\n",
+ xgbe_state_as_string(pdata->an_result));
}
if (cur_state != pdata->an_state)
@@ -702,30 +881,119 @@ again:
out:
/* Enable AN interrupts on the way out */
- XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_INT_MASK);
+ xgbe_an73_enable_interrupts(pdata);
+}
+
+static void
+xgbe_an_state_machine(struct xgbe_prv_data *pdata)
+{
+ sx_xlock(&pdata->an_mutex);
+
+ switch (pdata->an_mode) {
+ case XGBE_AN_MODE_CL73:
+ case XGBE_AN_MODE_CL73_REDRV:
+ xgbe_an73_state_machine(pdata);
+ break;
+ case XGBE_AN_MODE_CL37:
+ case XGBE_AN_MODE_CL37_SGMII:
+ xgbe_an37_state_machine(pdata);
+ break;
+ default:
+ break;
+ }
+
+ /* Reissue interrupt if status is not clear */
+ if (pdata->vdata->irq_reissue_support)
+ XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
sx_xunlock(&pdata->an_mutex);
}
-static void xgbe_an_init(struct xgbe_prv_data *pdata)
+static void
+xgbe_an37_init(struct xgbe_prv_data *pdata)
{
+ struct xgbe_phy local_phy;
unsigned int reg;
+ pdata->phy_if.phy_impl.an_advertising(pdata, &local_phy);
+
+ axgbe_printf(2, "%s: advertising 0x%x\n", __func__, local_phy.advertising);
+
+ /* Set up Advertisement register */
+ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
+ if (XGBE_ADV(&local_phy, Pause))
+ reg |= 0x100;
+ else
+ reg &= ~0x100;
+
+ if (XGBE_ADV(&local_phy, Asym_Pause))
+ reg |= 0x80;
+ else
+ reg &= ~0x80;
+
+ /* Full duplex, but not half */
+ reg |= XGBE_AN_CL37_FD_MASK;
+ reg &= ~XGBE_AN_CL37_HD_MASK;
+
+ axgbe_printf(2, "%s: Writing reg: 0x%x\n", __func__, reg);
+ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE, reg);
+
+ /* Set up the Control register */
+ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
+ axgbe_printf(2, "%s: AN_ADVERTISE reg 0x%x an_mode %d\n", __func__,
+ reg, pdata->an_mode);
+ reg &= ~XGBE_AN_CL37_TX_CONFIG_MASK;
+ reg &= ~XGBE_AN_CL37_PCS_MODE_MASK;
+
+ switch (pdata->an_mode) {
+ case XGBE_AN_MODE_CL37:
+ reg |= XGBE_AN_CL37_PCS_MODE_BASEX;
+ break;
+ case XGBE_AN_MODE_CL37_SGMII:
+ reg |= XGBE_AN_CL37_PCS_MODE_SGMII;
+ break;
+ default:
+ break;
+ }
+
+ reg |= XGBE_AN_CL37_MII_CTRL_8BIT;
+ axgbe_printf(2, "%s: Writing reg: 0x%x\n", __func__, reg);
+ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
+
+ axgbe_printf(2, "CL37 AN (%s) initialized\n",
+ (pdata->an_mode == XGBE_AN_MODE_CL37) ? "BaseX" : "SGMII");
+}
+
+static void
+xgbe_an73_init(struct xgbe_prv_data *pdata)
+{
+ /*
+ * This local_phy is needed because phy-v2 alters the
+ * advertising flag variable. so phy-v1 an_advertising is just copying
+ */
+ struct xgbe_phy local_phy;
+ unsigned int reg;
+
+ pdata->phy_if.phy_impl.an_advertising(pdata, &local_phy);
+
/* Set up Advertisement register 3 first */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
- reg &= ~0xc000;
+ if (XGBE_ADV(&local_phy, 10000baseR_FEC))
+ reg |= 0xc000;
+ else
+ reg &= ~0xc000;
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg);
/* Set up Advertisement register 2 next */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
- if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
+ if (XGBE_ADV(&local_phy, 10000baseKR_Full))
reg |= 0x80;
else
reg &= ~0x80;
- if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) ||
- (pdata->phy.advertising & ADVERTISED_2500baseX_Full))
+ if (XGBE_ADV(&local_phy, 1000baseKX_Full) ||
+ XGBE_ADV(&local_phy, 2500baseX_Full))
reg |= 0x20;
else
reg &= ~0x20;
@@ -734,12 +1002,12 @@ static void xgbe_an_init(struct xgbe_prv_data *pdata)
/* Set up Advertisement register 1 last */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- if (pdata->phy.advertising & ADVERTISED_Pause)
+ if (XGBE_ADV(&local_phy, Pause))
reg |= 0x400;
else
reg &= ~0x400;
- if (pdata->phy.advertising & ADVERTISED_Asym_Pause)
+ if (XGBE_ADV(&local_phy, Asym_Pause))
reg |= 0x800;
else
reg &= ~0x800;
@@ -748,97 +1016,239 @@ static void xgbe_an_init(struct xgbe_prv_data *pdata)
reg &= ~XGBE_XNP_NP_EXCHANGE;
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
+
+ axgbe_printf(2, "CL73 AN initialized\n");
+}
+
+static void
+xgbe_an_init(struct xgbe_prv_data *pdata)
+{
+ /* Set up advertisement registers based on current settings */
+ pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata);
+ axgbe_printf(2, "%s: setting up an_mode %d\n", __func__, pdata->an_mode);
+
+ switch (pdata->an_mode) {
+ case XGBE_AN_MODE_CL73:
+ case XGBE_AN_MODE_CL73_REDRV:
+ xgbe_an73_init(pdata);
+ break;
+ case XGBE_AN_MODE_CL37:
+ case XGBE_AN_MODE_CL37_SGMII:
+ xgbe_an37_init(pdata);
+ break;
+ default:
+ break;
+ }
+}
+
+static const char *
+xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
+{
+ if (pdata->tx_pause && pdata->rx_pause)
+ return ("rx/tx");
+ else if (pdata->rx_pause)
+ return ("rx");
+ else if (pdata->tx_pause)
+ return ("tx");
+ else
+ return ("off");
+}
+
+static const char *
+xgbe_phy_speed_string(int speed)
+{
+ switch (speed) {
+ case SPEED_100:
+ return ("100Mbps");
+ case SPEED_1000:
+ return ("1Gbps");
+ case SPEED_2500:
+ return ("2.5Gbps");
+ case SPEED_10000:
+ return ("10Gbps");
+ case SPEED_UNKNOWN:
+ return ("Unknown");
+ default:
+ return ("Unsupported");
+ }
+}
+
+static void
+xgbe_phy_print_status(struct xgbe_prv_data *pdata)
+{
+ if (pdata->phy.link)
+ axgbe_printf(0,
+ "Link is UP - %s/%s - flow control %s\n",
+ xgbe_phy_speed_string(pdata->phy.speed),
+ pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half",
+ xgbe_phy_fc_string(pdata));
+ else
+ axgbe_printf(0, "Link is DOWN\n");
}
-static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)
+static void
+xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)
{
+ int new_state = 0;
+
+ axgbe_printf(1, "link %d/%d tx %d/%d rx %d/%d speed %d/%d autoneg %d/%d\n",
+ pdata->phy_link, pdata->phy.link,
+ pdata->tx_pause, pdata->phy.tx_pause,
+ pdata->rx_pause, pdata->phy.rx_pause,
+ pdata->phy_speed, pdata->phy.speed,
+ pdata->pause_autoneg, pdata->phy.pause_autoneg);
if (pdata->phy.link) {
/* Flow control support */
pdata->pause_autoneg = pdata->phy.pause_autoneg;
if (pdata->tx_pause != pdata->phy.tx_pause) {
- pdata->hw_if.config_tx_flow_control(pdata);
+ new_state = 1;
+ axgbe_printf(2, "tx pause %d/%d\n", pdata->tx_pause,
+ pdata->phy.tx_pause);
pdata->tx_pause = pdata->phy.tx_pause;
+ pdata->hw_if.config_tx_flow_control(pdata);
}
if (pdata->rx_pause != pdata->phy.rx_pause) {
- pdata->hw_if.config_rx_flow_control(pdata);
+ new_state = 1;
+ axgbe_printf(2, "rx pause %d/%d\n", pdata->rx_pause,
+ pdata->phy.rx_pause);
pdata->rx_pause = pdata->phy.rx_pause;
+ pdata->hw_if.config_rx_flow_control(pdata);
}
/* Speed support */
if (pdata->phy_speed != pdata->phy.speed) {
+ new_state = 1;
pdata->phy_speed = pdata->phy.speed;
}
if (pdata->phy_link != pdata->phy.link) {
+ new_state = 1;
pdata->phy_link = pdata->phy.link;
}
} else if (pdata->phy_link) {
+ new_state = 1;
pdata->phy_link = 0;
pdata->phy_speed = SPEED_UNKNOWN;
}
+
+ axgbe_printf(2, "phy_link %d Link %d new_state %d\n", pdata->phy_link,
+ pdata->phy.link, new_state);
+
+ if (new_state)
+ xgbe_phy_print_status(pdata);
}
-static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
+static bool
+xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
{
+ return (pdata->phy_if.phy_impl.valid_speed(pdata, speed));
+}
- /* Disable auto-negotiation */
- xgbe_disable_an(pdata);
+static int
+xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
+{
+ enum xgbe_mode mode;
- /* Validate/Set specified speed */
- switch (pdata->phy.speed) {
- case SPEED_10000:
- xgbe_set_mode(pdata, XGBE_MODE_KR);
- break;
+ axgbe_printf(2, "fixed PHY configuration\n");
- case SPEED_2500:
- case SPEED_1000:
- xgbe_set_mode(pdata, XGBE_MODE_KX);
+ /* Disable auto-negotiation */
+ xgbe_an_disable(pdata);
+
+ /* Set specified mode for specified speed */
+ mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed);
+ switch (mode) {
+ case XGBE_MODE_KX_1000:
+ case XGBE_MODE_KX_2500:
+ case XGBE_MODE_KR:
+ case XGBE_MODE_SGMII_100:
+ case XGBE_MODE_SGMII_1000:
+ case XGBE_MODE_X:
+ case XGBE_MODE_SFI:
break;
-
+ case XGBE_MODE_UNKNOWN:
default:
- return -EINVAL;
+ return (-EINVAL);
}
/* Validate duplex mode */
if (pdata->phy.duplex != DUPLEX_FULL)
- return -EINVAL;
+ return (-EINVAL);
- return 0;
+ xgbe_set_mode(pdata, mode);
+
+ return (0);
}
-static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
+static int
+__xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
{
+ int ret;
+ unsigned int reg;
+
+ sx_xlock(&pdata->an_mutex);
+
set_bit(XGBE_LINK_INIT, &pdata->dev_state);
pdata->link_check = ticks;
- if (pdata->phy.autoneg != AUTONEG_ENABLE)
- return xgbe_phy_config_fixed(pdata);
+ ret = pdata->phy_if.phy_impl.an_config(pdata);
+ if (ret) {
+ axgbe_error("%s: an_config fail %d\n", __func__, ret);
+ goto out;
+ }
+
+ if (pdata->phy.autoneg != AUTONEG_ENABLE) {
+ ret = xgbe_phy_config_fixed(pdata);
+ if (ret || !pdata->kr_redrv) {
+ if (ret)
+ axgbe_error("%s: fix conf fail %d\n", __func__, ret);
+ goto out;
+ }
+
+ axgbe_printf(2, "AN redriver support\n");
+ } else
+ axgbe_printf(2, "AN PHY configuration\n");
/* Disable auto-negotiation interrupt */
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK);
+ axgbe_printf(2, "%s: set_mode %d AN int reg value 0x%x\n", __func__,
+ set_mode, reg);
/* Clear any auto-negotitation interrupts */
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
/* Start auto-negotiation in a supported mode */
- if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) {
- xgbe_set_mode(pdata, XGBE_MODE_KR);
- } else if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) ||
- (pdata->phy.advertising & ADVERTISED_2500baseX_Full)) {
- xgbe_set_mode(pdata, XGBE_MODE_KX);
- } else {
- XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
- return -EINVAL;
+ if (set_mode) {
+ /* Start auto-negotiation in a supported mode */
+ if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
+ xgbe_set_mode(pdata, XGBE_MODE_KR);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
+ xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
+ xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
+ xgbe_set_mode(pdata, XGBE_MODE_SFI);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
+ xgbe_set_mode(pdata, XGBE_MODE_X);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
+ xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
+ xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
+ } else {
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
+ ret = -EINVAL;
+ goto out;
+ }
}
/* Disable and stop any in progress auto-negotiation */
- xgbe_disable_an(pdata);
+ xgbe_an_disable_all(pdata);
/* Clear any auto-negotitation interrupts */
- XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ xgbe_an_clear_interrupts_all(pdata);
pdata->an_result = XGBE_AN_READY;
pdata->an_state = XGBE_AN_READY;
@@ -847,300 +1257,338 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
/* Re-enable auto-negotiation interrupt */
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
+ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK);
/* Set up advertisement registers based on current settings */
xgbe_an_init(pdata);
/* Enable and start auto-negotiation */
- xgbe_restart_an(pdata);
-
- return 0;
-}
+ xgbe_an_restart(pdata);
-static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
-{
- int ret;
-
- sx_xlock(&pdata->an_mutex);
-
- ret = __xgbe_phy_config_aneg(pdata);
- if (ret)
+out:
+ if (ret) {
+ axgbe_printf(0, "%s: set_mode %d AN int reg value 0x%x ret value %d\n",
+ __func__, set_mode, reg, ret);
set_bit(XGBE_LINK_ERR, &pdata->dev_state);
- else
+ } else
clear_bit(XGBE_LINK_ERR, &pdata->dev_state);
sx_unlock(&pdata->an_mutex);
- return ret;
+ return (ret);
+}
+
+static int
+xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
+{
+ return (__xgbe_phy_config_aneg(pdata, true));
+}
+
+static int
+xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata)
+{
+ return (__xgbe_phy_config_aneg(pdata, false));
}
-static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
+static bool
+xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
{
return (pdata->an_result == XGBE_AN_COMPLETE);
}
-static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
+static void
+xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
{
unsigned long link_timeout;
link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * hz);
- if ((int)(ticks - link_timeout) >= 0) {
+ if ((int)(ticks - link_timeout) > 0) {
+ axgbe_printf(2, "AN link timeout\n");
xgbe_phy_config_aneg(pdata);
}
}
-static void xgbe_phy_status_force(struct xgbe_prv_data *pdata)
+static enum xgbe_mode
+xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
{
- if (xgbe_in_kr_mode(pdata)) {
- pdata->phy.speed = SPEED_10000;
- } else {
- switch (pdata->speed_set) {
- case XGBE_SPEEDSET_1000_10000:
- pdata->phy.speed = SPEED_1000;
- break;
-
- case XGBE_SPEEDSET_2500_10000:
- pdata->phy.speed = SPEED_2500;
- break;
- }
- }
- pdata->phy.duplex = DUPLEX_FULL;
+ return (pdata->phy_if.phy_impl.an_outcome(pdata));
}
-static void xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
+static void
+xgbe_phy_status_result(struct xgbe_prv_data *pdata)
{
- unsigned int ad_reg, lp_reg;
+ enum xgbe_mode mode;
- pdata->phy.lp_advertising = 0;
+ XGBE_ZERO_LP_ADV(&pdata->phy);
if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
- return xgbe_phy_status_force(pdata);
-
- pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
- pdata->phy.lp_advertising |= ADVERTISED_Backplane;
-
- /* Compare Advertisement and Link Partner register 1 */
- ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
- if (lp_reg & 0x400)
- pdata->phy.lp_advertising |= ADVERTISED_Pause;
- if (lp_reg & 0x800)
- pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause;
-
- if (pdata->phy.pause_autoneg) {
- /* Set flow control based on auto-negotiation result */
- pdata->phy.tx_pause = 0;
- pdata->phy.rx_pause = 0;
-
- if (ad_reg & lp_reg & 0x400) {
- pdata->phy.tx_pause = 1;
- pdata->phy.rx_pause = 1;
- } else if (ad_reg & lp_reg & 0x800) {
- if (ad_reg & 0x400)
- pdata->phy.rx_pause = 1;
- else if (lp_reg & 0x400)
- pdata->phy.tx_pause = 1;
- }
- }
-
- /* Compare Advertisement and Link Partner register 2 */
- ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
- lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
- if (lp_reg & 0x80)
- pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full;
- if (lp_reg & 0x20) {
- switch (pdata->speed_set) {
- case XGBE_SPEEDSET_1000_10000:
- pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full;
- break;
- case XGBE_SPEEDSET_2500_10000:
- pdata->phy.lp_advertising |= ADVERTISED_2500baseX_Full;
- break;
- }
- }
+ mode = xgbe_cur_mode(pdata);
+ else
+ mode = xgbe_phy_status_aneg(pdata);
- ad_reg &= lp_reg;
- if (ad_reg & 0x80) {
+ axgbe_printf(3, "%s: xgbe mode %d\n", __func__, mode);
+ switch (mode) {
+ case XGBE_MODE_SGMII_100:
+ pdata->phy.speed = SPEED_100;
+ break;
+ case XGBE_MODE_X:
+ case XGBE_MODE_KX_1000:
+ case XGBE_MODE_SGMII_1000:
+ pdata->phy.speed = SPEED_1000;
+ break;
+ case XGBE_MODE_KX_2500:
+ pdata->phy.speed = SPEED_2500;
+ break;
+ case XGBE_MODE_KR:
+ case XGBE_MODE_SFI:
pdata->phy.speed = SPEED_10000;
- xgbe_set_mode(pdata, XGBE_MODE_KR);
- } else if (ad_reg & 0x20) {
- switch (pdata->speed_set) {
- case XGBE_SPEEDSET_1000_10000:
- pdata->phy.speed = SPEED_1000;
- break;
-
- case XGBE_SPEEDSET_2500_10000:
- pdata->phy.speed = SPEED_2500;
- break;
- }
-
- xgbe_set_mode(pdata, XGBE_MODE_KX);
- } else {
+ break;
+ case XGBE_MODE_UNKNOWN:
+ default:
+ axgbe_printf(1, "%s: unknown mode\n", __func__);
pdata->phy.speed = SPEED_UNKNOWN;
}
- /* Compare Advertisement and Link Partner register 3 */
- ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
- lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
+ pdata->phy.duplex = DUPLEX_FULL;
+ axgbe_printf(2, "%s: speed %d duplex %d\n", __func__, pdata->phy.speed,
+ pdata->phy.duplex);
+
+ if (xgbe_set_mode(pdata, mode) && pdata->an_again)
+ xgbe_phy_reconfig_aneg(pdata);
}
-static void xgbe_phy_status(struct xgbe_prv_data *pdata)
+static void
+xgbe_phy_status(struct xgbe_prv_data *pdata)
{
- unsigned int reg, link_aneg;
+ bool link_aneg;
+ int an_restart;
if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
+ axgbe_error("%s: LINK_ERR\n", __func__);
pdata->phy.link = 0;
goto adjust_link;
}
link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE);
+ axgbe_printf(3, "link_aneg - %d\n", link_aneg);
/* Get the link status. Link status is latched low, so read
* once to clear and then read again to get current state
*/
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
- pdata->phy.link = (reg & MDIO_STAT1_LSTATUS) ? 1 : 0;
+ pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata,
+ &an_restart);
+
+ axgbe_printf(1, "link_status returned Link:%d an_restart:%d aneg:%d\n",
+ pdata->phy.link, an_restart, link_aneg);
+
+ if (an_restart) {
+ xgbe_phy_config_aneg(pdata);
+ return;
+ }
if (pdata->phy.link) {
+ axgbe_printf(2, "Link Active\n");
if (link_aneg && !xgbe_phy_aneg_done(pdata)) {
+ axgbe_printf(1, "phy_link set check timeout\n");
xgbe_check_link_timeout(pdata);
return;
}
- xgbe_phy_status_aneg(pdata);
+ axgbe_printf(2, "%s: Link write phy_status result\n", __func__);
+ xgbe_phy_status_result(pdata);
if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
+
} else {
+ axgbe_printf(2, "Link Deactive\n");
if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
+ axgbe_printf(1, "phy_link not set check timeout\n");
xgbe_check_link_timeout(pdata);
- if (link_aneg)
+ if (link_aneg) {
+ axgbe_printf(2, "link_aneg case\n");
return;
+ }
}
- xgbe_phy_status_aneg(pdata);
+ xgbe_phy_status_result(pdata);
+
}
adjust_link:
+ axgbe_printf(2, "%s: Link %d\n", __func__, pdata->phy.link);
xgbe_phy_adjust_link(pdata);
}
-static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
+static void
+xgbe_phy_stop(struct xgbe_prv_data *pdata)
{
+ axgbe_printf(2, "stopping PHY\n");
- /* Disable auto-negotiation */
- xgbe_disable_an(pdata);
+ if (!pdata->phy_started)
+ return;
- /* Disable auto-negotiation interrupts */
- XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
+ /* Indicate the PHY is down */
+ pdata->phy_started = 0;
+
+ /* Disable auto-negotiation */
+ xgbe_an_disable_all(pdata);
- bus_teardown_intr(pdata->dev, pdata->an_irq_res, pdata->an_irq_tag);
+ pdata->phy_if.phy_impl.stop(pdata);
pdata->phy.link = 0;
xgbe_phy_adjust_link(pdata);
}
-static int xgbe_phy_start(struct xgbe_prv_data *pdata)
+static int
+xgbe_phy_start(struct xgbe_prv_data *pdata)
{
int ret;
- ret = bus_setup_intr(pdata->dev, pdata->an_irq_res,
- INTR_MPSAFE | INTR_TYPE_NET, NULL, xgbe_an_isr, pdata,
- &pdata->an_irq_tag);
+ DBGPR("-->xgbe_phy_start\n");
+
+ ret = pdata->phy_if.phy_impl.start(pdata);
if (ret) {
- return -ret;
+ axgbe_error("%s: impl start ret %d\n", __func__, ret);
+ return (ret);
}
/* Set initial mode - call the mode setting routines
* directly to insure we are properly configured
*/
- if (xgbe_use_xgmii_mode(pdata)) {
- xgbe_xgmii_mode(pdata);
- } else if (xgbe_use_gmii_mode(pdata)) {
- xgbe_gmii_mode(pdata);
- } else if (xgbe_use_gmii_2500_mode(pdata)) {
- xgbe_gmii_2500_mode(pdata);
+ if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
+ axgbe_printf(2, "%s: KR\n", __func__);
+ xgbe_kr_mode(pdata);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
+ axgbe_printf(2, "%s: KX 2500\n", __func__);
+ xgbe_kx_2500_mode(pdata);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
+ axgbe_printf(2, "%s: KX 1000\n", __func__);
+ xgbe_kx_1000_mode(pdata);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
+ axgbe_printf(2, "%s: SFI\n", __func__);
+ xgbe_sfi_mode(pdata);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
+ axgbe_printf(2, "%s: X\n", __func__);
+ xgbe_x_mode(pdata);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
+ axgbe_printf(2, "%s: SGMII 1000\n", __func__);
+ xgbe_sgmii_1000_mode(pdata);
+ } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
+ axgbe_printf(2, "%s: SGMII 100\n", __func__);
+ xgbe_sgmii_100_mode(pdata);
} else {
+ axgbe_error("%s: invalid mode\n", __func__);
ret = -EINVAL;
- goto err_irq;
+ goto err_stop;
}
+ /* Indicate the PHY is up and running */
+ pdata->phy_started = 1;
+
/* Set up advertisement registers based on current settings */
xgbe_an_init(pdata);
/* Enable auto-negotiation interrupts */
- XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
+ xgbe_an_enable_interrupts(pdata);
- return xgbe_phy_config_aneg(pdata);
+ ret = xgbe_phy_config_aneg(pdata);
+ if (ret)
+ axgbe_error("%s: phy_config_aneg %d\n", __func__, ret);
+
+ return (ret);
-err_irq:
- bus_teardown_intr(pdata->dev, pdata->an_irq_res, pdata->an_irq_tag);
+err_stop:
+ pdata->phy_if.phy_impl.stop(pdata);
- return ret;
+ return (ret);
}
-static int xgbe_phy_reset(struct xgbe_prv_data *pdata)
+static int
+xgbe_phy_reset(struct xgbe_prv_data *pdata)
{
- unsigned int count, reg;
-
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
- reg |= MDIO_CTRL1_RESET;
- XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg);
-
- count = 50;
- do {
- DELAY(20);
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
- } while ((reg & MDIO_CTRL1_RESET) && --count);
+ int ret;
- if (reg & MDIO_CTRL1_RESET)
- return -ETIMEDOUT;
+ ret = pdata->phy_if.phy_impl.reset(pdata);
+ if (ret) {
+ axgbe_error("%s: impl phy reset %d\n", __func__, ret);
+ return (ret);
+ }
/* Disable auto-negotiation for now */
- xgbe_disable_an(pdata);
+ xgbe_an_disable_all(pdata);
/* Clear auto-negotiation interrupts */
- XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ xgbe_an_clear_interrupts_all(pdata);
- return 0;
+ return (0);
}
-static void xgbe_phy_init(struct xgbe_prv_data *pdata)
+static int
+xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
{
+
+ if (XGBE_ADV(&pdata->phy, 10000baseKR_Full))
+ return (SPEED_10000);
+ else if (XGBE_ADV(&pdata->phy, 10000baseT_Full))
+ return (SPEED_10000);
+ else if (XGBE_ADV(&pdata->phy, 2500baseX_Full))
+ return (SPEED_2500);
+ else if (XGBE_ADV(&pdata->phy, 2500baseT_Full))
+ return (SPEED_2500);
+ else if (XGBE_ADV(&pdata->phy, 1000baseKX_Full))
+ return (SPEED_1000);
+ else if (XGBE_ADV(&pdata->phy, 1000baseT_Full))
+ return (SPEED_1000);
+ else if (XGBE_ADV(&pdata->phy, 100baseT_Full))
+ return (SPEED_100);
+
+ return (SPEED_UNKNOWN);
+}
+
+static void
+xgbe_phy_exit(struct xgbe_prv_data *pdata)
+{
+ pdata->phy_if.phy_impl.exit(pdata);
+}
+
+static int
+xgbe_phy_init(struct xgbe_prv_data *pdata)
+{
+ int ret = 0;
+
+ DBGPR("-->xgbe_phy_init\n");
+
sx_init(&pdata->an_mutex, "axgbe AN lock");
pdata->mdio_mmd = MDIO_MMD_PCS;
/* Initialize supported features */
- pdata->phy.supported = SUPPORTED_Autoneg;
- pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
- pdata->phy.supported |= SUPPORTED_Backplane;
- pdata->phy.supported |= SUPPORTED_10000baseKR_Full;
- switch (pdata->speed_set) {
- case XGBE_SPEEDSET_1000_10000:
- pdata->phy.supported |= SUPPORTED_1000baseKX_Full;
- break;
- case XGBE_SPEEDSET_2500_10000:
- pdata->phy.supported |= SUPPORTED_2500baseX_Full;
- break;
- }
-
pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD,
MDIO_PMA_10GBR_FECABLE);
pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE |
MDIO_PMA_10GBR_FECABLE_ERRABLE);
- if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
- pdata->phy.supported |= SUPPORTED_10000baseR_FEC;
- pdata->phy.advertising = pdata->phy.supported;
+ /* Setup the phy (including supported features) */
+ ret = pdata->phy_if.phy_impl.init(pdata);
+ if (ret)
+ return (ret);
+
+ /* Copy supported link modes to advertising link modes */
+ XGBE_LM_COPY(&pdata->phy, advertising, &pdata->phy, supported);
pdata->phy.address = 0;
- pdata->phy.autoneg = AUTONEG_ENABLE;
- pdata->phy.speed = SPEED_UNKNOWN;
- pdata->phy.duplex = DUPLEX_UNKNOWN;
+ if (XGBE_ADV(&pdata->phy, Autoneg)) {
+ pdata->phy.autoneg = AUTONEG_ENABLE;
+ pdata->phy.speed = SPEED_UNKNOWN;
+ pdata->phy.duplex = DUPLEX_UNKNOWN;
+ } else {
+ pdata->phy.autoneg = AUTONEG_DISABLE;
+ pdata->phy.speed = xgbe_phy_best_advertised_speed(pdata);
+ pdata->phy.duplex = DUPLEX_FULL;
+ }
pdata->phy.link = 0;
@@ -1149,26 +1597,38 @@ static void xgbe_phy_init(struct xgbe_prv_data *pdata)
pdata->phy.rx_pause = pdata->rx_pause;
/* Fix up Flow Control advertising */
- pdata->phy.advertising &= ~ADVERTISED_Pause;
- pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
+ XGBE_CLR_ADV(&pdata->phy, Pause);
+ XGBE_CLR_ADV(&pdata->phy, Asym_Pause);
if (pdata->rx_pause) {
- pdata->phy.advertising |= ADVERTISED_Pause;
- pdata->phy.advertising |= ADVERTISED_Asym_Pause;
+ XGBE_SET_ADV(&pdata->phy, Pause);
+ XGBE_SET_ADV(&pdata->phy, Asym_Pause);
+ }
+
+ if (pdata->tx_pause) {
+ if (XGBE_ADV(&pdata->phy, Asym_Pause))
+ XGBE_CLR_ADV(&pdata->phy, Asym_Pause);
+ else
+ XGBE_SET_ADV(&pdata->phy, Asym_Pause);
}
- if (pdata->tx_pause)
- pdata->phy.advertising ^= ADVERTISED_Asym_Pause;
+ return (0);
}
-void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if)
+void
+xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if)
{
- phy_if->phy_init = xgbe_phy_init;
+ phy_if->phy_init = xgbe_phy_init;
+ phy_if->phy_exit = xgbe_phy_exit;
phy_if->phy_reset = xgbe_phy_reset;
phy_if->phy_start = xgbe_phy_start;
- phy_if->phy_stop = xgbe_phy_stop;
+ phy_if->phy_stop = xgbe_phy_stop;
phy_if->phy_status = xgbe_phy_status;
phy_if->phy_config_aneg = xgbe_phy_config_aneg;
+
+ phy_if->phy_valid_speed = xgbe_phy_valid_speed;
+
+ phy_if->an_isr = xgbe_an_combined_isr;
}