18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/**************************************************************************** 38c2ecf20Sopenharmony_ci * Driver for Solarflare network controllers and boards 48c2ecf20Sopenharmony_ci * Copyright 2007-2012 Solarflare Communications Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "net_driver.h" 108c2ecf20Sopenharmony_ci#include "phy.h" 118c2ecf20Sopenharmony_ci#include "efx.h" 128c2ecf20Sopenharmony_ci#include "nic.h" 138c2ecf20Sopenharmony_ci#include "workarounds.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* Macros for unpacking the board revision */ 168c2ecf20Sopenharmony_ci/* The revision info is in host byte order. */ 178c2ecf20Sopenharmony_ci#define FALCON_BOARD_TYPE(_rev) (_rev >> 8) 188c2ecf20Sopenharmony_ci#define FALCON_BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf) 198c2ecf20Sopenharmony_ci#define FALCON_BOARD_MINOR(_rev) (_rev & 0xf) 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Board types */ 228c2ecf20Sopenharmony_ci#define FALCON_BOARD_SFE4001 0x01 238c2ecf20Sopenharmony_ci#define FALCON_BOARD_SFE4002 0x02 248c2ecf20Sopenharmony_ci#define FALCON_BOARD_SFE4003 0x03 258c2ecf20Sopenharmony_ci#define FALCON_BOARD_SFN4112F 0x52 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* Board temperature is about 15°C above ambient when air flow is 288c2ecf20Sopenharmony_ci * limited. The maximum acceptable ambient temperature varies 298c2ecf20Sopenharmony_ci * depending on the PHY specifications but the critical temperature 308c2ecf20Sopenharmony_ci * above which we should shut down to avoid damage is 80°C. */ 318c2ecf20Sopenharmony_ci#define FALCON_BOARD_TEMP_BIAS 15 328c2ecf20Sopenharmony_ci#define FALCON_BOARD_TEMP_CRIT (80 + FALCON_BOARD_TEMP_BIAS) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* SFC4000 datasheet says: 'The maximum permitted junction temperature 358c2ecf20Sopenharmony_ci * is 125°C; the thermal design of the environment for the SFC4000 368c2ecf20Sopenharmony_ci * should aim to keep this well below 100°C.' */ 378c2ecf20Sopenharmony_ci#define FALCON_JUNC_TEMP_MIN 0 388c2ecf20Sopenharmony_ci#define FALCON_JUNC_TEMP_MAX 90 398c2ecf20Sopenharmony_ci#define FALCON_JUNC_TEMP_CRIT 125 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/***************************************************************************** 428c2ecf20Sopenharmony_ci * Support for LM87 sensor chip used on several boards 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ci#define LM87_REG_TEMP_HW_INT_LOCK 0x13 458c2ecf20Sopenharmony_ci#define LM87_REG_TEMP_HW_EXT_LOCK 0x14 468c2ecf20Sopenharmony_ci#define LM87_REG_TEMP_HW_INT 0x17 478c2ecf20Sopenharmony_ci#define LM87_REG_TEMP_HW_EXT 0x18 488c2ecf20Sopenharmony_ci#define LM87_REG_TEMP_EXT1 0x26 498c2ecf20Sopenharmony_ci#define LM87_REG_TEMP_INT 0x27 508c2ecf20Sopenharmony_ci#define LM87_REG_ALARMS1 0x41 518c2ecf20Sopenharmony_ci#define LM87_REG_ALARMS2 0x42 528c2ecf20Sopenharmony_ci#define LM87_IN_LIMITS(nr, _min, _max) \ 538c2ecf20Sopenharmony_ci 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min 548c2ecf20Sopenharmony_ci#define LM87_AIN_LIMITS(nr, _min, _max) \ 558c2ecf20Sopenharmony_ci 0x3B + (nr), _max, 0x1A + (nr), _min 568c2ecf20Sopenharmony_ci#define LM87_TEMP_INT_LIMITS(_min, _max) \ 578c2ecf20Sopenharmony_ci 0x39, _max, 0x3A, _min 588c2ecf20Sopenharmony_ci#define LM87_TEMP_EXT1_LIMITS(_min, _max) \ 598c2ecf20Sopenharmony_ci 0x37, _max, 0x38, _min 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define LM87_ALARM_TEMP_INT 0x10 628c2ecf20Sopenharmony_ci#define LM87_ALARM_TEMP_EXT1 0x20 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SENSORS_LM87) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int ef4_poke_lm87(struct i2c_client *client, const u8 *reg_values) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci while (*reg_values) { 698c2ecf20Sopenharmony_ci u8 reg = *reg_values++; 708c2ecf20Sopenharmony_ci u8 value = *reg_values++; 718c2ecf20Sopenharmony_ci int rc = i2c_smbus_write_byte_data(client, reg, value); 728c2ecf20Sopenharmony_ci if (rc) 738c2ecf20Sopenharmony_ci return rc; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic const u8 falcon_lm87_common_regs[] = { 798c2ecf20Sopenharmony_ci LM87_REG_TEMP_HW_INT_LOCK, FALCON_BOARD_TEMP_CRIT, 808c2ecf20Sopenharmony_ci LM87_REG_TEMP_HW_INT, FALCON_BOARD_TEMP_CRIT, 818c2ecf20Sopenharmony_ci LM87_TEMP_EXT1_LIMITS(FALCON_JUNC_TEMP_MIN, FALCON_JUNC_TEMP_MAX), 828c2ecf20Sopenharmony_ci LM87_REG_TEMP_HW_EXT_LOCK, FALCON_JUNC_TEMP_CRIT, 838c2ecf20Sopenharmony_ci LM87_REG_TEMP_HW_EXT, FALCON_JUNC_TEMP_CRIT, 848c2ecf20Sopenharmony_ci 0 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int ef4_init_lm87(struct ef4_nic *efx, const struct i2c_board_info *info, 888c2ecf20Sopenharmony_ci const u8 *reg_values) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct falcon_board *board = falcon_board(efx); 918c2ecf20Sopenharmony_ci struct i2c_client *client = i2c_new_client_device(&board->i2c_adap, info); 928c2ecf20Sopenharmony_ci int rc; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (IS_ERR(client)) 958c2ecf20Sopenharmony_ci return PTR_ERR(client); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* Read-to-clear alarm/interrupt status */ 988c2ecf20Sopenharmony_ci i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); 998c2ecf20Sopenharmony_ci i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci rc = ef4_poke_lm87(client, reg_values); 1028c2ecf20Sopenharmony_ci if (rc) 1038c2ecf20Sopenharmony_ci goto err; 1048c2ecf20Sopenharmony_ci rc = ef4_poke_lm87(client, falcon_lm87_common_regs); 1058c2ecf20Sopenharmony_ci if (rc) 1068c2ecf20Sopenharmony_ci goto err; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci board->hwmon_client = client; 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cierr: 1128c2ecf20Sopenharmony_ci i2c_unregister_device(client); 1138c2ecf20Sopenharmony_ci return rc; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void ef4_fini_lm87(struct ef4_nic *efx) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci i2c_unregister_device(falcon_board(efx)->hwmon_client); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int ef4_check_lm87(struct ef4_nic *efx, unsigned mask) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct i2c_client *client = falcon_board(efx)->hwmon_client; 1248c2ecf20Sopenharmony_ci bool temp_crit, elec_fault, is_failure; 1258c2ecf20Sopenharmony_ci u16 alarms; 1268c2ecf20Sopenharmony_ci s32 reg; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* If link is up then do not monitor temperature */ 1298c2ecf20Sopenharmony_ci if (EF4_WORKAROUND_7884(efx) && efx->link_state.up) 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci reg = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); 1338c2ecf20Sopenharmony_ci if (reg < 0) 1348c2ecf20Sopenharmony_ci return reg; 1358c2ecf20Sopenharmony_ci alarms = reg; 1368c2ecf20Sopenharmony_ci reg = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); 1378c2ecf20Sopenharmony_ci if (reg < 0) 1388c2ecf20Sopenharmony_ci return reg; 1398c2ecf20Sopenharmony_ci alarms |= reg << 8; 1408c2ecf20Sopenharmony_ci alarms &= mask; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci temp_crit = false; 1438c2ecf20Sopenharmony_ci if (alarms & LM87_ALARM_TEMP_INT) { 1448c2ecf20Sopenharmony_ci reg = i2c_smbus_read_byte_data(client, LM87_REG_TEMP_INT); 1458c2ecf20Sopenharmony_ci if (reg < 0) 1468c2ecf20Sopenharmony_ci return reg; 1478c2ecf20Sopenharmony_ci if (reg > FALCON_BOARD_TEMP_CRIT) 1488c2ecf20Sopenharmony_ci temp_crit = true; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci if (alarms & LM87_ALARM_TEMP_EXT1) { 1518c2ecf20Sopenharmony_ci reg = i2c_smbus_read_byte_data(client, LM87_REG_TEMP_EXT1); 1528c2ecf20Sopenharmony_ci if (reg < 0) 1538c2ecf20Sopenharmony_ci return reg; 1548c2ecf20Sopenharmony_ci if (reg > FALCON_JUNC_TEMP_CRIT) 1558c2ecf20Sopenharmony_ci temp_crit = true; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci elec_fault = alarms & ~(LM87_ALARM_TEMP_INT | LM87_ALARM_TEMP_EXT1); 1588c2ecf20Sopenharmony_ci is_failure = temp_crit || elec_fault; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (alarms) 1618c2ecf20Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 1628c2ecf20Sopenharmony_ci "LM87 detected a hardware %s (status %02x:%02x)" 1638c2ecf20Sopenharmony_ci "%s%s%s%s\n", 1648c2ecf20Sopenharmony_ci is_failure ? "failure" : "problem", 1658c2ecf20Sopenharmony_ci alarms & 0xff, alarms >> 8, 1668c2ecf20Sopenharmony_ci (alarms & LM87_ALARM_TEMP_INT) ? 1678c2ecf20Sopenharmony_ci "; board is overheating" : "", 1688c2ecf20Sopenharmony_ci (alarms & LM87_ALARM_TEMP_EXT1) ? 1698c2ecf20Sopenharmony_ci "; controller is overheating" : "", 1708c2ecf20Sopenharmony_ci temp_crit ? "; reached critical temperature" : "", 1718c2ecf20Sopenharmony_ci elec_fault ? "; electrical fault" : ""); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return is_failure ? -ERANGE : 0; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#else /* !CONFIG_SENSORS_LM87 */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic inline int 1798c2ecf20Sopenharmony_cief4_init_lm87(struct ef4_nic *efx, const struct i2c_board_info *info, 1808c2ecf20Sopenharmony_ci const u8 *reg_values) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_cistatic inline void ef4_fini_lm87(struct ef4_nic *efx) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_cistatic inline int ef4_check_lm87(struct ef4_nic *efx, unsigned mask) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#endif /* CONFIG_SENSORS_LM87 */ 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/***************************************************************************** 1958c2ecf20Sopenharmony_ci * Support for the SFE4001 NIC. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * The SFE4001 does not power-up fully at reset due to its high power 1988c2ecf20Sopenharmony_ci * consumption. We control its power via a PCA9539 I/O expander. 1998c2ecf20Sopenharmony_ci * It also has a MAX6647 temperature monitor which we expose to 2008c2ecf20Sopenharmony_ci * the lm90 driver. 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * This also provides minimal support for reflashing the PHY, which is 2038c2ecf20Sopenharmony_ci * initiated by resetting it with the FLASH_CFG_1 pin pulled down. 2048c2ecf20Sopenharmony_ci * On SFE4001 rev A2 and later this is connected to the 3V3X output of 2058c2ecf20Sopenharmony_ci * the IO-expander. 2068c2ecf20Sopenharmony_ci * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually 2078c2ecf20Sopenharmony_ci * exclusive with the network device being open. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/************************************************************************** 2118c2ecf20Sopenharmony_ci * Support for I2C IO Expander device on SFE4001 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ci#define PCA9539 0x74 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci#define P0_IN 0x00 2168c2ecf20Sopenharmony_ci#define P0_OUT 0x02 2178c2ecf20Sopenharmony_ci#define P0_INVERT 0x04 2188c2ecf20Sopenharmony_ci#define P0_CONFIG 0x06 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci#define P0_EN_1V0X_LBN 0 2218c2ecf20Sopenharmony_ci#define P0_EN_1V0X_WIDTH 1 2228c2ecf20Sopenharmony_ci#define P0_EN_1V2_LBN 1 2238c2ecf20Sopenharmony_ci#define P0_EN_1V2_WIDTH 1 2248c2ecf20Sopenharmony_ci#define P0_EN_2V5_LBN 2 2258c2ecf20Sopenharmony_ci#define P0_EN_2V5_WIDTH 1 2268c2ecf20Sopenharmony_ci#define P0_EN_3V3X_LBN 3 2278c2ecf20Sopenharmony_ci#define P0_EN_3V3X_WIDTH 1 2288c2ecf20Sopenharmony_ci#define P0_EN_5V_LBN 4 2298c2ecf20Sopenharmony_ci#define P0_EN_5V_WIDTH 1 2308c2ecf20Sopenharmony_ci#define P0_SHORTEN_JTAG_LBN 5 2318c2ecf20Sopenharmony_ci#define P0_SHORTEN_JTAG_WIDTH 1 2328c2ecf20Sopenharmony_ci#define P0_X_TRST_LBN 6 2338c2ecf20Sopenharmony_ci#define P0_X_TRST_WIDTH 1 2348c2ecf20Sopenharmony_ci#define P0_DSP_RESET_LBN 7 2358c2ecf20Sopenharmony_ci#define P0_DSP_RESET_WIDTH 1 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#define P1_IN 0x01 2388c2ecf20Sopenharmony_ci#define P1_OUT 0x03 2398c2ecf20Sopenharmony_ci#define P1_INVERT 0x05 2408c2ecf20Sopenharmony_ci#define P1_CONFIG 0x07 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci#define P1_AFE_PWD_LBN 0 2438c2ecf20Sopenharmony_ci#define P1_AFE_PWD_WIDTH 1 2448c2ecf20Sopenharmony_ci#define P1_DSP_PWD25_LBN 1 2458c2ecf20Sopenharmony_ci#define P1_DSP_PWD25_WIDTH 1 2468c2ecf20Sopenharmony_ci#define P1_RESERVED_LBN 2 2478c2ecf20Sopenharmony_ci#define P1_RESERVED_WIDTH 2 2488c2ecf20Sopenharmony_ci#define P1_SPARE_LBN 4 2498c2ecf20Sopenharmony_ci#define P1_SPARE_WIDTH 4 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci/* Temperature Sensor */ 2528c2ecf20Sopenharmony_ci#define MAX664X_REG_RSL 0x02 2538c2ecf20Sopenharmony_ci#define MAX664X_REG_WLHO 0x0B 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic void sfe4001_poweroff(struct ef4_nic *efx) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; 2588c2ecf20Sopenharmony_ci struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Turn off all power rails and disable outputs */ 2618c2ecf20Sopenharmony_ci i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); 2628c2ecf20Sopenharmony_ci i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff); 2638c2ecf20Sopenharmony_ci i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Clear any over-temperature alert */ 2668c2ecf20Sopenharmony_ci i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int sfe4001_poweron(struct ef4_nic *efx) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; 2728c2ecf20Sopenharmony_ci struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; 2738c2ecf20Sopenharmony_ci unsigned int i, j; 2748c2ecf20Sopenharmony_ci int rc; 2758c2ecf20Sopenharmony_ci u8 out; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* Clear any previous over-temperature alert */ 2788c2ecf20Sopenharmony_ci rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); 2798c2ecf20Sopenharmony_ci if (rc < 0) 2808c2ecf20Sopenharmony_ci return rc; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* Enable port 0 and port 1 outputs on IO expander */ 2838c2ecf20Sopenharmony_ci rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); 2848c2ecf20Sopenharmony_ci if (rc) 2858c2ecf20Sopenharmony_ci return rc; 2868c2ecf20Sopenharmony_ci rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 2878c2ecf20Sopenharmony_ci 0xff & ~(1 << P1_SPARE_LBN)); 2888c2ecf20Sopenharmony_ci if (rc) 2898c2ecf20Sopenharmony_ci goto fail_on; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* If PHY power is on, turn it all off and wait 1 second to 2928c2ecf20Sopenharmony_ci * ensure a full reset. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT); 2958c2ecf20Sopenharmony_ci if (rc < 0) 2968c2ecf20Sopenharmony_ci goto fail_on; 2978c2ecf20Sopenharmony_ci out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | 2988c2ecf20Sopenharmony_ci (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | 2998c2ecf20Sopenharmony_ci (0 << P0_EN_1V0X_LBN)); 3008c2ecf20Sopenharmony_ci if (rc != out) { 3018c2ecf20Sopenharmony_ci netif_info(efx, hw, efx->net_dev, "power-cycling PHY\n"); 3028c2ecf20Sopenharmony_ci rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); 3038c2ecf20Sopenharmony_ci if (rc) 3048c2ecf20Sopenharmony_ci goto fail_on; 3058c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(HZ); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci for (i = 0; i < 20; ++i) { 3098c2ecf20Sopenharmony_ci /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ 3108c2ecf20Sopenharmony_ci out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | 3118c2ecf20Sopenharmony_ci (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | 3128c2ecf20Sopenharmony_ci (1 << P0_X_TRST_LBN)); 3138c2ecf20Sopenharmony_ci if (efx->phy_mode & PHY_MODE_SPECIAL) 3148c2ecf20Sopenharmony_ci out |= 1 << P0_EN_3V3X_LBN; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); 3178c2ecf20Sopenharmony_ci if (rc) 3188c2ecf20Sopenharmony_ci goto fail_on; 3198c2ecf20Sopenharmony_ci msleep(10); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* Turn on 1V power rail */ 3228c2ecf20Sopenharmony_ci out &= ~(1 << P0_EN_1V0X_LBN); 3238c2ecf20Sopenharmony_ci rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); 3248c2ecf20Sopenharmony_ci if (rc) 3258c2ecf20Sopenharmony_ci goto fail_on; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci netif_info(efx, hw, efx->net_dev, 3288c2ecf20Sopenharmony_ci "waiting for DSP boot (attempt %d)...\n", i); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* In flash config mode, DSP does not turn on AFE, so 3318c2ecf20Sopenharmony_ci * just wait 1 second. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ci if (efx->phy_mode & PHY_MODE_SPECIAL) { 3348c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(HZ); 3358c2ecf20Sopenharmony_ci return 0; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci for (j = 0; j < 10; ++j) { 3398c2ecf20Sopenharmony_ci msleep(100); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* Check DSP has asserted AFE power line */ 3428c2ecf20Sopenharmony_ci rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); 3438c2ecf20Sopenharmony_ci if (rc < 0) 3448c2ecf20Sopenharmony_ci goto fail_on; 3458c2ecf20Sopenharmony_ci if (rc & (1 << P1_AFE_PWD_LBN)) 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci netif_info(efx, hw, efx->net_dev, "timed out waiting for DSP boot\n"); 3518c2ecf20Sopenharmony_ci rc = -ETIMEDOUT; 3528c2ecf20Sopenharmony_cifail_on: 3538c2ecf20Sopenharmony_ci sfe4001_poweroff(efx); 3548c2ecf20Sopenharmony_ci return rc; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic ssize_t show_phy_flash_cfg(struct device *dev, 3588c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct ef4_nic *efx = dev_get_drvdata(dev); 3618c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL)); 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic ssize_t set_phy_flash_cfg(struct device *dev, 3658c2ecf20Sopenharmony_ci struct device_attribute *attr, 3668c2ecf20Sopenharmony_ci const char *buf, size_t count) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct ef4_nic *efx = dev_get_drvdata(dev); 3698c2ecf20Sopenharmony_ci enum ef4_phy_mode old_mode, new_mode; 3708c2ecf20Sopenharmony_ci int err; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci rtnl_lock(); 3738c2ecf20Sopenharmony_ci old_mode = efx->phy_mode; 3748c2ecf20Sopenharmony_ci if (count == 0 || *buf == '0') 3758c2ecf20Sopenharmony_ci new_mode = old_mode & ~PHY_MODE_SPECIAL; 3768c2ecf20Sopenharmony_ci else 3778c2ecf20Sopenharmony_ci new_mode = PHY_MODE_SPECIAL; 3788c2ecf20Sopenharmony_ci if (!((old_mode ^ new_mode) & PHY_MODE_SPECIAL)) { 3798c2ecf20Sopenharmony_ci err = 0; 3808c2ecf20Sopenharmony_ci } else if (efx->state != STATE_READY || netif_running(efx->net_dev)) { 3818c2ecf20Sopenharmony_ci err = -EBUSY; 3828c2ecf20Sopenharmony_ci } else { 3838c2ecf20Sopenharmony_ci /* Reset the PHY, reconfigure the MAC and enable/disable 3848c2ecf20Sopenharmony_ci * MAC stats accordingly. */ 3858c2ecf20Sopenharmony_ci efx->phy_mode = new_mode; 3868c2ecf20Sopenharmony_ci if (new_mode & PHY_MODE_SPECIAL) 3878c2ecf20Sopenharmony_ci falcon_stop_nic_stats(efx); 3888c2ecf20Sopenharmony_ci err = sfe4001_poweron(efx); 3898c2ecf20Sopenharmony_ci if (!err) 3908c2ecf20Sopenharmony_ci err = ef4_reconfigure_port(efx); 3918c2ecf20Sopenharmony_ci if (!(new_mode & PHY_MODE_SPECIAL)) 3928c2ecf20Sopenharmony_ci falcon_start_nic_stats(efx); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci rtnl_unlock(); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return err ? err : count; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic void sfe4001_fini(struct ef4_nic *efx) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct falcon_board *board = falcon_board(efx); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci netif_info(efx, drv, efx->net_dev, "%s\n", __func__); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); 4088c2ecf20Sopenharmony_ci sfe4001_poweroff(efx); 4098c2ecf20Sopenharmony_ci i2c_unregister_device(board->ioexp_client); 4108c2ecf20Sopenharmony_ci i2c_unregister_device(board->hwmon_client); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic int sfe4001_check_hw(struct ef4_nic *efx) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct falcon_nic_data *nic_data = efx->nic_data; 4168c2ecf20Sopenharmony_ci s32 status; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* If XAUI link is up then do not monitor */ 4198c2ecf20Sopenharmony_ci if (EF4_WORKAROUND_7884(efx) && !nic_data->xmac_poll_required) 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* Check the powered status of the PHY. Lack of power implies that 4238c2ecf20Sopenharmony_ci * the MAX6647 has shut down power to it, probably due to a temp. 4248c2ecf20Sopenharmony_ci * alarm. Reading the power status rather than the MAX6647 status 4258c2ecf20Sopenharmony_ci * directly because the later is read-to-clear and would thus 4268c2ecf20Sopenharmony_ci * start to power up the PHY again when polled, causing us to blip 4278c2ecf20Sopenharmony_ci * the power undesirably. 4288c2ecf20Sopenharmony_ci * We know we can read from the IO expander because we did 4298c2ecf20Sopenharmony_ci * it during power-on. Assume failure now is bad news. */ 4308c2ecf20Sopenharmony_ci status = i2c_smbus_read_byte_data(falcon_board(efx)->ioexp_client, P1_IN); 4318c2ecf20Sopenharmony_ci if (status >= 0 && 4328c2ecf20Sopenharmony_ci (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) 4338c2ecf20Sopenharmony_ci return 0; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* Use board power control, not PHY power control */ 4368c2ecf20Sopenharmony_ci sfe4001_poweroff(efx); 4378c2ecf20Sopenharmony_ci efx->phy_mode = PHY_MODE_OFF; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return (status < 0) ? -EIO : -ERANGE; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic const struct i2c_board_info sfe4001_hwmon_info = { 4438c2ecf20Sopenharmony_ci I2C_BOARD_INFO("max6647", 0x4e), 4448c2ecf20Sopenharmony_ci}; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* This board uses an I2C expander to provider power to the PHY, which needs to 4478c2ecf20Sopenharmony_ci * be turned on before the PHY can be used. 4488c2ecf20Sopenharmony_ci * Context: Process context, rtnl lock held 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_cistatic int sfe4001_init(struct ef4_nic *efx) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct falcon_board *board = falcon_board(efx); 4538c2ecf20Sopenharmony_ci int rc; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SENSORS_LM90) 4568c2ecf20Sopenharmony_ci board->hwmon_client = 4578c2ecf20Sopenharmony_ci i2c_new_client_device(&board->i2c_adap, &sfe4001_hwmon_info); 4588c2ecf20Sopenharmony_ci#else 4598c2ecf20Sopenharmony_ci board->hwmon_client = 4608c2ecf20Sopenharmony_ci i2c_new_dummy_device(&board->i2c_adap, sfe4001_hwmon_info.addr); 4618c2ecf20Sopenharmony_ci#endif 4628c2ecf20Sopenharmony_ci if (IS_ERR(board->hwmon_client)) 4638c2ecf20Sopenharmony_ci return PTR_ERR(board->hwmon_client); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ 4668c2ecf20Sopenharmony_ci rc = i2c_smbus_write_byte_data(board->hwmon_client, 4678c2ecf20Sopenharmony_ci MAX664X_REG_WLHO, 90); 4688c2ecf20Sopenharmony_ci if (rc) 4698c2ecf20Sopenharmony_ci goto fail_hwmon; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci board->ioexp_client = i2c_new_dummy_device(&board->i2c_adap, PCA9539); 4728c2ecf20Sopenharmony_ci if (IS_ERR(board->ioexp_client)) { 4738c2ecf20Sopenharmony_ci rc = PTR_ERR(board->ioexp_client); 4748c2ecf20Sopenharmony_ci goto fail_hwmon; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (efx->phy_mode & PHY_MODE_SPECIAL) { 4788c2ecf20Sopenharmony_ci /* PHY won't generate a 156.25 MHz clock and MAC stats fetch 4798c2ecf20Sopenharmony_ci * will fail. */ 4808c2ecf20Sopenharmony_ci falcon_stop_nic_stats(efx); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci rc = sfe4001_poweron(efx); 4838c2ecf20Sopenharmony_ci if (rc) 4848c2ecf20Sopenharmony_ci goto fail_ioexp; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); 4878c2ecf20Sopenharmony_ci if (rc) 4888c2ecf20Sopenharmony_ci goto fail_on; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci netif_info(efx, hw, efx->net_dev, "PHY is powered on\n"); 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cifail_on: 4948c2ecf20Sopenharmony_ci sfe4001_poweroff(efx); 4958c2ecf20Sopenharmony_cifail_ioexp: 4968c2ecf20Sopenharmony_ci i2c_unregister_device(board->ioexp_client); 4978c2ecf20Sopenharmony_cifail_hwmon: 4988c2ecf20Sopenharmony_ci i2c_unregister_device(board->hwmon_client); 4998c2ecf20Sopenharmony_ci return rc; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/***************************************************************************** 5038c2ecf20Sopenharmony_ci * Support for the SFE4002 5048c2ecf20Sopenharmony_ci * 5058c2ecf20Sopenharmony_ci */ 5068c2ecf20Sopenharmony_cistatic u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */ 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic const u8 sfe4002_lm87_regs[] = { 5098c2ecf20Sopenharmony_ci LM87_IN_LIMITS(0, 0x7c, 0x99), /* 2.5V: 1.8V +/- 10% */ 5108c2ecf20Sopenharmony_ci LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */ 5118c2ecf20Sopenharmony_ci LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */ 5128c2ecf20Sopenharmony_ci LM87_IN_LIMITS(3, 0xac, 0xd4), /* 5V: 5.0V +/- 10% */ 5138c2ecf20Sopenharmony_ci LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */ 5148c2ecf20Sopenharmony_ci LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */ 5158c2ecf20Sopenharmony_ci LM87_AIN_LIMITS(0, 0x98, 0xbb), /* AIN1: 1.66V +/- 10% */ 5168c2ecf20Sopenharmony_ci LM87_AIN_LIMITS(1, 0x8a, 0xa9), /* AIN2: 1.5V +/- 10% */ 5178c2ecf20Sopenharmony_ci LM87_TEMP_INT_LIMITS(0, 80 + FALCON_BOARD_TEMP_BIAS), 5188c2ecf20Sopenharmony_ci LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX), 5198c2ecf20Sopenharmony_ci 0 5208c2ecf20Sopenharmony_ci}; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic const struct i2c_board_info sfe4002_hwmon_info = { 5238c2ecf20Sopenharmony_ci I2C_BOARD_INFO("lm87", 0x2e), 5248c2ecf20Sopenharmony_ci .platform_data = &sfe4002_lm87_channel, 5258c2ecf20Sopenharmony_ci}; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/****************************************************************************/ 5288c2ecf20Sopenharmony_ci/* LED allocations. Note that on rev A0 boards the schematic and the reality 5298c2ecf20Sopenharmony_ci * differ: red and green are swapped. Below is the fixed (A1) layout (there 5308c2ecf20Sopenharmony_ci * are only 3 A0 boards in existence, so no real reason to make this 5318c2ecf20Sopenharmony_ci * conditional). 5328c2ecf20Sopenharmony_ci */ 5338c2ecf20Sopenharmony_ci#define SFE4002_FAULT_LED (2) /* Red */ 5348c2ecf20Sopenharmony_ci#define SFE4002_RX_LED (0) /* Green */ 5358c2ecf20Sopenharmony_ci#define SFE4002_TX_LED (1) /* Amber */ 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic void sfe4002_init_phy(struct ef4_nic *efx) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci /* Set the TX and RX LEDs to reflect status and activity, and the 5408c2ecf20Sopenharmony_ci * fault LED off */ 5418c2ecf20Sopenharmony_ci falcon_qt202x_set_led(efx, SFE4002_TX_LED, 5428c2ecf20Sopenharmony_ci QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT); 5438c2ecf20Sopenharmony_ci falcon_qt202x_set_led(efx, SFE4002_RX_LED, 5448c2ecf20Sopenharmony_ci QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT); 5458c2ecf20Sopenharmony_ci falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic void sfe4002_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci falcon_qt202x_set_led( 5518c2ecf20Sopenharmony_ci efx, SFE4002_FAULT_LED, 5528c2ecf20Sopenharmony_ci (mode == EF4_LED_ON) ? QUAKE_LED_ON : QUAKE_LED_OFF); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic int sfe4002_check_hw(struct ef4_nic *efx) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct falcon_board *board = falcon_board(efx); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* A0 board rev. 4002s report a temperature fault the whole time 5608c2ecf20Sopenharmony_ci * (bad sensor) so we mask it out. */ 5618c2ecf20Sopenharmony_ci unsigned alarm_mask = 5628c2ecf20Sopenharmony_ci (board->major == 0 && board->minor == 0) ? 5638c2ecf20Sopenharmony_ci ~LM87_ALARM_TEMP_EXT1 : ~0; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return ef4_check_lm87(efx, alarm_mask); 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int sfe4002_init(struct ef4_nic *efx) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci return ef4_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci/***************************************************************************** 5748c2ecf20Sopenharmony_ci * Support for the SFN4112F 5758c2ecf20Sopenharmony_ci * 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_cistatic u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */ 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic const u8 sfn4112f_lm87_regs[] = { 5808c2ecf20Sopenharmony_ci LM87_IN_LIMITS(0, 0x7c, 0x99), /* 2.5V: 1.8V +/- 10% */ 5818c2ecf20Sopenharmony_ci LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */ 5828c2ecf20Sopenharmony_ci LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */ 5838c2ecf20Sopenharmony_ci LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */ 5848c2ecf20Sopenharmony_ci LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */ 5858c2ecf20Sopenharmony_ci LM87_AIN_LIMITS(1, 0x8a, 0xa9), /* AIN2: 1.5V +/- 10% */ 5868c2ecf20Sopenharmony_ci LM87_TEMP_INT_LIMITS(0, 60 + FALCON_BOARD_TEMP_BIAS), 5878c2ecf20Sopenharmony_ci LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX), 5888c2ecf20Sopenharmony_ci 0 5898c2ecf20Sopenharmony_ci}; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic const struct i2c_board_info sfn4112f_hwmon_info = { 5928c2ecf20Sopenharmony_ci I2C_BOARD_INFO("lm87", 0x2e), 5938c2ecf20Sopenharmony_ci .platform_data = &sfn4112f_lm87_channel, 5948c2ecf20Sopenharmony_ci}; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci#define SFN4112F_ACT_LED 0 5978c2ecf20Sopenharmony_ci#define SFN4112F_LINK_LED 1 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void sfn4112f_init_phy(struct ef4_nic *efx) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci falcon_qt202x_set_led(efx, SFN4112F_ACT_LED, 6028c2ecf20Sopenharmony_ci QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT); 6038c2ecf20Sopenharmony_ci falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, 6048c2ecf20Sopenharmony_ci QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT); 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic void sfn4112f_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci int reg; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci switch (mode) { 6128c2ecf20Sopenharmony_ci case EF4_LED_OFF: 6138c2ecf20Sopenharmony_ci reg = QUAKE_LED_OFF; 6148c2ecf20Sopenharmony_ci break; 6158c2ecf20Sopenharmony_ci case EF4_LED_ON: 6168c2ecf20Sopenharmony_ci reg = QUAKE_LED_ON; 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci default: 6198c2ecf20Sopenharmony_ci reg = QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT; 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, reg); 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic int sfn4112f_check_hw(struct ef4_nic *efx) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci /* Mask out unused sensors */ 6298c2ecf20Sopenharmony_ci return ef4_check_lm87(efx, ~0x48); 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cistatic int sfn4112f_init(struct ef4_nic *efx) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci return ef4_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs); 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci/***************************************************************************** 6388c2ecf20Sopenharmony_ci * Support for the SFE4003 6398c2ecf20Sopenharmony_ci * 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_cistatic u8 sfe4003_lm87_channel = 0x03; /* use AIN not FAN inputs */ 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic const u8 sfe4003_lm87_regs[] = { 6448c2ecf20Sopenharmony_ci LM87_IN_LIMITS(0, 0x67, 0x7f), /* 2.5V: 1.5V +/- 10% */ 6458c2ecf20Sopenharmony_ci LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */ 6468c2ecf20Sopenharmony_ci LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */ 6478c2ecf20Sopenharmony_ci LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */ 6488c2ecf20Sopenharmony_ci LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */ 6498c2ecf20Sopenharmony_ci LM87_TEMP_INT_LIMITS(0, 70 + FALCON_BOARD_TEMP_BIAS), 6508c2ecf20Sopenharmony_ci 0 6518c2ecf20Sopenharmony_ci}; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic const struct i2c_board_info sfe4003_hwmon_info = { 6548c2ecf20Sopenharmony_ci I2C_BOARD_INFO("lm87", 0x2e), 6558c2ecf20Sopenharmony_ci .platform_data = &sfe4003_lm87_channel, 6568c2ecf20Sopenharmony_ci}; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci/* Board-specific LED info. */ 6598c2ecf20Sopenharmony_ci#define SFE4003_RED_LED_GPIO 11 6608c2ecf20Sopenharmony_ci#define SFE4003_LED_ON 1 6618c2ecf20Sopenharmony_ci#define SFE4003_LED_OFF 0 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic void sfe4003_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct falcon_board *board = falcon_board(efx); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* The LEDs were not wired to GPIOs before A3 */ 6688c2ecf20Sopenharmony_ci if (board->minor < 3 && board->major == 0) 6698c2ecf20Sopenharmony_ci return; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci falcon_txc_set_gpio_val( 6728c2ecf20Sopenharmony_ci efx, SFE4003_RED_LED_GPIO, 6738c2ecf20Sopenharmony_ci (mode == EF4_LED_ON) ? SFE4003_LED_ON : SFE4003_LED_OFF); 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic void sfe4003_init_phy(struct ef4_nic *efx) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct falcon_board *board = falcon_board(efx); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* The LEDs were not wired to GPIOs before A3 */ 6818c2ecf20Sopenharmony_ci if (board->minor < 3 && board->major == 0) 6828c2ecf20Sopenharmony_ci return; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci falcon_txc_set_gpio_dir(efx, SFE4003_RED_LED_GPIO, TXC_GPIO_DIR_OUTPUT); 6858c2ecf20Sopenharmony_ci falcon_txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO, SFE4003_LED_OFF); 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic int sfe4003_check_hw(struct ef4_nic *efx) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct falcon_board *board = falcon_board(efx); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* A0/A1/A2 board rev. 4003s report a temperature fault the whole time 6938c2ecf20Sopenharmony_ci * (bad sensor) so we mask it out. */ 6948c2ecf20Sopenharmony_ci unsigned alarm_mask = 6958c2ecf20Sopenharmony_ci (board->major == 0 && board->minor <= 2) ? 6968c2ecf20Sopenharmony_ci ~LM87_ALARM_TEMP_EXT1 : ~0; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return ef4_check_lm87(efx, alarm_mask); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic int sfe4003_init(struct ef4_nic *efx) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci return ef4_init_lm87(efx, &sfe4003_hwmon_info, sfe4003_lm87_regs); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic const struct falcon_board_type board_types[] = { 7078c2ecf20Sopenharmony_ci { 7088c2ecf20Sopenharmony_ci .id = FALCON_BOARD_SFE4001, 7098c2ecf20Sopenharmony_ci .init = sfe4001_init, 7108c2ecf20Sopenharmony_ci .init_phy = ef4_port_dummy_op_void, 7118c2ecf20Sopenharmony_ci .fini = sfe4001_fini, 7128c2ecf20Sopenharmony_ci .set_id_led = tenxpress_set_id_led, 7138c2ecf20Sopenharmony_ci .monitor = sfe4001_check_hw, 7148c2ecf20Sopenharmony_ci }, 7158c2ecf20Sopenharmony_ci { 7168c2ecf20Sopenharmony_ci .id = FALCON_BOARD_SFE4002, 7178c2ecf20Sopenharmony_ci .init = sfe4002_init, 7188c2ecf20Sopenharmony_ci .init_phy = sfe4002_init_phy, 7198c2ecf20Sopenharmony_ci .fini = ef4_fini_lm87, 7208c2ecf20Sopenharmony_ci .set_id_led = sfe4002_set_id_led, 7218c2ecf20Sopenharmony_ci .monitor = sfe4002_check_hw, 7228c2ecf20Sopenharmony_ci }, 7238c2ecf20Sopenharmony_ci { 7248c2ecf20Sopenharmony_ci .id = FALCON_BOARD_SFE4003, 7258c2ecf20Sopenharmony_ci .init = sfe4003_init, 7268c2ecf20Sopenharmony_ci .init_phy = sfe4003_init_phy, 7278c2ecf20Sopenharmony_ci .fini = ef4_fini_lm87, 7288c2ecf20Sopenharmony_ci .set_id_led = sfe4003_set_id_led, 7298c2ecf20Sopenharmony_ci .monitor = sfe4003_check_hw, 7308c2ecf20Sopenharmony_ci }, 7318c2ecf20Sopenharmony_ci { 7328c2ecf20Sopenharmony_ci .id = FALCON_BOARD_SFN4112F, 7338c2ecf20Sopenharmony_ci .init = sfn4112f_init, 7348c2ecf20Sopenharmony_ci .init_phy = sfn4112f_init_phy, 7358c2ecf20Sopenharmony_ci .fini = ef4_fini_lm87, 7368c2ecf20Sopenharmony_ci .set_id_led = sfn4112f_set_id_led, 7378c2ecf20Sopenharmony_ci .monitor = sfn4112f_check_hw, 7388c2ecf20Sopenharmony_ci }, 7398c2ecf20Sopenharmony_ci}; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ciint falcon_probe_board(struct ef4_nic *efx, u16 revision_info) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct falcon_board *board = falcon_board(efx); 7448c2ecf20Sopenharmony_ci u8 type_id = FALCON_BOARD_TYPE(revision_info); 7458c2ecf20Sopenharmony_ci int i; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci board->major = FALCON_BOARD_MAJOR(revision_info); 7488c2ecf20Sopenharmony_ci board->minor = FALCON_BOARD_MINOR(revision_info); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(board_types); i++) 7518c2ecf20Sopenharmony_ci if (board_types[i].id == type_id) 7528c2ecf20Sopenharmony_ci board->type = &board_types[i]; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (board->type) { 7558c2ecf20Sopenharmony_ci return 0; 7568c2ecf20Sopenharmony_ci } else { 7578c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, "unknown board type %d\n", 7588c2ecf20Sopenharmony_ci type_id); 7598c2ecf20Sopenharmony_ci return -ENODEV; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci} 762