aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/qt202x_phy.c
diff options
context:
space:
mode:
authorMatthew Slattery <mslattery@solarflare.com>2009-12-23 08:48:04 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-23 22:09:06 -0500
commit0d83b2f64c330ee3892cb3117ac5d56e97185ecf (patch)
tree40d511c2dd7d565330771a82165b6a26dfb8928c /drivers/net/sfc/qt202x_phy.c
parent17d6aeafe9d8268612d91edc0102659edb382282 (diff)
sfc: QT2025C: Switch into self-configure mode when not in loopback
The PHY boots in a mode which is not necessarily optimal. This change switches it to self-configure mode (except when in loopback, which won't work in that mode if an SFP+ module is not present) by rebooting the PHY's microcontroller, and replicating the sequence of configuration writes from the boot EEPROM with the appropriate changes. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc/qt202x_phy.c')
-rw-r--r--drivers/net/sfc/qt202x_phy.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index e4590fb528a1..0cd6eed02069 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -33,6 +33,9 @@
33#define PCS_FW_HEARTBEAT_REG 0xd7ee 33#define PCS_FW_HEARTBEAT_REG 0xd7ee
34#define PCS_FW_HEARTB_LBN 0 34#define PCS_FW_HEARTB_LBN 0
35#define PCS_FW_HEARTB_WIDTH 8 35#define PCS_FW_HEARTB_WIDTH 8
36#define PCS_FW_PRODUCT_CODE_1 0xd7f0
37#define PCS_FW_VERSION_1 0xd7f3
38#define PCS_FW_BUILD_1 0xd7f6
36#define PCS_UC8051_STATUS_REG 0xd7fd 39#define PCS_UC8051_STATUS_REG 0xd7fd
37#define PCS_UC_STATUS_LBN 0 40#define PCS_UC_STATUS_LBN 0
38#define PCS_UC_STATUS_WIDTH 8 41#define PCS_UC_STATUS_WIDTH 8
@@ -54,6 +57,7 @@ struct qt202x_phy_data {
54 enum efx_phy_mode phy_mode; 57 enum efx_phy_mode phy_mode;
55 bool bug17190_in_bad_state; 58 bool bug17190_in_bad_state;
56 unsigned long bug17190_timer; 59 unsigned long bug17190_timer;
60 u32 firmware_ver;
57}; 61};
58 62
59#define QT2022C2_MAX_RESET_TIME 500 63#define QT2022C2_MAX_RESET_TIME 500
@@ -100,6 +104,25 @@ static int qt2025c_wait_reset(struct efx_nic *efx)
100 return 0; 104 return 0;
101} 105}
102 106
107static void qt2025c_firmware_id(struct efx_nic *efx)
108{
109 struct qt202x_phy_data *phy_data = efx->phy_data;
110 u8 firmware_id[9];
111 size_t i;
112
113 for (i = 0; i < sizeof(firmware_id); i++)
114 firmware_id[i] = efx_mdio_read(efx, MDIO_MMD_PCS,
115 PCS_FW_PRODUCT_CODE_1 + i);
116 EFX_INFO(efx, "QT2025C firmware %xr%d v%d.%d.%d.%d [20%02d-%02d-%02d]\n",
117 (firmware_id[0] << 8) | firmware_id[1], firmware_id[2],
118 firmware_id[3] >> 4, firmware_id[3] & 0xf,
119 firmware_id[4], firmware_id[5],
120 firmware_id[6], firmware_id[7], firmware_id[8]);
121 phy_data->firmware_ver = ((firmware_id[3] & 0xf0) << 20) |
122 ((firmware_id[3] & 0x0f) << 16) |
123 (firmware_id[4] << 8) | firmware_id[5];
124}
125
103static void qt2025c_bug17190_workaround(struct efx_nic *efx) 126static void qt2025c_bug17190_workaround(struct efx_nic *efx)
104{ 127{
105 struct qt202x_phy_data *phy_data = efx->phy_data; 128 struct qt202x_phy_data *phy_data = efx->phy_data;
@@ -133,6 +156,95 @@ static void qt2025c_bug17190_workaround(struct efx_nic *efx)
133 } 156 }
134} 157}
135 158
159static int qt2025c_select_phy_mode(struct efx_nic *efx)
160{
161 struct qt202x_phy_data *phy_data = efx->phy_data;
162 struct falcon_board *board = falcon_board(efx);
163 int reg, rc, i;
164 uint16_t phy_op_mode;
165
166 /* Only 2.0.1.0+ PHY firmware supports the more optimal SFP+
167 * Self-Configure mode. Don't attempt any switching if we encounter
168 * older firmware. */
169 if (phy_data->firmware_ver < 0x02000100)
170 return 0;
171
172 /* In general we will get optimal behaviour in "SFP+ Self-Configure"
173 * mode; however, that powers down most of the PHY when no module is
174 * present, so we must use a different mode (any fixed mode will do)
175 * to be sure that loopbacks will work. */
176 phy_op_mode = (efx->loopback_mode == LOOPBACK_NONE) ? 0x0038 : 0x0020;
177
178 /* Only change mode if really necessary */
179 reg = efx_mdio_read(efx, 1, 0xc319);
180 if ((reg & 0x0038) == phy_op_mode)
181 return 0;
182 EFX_LOG(efx, "Switching PHY to mode 0x%04x\n", phy_op_mode);
183
184 /* This sequence replicates the register writes configured in the boot
185 * EEPROM (including the differences between board revisions), except
186 * that the operating mode is changed, and the PHY is prevented from
187 * unnecessarily reloading the main firmware image again. */
188 efx_mdio_write(efx, 1, 0xc300, 0x0000);
189 /* (Note: this portion of the boot EEPROM sequence, which bit-bashes 9
190 * STOPs onto the firmware/module I2C bus to reset it, varies across
191 * board revisions, as the bus is connected to different GPIO/LED
192 * outputs on the PHY.) */
193 if (board->major == 0 && board->minor < 2) {
194 efx_mdio_write(efx, 1, 0xc303, 0x4498);
195 for (i = 0; i < 9; i++) {
196 efx_mdio_write(efx, 1, 0xc303, 0x4488);
197 efx_mdio_write(efx, 1, 0xc303, 0x4480);
198 efx_mdio_write(efx, 1, 0xc303, 0x4490);
199 efx_mdio_write(efx, 1, 0xc303, 0x4498);
200 }
201 } else {
202 efx_mdio_write(efx, 1, 0xc303, 0x0920);
203 efx_mdio_write(efx, 1, 0xd008, 0x0004);
204 for (i = 0; i < 9; i++) {
205 efx_mdio_write(efx, 1, 0xc303, 0x0900);
206 efx_mdio_write(efx, 1, 0xd008, 0x0005);
207 efx_mdio_write(efx, 1, 0xc303, 0x0920);
208 efx_mdio_write(efx, 1, 0xd008, 0x0004);
209 }
210 efx_mdio_write(efx, 1, 0xc303, 0x4900);
211 }
212 efx_mdio_write(efx, 1, 0xc303, 0x4900);
213 efx_mdio_write(efx, 1, 0xc302, 0x0004);
214 efx_mdio_write(efx, 1, 0xc316, 0x0013);
215 efx_mdio_write(efx, 1, 0xc318, 0x0054);
216 efx_mdio_write(efx, 1, 0xc319, phy_op_mode);
217 efx_mdio_write(efx, 1, 0xc31a, 0x0098);
218 efx_mdio_write(efx, 3, 0x0026, 0x0e00);
219 efx_mdio_write(efx, 3, 0x0027, 0x0013);
220 efx_mdio_write(efx, 3, 0x0028, 0xa528);
221 efx_mdio_write(efx, 1, 0xd006, 0x000a);
222 efx_mdio_write(efx, 1, 0xd007, 0x0009);
223 efx_mdio_write(efx, 1, 0xd008, 0x0004);
224 /* This additional write is not present in the boot EEPROM. It
225 * prevents the PHY's internal boot ROM doing another pointless (and
226 * slow) reload of the firmware image (the microcontroller's code
227 * memory is not affected by the microcontroller reset). */
228 efx_mdio_write(efx, 1, 0xc317, 0x00ff);
229 efx_mdio_write(efx, 1, 0xc300, 0x0002);
230 msleep(20);
231
232 /* Restart microcontroller execution from RAM */
233 efx_mdio_write(efx, 3, 0xe854, 0x00c0);
234 efx_mdio_write(efx, 3, 0xe854, 0x0040);
235 msleep(50);
236
237 /* Wait for the microcontroller to be ready again */
238 rc = qt2025c_wait_reset(efx);
239 if (rc < 0) {
240 EFX_ERR(efx, "PHY microcontroller reset during mode switch "
241 "timed out\n");
242 return rc;
243 }
244
245 return 0;
246}
247
136static int qt202x_reset_phy(struct efx_nic *efx) 248static int qt202x_reset_phy(struct efx_nic *efx)
137{ 249{
138 int rc; 250 int rc;
@@ -206,6 +318,9 @@ static int qt202x_phy_init(struct efx_nic *efx)
206 devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), 318 devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid),
207 efx_mdio_id_rev(devid)); 319 efx_mdio_id_rev(devid));
208 320
321 if (efx->phy_type == PHY_TYPE_QT2025C)
322 qt2025c_firmware_id(efx);
323
209 return 0; 324 return 0;
210} 325}
211 326
@@ -234,6 +349,10 @@ static int qt202x_phy_reconfigure(struct efx_nic *efx)
234 struct qt202x_phy_data *phy_data = efx->phy_data; 349 struct qt202x_phy_data *phy_data = efx->phy_data;
235 350
236 if (efx->phy_type == PHY_TYPE_QT2025C) { 351 if (efx->phy_type == PHY_TYPE_QT2025C) {
352 int rc = qt2025c_select_phy_mode(efx);
353 if (rc)
354 return rc;
355
237 /* There are several different register bits which can 356 /* There are several different register bits which can
238 * disable TX (and save power) on direct-attach cables 357 * disable TX (and save power) on direct-attach cables
239 * or optical transceivers, varying somewhat between 358 * or optical transceivers, varying somewhat between