sfe4001.c 8.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/****************************************************************************
 * Driver for Solarflare Solarstorm network controllers and boards
 * Copyright 2007 Solarflare Communications Inc.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation, incorporated herein by reference.
 */

/*****************************************************************************
 * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that
 * controls the PHY power rails, and for the MAX6647 temp. sensor used to check
 * the PHY
 */
#include <linux/delay.h>
16
#include "net_driver.h"
17 18 19 20 21
#include "efx.h"
#include "phy.h"
#include "boards.h"
#include "falcon.h"
#include "falcon_hwdefs.h"
22
#include "falcon_io.h"
23
#include "mac.h"
24
#include "workarounds.h"
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

/**************************************************************************
 *
 * I2C IO Expander device
 *
 **************************************************************************/
#define	PCA9539 0x74

#define	P0_IN 0x00
#define	P0_OUT 0x02
#define	P0_INVERT 0x04
#define	P0_CONFIG 0x06

#define	P0_EN_1V0X_LBN 0
#define	P0_EN_1V0X_WIDTH 1
#define	P0_EN_1V2_LBN 1
#define	P0_EN_1V2_WIDTH 1
#define	P0_EN_2V5_LBN 2
#define	P0_EN_2V5_WIDTH 1
#define	P0_EN_3V3X_LBN 3
#define	P0_EN_3V3X_WIDTH 1
#define	P0_EN_5V_LBN 4
#define	P0_EN_5V_WIDTH 1
#define	P0_SHORTEN_JTAG_LBN 5
#define	P0_SHORTEN_JTAG_WIDTH 1
#define	P0_X_TRST_LBN 6
#define	P0_X_TRST_WIDTH 1
#define	P0_DSP_RESET_LBN 7
#define	P0_DSP_RESET_WIDTH 1

#define	P1_IN 0x01
#define	P1_OUT 0x03
#define	P1_INVERT 0x05
#define	P1_CONFIG 0x07

#define	P1_AFE_PWD_LBN 0
#define	P1_AFE_PWD_WIDTH 1
#define	P1_DSP_PWD25_LBN 1
#define	P1_DSP_PWD25_WIDTH 1
#define	P1_RESERVED_LBN 2
#define	P1_RESERVED_WIDTH 2
#define	P1_SPARE_LBN 4
#define	P1_SPARE_WIDTH 4

69 70 71
/* Temperature Sensor */
#define MAX664X_REG_RSL		0x02
#define MAX664X_REG_WLHO	0x0B
72

73
static void sfe4001_poweroff(struct efx_nic *efx)
74
{
75 76
	struct i2c_client *ioexp_client = efx->board_info.ioexp_client;
	struct i2c_client *hwmon_client = efx->board_info.hwmon_client;
77

78 79 80 81
	/* Turn off all power rails and disable outputs */
	i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff);
	i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff);
	i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff);
82

83
	/* Clear any over-temperature alert */
84
	i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
85
}
86

87
static int sfe4001_poweron(struct efx_nic *efx)
88
{
89 90
	struct i2c_client *hwmon_client = efx->board_info.hwmon_client;
	struct i2c_client *ioexp_client = efx->board_info.ioexp_client;
91
	unsigned int i, j;
92
	int rc;
93
	u8 out;
94 95

	/* Clear any previous over-temperature alert */
96
	rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
97
	if (rc < 0)
98
		return rc;
99 100

	/* Enable port 0 and port 1 outputs on IO expander */
101
	rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00);
102
	if (rc)
103
		return rc;
104 105
	rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG,
				       0xff & ~(1 << P1_SPARE_LBN));
106
	if (rc)
107
		goto fail_on;
108

109 110 111 112 113 114
	/* If PHY power is on, turn it all off and wait 1 second to
	 * ensure a full reset.
	 */
	rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT);
	if (rc < 0)
		goto fail_on;
115 116 117
	out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
		       (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
		       (0 << P0_EN_1V0X_LBN));
118 119 120 121 122 123 124
	if (rc != out) {
		EFX_INFO(efx, "power-cycling PHY\n");
		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
		if (rc)
			goto fail_on;
		schedule_timeout_uninterruptible(HZ);
	}
125

126
	for (i = 0; i < 20; ++i) {
127 128 129 130
		/* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
		out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
			       (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
			       (1 << P0_X_TRST_LBN));
131
		if (efx->phy_mode & PHY_MODE_SPECIAL)
132
			out |= 1 << P0_EN_3V3X_LBN;
133

134
		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
135
		if (rc)
136
			goto fail_on;
137 138 139 140
		msleep(10);

		/* Turn on 1V power rail */
		out &= ~(1 << P0_EN_1V0X_LBN);
141
		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
142
		if (rc)
143
			goto fail_on;
144

145
		EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i);
146

147 148 149
		/* In flash config mode, DSP does not turn on AFE, so
		 * just wait 1 second.
		 */
