Commit d2d2c373 authored by Ben Hutchings's avatar Ben Hutchings Committed by David S. Miller

sfc: Add support for QT2025C PHY

This is a new PHY supporting SFP+ modules, used in the SFN4112F
reference design.  It is similar to the QT2022C2 and shares much of
its support code.
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3f39a5e9
...@@ -2249,6 +2249,7 @@ static int falcon_probe_phy(struct efx_nic *efx) ...@@ -2249,6 +2249,7 @@ static int falcon_probe_phy(struct efx_nic *efx)
efx->phy_op = &falcon_sft9001_phy_ops; efx->phy_op = &falcon_sft9001_phy_ops;
break; break;
case PHY_TYPE_QT2022C2: case PHY_TYPE_QT2022C2:
case PHY_TYPE_QT2025C:
efx->phy_op = &falcon_xfp_phy_ops; efx->phy_op = &falcon_xfp_phy_ops;
break; break;
default: default:
......
...@@ -450,6 +450,7 @@ enum phy_type { ...@@ -450,6 +450,7 @@ enum phy_type {
PHY_TYPE_QT2022C2 = 4, PHY_TYPE_QT2022C2 = 4,
PHY_TYPE_PM8358 = 6, PHY_TYPE_PM8358 = 6,
PHY_TYPE_SFT9001A = 8, PHY_TYPE_SFT9001A = 8,
PHY_TYPE_QT2025C = 9,
PHY_TYPE_SFT9001B = 10, PHY_TYPE_SFT9001B = 10,
PHY_TYPE_MAX /* Insert any new items before this */ PHY_TYPE_MAX /* Insert any new items before this */
}; };
......
...@@ -23,11 +23,11 @@ extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); ...@@ -23,11 +23,11 @@ extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink);
extern int sft9001_wait_boot(struct efx_nic *efx); extern int sft9001_wait_boot(struct efx_nic *efx);
/**************************************************************************** /****************************************************************************
* Exported functions from the driver for XFP optical PHYs * AMCC/Quake QT20xx PHYs
*/ */
extern struct efx_phy_operations falcon_xfp_phy_ops; extern struct efx_phy_operations falcon_xfp_phy_ops;
/* The QUAKE XFP PHY provides various H/W control states for LEDs */ /* These PHYs provide various H/W control states for LEDs */
#define QUAKE_LED_LINK_INVAL (0) #define QUAKE_LED_LINK_INVAL (0)
#define QUAKE_LED_LINK_STAT (1) #define QUAKE_LED_LINK_STAT (1)
#define QUAKE_LED_LINK_ACT (2) #define QUAKE_LED_LINK_ACT (2)
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
* by the Free Software Foundation, incorporated herein by reference. * by the Free Software Foundation, incorporated herein by reference.
*/ */
/* /*
* Driver for XFP optical PHYs (plus some support specific to the Quake 2022/32) * Driver for SFP+ and XFP optical PHYs plus some support specific to the
* See www.amcc.com for details (search for qt2032) * AMCC QT20xx adapters; see www.amcc.com for details
*/ */
#include <linux/timer.h> #include <linux/timer.h>
...@@ -31,6 +31,21 @@ ...@@ -31,6 +31,21 @@
/* Quake-specific MDIO registers */ /* Quake-specific MDIO registers */
#define MDIO_QUAKE_LED0_REG (0xD006) #define MDIO_QUAKE_LED0_REG (0xD006)
/* QT2025C only */
#define PCS_FW_HEARTBEAT_REG 0xd7ee
#define PCS_FW_HEARTB_LBN 0
#define PCS_FW_HEARTB_WIDTH 8
#define PCS_UC8051_STATUS_REG 0xd7fd
#define PCS_UC_STATUS_LBN 0
#define PCS_UC_STATUS_WIDTH 8
#define PCS_UC_STATUS_FW_SAVE 0x20
#define PMA_PMD_FTX_CTRL2_REG 0xc309
#define PMA_PMD_FTX_STATIC_LBN 13
#define PMA_PMD_VEND1_REG 0xc001
#define PMA_PMD_VEND1_LBTXD_LBN 15
#define PCS_VEND1_REG 0xc000
#define PCS_VEND1_LBTXD_LBN 5
void xfp_set_led(struct efx_nic *p, int led, int mode) void xfp_set_led(struct efx_nic *p, int led, int mode)
{ {
int addr = MDIO_QUAKE_LED0_REG + led; int addr = MDIO_QUAKE_LED0_REG + led;
...@@ -45,7 +60,49 @@ struct xfp_phy_data { ...@@ -45,7 +60,49 @@ struct xfp_phy_data {
#define XFP_MAX_RESET_TIME 500 #define XFP_MAX_RESET_TIME 500
#define XFP_RESET_WAIT 10 #define XFP_RESET_WAIT 10
/* Reset the PHYXS MMD. This is documented (for the Quake PHY) as doing static int qt2025c_wait_reset(struct efx_nic *efx)
{
unsigned long timeout = jiffies + 10 * HZ;
int phy_id = efx->mii.phy_id;
int reg, old_counter = 0;
/* Wait for firmware heartbeat to start */
for (;;) {
int counter;
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
PCS_FW_HEARTBEAT_REG);
if (reg < 0)
return reg;
counter = ((reg >> PCS_FW_HEARTB_LBN) &
((1 << PCS_FW_HEARTB_WIDTH) - 1));
if (old_counter == 0)
old_counter = counter;
else if (counter != old_counter)
break;
if (time_after(jiffies, timeout))
return -ETIMEDOUT;
msleep(10);
}
/* Wait for firmware status to look good */
for (;;) {
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
PCS_UC8051_STATUS_REG);
if (reg < 0)
return reg;
if ((reg &
((1 << PCS_UC_STATUS_WIDTH) - 1) << PCS_UC_STATUS_LBN) >=
PCS_UC_STATUS_FW_SAVE)
break;
if (time_after(jiffies, timeout))
return -ETIMEDOUT;
msleep(100);
}
return 0;
}
/* Reset the PHYXS MMD. This is documented (for the Quake PHYs) as doing
* a complete soft reset. * a complete soft reset.
*/ */
static int xfp_reset_phy(struct efx_nic *efx) static int xfp_reset_phy(struct efx_nic *efx)
...@@ -58,6 +115,12 @@ static int xfp_reset_phy(struct efx_nic *efx) ...@@ -58,6 +115,12 @@ static int xfp_reset_phy(struct efx_nic *efx)
if (rc < 0) if (rc < 0)
goto fail; goto fail;
if (efx->phy_type == PHY_TYPE_QT2025C) {
rc = qt2025c_wait_reset(efx);
if (rc < 0)
goto fail;
}
/* Wait 250ms for the PHY to complete bootup */ /* Wait 250ms for the PHY to complete bootup */
msleep(250); msleep(250);
...@@ -131,12 +194,28 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) ...@@ -131,12 +194,28 @@ static void xfp_phy_reconfigure(struct efx_nic *efx)
{ {
struct xfp_phy_data *phy_data = efx->phy_data; struct xfp_phy_data *phy_data = efx->phy_data;
if (efx->phy_type == PHY_TYPE_QT2025C) {
/* There are several different register bits which can
* disable TX (and save power) on direct-attach cables
* or optical transceivers, varying somewhat between
* firmware versions. Only 'static mode' appears to
* cover everything. */
mdio_clause45_set_flag(
efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
PMA_PMD_FTX_CTRL2_REG, PMA_PMD_FTX_STATIC_LBN,
efx->phy_mode & PHY_MODE_TX_DISABLED ||
efx->phy_mode & PHY_MODE_LOW_POWER ||
efx->loopback_mode == LOOPBACK_PCS ||
efx->loopback_mode == LOOPBACK_PMAPMD);
} else {
/* Reset the PHY when moving from tx off to tx on */ /* Reset the PHY when moving from tx off to tx on */
if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) && if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) &&
(phy_data->phy_mode & PHY_MODE_TX_DISABLED)) (phy_data->phy_mode & PHY_MODE_TX_DISABLED))
xfp_reset_phy(efx); xfp_reset_phy(efx);
mdio_clause45_transmit_disable(efx); mdio_clause45_transmit_disable(efx);
}
mdio_clause45_phy_reconfigure(efx); mdio_clause45_phy_reconfigure(efx);
phy_data->phy_mode = efx->phy_mode; phy_data->phy_mode = efx->phy_mode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment