1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /**************************************************************************** |
3 | * Driver for Solarflare network controllers and boards |
4 | * Copyright 2007-2012 Solarflare Communications Inc. |
5 | */ |
6 | |
7 | #include <linux/rtnetlink.h> |
8 | |
9 | #include "net_driver.h" |
10 | #include "phy.h" |
11 | #include "efx.h" |
12 | #include "nic.h" |
13 | #include "workarounds.h" |
14 | |
15 | /* Macros for unpacking the board revision */ |
16 | /* The revision info is in host byte order. */ |
17 | #define FALCON_BOARD_TYPE(_rev) (_rev >> 8) |
18 | #define FALCON_BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf) |
19 | #define FALCON_BOARD_MINOR(_rev) (_rev & 0xf) |
20 | |
21 | /* Board types */ |
22 | #define FALCON_BOARD_SFE4001 0x01 |
23 | #define FALCON_BOARD_SFE4002 0x02 |
24 | #define FALCON_BOARD_SFE4003 0x03 |
25 | #define FALCON_BOARD_SFN4112F 0x52 |
26 | |
27 | /* Board temperature is about 15°C above ambient when air flow is |
28 | * limited. The maximum acceptable ambient temperature varies |
29 | * depending on the PHY specifications but the critical temperature |
30 | * above which we should shut down to avoid damage is 80°C. */ |
31 | #define FALCON_BOARD_TEMP_BIAS 15 |
32 | #define FALCON_BOARD_TEMP_CRIT (80 + FALCON_BOARD_TEMP_BIAS) |
33 | |
34 | /* SFC4000 datasheet says: 'The maximum permitted junction temperature |
35 | * is 125°C; the thermal design of the environment for the SFC4000 |
36 | * should aim to keep this well below 100°C.' */ |
37 | #define FALCON_JUNC_TEMP_MIN 0 |
38 | #define FALCON_JUNC_TEMP_MAX 90 |
39 | #define FALCON_JUNC_TEMP_CRIT 125 |
40 | |
41 | /***************************************************************************** |
42 | * Support for LM87 sensor chip used on several boards |
43 | */ |
44 | #define LM87_REG_TEMP_HW_INT_LOCK 0x13 |
45 | #define LM87_REG_TEMP_HW_EXT_LOCK 0x14 |
46 | #define LM87_REG_TEMP_HW_INT 0x17 |
47 | #define LM87_REG_TEMP_HW_EXT 0x18 |
48 | #define LM87_REG_TEMP_EXT1 0x26 |
49 | #define LM87_REG_TEMP_INT 0x27 |
50 | #define LM87_REG_ALARMS1 0x41 |
51 | #define LM87_REG_ALARMS2 0x42 |
52 | #define LM87_IN_LIMITS(nr, _min, _max) \ |
53 | 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min |
54 | #define LM87_AIN_LIMITS(nr, _min, _max) \ |
55 | 0x3B + (nr), _max, 0x1A + (nr), _min |
56 | #define LM87_TEMP_INT_LIMITS(_min, _max) \ |
57 | 0x39, _max, 0x3A, _min |
58 | #define LM87_TEMP_EXT1_LIMITS(_min, _max) \ |
59 | 0x37, _max, 0x38, _min |
60 | |
61 | #define LM87_ALARM_TEMP_INT 0x10 |
62 | #define LM87_ALARM_TEMP_EXT1 0x20 |
63 | |
64 | #if IS_ENABLED(CONFIG_SENSORS_LM87) |
65 | |
66 | static int ef4_poke_lm87(struct i2c_client *client, const u8 *reg_values) |
67 | { |
68 | while (*reg_values) { |
69 | u8 reg = *reg_values++; |
70 | u8 value = *reg_values++; |
71 | int rc = i2c_smbus_write_byte_data(client, command: reg, value); |
72 | if (rc) |
73 | return rc; |
74 | } |
75 | return 0; |
76 | } |
77 | |
78 | static const u8 falcon_lm87_common_regs[] = { |
79 | LM87_REG_TEMP_HW_INT_LOCK, FALCON_BOARD_TEMP_CRIT, |
80 | LM87_REG_TEMP_HW_INT, FALCON_BOARD_TEMP_CRIT, |
81 | LM87_TEMP_EXT1_LIMITS(FALCON_JUNC_TEMP_MIN, FALCON_JUNC_TEMP_MAX), |
82 | LM87_REG_TEMP_HW_EXT_LOCK, FALCON_JUNC_TEMP_CRIT, |
83 | LM87_REG_TEMP_HW_EXT, FALCON_JUNC_TEMP_CRIT, |
84 | 0 |
85 | }; |
86 | |
87 | static int ef4_init_lm87(struct ef4_nic *efx, const struct i2c_board_info *info, |
88 | const u8 *reg_values) |
89 | { |
90 | struct falcon_board *board = falcon_board(efx); |
91 | struct i2c_client *client = i2c_new_client_device(adap: &board->i2c_adap, info); |
92 | int rc; |
93 | |
94 | if (IS_ERR(ptr: client)) |
95 | return PTR_ERR(ptr: client); |
96 | |
97 | /* Read-to-clear alarm/interrupt status */ |
98 | i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); |
99 | i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); |
100 | |
101 | rc = ef4_poke_lm87(client, reg_values); |
102 | if (rc) |
103 | goto err; |
104 | rc = ef4_poke_lm87(client, reg_values: falcon_lm87_common_regs); |
105 | if (rc) |
106 | goto err; |
107 | |
108 | board->hwmon_client = client; |
109 | return 0; |
110 | |
111 | err: |
112 | i2c_unregister_device(client); |
113 | return rc; |
114 | } |
115 | |
116 | static void ef4_fini_lm87(struct ef4_nic *efx) |
117 | { |
118 | i2c_unregister_device(client: falcon_board(efx)->hwmon_client); |
119 | } |
120 | |
121 | static int ef4_check_lm87(struct ef4_nic *efx, unsigned mask) |
122 | { |
123 | struct i2c_client *client = falcon_board(efx)->hwmon_client; |
124 | bool temp_crit, elec_fault, is_failure; |
125 | u16 alarms; |
126 | s32 reg; |
127 | |
128 | /* If link is up then do not monitor temperature */ |
129 | if (EF4_WORKAROUND_7884(efx) && efx->link_state.up) |
130 | return 0; |
131 | |
132 | reg = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); |
133 | if (reg < 0) |
134 | return reg; |
135 | alarms = reg; |
136 | reg = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); |
137 | if (reg < 0) |
138 | return reg; |
139 | alarms |= reg << 8; |
140 | alarms &= mask; |
141 | |
142 | temp_crit = false; |
143 | if (alarms & LM87_ALARM_TEMP_INT) { |
144 | reg = i2c_smbus_read_byte_data(client, LM87_REG_TEMP_INT); |
145 | if (reg < 0) |
146 | return reg; |
147 | if (reg > FALCON_BOARD_TEMP_CRIT) |
148 | temp_crit = true; |
149 | } |
150 | if (alarms & LM87_ALARM_TEMP_EXT1) { |
151 | reg = i2c_smbus_read_byte_data(client, LM87_REG_TEMP_EXT1); |
152 | if (reg < 0) |
153 | return reg; |
154 | if (reg > FALCON_JUNC_TEMP_CRIT) |
155 | temp_crit = true; |
156 | } |
157 | elec_fault = alarms & ~(LM87_ALARM_TEMP_INT | LM87_ALARM_TEMP_EXT1); |
158 | is_failure = temp_crit || elec_fault; |
159 | |
160 | if (alarms) |
161 | netif_err(efx, hw, efx->net_dev, |
162 | "LM87 detected a hardware %s (status %02x:%02x)" |
163 | "%s%s%s%s\n" , |
164 | is_failure ? "failure" : "problem" , |
165 | alarms & 0xff, alarms >> 8, |
166 | (alarms & LM87_ALARM_TEMP_INT) ? |
167 | "; board is overheating" : "" , |
168 | (alarms & LM87_ALARM_TEMP_EXT1) ? |
169 | "; controller is overheating" : "" , |
170 | temp_crit ? "; reached critical temperature" : "" , |
171 | elec_fault ? "; electrical fault" : "" ); |
172 | |
173 | return is_failure ? -ERANGE : 0; |
174 | } |
175 | |
176 | #else /* !CONFIG_SENSORS_LM87 */ |
177 | |
178 | static inline int |
179 | ef4_init_lm87(struct ef4_nic *efx, const struct i2c_board_info *info, |
180 | const u8 *reg_values) |
181 | { |
182 | return 0; |
183 | } |
184 | static inline void ef4_fini_lm87(struct ef4_nic *efx) |
185 | { |
186 | } |
187 | static inline int ef4_check_lm87(struct ef4_nic *efx, unsigned mask) |
188 | { |
189 | return 0; |
190 | } |
191 | |
192 | #endif /* CONFIG_SENSORS_LM87 */ |
193 | |
194 | /***************************************************************************** |
195 | * Support for the SFE4001 NIC. |
196 | * |
197 | * The SFE4001 does not power-up fully at reset due to its high power |
198 | * consumption. We control its power via a PCA9539 I/O expander. |
199 | * It also has a MAX6647 temperature monitor which we expose to |
200 | * the lm90 driver. |
201 | * |
202 | * This also provides minimal support for reflashing the PHY, which is |
203 | * initiated by resetting it with the FLASH_CFG_1 pin pulled down. |
204 | * On SFE4001 rev A2 and later this is connected to the 3V3X output of |
205 | * the IO-expander. |
206 | * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually |
207 | * exclusive with the network device being open. |
208 | */ |
209 | |
210 | /************************************************************************** |
211 | * Support for I2C IO Expander device on SFE4001 |
212 | */ |
213 | #define PCA9539 0x74 |
214 | |
215 | #define P0_IN 0x00 |
216 | #define P0_OUT 0x02 |
217 | #define P0_INVERT 0x04 |
218 | #define P0_CONFIG 0x06 |
219 | |
220 | #define P0_EN_1V0X_LBN 0 |
221 | #define P0_EN_1V0X_WIDTH 1 |
222 | #define P0_EN_1V2_LBN 1 |
223 | #define P0_EN_1V2_WIDTH 1 |
224 | #define P0_EN_2V5_LBN 2 |
225 | #define P0_EN_2V5_WIDTH 1 |
226 | #define P0_EN_3V3X_LBN 3 |
227 | #define P0_EN_3V3X_WIDTH 1 |
228 | #define P0_EN_5V_LBN 4 |
229 | #define P0_EN_5V_WIDTH 1 |
230 | #define P0_SHORTEN_JTAG_LBN 5 |
231 | #define P0_SHORTEN_JTAG_WIDTH 1 |
232 | #define P0_X_TRST_LBN 6 |
233 | #define P0_X_TRST_WIDTH 1 |
234 | #define P0_DSP_RESET_LBN 7 |
235 | #define P0_DSP_RESET_WIDTH 1 |
236 | |
237 | #define P1_IN 0x01 |
238 | #define P1_OUT 0x03 |
239 | #define P1_INVERT 0x05 |
240 | #define P1_CONFIG 0x07 |
241 | |
242 | #define P1_AFE_PWD_LBN 0 |
243 | #define P1_AFE_PWD_WIDTH 1 |
244 | #define P1_DSP_PWD25_LBN 1 |
245 | #define P1_DSP_PWD25_WIDTH 1 |
246 | #define P1_RESERVED_LBN 2 |
247 | #define P1_RESERVED_WIDTH 2 |
248 | #define P1_SPARE_LBN 4 |
249 | #define P1_SPARE_WIDTH 4 |
250 | |
251 | /* Temperature Sensor */ |
252 | #define MAX664X_REG_RSL 0x02 |
253 | #define MAX664X_REG_WLHO 0x0B |
254 | |
255 | static void sfe4001_poweroff(struct ef4_nic *efx) |
256 | { |
257 | struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; |
258 | struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; |
259 | |
260 | /* Turn off all power rails and disable outputs */ |
261 | i2c_smbus_write_byte_data(client: ioexp_client, P0_OUT, value: 0xff); |
262 | i2c_smbus_write_byte_data(client: ioexp_client, P1_CONFIG, value: 0xff); |
263 | i2c_smbus_write_byte_data(client: ioexp_client, P0_CONFIG, value: 0xff); |
264 | |
265 | /* Clear any over-temperature alert */ |
266 | i2c_smbus_read_byte_data(client: hwmon_client, MAX664X_REG_RSL); |
267 | } |
268 | |
269 | static int sfe4001_poweron(struct ef4_nic *efx) |
270 | { |
271 | struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; |
272 | struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; |
273 | unsigned int i, j; |
274 | int rc; |
275 | u8 out; |
276 | |
277 | /* Clear any previous over-temperature alert */ |
278 | rc = i2c_smbus_read_byte_data(client: hwmon_client, MAX664X_REG_RSL); |
279 | if (rc < 0) |
280 | return rc; |
281 | |
282 | /* Enable port 0 and port 1 outputs on IO expander */ |
283 | rc = i2c_smbus_write_byte_data(client: ioexp_client, P0_CONFIG, value: 0x00); |
284 | if (rc) |
285 | return rc; |
286 | rc = i2c_smbus_write_byte_data(client: ioexp_client, P1_CONFIG, |
287 | value: 0xff & ~(1 << P1_SPARE_LBN)); |
288 | if (rc) |
289 | goto fail_on; |
290 | |
291 | /* If PHY power is on, turn it all off and wait 1 second to |
292 | * ensure a full reset. |
293 | */ |
294 | rc = i2c_smbus_read_byte_data(client: ioexp_client, P0_OUT); |
295 | if (rc < 0) |
296 | goto fail_on; |
297 | out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | |
298 | (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | |
299 | (0 << P0_EN_1V0X_LBN)); |
300 | if (rc != out) { |
301 | netif_info(efx, hw, efx->net_dev, "power-cycling PHY\n" ); |
302 | rc = i2c_smbus_write_byte_data(client: ioexp_client, P0_OUT, value: out); |
303 | if (rc) |
304 | goto fail_on; |
305 | schedule_timeout_uninterruptible(HZ); |
306 | } |
307 | |
308 | for (i = 0; i < 20; ++i) { |
309 | /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ |
310 | out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | |
311 | (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | |
312 | (1 << P0_X_TRST_LBN)); |
313 | if (efx->phy_mode & PHY_MODE_SPECIAL) |
314 | out |= 1 << P0_EN_3V3X_LBN; |
315 | |
316 | rc = i2c_smbus_write_byte_data(client: ioexp_client, P0_OUT, value: out); |
317 | if (rc) |
318 | goto fail_on; |
319 | msleep(msecs: 10); |
320 | |
321 | /* Turn on 1V power rail */ |
322 | out &= ~(1 << P0_EN_1V0X_LBN); |
323 | rc = i2c_smbus_write_byte_data(client: ioexp_client, P0_OUT, value: out); |
324 | if (rc) |
325 | goto fail_on; |
326 | |
327 | netif_info(efx, hw, efx->net_dev, |
328 | "waiting for DSP boot (attempt %d)...\n" , i); |
329 | |
330 | /* In flash config mode, DSP does not turn on AFE, so |
331 | * just wait 1 second. |
332 | */ |
333 | if (efx->phy_mode & PHY_MODE_SPECIAL) { |
334 | schedule_timeout_uninterruptible(HZ); |
335 | return 0; |
336 | } |
337 | |
338 | for (j = 0; j < 10; ++j) { |
339 | msleep(msecs: 100); |
340 | |
341 | /* Check DSP has asserted AFE power line */ |
342 | rc = i2c_smbus_read_byte_data(client: ioexp_client, P1_IN); |
343 | if (rc < 0) |
344 | goto fail_on; |
345 | if (rc & (1 << P1_AFE_PWD_LBN)) |
346 | return 0; |
347 | } |
348 | } |
349 | |
350 | netif_info(efx, hw, efx->net_dev, "timed out waiting for DSP boot\n" ); |
351 | rc = -ETIMEDOUT; |
352 | fail_on: |
353 | sfe4001_poweroff(efx); |
354 | return rc; |
355 | } |
356 | |
357 | static ssize_t phy_flash_cfg_show(struct device *dev, |
358 | struct device_attribute *attr, char *buf) |
359 | { |
360 | struct ef4_nic *efx = dev_get_drvdata(dev); |
361 | return sprintf(buf, fmt: "%d\n" , !!(efx->phy_mode & PHY_MODE_SPECIAL)); |
362 | } |
363 | |
364 | static ssize_t phy_flash_cfg_store(struct device *dev, |
365 | struct device_attribute *attr, |
366 | const char *buf, size_t count) |
367 | { |
368 | struct ef4_nic *efx = dev_get_drvdata(dev); |
369 | enum ef4_phy_mode old_mode, new_mode; |
370 | int err; |
371 | |
372 | rtnl_lock(); |
373 | old_mode = efx->phy_mode; |
374 | if (count == 0 || *buf == '0') |
375 | new_mode = old_mode & ~PHY_MODE_SPECIAL; |
376 | else |
377 | new_mode = PHY_MODE_SPECIAL; |
378 | if (!((old_mode ^ new_mode) & PHY_MODE_SPECIAL)) { |
379 | err = 0; |
380 | } else if (efx->state != STATE_READY || netif_running(dev: efx->net_dev)) { |
381 | err = -EBUSY; |
382 | } else { |
383 | /* Reset the PHY, reconfigure the MAC and enable/disable |
384 | * MAC stats accordingly. */ |
385 | efx->phy_mode = new_mode; |
386 | if (new_mode & PHY_MODE_SPECIAL) |
387 | falcon_stop_nic_stats(efx); |
388 | err = sfe4001_poweron(efx); |
389 | if (!err) |
390 | err = ef4_reconfigure_port(efx); |
391 | if (!(new_mode & PHY_MODE_SPECIAL)) |
392 | falcon_start_nic_stats(efx); |
393 | } |
394 | rtnl_unlock(); |
395 | |
396 | return err ? err : count; |
397 | } |
398 | |
399 | static DEVICE_ATTR_RW(phy_flash_cfg); |
400 | |
401 | static void sfe4001_fini(struct ef4_nic *efx) |
402 | { |
403 | struct falcon_board *board = falcon_board(efx); |
404 | |
405 | netif_info(efx, drv, efx->net_dev, "%s\n" , __func__); |
406 | |
407 | device_remove_file(dev: &efx->pci_dev->dev, attr: &dev_attr_phy_flash_cfg); |
408 | sfe4001_poweroff(efx); |
409 | i2c_unregister_device(client: board->ioexp_client); |
410 | i2c_unregister_device(client: board->hwmon_client); |
411 | } |
412 | |
413 | static int sfe4001_check_hw(struct ef4_nic *efx) |
414 | { |
415 | struct falcon_nic_data *nic_data = efx->nic_data; |
416 | s32 status; |
417 | |
418 | /* If XAUI link is up then do not monitor */ |
419 | if (EF4_WORKAROUND_7884(efx) && !nic_data->xmac_poll_required) |
420 | return 0; |
421 | |
422 | /* Check the powered status of the PHY. Lack of power implies that |
423 | * the MAX6647 has shut down power to it, probably due to a temp. |
424 | * alarm. Reading the power status rather than the MAX6647 status |
425 | * directly because the later is read-to-clear and would thus |
426 | * start to power up the PHY again when polled, causing us to blip |
427 | * the power undesirably. |
428 | * We know we can read from the IO expander because we did |
429 | * it during power-on. Assume failure now is bad news. */ |
430 | status = i2c_smbus_read_byte_data(client: falcon_board(efx)->ioexp_client, P1_IN); |
431 | if (status >= 0 && |
432 | (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) |
433 | return 0; |
434 | |
435 | /* Use board power control, not PHY power control */ |
436 | sfe4001_poweroff(efx); |
437 | efx->phy_mode = PHY_MODE_OFF; |
438 | |
439 | return (status < 0) ? -EIO : -ERANGE; |
440 | } |
441 | |
442 | static const struct i2c_board_info sfe4001_hwmon_info = { |
443 | I2C_BOARD_INFO("max6647" , 0x4e), |
444 | }; |
445 | |
446 | /* This board uses an I2C expander to provider power to the PHY, which needs to |
447 | * be turned on before the PHY can be used. |
448 | * Context: Process context, rtnl lock held |
449 | */ |
450 | static int sfe4001_init(struct ef4_nic *efx) |
451 | { |
452 | struct falcon_board *board = falcon_board(efx); |
453 | int rc; |
454 | |
455 | #if IS_ENABLED(CONFIG_SENSORS_LM90) |
456 | board->hwmon_client = |
457 | i2c_new_client_device(adap: &board->i2c_adap, info: &sfe4001_hwmon_info); |
458 | #else |
459 | board->hwmon_client = |
460 | i2c_new_dummy_device(&board->i2c_adap, sfe4001_hwmon_info.addr); |
461 | #endif |
462 | if (IS_ERR(ptr: board->hwmon_client)) |
463 | return PTR_ERR(ptr: board->hwmon_client); |
464 | |
465 | /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ |
466 | rc = i2c_smbus_write_byte_data(client: board->hwmon_client, |
467 | MAX664X_REG_WLHO, value: 90); |
468 | if (rc) |
469 | goto fail_hwmon; |
470 | |
471 | board->ioexp_client = i2c_new_dummy_device(adapter: &board->i2c_adap, PCA9539); |
472 | if (IS_ERR(ptr: board->ioexp_client)) { |
473 | rc = PTR_ERR(ptr: board->ioexp_client); |
474 | goto fail_hwmon; |
475 | } |
476 | |
477 | if (efx->phy_mode & PHY_MODE_SPECIAL) { |
478 | /* PHY won't generate a 156.25 MHz clock and MAC stats fetch |
479 | * will fail. */ |
480 | falcon_stop_nic_stats(efx); |
481 | } |
482 | rc = sfe4001_poweron(efx); |
483 | if (rc) |
484 | goto fail_ioexp; |
485 | |
486 | rc = device_create_file(device: &efx->pci_dev->dev, entry: &dev_attr_phy_flash_cfg); |
487 | if (rc) |
488 | goto fail_on; |
489 | |
490 | netif_info(efx, hw, efx->net_dev, "PHY is powered on\n" ); |
491 | return 0; |
492 | |
493 | fail_on: |
494 | sfe4001_poweroff(efx); |
495 | fail_ioexp: |
496 | i2c_unregister_device(client: board->ioexp_client); |
497 | fail_hwmon: |
498 | i2c_unregister_device(client: board->hwmon_client); |
499 | return rc; |
500 | } |
501 | |
502 | /***************************************************************************** |
503 | * Support for the SFE4002 |
504 | * |
505 | */ |
506 | static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */ |
507 | |
508 | static const u8 sfe4002_lm87_regs[] = { |
509 | LM87_IN_LIMITS(0, 0x7c, 0x99), /* 2.5V: 1.8V +/- 10% */ |
510 | LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */ |
511 | LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */ |
512 | LM87_IN_LIMITS(3, 0xac, 0xd4), /* 5V: 5.0V +/- 10% */ |
513 | LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */ |
514 | LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */ |
515 | LM87_AIN_LIMITS(0, 0x98, 0xbb), /* AIN1: 1.66V +/- 10% */ |
516 | LM87_AIN_LIMITS(1, 0x8a, 0xa9), /* AIN2: 1.5V +/- 10% */ |
517 | LM87_TEMP_INT_LIMITS(0, 80 + FALCON_BOARD_TEMP_BIAS), |
518 | LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX), |
519 | 0 |
520 | }; |
521 | |
522 | static const struct i2c_board_info sfe4002_hwmon_info = { |
523 | I2C_BOARD_INFO("lm87" , 0x2e), |
524 | .platform_data = &sfe4002_lm87_channel, |
525 | }; |
526 | |
527 | /****************************************************************************/ |
528 | /* LED allocations. Note that on rev A0 boards the schematic and the reality |
529 | * differ: red and green are swapped. Below is the fixed (A1) layout (there |
530 | * are only 3 A0 boards in existence, so no real reason to make this |
531 | * conditional). |
532 | */ |
533 | #define SFE4002_FAULT_LED (2) /* Red */ |
534 | #define SFE4002_RX_LED (0) /* Green */ |
535 | #define SFE4002_TX_LED (1) /* Amber */ |
536 | |
537 | static void sfe4002_init_phy(struct ef4_nic *efx) |
538 | { |
539 | /* Set the TX and RX LEDs to reflect status and activity, and the |
540 | * fault LED off */ |
541 | falcon_qt202x_set_led(p: efx, SFE4002_TX_LED, |
542 | QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT); |
543 | falcon_qt202x_set_led(p: efx, SFE4002_RX_LED, |
544 | QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT); |
545 | falcon_qt202x_set_led(p: efx, SFE4002_FAULT_LED, QUAKE_LED_OFF); |
546 | } |
547 | |
548 | static void sfe4002_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode) |
549 | { |
550 | falcon_qt202x_set_led( |
551 | p: efx, SFE4002_FAULT_LED, |
552 | state: (mode == EF4_LED_ON) ? QUAKE_LED_ON : QUAKE_LED_OFF); |
553 | } |
554 | |
555 | static int sfe4002_check_hw(struct ef4_nic *efx) |
556 | { |
557 | struct falcon_board *board = falcon_board(efx); |
558 | |
559 | /* A0 board rev. 4002s report a temperature fault the whole time |
560 | * (bad sensor) so we mask it out. */ |
561 | unsigned alarm_mask = |
562 | (board->major == 0 && board->minor == 0) ? |
563 | ~LM87_ALARM_TEMP_EXT1 : ~0; |
564 | |
565 | return ef4_check_lm87(efx, mask: alarm_mask); |
566 | } |
567 | |
568 | static int sfe4002_init(struct ef4_nic *efx) |
569 | { |
570 | return ef4_init_lm87(efx, info: &sfe4002_hwmon_info, reg_values: sfe4002_lm87_regs); |
571 | } |
572 | |
573 | /***************************************************************************** |
574 | * Support for the SFN4112F |
575 | * |
576 | */ |
577 | static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */ |
578 | |
579 | static const u8 sfn4112f_lm87_regs[] = { |
580 | LM87_IN_LIMITS(0, 0x7c, 0x99), /* 2.5V: 1.8V +/- 10% */ |
581 | LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */ |
582 | LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */ |
583 | LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */ |
584 | LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */ |
585 | LM87_AIN_LIMITS(1, 0x8a, 0xa9), /* AIN2: 1.5V +/- 10% */ |
586 | LM87_TEMP_INT_LIMITS(0, 60 + FALCON_BOARD_TEMP_BIAS), |
587 | LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX), |
588 | 0 |
589 | }; |
590 | |
591 | static const struct i2c_board_info sfn4112f_hwmon_info = { |
592 | I2C_BOARD_INFO("lm87" , 0x2e), |
593 | .platform_data = &sfn4112f_lm87_channel, |
594 | }; |
595 | |
596 | #define SFN4112F_ACT_LED 0 |
597 | #define SFN4112F_LINK_LED 1 |
598 | |
599 | static void sfn4112f_init_phy(struct ef4_nic *efx) |
600 | { |
601 | falcon_qt202x_set_led(p: efx, SFN4112F_ACT_LED, |
602 | QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT); |
603 | falcon_qt202x_set_led(p: efx, SFN4112F_LINK_LED, |
604 | QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT); |
605 | } |
606 | |
607 | static void sfn4112f_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode) |
608 | { |
609 | int reg; |
610 | |
611 | switch (mode) { |
612 | case EF4_LED_OFF: |
613 | reg = QUAKE_LED_OFF; |
614 | break; |
615 | case EF4_LED_ON: |
616 | reg = QUAKE_LED_ON; |
617 | break; |
618 | default: |
619 | reg = QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT; |
620 | break; |
621 | } |
622 | |
623 | falcon_qt202x_set_led(p: efx, SFN4112F_LINK_LED, state: reg); |
624 | } |
625 | |
626 | static int sfn4112f_check_hw(struct ef4_nic *efx) |
627 | { |
628 | /* Mask out unused sensors */ |
629 | return ef4_check_lm87(efx, mask: ~0x48); |
630 | } |
631 | |
632 | static int sfn4112f_init(struct ef4_nic *efx) |
633 | { |
634 | return ef4_init_lm87(efx, info: &sfn4112f_hwmon_info, reg_values: sfn4112f_lm87_regs); |
635 | } |
636 | |
637 | /***************************************************************************** |
638 | * Support for the SFE4003 |
639 | * |
640 | */ |
641 | static u8 sfe4003_lm87_channel = 0x03; /* use AIN not FAN inputs */ |
642 | |
643 | static const u8 sfe4003_lm87_regs[] = { |
644 | LM87_IN_LIMITS(0, 0x67, 0x7f), /* 2.5V: 1.5V +/- 10% */ |
645 | LM87_IN_LIMITS(1, 0x4c, 0x5e), /* Vccp1: 1.2V +/- 10% */ |
646 | LM87_IN_LIMITS(2, 0xac, 0xd4), /* 3.3V: 3.3V +/- 10% */ |
647 | LM87_IN_LIMITS(4, 0xac, 0xe0), /* 12V: 10.8-14V */ |
648 | LM87_IN_LIMITS(5, 0x3f, 0x4f), /* Vccp2: 1.0V +/- 10% */ |
649 | LM87_TEMP_INT_LIMITS(0, 70 + FALCON_BOARD_TEMP_BIAS), |
650 | 0 |
651 | }; |
652 | |
653 | static const struct i2c_board_info sfe4003_hwmon_info = { |
654 | I2C_BOARD_INFO("lm87" , 0x2e), |
655 | .platform_data = &sfe4003_lm87_channel, |
656 | }; |
657 | |
658 | /* Board-specific LED info. */ |
659 | #define SFE4003_RED_LED_GPIO 11 |
660 | #define SFE4003_LED_ON 1 |
661 | #define SFE4003_LED_OFF 0 |
662 | |
663 | static void sfe4003_set_id_led(struct ef4_nic *efx, enum ef4_led_mode mode) |
664 | { |
665 | struct falcon_board *board = falcon_board(efx); |
666 | |
667 | /* The LEDs were not wired to GPIOs before A3 */ |
668 | if (board->minor < 3 && board->major == 0) |
669 | return; |
670 | |
671 | falcon_txc_set_gpio_val( |
672 | efx, SFE4003_RED_LED_GPIO, |
673 | val: (mode == EF4_LED_ON) ? SFE4003_LED_ON : SFE4003_LED_OFF); |
674 | } |
675 | |
676 | static void sfe4003_init_phy(struct ef4_nic *efx) |
677 | { |
678 | struct falcon_board *board = falcon_board(efx); |
679 | |
680 | /* The LEDs were not wired to GPIOs before A3 */ |
681 | if (board->minor < 3 && board->major == 0) |
682 | return; |
683 | |
684 | falcon_txc_set_gpio_dir(efx, SFE4003_RED_LED_GPIO, TXC_GPIO_DIR_OUTPUT); |
685 | falcon_txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO, SFE4003_LED_OFF); |
686 | } |
687 | |
688 | static int sfe4003_check_hw(struct ef4_nic *efx) |
689 | { |
690 | struct falcon_board *board = falcon_board(efx); |
691 | |
692 | /* A0/A1/A2 board rev. 4003s report a temperature fault the whole time |
693 | * (bad sensor) so we mask it out. */ |
694 | unsigned alarm_mask = |
695 | (board->major == 0 && board->minor <= 2) ? |
696 | ~LM87_ALARM_TEMP_EXT1 : ~0; |
697 | |
698 | return ef4_check_lm87(efx, mask: alarm_mask); |
699 | } |
700 | |
701 | static int sfe4003_init(struct ef4_nic *efx) |
702 | { |
703 | return ef4_init_lm87(efx, info: &sfe4003_hwmon_info, reg_values: sfe4003_lm87_regs); |
704 | } |
705 | |
706 | static const struct falcon_board_type board_types[] = { |
707 | { |
708 | .id = FALCON_BOARD_SFE4001, |
709 | .init = sfe4001_init, |
710 | .init_phy = ef4_port_dummy_op_void, |
711 | .fini = sfe4001_fini, |
712 | .set_id_led = tenxpress_set_id_led, |
713 | .monitor = sfe4001_check_hw, |
714 | }, |
715 | { |
716 | .id = FALCON_BOARD_SFE4002, |
717 | .init = sfe4002_init, |
718 | .init_phy = sfe4002_init_phy, |
719 | .fini = ef4_fini_lm87, |
720 | .set_id_led = sfe4002_set_id_led, |
721 | .monitor = sfe4002_check_hw, |
722 | }, |
723 | { |
724 | .id = FALCON_BOARD_SFE4003, |
725 | .init = sfe4003_init, |
726 | .init_phy = sfe4003_init_phy, |
727 | .fini = ef4_fini_lm87, |
728 | .set_id_led = sfe4003_set_id_led, |
729 | .monitor = sfe4003_check_hw, |
730 | }, |
731 | { |
732 | .id = FALCON_BOARD_SFN4112F, |
733 | .init = sfn4112f_init, |
734 | .init_phy = sfn4112f_init_phy, |
735 | .fini = ef4_fini_lm87, |
736 | .set_id_led = sfn4112f_set_id_led, |
737 | .monitor = sfn4112f_check_hw, |
738 | }, |
739 | }; |
740 | |
741 | int falcon_probe_board(struct ef4_nic *efx, u16 revision_info) |
742 | { |
743 | struct falcon_board *board = falcon_board(efx); |
744 | u8 type_id = FALCON_BOARD_TYPE(revision_info); |
745 | int i; |
746 | |
747 | board->major = FALCON_BOARD_MAJOR(revision_info); |
748 | board->minor = FALCON_BOARD_MINOR(revision_info); |
749 | |
750 | for (i = 0; i < ARRAY_SIZE(board_types); i++) |
751 | if (board_types[i].id == type_id) |
752 | board->type = &board_types[i]; |
753 | |
754 | if (board->type) { |
755 | return 0; |
756 | } else { |
757 | netif_err(efx, probe, efx->net_dev, "unknown board type %d\n" , |
758 | type_id); |
759 | return -ENODEV; |
760 | } |
761 | } |
762 | |