150
		if (efx->phy_mode & PHY_MODE_SPECIAL) {
151
			schedule_timeout_uninterruptible(HZ);
152
			return 0;
153 154 155 156 157 158 159 160 161 162
		}

		for (j = 0; j < 10; ++j) {
			msleep(100);

			/* Check DSP has asserted AFE power line */
			rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN);
			if (rc < 0)
				goto fail_on;
			if (rc & (1 << P1_AFE_PWD_LBN))
163
				return 0;
164 165
		}
	}
166

167
	EFX_INFO(efx, "timed out waiting for DSP boot\n");
168
	rc = -ETIMEDOUT;
169 170 171 172 173
fail_on:
	sfe4001_poweroff(efx);
	return rc;
}

174 175 176 177 178
static int sfe4001_check_hw(struct efx_nic *efx)
{
	s32 status;

	/* If XAUI link is up then do not monitor */
179
	if (EFX_WORKAROUND_7884(efx) && efx->mac_up)
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
		return 0;

	/* Check the powered status of the PHY. Lack of power implies that
	 * the MAX6647 has shut down power to it, probably due to a temp.
	 * alarm. Reading the power status rather than the MAX6647 status
	 * directly because the later is read-to-clear and would thus
	 * start to power up the PHY again when polled, causing us to blip
	 * the power undesirably.
	 * We know we can read from the IO expander because we did
	 * it during power-on. Assume failure now is bad news. */
	status = i2c_smbus_read_byte_data(efx->board_info.ioexp_client, P1_IN);
	if (status >= 0 &&
	    (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0)
		return 0;

	/* Use board power control, not PHY power control */
	sfe4001_poweroff(efx);
	efx->phy_mode = PHY_MODE_OFF;

	return (status < 0) ? -EIO : -ERANGE;
}

202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin
 * using the 3V3X output of the IO-expander.  Allow the user to set
 * this when the device is stopped, and keep it stopped then.
 */

static ssize_t show_phy_flash_cfg(struct device *dev,
				  struct device_attribute *attr, char *buf)
{
	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
	return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL));
}

static ssize_t set_phy_flash_cfg(struct device *dev,
				 struct device_attribute *attr,
				 const char *buf, size_t count)
{
	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
	enum efx_phy_mode old_mode, new_mode;
	int err;

	rtnl_lock();
	old_mode = efx->phy_mode;
	if (count == 0 || *buf == '0')
		new_mode = old_mode & ~PHY_MODE_SPECIAL;
	else
		new_mode = PHY_MODE_SPECIAL;
	if (old_mode == new_mode) {
		err = 0;
	} else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) {
		err = -EBUSY;
	} else {
		efx->phy_mode = new_mode;
		err = sfe4001_poweron(efx);
		efx_reconfigure_port(efx);
	}
	rtnl_unlock();

	return err ? err : count;
}

static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg);

static void sfe4001_fini(struct efx_nic *efx)
{
	EFX_INFO(efx, "%s\n", __func__);

	device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
	sfe4001_poweroff(efx);
	i2c_unregister_device(efx->board_info.ioexp_client);
	i2c_unregister_device(efx->board_info.hwmon_client);
}

254 255 256 257 258
static struct i2c_board_info sfe4001_hwmon_info = {
	I2C_BOARD_INFO("max6647", 0x4e),
	.irq		= -1,
};

259 260 261 262 263 264 265 266
/* This board uses an I2C expander to provider power to the PHY, which needs to
 * be turned on before the PHY can be used.
 * Context: Process context, rtnl lock held
 */
int sfe4001_init(struct efx_nic *efx)
{
	int rc;

267 268 269 270 271 272 273 274
#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE)
	efx->board_info.hwmon_client =
		i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);
#else
	efx->board_info.hwmon_client =
		i2c_new_dummy(&efx->i2c_adap, sfe4001_hwmon_info.addr);
#endif
	if (!efx->board_info.hwmon_client)
275 276
		return -EIO;

277 278 279
	/* Raise board/PHY high limit from 85 to 90 degrees Celsius */
	rc = i2c_smbus_write_byte_data(efx->board_info.hwmon_client,
				       MAX664X_REG_WLHO, 90);
280
	if (rc)
281
		goto fail_hwmon;
282 283 284 285 286 287 288 289 290 291 292

	efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
	if (!efx->board_info.ioexp_client) {
		rc = -EIO;
		goto fail_hwmon;
	}

	/* 10Xpress has fixed-function LED pins, so there is no board-specific
	 * blink code. */
	efx->board_info.blink = tenxpress_phy_blink;

293
	efx->board_info.monitor = sfe4001_check_hw;
294 295 296 297 298 299 300 301 302
	efx->board_info.fini = sfe4001_fini;

	rc = sfe4001_poweron(efx);
	if (rc)
		goto fail_ioexp;

	rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
	if (rc)
		goto fail_on;
303 304 305 306

	EFX_INFO(efx, "PHY is powered on\n");
	return 0;

307 308 309
fail_on:
	sfe4001_poweroff(efx);
fail_ioexp:
310
	i2c_unregister_device(efx->board_info.ioexp_client);
311
fail_hwmon:
312
	i2c_unregister_device(efx->board_info.hwmon_client);
313 314
	return rc;
}