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