diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-02-27 08:07:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-02 06:15:04 -0500 |
commit | d2d2c3731474614bff5cf47a605e59e847882f5d (patch) | |
tree | cc4f544fef07c9e5754327b4721e4f49c698197b | |
parent | 3f39a5e9bff000025c2679101b4f83e4fc21dbba (diff) |
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: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/sfc/falcon.c | 1 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 1 | ||||
-rw-r--r-- | drivers/net/sfc/phy.h | 4 | ||||
-rw-r--r-- | drivers/net/sfc/xfp_phy.c | 95 |
4 files changed, 91 insertions, 10 deletions
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d5378e60fcdd..9e2f0f0d47a8 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c | |||
@@ -2249,6 +2249,7 @@ static int falcon_probe_phy(struct efx_nic *efx) | |||
2249 | efx->phy_op = &falcon_sft9001_phy_ops; | 2249 | efx->phy_op = &falcon_sft9001_phy_ops; |
2250 | break; | 2250 | break; |
2251 | case PHY_TYPE_QT2022C2: | 2251 | case PHY_TYPE_QT2022C2: |
2252 | case PHY_TYPE_QT2025C: | ||
2252 | efx->phy_op = &falcon_xfp_phy_ops; | 2253 | efx->phy_op = &falcon_xfp_phy_ops; |
2253 | break; | 2254 | break; |
2254 | default: | 2255 | default: |
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 19930ff9df7b..eb768fcb3cc8 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -450,6 +450,7 @@ enum phy_type { | |||
450 | PHY_TYPE_QT2022C2 = 4, | 450 | PHY_TYPE_QT2022C2 = 4, |
451 | PHY_TYPE_PM8358 = 6, | 451 | PHY_TYPE_PM8358 = 6, |
452 | PHY_TYPE_SFT9001A = 8, | 452 | PHY_TYPE_SFT9001A = 8, |
453 | PHY_TYPE_QT2025C = 9, | ||
453 | PHY_TYPE_SFT9001B = 10, | 454 | PHY_TYPE_SFT9001B = 10, |
454 | PHY_TYPE_MAX /* Insert any new items before this */ | 455 | PHY_TYPE_MAX /* Insert any new items before this */ |
455 | }; | 456 | }; |
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index f6e47227d245..c1cff9c0c173 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h | |||
@@ -23,11 +23,11 @@ extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); | |||
23 | extern int sft9001_wait_boot(struct efx_nic *efx); | 23 | extern int sft9001_wait_boot(struct efx_nic *efx); |
24 | 24 | ||
25 | /**************************************************************************** | 25 | /**************************************************************************** |
26 | * Exported functions from the driver for XFP optical PHYs | 26 | * AMCC/Quake QT20xx PHYs |
27 | */ | 27 | */ |
28 | extern struct efx_phy_operations falcon_xfp_phy_ops; | 28 | extern struct efx_phy_operations falcon_xfp_phy_ops; |
29 | 29 | ||
30 | /* The QUAKE XFP PHY provides various H/W control states for LEDs */ | 30 | /* These PHYs provide various H/W control states for LEDs */ |
31 | #define QUAKE_LED_LINK_INVAL (0) | 31 | #define QUAKE_LED_LINK_INVAL (0) |
32 | #define QUAKE_LED_LINK_STAT (1) | 32 | #define QUAKE_LED_LINK_STAT (1) |
33 | #define QUAKE_LED_LINK_ACT (2) | 33 | #define QUAKE_LED_LINK_ACT (2) |
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index 2df467d28064..bb1ef77d5f56 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c | |||
@@ -7,8 +7,8 @@ | |||
7 | * by the Free Software Foundation, incorporated herein by reference. | 7 | * by the Free Software Foundation, incorporated herein by reference. |
8 | */ | 8 | */ |
9 | /* | 9 | /* |
10 | * Driver for XFP optical PHYs (plus some support specific to the Quake 2022/32) | 10 | * Driver for SFP+ and XFP optical PHYs plus some support specific to the |
11 | * See www.amcc.com for details (search for qt2032) | 11 | * AMCC QT20xx adapters; see www.amcc.com for details |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/timer.h> | 14 | #include <linux/timer.h> |
@@ -31,6 +31,21 @@ | |||
31 | /* Quake-specific MDIO registers */ | 31 | /* Quake-specific MDIO registers */ |
32 | #define MDIO_QUAKE_LED0_REG (0xD006) | 32 | #define MDIO_QUAKE_LED0_REG (0xD006) |
33 | 33 | ||
34 | /* QT2025C only */ | ||
35 | #define PCS_FW_HEARTBEAT_REG 0xd7ee | ||
36 | #define PCS_FW_HEARTB_LBN 0 | ||
37 | #define PCS_FW_HEARTB_WIDTH 8 | ||
38 | #define PCS_UC8051_STATUS_REG 0xd7fd | ||
39 | #define PCS_UC_STATUS_LBN 0 | ||
40 | #define PCS_UC_STATUS_WIDTH 8 | ||
41 | #define PCS_UC_STATUS_FW_SAVE 0x20 | ||
42 | #define PMA_PMD_FTX_CTRL2_REG 0xc309 | ||
43 | #define PMA_PMD_FTX_STATIC_LBN 13 | ||
44 | #define PMA_PMD_VEND1_REG 0xc001 | ||
45 | #define PMA_PMD_VEND1_LBTXD_LBN 15 | ||
46 | #define PCS_VEND1_REG 0xc000 | ||
47 | #define PCS_VEND1_LBTXD_LBN 5 | ||
48 | |||
34 | void xfp_set_led(struct efx_nic *p, int led, int mode) | 49 | void xfp_set_led(struct efx_nic *p, int led, int mode) |
35 | { | 50 | { |
36 | int addr = MDIO_QUAKE_LED0_REG + led; | 51 | int addr = MDIO_QUAKE_LED0_REG + led; |
@@ -45,7 +60,49 @@ struct xfp_phy_data { | |||
45 | #define XFP_MAX_RESET_TIME 500 | 60 | #define XFP_MAX_RESET_TIME 500 |
46 | #define XFP_RESET_WAIT 10 | 61 | #define XFP_RESET_WAIT 10 |
47 | 62 | ||
48 | /* Reset the PHYXS MMD. This is documented (for the Quake PHY) as doing | 63 | static int qt2025c_wait_reset(struct efx_nic *efx) |
64 | { | ||
65 | unsigned long timeout = jiffies + 10 * HZ; | ||
66 | int phy_id = efx->mii.phy_id; | ||
67 | int reg, old_counter = 0; | ||
68 | |||
69 | /* Wait for firmware heartbeat to start */ | ||
70 | for (;;) { | ||
71 | int counter; | ||
72 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, | ||
73 | PCS_FW_HEARTBEAT_REG); | ||
74 | if (reg < 0) | ||
75 | return reg; | ||
76 | counter = ((reg >> PCS_FW_HEARTB_LBN) & | ||
77 | ((1 << PCS_FW_HEARTB_WIDTH) - 1)); | ||
78 | if (old_counter == 0) | ||
79 | old_counter = counter; | ||
80 | else if (counter != old_counter) | ||
81 | break; | ||
82 | if (time_after(jiffies, timeout)) | ||
83 | return -ETIMEDOUT; | ||
84 | msleep(10); | ||
85 | } | ||
86 | |||
87 | /* Wait for firmware status to look good */ | ||
88 | for (;;) { | ||
89 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, | ||
90 | PCS_UC8051_STATUS_REG); | ||
91 | if (reg < 0) | ||
92 | return reg; | ||
93 | if ((reg & | ||
94 | ((1 << PCS_UC_STATUS_WIDTH) - 1) << PCS_UC_STATUS_LBN) >= | ||
95 | PCS_UC_STATUS_FW_SAVE) | ||
96 | break; | ||
97 | if (time_after(jiffies, timeout)) | ||
98 | return -ETIMEDOUT; | ||
99 | msleep(100); | ||
100 | } | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | /* Reset the PHYXS MMD. This is documented (for the Quake PHYs) as doing | ||
49 | * a complete soft reset. | 106 | * a complete soft reset. |
50 | */ | 107 | */ |
51 | static int xfp_reset_phy(struct efx_nic *efx) | 108 | static int xfp_reset_phy(struct efx_nic *efx) |
@@ -58,6 +115,12 @@ static int xfp_reset_phy(struct efx_nic *efx) | |||
58 | if (rc < 0) | 115 | if (rc < 0) |
59 | goto fail; | 116 | goto fail; |
60 | 117 | ||
118 | if (efx->phy_type == PHY_TYPE_QT2025C) { | ||
119 | rc = qt2025c_wait_reset(efx); | ||
120 | if (rc < 0) | ||
121 | goto fail; | ||
122 | } | ||
123 | |||
61 | /* Wait 250ms for the PHY to complete bootup */ | 124 | /* Wait 250ms for the PHY to complete bootup */ |
62 | msleep(250); | 125 | msleep(250); |
63 | 126 | ||
@@ -131,12 +194,28 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) | |||
131 | { | 194 | { |
132 | struct xfp_phy_data *phy_data = efx->phy_data; | 195 | struct xfp_phy_data *phy_data = efx->phy_data; |
133 | 196 | ||
134 | /* Reset the PHY when moving from tx off to tx on */ | 197 | if (efx->phy_type == PHY_TYPE_QT2025C) { |
135 | if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) && | 198 | /* There are several different register bits which can |
136 | (phy_data->phy_mode & PHY_MODE_TX_DISABLED)) | 199 | * disable TX (and save power) on direct-attach cables |
137 | xfp_reset_phy(efx); | 200 | * or optical transceivers, varying somewhat between |
201 | * firmware versions. Only 'static mode' appears to | ||
202 | * cover everything. */ | ||
203 | mdio_clause45_set_flag( | ||
204 | efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, | ||
205 | PMA_PMD_FTX_CTRL2_REG, PMA_PMD_FTX_STATIC_LBN, | ||
206 | efx->phy_mode & PHY_MODE_TX_DISABLED || | ||
207 | efx->phy_mode & PHY_MODE_LOW_POWER || | ||
208 | efx->loopback_mode == LOOPBACK_PCS || | ||
209 | efx->loopback_mode == LOOPBACK_PMAPMD); | ||
210 | } else { | ||
211 | /* Reset the PHY when moving from tx off to tx on */ | ||
212 | if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) && | ||
213 | (phy_data->phy_mode & PHY_MODE_TX_DISABLED)) | ||
214 | xfp_reset_phy(efx); | ||
215 | |||
216 | mdio_clause45_transmit_disable(efx); | ||
217 | } | ||
138 | 218 | ||
139 | mdio_clause45_transmit_disable(efx); | ||
140 | mdio_clause45_phy_reconfigure(efx); | 219 | mdio_clause45_phy_reconfigure(efx); |
141 | 220 | ||
142 | phy_data->phy_mode = efx->phy_mode; | 221 | phy_data->phy_mode = efx->phy_mode; |