162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/****************************************************************************
362306a36Sopenharmony_ci * Driver for Solarflare network controllers and boards
462306a36Sopenharmony_ci * Copyright 2007-2012 Solarflare Communications Inc.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/rtnetlink.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "net_driver.h"
1062306a36Sopenharmony_ci#include "phy.h"
1162306a36Sopenharmony_ci#include "efx.h"
1262306a36Sopenharmony_ci#include "nic.h"
1362306a36Sopenharmony_ci#include "workarounds.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* Macros for unpacking the board revision */
1662306a36Sopenharmony_ci/* The revision info is in host byte order. */
1762306a36Sopenharmony_ci#define FALCON_BOARD_TYPE(_rev) (_rev >> 8)
1862306a36Sopenharmony_ci#define FALCON_BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
1962306a36Sopenharmony_ci#define FALCON_BOARD_MINOR(_rev) (_rev & 0xf)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* Board types */
2262306a36Sopenharmony_ci#define FALCON_BOARD_SFE4001 0x01
2362306a36Sopenharmony_ci#define FALCON_BOARD_SFE4002 0x02
2462306a36Sopenharmony_ci#define FALCON_BOARD_SFE4003 0x03
2562306a36Sopenharmony_ci#define FALCON_BOARD_SFN4112F 0x52
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* Board temperature is about 15°C above ambient when air flow is
2862306a36Sopenharmony_ci * limited.  The maximum acceptable ambient temperature varies
2962306a36Sopenharmony_ci * depending on the PHY specifications but the critical temperature
3062306a36Sopenharmony_ci * above which we should shut down to avoid damage is 80°C. */
3162306a36Sopenharmony_ci#define FALCON_BOARD_TEMP_BIAS	15
3262306a36Sopenharmony_ci#define FALCON_BOARD_TEMP_CRIT	(80 + FALCON_BOARD_TEMP_BIAS)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* SFC4000 datasheet says: 'The maximum permitted junction temperature
3562306a36Sopenharmony_ci * is 125°C; the thermal design of the environment for the SFC4000
3662306a36Sopenharmony_ci * should aim to keep this well below 100°C.' */
3762306a36Sopenharmony_ci#define FALCON_JUNC_TEMP_MIN	0
3862306a36Sopenharmony_ci#define FALCON_JUNC_TEMP_MAX	90
3962306a36Sopenharmony_ci#define FALCON_JUNC_TEMP_CRIT	125
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*****************************************************************************
4262306a36Sopenharmony_ci * Support for LM87 sensor chip used on several boards
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ci#define LM87_REG_TEMP_HW_INT_LOCK	0x13
4562306a36Sopenharmony_ci#define LM87_REG_TEMP_HW_EXT_LOCK	0x14
4662306a36Sopenharmony_ci#define LM87_REG_TEMP_HW_INT		0x17
4762306a36Sopenharmony_ci#define LM87_REG_TEMP_HW_EXT		0x18
4862306a36Sopenharmony_ci#define LM87_REG_TEMP_EXT1		0x26
4962306a36Sopenharmony_ci#define LM87_REG_TEMP_INT		0x27
5062306a36Sopenharmony_ci#define LM87_REG_ALARMS1		0x41
5162306a36Sopenharmony_ci#define LM87_REG_ALARMS2		0x42
5262306a36Sopenharmony_ci#define LM87_IN_LIMITS(nr, _min, _max)			\
5362306a36Sopenharmony_ci	0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min
5462306a36Sopenharmony_ci#define LM87_AIN_LIMITS(nr, _min, _max)			\
5562306a36Sopenharmony_ci	0x3B + (nr), _max, 0x1A + (nr), _min
5662306a36Sopenharmony_ci#define LM87_TEMP_INT_LIMITS(_min, _max)		\
5762306a36Sopenharmony_ci	0x39, _max, 0x3A, _min
5862306a36Sopenharmony_ci#define LM87_TEMP_EXT1_LIMITS(_min, _max)		\
5962306a36Sopenharmony_ci	0x37, _max, 0x38, _min
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define LM87_ALARM_TEMP_INT		0x10
6262306a36Sopenharmony_ci#define LM87_ALARM_TEMP_EXT1		0x20
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SENSORS_LM87)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic int ef4_poke_lm87(struct i2c_client *client, const u8 *reg_values)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	while (*reg_values) {
6962306a36Sopenharmony_ci		u8 reg = *reg_values++;
7062306a36Sopenharmony_ci		u8 value = *reg_values++;
7162306a36Sopenharmony_ci		int rc = i2c_smbus_write_byte_data(client, reg, value);
7262306a36Sopenharmony_ci		if (rc)
7362306a36Sopenharmony_ci			return rc;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci	return 0;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic const u8 falcon_lm87_common_regs[] = {
7962306a36Sopenharmony_ci	LM87_REG_TEMP_HW_INT_LOCK, FALCON_BOARD_TEMP_CRIT,
8062306a36Sopenharmony_ci	LM87_REG_TEMP_HW_INT, FALCON_BOARD_TEMP_CRIT,
8162306a36Sopenharmony_ci	LM87_TEMP_EXT1_LIMITS(FALCON_JUNC_TEMP_MIN, FALCON_JUNC_TEMP_MAX),
8262306a36Sopenharmony_ci	LM87_REG_TEMP_HW_EXT_LOCK, FALCON_JUNC_TEMP_CRIT,
8362306a36Sopenharmony_ci	LM87_REG_TEMP_HW_EXT, FALCON_JUNC_TEMP_CRIT,
8462306a36Sopenharmony_ci	0
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int ef4_init_lm87(struct ef4_nic *efx, const struct i2c_board_info *info,
8862306a36Sopenharmony_ci			 const u8 *reg_values)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct falcon_board *board = falcon_board(efx);
9162306a36Sopenharmony_ci	struct i2c_client *client = i2c_new_client_device(&board->i2c_adap, info);
9262306a36Sopenharmony_ci	int rc;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (IS_ERR(client))
9562306a36Sopenharmony_ci		return PTR_ERR(client);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/* Read-to-clear alarm/interrupt status */
9862306a36Sopenharmony_ci	i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
9962306a36Sopenharmony_ci	i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	rc = ef4_poke_lm87(client, reg_values);
10262306a36Sopenharmony_ci	if (rc)
10362306a36Sopenharmony_ci		goto err;
10462306a36Sopenharmony_ci	rc = ef4_poke_lm87(client, falcon_lm87_common_regs);
10562306a36Sopenharmony_ci	if (rc)
10662306a36Sopenharmony_ci		goto err;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	board->hwmon_client = client;
10962306a36Sopenharmony_ci	return 0;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cierr:
11262306a36Sopenharmony_ci	i2c_unregister_device(client);
11362306a36Sopenharmony_ci	return rc;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic void ef4_fini_lm87(struct ef4_nic *efx)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	i2c_unregister_device(falcon_board(efx)->hwmon_client);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic int ef4_check_lm87(struct ef4_nic *efx, unsigned mask)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct i2c_client *client = falcon_board(efx)->hwmon_client;
12462306a36Sopenharmony_ci	bool temp_crit, elec_fault, is_failure;
12562306a36Sopenharmony_ci	u16 alarms;
12662306a36Sopenharmony_ci	s32 reg;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* If link is up then do not monitor temperature */
12962306a36Sopenharmony_ci	if (EF4_WORKAROUND_7884(efx) && efx->link_state.up)
13062306a36Sopenharmony_ci		return 0;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	reg = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
13362306a36Sopenharmony_ci	if (reg < 0)
13462306a36Sopenharmony_ci		return reg;
13562306a36Sopenharmony_ci	alarms = reg;
13662306a36Sopenharmony_ci	reg = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
13762306a36Sopenharmony_ci	if (reg < 0)
13862306a36Sopenharmony_ci		return reg;
13962306a36Sopenharmony_ci	alarms |= reg << 8;
14062306a36Sopenharmony_ci	alarms &= mask;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	temp_crit = false;
14362306a36Sopenharmony_ci	if (alarms & LM87_ALARM_TEMP_INT) {
14462306a36Sopenharmony_ci		reg = i2c_smbus_read_byte_data(client, LM87_REG_TEMP_INT);
14562306a36Sopenharmony_ci		if (reg < 0)
14662306a36Sopenharmony_ci			return reg;
14762306a36Sopenharmony_ci		if (reg > FALCON_BOARD_TEMP_CRIT)
14862306a36Sopenharmony_ci			temp_crit = true;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci	if (alarms & LM87_ALARM_TEMP_EXT1) {
15162306a36Sopenharmony_ci		reg = i2c_smbus_read_byte_data(client, LM87_REG_TEMP_EXT1);
15262306a36Sopenharmony_ci		if (reg < 0)
15362306a36Sopenharmony_ci			return reg;
15462306a36Sopenharmony_ci		if (reg > FALCON_JUNC_TEMP_CRIT)
15562306a36Sopenharmony_ci			temp_crit = true;
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci	elec_fault = alarms & ~(LM87_ALARM_TEMP_INT | LM87_ALARM_TEMP_EXT1);
15862306a36Sopenharmony_ci	is_failure = temp_crit || elec_fault;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (alarms)
16162306a36Sopenharmony_ci		netif_err(efx, hw, efx->net_dev,
16262306a36Sopenharmony_ci			  "LM87 detected a hardware %s (status %02x:%02x)"
16362306a36Sopenharmony_ci			  "%s%s%s%s\n",
16462306a36Sopenharmony_ci			  is_failure ? "failure" : "problem",
16562306a36Sopenharmony_ci			  alarms & 0xff, alarms >> 8,
16662306a36Sopenharmony_ci			  (alarms & LM87_ALARM_TEMP_INT) ?
16762306a36Sopenharmony_ci			  "; board is overheating" : "",
16862306a36Sopenharmony_ci			  (alarms & LM87_ALARM_TEMP_EXT1) ?
16962306a36Sopenharmony_ci			  "; controller is overheating" : "",
17062306a36Sopenharmony_ci			  temp_crit ? "; reached critical temperature" : "",
17162306a36Sopenharmony_ci			  elec_fault ? "; electrical fault" : "");
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return is_failure ? -ERANGE : 0;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci#else /* !CONFIG_SENSORS_LM87 */
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic inline int
17962306a36Sopenharmony_cief4_init_lm87(struct ef4_nic *efx, const struct i2c_board_info *info,
18062306a36Sopenharmony_ci	      const u8 *reg_values)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	return 0;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_cistatic inline void ef4_fini_lm87(struct ef4_nic *efx)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_cistatic inline int ef4_check_lm87(struct ef4_nic *efx, unsigned mask)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci#endif /* CONFIG_SENSORS_LM87 */
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/*****************************************************************************
19562306a36Sopenharmony_ci * Support for the SFE4001 NIC.
19662306a36Sopenharmony_ci *
19762306a36Sopenharmony_ci * The SFE4001 does not power-up fully at reset due to its high power
19862306a36Sopenharmony_ci * consumption.  We control its power via a PCA9539 I/O expander.
19962306a36Sopenharmony_ci * It also has a MAX6647 temperature monitor which we expose to
20062306a36Sopenharmony_ci * the lm90 driver.
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci * This also provides minimal support for reflashing the PHY, which is
20362306a36Sopenharmony_ci * initiated by resetting it with the FLASH_CFG_1 pin pulled down.
20462306a36Sopenharmony_ci * On SFE4001 rev A2 and later this is connected to the 3V3X output of
20562306a36Sopenharmony_ci * the IO-expander.
20662306a36Sopenharmony_ci * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually
20762306a36Sopenharmony_ci * exclusive with the network device being open.
20862306a36Sopenharmony_ci */
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci/**************************************************************************
21162306a36Sopenharmony_ci * Support for I2C IO Expander device on SFE4001
21262306a36Sopenharmony_ci */
21362306a36Sopenharmony_ci#define	PCA9539 0x74
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci#define	P0_IN 0x00
21662306a36Sopenharmony_ci#define	P0_OUT 0x02
21762306a36Sopenharmony_ci#define	P0_INVERT 0x04
21862306a36Sopenharmony_ci#define	P0_CONFIG 0x06
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#define	P0_EN_1V0X_LBN 0
22162306a36Sopenharmony_ci#define	P0_EN_1V0X_WIDTH 1
22262306a36Sopenharmony_ci#define	P0_EN_1V2_LBN 1
22362306a36Sopenharmony_ci#define	P0_EN_1V2_WIDTH 1
22462306a36Sopenharmony_ci#define	P0_EN_2V5_LBN 2
22562306a36Sopenharmony_ci#define	P0_EN_2V5_WIDTH 1
22662306a36Sopenharmony_ci#define	P0_EN_3V3X_LBN 3
22762306a36Sopenharmony_ci#define	P0_EN_3V3X_WIDTH 1
22862306a36Sopenharmony_ci#define	P0_EN_5V_LBN 4
22962306a36Sopenharmony_ci#define	P0_EN_5V_WIDTH 1
23062306a36Sopenharmony_ci#define	P0_SHORTEN_JTAG_LBN 5
23162306a36Sopenharmony_ci#define	P0_SHORTEN_JTAG_WIDTH 1
23262306a36Sopenharmony_ci#define	P0_X_TRST_LBN 6
23362306a36Sopenharmony_ci#define	P0_X_TRST_WIDTH 1
23462306a36Sopenharmony_ci#define	P0_DSP_RESET_LBN 7
23562306a36Sopenharmony_ci#define	P0_DSP_RESET_WIDTH 1
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci#define	P1_IN 0x01
23862306a36Sopenharmony_ci#define	P1_OUT 0x03
23962306a36Sopenharmony_ci#define	P1_INVERT 0x05
24062306a36Sopenharmony_ci#define	P1_CONFIG 0x07
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci#define	P1_AFE_PWD_LBN 0
24362306a36Sopenharmony_ci#define	P1_AFE_PWD_WIDTH 1
24462306a36Sopenharmony_ci#define	P1_DSP_PWD25_LBN 1
24562306a36Sopenharmony_ci#define	P1_DSP_PWD25_WIDTH 1
24662306a36Sopenharmony_ci#define	P1_RESERVED_LBN 2
24762306a36Sopenharmony_ci#define	P1_RESERVED_WIDTH 2
24862306a36Sopenharmony_ci#define	P1_SPARE_LBN 4
24962306a36Sopenharmony_ci#define	P1_SPARE_WIDTH 4
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci/* Temperature Sensor */
25262306a36Sopenharmony_ci#define MAX664X_REG_RSL		0x02
25362306a36Sopenharmony_ci#define MAX664X_REG_WLHO	0x0B
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic void sfe4001_poweroff(struct ef4_nic *efx)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client;
25862306a36Sopenharmony_ci	struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/* Turn off all power rails and disable outputs */
26162306a36Sopenharmony_ci	i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff);
26262306a36Sopenharmony_ci	i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff);
26362306a36Sopenharmony_ci	i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* Clear any over-temperature alert */
26662306a36Sopenharmony_ci	i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic int sfe4001_poweron(struct ef4_nic *efx)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client;
27262306a36Sopenharmony_ci	struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client;
27362306a36Sopenharmony_ci	unsigned int i, j;
27462306a36Sopenharmony_ci	int rc;
27562306a36Sopenharmony_ci	u8 out;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* Clear any previous over-temperature alert */
27862306a36Sopenharmony_ci	rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
27962306a36Sopenharmony_ci	if (rc < 0)
28062306a36Sopenharmony_ci		return rc;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/* Enable port 0 and port 1 outputs on IO expander */
28362306a36Sopenharmony_ci	rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00);
28462306a36Sopenharmony_ci	if (rc)
28562306a36Sopenharmony_ci		return rc;
28662306a36Sopenharmony_ci	rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG,
28762306a36Sopenharmony_ci				       0xff & ~(1 << P1_SPARE_LBN));
28862306a36Sopenharmony_ci	if (rc)
28962306a36Sopenharmony_ci		goto fail_on;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* If PHY power is on, turn it all off and wait 1 second to
29262306a36Sopenharmony_ci	 * ensure a full reset.
29362306a36Sopenharmony_ci	 */
29462306a36Sopenharmony_ci	rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT);
29562306a36Sopenharmony_ci	if (rc < 0)
29662306a36Sopenharmony_ci		goto fail_on;
29762306a36Sopenharmony_ci	out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
29862306a36Sopenharmony_ci		       (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
29962306a36Sopenharmony_ci		       (0 << P0_EN_1V0X_LBN));
30062306a36Sopenharmony_ci	if (rc != out) {
30162306a36Sopenharmony_ci		netif_info(efx, hw, efx->net_dev, "power-cycling PHY\n");
30262306a36Sopenharmony_ci		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
30362306a36Sopenharmony_ci		if (rc)
30462306a36Sopenharmony_ci			goto fail_on;
30562306a36Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	for (i = 0; i < 20; ++i) {
30962306a36Sopenharmony_ci		/* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
31062306a36Sopenharmony_ci		out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
31162306a36Sopenharmony_ci			       (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
31262306a36Sopenharmony_ci			       (1 << P0_X_TRST_LBN));
31362306a36Sopenharmony_ci		if (efx->phy_mode & PHY_MODE_SPECIAL)
31462306a36Sopenharmony_ci			out |= 1 << P0_EN_3V3X_LBN;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
31762306a36Sopenharmony_ci		if (rc)
31862306a36Sopenharmony_ci			goto fail_on;
31962306a36Sopenharmony_ci		msleep(10);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci		/* Turn on 1V power rail */
32262306a36Sopenharmony_ci		out &= ~(1 << P0_EN_1V0X_LBN);
32362306a36Sopenharmony_ci		rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
32462306a36Sopenharmony_ci		if (rc)
32562306a36Sopenharmony_ci			goto fail_on;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		netif_info(efx, hw, efx->net_dev,
32862306a36Sopenharmony_ci			   "waiting for DSP boot (attempt %d)...\n", i);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci		/* In flash config mode, DSP does not turn on AFE, so
33162306a36Sopenharmony_ci		 * just wait 1 second.
33262306a36Sopenharmony_ci		 */
33362306a36Sopenharmony_ci		if (efx->phy_mode & PHY_MODE_SPECIAL) {
33462306a36Sopenharmony_ci			schedule_timeout_uninterruptible(HZ);
33562306a36Sopenharmony_ci			return 0;
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci		for (j = 0; j < 10; ++j) {
33962306a36Sopenharmony_ci			msleep(100);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci			/* Check DSP has asserted AFE power line */
34262306a36Sopenharmony_ci			rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN);
34362306a36Sopenharmony_ci			if (rc < 0)
34462306a36Sopenharmony_ci				goto fail_on;
34562306a36Sopenharmony_ci			if (rc & (1 << P1_AFE_PWD_LBN))
34662306a36Sopenharmony_ci				return 0;
34762306a36Sopenharmony_ci		}
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	netif_info(efx, hw, efx->net_dev, "timed out waiting for DSP boot\n");
35162306a36Sopenharmony_ci	rc = -ETIMEDOUT;
35262306a36Sopenharmony_cifail_on:
35362306a36Sopenharmony_ci	sfe4001_poweroff(efx);
35462306a36Sopenharmony_ci	return rc;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic ssize_t phy_flash_cfg_show(struct device *dev,
35862306a36Sopenharmony_ci				  struct device_attribute *attr, char *buf)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct ef4_nic *efx = dev_get_drvdata(dev);
36162306a36Sopenharmony_ci	return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL));
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic ssize_t phy_flash_cfg_store(struct device *dev,
36562306a36Sopenharmony_ci				   struct device_attribute *attr,
36662306a36Sopenharmony_ci				   const char *buf, size_t count)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct ef4_nic *efx = dev_get_drvdata(dev);
36962306a36Sopenharmony_ci	enum ef4_phy_mode old_mode, new_mode;
37062306a36Sopenharmony_ci	int err;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	rtnl_lock();
37362306a36Sopenharmony_ci	old_mode = efx->phy_mode;
37462306a36Sopenharmony_ci	if (count == 0 || *buf == '0')
37562306a36Sopenharmony_ci		new_mode = old_mode & ~PHY_MODE_SPECIAL;
37662306a36Sopenharmony_ci	else
37762306a36Sopenharmony_ci		new_mode = PHY_MODE_SPECIAL;
37862306a36Sopenharmony_ci	if (!((old_mode ^ new_mode) & PHY_MODE_SPECIAL)) {
37962306a36Sopenharmony_ci		err = 0;
38062306a36Sopenharmony_ci	} else if (efx->state != STATE_READY || netif_running(efx->net_dev)) {
38162306a36Sopenharmony_ci		err = -EBUSY;
38262306a36Sopenharmony_ci	} else {
38362306a36Sopenharmony_ci		/* Reset the PHY, reconfigure the MAC and enable/disable
38462306a36Sopenharmony_ci		 * MAC stats accordingly. */
38562306a36Sopenharmony_ci		efx->phy_mode = new_mode;
38662306a36Sopenharmony_ci		if (new_mode & PHY_MODE_SPECIAL)
38762306a36Sopenharmony_ci			falcon_stop_nic_stats(efx);
38862306a36Sopenharmony_ci		err = sfe4001_poweron(efx);
38962306a36Sopenharmony_ci		if (!err)
39062306a36Sopenharmony_ci			err = ef4_reconfigure_port(efx);
39162306a36Sopenharmony_ci		if (!(new_mode & PHY_MODE_SPECIAL))
39262306a36Sopenharmony_ci			falcon_start_nic_stats(efx);
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci	rtnl_unlock();
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return err ? err : count;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic DEVICE_ATTR_RW(phy_flash_cfg);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic void sfe4001_fini(struct ef4_nic *efx)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct falcon_board *board = falcon_board(efx);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	netif_info(efx, drv, efx->net_dev, "%s\n", __func__);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
40862306a36Sopenharmony_ci	sfe4001_poweroff(efx);
40962306a36Sopenharmony_ci	i2c_unregister_device(board->ioexp_client);
41062306a36Sopenharmony_ci	i2c_unregister_device(board->hwmon_client);
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic int sfe4001_check_hw(struct ef4_nic *efx)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	struct falcon_nic_data *nic_data = efx->nic_data;
41662306a36Sopenharmony_ci	s32 status;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* If XAUI link is up then do not monitor */
41962306a36Sopenharmony_ci	if (EF4_WORKAROUND_7884(efx) && !nic_data->xmac_poll_required)
42062306a36Sopenharmony_ci		return 0;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* Check the powered status of the PHY. Lack of power implies that
42362306a36Sopenharmony_ci	 * the MAX6647 has shut down power to it, probably due to a temp.
42462306a36Sopenharmony_ci	 * alarm. Reading the power status rather than the MAX6647 status
42562306a36Sopenharmony_ci	 * directly because the later is read-to-clear and would thus
42662306a36Sopenharmony_ci	 * start to power up the PHY again when polled, causing us to blip
42762306a36Sopenharmony_ci	 * the power undesirably.
42862306a36Sopenharmony_ci	 * We know we can read from the IO expander because we did
42962306a36Sopenharmony_ci	 * it during power-on. Assume failure now is bad news. */
43062306a36Sopenharmony_ci	status = i2c_smbus_read_byte_data(falcon_board(efx)->ioexp_client, P1_IN);
43162306a36Sopenharmony_ci	if (status >= 0 &&
43262306a36Sopenharmony_ci	    (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0)
43362306a36Sopenharmony_ci		return 0;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* Use board power control, not PHY power control */
43662306a36Sopenharmony_ci	sfe4001_poweroff(efx);
43762306a36Sopenharmony_ci	efx->phy_mode = PHY_MODE_OFF;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	return (status < 0) ? -EIO : -ERANGE;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic const struct i2c_board_info sfe4001_hwmon_info = {
44362306a36Sopenharmony_ci	I2C_BOARD_INFO("max6647", 0x4e),
44462306a36Sopenharmony_ci};
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci/* This board uses an I2C expander to provider power to the PHY, which needs to
44762306a36Sopenharmony_ci * be turned on before the PHY can be used.
44862306a36Sopenharmony_ci * Context: Process context, rtnl lock held
44962306a36Sopenharmony_ci */
45062306a36Sopenharmony_cistatic int sfe4001_init(struct ef4_nic *efx)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	struct falcon_board *board = falcon_board(efx);
45362306a36Sopenharmony_ci	int rc;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SENSORS_LM90)
45662306a36Sopenharmony_ci	board->hwmon_client =
45762306a36Sopenharmony_ci		i2c_new_client_device(&board->i2c_adap, &sfe4001_hwmon_info);
45862306a36Sopenharmony_ci#else
45962306a36Sopenharmony_ci	board->hwmon_client =
46062306a36Sopenharmony_ci		i2c_new_dummy_device(&board->i2c_adap, sfe4001_hwmon_info.addr);
46162306a36Sopenharmony_ci#endif
46262306a36Sopenharmony_ci	if (IS_ERR(board->hwmon_client))
46362306a36Sopenharmony_ci		return PTR_ERR(board->hwmon_client);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	/* Raise board/PHY high limit from 85 to 90 degrees Celsius */
46662306a36Sopenharmony_ci	rc = i2c_smbus_write_byte_data(board->hwmon_client,
46762306a36Sopenharmony_ci				       MAX664X_REG_WLHO, 90);
46862306a36Sopenharmony_ci	if (rc)
46962306a36Sopenharmony_ci		goto fail_hwmon;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	board->ioexp_client = i2c_new_dummy_device(&board->i2c_adap, PCA9539);
47262306a36Sopenharmony_ci	if (IS_ERR(board->ioexp_client)) {
47362306a36Sopenharmony_ci		rc = PTR_ERR(board->ioexp_client);
47462306a36Sopenharmony_ci		goto fail_hwmon;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (efx->phy_mode & PHY_MODE_SPECIAL) {
47862306a36Sopenharmony_ci		/* PHY won't generate a 156.25 MHz clock and MAC stats fetch
47962306a36Sopenharmony_ci		 * will fail. */
48062306a36Sopenharmony_ci		falcon_stop_nic_stats(efx);
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci	rc = sfe4001_poweron(efx);
48362306a36Sopenharmony_ci	if (rc)
48462306a36Sopenharmony_ci		goto fail_ioexp;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
48762306a36Sopenharmony_ci	if (rc)
48862306a36Sopenharmony_ci		goto fail_on;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	netif_info(efx, hw, efx->net_dev, "PHY is powered on\n");
49162306a36Sopenharmony_ci	return 0;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cifail_on:
49462306a36Sopenharmony_ci	sfe4001_poweroff(efx);
49562306a36Sopenharmony_cifail_ioexp:
49662306a36Sopenharmony_ci	i2c_unregister_device(board->ioexp_client);
49762306a36Sopenharmony_cifail_hwmon:
49862306a36Sopenharmony_ci	i2c_unregister_device(board->hwmon_client);
49962306a36Sopenharmony_ci	return rc;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci/*****************************************************************************
50362306a36Sopenharmony_ci * Support for the SFE4002
50462306a36Sopenharmony_ci *
50562306a36Sopenharmony_ci */
50662306a36Sopenharmony_cistatic u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic const u8 sfe4002_lm87_regs[] = {
50962306a36Sopenharmony_ci	LM87_IN_LIMITS(0, 0x7c, 0x99),		/* 2.5V:  1.8V +/- 10% */
51062306a36Sopenharmony_ci	LM87_IN_LIMITS(1, 0x4c, 0x5e),		/* Vccp1: 1.2V +/- 10% */
51162306a36Sopenharmony_ci	LM87_IN_LIMITS(2, 0xac, 0xd4),		/* 3.3V:  3.3V +/- 10% */
51262306a36Sopenharmony_ci	LM87_IN_LIMITS(3, 0xac, 0xd4),		/* 5V:    5.0V +/- 10% */
51362306a36Sopenharmony_ci	LM87_IN_LIMITS(4, 0xac, 0xe0),		/* 12V:   10.8-14V */
51462306a36Sopenharmony_ci	LM87_IN_LIMITS(5, 0x3f, 0x4f),		/* Vccp2: 1.0V +/- 10% */
51562306a36Sopenharmony_ci	LM87_AIN_LIMITS(0, 0x98, 0xbb),		/* AIN1:  1.66V +/- 10% */
51662306a36Sopenharmony_ci	LM87_AIN_LIMITS(1, 0x8a, 0xa9),		/* AIN2:  1.5V +/- 10% */
51762306a36Sopenharmony_ci	LM87_TEMP_INT_LIMITS(0, 80 + FALCON_BOARD_TEMP_BIAS),
51862306a36Sopenharmony_ci	LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX),
51962306a36Sopenharmony_ci	0
52062306a36Sopenharmony_ci};
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic const struct i2c_board_info sfe4002_hwmon_info = {
52362306a36Sopenharmony_ci	I2C_BOARD_INFO("lm87", 0x2e),
52462306a36Sopenharmony_ci	.platform_data	= &sfe4002_lm87_channel,
52562306a36Sopenharmony_ci};
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci/****************************************************************************/
52862306a36Sopenharmony_ci/* LED allocations. Note that on rev A0 boards the schematic and the reality
52962306a36Sopenharmony_ci * differ: red and green are swapped. Below is the fixed (A1) layout (there
53062306a36Sopenharmony_ci * are only 3 A0 boards in existence, so no real reason to make this
53162306a36Sopenharmony_ci * conditional).
53262306a36Sopenharmony_ci */
53362306a36Sopenharmony_ci#define SFE4002_FAULT_LED (2)	/* Red */
53462306a36Sopenharmony_ci#define SFE4002_RX_LED    (0)	/* Green */
53562306a36Sopenharmony_ci#define SFE4002_TX_LED    (1)	/* Amber */
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic void sfe4002_init_phy(struct ef4_nic *efx)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	/* Set the TX and RX LEDs to reflect status and activity, and the
54062306a36Sopenharmony_ci	 * fault LED off */
54162306a36Sopenharmony_ci	falcon_qt202x_set_led(efx, SFE4002_TX_LED,
54262306a36Sopenharmony_ci			      QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
54362306a36Sopenharmony_ci	falcon_qt202x_set_led(efx, SFE4002_RX_LED,
54462306a36Sopenharmony_ci			      QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
54562306a36Sopenharmony_ci	falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic void sfe4002_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	falcon_qt202x_set_led(
55162306a36Sopenharmony_ci		efx, SFE4002_FAULT_LED,
55262306a36Sopenharmony_ci		(mode == EF4_LED_ON) ? QUAKE_LED_ON : QUAKE_LED_OFF);
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic int sfe4002_check_hw(struct ef4_nic *efx)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	struct falcon_board *board = falcon_board(efx);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* A0 board rev. 4002s report a temperature fault the whole time
56062306a36Sopenharmony_ci	 * (bad sensor) so we mask it out. */
56162306a36Sopenharmony_ci	unsigned alarm_mask =
56262306a36Sopenharmony_ci		(board->major == 0 && board->minor == 0) ?
56362306a36Sopenharmony_ci		~LM87_ALARM_TEMP_EXT1 : ~0;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	return ef4_check_lm87(efx, alarm_mask);
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic int sfe4002_init(struct ef4_nic *efx)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	return ef4_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/*****************************************************************************
57462306a36Sopenharmony_ci * Support for the SFN4112F
57562306a36Sopenharmony_ci *
57662306a36Sopenharmony_ci */
57762306a36Sopenharmony_cistatic u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic const u8 sfn4112f_lm87_regs[] = {
58062306a36Sopenharmony_ci	LM87_IN_LIMITS(0, 0x7c, 0x99),		/* 2.5V:  1.8V +/- 10% */
58162306a36Sopenharmony_ci	LM87_IN_LIMITS(1, 0x4c, 0x5e),		/* Vccp1: 1.2V +/- 10% */
58262306a36Sopenharmony_ci	LM87_IN_LIMITS(2, 0xac, 0xd4),		/* 3.3V:  3.3V +/- 10% */
58362306a36Sopenharmony_ci	LM87_IN_LIMITS(4, 0xac, 0xe0),		/* 12V:   10.8-14V */
58462306a36Sopenharmony_ci	LM87_IN_LIMITS(5, 0x3f, 0x4f),		/* Vccp2: 1.0V +/- 10% */
58562306a36Sopenharmony_ci	LM87_AIN_LIMITS(1, 0x8a, 0xa9),		/* AIN2:  1.5V +/- 10% */
58662306a36Sopenharmony_ci	LM87_TEMP_INT_LIMITS(0, 60 + FALCON_BOARD_TEMP_BIAS),
58762306a36Sopenharmony_ci	LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX),
58862306a36Sopenharmony_ci	0
58962306a36Sopenharmony_ci};
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic const struct i2c_board_info sfn4112f_hwmon_info = {
59262306a36Sopenharmony_ci	I2C_BOARD_INFO("lm87", 0x2e),
59362306a36Sopenharmony_ci	.platform_data	= &sfn4112f_lm87_channel,
59462306a36Sopenharmony_ci};
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci#define SFN4112F_ACT_LED	0
59762306a36Sopenharmony_ci#define SFN4112F_LINK_LED	1
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic void sfn4112f_init_phy(struct ef4_nic *efx)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	falcon_qt202x_set_led(efx, SFN4112F_ACT_LED,
60262306a36Sopenharmony_ci			      QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT);
60362306a36Sopenharmony_ci	falcon_qt202x_set_led(efx, SFN4112F_LINK_LED,
60462306a36Sopenharmony_ci			      QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT);
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic void sfn4112f_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	int reg;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	switch (mode) {
61262306a36Sopenharmony_ci	case EF4_LED_OFF:
61362306a36Sopenharmony_ci		reg = QUAKE_LED_OFF;
61462306a36Sopenharmony_ci		break;
61562306a36Sopenharmony_ci	case EF4_LED_ON:
61662306a36Sopenharmony_ci		reg = QUAKE_LED_ON;
61762306a36Sopenharmony_ci		break;
61862306a36Sopenharmony_ci	default:
61962306a36Sopenharmony_ci		reg = QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT;
62062306a36Sopenharmony_ci		break;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, reg);
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic int sfn4112f_check_hw(struct ef4_nic *efx)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	/* Mask out unused sensors */
62962306a36Sopenharmony_ci	return ef4_check_lm87(efx, ~0x48);
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic int sfn4112f_init(struct ef4_nic *efx)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	return ef4_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs);
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci/*****************************************************************************
63862306a36Sopenharmony_ci * Support for the SFE4003
63962306a36Sopenharmony_ci *
64062306a36Sopenharmony_ci */
64162306a36Sopenharmony_cistatic u8 sfe4003_lm87_channel = 0x03; /* use AIN not FAN inputs */
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cistatic const u8 sfe4003_lm87_regs[] = {
64462306a36Sopenharmony_ci	LM87_IN_LIMITS(0, 0x67, 0x7f),		/* 2.5V:  1.5V +/- 10% */
64562306a36Sopenharmony_ci	LM87_IN_LIMITS(1, 0x4c, 0x5e),		/* Vccp1: 1.2V +/- 10% */
64662306a36Sopenharmony_ci	LM87_IN_LIMITS(2, 0xac, 0xd4),		/* 3.3V:  3.3V +/- 10% */
64762306a36Sopenharmony_ci	LM87_IN_LIMITS(4, 0xac, 0xe0),		/* 12V:   10.8-14V */
64862306a36Sopenharmony_ci	LM87_IN_LIMITS(5, 0x3f, 0x4f),		/* Vccp2: 1.0V +/- 10% */
64962306a36Sopenharmony_ci	LM87_TEMP_INT_LIMITS(0, 70 + FALCON_BOARD_TEMP_BIAS),
65062306a36Sopenharmony_ci	0
65162306a36Sopenharmony_ci};
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic const struct i2c_board_info sfe4003_hwmon_info = {
65462306a36Sopenharmony_ci	I2C_BOARD_INFO("lm87", 0x2e),
65562306a36Sopenharmony_ci	.platform_data	= &sfe4003_lm87_channel,
65662306a36Sopenharmony_ci};
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci/* Board-specific LED info. */
65962306a36Sopenharmony_ci#define SFE4003_RED_LED_GPIO	11
66062306a36Sopenharmony_ci#define SFE4003_LED_ON		1
66162306a36Sopenharmony_ci#define SFE4003_LED_OFF		0
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_cistatic void sfe4003_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	struct falcon_board *board = falcon_board(efx);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	/* The LEDs were not wired to GPIOs before A3 */
66862306a36Sopenharmony_ci	if (board->minor < 3 && board->major == 0)
66962306a36Sopenharmony_ci		return;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	falcon_txc_set_gpio_val(
67262306a36Sopenharmony_ci		efx, SFE4003_RED_LED_GPIO,
67362306a36Sopenharmony_ci		(mode == EF4_LED_ON) ? SFE4003_LED_ON : SFE4003_LED_OFF);
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cistatic void sfe4003_init_phy(struct ef4_nic *efx)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	struct falcon_board *board = falcon_board(efx);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	/* The LEDs were not wired to GPIOs before A3 */
68162306a36Sopenharmony_ci	if (board->minor < 3 && board->major == 0)
68262306a36Sopenharmony_ci		return;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	falcon_txc_set_gpio_dir(efx, SFE4003_RED_LED_GPIO, TXC_GPIO_DIR_OUTPUT);
68562306a36Sopenharmony_ci	falcon_txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO, SFE4003_LED_OFF);
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cistatic int sfe4003_check_hw(struct ef4_nic *efx)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	struct falcon_board *board = falcon_board(efx);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/* A0/A1/A2 board rev. 4003s  report a temperature fault the whole time
69362306a36Sopenharmony_ci	 * (bad sensor) so we mask it out. */
69462306a36Sopenharmony_ci	unsigned alarm_mask =
69562306a36Sopenharmony_ci		(board->major == 0 && board->minor <= 2) ?
69662306a36Sopenharmony_ci		~LM87_ALARM_TEMP_EXT1 : ~0;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	return ef4_check_lm87(efx, alarm_mask);
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic int sfe4003_init(struct ef4_nic *efx)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	return ef4_init_lm87(efx, &sfe4003_hwmon_info, sfe4003_lm87_regs);
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic const struct falcon_board_type board_types[] = {
70762306a36Sopenharmony_ci	{
70862306a36Sopenharmony_ci		.id		= FALCON_BOARD_SFE4001,
70962306a36Sopenharmony_ci		.init		= sfe4001_init,
71062306a36Sopenharmony_ci		.init_phy	= ef4_port_dummy_op_void,
71162306a36Sopenharmony_ci		.fini		= sfe4001_fini,
71262306a36Sopenharmony_ci		.set_id_led	= tenxpress_set_id_led,
71362306a36Sopenharmony_ci		.monitor	= sfe4001_check_hw,
71462306a36Sopenharmony_ci	},
71562306a36Sopenharmony_ci	{
71662306a36Sopenharmony_ci		.id		= FALCON_BOARD_SFE4002,
71762306a36Sopenharmony_ci		.init		= sfe4002_init,
71862306a36Sopenharmony_ci		.init_phy	= sfe4002_init_phy,
71962306a36Sopenharmony_ci		.fini		= ef4_fini_lm87,
72062306a36Sopenharmony_ci		.set_id_led	= sfe4002_set_id_led,
72162306a36Sopenharmony_ci		.monitor	= sfe4002_check_hw,
72262306a36Sopenharmony_ci	},
72362306a36Sopenharmony_ci	{
72462306a36Sopenharmony_ci		.id		= FALCON_BOARD_SFE4003,
72562306a36Sopenharmony_ci		.init		= sfe4003_init,
72662306a36Sopenharmony_ci		.init_phy	= sfe4003_init_phy,
72762306a36Sopenharmony_ci		.fini		= ef4_fini_lm87,
72862306a36Sopenharmony_ci		.set_id_led	= sfe4003_set_id_led,
72962306a36Sopenharmony_ci		.monitor	= sfe4003_check_hw,
73062306a36Sopenharmony_ci	},
73162306a36Sopenharmony_ci	{
73262306a36Sopenharmony_ci		.id		= FALCON_BOARD_SFN4112F,
73362306a36Sopenharmony_ci		.init		= sfn4112f_init,
73462306a36Sopenharmony_ci		.init_phy	= sfn4112f_init_phy,
73562306a36Sopenharmony_ci		.fini		= ef4_fini_lm87,
73662306a36Sopenharmony_ci		.set_id_led	= sfn4112f_set_id_led,
73762306a36Sopenharmony_ci		.monitor	= sfn4112f_check_hw,
73862306a36Sopenharmony_ci	},
73962306a36Sopenharmony_ci};
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ciint falcon_probe_board(struct ef4_nic *efx, u16 revision_info)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	struct falcon_board *board = falcon_board(efx);
74462306a36Sopenharmony_ci	u8 type_id = FALCON_BOARD_TYPE(revision_info);
74562306a36Sopenharmony_ci	int i;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	board->major = FALCON_BOARD_MAJOR(revision_info);
74862306a36Sopenharmony_ci	board->minor = FALCON_BOARD_MINOR(revision_info);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(board_types); i++)
75162306a36Sopenharmony_ci		if (board_types[i].id == type_id)
75262306a36Sopenharmony_ci			board->type = &board_types[i];
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	if (board->type) {
75562306a36Sopenharmony_ci		return 0;
75662306a36Sopenharmony_ci	} else {
75762306a36Sopenharmony_ci		netif_err(efx, probe, efx->net_dev, "unknown board type %d\n",
75862306a36Sopenharmony_ci			  type_id);
75962306a36Sopenharmony_ci		return -ENODEV;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci}
762