blob: b7005da55d5e257e33e0e78ac85009947fd4ea1f [file] [log] [blame]
Ben Hutchings8ceee662008-04-27 12:55:59 +01001/****************************************************************************
2 * Driver for Solarflare Solarstorm network controllers and boards
3 * Copyright 2007 Solarflare Communications Inc.
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/*****************************************************************************
11 * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that
12 * controls the PHY power rails, and for the MAX6647 temp. sensor used to check
13 * the PHY
14 */
15#include <linux/delay.h>
Ben Hutchingsf8b87c12008-09-01 12:48:17 +010016#include "net_driver.h"
Ben Hutchings8ceee662008-04-27 12:55:59 +010017#include "efx.h"
18#include "phy.h"
19#include "boards.h"
20#include "falcon.h"
21#include "falcon_hwdefs.h"
Ben Hutchingsc1e5fcc2008-09-01 12:48:41 +010022#include "falcon_io.h"
Ben Hutchings8ceee662008-04-27 12:55:59 +010023#include "mac.h"
24
25/**************************************************************************
26 *
27 * I2C IO Expander device
28 *
29 **************************************************************************/
30#define PCA9539 0x74
31
32#define P0_IN 0x00
33#define P0_OUT 0x02
34#define P0_INVERT 0x04
35#define P0_CONFIG 0x06
36
37#define P0_EN_1V0X_LBN 0
38#define P0_EN_1V0X_WIDTH 1
39#define P0_EN_1V2_LBN 1
40#define P0_EN_1V2_WIDTH 1
41#define P0_EN_2V5_LBN 2
42#define P0_EN_2V5_WIDTH 1
43#define P0_EN_3V3X_LBN 3
44#define P0_EN_3V3X_WIDTH 1
45#define P0_EN_5V_LBN 4
46#define P0_EN_5V_WIDTH 1
47#define P0_SHORTEN_JTAG_LBN 5
48#define P0_SHORTEN_JTAG_WIDTH 1
49#define P0_X_TRST_LBN 6
50#define P0_X_TRST_WIDTH 1
51#define P0_DSP_RESET_LBN 7
52#define P0_DSP_RESET_WIDTH 1
53
54#define P1_IN 0x01
55#define P1_OUT 0x03
56#define P1_INVERT 0x05
57#define P1_CONFIG 0x07
58
59#define P1_AFE_PWD_LBN 0
60#define P1_AFE_PWD_WIDTH 1
61#define P1_DSP_PWD25_LBN 1
62#define P1_DSP_PWD25_WIDTH 1
63#define P1_RESERVED_LBN 2
64#define P1_RESERVED_WIDTH 2
65#define P1_SPARE_LBN 4
66#define P1_SPARE_WIDTH 4
67
68
69/**************************************************************************
70 *
71 * Temperature Sensor
72 *
73 **************************************************************************/
74#define MAX6647 0x4e
75
76#define RLTS 0x00
77#define RLTE 0x01
78#define RSL 0x02
79#define RCL 0x03
80#define RCRA 0x04
81#define RLHN 0x05
82#define RLLI 0x06
83#define RRHI 0x07
84#define RRLS 0x08
85#define WCRW 0x0a
86#define WLHO 0x0b
87#define WRHA 0x0c
88#define WRLN 0x0e
89#define OSHT 0x0f
90#define REET 0x10
91#define RIET 0x11
92#define RWOE 0x19
93#define RWOI 0x20
94#define HYS 0x21
95#define QUEUE 0x22
96#define MFID 0xfe
97#define REVID 0xff
98
99/* Status bits */
100#define MAX6647_BUSY (1 << 7) /* ADC is converting */
101#define MAX6647_LHIGH (1 << 6) /* Local high temp. alarm */
102#define MAX6647_LLOW (1 << 5) /* Local low temp. alarm */
103#define MAX6647_RHIGH (1 << 4) /* Remote high temp. alarm */
104#define MAX6647_RLOW (1 << 3) /* Remote low temp. alarm */
105#define MAX6647_FAULT (1 << 2) /* DXN/DXP short/open circuit */
106#define MAX6647_EOT (1 << 1) /* Remote junction overtemp. */
107#define MAX6647_IOT (1 << 0) /* Local junction overtemp. */
108
109static const u8 xgphy_max_temperature = 90;
110
Ben Hutchings37b5a602008-05-30 22:27:04 +0100111static void sfe4001_poweroff(struct efx_nic *efx)
Ben Hutchings8ceee662008-04-27 12:55:59 +0100112{
Ben Hutchings37b5a602008-05-30 22:27:04 +0100113 struct i2c_client *ioexp_client = efx->board_info.ioexp_client;
114 struct i2c_client *hwmon_client = efx->board_info.hwmon_client;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100115
Ben Hutchings37b5a602008-05-30 22:27:04 +0100116 /* Turn off all power rails and disable outputs */
117 i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff);
118 i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff);
119 i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100120
121 /* Clear any over-temperature alert */
Ben Hutchings37b5a602008-05-30 22:27:04 +0100122 i2c_smbus_read_byte_data(hwmon_client, RSL);
123}
124
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100125static int sfe4001_poweron(struct efx_nic *efx)
Ben Hutchings37b5a602008-05-30 22:27:04 +0100126{
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100127 struct i2c_client *hwmon_client = efx->board_info.hwmon_client;
128 struct i2c_client *ioexp_client = efx->board_info.ioexp_client;
Ben Hutchings11f34e62008-09-01 12:45:48 +0100129 unsigned int i, j;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100130 int rc;
Ben Hutchings37b5a602008-05-30 22:27:04 +0100131 u8 out;
Ben Hutchingsc1e5fcc2008-09-01 12:48:41 +0100132 efx_oword_t reg;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100133
Ben Hutchings8ceee662008-04-27 12:55:59 +0100134 /* Ensure that XGXS and XAUI SerDes are held in reset */
Ben Hutchingsc1e5fcc2008-09-01 12:48:41 +0100135 EFX_POPULATE_OWORD_7(reg, XX_PWRDNA_EN, 1,
Ben Hutchings8ceee662008-04-27 12:55:59 +0100136 XX_PWRDNB_EN, 1,
137 XX_RSTPLLAB_EN, 1,
138 XX_RESETA_EN, 1,
139 XX_RESETB_EN, 1,
140 XX_RSTXGXSRX_EN, 1,
141 XX_RSTXGXSTX_EN, 1);
Ben Hutchingsc1e5fcc2008-09-01 12:48:41 +0100142 falcon_write(efx, &reg, XX_PWR_RST_REG);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100143 udelay(10);
144
Ben Hutchings8ceee662008-04-27 12:55:59 +0100145 /* Clear any previous over-temperature alert */
Ben Hutchings37b5a602008-05-30 22:27:04 +0100146 rc = i2c_smbus_read_byte_data(hwmon_client, RSL);
147 if (rc < 0)
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100148 return rc;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100149
150 /* Enable port 0 and port 1 outputs on IO expander */
Ben Hutchings37b5a602008-05-30 22:27:04 +0100151 rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100152 if (rc)
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100153 return rc;
Ben Hutchings37b5a602008-05-30 22:27:04 +0100154 rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG,
155 0xff & ~(1 << P1_SPARE_LBN));
Ben Hutchings8ceee662008-04-27 12:55:59 +0100156 if (rc)
Ben Hutchings37b5a602008-05-30 22:27:04 +0100157 goto fail_on;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100158
Ben Hutchings11f34e62008-09-01 12:45:48 +0100159 /* If PHY power is on, turn it all off and wait 1 second to
160 * ensure a full reset.
161 */
162 rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT);
163 if (rc < 0)
164 goto fail_on;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100165 out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
166 (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
167 (0 << P0_EN_1V0X_LBN));
Ben Hutchings11f34e62008-09-01 12:45:48 +0100168 if (rc != out) {
169 EFX_INFO(efx, "power-cycling PHY\n");
170 rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
171 if (rc)
172 goto fail_on;
173 schedule_timeout_uninterruptible(HZ);
174 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100175
Ben Hutchings11f34e62008-09-01 12:45:48 +0100176 for (i = 0; i < 20; ++i) {
Ben Hutchings8ceee662008-04-27 12:55:59 +0100177 /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
178 out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
179 (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
180 (1 << P0_X_TRST_LBN));
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100181 if (efx->phy_mode & PHY_MODE_SPECIAL)
Ben Hutchings75f2d3e2008-05-07 12:55:13 +0100182 out |= 1 << P0_EN_3V3X_LBN;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100183
Ben Hutchings37b5a602008-05-30 22:27:04 +0100184 rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100185 if (rc)
Ben Hutchings37b5a602008-05-30 22:27:04 +0100186 goto fail_on;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100187 msleep(10);
188
189 /* Turn on 1V power rail */
190 out &= ~(1 << P0_EN_1V0X_LBN);
Ben Hutchings37b5a602008-05-30 22:27:04 +0100191 rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100192 if (rc)
Ben Hutchings37b5a602008-05-30 22:27:04 +0100193 goto fail_on;
Ben Hutchings8ceee662008-04-27 12:55:59 +0100194
Ben Hutchings11f34e62008-09-01 12:45:48 +0100195 EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100196
Ben Hutchings11f34e62008-09-01 12:45:48 +0100197 /* In flash config mode, DSP does not turn on AFE, so
198 * just wait 1 second.
199 */
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100200 if (efx->phy_mode & PHY_MODE_SPECIAL) {
Ben Hutchings11f34e62008-09-01 12:45:48 +0100201 schedule_timeout_uninterruptible(HZ);
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100202 return 0;
Ben Hutchings11f34e62008-09-01 12:45:48 +0100203 }
Ben Hutchings8ceee662008-04-27 12:55:59 +0100204
Ben Hutchings11f34e62008-09-01 12:45:48 +0100205 for (j = 0; j < 10; ++j) {
206 msleep(100);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100207
Ben Hutchings11f34e62008-09-01 12:45:48 +0100208 /* Check DSP has asserted AFE power line */
209 rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN);
210 if (rc < 0)
211 goto fail_on;
212 if (rc & (1 << P1_AFE_PWD_LBN))
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100213 return 0;
Ben Hutchings11f34e62008-09-01 12:45:48 +0100214 }
215 }
216
217 EFX_INFO(efx, "timed out waiting for DSP boot\n");
Ben Hutchings8ceee662008-04-27 12:55:59 +0100218 rc = -ETIMEDOUT;
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100219fail_on:
220 sfe4001_poweroff(efx);
221 return rc;
222}
Ben Hutchings8ceee662008-04-27 12:55:59 +0100223
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100224/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin
225 * using the 3V3X output of the IO-expander. Allow the user to set
226 * this when the device is stopped, and keep it stopped then.
227 */
228
229static ssize_t show_phy_flash_cfg(struct device *dev,
230 struct device_attribute *attr, char *buf)
231{
232 struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
233 return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL));
234}
235
236static ssize_t set_phy_flash_cfg(struct device *dev,
237 struct device_attribute *attr,
238 const char *buf, size_t count)
239{
240 struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
241 enum efx_phy_mode old_mode, new_mode;
242 int err;
243
244 rtnl_lock();
245 old_mode = efx->phy_mode;
246 if (count == 0 || *buf == '0')
247 new_mode = old_mode & ~PHY_MODE_SPECIAL;
248 else
249 new_mode = PHY_MODE_SPECIAL;
250 if (old_mode == new_mode) {
251 err = 0;
252 } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) {
253 err = -EBUSY;
254 } else {
255 efx->phy_mode = new_mode;
256 err = sfe4001_poweron(efx);
257 efx_reconfigure_port(efx);
258 }
259 rtnl_unlock();
260
261 return err ? err : count;
262}
263
264static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg);
265
266static void sfe4001_fini(struct efx_nic *efx)
267{
268 EFX_INFO(efx, "%s\n", __func__);
269
270 device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
271 sfe4001_poweroff(efx);
272 i2c_unregister_device(efx->board_info.ioexp_client);
273 i2c_unregister_device(efx->board_info.hwmon_client);
274}
275
276/* This board uses an I2C expander to provider power to the PHY, which needs to
277 * be turned on before the PHY can be used.
278 * Context: Process context, rtnl lock held
279 */
280int sfe4001_init(struct efx_nic *efx)
281{
282 struct i2c_client *hwmon_client;
283 int rc;
284
285 hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647);
286 if (!hwmon_client)
287 return -EIO;
288 efx->board_info.hwmon_client = hwmon_client;
289
290 /* Set DSP over-temperature alert threshold */
291 EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
292 rc = i2c_smbus_write_byte_data(hwmon_client, WLHO,
293 xgphy_max_temperature);
294 if (rc)
295 goto fail_ioexp;
296
297 /* Read it back and verify */
298 rc = i2c_smbus_read_byte_data(hwmon_client, RLHN);
299 if (rc < 0)
300 goto fail_ioexp;
301 if (rc != xgphy_max_temperature) {
302 rc = -EFAULT;
303 goto fail_ioexp;
304 }
305
306 efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
307 if (!efx->board_info.ioexp_client) {
308 rc = -EIO;
309 goto fail_hwmon;
310 }
311
312 /* 10Xpress has fixed-function LED pins, so there is no board-specific
313 * blink code. */
314 efx->board_info.blink = tenxpress_phy_blink;
315
316 efx->board_info.fini = sfe4001_fini;
317
318 rc = sfe4001_poweron(efx);
319 if (rc)
320 goto fail_ioexp;
321
322 rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
323 if (rc)
324 goto fail_on;
325
Ben Hutchings8ceee662008-04-27 12:55:59 +0100326 EFX_INFO(efx, "PHY is powered on\n");
327 return 0;
328
Ben Hutchings37b5a602008-05-30 22:27:04 +0100329fail_on:
330 sfe4001_poweroff(efx);
331fail_ioexp:
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100332 i2c_unregister_device(efx->board_info.ioexp_client);
Ben Hutchings37b5a602008-05-30 22:27:04 +0100333fail_hwmon:
Ben Hutchingsf8b87c12008-09-01 12:48:17 +0100334 i2c_unregister_device(hwmon_client);
Ben Hutchings8ceee662008-04-27 12:55:59 +0100335 return rc;
336}