]>
Commit | Line | Data |
---|---|---|
8ceee660 BH |
1 | /**************************************************************************** |
2 | * Driver for Solarflare Solarstorm network controllers and boards | |
6f158d5f | 3 | * Copyright 2007-2008 Solarflare Communications Inc. |
8ceee660 BH |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License version 2 as published | |
7 | * by the Free Software Foundation, incorporated herein by reference. | |
8 | */ | |
9 | ||
10 | /***************************************************************************** | |
6f158d5f BH |
11 | * Support for the SFE4001 and SFN4111T NICs. |
12 | * | |
13 | * The SFE4001 does not power-up fully at reset due to its high power | |
14 | * consumption. We control its power via a PCA9539 I/O expander. | |
15 | * Both boards have a MAX6647 temperature monitor which we expose to | |
16 | * the lm90 driver. | |
17 | * | |
18 | * This also provides minimal support for reflashing the PHY, which is | |
19 | * initiated by resetting it with the FLASH_CFG_1 pin pulled down. | |
20 | * On SFE4001 rev A2 and later this is connected to the 3V3X output of | |
21 | * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3. | |
22 | * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually | |
23 | * exclusive with the network device being open. | |
8ceee660 | 24 | */ |
6f158d5f | 25 | |
8ceee660 | 26 | #include <linux/delay.h> |
da3bc071 | 27 | #include <linux/rtnetlink.h> |
f8b87c17 | 28 | #include "net_driver.h" |
8ceee660 BH |
29 | #include "efx.h" |
30 | #include "phy.h" | |
31 | #include "boards.h" | |
32 | #include "falcon.h" | |
33 | #include "falcon_hwdefs.h" | |
c1e5fcc9 | 34 | #include "falcon_io.h" |
8ceee660 | 35 | #include "mac.h" |
3e133c44 | 36 | #include "workarounds.h" |
8ceee660 BH |
37 | |
38 | /************************************************************************** | |
39 | * | |
40 | * I2C IO Expander device | |
41 | * | |
42 | **************************************************************************/ | |
43 | #define PCA9539 0x74 | |
44 | ||
45 | #define P0_IN 0x00 | |
46 | #define P0_OUT 0x02 | |
47 | #define P0_INVERT 0x04 | |
48 | #define P0_CONFIG 0x06 | |
49 | ||
50 | #define P0_EN_1V0X_LBN 0 | |
51 | #define P0_EN_1V0X_WIDTH 1 | |
52 | #define P0_EN_1V2_LBN 1 | |
53 | #define P0_EN_1V2_WIDTH 1 | |
54 | #define P0_EN_2V5_LBN 2 | |
55 | #define P0_EN_2V5_WIDTH 1 | |
56 | #define P0_EN_3V3X_LBN 3 | |
57 | #define P0_EN_3V3X_WIDTH 1 | |
58 | #define P0_EN_5V_LBN 4 | |
59 | #define P0_EN_5V_WIDTH 1 | |
60 | #define P0_SHORTEN_JTAG_LBN 5 | |
61 | #define P0_SHORTEN_JTAG_WIDTH 1 | |
62 | #define P0_X_TRST_LBN 6 | |
63 | #define P0_X_TRST_WIDTH 1 | |
64 | #define P0_DSP_RESET_LBN 7 | |
65 | #define P0_DSP_RESET_WIDTH 1 | |
66 | ||
67 | #define P1_IN 0x01 | |
68 | #define P1_OUT 0x03 | |
69 | #define P1_INVERT 0x05 | |
70 | #define P1_CONFIG 0x07 | |
71 | ||
72 | #define P1_AFE_PWD_LBN 0 | |
73 | #define P1_AFE_PWD_WIDTH 1 | |
74 | #define P1_DSP_PWD25_LBN 1 | |
75 | #define P1_DSP_PWD25_WIDTH 1 | |
76 | #define P1_RESERVED_LBN 2 | |
77 | #define P1_RESERVED_WIDTH 2 | |
78 | #define P1_SPARE_LBN 4 | |
79 | #define P1_SPARE_WIDTH 4 | |
80 | ||
3e133c44 BH |
81 | /* Temperature Sensor */ |
82 | #define MAX664X_REG_RSL 0x02 | |
83 | #define MAX664X_REG_WLHO 0x0B | |
8ceee660 | 84 | |
37b5a603 | 85 | static void sfe4001_poweroff(struct efx_nic *efx) |
8ceee660 | 86 | { |
37b5a603 BH |
87 | struct i2c_client *ioexp_client = efx->board_info.ioexp_client; |
88 | struct i2c_client *hwmon_client = efx->board_info.hwmon_client; | |
8ceee660 | 89 | |
37b5a603 BH |
90 | /* Turn off all power rails and disable outputs */ |
91 | i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); | |
92 | i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff); | |
93 | i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); | |
8ceee660 | 94 | |
37b5a603 | 95 | /* Clear any over-temperature alert */ |
3e133c44 | 96 | i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); |
37b5a603 | 97 | } |
8ceee660 | 98 | |
f8b87c17 | 99 | static int sfe4001_poweron(struct efx_nic *efx) |
37b5a603 | 100 | { |
f8b87c17 BH |
101 | struct i2c_client *hwmon_client = efx->board_info.hwmon_client; |
102 | struct i2c_client *ioexp_client = efx->board_info.ioexp_client; | |
11f34e69 | 103 | unsigned int i, j; |
8ceee660 | 104 | int rc; |
37b5a603 | 105 | u8 out; |
8ceee660 | 106 | |
8ceee660 | 107 | /* Clear any previous over-temperature alert */ |
3e133c44 | 108 | rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); |
37b5a603 | 109 | if (rc < 0) |
f8b87c17 | 110 | return rc; |
8ceee660 BH |
111 | |
112 | /* Enable port 0 and port 1 outputs on IO expander */ | |
37b5a603 | 113 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); |
8ceee660 | 114 | if (rc) |
f8b87c17 | 115 | return rc; |
37b5a603 BH |
116 | rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, |
117 | 0xff & ~(1 << P1_SPARE_LBN)); | |
8ceee660 | 118 | if (rc) |
37b5a603 | 119 | goto fail_on; |
8ceee660 | 120 | |
11f34e69 BH |
121 | /* If PHY power is on, turn it all off and wait 1 second to |
122 | * ensure a full reset. | |
123 | */ | |
124 | rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT); | |
125 | if (rc < 0) | |
126 | goto fail_on; | |
8ceee660 BH |
127 | out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | |
128 | (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | | |
129 | (0 << P0_EN_1V0X_LBN)); | |
11f34e69 BH |
130 | if (rc != out) { |
131 | EFX_INFO(efx, "power-cycling PHY\n"); | |
132 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); | |
133 | if (rc) | |
134 | goto fail_on; | |
135 | schedule_timeout_uninterruptible(HZ); | |
136 | } | |
8ceee660 | 137 | |
11f34e69 | 138 | for (i = 0; i < 20; ++i) { |
8ceee660 BH |
139 | /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ |
140 | out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | | |
141 | (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | | |
142 | (1 << P0_X_TRST_LBN)); | |
f8b87c17 | 143 | if (efx->phy_mode & PHY_MODE_SPECIAL) |
75f2d3ea | 144 | out |= 1 << P0_EN_3V3X_LBN; |
8ceee660 | 145 | |
37b5a603 | 146 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); |
8ceee660 | 147 | if (rc) |
37b5a603 | 148 | goto fail_on; |
8ceee660 BH |
149 | msleep(10); |
150 | ||
151 | /* Turn on 1V power rail */ | |
152 | out &= ~(1 << P0_EN_1V0X_LBN); | |
37b5a603 | 153 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); |
8ceee660 | 154 | if (rc) |
37b5a603 | 155 | goto fail_on; |
8ceee660 | 156 | |
11f34e69 | 157 | EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i); |
8ceee660 | 158 | |
11f34e69 BH |
159 | /* In flash config mode, DSP does not turn on AFE, so |
160 | * just wait 1 second. | |
161 | */ | |
f8b87c17 | 162 | if (efx->phy_mode & PHY_MODE_SPECIAL) { |
11f34e69 | 163 | schedule_timeout_uninterruptible(HZ); |
f8b87c17 | 164 | return 0; |
11f34e69 BH |
165 | } |
166 | ||
167 | for (j = 0; j < 10; ++j) { | |
168 | msleep(100); | |
169 | ||
170 | /* Check DSP has asserted AFE power line */ | |
171 | rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); | |
172 | if (rc < 0) | |
173 | goto fail_on; | |
174 | if (rc & (1 << P1_AFE_PWD_LBN)) | |
f8b87c17 | 175 | return 0; |
11f34e69 BH |
176 | } |
177 | } | |
8ceee660 | 178 | |
11f34e69 | 179 | EFX_INFO(efx, "timed out waiting for DSP boot\n"); |
8ceee660 | 180 | rc = -ETIMEDOUT; |
f8b87c17 BH |
181 | fail_on: |
182 | sfe4001_poweroff(efx); | |
183 | return rc; | |
184 | } | |
185 | ||
6f158d5f | 186 | static int sfn4111t_reset(struct efx_nic *efx) |
3e133c44 | 187 | { |
6f158d5f | 188 | efx_oword_t reg; |
3e133c44 | 189 | |
2f085753 | 190 | /* GPIO 3 and the GPIO register are shared with I2C, so block that */ |
6f158d5f | 191 | mutex_lock(&efx->i2c_adap.bus_lock); |
3e133c44 | 192 | |
2f085753 BH |
193 | /* Pull RST_N (GPIO 2) low then let it up again, setting the |
194 | * FLASH_CFG_1 strap (GPIO 3) appropriately. Only change the | |
195 | * output enables; the output levels should always be 0 (low) | |
196 | * and we rely on external pull-ups. */ | |
6f158d5f BH |
197 | falcon_read(efx, ®, GPIO_CTL_REG_KER); |
198 | EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, true); | |
6f158d5f BH |
199 | falcon_write(efx, ®, GPIO_CTL_REG_KER); |
200 | msleep(1000); | |
2f085753 BH |
201 | EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, false); |
202 | EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, | |
203 | !!(efx->phy_mode & PHY_MODE_SPECIAL)); | |
6f158d5f | 204 | falcon_write(efx, ®, GPIO_CTL_REG_KER); |
2f085753 | 205 | msleep(1); |
3e133c44 | 206 | |
6f158d5f | 207 | mutex_unlock(&efx->i2c_adap.bus_lock); |
3e133c44 | 208 | |
6f158d5f BH |
209 | ssleep(1); |
210 | return 0; | |
3e133c44 BH |
211 | } |
212 | ||
f8b87c17 BH |
213 | static ssize_t show_phy_flash_cfg(struct device *dev, |
214 | struct device_attribute *attr, char *buf) | |
215 | { | |
216 | struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); | |
217 | return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL)); | |
218 | } | |
219 | ||
220 | static ssize_t set_phy_flash_cfg(struct device *dev, | |
221 | struct device_attribute *attr, | |
222 | const char *buf, size_t count) | |
223 | { | |
224 | struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); | |
225 | enum efx_phy_mode old_mode, new_mode; | |
226 | int err; | |
227 | ||
228 | rtnl_lock(); | |
229 | old_mode = efx->phy_mode; | |
230 | if (count == 0 || *buf == '0') | |
231 | new_mode = old_mode & ~PHY_MODE_SPECIAL; | |
232 | else | |
233 | new_mode = PHY_MODE_SPECIAL; | |
234 | if (old_mode == new_mode) { | |
235 | err = 0; | |
236 | } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { | |
237 | err = -EBUSY; | |
238 | } else { | |
1974cc20 BH |
239 | /* Reset the PHY, reconfigure the MAC and enable/disable |
240 | * MAC stats accordingly. */ | |
f8b87c17 | 241 | efx->phy_mode = new_mode; |
1974cc20 BH |
242 | if (new_mode & PHY_MODE_SPECIAL) |
243 | efx_stats_disable(efx); | |
6f158d5f BH |
244 | if (efx->board_info.type == EFX_BOARD_SFE4001) |
245 | err = sfe4001_poweron(efx); | |
246 | else | |
247 | err = sfn4111t_reset(efx); | |
f8b87c17 | 248 | efx_reconfigure_port(efx); |
1974cc20 BH |
249 | if (!(new_mode & PHY_MODE_SPECIAL)) |
250 | efx_stats_enable(efx); | |
f8b87c17 BH |
251 | } |
252 | rtnl_unlock(); | |
253 | ||
254 | return err ? err : count; | |
255 | } | |
256 | ||
257 | static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg); | |
258 | ||
259 | static void sfe4001_fini(struct efx_nic *efx) | |
260 | { | |
261 | EFX_INFO(efx, "%s\n", __func__); | |
262 | ||
263 | device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); | |
264 | sfe4001_poweroff(efx); | |
265 | i2c_unregister_device(efx->board_info.ioexp_client); | |
266 | i2c_unregister_device(efx->board_info.hwmon_client); | |
267 | } | |
268 | ||
6f158d5f BH |
269 | static int sfe4001_check_hw(struct efx_nic *efx) |
270 | { | |
271 | s32 status; | |
272 | ||
273 | /* If XAUI link is up then do not monitor */ | |
274 | if (EFX_WORKAROUND_7884(efx) && efx->mac_up) | |
275 | return 0; | |
276 | ||
277 | /* Check the powered status of the PHY. Lack of power implies that | |
278 | * the MAX6647 has shut down power to it, probably due to a temp. | |
279 | * alarm. Reading the power status rather than the MAX6647 status | |
280 | * directly because the later is read-to-clear and would thus | |
281 | * start to power up the PHY again when polled, causing us to blip | |
282 | * the power undesirably. | |
283 | * We know we can read from the IO expander because we did | |
284 | * it during power-on. Assume failure now is bad news. */ | |
285 | status = i2c_smbus_read_byte_data(efx->board_info.ioexp_client, P1_IN); | |
286 | if (status >= 0 && | |
287 | (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) | |
288 | return 0; | |
289 | ||
290 | /* Use board power control, not PHY power control */ | |
291 | sfe4001_poweroff(efx); | |
292 | efx->phy_mode = PHY_MODE_OFF; | |
293 | ||
294 | return (status < 0) ? -EIO : -ERANGE; | |
295 | } | |
296 | ||
3e133c44 BH |
297 | static struct i2c_board_info sfe4001_hwmon_info = { |
298 | I2C_BOARD_INFO("max6647", 0x4e), | |
3e133c44 BH |
299 | }; |
300 | ||
f8b87c17 BH |
301 | /* This board uses an I2C expander to provider power to the PHY, which needs to |
302 | * be turned on before the PHY can be used. | |
303 | * Context: Process context, rtnl lock held | |
304 | */ | |
305 | int sfe4001_init(struct efx_nic *efx) | |
306 | { | |
f8b87c17 BH |
307 | int rc; |
308 | ||
3e133c44 BH |
309 | #if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE) |
310 | efx->board_info.hwmon_client = | |
311 | i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info); | |
312 | #else | |
313 | efx->board_info.hwmon_client = | |
314 | i2c_new_dummy(&efx->i2c_adap, sfe4001_hwmon_info.addr); | |
315 | #endif | |
316 | if (!efx->board_info.hwmon_client) | |
f8b87c17 | 317 | return -EIO; |
f8b87c17 | 318 | |
3e133c44 BH |
319 | /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ |
320 | rc = i2c_smbus_write_byte_data(efx->board_info.hwmon_client, | |
321 | MAX664X_REG_WLHO, 90); | |
f8b87c17 | 322 | if (rc) |
3e133c44 | 323 | goto fail_hwmon; |
f8b87c17 BH |
324 | |
325 | efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); | |
326 | if (!efx->board_info.ioexp_client) { | |
327 | rc = -EIO; | |
328 | goto fail_hwmon; | |
329 | } | |
330 | ||
331 | /* 10Xpress has fixed-function LED pins, so there is no board-specific | |
332 | * blink code. */ | |
333 | efx->board_info.blink = tenxpress_phy_blink; | |
334 | ||
3e133c44 | 335 | efx->board_info.monitor = sfe4001_check_hw; |
f8b87c17 BH |
336 | efx->board_info.fini = sfe4001_fini; |
337 | ||
1974cc20 BH |
338 | if (efx->phy_mode & PHY_MODE_SPECIAL) { |
339 | /* PHY won't generate a 156.25 MHz clock and MAC stats fetch | |
340 | * will fail. */ | |
341 | efx_stats_disable(efx); | |
342 | } | |
f8b87c17 BH |
343 | rc = sfe4001_poweron(efx); |
344 | if (rc) | |
345 | goto fail_ioexp; | |
346 | ||
347 | rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); | |
348 | if (rc) | |
349 | goto fail_on; | |
8ceee660 | 350 | |
8ceee660 BH |
351 | EFX_INFO(efx, "PHY is powered on\n"); |
352 | return 0; | |
353 | ||
37b5a603 BH |
354 | fail_on: |
355 | sfe4001_poweroff(efx); | |
356 | fail_ioexp: | |
f8b87c17 | 357 | i2c_unregister_device(efx->board_info.ioexp_client); |
37b5a603 | 358 | fail_hwmon: |
3e133c44 | 359 | i2c_unregister_device(efx->board_info.hwmon_client); |
8ceee660 BH |
360 | return rc; |
361 | } | |
6f158d5f BH |
362 | |
363 | static int sfn4111t_check_hw(struct efx_nic *efx) | |
364 | { | |
365 | s32 status; | |
366 | ||
367 | /* If XAUI link is up then do not monitor */ | |
368 | if (EFX_WORKAROUND_7884(efx) && efx->mac_up) | |
369 | return 0; | |
370 | ||
371 | /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */ | |
372 | status = i2c_smbus_read_byte_data(efx->board_info.hwmon_client, | |
373 | MAX664X_REG_RSL); | |
374 | if (status < 0) | |
375 | return -EIO; | |
376 | if (status & 0x57) | |
377 | return -ERANGE; | |
378 | return 0; | |
379 | } | |
380 | ||
381 | static void sfn4111t_fini(struct efx_nic *efx) | |
382 | { | |
383 | EFX_INFO(efx, "%s\n", __func__); | |
384 | ||
385 | device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); | |
386 | i2c_unregister_device(efx->board_info.hwmon_client); | |
387 | } | |
388 | ||
44176b45 | 389 | static struct i2c_board_info sfn4111t_a0_hwmon_info = { |
6f158d5f | 390 | I2C_BOARD_INFO("max6647", 0x4e), |
6f158d5f BH |
391 | }; |
392 | ||
44176b45 BH |
393 | static struct i2c_board_info sfn4111t_r5_hwmon_info = { |
394 | I2C_BOARD_INFO("max6646", 0x4d), | |
44176b45 BH |
395 | }; |
396 | ||
6f158d5f BH |
397 | int sfn4111t_init(struct efx_nic *efx) |
398 | { | |
190dbcfd | 399 | int i = 0; |
6f158d5f BH |
400 | int rc; |
401 | ||
402 | efx->board_info.hwmon_client = | |
44176b45 BH |
403 | i2c_new_device(&efx->i2c_adap, |
404 | (efx->board_info.minor < 5) ? | |
405 | &sfn4111t_a0_hwmon_info : | |
406 | &sfn4111t_r5_hwmon_info); | |
6f158d5f BH |
407 | if (!efx->board_info.hwmon_client) |
408 | return -EIO; | |
409 | ||
410 | efx->board_info.blink = tenxpress_phy_blink; | |
411 | efx->board_info.monitor = sfn4111t_check_hw; | |
412 | efx->board_info.fini = sfn4111t_fini; | |
413 | ||
414 | rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); | |
415 | if (rc) | |
416 | goto fail_hwmon; | |
417 | ||
190dbcfd BH |
418 | do { |
419 | if (efx->phy_mode & PHY_MODE_SPECIAL) { | |
420 | /* PHY may not generate a 156.25 MHz clock and MAC | |
421 | * stats fetch will fail. */ | |
422 | efx_stats_disable(efx); | |
423 | sfn4111t_reset(efx); | |
424 | } | |
425 | rc = sft9001_wait_boot(efx); | |
426 | if (rc == 0) | |
427 | return 0; | |
428 | efx->phy_mode = PHY_MODE_SPECIAL; | |
429 | } while (rc == -EINVAL && ++i < 2); | |
6f158d5f | 430 | |
190dbcfd | 431 | device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); |
6f158d5f BH |
432 | fail_hwmon: |
433 | i2c_unregister_device(efx->board_info.hwmon_client); | |
434 | return rc; | |
435 | } |