Commit | Line | Data |
---|---|---|
8ceee660 BH |
1 | /**************************************************************************** |
2 | * Driver for Solarflare Solarstorm network controllers and boards | |
3 | * Copyright 2007 Solarflare Communications Inc. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License version 2 as published | |
7 | * by the Free Software Foundation, incorporated herein by reference. | |
8 | */ | |
9 | ||
10 | /***************************************************************************** | |
11 | * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that | |
12 | * controls the PHY power rails, and for the MAX6647 temp. sensor used to check | |
13 | * the PHY | |
14 | */ | |
15 | #include <linux/delay.h> | |
16 | #include "efx.h" | |
17 | #include "phy.h" | |
18 | #include "boards.h" | |
19 | #include "falcon.h" | |
20 | #include "falcon_hwdefs.h" | |
21 | #include "mac.h" | |
22 | ||
23 | /************************************************************************** | |
24 | * | |
25 | * I2C IO Expander device | |
26 | * | |
27 | **************************************************************************/ | |
28 | #define PCA9539 0x74 | |
29 | ||
30 | #define P0_IN 0x00 | |
31 | #define P0_OUT 0x02 | |
32 | #define P0_INVERT 0x04 | |
33 | #define P0_CONFIG 0x06 | |
34 | ||
35 | #define P0_EN_1V0X_LBN 0 | |
36 | #define P0_EN_1V0X_WIDTH 1 | |
37 | #define P0_EN_1V2_LBN 1 | |
38 | #define P0_EN_1V2_WIDTH 1 | |
39 | #define P0_EN_2V5_LBN 2 | |
40 | #define P0_EN_2V5_WIDTH 1 | |
41 | #define P0_EN_3V3X_LBN 3 | |
42 | #define P0_EN_3V3X_WIDTH 1 | |
43 | #define P0_EN_5V_LBN 4 | |
44 | #define P0_EN_5V_WIDTH 1 | |
45 | #define P0_SHORTEN_JTAG_LBN 5 | |
46 | #define P0_SHORTEN_JTAG_WIDTH 1 | |
47 | #define P0_X_TRST_LBN 6 | |
48 | #define P0_X_TRST_WIDTH 1 | |
49 | #define P0_DSP_RESET_LBN 7 | |
50 | #define P0_DSP_RESET_WIDTH 1 | |
51 | ||
52 | #define P1_IN 0x01 | |
53 | #define P1_OUT 0x03 | |
54 | #define P1_INVERT 0x05 | |
55 | #define P1_CONFIG 0x07 | |
56 | ||
57 | #define P1_AFE_PWD_LBN 0 | |
58 | #define P1_AFE_PWD_WIDTH 1 | |
59 | #define P1_DSP_PWD25_LBN 1 | |
60 | #define P1_DSP_PWD25_WIDTH 1 | |
61 | #define P1_RESERVED_LBN 2 | |
62 | #define P1_RESERVED_WIDTH 2 | |
63 | #define P1_SPARE_LBN 4 | |
64 | #define P1_SPARE_WIDTH 4 | |
65 | ||
66 | ||
67 | /************************************************************************** | |
68 | * | |
69 | * Temperature Sensor | |
70 | * | |
71 | **************************************************************************/ | |
72 | #define MAX6647 0x4e | |
73 | ||
74 | #define RLTS 0x00 | |
75 | #define RLTE 0x01 | |
76 | #define RSL 0x02 | |
77 | #define RCL 0x03 | |
78 | #define RCRA 0x04 | |
79 | #define RLHN 0x05 | |
80 | #define RLLI 0x06 | |
81 | #define RRHI 0x07 | |
82 | #define RRLS 0x08 | |
83 | #define WCRW 0x0a | |
84 | #define WLHO 0x0b | |
85 | #define WRHA 0x0c | |
86 | #define WRLN 0x0e | |
87 | #define OSHT 0x0f | |
88 | #define REET 0x10 | |
89 | #define RIET 0x11 | |
90 | #define RWOE 0x19 | |
91 | #define RWOI 0x20 | |
92 | #define HYS 0x21 | |
93 | #define QUEUE 0x22 | |
94 | #define MFID 0xfe | |
95 | #define REVID 0xff | |
96 | ||
97 | /* Status bits */ | |
98 | #define MAX6647_BUSY (1 << 7) /* ADC is converting */ | |
99 | #define MAX6647_LHIGH (1 << 6) /* Local high temp. alarm */ | |
100 | #define MAX6647_LLOW (1 << 5) /* Local low temp. alarm */ | |
101 | #define MAX6647_RHIGH (1 << 4) /* Remote high temp. alarm */ | |
102 | #define MAX6647_RLOW (1 << 3) /* Remote low temp. alarm */ | |
103 | #define MAX6647_FAULT (1 << 2) /* DXN/DXP short/open circuit */ | |
104 | #define MAX6647_EOT (1 << 1) /* Remote junction overtemp. */ | |
105 | #define MAX6647_IOT (1 << 0) /* Local junction overtemp. */ | |
106 | ||
107 | static const u8 xgphy_max_temperature = 90; | |
108 | ||
37b5a603 | 109 | static void sfe4001_poweroff(struct efx_nic *efx) |
8ceee660 | 110 | { |
37b5a603 BH |
111 | struct i2c_client *ioexp_client = efx->board_info.ioexp_client; |
112 | struct i2c_client *hwmon_client = efx->board_info.hwmon_client; | |
8ceee660 | 113 | |
37b5a603 BH |
114 | /* Turn off all power rails and disable outputs */ |
115 | i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); | |
116 | i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff); | |
117 | i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); | |
8ceee660 | 118 | |
37b5a603 BH |
119 | /* Clear any over-temperature alert */ |
120 | i2c_smbus_read_byte_data(hwmon_client, RSL); | |
121 | } | |
8ceee660 | 122 | |
37b5a603 BH |
123 | static void sfe4001_fini(struct efx_nic *efx) |
124 | { | |
125 | EFX_INFO(efx, "%s\n", __func__); | |
8ceee660 | 126 | |
37b5a603 BH |
127 | sfe4001_poweroff(efx); |
128 | i2c_unregister_device(efx->board_info.ioexp_client); | |
129 | i2c_unregister_device(efx->board_info.hwmon_client); | |
8ceee660 BH |
130 | } |
131 | ||
75f2d3ea BH |
132 | /* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected |
133 | * to the FLASH_CFG_1 input on the DSP. We must keep it high at power- | |
134 | * up to allow writing the flash (done through MDIO from userland). | |
135 | */ | |
136 | unsigned int sfe4001_phy_flash_cfg; | |
137 | module_param_named(phy_flash_cfg, sfe4001_phy_flash_cfg, uint, 0444); | |
138 | MODULE_PARM_DESC(phy_flash_cfg, | |
139 | "Force PHY to enter flash configuration mode"); | |
140 | ||
8ceee660 BH |
141 | /* This board uses an I2C expander to provider power to the PHY, which needs to |
142 | * be turned on before the PHY can be used. | |
143 | * Context: Process context, rtnl lock held | |
144 | */ | |
37b5a603 | 145 | int sfe4001_init(struct efx_nic *efx) |
8ceee660 | 146 | { |
37b5a603 | 147 | struct i2c_client *hwmon_client, *ioexp_client; |
8ceee660 BH |
148 | unsigned int count; |
149 | int rc; | |
37b5a603 | 150 | u8 out; |
8ceee660 BH |
151 | efx_dword_t reg; |
152 | ||
37b5a603 BH |
153 | hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647); |
154 | if (!hwmon_client) | |
155 | return -EIO; | |
156 | efx->board_info.hwmon_client = hwmon_client; | |
157 | ||
158 | ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); | |
159 | if (!ioexp_client) { | |
160 | rc = -EIO; | |
161 | goto fail_hwmon; | |
162 | } | |
163 | efx->board_info.ioexp_client = ioexp_client; | |
164 | ||
8ceee660 BH |
165 | /* 10Xpress has fixed-function LED pins, so there is no board-specific |
166 | * blink code. */ | |
167 | efx->board_info.blink = tenxpress_phy_blink; | |
168 | ||
169 | /* Ensure that XGXS and XAUI SerDes are held in reset */ | |
170 | EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1, | |
171 | XX_PWRDNB_EN, 1, | |
172 | XX_RSTPLLAB_EN, 1, | |
173 | XX_RESETA_EN, 1, | |
174 | XX_RESETB_EN, 1, | |
175 | XX_RSTXGXSRX_EN, 1, | |
176 | XX_RSTXGXSTX_EN, 1); | |
177 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | |
178 | udelay(10); | |
179 | ||
37b5a603 BH |
180 | efx->board_info.fini = sfe4001_fini; |
181 | ||
8ceee660 BH |
182 | /* Set DSP over-temperature alert threshold */ |
183 | EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature); | |
37b5a603 BH |
184 | rc = i2c_smbus_write_byte_data(hwmon_client, WLHO, |
185 | xgphy_max_temperature); | |
8ceee660 | 186 | if (rc) |
37b5a603 | 187 | goto fail_ioexp; |
8ceee660 BH |
188 | |
189 | /* Read it back and verify */ | |
37b5a603 BH |
190 | rc = i2c_smbus_read_byte_data(hwmon_client, RLHN); |
191 | if (rc < 0) | |
192 | goto fail_ioexp; | |
193 | if (rc != xgphy_max_temperature) { | |
8ceee660 | 194 | rc = -EFAULT; |
37b5a603 | 195 | goto fail_ioexp; |
8ceee660 BH |
196 | } |
197 | ||
198 | /* Clear any previous over-temperature alert */ | |
37b5a603 BH |
199 | rc = i2c_smbus_read_byte_data(hwmon_client, RSL); |
200 | if (rc < 0) | |
201 | goto fail_ioexp; | |
8ceee660 BH |
202 | |
203 | /* Enable port 0 and port 1 outputs on IO expander */ | |
37b5a603 | 204 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); |
8ceee660 | 205 | if (rc) |
37b5a603 BH |
206 | goto fail_ioexp; |
207 | rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, | |
208 | 0xff & ~(1 << P1_SPARE_LBN)); | |
8ceee660 | 209 | if (rc) |
37b5a603 | 210 | goto fail_on; |
8ceee660 BH |
211 | |
212 | /* Turn all power off then wait 1 sec. This ensures PHY is reset */ | |
213 | out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | | |
214 | (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | | |
215 | (0 << P0_EN_1V0X_LBN)); | |
37b5a603 | 216 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); |
8ceee660 | 217 | if (rc) |
37b5a603 | 218 | goto fail_on; |
8ceee660 BH |
219 | |
220 | schedule_timeout_uninterruptible(HZ); | |
221 | count = 0; | |
222 | do { | |
223 | /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ | |
224 | out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | | |
225 | (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | | |
226 | (1 << P0_X_TRST_LBN)); | |
75f2d3ea BH |
227 | if (sfe4001_phy_flash_cfg) |
228 | out |= 1 << P0_EN_3V3X_LBN; | |
8ceee660 | 229 | |
37b5a603 | 230 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); |
8ceee660 | 231 | if (rc) |
37b5a603 | 232 | goto fail_on; |
8ceee660 BH |
233 | msleep(10); |
234 | ||
235 | /* Turn on 1V power rail */ | |
236 | out &= ~(1 << P0_EN_1V0X_LBN); | |
37b5a603 | 237 | rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); |
8ceee660 | 238 | if (rc) |
37b5a603 | 239 | goto fail_on; |
8ceee660 BH |
240 | |
241 | EFX_INFO(efx, "waiting for power (attempt %d)...\n", count); | |
242 | ||
243 | schedule_timeout_uninterruptible(HZ); | |
244 | ||
245 | /* Check DSP is powered */ | |
37b5a603 BH |
246 | rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); |
247 | if (rc < 0) | |
248 | goto fail_on; | |
249 | if (rc & (1 << P1_AFE_PWD_LBN)) | |
8ceee660 BH |
250 | goto done; |
251 | ||
75f2d3ea BH |
252 | /* DSP doesn't look powered in flash config mode */ |
253 | if (sfe4001_phy_flash_cfg) | |
254 | goto done; | |
8ceee660 BH |
255 | } while (++count < 20); |
256 | ||
257 | EFX_INFO(efx, "timed out waiting for power\n"); | |
258 | rc = -ETIMEDOUT; | |
37b5a603 | 259 | goto fail_on; |
8ceee660 BH |
260 | |
261 | done: | |
262 | EFX_INFO(efx, "PHY is powered on\n"); | |
263 | return 0; | |
264 | ||
37b5a603 BH |
265 | fail_on: |
266 | sfe4001_poweroff(efx); | |
267 | fail_ioexp: | |
268 | i2c_unregister_device(ioexp_client); | |
269 | fail_hwmon: | |
270 | i2c_unregister_device(hwmon_client); | |
8ceee660 BH |
271 | return rc; |
272 | } |