blob: bf1021ed5dd6c7d32d7c5ce4625c83e69687985e [file] [log] [blame]
Eilon Greensteind05c26c2009-01-17 23:26:13 -08001/* Copyright 2008-2009 Broadcom Corporation
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002 *
3 * Unless you and Broadcom execute a separate written software license
4 * agreement governing use of this software, this software is licensed to you
5 * under the terms of the GNU General Public License version 2, available
6 * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
7 *
8 * Notwithstanding the above, under no circumstances may you combine this
9 * software in any way with any other Broadcom software provided under a
10 * license other than the GPL, without Broadcom's express prior written
11 * consent.
12 *
13 * Written by Yaniv Rosner
14 *
15 */
16
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/pci.h>
20#include <linux/netdevice.h>
21#include <linux/delay.h>
22#include <linux/ethtool.h>
23#include <linux/mutex.h>
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070024
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070025#include "bnx2x.h"
26
27/********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070028#define ETH_HLEN 14
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070029#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
30#define ETH_MIN_PACKET_SIZE 60
31#define ETH_MAX_PACKET_SIZE 1500
32#define ETH_MAX_JUMBO_PACKET_SIZE 9600
33#define MDIO_ACCESS_TIMEOUT 1000
34#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070035
36/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070037/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070038/***********************************************************/
39
Eilon Greenstein2f904462009-08-12 08:22:16 +000040#define NIG_LATCH_BC_ENABLE_MI_INT 0
41
42#define NIG_STATUS_EMAC0_MI_INT \
43 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070044#define NIG_STATUS_XGXS0_LINK10G \
45 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
46#define NIG_STATUS_XGXS0_LINK_STATUS \
47 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
48#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
49 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
50#define NIG_STATUS_SERDES0_LINK_STATUS \
51 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
52#define NIG_MASK_MI_INT \
53 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
54#define NIG_MASK_XGXS0_LINK10G \
55 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
56#define NIG_MASK_XGXS0_LINK_STATUS \
57 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
58#define NIG_MASK_SERDES0_LINK_STATUS \
59 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
60
61#define MDIO_AN_CL73_OR_37_COMPLETE \
62 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
63 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
64
65#define XGXS_RESET_BITS \
66 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
67 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
68 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
71
72#define SERDES_RESET_BITS \
73 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
74 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
75 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
77
78#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
79#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Eilon Greenstein3196a882008-08-13 15:58:49 -070080#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
81#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070082 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070083#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070084 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070085#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070086
87#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
88 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
89#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
90 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
91#define GP_STATUS_SPEED_MASK \
92 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
93#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
94#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
95#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
96#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
97#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
98#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
99#define GP_STATUS_10G_HIG \
100 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
101#define GP_STATUS_10G_CX4 \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
103#define GP_STATUS_12G_HIG \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
105#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
106#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
107#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
108#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
109#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
110#define GP_STATUS_10G_KX4 \
111 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
112
113#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
114#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
115#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
116#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
117#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
118#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
119#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
120#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
121#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
122#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
123#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
124#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
125#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
126#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
127#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
128#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
129#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
130#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
131#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
132#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
133#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
134#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
135#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
136
137#define PHY_XGXS_FLAG 0x1
138#define PHY_SGMII_FLAG 0x2
139#define PHY_SERDES_FLAG 0x4
140
Eilon Greenstein589abe32009-02-12 08:36:55 +0000141/* */
142#define SFP_EEPROM_CON_TYPE_ADDR 0x2
143 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
144 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
145
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000146
147#define SFP_EEPROM_COMP_CODE_ADDR 0x3
148 #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
149 #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
150 #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
151
Eilon Greenstein589abe32009-02-12 08:36:55 +0000152#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
153 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
154 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000155
Eilon Greenstein589abe32009-02-12 08:36:55 +0000156#define SFP_EEPROM_OPTIONS_ADDR 0x40
157 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
158#define SFP_EEPROM_OPTIONS_SIZE 2
159
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000160#define EDC_MODE_LINEAR 0x0022
161#define EDC_MODE_LIMITING 0x0044
162#define EDC_MODE_PASSIVE_DAC 0x0055
Eilon Greenstein589abe32009-02-12 08:36:55 +0000163
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000164
165
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700166/**********************************************************/
167/* INTERFACE */
168/**********************************************************/
169#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
170 bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
171 DEFAULT_PHY_DEV_ADDR, \
172 (_bank + (_addr & 0xf)), \
173 _val)
174
175#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
176 bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
177 DEFAULT_PHY_DEV_ADDR, \
178 (_bank + (_addr & 0xf)), \
179 _val)
180
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000181static void bnx2x_set_serdes_access(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700182{
183 struct bnx2x *bp = params->bp;
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000184 u32 emac_base = (params->port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000185
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000186 /* Set Clause 22 */
187 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 1);
188 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
189 udelay(500);
190 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
191 udelay(500);
192 /* Set Clause 45 */
193 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 0);
194}
195static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags)
196{
197 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000198
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000199 if (phy_flags & PHY_XGXS_FLAG) {
200 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
201 params->port*0x18, 0);
202 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
203 DEFAULT_PHY_DEV_ADDR);
204 } else {
205 bnx2x_set_serdes_access(params);
206
207 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
208 params->port*0x10,
209 DEFAULT_PHY_DEV_ADDR);
210 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700211}
212
213static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
214{
215 u32 val = REG_RD(bp, reg);
216
217 val |= bits;
218 REG_WR(bp, reg, val);
219 return val;
220}
221
222static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
223{
224 u32 val = REG_RD(bp, reg);
225
226 val &= ~bits;
227 REG_WR(bp, reg, val);
228 return val;
229}
230
231static void bnx2x_emac_init(struct link_params *params,
232 struct link_vars *vars)
233{
234 /* reset and unreset the emac core */
235 struct bnx2x *bp = params->bp;
236 u8 port = params->port;
237 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
238 u32 val;
239 u16 timeout;
240
241 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
242 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
243 udelay(5);
244 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
245 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
246
247 /* init emac - use read-modify-write */
248 /* self clear reset */
249 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700250 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700251
252 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700253 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700254 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
255 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
256 if (!timeout) {
257 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
258 return;
259 }
260 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700261 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700262
263 /* Set mac address */
264 val = ((params->mac_addr[0] << 8) |
265 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700266 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700267
268 val = ((params->mac_addr[2] << 24) |
269 (params->mac_addr[3] << 16) |
270 (params->mac_addr[4] << 8) |
271 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700272 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700273}
274
275static u8 bnx2x_emac_enable(struct link_params *params,
276 struct link_vars *vars, u8 lb)
277{
278 struct bnx2x *bp = params->bp;
279 u8 port = params->port;
280 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
281 u32 val;
282
283 DP(NETIF_MSG_LINK, "enabling EMAC\n");
284
285 /* enable emac and not bmac */
286 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
287
288 /* for paladium */
289 if (CHIP_REV_IS_EMUL(bp)) {
290 /* Use lane 1 (of lanes 0-3) */
291 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
292 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
293 port*4, 1);
294 }
295 /* for fpga */
296 else
297
298 if (CHIP_REV_IS_FPGA(bp)) {
299 /* Use lane 1 (of lanes 0-3) */
300 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
301
302 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
303 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
304 0);
305 } else
306 /* ASIC */
307 if (vars->phy_flags & PHY_XGXS_FLAG) {
308 u32 ser_lane = ((params->lane_config &
309 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
310 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
311
312 DP(NETIF_MSG_LINK, "XGXS\n");
313 /* select the master lanes (out of 0-3) */
314 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
315 port*4, ser_lane);
316 /* select XGXS */
317 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
318 port*4, 1);
319
320 } else { /* SerDes */
321 DP(NETIF_MSG_LINK, "SerDes\n");
322 /* select SerDes */
323 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
324 port*4, 0);
325 }
326
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000327 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
328 EMAC_RX_MODE_RESET);
329 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
330 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700331
332 if (CHIP_REV_IS_SLOW(bp)) {
333 /* config GMII mode */
334 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700335 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700336 (val | EMAC_MODE_PORT_GMII));
337 } else { /* ASIC */
338 /* pause enable/disable */
339 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
340 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800341 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700342 bnx2x_bits_en(bp, emac_base +
343 EMAC_REG_EMAC_RX_MODE,
344 EMAC_RX_MODE_FLOW_EN);
345
346 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700347 (EMAC_TX_MODE_EXT_PAUSE_EN |
348 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800349 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700350 bnx2x_bits_en(bp, emac_base +
351 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700352 (EMAC_TX_MODE_EXT_PAUSE_EN |
353 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700354 }
355
356 /* KEEP_VLAN_TAG, promiscuous */
357 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
358 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700359 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700360
361 /* Set Loopback */
362 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
363 if (lb)
364 val |= 0x810;
365 else
366 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700367 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700368
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000369 /* enable emac */
370 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
371
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700372 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700373 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700374 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
375 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
376
377 /* strip CRC */
378 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
379
380 /* disable the NIG in/out to the bmac */
381 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
382 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
383 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
384
385 /* enable the NIG in/out to the emac */
386 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
387 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800388 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700389 val = 1;
390
391 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
392 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
393
394 if (CHIP_REV_IS_EMUL(bp)) {
395 /* take the BigMac out of reset */
396 REG_WR(bp,
397 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
398 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
399
400 /* enable access for bmac registers */
401 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
Eilon Greenstein6f654972009-08-12 08:23:51 +0000402 } else
403 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700404
405 vars->mac_type = MAC_TYPE_EMAC;
406 return 0;
407}
408
409
410
411static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
412 u8 is_lb)
413{
414 struct bnx2x *bp = params->bp;
415 u8 port = params->port;
416 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
417 NIG_REG_INGRESS_BMAC0_MEM;
418 u32 wb_data[2];
419 u32 val;
420
421 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
422 /* reset and unreset the BigMac */
423 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
424 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
425 msleep(1);
426
427 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
428 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
429
430 /* enable access for bmac registers */
431 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
432
433 /* XGXS control */
434 wb_data[0] = 0x3c;
435 wb_data[1] = 0;
436 REG_WR_DMAE(bp, bmac_addr +
437 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
438 wb_data, 2);
439
440 /* tx MAC SA */
441 wb_data[0] = ((params->mac_addr[2] << 24) |
442 (params->mac_addr[3] << 16) |
443 (params->mac_addr[4] << 8) |
444 params->mac_addr[5]);
445 wb_data[1] = ((params->mac_addr[0] << 8) |
446 params->mac_addr[1]);
447 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
448 wb_data, 2);
449
450 /* tx control */
451 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800452 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700453 val |= 0x800000;
454 wb_data[0] = val;
455 wb_data[1] = 0;
456 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
457 wb_data, 2);
458
459 /* mac control */
460 val = 0x3;
461 if (is_lb) {
462 val |= 0x4;
463 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
464 }
465 wb_data[0] = val;
466 wb_data[1] = 0;
467 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
468 wb_data, 2);
469
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700470 /* set rx mtu */
471 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
472 wb_data[1] = 0;
473 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
474 wb_data, 2);
475
476 /* rx control set to don't strip crc */
477 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800478 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700479 val |= 0x20;
480 wb_data[0] = val;
481 wb_data[1] = 0;
482 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
483 wb_data, 2);
484
485 /* set tx mtu */
486 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
487 wb_data[1] = 0;
488 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
489 wb_data, 2);
490
491 /* set cnt max size */
492 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
493 wb_data[1] = 0;
494 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
495 wb_data, 2);
496
497 /* configure safc */
498 wb_data[0] = 0x1000200;
499 wb_data[1] = 0;
500 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
501 wb_data, 2);
502 /* fix for emulation */
503 if (CHIP_REV_IS_EMUL(bp)) {
504 wb_data[0] = 0xf000;
505 wb_data[1] = 0;
506 REG_WR_DMAE(bp,
507 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
508 wb_data, 2);
509 }
510
511 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
512 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
513 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
514 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800515 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700516 val = 1;
517 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
518 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
519 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
520 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
521 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
522 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
523
524 vars->mac_type = MAC_TYPE_BMAC;
525 return 0;
526}
527
528static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
529{
530 struct bnx2x *bp = params->bp;
531 u32 val;
532
533 if (phy_flags & PHY_XGXS_FLAG) {
534 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
535 val = XGXS_RESET_BITS;
536
537 } else { /* SerDes */
538 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
539 val = SERDES_RESET_BITS;
540 }
541
542 val = val << (params->port*16);
543
544 /* reset and unreset the SerDes/XGXS */
545 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
546 val);
547 udelay(500);
548 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
549 val);
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000550 bnx2x_set_phy_mdio(params, phy_flags);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700551}
552
553void bnx2x_link_status_update(struct link_params *params,
554 struct link_vars *vars)
555{
556 struct bnx2x *bp = params->bp;
557 u8 link_10g;
558 u8 port = params->port;
559
560 if (params->switch_cfg == SWITCH_CFG_1G)
561 vars->phy_flags = PHY_SERDES_FLAG;
562 else
563 vars->phy_flags = PHY_XGXS_FLAG;
564 vars->link_status = REG_RD(bp, params->shmem_base +
565 offsetof(struct shmem_region,
566 port_mb[port].link_status));
567
568 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
569
570 if (vars->link_up) {
571 DP(NETIF_MSG_LINK, "phy link up\n");
572
573 vars->phy_link_up = 1;
574 vars->duplex = DUPLEX_FULL;
575 switch (vars->link_status &
576 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
577 case LINK_10THD:
578 vars->duplex = DUPLEX_HALF;
579 /* fall thru */
580 case LINK_10TFD:
581 vars->line_speed = SPEED_10;
582 break;
583
584 case LINK_100TXHD:
585 vars->duplex = DUPLEX_HALF;
586 /* fall thru */
587 case LINK_100T4:
588 case LINK_100TXFD:
589 vars->line_speed = SPEED_100;
590 break;
591
592 case LINK_1000THD:
593 vars->duplex = DUPLEX_HALF;
594 /* fall thru */
595 case LINK_1000TFD:
596 vars->line_speed = SPEED_1000;
597 break;
598
599 case LINK_2500THD:
600 vars->duplex = DUPLEX_HALF;
601 /* fall thru */
602 case LINK_2500TFD:
603 vars->line_speed = SPEED_2500;
604 break;
605
606 case LINK_10GTFD:
607 vars->line_speed = SPEED_10000;
608 break;
609
610 case LINK_12GTFD:
611 vars->line_speed = SPEED_12000;
612 break;
613
614 case LINK_12_5GTFD:
615 vars->line_speed = SPEED_12500;
616 break;
617
618 case LINK_13GTFD:
619 vars->line_speed = SPEED_13000;
620 break;
621
622 case LINK_15GTFD:
623 vars->line_speed = SPEED_15000;
624 break;
625
626 case LINK_16GTFD:
627 vars->line_speed = SPEED_16000;
628 break;
629
630 default:
631 break;
632 }
633
634 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800635 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700636 else
David S. Millerc0700f92008-12-16 23:53:20 -0800637 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700638
639 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800640 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700641 else
David S. Millerc0700f92008-12-16 23:53:20 -0800642 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700643
644 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700645 if (vars->line_speed &&
646 ((vars->line_speed == SPEED_10) ||
647 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700648 vars->phy_flags |= PHY_SGMII_FLAG;
649 } else {
650 vars->phy_flags &= ~PHY_SGMII_FLAG;
651 }
652 }
653
654 /* anything 10 and over uses the bmac */
655 link_10g = ((vars->line_speed == SPEED_10000) ||
656 (vars->line_speed == SPEED_12000) ||
657 (vars->line_speed == SPEED_12500) ||
658 (vars->line_speed == SPEED_13000) ||
659 (vars->line_speed == SPEED_15000) ||
660 (vars->line_speed == SPEED_16000));
661 if (link_10g)
662 vars->mac_type = MAC_TYPE_BMAC;
663 else
664 vars->mac_type = MAC_TYPE_EMAC;
665
666 } else { /* link down */
667 DP(NETIF_MSG_LINK, "phy link down\n");
668
669 vars->phy_link_up = 0;
670
671 vars->line_speed = 0;
672 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -0800673 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700674
675 /* indicate no mac active */
676 vars->mac_type = MAC_TYPE_NONE;
677 }
678
679 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
680 vars->link_status, vars->phy_link_up);
681 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
682 vars->line_speed, vars->duplex, vars->flow_ctrl);
683}
684
685static void bnx2x_update_mng(struct link_params *params, u32 link_status)
686{
687 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000688
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700689 REG_WR(bp, params->shmem_base +
690 offsetof(struct shmem_region,
691 port_mb[params->port].link_status),
692 link_status);
693}
694
695static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
696{
697 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
698 NIG_REG_INGRESS_BMAC0_MEM;
699 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700700 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700701
702 /* Only if the bmac is out of reset */
703 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
704 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
705 nig_bmac_enable) {
706
707 /* Clear Rx Enable bit in BMAC_CONTROL register */
708 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
709 wb_data, 2);
710 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
711 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
712 wb_data, 2);
713
714 msleep(1);
715 }
716}
717
718static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
719 u32 line_speed)
720{
721 struct bnx2x *bp = params->bp;
722 u8 port = params->port;
723 u32 init_crd, crd;
724 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700725
726 /* disable port */
727 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
728
729 /* wait for init credit */
730 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
731 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
732 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
733
734 while ((init_crd != crd) && count) {
735 msleep(5);
736
737 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
738 count--;
739 }
740 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
741 if (init_crd != crd) {
742 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
743 init_crd, crd);
744 return -EINVAL;
745 }
746
David S. Millerc0700f92008-12-16 23:53:20 -0800747 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700748 line_speed == SPEED_10 ||
749 line_speed == SPEED_100 ||
750 line_speed == SPEED_1000 ||
751 line_speed == SPEED_2500) {
752 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700753 /* update threshold */
754 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
755 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700756 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700757
758 } else {
759 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
760 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700761 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700762 /* update threshold */
763 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
764 /* update init credit */
765 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700766 case SPEED_10000:
767 init_crd = thresh + 553 - 22;
768 break;
769
770 case SPEED_12000:
771 init_crd = thresh + 664 - 22;
772 break;
773
774 case SPEED_13000:
775 init_crd = thresh + 742 - 22;
776 break;
777
778 case SPEED_16000:
779 init_crd = thresh + 778 - 22;
780 break;
781 default:
782 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
783 line_speed);
784 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700785 }
786 }
787 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
788 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
789 line_speed, init_crd);
790
791 /* probe the credit changes */
792 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
793 msleep(5);
794 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
795
796 /* enable port */
797 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
798 return 0;
799}
800
Eilon Greenstein589abe32009-02-12 08:36:55 +0000801static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700802{
803 u32 emac_base;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000804
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700805 switch (ext_phy_type) {
806 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000807 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000808 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000809 /* All MDC/MDIO is directed through single EMAC */
810 if (REG_RD(bp, NIG_REG_PORT_SWAP))
811 emac_base = GRCBASE_EMAC0;
812 else
813 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700814 break;
815 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700816 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700817 break;
818 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700819 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700820 break;
821 }
822 return emac_base;
823
824}
825
826u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
827 u8 phy_addr, u8 devad, u16 reg, u16 val)
828{
829 u32 tmp, saved_mode;
830 u8 i, rc = 0;
Eilon Greenstein589abe32009-02-12 08:36:55 +0000831 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700832
833 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
834 * (a value of 49==0x31) and make sure that the AUTO poll is off
835 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000836
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700837 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
838 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
839 EMAC_MDIO_MODE_CLOCK_CNT);
840 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
841 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
842 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
843 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
844 udelay(40);
845
846 /* address */
847
848 tmp = ((phy_addr << 21) | (devad << 16) | reg |
849 EMAC_MDIO_COMM_COMMAND_ADDRESS |
850 EMAC_MDIO_COMM_START_BUSY);
851 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
852
853 for (i = 0; i < 50; i++) {
854 udelay(10);
855
856 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
857 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
858 udelay(5);
859 break;
860 }
861 }
862 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
863 DP(NETIF_MSG_LINK, "write phy register failed\n");
864 rc = -EFAULT;
865 } else {
866 /* data */
867 tmp = ((phy_addr << 21) | (devad << 16) | val |
868 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
869 EMAC_MDIO_COMM_START_BUSY);
870 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
871
872 for (i = 0; i < 50; i++) {
873 udelay(10);
874
875 tmp = REG_RD(bp, mdio_ctrl +
876 EMAC_REG_EMAC_MDIO_COMM);
877 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
878 udelay(5);
879 break;
880 }
881 }
882 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
883 DP(NETIF_MSG_LINK, "write phy register failed\n");
884 rc = -EFAULT;
885 }
886 }
887
888 /* Restore the saved mode */
889 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
890
891 return rc;
892}
893
894u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
895 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
896{
897 u32 val, saved_mode;
898 u16 i;
899 u8 rc = 0;
900
Eilon Greenstein589abe32009-02-12 08:36:55 +0000901 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700902 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
903 * (a value of 49==0x31) and make sure that the AUTO poll is off
904 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000905
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700906 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
907 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
908 EMAC_MDIO_MODE_CLOCK_CNT));
909 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000910 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700911 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
912 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
913 udelay(40);
914
915 /* address */
916 val = ((phy_addr << 21) | (devad << 16) | reg |
917 EMAC_MDIO_COMM_COMMAND_ADDRESS |
918 EMAC_MDIO_COMM_START_BUSY);
919 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
920
921 for (i = 0; i < 50; i++) {
922 udelay(10);
923
924 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
925 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
926 udelay(5);
927 break;
928 }
929 }
930 if (val & EMAC_MDIO_COMM_START_BUSY) {
931 DP(NETIF_MSG_LINK, "read phy register failed\n");
932
933 *ret_val = 0;
934 rc = -EFAULT;
935
936 } else {
937 /* data */
938 val = ((phy_addr << 21) | (devad << 16) |
939 EMAC_MDIO_COMM_COMMAND_READ_45 |
940 EMAC_MDIO_COMM_START_BUSY);
941 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
942
943 for (i = 0; i < 50; i++) {
944 udelay(10);
945
946 val = REG_RD(bp, mdio_ctrl +
947 EMAC_REG_EMAC_MDIO_COMM);
948 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
949 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
950 break;
951 }
952 }
953 if (val & EMAC_MDIO_COMM_START_BUSY) {
954 DP(NETIF_MSG_LINK, "read phy register failed\n");
955
956 *ret_val = 0;
957 rc = -EFAULT;
958 }
959 }
960
961 /* Restore the saved mode */
962 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
963
964 return rc;
965}
966
967static void bnx2x_set_aer_mmd(struct link_params *params,
968 struct link_vars *vars)
969{
970 struct bnx2x *bp = params->bp;
971 u32 ser_lane;
972 u16 offset;
973
974 ser_lane = ((params->lane_config &
975 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
976 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
977
978 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
979 (params->phy_addr + ser_lane) : 0;
980
981 CL45_WR_OVER_CL22(bp, params->port,
982 params->phy_addr,
983 MDIO_REG_BANK_AER_BLOCK,
984 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
985}
986
987static void bnx2x_set_master_ln(struct link_params *params)
988{
989 struct bnx2x *bp = params->bp;
990 u16 new_master_ln, ser_lane;
991 ser_lane = ((params->lane_config &
992 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
993 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
994
995 /* set the master_ln for AN */
996 CL45_RD_OVER_CL22(bp, params->port,
997 params->phy_addr,
998 MDIO_REG_BANK_XGXS_BLOCK2,
999 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1000 &new_master_ln);
1001
1002 CL45_WR_OVER_CL22(bp, params->port,
1003 params->phy_addr,
1004 MDIO_REG_BANK_XGXS_BLOCK2 ,
1005 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1006 (new_master_ln | ser_lane));
1007}
1008
1009static u8 bnx2x_reset_unicore(struct link_params *params)
1010{
1011 struct bnx2x *bp = params->bp;
1012 u16 mii_control;
1013 u16 i;
1014
1015 CL45_RD_OVER_CL22(bp, params->port,
1016 params->phy_addr,
1017 MDIO_REG_BANK_COMBO_IEEE0,
1018 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1019
1020 /* reset the unicore */
1021 CL45_WR_OVER_CL22(bp, params->port,
1022 params->phy_addr,
1023 MDIO_REG_BANK_COMBO_IEEE0,
1024 MDIO_COMBO_IEEE0_MII_CONTROL,
1025 (mii_control |
1026 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Eilon Greenstein6f654972009-08-12 08:23:51 +00001027 if (params->switch_cfg == SWITCH_CFG_1G)
1028 bnx2x_set_serdes_access(params);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001029
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001030 /* wait for the reset to self clear */
1031 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1032 udelay(5);
1033
1034 /* the reset erased the previous bank value */
1035 CL45_RD_OVER_CL22(bp, params->port,
1036 params->phy_addr,
1037 MDIO_REG_BANK_COMBO_IEEE0,
1038 MDIO_COMBO_IEEE0_MII_CONTROL,
1039 &mii_control);
1040
1041 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1042 udelay(5);
1043 return 0;
1044 }
1045 }
1046
1047 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1048 return -EINVAL;
1049
1050}
1051
1052static void bnx2x_set_swap_lanes(struct link_params *params)
1053{
1054 struct bnx2x *bp = params->bp;
1055 /* Each two bits represents a lane number:
1056 No swap is 0123 => 0x1b no need to enable the swap */
1057 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1058
1059 ser_lane = ((params->lane_config &
1060 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1061 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1062 rx_lane_swap = ((params->lane_config &
1063 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1064 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1065 tx_lane_swap = ((params->lane_config &
1066 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1067 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1068
1069 if (rx_lane_swap != 0x1b) {
1070 CL45_WR_OVER_CL22(bp, params->port,
1071 params->phy_addr,
1072 MDIO_REG_BANK_XGXS_BLOCK2,
1073 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1074 (rx_lane_swap |
1075 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1076 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1077 } else {
1078 CL45_WR_OVER_CL22(bp, params->port,
1079 params->phy_addr,
1080 MDIO_REG_BANK_XGXS_BLOCK2,
1081 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1082 }
1083
1084 if (tx_lane_swap != 0x1b) {
1085 CL45_WR_OVER_CL22(bp, params->port,
1086 params->phy_addr,
1087 MDIO_REG_BANK_XGXS_BLOCK2,
1088 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1089 (tx_lane_swap |
1090 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1091 } else {
1092 CL45_WR_OVER_CL22(bp, params->port,
1093 params->phy_addr,
1094 MDIO_REG_BANK_XGXS_BLOCK2,
1095 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1096 }
1097}
1098
1099static void bnx2x_set_parallel_detection(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07001100 u8 phy_flags)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001101{
1102 struct bnx2x *bp = params->bp;
1103 u16 control2;
1104
1105 CL45_RD_OVER_CL22(bp, params->port,
1106 params->phy_addr,
1107 MDIO_REG_BANK_SERDES_DIGITAL,
1108 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1109 &control2);
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001110 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1111 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1112 else
1113 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1114 DP(NETIF_MSG_LINK, "params->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1115 params->speed_cap_mask, control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001116 CL45_WR_OVER_CL22(bp, params->port,
1117 params->phy_addr,
1118 MDIO_REG_BANK_SERDES_DIGITAL,
1119 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1120 control2);
1121
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001122 if ((phy_flags & PHY_XGXS_FLAG) &&
1123 (params->speed_cap_mask &
1124 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001125 DP(NETIF_MSG_LINK, "XGXS\n");
1126
1127 CL45_WR_OVER_CL22(bp, params->port,
1128 params->phy_addr,
1129 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1130 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1131 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1132
1133 CL45_RD_OVER_CL22(bp, params->port,
1134 params->phy_addr,
1135 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1136 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1137 &control2);
1138
1139
1140 control2 |=
1141 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1142
1143 CL45_WR_OVER_CL22(bp, params->port,
1144 params->phy_addr,
1145 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1146 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1147 control2);
1148
1149 /* Disable parallel detection of HiG */
1150 CL45_WR_OVER_CL22(bp, params->port,
1151 params->phy_addr,
1152 MDIO_REG_BANK_XGXS_BLOCK2,
1153 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1154 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1155 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1156 }
1157}
1158
1159static void bnx2x_set_autoneg(struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001160 struct link_vars *vars,
1161 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001162{
1163 struct bnx2x *bp = params->bp;
1164 u16 reg_val;
1165
1166 /* CL37 Autoneg */
1167
1168 CL45_RD_OVER_CL22(bp, params->port,
1169 params->phy_addr,
1170 MDIO_REG_BANK_COMBO_IEEE0,
1171 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1172
1173 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001174 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001175 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1176 else /* CL37 Autoneg Disabled */
1177 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1178 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1179
1180 CL45_WR_OVER_CL22(bp, params->port,
1181 params->phy_addr,
1182 MDIO_REG_BANK_COMBO_IEEE0,
1183 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1184
1185 /* Enable/Disable Autodetection */
1186
1187 CL45_RD_OVER_CL22(bp, params->port,
1188 params->phy_addr,
1189 MDIO_REG_BANK_SERDES_DIGITAL,
1190 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001191 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1192 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1193 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001194 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001195 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1196 else
1197 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1198
1199 CL45_WR_OVER_CL22(bp, params->port,
1200 params->phy_addr,
1201 MDIO_REG_BANK_SERDES_DIGITAL,
1202 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1203
1204 /* Enable TetonII and BAM autoneg */
1205 CL45_RD_OVER_CL22(bp, params->port,
1206 params->phy_addr,
1207 MDIO_REG_BANK_BAM_NEXT_PAGE,
1208 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1209 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001210 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001211 /* Enable BAM aneg Mode and TetonII aneg Mode */
1212 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1213 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1214 } else {
1215 /* TetonII and BAM Autoneg Disabled */
1216 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1217 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1218 }
1219 CL45_WR_OVER_CL22(bp, params->port,
1220 params->phy_addr,
1221 MDIO_REG_BANK_BAM_NEXT_PAGE,
1222 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1223 reg_val);
1224
Eilon Greenstein239d6862009-08-12 08:23:04 +00001225 if (enable_cl73) {
1226 /* Enable Cl73 FSM status bits */
1227 CL45_WR_OVER_CL22(bp, params->port,
1228 params->phy_addr,
1229 MDIO_REG_BANK_CL73_USERB0,
1230 MDIO_CL73_USERB0_CL73_UCTRL,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001231 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001232
1233 /* Enable BAM Station Manager*/
1234 CL45_WR_OVER_CL22(bp, params->port,
1235 params->phy_addr,
1236 MDIO_REG_BANK_CL73_USERB0,
1237 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1238 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1239 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1240 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
1241
Yaniv Rosner7846e472009-11-05 19:18:07 +02001242 /* Advertise CL73 link speeds */
Eilon Greenstein239d6862009-08-12 08:23:04 +00001243 CL45_RD_OVER_CL22(bp, params->port,
1244 params->phy_addr,
1245 MDIO_REG_BANK_CL73_IEEEB1,
1246 MDIO_CL73_IEEEB1_AN_ADV2,
1247 &reg_val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02001248 if (params->speed_cap_mask &
1249 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1250 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1251 if (params->speed_cap_mask &
1252 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1253 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001254
1255 CL45_WR_OVER_CL22(bp, params->port,
1256 params->phy_addr,
1257 MDIO_REG_BANK_CL73_IEEEB1,
1258 MDIO_CL73_IEEEB1_AN_ADV2,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001259 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001260
Eilon Greenstein239d6862009-08-12 08:23:04 +00001261 /* CL73 Autoneg Enabled */
1262 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1263
1264 } else /* CL73 Autoneg Disabled */
1265 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001266
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001267 CL45_WR_OVER_CL22(bp, params->port,
1268 params->phy_addr,
1269 MDIO_REG_BANK_CL73_IEEEB0,
1270 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1271}
1272
1273/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001274static void bnx2x_program_serdes(struct link_params *params,
1275 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001276{
1277 struct bnx2x *bp = params->bp;
1278 u16 reg_val;
1279
Eilon Greenstein57937202009-08-12 08:23:53 +00001280 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001281 CL45_RD_OVER_CL22(bp, params->port,
1282 params->phy_addr,
1283 MDIO_REG_BANK_COMBO_IEEE0,
1284 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1285 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00001286 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1287 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001288 if (params->req_duplex == DUPLEX_FULL)
1289 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1290 CL45_WR_OVER_CL22(bp, params->port,
1291 params->phy_addr,
1292 MDIO_REG_BANK_COMBO_IEEE0,
1293 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1294
1295 /* program speed
1296 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001297 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001298 params->phy_addr,
1299 MDIO_REG_BANK_SERDES_DIGITAL,
1300 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001301 /* clearing the speed value before setting the right speed */
1302 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1303
1304 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1305 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1306
1307 if (!((vars->line_speed == SPEED_1000) ||
1308 (vars->line_speed == SPEED_100) ||
1309 (vars->line_speed == SPEED_10))) {
1310
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001311 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1312 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001313 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001314 reg_val |=
1315 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001316 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001317 reg_val |=
1318 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001319 }
1320
1321 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001322 params->phy_addr,
1323 MDIO_REG_BANK_SERDES_DIGITAL,
1324 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001325
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001326}
1327
1328static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1329{
1330 struct bnx2x *bp = params->bp;
1331 u16 val = 0;
1332
1333 /* configure the 48 bits for BAM AN */
1334
1335 /* set extended capabilities */
1336 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1337 val |= MDIO_OVER_1G_UP1_2_5G;
1338 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1339 val |= MDIO_OVER_1G_UP1_10G;
1340 CL45_WR_OVER_CL22(bp, params->port,
1341 params->phy_addr,
1342 MDIO_REG_BANK_OVER_1G,
1343 MDIO_OVER_1G_UP1, val);
1344
1345 CL45_WR_OVER_CL22(bp, params->port,
1346 params->phy_addr,
1347 MDIO_REG_BANK_OVER_1G,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001348 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001349}
1350
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001351static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001352{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001353 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001354 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001355 /* resolve pause mode and advertisement
1356 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1357
1358 switch (params->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001359 case BNX2X_FLOW_CTRL_AUTO:
1360 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001361 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001362 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1363 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001364 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001365 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1366 }
1367 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001368 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001369 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001370 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1371 break;
1372
David S. Millerc0700f92008-12-16 23:53:20 -08001373 case BNX2X_FLOW_CTRL_RX:
1374 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001375 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001376 break;
1377
David S. Millerc0700f92008-12-16 23:53:20 -08001378 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001379 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001380 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001381 break;
1382 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001383 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001384}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001385
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001386static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001387 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001388{
1389 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001390 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001391 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001392
1393 CL45_WR_OVER_CL22(bp, params->port,
1394 params->phy_addr,
1395 MDIO_REG_BANK_COMBO_IEEE0,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001396 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosner7846e472009-11-05 19:18:07 +02001397 CL45_RD_OVER_CL22(bp, params->port,
1398 params->phy_addr,
1399 MDIO_REG_BANK_CL73_IEEEB1,
1400 MDIO_CL73_IEEEB1_AN_ADV1, &val);
1401 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
1402 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
1403 CL45_WR_OVER_CL22(bp, params->port,
1404 params->phy_addr,
1405 MDIO_REG_BANK_CL73_IEEEB1,
1406 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001407}
1408
Eilon Greenstein239d6862009-08-12 08:23:04 +00001409static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001410{
1411 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001412 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001413
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001414 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001415 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001416
Eilon Greenstein239d6862009-08-12 08:23:04 +00001417 if (enable_cl73) {
1418 CL45_RD_OVER_CL22(bp, params->port,
1419 params->phy_addr,
1420 MDIO_REG_BANK_CL73_IEEEB0,
1421 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1422 &mii_control);
1423
1424 CL45_WR_OVER_CL22(bp, params->port,
1425 params->phy_addr,
1426 MDIO_REG_BANK_CL73_IEEEB0,
1427 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1428 (mii_control |
1429 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1430 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1431 } else {
1432
1433 CL45_RD_OVER_CL22(bp, params->port,
1434 params->phy_addr,
1435 MDIO_REG_BANK_COMBO_IEEE0,
1436 MDIO_COMBO_IEEE0_MII_CONTROL,
1437 &mii_control);
1438 DP(NETIF_MSG_LINK,
1439 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1440 mii_control);
1441 CL45_WR_OVER_CL22(bp, params->port,
1442 params->phy_addr,
1443 MDIO_REG_BANK_COMBO_IEEE0,
1444 MDIO_COMBO_IEEE0_MII_CONTROL,
1445 (mii_control |
1446 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1447 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1448 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001449}
1450
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001451static void bnx2x_initialize_sgmii_process(struct link_params *params,
1452 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001453{
1454 struct bnx2x *bp = params->bp;
1455 u16 control1;
1456
1457 /* in SGMII mode, the unicore is always slave */
1458
1459 CL45_RD_OVER_CL22(bp, params->port,
1460 params->phy_addr,
1461 MDIO_REG_BANK_SERDES_DIGITAL,
1462 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1463 &control1);
1464 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1465 /* set sgmii mode (and not fiber) */
1466 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1467 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1468 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1469 CL45_WR_OVER_CL22(bp, params->port,
1470 params->phy_addr,
1471 MDIO_REG_BANK_SERDES_DIGITAL,
1472 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1473 control1);
1474
1475 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001476 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001477 /* set speed, disable autoneg */
1478 u16 mii_control;
1479
1480 CL45_RD_OVER_CL22(bp, params->port,
1481 params->phy_addr,
1482 MDIO_REG_BANK_COMBO_IEEE0,
1483 MDIO_COMBO_IEEE0_MII_CONTROL,
1484 &mii_control);
1485 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1486 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1487 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1488
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001489 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001490 case SPEED_100:
1491 mii_control |=
1492 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1493 break;
1494 case SPEED_1000:
1495 mii_control |=
1496 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1497 break;
1498 case SPEED_10:
1499 /* there is nothing to set for 10M */
1500 break;
1501 default:
1502 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001503 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1504 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001505 break;
1506 }
1507
1508 /* setting the full duplex */
1509 if (params->req_duplex == DUPLEX_FULL)
1510 mii_control |=
1511 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1512 CL45_WR_OVER_CL22(bp, params->port,
1513 params->phy_addr,
1514 MDIO_REG_BANK_COMBO_IEEE0,
1515 MDIO_COMBO_IEEE0_MII_CONTROL,
1516 mii_control);
1517
1518 } else { /* AN mode */
1519 /* enable and restart AN */
Eilon Greenstein239d6862009-08-12 08:23:04 +00001520 bnx2x_restart_autoneg(params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001521 }
1522}
1523
1524
1525/*
1526 * link management
1527 */
1528
1529static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001530{ /* LD LP */
1531 switch (pause_result) { /* ASYM P ASYM P */
1532 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001533 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001534 break;
1535
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001536 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001537 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001538 break;
1539
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001540 case 0x5: /* 0 1 0 1 */
1541 case 0x7: /* 0 1 1 1 */
1542 case 0xd: /* 1 1 0 1 */
1543 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001544 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001545 break;
1546
1547 default:
1548 break;
1549 }
1550}
1551
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001552static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001553 struct link_vars *vars)
1554{
1555 struct bnx2x *bp = params->bp;
1556 u8 ext_phy_addr;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001557 u16 ld_pause; /* local */
1558 u16 lp_pause; /* link partner */
1559 u16 an_complete; /* AN complete */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001560 u16 pause_result;
1561 u8 ret = 0;
1562 u32 ext_phy_type;
1563 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00001564 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001565 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1566 /* read twice */
1567
1568 bnx2x_cl45_read(bp, port,
1569 ext_phy_type,
1570 ext_phy_addr,
1571 MDIO_AN_DEVAD,
1572 MDIO_AN_REG_STATUS, &an_complete);
1573 bnx2x_cl45_read(bp, port,
1574 ext_phy_type,
1575 ext_phy_addr,
1576 MDIO_AN_DEVAD,
1577 MDIO_AN_REG_STATUS, &an_complete);
1578
1579 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1580 ret = 1;
1581 bnx2x_cl45_read(bp, port,
1582 ext_phy_type,
1583 ext_phy_addr,
1584 MDIO_AN_DEVAD,
1585 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1586 bnx2x_cl45_read(bp, port,
1587 ext_phy_type,
1588 ext_phy_addr,
1589 MDIO_AN_DEVAD,
1590 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1591 pause_result = (ld_pause &
1592 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1593 pause_result |= (lp_pause &
1594 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1595 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
1596 pause_result);
1597 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001598 if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001599 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1600 bnx2x_cl45_read(bp, port,
1601 ext_phy_type,
1602 ext_phy_addr,
1603 MDIO_AN_DEVAD,
1604 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1605
1606 bnx2x_cl45_read(bp, port,
1607 ext_phy_type,
1608 ext_phy_addr,
1609 MDIO_AN_DEVAD,
1610 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1611 pause_result = (ld_pause &
1612 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1613 pause_result |= (lp_pause &
1614 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1615
1616 bnx2x_pause_resolve(vars, pause_result);
1617 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
1618 pause_result);
1619 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001620 }
1621 return ret;
1622}
1623
1624
1625static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1626 struct link_vars *vars,
1627 u32 gp_status)
1628{
1629 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001630 u16 ld_pause; /* local driver */
1631 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001632 u16 pause_result;
1633
David S. Millerc0700f92008-12-16 23:53:20 -08001634 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001635
1636 /* resolve from gp_status in case of AN complete and not sgmii */
David S. Millerc0700f92008-12-16 23:53:20 -08001637 if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001638 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1639 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1640 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1641 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
Yaniv Rosner7846e472009-11-05 19:18:07 +02001642 if ((gp_status &
1643 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1644 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
1645 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1646 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
1647
1648 CL45_RD_OVER_CL22(bp, params->port,
1649 params->phy_addr,
1650 MDIO_REG_BANK_CL73_IEEEB1,
1651 MDIO_CL73_IEEEB1_AN_ADV1,
1652 &ld_pause);
1653 CL45_RD_OVER_CL22(bp, params->port,
1654 params->phy_addr,
1655 MDIO_REG_BANK_CL73_IEEEB1,
1656 MDIO_CL73_IEEEB1_AN_LP_ADV1,
1657 &lp_pause);
1658 pause_result = (ld_pause &
1659 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
1660 >> 8;
1661 pause_result |= (lp_pause &
1662 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
1663 >> 10;
1664 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
1665 pause_result);
1666 } else {
1667
1668 CL45_RD_OVER_CL22(bp, params->port,
1669 params->phy_addr,
1670 MDIO_REG_BANK_COMBO_IEEE0,
1671 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1672 &ld_pause);
1673 CL45_RD_OVER_CL22(bp, params->port,
1674 params->phy_addr,
1675 MDIO_REG_BANK_COMBO_IEEE0,
1676 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1677 &lp_pause);
1678 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001679 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001680 pause_result |= (lp_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001681 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001682 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
1683 pause_result);
1684 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001685 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001686 } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001687 (bnx2x_ext_phy_resolve_fc(params, vars))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001688 return;
1689 } else {
David S. Millerc0700f92008-12-16 23:53:20 -08001690 if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001691 vars->flow_ctrl = params->req_fc_auto_adv;
1692 else
1693 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001694 }
1695 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1696}
1697
Eilon Greenstein239d6862009-08-12 08:23:04 +00001698static void bnx2x_check_fallback_to_cl37(struct link_params *params)
1699{
1700 struct bnx2x *bp = params->bp;
1701 u16 rx_status, ustat_val, cl37_fsm_recieved;
1702 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
1703 /* Step 1: Make sure signal is detected */
1704 CL45_RD_OVER_CL22(bp, params->port,
1705 params->phy_addr,
1706 MDIO_REG_BANK_RX0,
1707 MDIO_RX0_RX_STATUS,
1708 &rx_status);
1709 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
1710 (MDIO_RX0_RX_STATUS_SIGDET)) {
1711 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
1712 "rx_status(0x80b0) = 0x%x\n", rx_status);
1713 CL45_WR_OVER_CL22(bp, params->port,
1714 params->phy_addr,
1715 MDIO_REG_BANK_CL73_IEEEB0,
1716 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1717 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
1718 return;
1719 }
1720 /* Step 2: Check CL73 state machine */
1721 CL45_RD_OVER_CL22(bp, params->port,
1722 params->phy_addr,
1723 MDIO_REG_BANK_CL73_USERB0,
1724 MDIO_CL73_USERB0_CL73_USTAT1,
1725 &ustat_val);
1726 if ((ustat_val &
1727 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1728 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
1729 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1730 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
1731 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
1732 "ustat_val(0x8371) = 0x%x\n", ustat_val);
1733 return;
1734 }
1735 /* Step 3: Check CL37 Message Pages received to indicate LP
1736 supports only CL37 */
1737 CL45_RD_OVER_CL22(bp, params->port,
1738 params->phy_addr,
1739 MDIO_REG_BANK_REMOTE_PHY,
1740 MDIO_REMOTE_PHY_MISC_RX_STATUS,
1741 &cl37_fsm_recieved);
1742 if ((cl37_fsm_recieved &
1743 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1744 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
1745 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1746 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
1747 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
1748 "misc_rx_status(0x8330) = 0x%x\n",
1749 cl37_fsm_recieved);
1750 return;
1751 }
1752 /* The combined cl37/cl73 fsm state information indicating that we are
1753 connected to a device which does not support cl73, but does support
1754 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
1755 /* Disable CL73 */
1756 CL45_WR_OVER_CL22(bp, params->port,
1757 params->phy_addr,
1758 MDIO_REG_BANK_CL73_IEEEB0,
1759 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1760 0);
1761 /* Restart CL37 autoneg */
1762 bnx2x_restart_autoneg(params, 0);
1763 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
1764}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001765static u8 bnx2x_link_settings_status(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00001766 struct link_vars *vars,
1767 u32 gp_status,
1768 u8 ext_phy_link_up)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001769{
1770 struct bnx2x *bp = params->bp;
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001771 u16 new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001772 u8 rc = 0;
1773 vars->link_status = 0;
1774
1775 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1776 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1777 gp_status);
1778
1779 vars->phy_link_up = 1;
1780 vars->link_status |= LINK_STATUS_LINK_UP;
1781
1782 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1783 vars->duplex = DUPLEX_FULL;
1784 else
1785 vars->duplex = DUPLEX_HALF;
1786
1787 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1788
1789 switch (gp_status & GP_STATUS_SPEED_MASK) {
1790 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001791 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001792 if (vars->duplex == DUPLEX_FULL)
1793 vars->link_status |= LINK_10TFD;
1794 else
1795 vars->link_status |= LINK_10THD;
1796 break;
1797
1798 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001799 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001800 if (vars->duplex == DUPLEX_FULL)
1801 vars->link_status |= LINK_100TXFD;
1802 else
1803 vars->link_status |= LINK_100TXHD;
1804 break;
1805
1806 case GP_STATUS_1G:
1807 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001808 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001809 if (vars->duplex == DUPLEX_FULL)
1810 vars->link_status |= LINK_1000TFD;
1811 else
1812 vars->link_status |= LINK_1000THD;
1813 break;
1814
1815 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001816 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001817 if (vars->duplex == DUPLEX_FULL)
1818 vars->link_status |= LINK_2500TFD;
1819 else
1820 vars->link_status |= LINK_2500THD;
1821 break;
1822
1823 case GP_STATUS_5G:
1824 case GP_STATUS_6G:
1825 DP(NETIF_MSG_LINK,
1826 "link speed unsupported gp_status 0x%x\n",
1827 gp_status);
1828 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001829
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001830 case GP_STATUS_10G_KX4:
1831 case GP_STATUS_10G_HIG:
1832 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001833 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001834 vars->link_status |= LINK_10GTFD;
1835 break;
1836
1837 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001838 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001839 vars->link_status |= LINK_12GTFD;
1840 break;
1841
1842 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001843 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001844 vars->link_status |= LINK_12_5GTFD;
1845 break;
1846
1847 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001848 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001849 vars->link_status |= LINK_13GTFD;
1850 break;
1851
1852 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001853 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001854 vars->link_status |= LINK_15GTFD;
1855 break;
1856
1857 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001858 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001859 vars->link_status |= LINK_16GTFD;
1860 break;
1861
1862 default:
1863 DP(NETIF_MSG_LINK,
1864 "link speed unsupported gp_status 0x%x\n",
1865 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001866 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001867 }
1868
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001869 /* Upon link speed change set the NIG into drain mode.
1870 Comes to deals with possible FIFO glitch due to clk change
1871 when speed is decreased without link down indicator */
1872 if (new_line_speed != vars->line_speed) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00001873 if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) !=
1874 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT &&
1875 ext_phy_link_up) {
1876 DP(NETIF_MSG_LINK, "Internal link speed %d is"
1877 " different than the external"
1878 " link speed %d\n", new_line_speed,
1879 vars->line_speed);
1880 vars->phy_link_up = 0;
1881 return 0;
1882 }
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001883 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
1884 + params->port*4, 0);
1885 msleep(1);
1886 }
1887 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001888 vars->link_status |= LINK_STATUS_SERDES_LINK;
1889
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001890 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1891 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1892 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1893 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein589abe32009-02-12 08:36:55 +00001894 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
1895 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein2f904462009-08-12 08:22:16 +00001896 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001897 vars->autoneg = AUTO_NEG_ENABLED;
1898
1899 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1900 vars->autoneg |= AUTO_NEG_COMPLETE;
1901 vars->link_status |=
1902 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1903 }
1904
1905 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1906 vars->link_status |=
1907 LINK_STATUS_PARALLEL_DETECTION_USED;
1908
1909 }
David S. Millerc0700f92008-12-16 23:53:20 -08001910 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001911 vars->link_status |=
1912 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001913
David S. Millerc0700f92008-12-16 23:53:20 -08001914 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001915 vars->link_status |=
1916 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001917
1918 } else { /* link_down */
1919 DP(NETIF_MSG_LINK, "phy link down\n");
1920
1921 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001922
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001923 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001924 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001925 vars->autoneg = AUTO_NEG_DISABLED;
1926 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001927
1928 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1929 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1930 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT))) {
1931 /* Check signal is detected */
1932 bnx2x_check_fallback_to_cl37(params);
1933 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001934 }
1935
1936 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n",
1937 gp_status, vars->phy_link_up, vars->line_speed);
1938 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1939 " autoneg 0x%x\n",
1940 vars->duplex,
1941 vars->flow_ctrl, vars->autoneg);
1942 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1943
1944 return rc;
1945}
1946
Eilon Greensteined8680a2009-02-12 08:37:12 +00001947static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001948{
1949 struct bnx2x *bp = params->bp;
1950 u16 lp_up2;
1951 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001952 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001953
1954 /* read precomp */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001955 CL45_RD_OVER_CL22(bp, params->port,
1956 params->phy_addr,
1957 MDIO_REG_BANK_OVER_1G,
1958 MDIO_OVER_1G_LP_UP2, &lp_up2);
1959
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001960 /* bits [10:7] at lp_up2, positioned at [15:12] */
1961 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1962 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1963 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1964
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001965 if (lp_up2 == 0)
1966 return;
1967
1968 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
1969 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
1970 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001971 params->phy_addr,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001972 bank,
1973 MDIO_TX0_TX_DRIVER, &tx_driver);
1974
1975 /* replace tx_driver bits [15:12] */
1976 if (lp_up2 !=
1977 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
1978 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1979 tx_driver |= lp_up2;
1980 CL45_WR_OVER_CL22(bp, params->port,
1981 params->phy_addr,
1982 bank,
1983 MDIO_TX0_TX_DRIVER, tx_driver);
1984 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001985 }
1986}
1987
1988static u8 bnx2x_emac_program(struct link_params *params,
1989 u32 line_speed, u32 duplex)
1990{
1991 struct bnx2x *bp = params->bp;
1992 u8 port = params->port;
1993 u16 mode = 0;
1994
1995 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1996 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1997 EMAC_REG_EMAC_MODE,
1998 (EMAC_MODE_25G_MODE |
1999 EMAC_MODE_PORT_MII_10M |
2000 EMAC_MODE_HALF_DUPLEX));
2001 switch (line_speed) {
2002 case SPEED_10:
2003 mode |= EMAC_MODE_PORT_MII_10M;
2004 break;
2005
2006 case SPEED_100:
2007 mode |= EMAC_MODE_PORT_MII;
2008 break;
2009
2010 case SPEED_1000:
2011 mode |= EMAC_MODE_PORT_GMII;
2012 break;
2013
2014 case SPEED_2500:
2015 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2016 break;
2017
2018 default:
2019 /* 10G not valid for EMAC */
2020 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
2021 return -EINVAL;
2022 }
2023
2024 if (duplex == DUPLEX_HALF)
2025 mode |= EMAC_MODE_HALF_DUPLEX;
2026 bnx2x_bits_en(bp,
2027 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2028 mode);
2029
Yaniv Rosner7846e472009-11-05 19:18:07 +02002030 bnx2x_set_led(params, LED_MODE_OPER, line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002031 return 0;
2032}
2033
2034/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002035/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002036/*****************************************************************************/
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002037void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002038{
2039 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002040 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002041 msleep(1);
2042 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002043 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002044}
2045
2046static void bnx2x_ext_phy_reset(struct link_params *params,
2047 struct link_vars *vars)
2048{
2049 struct bnx2x *bp = params->bp;
2050 u32 ext_phy_type;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002051 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
2052
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002053 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
2054 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2055 /* The PHY reset is controled by GPIO 1
2056 * Give it 1ms of reset pulse
2057 */
2058 if (vars->phy_flags & PHY_XGXS_FLAG) {
2059
2060 switch (ext_phy_type) {
2061 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
2062 DP(NETIF_MSG_LINK, "XGXS Direct\n");
2063 break;
2064
2065 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2066 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2067 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
2068
2069 /* Restore normal power mode*/
2070 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002071 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2072 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002073
2074 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002075 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002076
2077 bnx2x_cl45_write(bp, params->port,
2078 ext_phy_type,
2079 ext_phy_addr,
2080 MDIO_PMA_DEVAD,
2081 MDIO_PMA_REG_CTRL, 0xa040);
2082 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002083
2084 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
2085 break;
2086
Eilon Greenstein589abe32009-02-12 08:36:55 +00002087 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
2088
2089 /* Restore normal power mode*/
2090 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2091 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2092 params->port);
2093
2094 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
2095 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2096 params->port);
2097
2098 bnx2x_cl45_write(bp, params->port,
2099 ext_phy_type,
2100 ext_phy_addr,
2101 MDIO_PMA_DEVAD,
2102 MDIO_PMA_REG_CTRL,
2103 1<<15);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002104 break;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002105
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002106 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002107 DP(NETIF_MSG_LINK, "XGXS 8072\n");
2108
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002109 /* Unset Low Power Mode and SW reset */
2110 /* Restore normal power mode*/
2111 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002112 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2113 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002114
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002115 bnx2x_cl45_write(bp, params->port,
2116 ext_phy_type,
2117 ext_phy_addr,
2118 MDIO_PMA_DEVAD,
2119 MDIO_PMA_REG_CTRL,
2120 1<<15);
2121 break;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002122
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002123 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002124 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002125
2126 /* Restore normal power mode*/
2127 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002128 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2129 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002130
2131 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002132 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2133 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002134 break;
2135
2136 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
2137 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
2138
2139 /* Restore normal power mode*/
2140 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002141 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2142 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002143
2144 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002145 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002146 break;
2147
Eilon Greenstein28577182009-02-12 08:37:00 +00002148 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Eilon Greenstein28577182009-02-12 08:37:00 +00002149 /* Restore normal power mode*/
2150 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2151 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2152 params->port);
2153
2154 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002155 bnx2x_ext_phy_hw_reset(bp, params->port);
Eilon Greenstein28577182009-02-12 08:37:00 +00002156
2157 bnx2x_cl45_write(bp, params->port,
2158 ext_phy_type,
2159 ext_phy_addr,
2160 MDIO_PMA_DEVAD,
2161 MDIO_PMA_REG_CTRL,
2162 1<<15);
2163 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002164 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
2165 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
2166 break;
2167
2168 default:
2169 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
2170 params->ext_phy_config);
2171 break;
2172 }
2173
2174 } else { /* SerDes */
2175 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
2176 switch (ext_phy_type) {
2177 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
2178 DP(NETIF_MSG_LINK, "SerDes Direct\n");
2179 break;
2180
2181 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
2182 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002183 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002184 break;
2185
2186 default:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002187 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002188 params->ext_phy_config);
2189 break;
2190 }
2191 }
2192}
2193
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002194static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
2195 u32 shmem_base, u32 spirom_ver)
2196{
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002197 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
2198 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002199 REG_WR(bp, shmem_base +
2200 offsetof(struct shmem_region,
2201 port_mb[port].ext_phy_fw_version),
2202 spirom_ver);
2203}
2204
2205static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
2206 u32 ext_phy_type, u8 ext_phy_addr,
2207 u32 shmem_base)
2208{
2209 u16 fw_ver1, fw_ver2;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002210
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002211 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2212 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2213 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2214 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2215 bnx2x_save_spirom_version(bp, port, shmem_base,
2216 (u32)(fw_ver1<<16 | fw_ver2));
2217}
2218
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002219
2220static void bnx2x_save_8481_spirom_version(struct bnx2x *bp, u8 port,
2221 u8 ext_phy_addr, u32 shmem_base)
2222{
2223 u16 val, fw_ver1, fw_ver2, cnt;
2224 /* For the 32 bits registers in 8481, access via MDIO2ARM interface.*/
2225 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
2226 bnx2x_cl45_write(bp, port,
2227 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2228 ext_phy_addr, MDIO_PMA_DEVAD,
2229 0xA819, 0x0014);
2230 bnx2x_cl45_write(bp, port,
2231 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2232 ext_phy_addr,
2233 MDIO_PMA_DEVAD,
2234 0xA81A,
2235 0xc200);
2236 bnx2x_cl45_write(bp, port,
2237 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2238 ext_phy_addr,
2239 MDIO_PMA_DEVAD,
2240 0xA81B,
2241 0x0000);
2242 bnx2x_cl45_write(bp, port,
2243 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2244 ext_phy_addr,
2245 MDIO_PMA_DEVAD,
2246 0xA81C,
2247 0x0300);
2248 bnx2x_cl45_write(bp, port,
2249 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2250 ext_phy_addr,
2251 MDIO_PMA_DEVAD,
2252 0xA817,
2253 0x0009);
2254
2255 for (cnt = 0; cnt < 100; cnt++) {
2256 bnx2x_cl45_read(bp, port,
2257 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2258 ext_phy_addr,
2259 MDIO_PMA_DEVAD,
2260 0xA818,
2261 &val);
2262 if (val & 1)
2263 break;
2264 udelay(5);
2265 }
2266 if (cnt == 100) {
2267 DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n");
2268 bnx2x_save_spirom_version(bp, port,
2269 shmem_base, 0);
2270 return;
2271 }
2272
2273
2274 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
2275 bnx2x_cl45_write(bp, port,
2276 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2277 ext_phy_addr, MDIO_PMA_DEVAD,
2278 0xA819, 0x0000);
2279 bnx2x_cl45_write(bp, port,
2280 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2281 ext_phy_addr, MDIO_PMA_DEVAD,
2282 0xA81A, 0xc200);
2283 bnx2x_cl45_write(bp, port,
2284 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2285 ext_phy_addr, MDIO_PMA_DEVAD,
2286 0xA817, 0x000A);
2287 for (cnt = 0; cnt < 100; cnt++) {
2288 bnx2x_cl45_read(bp, port,
2289 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2290 ext_phy_addr,
2291 MDIO_PMA_DEVAD,
2292 0xA818,
2293 &val);
2294 if (val & 1)
2295 break;
2296 udelay(5);
2297 }
2298 if (cnt == 100) {
2299 DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(2)\n");
2300 bnx2x_save_spirom_version(bp, port,
2301 shmem_base, 0);
2302 return;
2303 }
2304
2305 /* lower 16 bits of the register SPI_FW_STATUS */
2306 bnx2x_cl45_read(bp, port,
2307 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2308 ext_phy_addr,
2309 MDIO_PMA_DEVAD,
2310 0xA81B,
2311 &fw_ver1);
2312 /* upper 16 bits of register SPI_FW_STATUS */
2313 bnx2x_cl45_read(bp, port,
2314 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2315 ext_phy_addr,
2316 MDIO_PMA_DEVAD,
2317 0xA81C,
2318 &fw_ver2);
2319
2320 bnx2x_save_spirom_version(bp, port,
2321 shmem_base, (fw_ver2<<16) | fw_ver1);
2322}
2323
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002324static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
2325{
2326 struct bnx2x *bp = params->bp;
2327 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002328 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002329 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002330
2331 /* Need to wait 200ms after reset */
2332 msleep(200);
2333 /* Boot port from external ROM
2334 * Set ser_boot_ctl bit in the MISC_CTRL1 register
2335 */
2336 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2337 MDIO_PMA_DEVAD,
2338 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2339
2340 /* Reset internal microprocessor */
2341 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2342 MDIO_PMA_DEVAD,
2343 MDIO_PMA_REG_GEN_CTRL,
2344 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2345 /* set micro reset = 0 */
2346 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2347 MDIO_PMA_DEVAD,
2348 MDIO_PMA_REG_GEN_CTRL,
2349 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2350 /* Reset internal microprocessor */
2351 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2352 MDIO_PMA_DEVAD,
2353 MDIO_PMA_REG_GEN_CTRL,
2354 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2355 /* wait for 100ms for code download via SPI port */
2356 msleep(100);
2357
2358 /* Clear ser_boot_ctl bit */
2359 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2360 MDIO_PMA_DEVAD,
2361 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2362 /* Wait 100ms */
2363 msleep(100);
2364
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002365 bnx2x_save_bcm_spirom_ver(bp, port,
2366 ext_phy_type,
2367 ext_phy_addr,
2368 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002369}
2370
2371static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2372{
2373 /* This is only required for 8073A1, version 102 only */
2374
2375 struct bnx2x *bp = params->bp;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002376 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002377 u16 val;
2378
2379 /* Read 8073 HW revision*/
2380 bnx2x_cl45_read(bp, params->port,
2381 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2382 ext_phy_addr,
2383 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002384 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002385
2386 if (val != 1) {
2387 /* No need to workaround in 8073 A1 */
2388 return 0;
2389 }
2390
2391 bnx2x_cl45_read(bp, params->port,
2392 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2393 ext_phy_addr,
2394 MDIO_PMA_DEVAD,
2395 MDIO_PMA_REG_ROM_VER2, &val);
2396
2397 /* SNR should be applied only for version 0x102 */
2398 if (val != 0x102)
2399 return 0;
2400
2401 return 1;
2402}
2403
2404static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2405{
2406 struct bnx2x *bp = params->bp;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002407 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002408 u16 val, cnt, cnt1 ;
2409
2410 bnx2x_cl45_read(bp, params->port,
2411 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2412 ext_phy_addr,
2413 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002414 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002415
2416 if (val > 0) {
2417 /* No need to workaround in 8073 A1 */
2418 return 0;
2419 }
2420 /* XAUI workaround in 8073 A0: */
2421
2422 /* After loading the boot ROM and restarting Autoneg,
2423 poll Dev1, Reg $C820: */
2424
2425 for (cnt = 0; cnt < 1000; cnt++) {
2426 bnx2x_cl45_read(bp, params->port,
2427 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2428 ext_phy_addr,
2429 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002430 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
2431 &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002432 /* If bit [14] = 0 or bit [13] = 0, continue on with
2433 system initialization (XAUI work-around not required,
2434 as these bits indicate 2.5G or 1G link up). */
2435 if (!(val & (1<<14)) || !(val & (1<<13))) {
2436 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2437 return 0;
2438 } else if (!(val & (1<<15))) {
2439 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2440 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2441 it's MSB (bit 15) goes to 1 (indicating that the
2442 XAUI workaround has completed),
2443 then continue on with system initialization.*/
2444 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2445 bnx2x_cl45_read(bp, params->port,
2446 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2447 ext_phy_addr,
2448 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002449 MDIO_PMA_REG_8073_XAUI_WA, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002450 if (val & (1<<15)) {
2451 DP(NETIF_MSG_LINK,
2452 "XAUI workaround has completed\n");
2453 return 0;
2454 }
2455 msleep(3);
2456 }
2457 break;
2458 }
2459 msleep(3);
2460 }
2461 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2462 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002463}
2464
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002465static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
2466 u8 ext_phy_addr,
2467 u32 ext_phy_type,
2468 u32 shmem_base)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002469{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002470 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002471 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002472 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002473 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002474 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002475 MDIO_PMA_DEVAD,
2476 MDIO_PMA_REG_GEN_CTRL,
2477 0x0001);
2478
2479 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002480 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002481 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002482 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002483 MDIO_PMA_DEVAD,
2484 MDIO_PMA_REG_GEN_CTRL,
2485 0x008c);
2486
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002487 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002488 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002489 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002490 MDIO_PMA_DEVAD,
2491 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2492
2493 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002494 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002495 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002496 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002497 MDIO_PMA_DEVAD,
2498 MDIO_PMA_REG_GEN_CTRL,
2499 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2500
2501 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002502 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002503 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002504 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002505 MDIO_PMA_DEVAD,
2506 MDIO_PMA_REG_GEN_CTRL,
2507 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2508
2509 /* wait for 100ms for code download via SPI port */
2510 msleep(100);
2511
2512 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002513 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002514 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002515 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002516 MDIO_PMA_DEVAD,
2517 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2518
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002519 bnx2x_save_bcm_spirom_ver(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002520 ext_phy_type,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002521 ext_phy_addr,
2522 shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002523}
2524
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002525static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
2526 u8 ext_phy_addr,
2527 u32 shmem_base)
2528{
2529 bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
2530 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2531 shmem_base);
2532}
2533
2534static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
2535 u8 ext_phy_addr,
2536 u32 shmem_base)
2537{
2538 bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
2539 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
2540 shmem_base);
2541
2542}
2543
Eilon Greenstein589abe32009-02-12 08:36:55 +00002544static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
2545{
2546 struct bnx2x *bp = params->bp;
2547 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002548 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002549 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2550
2551 /* Need to wait 100ms after reset */
2552 msleep(100);
2553
2554 /* Set serial boot control for external load */
2555 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2556 MDIO_PMA_DEVAD,
2557 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2558
2559 /* Micro controller re-boot */
2560 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2561 MDIO_PMA_DEVAD,
2562 MDIO_PMA_REG_GEN_CTRL,
2563 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2564
2565 /* Set soft reset */
2566 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2567 MDIO_PMA_DEVAD,
2568 MDIO_PMA_REG_GEN_CTRL,
2569 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2570
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002571 /* Set PLL register value to be same like in P13 ver */
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002572 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2573 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002574 MDIO_PMA_REG_PLL_CTRL,
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002575 0x73A0);
2576
Eilon Greenstein589abe32009-02-12 08:36:55 +00002577 /* Clear soft reset.
2578 Will automatically reset micro-controller re-boot */
2579 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2580 MDIO_PMA_DEVAD,
2581 MDIO_PMA_REG_GEN_CTRL,
2582 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2583
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002584 /* wait for 150ms for microcode load */
2585 msleep(150);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002586
2587 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
2588 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2589 MDIO_PMA_DEVAD,
2590 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2591
2592 msleep(200);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002593 bnx2x_save_bcm_spirom_ver(bp, port,
2594 ext_phy_type,
2595 ext_phy_addr,
2596 params->shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002597}
2598
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002599static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
2600 u32 ext_phy_type, u8 ext_phy_addr,
2601 u8 tx_en)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002602{
2603 u16 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002604
Eilon Greenstein589abe32009-02-12 08:36:55 +00002605 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2606 tx_en, port);
2607 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
2608 bnx2x_cl45_read(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002609 ext_phy_type,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002610 ext_phy_addr,
2611 MDIO_PMA_DEVAD,
2612 MDIO_PMA_REG_PHY_IDENTIFIER,
2613 &val);
2614
2615 if (tx_en)
2616 val &= ~(1<<15);
2617 else
2618 val |= (1<<15);
2619
2620 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002621 ext_phy_type,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002622 ext_phy_addr,
2623 MDIO_PMA_DEVAD,
2624 MDIO_PMA_REG_PHY_IDENTIFIER,
2625 val);
2626}
2627
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002628static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
2629 u16 addr, u8 byte_cnt, u8 *o_buf)
2630{
Eilon Greenstein589abe32009-02-12 08:36:55 +00002631 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002632 u16 val = 0;
2633 u16 i;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002634 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002635 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002636 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002637
Eilon Greenstein589abe32009-02-12 08:36:55 +00002638 if (byte_cnt > 16) {
2639 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2640 " is limited to 0xf\n");
2641 return -EINVAL;
2642 }
2643 /* Set the read command byte count */
2644 bnx2x_cl45_write(bp, port,
2645 ext_phy_type,
2646 ext_phy_addr,
2647 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002648 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002649 (byte_cnt | 0xa000));
2650
2651 /* Set the read command address */
2652 bnx2x_cl45_write(bp, port,
2653 ext_phy_type,
2654 ext_phy_addr,
2655 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002656 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002657 addr);
2658
2659 /* Activate read command */
2660 bnx2x_cl45_write(bp, port,
2661 ext_phy_type,
2662 ext_phy_addr,
2663 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002664 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002665 0x2c0f);
2666
2667 /* Wait up to 500us for command complete status */
2668 for (i = 0; i < 100; i++) {
2669 bnx2x_cl45_read(bp, port,
2670 ext_phy_type,
2671 ext_phy_addr,
2672 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002673 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2674 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2675 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002676 break;
2677 udelay(5);
2678 }
2679
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002680 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2681 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002682 DP(NETIF_MSG_LINK,
2683 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002684 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Eilon Greenstein589abe32009-02-12 08:36:55 +00002685 return -EINVAL;
2686 }
2687
2688 /* Read the buffer */
2689 for (i = 0; i < byte_cnt; i++) {
2690 bnx2x_cl45_read(bp, port,
2691 ext_phy_type,
2692 ext_phy_addr,
2693 MDIO_PMA_DEVAD,
2694 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2695 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2696 }
2697
2698 for (i = 0; i < 100; i++) {
2699 bnx2x_cl45_read(bp, port,
2700 ext_phy_type,
2701 ext_phy_addr,
2702 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002703 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2704 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2705 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002706 return 0;;
2707 msleep(1);
2708 }
2709 return -EINVAL;
2710}
2711
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002712static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
2713 u16 addr, u8 byte_cnt, u8 *o_buf)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002714{
2715 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002716 u16 val, i;
2717 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002718 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002719 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2720
2721 if (byte_cnt > 16) {
2722 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2723 " is limited to 0xf\n");
2724 return -EINVAL;
2725 }
2726
2727 /* Need to read from 1.8000 to clear it */
2728 bnx2x_cl45_read(bp, port,
2729 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
2730 ext_phy_addr,
2731 MDIO_PMA_DEVAD,
2732 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2733 &val);
2734
2735 /* Set the read command byte count */
2736 bnx2x_cl45_write(bp, port,
2737 ext_phy_type,
2738 ext_phy_addr,
2739 MDIO_PMA_DEVAD,
2740 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
2741 ((byte_cnt < 2) ? 2 : byte_cnt));
2742
2743 /* Set the read command address */
2744 bnx2x_cl45_write(bp, port,
2745 ext_phy_type,
2746 ext_phy_addr,
2747 MDIO_PMA_DEVAD,
2748 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
2749 addr);
2750 /* Set the destination address */
2751 bnx2x_cl45_write(bp, port,
2752 ext_phy_type,
2753 ext_phy_addr,
2754 MDIO_PMA_DEVAD,
2755 0x8004,
2756 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
2757
2758 /* Activate read command */
2759 bnx2x_cl45_write(bp, port,
2760 ext_phy_type,
2761 ext_phy_addr,
2762 MDIO_PMA_DEVAD,
2763 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2764 0x8002);
2765 /* Wait appropriate time for two-wire command to finish before
2766 polling the status register */
2767 msleep(1);
2768
2769 /* Wait up to 500us for command complete status */
2770 for (i = 0; i < 100; i++) {
2771 bnx2x_cl45_read(bp, port,
2772 ext_phy_type,
2773 ext_phy_addr,
2774 MDIO_PMA_DEVAD,
2775 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2776 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2777 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
2778 break;
2779 udelay(5);
2780 }
2781
2782 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2783 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
2784 DP(NETIF_MSG_LINK,
2785 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2786 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
2787 return -EINVAL;
2788 }
2789
2790 /* Read the buffer */
2791 for (i = 0; i < byte_cnt; i++) {
2792 bnx2x_cl45_read(bp, port,
2793 ext_phy_type,
2794 ext_phy_addr,
2795 MDIO_PMA_DEVAD,
2796 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
2797 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
2798 }
2799
2800 for (i = 0; i < 100; i++) {
2801 bnx2x_cl45_read(bp, port,
2802 ext_phy_type,
2803 ext_phy_addr,
2804 MDIO_PMA_DEVAD,
2805 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2806 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2807 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
2808 return 0;;
2809 msleep(1);
2810 }
2811
2812 return -EINVAL;
2813}
2814
2815u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
2816 u8 byte_cnt, u8 *o_buf)
2817{
2818 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2819
2820 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
2821 return bnx2x_8726_read_sfp_module_eeprom(params, addr,
2822 byte_cnt, o_buf);
2823 else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
2824 return bnx2x_8727_read_sfp_module_eeprom(params, addr,
2825 byte_cnt, o_buf);
2826 return -EINVAL;
2827}
2828
2829static u8 bnx2x_get_edc_mode(struct link_params *params,
2830 u16 *edc_mode)
2831{
2832 struct bnx2x *bp = params->bp;
2833 u8 val, check_limiting_mode = 0;
2834 *edc_mode = EDC_MODE_LIMITING;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002835
2836 /* First check for copper cable */
2837 if (bnx2x_read_sfp_module_eeprom(params,
2838 SFP_EEPROM_CON_TYPE_ADDR,
2839 1,
2840 &val) != 0) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002841 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002842 return -EINVAL;
2843 }
2844
2845 switch (val) {
2846 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2847 {
2848 u8 copper_module_type;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002849
Eilon Greenstein589abe32009-02-12 08:36:55 +00002850 /* Check if its active cable( includes SFP+ module)
2851 of passive cable*/
2852 if (bnx2x_read_sfp_module_eeprom(params,
2853 SFP_EEPROM_FC_TX_TECH_ADDR,
2854 1,
2855 &copper_module_type) !=
2856 0) {
2857 DP(NETIF_MSG_LINK,
2858 "Failed to read copper-cable-type"
2859 " from SFP+ EEPROM\n");
2860 return -EINVAL;
2861 }
2862
2863 if (copper_module_type &
2864 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2865 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002866 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002867 } else if (copper_module_type &
2868 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2869 DP(NETIF_MSG_LINK, "Passive Copper"
2870 " cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002871 *edc_mode =
2872 EDC_MODE_PASSIVE_DAC;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002873 } else {
2874 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2875 "type 0x%x !!!\n", copper_module_type);
2876 return -EINVAL;
2877 }
2878 break;
2879 }
2880 case SFP_EEPROM_CON_TYPE_VAL_LC:
2881 DP(NETIF_MSG_LINK, "Optic module detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002882 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002883 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002884 default:
2885 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2886 val);
2887 return -EINVAL;
2888 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002889
2890 if (check_limiting_mode) {
2891 u8 options[SFP_EEPROM_OPTIONS_SIZE];
2892 if (bnx2x_read_sfp_module_eeprom(params,
2893 SFP_EEPROM_OPTIONS_ADDR,
2894 SFP_EEPROM_OPTIONS_SIZE,
2895 options) != 0) {
2896 DP(NETIF_MSG_LINK, "Failed to read Option"
2897 " field from module EEPROM\n");
2898 return -EINVAL;
2899 }
2900 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
2901 *edc_mode = EDC_MODE_LINEAR;
2902 else
2903 *edc_mode = EDC_MODE_LIMITING;
2904 }
2905 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002906 return 0;
2907}
2908
Eilon Greenstein589abe32009-02-12 08:36:55 +00002909/* This function read the relevant field from the module ( SFP+ ),
2910 and verify it is compliant with this board */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002911static u8 bnx2x_verify_sfp_module(struct link_params *params)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002912{
2913 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002914 u32 val;
2915 u32 fw_resp;
2916 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
2917 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Eilon Greenstein589abe32009-02-12 08:36:55 +00002918
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002919 val = REG_RD(bp, params->shmem_base +
2920 offsetof(struct shmem_region, dev_info.
2921 port_feature_config[params->port].config));
2922 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
2923 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002924 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2925 return 0;
2926 }
2927
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002928 /* Ask the FW to validate the module */
2929 if (!(params->feature_config_flags &
2930 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
2931 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
2932 "verification\n");
2933 return -EINVAL;
2934 }
2935
2936 fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
2937 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
2938 DP(NETIF_MSG_LINK, "Approved module\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002939 return 0;
2940 }
2941
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002942 /* format the warning message */
Eilon Greenstein589abe32009-02-12 08:36:55 +00002943 if (bnx2x_read_sfp_module_eeprom(params,
2944 SFP_EEPROM_VENDOR_NAME_ADDR,
2945 SFP_EEPROM_VENDOR_NAME_SIZE,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002946 (u8 *)vendor_name))
2947 vendor_name[0] = '\0';
2948 else
2949 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
2950 if (bnx2x_read_sfp_module_eeprom(params,
2951 SFP_EEPROM_PART_NO_ADDR,
2952 SFP_EEPROM_PART_NO_SIZE,
2953 (u8 *)vendor_pn))
2954 vendor_pn[0] = '\0';
2955 else
2956 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
Eilon Greenstein589abe32009-02-12 08:36:55 +00002957
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002958 printk(KERN_INFO PFX "Warning: "
2959 "Unqualified SFP+ module "
2960 "detected on %s, Port %d from %s part number %s\n"
2961 , bp->dev->name, params->port,
2962 vendor_name, vendor_pn);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002963 return -EINVAL;
2964}
2965
Eilon Greenstein589abe32009-02-12 08:36:55 +00002966static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002967 u16 edc_mode)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002968{
2969 struct bnx2x *bp = params->bp;
2970 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002971 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002972 u16 cur_limiting_mode;
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002973
2974 bnx2x_cl45_read(bp, port,
2975 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2976 ext_phy_addr,
2977 MDIO_PMA_DEVAD,
2978 MDIO_PMA_REG_ROM_VER2,
2979 &cur_limiting_mode);
2980 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
2981 cur_limiting_mode);
2982
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002983 if (edc_mode == EDC_MODE_LIMITING) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002984 DP(NETIF_MSG_LINK,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002985 "Setting LIMITING MODE\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002986 bnx2x_cl45_write(bp, port,
2987 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2988 ext_phy_addr,
2989 MDIO_PMA_DEVAD,
2990 MDIO_PMA_REG_ROM_VER2,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002991 EDC_MODE_LIMITING);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002992 } else { /* LRM mode ( default )*/
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002993
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002994 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002995
Eilon Greenstein589abe32009-02-12 08:36:55 +00002996 /* Changing to LRM mode takes quite few seconds.
2997 So do it only if current mode is limiting
2998 ( default is LRM )*/
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002999 if (cur_limiting_mode != EDC_MODE_LIMITING)
Eilon Greenstein589abe32009-02-12 08:36:55 +00003000 return 0;
3001
3002 bnx2x_cl45_write(bp, port,
3003 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3004 ext_phy_addr,
3005 MDIO_PMA_DEVAD,
3006 MDIO_PMA_REG_LRM_MODE,
3007 0);
3008 bnx2x_cl45_write(bp, port,
3009 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3010 ext_phy_addr,
3011 MDIO_PMA_DEVAD,
3012 MDIO_PMA_REG_ROM_VER2,
3013 0x128);
3014 bnx2x_cl45_write(bp, port,
3015 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3016 ext_phy_addr,
3017 MDIO_PMA_DEVAD,
3018 MDIO_PMA_REG_MISC_CTRL0,
3019 0x4008);
3020 bnx2x_cl45_write(bp, port,
3021 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3022 ext_phy_addr,
3023 MDIO_PMA_DEVAD,
3024 MDIO_PMA_REG_LRM_MODE,
3025 0xaaaa);
3026 }
3027 return 0;
3028}
3029
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003030static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
3031 u16 edc_mode)
3032{
3033 struct bnx2x *bp = params->bp;
3034 u8 port = params->port;
3035 u16 phy_identifier;
3036 u16 rom_ver2_val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003037 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003038
3039 bnx2x_cl45_read(bp, port,
3040 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3041 ext_phy_addr,
3042 MDIO_PMA_DEVAD,
3043 MDIO_PMA_REG_PHY_IDENTIFIER,
3044 &phy_identifier);
3045
3046 bnx2x_cl45_write(bp, port,
3047 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3048 ext_phy_addr,
3049 MDIO_PMA_DEVAD,
3050 MDIO_PMA_REG_PHY_IDENTIFIER,
3051 (phy_identifier & ~(1<<9)));
3052
3053 bnx2x_cl45_read(bp, port,
3054 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3055 ext_phy_addr,
3056 MDIO_PMA_DEVAD,
3057 MDIO_PMA_REG_ROM_VER2,
3058 &rom_ver2_val);
3059 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
3060 bnx2x_cl45_write(bp, port,
3061 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3062 ext_phy_addr,
3063 MDIO_PMA_DEVAD,
3064 MDIO_PMA_REG_ROM_VER2,
3065 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
3066
3067 bnx2x_cl45_write(bp, port,
3068 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3069 ext_phy_addr,
3070 MDIO_PMA_DEVAD,
3071 MDIO_PMA_REG_PHY_IDENTIFIER,
3072 (phy_identifier | (1<<9)));
3073
3074 return 0;
3075}
3076
3077
Eilon Greenstein589abe32009-02-12 08:36:55 +00003078static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
3079{
3080 u8 val;
3081 struct bnx2x *bp = params->bp;
3082 u16 timeout;
3083 /* Initialization time after hot-plug may take up to 300ms for some
3084 phys type ( e.g. JDSU ) */
3085 for (timeout = 0; timeout < 60; timeout++) {
3086 if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
3087 == 0) {
3088 DP(NETIF_MSG_LINK, "SFP+ module initialization "
3089 "took %d ms\n", timeout * 5);
3090 return 0;
3091 }
3092 msleep(5);
3093 }
3094 return -EINVAL;
3095}
3096
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003097static void bnx2x_8727_power_module(struct bnx2x *bp,
3098 struct link_params *params,
3099 u8 ext_phy_addr, u8 is_power_up) {
3100 /* Make sure GPIOs are not using for LED mode */
3101 u16 val;
3102 u8 port = params->port;
3103 /*
3104 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
3105 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
3106 * output
3107 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
3108 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
3109 * where the 1st bit is the over-current(only input), and 2nd bit is
3110 * for power( only output )
3111 */
3112
3113 /*
3114 * In case of NOC feature is disabled and power is up, set GPIO control
3115 * as input to enable listening of over-current indication
3116 */
3117
3118 if (!(params->feature_config_flags &
3119 FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
3120 val = (1<<4);
3121 else
3122 /*
3123 * Set GPIO control to OUTPUT, and set the power bit
3124 * to according to the is_power_up
3125 */
3126 val = ((!(is_power_up)) << 1);
3127
3128 bnx2x_cl45_write(bp, port,
3129 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3130 ext_phy_addr,
3131 MDIO_PMA_DEVAD,
3132 MDIO_PMA_REG_8727_GPIO_CTRL,
3133 val);
3134}
3135
Eilon Greenstein589abe32009-02-12 08:36:55 +00003136static u8 bnx2x_sfp_module_detection(struct link_params *params)
3137{
3138 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003139 u16 edc_mode;
3140 u8 rc = 0;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003141 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003142 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003143 u32 val = REG_RD(bp, params->shmem_base +
3144 offsetof(struct shmem_region, dev_info.
3145 port_feature_config[params->port].config));
Eilon Greenstein589abe32009-02-12 08:36:55 +00003146
3147 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
3148 params->port);
3149
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003150 if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003151 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003152 return -EINVAL;
3153 } else if (bnx2x_verify_sfp_module(params) !=
Eilon Greenstein589abe32009-02-12 08:36:55 +00003154 0) {
3155 /* check SFP+ module compatibility */
3156 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003157 rc = -EINVAL;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003158 /* Turn on fault module-detected led */
3159 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3160 MISC_REGISTERS_GPIO_HIGH,
3161 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003162 if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
3163 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3164 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
3165 /* Shutdown SFP+ module */
3166 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
3167 bnx2x_8727_power_module(bp, params,
3168 ext_phy_addr, 0);
3169 return rc;
3170 }
3171 } else {
3172 /* Turn off fault module-detected led */
3173 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
3174 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3175 MISC_REGISTERS_GPIO_LOW,
3176 params->port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003177 }
3178
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003179 /* power up the SFP module */
3180 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
3181 bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003182
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003183 /* Check and set limiting mode / LRM mode on 8726.
3184 On 8727 it is done automatically */
3185 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
3186 bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
3187 else
3188 bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
3189 /*
3190 * Enable transmit for this module if the module is approved, or
3191 * if unapproved modules should also enable the Tx laser
3192 */
3193 if (rc == 0 ||
3194 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
3195 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
3196 bnx2x_sfp_set_transmitter(bp, params->port,
3197 ext_phy_type, ext_phy_addr, 1);
3198 else
3199 bnx2x_sfp_set_transmitter(bp, params->port,
3200 ext_phy_type, ext_phy_addr, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003201
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003202 return rc;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003203}
3204
3205void bnx2x_handle_module_detect_int(struct link_params *params)
3206{
3207 struct bnx2x *bp = params->bp;
3208 u32 gpio_val;
3209 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003210
Eilon Greenstein589abe32009-02-12 08:36:55 +00003211 /* Set valid module led off */
3212 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3213 MISC_REGISTERS_GPIO_HIGH,
3214 params->port);
3215
3216 /* Get current gpio val refelecting module plugged in / out*/
3217 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
3218
3219 /* Call the handling function in case module is detected */
3220 if (gpio_val == 0) {
3221
3222 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
3223 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
3224 port);
3225
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003226 if (bnx2x_wait_for_sfp_module_initialized(params) ==
3227 0)
Eilon Greenstein589abe32009-02-12 08:36:55 +00003228 bnx2x_sfp_module_detection(params);
3229 else
3230 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
3231 } else {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003232 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
3233
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003234 u32 ext_phy_type =
3235 XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3236 u32 val = REG_RD(bp, params->shmem_base +
3237 offsetof(struct shmem_region, dev_info.
3238 port_feature_config[params->port].
3239 config));
3240
Eilon Greenstein589abe32009-02-12 08:36:55 +00003241 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
3242 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
3243 port);
3244 /* Module was plugged out. */
3245 /* Disable transmit for this module */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003246 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3247 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
3248 bnx2x_sfp_set_transmitter(bp, params->port,
3249 ext_phy_type, ext_phy_addr, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003250 }
3251}
3252
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003253static void bnx2x_bcm807x_force_10G(struct link_params *params)
3254{
3255 struct bnx2x *bp = params->bp;
3256 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003257 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003258 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3259
3260 /* Force KR or KX */
3261 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3262 MDIO_PMA_DEVAD,
3263 MDIO_PMA_REG_CTRL,
3264 0x2040);
3265 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3266 MDIO_PMA_DEVAD,
3267 MDIO_PMA_REG_10G_CTRL2,
3268 0x000b);
3269 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3270 MDIO_PMA_DEVAD,
3271 MDIO_PMA_REG_BCM_CTRL,
3272 0x0000);
3273 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3274 MDIO_AN_DEVAD,
3275 MDIO_AN_REG_CTRL,
3276 0x0000);
3277}
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003278
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003279static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
3280{
3281 struct bnx2x *bp = params->bp;
3282 u8 port = params->port;
3283 u16 val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003284 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003285 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3286
3287 bnx2x_cl45_read(bp, params->port,
3288 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
3289 ext_phy_addr,
3290 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003291 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003292
3293 if (val == 0) {
3294 /* Mustn't set low power mode in 8073 A0 */
3295 return;
3296 }
3297
3298 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
3299 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
3300 MDIO_XS_DEVAD,
3301 MDIO_XS_PLL_SEQUENCER, &val);
3302 val &= ~(1<<13);
3303 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3304 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3305
3306 /* PLL controls */
3307 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3308 MDIO_XS_DEVAD, 0x805E, 0x1077);
3309 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3310 MDIO_XS_DEVAD, 0x805D, 0x0000);
3311 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3312 MDIO_XS_DEVAD, 0x805C, 0x030B);
3313 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3314 MDIO_XS_DEVAD, 0x805B, 0x1240);
3315 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3316 MDIO_XS_DEVAD, 0x805A, 0x2490);
3317
3318 /* Tx Controls */
3319 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3320 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
3321 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3322 MDIO_XS_DEVAD, 0x80A6, 0x9041);
3323 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3324 MDIO_XS_DEVAD, 0x80A5, 0x4640);
3325
3326 /* Rx Controls */
3327 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3328 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
3329 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3330 MDIO_XS_DEVAD, 0x80FD, 0x9249);
3331 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3332 MDIO_XS_DEVAD, 0x80FC, 0x2015);
3333
3334 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
3335 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
3336 MDIO_XS_DEVAD,
3337 MDIO_XS_PLL_SEQUENCER, &val);
3338 val |= (1<<13);
3339 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3340 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3341}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003342
3343static void bnx2x_8073_set_pause_cl37(struct link_params *params,
3344 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003345{
3346 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003347 u16 cl37_val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003348 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003349 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3350
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003351 bnx2x_cl45_read(bp, params->port,
3352 ext_phy_type,
3353 ext_phy_addr,
3354 MDIO_AN_DEVAD,
3355 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
3356
3357 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3358 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3359
3360 if ((vars->ieee_fc &
3361 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
3362 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
3363 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
3364 }
3365 if ((vars->ieee_fc &
3366 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3367 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3368 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3369 }
3370 if ((vars->ieee_fc &
3371 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3372 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3373 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3374 }
3375 DP(NETIF_MSG_LINK,
3376 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
3377
3378 bnx2x_cl45_write(bp, params->port,
3379 ext_phy_type,
3380 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003381 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003382 MDIO_AN_REG_CL37_FC_LD, cl37_val);
3383 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003384}
3385
3386static void bnx2x_ext_phy_set_pause(struct link_params *params,
3387 struct link_vars *vars)
3388{
3389 struct bnx2x *bp = params->bp;
3390 u16 val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003391 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003392 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3393
3394 /* read modify write pause advertizing */
3395 bnx2x_cl45_read(bp, params->port,
3396 ext_phy_type,
3397 ext_phy_addr,
3398 MDIO_AN_DEVAD,
3399 MDIO_AN_REG_ADV_PAUSE, &val);
3400
3401 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003402
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003403 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3404
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003405 if ((vars->ieee_fc &
3406 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003407 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3408 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3409 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003410 if ((vars->ieee_fc &
3411 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003412 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3413 val |=
3414 MDIO_AN_REG_ADV_PAUSE_PAUSE;
3415 }
3416 DP(NETIF_MSG_LINK,
3417 "Ext phy AN advertize 0x%x\n", val);
3418 bnx2x_cl45_write(bp, params->port,
3419 ext_phy_type,
3420 ext_phy_addr,
3421 MDIO_AN_DEVAD,
3422 MDIO_AN_REG_ADV_PAUSE, val);
3423}
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003424static void bnx2x_set_preemphasis(struct link_params *params)
3425{
3426 u16 bank, i = 0;
3427 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003428
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003429 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
3430 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
3431 CL45_WR_OVER_CL22(bp, params->port,
3432 params->phy_addr,
3433 bank,
3434 MDIO_RX0_RX_EQ_BOOST,
3435 params->xgxs_config_rx[i]);
3436 }
3437
3438 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
3439 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
3440 CL45_WR_OVER_CL22(bp, params->port,
3441 params->phy_addr,
3442 bank,
3443 MDIO_TX0_TX_DRIVER,
3444 params->xgxs_config_tx[i]);
3445 }
3446}
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003447
Eilon Greenstein2f904462009-08-12 08:22:16 +00003448
3449static void bnx2x_8481_set_led4(struct link_params *params,
3450 u32 ext_phy_type, u8 ext_phy_addr)
3451{
3452 struct bnx2x *bp = params->bp;
3453
3454 /* PHYC_CTL_LED_CTL */
3455 bnx2x_cl45_write(bp, params->port,
3456 ext_phy_type,
3457 ext_phy_addr,
3458 MDIO_PMA_DEVAD,
3459 MDIO_PMA_REG_8481_LINK_SIGNAL, 0xa482);
3460
3461 /* Unmask LED4 for 10G link */
3462 bnx2x_cl45_write(bp, params->port,
3463 ext_phy_type,
3464 ext_phy_addr,
3465 MDIO_PMA_DEVAD,
3466 MDIO_PMA_REG_8481_SIGNAL_MASK, (1<<6));
3467 /* 'Interrupt Mask' */
3468 bnx2x_cl45_write(bp, params->port,
3469 ext_phy_type,
3470 ext_phy_addr,
3471 MDIO_AN_DEVAD,
3472 0xFFFB, 0xFFFD);
3473}
3474static void bnx2x_8481_set_legacy_led_mode(struct link_params *params,
3475 u32 ext_phy_type, u8 ext_phy_addr)
3476{
3477 struct bnx2x *bp = params->bp;
3478
3479 /* LED1 (10G Link): Disable LED1 when 10/100/1000 link */
3480 /* LED2 (1G/100/10 Link): Enable LED2 when 10/100/1000 link) */
3481 bnx2x_cl45_write(bp, params->port,
3482 ext_phy_type,
3483 ext_phy_addr,
3484 MDIO_AN_DEVAD,
3485 MDIO_AN_REG_8481_LEGACY_SHADOW,
3486 (1<<15) | (0xd << 10) | (0xc<<4) | 0xe);
3487}
3488
3489static void bnx2x_8481_set_10G_led_mode(struct link_params *params,
3490 u32 ext_phy_type, u8 ext_phy_addr)
3491{
3492 struct bnx2x *bp = params->bp;
3493 u16 val1;
3494
3495 /* LED1 (10G Link) */
3496 /* Enable continuse based on source 7(10G-link) */
3497 bnx2x_cl45_read(bp, params->port,
3498 ext_phy_type,
3499 ext_phy_addr,
3500 MDIO_PMA_DEVAD,
3501 MDIO_PMA_REG_8481_LINK_SIGNAL,
3502 &val1);
3503 /* Set bit 2 to 0, and bits [1:0] to 10 */
3504 val1 &= ~((1<<0) | (1<<2)); /* Clear bits 0,2*/
3505 val1 |= (1<<1); /* Set bit 1 */
3506
3507 bnx2x_cl45_write(bp, params->port,
3508 ext_phy_type,
3509 ext_phy_addr,
3510 MDIO_PMA_DEVAD,
3511 MDIO_PMA_REG_8481_LINK_SIGNAL,
3512 val1);
3513
3514 /* Unmask LED1 for 10G link */
3515 bnx2x_cl45_read(bp, params->port,
3516 ext_phy_type,
3517 ext_phy_addr,
3518 MDIO_PMA_DEVAD,
3519 MDIO_PMA_REG_8481_LED1_MASK,
3520 &val1);
3521 /* Set bit 2 to 0, and bits [1:0] to 10 */
3522 val1 |= (1<<7);
3523 bnx2x_cl45_write(bp, params->port,
3524 ext_phy_type,
3525 ext_phy_addr,
3526 MDIO_PMA_DEVAD,
3527 MDIO_PMA_REG_8481_LED1_MASK,
3528 val1);
3529
3530 /* LED2 (1G/100/10G Link) */
3531 /* Mask LED2 for 10G link */
3532 bnx2x_cl45_write(bp, params->port,
3533 ext_phy_type,
3534 ext_phy_addr,
3535 MDIO_PMA_DEVAD,
3536 MDIO_PMA_REG_8481_LED2_MASK,
3537 0);
3538
3539 /* LED3 (10G/1G/100/10G Activity) */
3540 bnx2x_cl45_read(bp, params->port,
3541 ext_phy_type,
3542 ext_phy_addr,
3543 MDIO_PMA_DEVAD,
3544 MDIO_PMA_REG_8481_LINK_SIGNAL,
3545 &val1);
3546 /* Enable blink based on source 4(Activity) */
3547 val1 &= ~((1<<7) | (1<<8)); /* Clear bits 7,8 */
3548 val1 |= (1<<6); /* Set only bit 6 */
3549 bnx2x_cl45_write(bp, params->port,
3550 ext_phy_type,
3551 ext_phy_addr,
3552 MDIO_PMA_DEVAD,
3553 MDIO_PMA_REG_8481_LINK_SIGNAL,
3554 val1);
3555
3556 bnx2x_cl45_read(bp, params->port,
3557 ext_phy_type,
3558 ext_phy_addr,
3559 MDIO_PMA_DEVAD,
3560 MDIO_PMA_REG_8481_LED3_MASK,
3561 &val1);
3562 val1 |= (1<<4); /* Unmask LED3 for 10G link */
3563 bnx2x_cl45_write(bp, params->port,
3564 ext_phy_type,
3565 ext_phy_addr,
3566 MDIO_PMA_DEVAD,
3567 MDIO_PMA_REG_8481_LED3_MASK,
3568 val1);
3569}
3570
3571
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003572static void bnx2x_init_internal_phy(struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00003573 struct link_vars *vars,
3574 u8 enable_cl73)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003575{
3576 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003577
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003578 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003579 if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
3580 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3581 (params->feature_config_flags &
3582 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
3583 bnx2x_set_preemphasis(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003584
3585 /* forced speed requested? */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003586 if (vars->line_speed != SPEED_AUTO_NEG ||
3587 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
3588 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3589 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003590 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
3591
3592 /* disable autoneg */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003593 bnx2x_set_autoneg(params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003594
3595 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003596 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003597
3598 } else { /* AN_mode */
3599 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
3600
3601 /* AN enabled */
3602 bnx2x_set_brcm_cl37_advertisment(params);
3603
3604 /* program duplex & pause advertisement (for aneg) */
3605 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003606 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003607
3608 /* enable autoneg */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003609 bnx2x_set_autoneg(params, vars, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003610
3611 /* enable and restart AN */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003612 bnx2x_restart_autoneg(params, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003613 }
3614
3615 } else { /* SGMII mode */
3616 DP(NETIF_MSG_LINK, "SGMII\n");
3617
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003618 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003619 }
3620}
3621
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003622static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
3623{
3624 struct bnx2x *bp = params->bp;
3625 u32 ext_phy_type;
3626 u8 ext_phy_addr;
3627 u16 cnt;
3628 u16 ctrl = 0;
3629 u16 val = 0;
3630 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003631
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003632 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003633 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003634
3635 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3636 /* Make sure that the soft reset is off (expect for the 8072:
3637 * due to the lock, it will be done inside the specific
3638 * handling)
3639 */
3640 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3641 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3642 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
3643 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
3644 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
3645 /* Wait for soft reset to get cleared upto 1 sec */
3646 for (cnt = 0; cnt < 1000; cnt++) {
3647 bnx2x_cl45_read(bp, params->port,
3648 ext_phy_type,
3649 ext_phy_addr,
3650 MDIO_PMA_DEVAD,
3651 MDIO_PMA_REG_CTRL, &ctrl);
3652 if (!(ctrl & (1<<15)))
3653 break;
3654 msleep(1);
3655 }
3656 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
3657 ctrl, cnt);
3658 }
3659
3660 switch (ext_phy_type) {
3661 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003662 break;
3663
3664 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3665 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3666
3667 bnx2x_cl45_write(bp, params->port,
3668 ext_phy_type,
3669 ext_phy_addr,
3670 MDIO_PMA_DEVAD,
3671 MDIO_PMA_REG_MISC_CTRL,
3672 0x8288);
3673 bnx2x_cl45_write(bp, params->port,
3674 ext_phy_type,
3675 ext_phy_addr,
3676 MDIO_PMA_DEVAD,
3677 MDIO_PMA_REG_PHY_IDENTIFIER,
3678 0x7fbf);
3679 bnx2x_cl45_write(bp, params->port,
3680 ext_phy_type,
3681 ext_phy_addr,
3682 MDIO_PMA_DEVAD,
3683 MDIO_PMA_REG_CMU_PLL_BYPASS,
3684 0x0100);
3685 bnx2x_cl45_write(bp, params->port,
3686 ext_phy_type,
3687 ext_phy_addr,
3688 MDIO_WIS_DEVAD,
3689 MDIO_WIS_REG_LASI_CNTL, 0x1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003690
Eilon Greenstein3b313b62009-03-02 08:00:10 +00003691 /* BCM8705 doesn't have microcode, hence the 0 */
3692 bnx2x_save_spirom_version(bp, params->port,
3693 params->shmem_base, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003694 break;
3695
3696 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003697 /* Wait until fw is loaded */
3698 for (cnt = 0; cnt < 100; cnt++) {
3699 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3700 ext_phy_addr, MDIO_PMA_DEVAD,
3701 MDIO_PMA_REG_ROM_VER1, &val);
3702 if (val)
3703 break;
3704 msleep(10);
3705 }
3706 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized "
3707 "after %d ms\n", cnt);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003708 if ((params->feature_config_flags &
3709 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3710 u8 i;
3711 u16 reg;
3712 for (i = 0; i < 4; i++) {
3713 reg = MDIO_XS_8706_REG_BANK_RX0 +
3714 i*(MDIO_XS_8706_REG_BANK_RX1 -
3715 MDIO_XS_8706_REG_BANK_RX0);
3716 bnx2x_cl45_read(bp, params->port,
3717 ext_phy_type,
3718 ext_phy_addr,
3719 MDIO_XS_DEVAD,
3720 reg, &val);
3721 /* Clear first 3 bits of the control */
3722 val &= ~0x7;
3723 /* Set control bits according to
3724 configuation */
3725 val |= (params->xgxs_config_rx[i] &
3726 0x7);
3727 DP(NETIF_MSG_LINK, "Setting RX"
3728 "Equalizer to BCM8706 reg 0x%x"
3729 " <-- val 0x%x\n", reg, val);
3730 bnx2x_cl45_write(bp, params->port,
3731 ext_phy_type,
3732 ext_phy_addr,
3733 MDIO_XS_DEVAD,
3734 reg, val);
3735 }
3736 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003737 /* Force speed */
3738 /* First enable LASI */
3739 bnx2x_cl45_write(bp, params->port,
3740 ext_phy_type,
3741 ext_phy_addr,
3742 MDIO_PMA_DEVAD,
3743 MDIO_PMA_REG_RX_ALARM_CTRL,
3744 0x0400);
3745 bnx2x_cl45_write(bp, params->port,
3746 ext_phy_type,
3747 ext_phy_addr,
3748 MDIO_PMA_DEVAD,
3749 MDIO_PMA_REG_LASI_CTRL, 0x0004);
3750
3751 if (params->req_line_speed == SPEED_10000) {
3752 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
3753
3754 bnx2x_cl45_write(bp, params->port,
3755 ext_phy_type,
3756 ext_phy_addr,
3757 MDIO_PMA_DEVAD,
3758 MDIO_PMA_REG_DIGITAL_CTRL,
3759 0x400);
3760 } else {
3761 /* Force 1Gbps using autoneg with 1G
3762 advertisment */
3763
3764 /* Allow CL37 through CL73 */
3765 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3766 bnx2x_cl45_write(bp, params->port,
3767 ext_phy_type,
3768 ext_phy_addr,
3769 MDIO_AN_DEVAD,
3770 MDIO_AN_REG_CL37_CL73,
3771 0x040c);
3772
3773 /* Enable Full-Duplex advertisment on CL37 */
3774 bnx2x_cl45_write(bp, params->port,
3775 ext_phy_type,
3776 ext_phy_addr,
3777 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003778 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003779 0x0020);
3780 /* Enable CL37 AN */
3781 bnx2x_cl45_write(bp, params->port,
3782 ext_phy_type,
3783 ext_phy_addr,
3784 MDIO_AN_DEVAD,
3785 MDIO_AN_REG_CL37_AN,
3786 0x1000);
3787 /* 1G support */
3788 bnx2x_cl45_write(bp, params->port,
3789 ext_phy_type,
3790 ext_phy_addr,
3791 MDIO_AN_DEVAD,
3792 MDIO_AN_REG_ADV, (1<<5));
3793
3794 /* Enable clause 73 AN */
3795 bnx2x_cl45_write(bp, params->port,
3796 ext_phy_type,
3797 ext_phy_addr,
3798 MDIO_AN_DEVAD,
3799 MDIO_AN_REG_CTRL,
3800 0x1200);
3801
3802 }
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003803 bnx2x_save_bcm_spirom_ver(bp, params->port,
3804 ext_phy_type,
3805 ext_phy_addr,
3806 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003807 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003808 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3809 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3810 bnx2x_bcm8726_external_rom_boot(params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003811
Eilon Greenstein589abe32009-02-12 08:36:55 +00003812 /* Need to call module detected on initialization since
3813 the module detection triggered by actual module
3814 insertion might occur before driver is loaded, and when
3815 driver is loaded, it reset all registers, including the
3816 transmitter */
3817 bnx2x_sfp_module_detection(params);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003818
3819 /* Set Flow control */
3820 bnx2x_ext_phy_set_pause(params, vars);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003821 if (params->req_line_speed == SPEED_1000) {
3822 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3823 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3824 ext_phy_addr, MDIO_PMA_DEVAD,
3825 MDIO_PMA_REG_CTRL, 0x40);
3826 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3827 ext_phy_addr, MDIO_PMA_DEVAD,
3828 MDIO_PMA_REG_10G_CTRL2, 0xD);
3829 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3830 ext_phy_addr, MDIO_PMA_DEVAD,
3831 MDIO_PMA_REG_LASI_CTRL, 0x5);
3832 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3833 ext_phy_addr, MDIO_PMA_DEVAD,
3834 MDIO_PMA_REG_RX_ALARM_CTRL,
3835 0x400);
3836 } else if ((params->req_line_speed ==
3837 SPEED_AUTO_NEG) &&
3838 ((params->speed_cap_mask &
3839 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
3840 DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
3841 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3842 ext_phy_addr, MDIO_AN_DEVAD,
3843 MDIO_AN_REG_ADV, 0x20);
3844 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3845 ext_phy_addr, MDIO_AN_DEVAD,
3846 MDIO_AN_REG_CL37_CL73, 0x040c);
3847 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3848 ext_phy_addr, MDIO_AN_DEVAD,
3849 MDIO_AN_REG_CL37_FC_LD, 0x0020);
3850 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3851 ext_phy_addr, MDIO_AN_DEVAD,
3852 MDIO_AN_REG_CL37_AN, 0x1000);
3853 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3854 ext_phy_addr, MDIO_AN_DEVAD,
3855 MDIO_AN_REG_CTRL, 0x1200);
3856
3857 /* Enable RX-ALARM control to receive
3858 interrupt for 1G speed change */
3859 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3860 ext_phy_addr, MDIO_PMA_DEVAD,
3861 MDIO_PMA_REG_LASI_CTRL, 0x4);
3862 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3863 ext_phy_addr, MDIO_PMA_DEVAD,
3864 MDIO_PMA_REG_RX_ALARM_CTRL,
3865 0x400);
3866
3867 } else { /* Default 10G. Set only LASI control */
3868 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3869 ext_phy_addr, MDIO_PMA_DEVAD,
3870 MDIO_PMA_REG_LASI_CTRL, 1);
3871 }
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003872
3873 /* Set TX PreEmphasis if needed */
3874 if ((params->feature_config_flags &
3875 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3876 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
3877 "TX_CTRL2 0x%x\n",
3878 params->xgxs_config_tx[0],
3879 params->xgxs_config_tx[1]);
3880 bnx2x_cl45_write(bp, params->port,
3881 ext_phy_type,
3882 ext_phy_addr,
3883 MDIO_PMA_DEVAD,
3884 MDIO_PMA_REG_8726_TX_CTRL1,
3885 params->xgxs_config_tx[0]);
3886
3887 bnx2x_cl45_write(bp, params->port,
3888 ext_phy_type,
3889 ext_phy_addr,
3890 MDIO_PMA_DEVAD,
3891 MDIO_PMA_REG_8726_TX_CTRL2,
3892 params->xgxs_config_tx[1]);
3893 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00003894 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003895 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3896 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3897 {
3898 u16 tmp1;
3899 u16 rx_alarm_ctrl_val;
3900 u16 lasi_ctrl_val;
3901 if (ext_phy_type ==
3902 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3903 rx_alarm_ctrl_val = 0x400;
3904 lasi_ctrl_val = 0x0004;
3905 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003906 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003907 lasi_ctrl_val = 0x0004;
3908 }
3909
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003910 /* enable LASI */
3911 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003912 ext_phy_type,
3913 ext_phy_addr,
3914 MDIO_PMA_DEVAD,
3915 MDIO_PMA_REG_RX_ALARM_CTRL,
3916 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003917
3918 bnx2x_cl45_write(bp, params->port,
3919 ext_phy_type,
3920 ext_phy_addr,
3921 MDIO_PMA_DEVAD,
3922 MDIO_PMA_REG_LASI_CTRL,
3923 lasi_ctrl_val);
3924
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003925 bnx2x_8073_set_pause_cl37(params, vars);
3926
3927 if (ext_phy_type ==
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003928 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003929 bnx2x_bcm8072_external_rom_boot(params);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003930 else
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003931 /* In case of 8073 with long xaui lines,
3932 don't set the 8073 xaui low power*/
3933 bnx2x_bcm8073_set_xaui_low_power_mode(params);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003934
3935 bnx2x_cl45_read(bp, params->port,
3936 ext_phy_type,
3937 ext_phy_addr,
3938 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003939 MDIO_PMA_REG_M8051_MSGOUT_REG,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003940 &tmp1);
3941
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003942 bnx2x_cl45_read(bp, params->port,
3943 ext_phy_type,
3944 ext_phy_addr,
3945 MDIO_PMA_DEVAD,
3946 MDIO_PMA_REG_RX_ALARM, &tmp1);
3947
3948 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
3949 "0x%x\n", tmp1);
3950
3951 /* If this is forced speed, set to KR or KX
3952 * (all other are not supported)
3953 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003954 if (params->loopback_mode == LOOPBACK_EXT) {
3955 bnx2x_bcm807x_force_10G(params);
3956 DP(NETIF_MSG_LINK,
3957 "Forced speed 10G on 807X\n");
3958 break;
3959 } else {
3960 bnx2x_cl45_write(bp, params->port,
3961 ext_phy_type, ext_phy_addr,
3962 MDIO_PMA_DEVAD,
3963 MDIO_PMA_REG_BCM_CTRL,
3964 0x0002);
3965 }
3966 if (params->req_line_speed != SPEED_AUTO_NEG) {
3967 if (params->req_line_speed == SPEED_10000) {
3968 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003969 } else if (params->req_line_speed ==
3970 SPEED_2500) {
3971 val = (1<<5);
3972 /* Note that 2.5G works only
3973 when used with 1G advertisment */
3974 } else
3975 val = (1<<5);
3976 } else {
3977
3978 val = 0;
3979 if (params->speed_cap_mask &
3980 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3981 val |= (1<<7);
3982
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003983 /* Note that 2.5G works only when
3984 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003985 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003986 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3987 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003988 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003989 DP(NETIF_MSG_LINK,
3990 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003991 }
3992
3993 bnx2x_cl45_write(bp, params->port,
3994 ext_phy_type,
3995 ext_phy_addr,
3996 MDIO_AN_DEVAD,
3997 MDIO_AN_REG_ADV, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003998 if (ext_phy_type ==
3999 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004000 bnx2x_cl45_read(bp, params->port,
4001 ext_phy_type,
4002 ext_phy_addr,
4003 MDIO_AN_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004004 MDIO_AN_REG_8073_2_5G, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004005
4006 if (((params->speed_cap_mask &
4007 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
4008 (params->req_line_speed ==
4009 SPEED_AUTO_NEG)) ||
4010 (params->req_line_speed ==
4011 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004012 u16 phy_ver;
4013 /* Allow 2.5G for A1 and above */
4014 bnx2x_cl45_read(bp, params->port,
4015 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4016 ext_phy_addr,
4017 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004018 MDIO_PMA_REG_8073_CHIP_REV, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004019 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004020 if (phy_ver > 0)
4021 tmp1 |= 1;
4022 else
4023 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004024 } else {
4025 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004026 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004027 }
4028
4029 bnx2x_cl45_write(bp, params->port,
4030 ext_phy_type,
4031 ext_phy_addr,
4032 MDIO_AN_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004033 MDIO_AN_REG_8073_2_5G, tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004034 }
4035
4036 /* Add support for CL37 (passive mode) II */
4037
4038 bnx2x_cl45_read(bp, params->port,
4039 ext_phy_type,
4040 ext_phy_addr,
4041 MDIO_AN_DEVAD,
4042 MDIO_AN_REG_CL37_FC_LD,
4043 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004044
4045 bnx2x_cl45_write(bp, params->port,
4046 ext_phy_type,
4047 ext_phy_addr,
4048 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004049 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
4050 ((params->req_duplex == DUPLEX_FULL) ?
4051 0x20 : 0x40)));
4052
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004053 /* Add support for CL37 (passive mode) III */
4054 bnx2x_cl45_write(bp, params->port,
4055 ext_phy_type,
4056 ext_phy_addr,
4057 MDIO_AN_DEVAD,
4058 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004059
4060 if (ext_phy_type ==
4061 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004062 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004063 BW and FEE main tap. Rest commands are executed
4064 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004065 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004066 if (bnx2x_8073_is_snr_needed(params))
4067 bnx2x_cl45_write(bp, params->port,
4068 ext_phy_type,
4069 ext_phy_addr,
4070 MDIO_PMA_DEVAD,
4071 MDIO_PMA_REG_EDC_FFE_MAIN,
4072 0xFB0C);
4073
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004074 /* Enable FEC (Forware Error Correction)
4075 Request in the AN */
4076 bnx2x_cl45_read(bp, params->port,
4077 ext_phy_type,
4078 ext_phy_addr,
4079 MDIO_AN_DEVAD,
4080 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004081
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004082 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004083
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004084 bnx2x_cl45_write(bp, params->port,
4085 ext_phy_type,
4086 ext_phy_addr,
4087 MDIO_AN_DEVAD,
4088 MDIO_AN_REG_ADV2, tmp1);
4089
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004090 }
4091
4092 bnx2x_ext_phy_set_pause(params, vars);
4093
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004094 /* Restart autoneg */
4095 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004096 bnx2x_cl45_write(bp, params->port,
4097 ext_phy_type,
4098 ext_phy_addr,
4099 MDIO_AN_DEVAD,
4100 MDIO_AN_REG_CTRL, 0x1200);
4101 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
4102 "Advertise 1G=%x, 10G=%x\n",
4103 ((val & (1<<5)) > 0),
4104 ((val & (1<<7)) > 0));
4105 break;
4106 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004107
4108 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
4109 {
4110 u16 tmp1;
4111 u16 rx_alarm_ctrl_val;
4112 u16 lasi_ctrl_val;
4113
4114 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
4115
4116 u16 mod_abs;
4117 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
4118 lasi_ctrl_val = 0x0004;
4119
4120 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
4121 /* enable LASI */
4122 bnx2x_cl45_write(bp, params->port,
4123 ext_phy_type,
4124 ext_phy_addr,
4125 MDIO_PMA_DEVAD,
4126 MDIO_PMA_REG_RX_ALARM_CTRL,
4127 rx_alarm_ctrl_val);
4128
4129 bnx2x_cl45_write(bp, params->port,
4130 ext_phy_type,
4131 ext_phy_addr,
4132 MDIO_PMA_DEVAD,
4133 MDIO_PMA_REG_LASI_CTRL,
4134 lasi_ctrl_val);
4135
4136 /* Initially configure MOD_ABS to interrupt when
4137 module is presence( bit 8) */
4138 bnx2x_cl45_read(bp, params->port,
4139 ext_phy_type,
4140 ext_phy_addr,
4141 MDIO_PMA_DEVAD,
4142 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4143 /* Set EDC off by setting OPTXLOS signal input to low
4144 (bit 9).
4145 When the EDC is off it locks onto a reference clock and
4146 avoids becoming 'lost'.*/
4147 mod_abs &= ~((1<<8) | (1<<9));
4148 bnx2x_cl45_write(bp, params->port,
4149 ext_phy_type,
4150 ext_phy_addr,
4151 MDIO_PMA_DEVAD,
4152 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4153
4154 /* Make MOD_ABS give interrupt on change */
4155 bnx2x_cl45_read(bp, params->port,
4156 ext_phy_type,
4157 ext_phy_addr,
4158 MDIO_PMA_DEVAD,
4159 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4160 &val);
4161 val |= (1<<12);
4162 bnx2x_cl45_write(bp, params->port,
4163 ext_phy_type,
4164 ext_phy_addr,
4165 MDIO_PMA_DEVAD,
4166 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4167 val);
4168
4169 /* Set 8727 GPIOs to input to allow reading from the
4170 8727 GPIO0 status which reflect SFP+ module
4171 over-current */
4172
4173 bnx2x_cl45_read(bp, params->port,
4174 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4175 ext_phy_addr,
4176 MDIO_PMA_DEVAD,
4177 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4178 &val);
4179 val &= 0xff8f; /* Reset bits 4-6 */
4180 bnx2x_cl45_write(bp, params->port,
4181 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4182 ext_phy_addr,
4183 MDIO_PMA_DEVAD,
4184 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4185 val);
4186
4187 bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
4188 bnx2x_bcm8073_set_xaui_low_power_mode(params);
4189
4190 bnx2x_cl45_read(bp, params->port,
4191 ext_phy_type,
4192 ext_phy_addr,
4193 MDIO_PMA_DEVAD,
4194 MDIO_PMA_REG_M8051_MSGOUT_REG,
4195 &tmp1);
4196
4197 bnx2x_cl45_read(bp, params->port,
4198 ext_phy_type,
4199 ext_phy_addr,
4200 MDIO_PMA_DEVAD,
4201 MDIO_PMA_REG_RX_ALARM, &tmp1);
4202
4203 /* Set option 1G speed */
4204 if (params->req_line_speed == SPEED_1000) {
4205
4206 DP(NETIF_MSG_LINK, "Setting 1G force\n");
4207 bnx2x_cl45_write(bp, params->port,
4208 ext_phy_type,
4209 ext_phy_addr,
4210 MDIO_PMA_DEVAD,
4211 MDIO_PMA_REG_CTRL, 0x40);
4212 bnx2x_cl45_write(bp, params->port,
4213 ext_phy_type,
4214 ext_phy_addr,
4215 MDIO_PMA_DEVAD,
4216 MDIO_PMA_REG_10G_CTRL2, 0xD);
4217 bnx2x_cl45_read(bp, params->port,
4218 ext_phy_type,
4219 ext_phy_addr,
4220 MDIO_PMA_DEVAD,
4221 MDIO_PMA_REG_10G_CTRL2, &tmp1);
4222 DP(NETIF_MSG_LINK, "1.7 = 0x%x \n", tmp1);
4223
4224 } else if ((params->req_line_speed ==
4225 SPEED_AUTO_NEG) &&
4226 ((params->speed_cap_mask &
4227 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
4228
4229 DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
4230 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4231 ext_phy_addr, MDIO_AN_DEVAD,
4232 MDIO_PMA_REG_8727_MISC_CTRL, 0);
4233 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4234 ext_phy_addr, MDIO_AN_DEVAD,
4235 MDIO_AN_REG_CL37_AN, 0x1300);
4236 } else {
4237 /* Since the 8727 has only single reset pin,
4238 need to set the 10G registers although it is
4239 default */
4240 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4241 ext_phy_addr, MDIO_AN_DEVAD,
4242 MDIO_AN_REG_CTRL, 0x0020);
4243 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4244 ext_phy_addr, MDIO_AN_DEVAD,
4245 0x7, 0x0100);
4246 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4247 ext_phy_addr, MDIO_PMA_DEVAD,
4248 MDIO_PMA_REG_CTRL, 0x2040);
4249 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4250 ext_phy_addr, MDIO_PMA_DEVAD,
4251 MDIO_PMA_REG_10G_CTRL2, 0x0008);
4252 }
4253
4254 /* Set 2-wire transfer rate to 400Khz since 100Khz
4255 is not operational */
4256 bnx2x_cl45_write(bp, params->port,
4257 ext_phy_type,
4258 ext_phy_addr,
4259 MDIO_PMA_DEVAD,
4260 MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
4261 0xa101);
4262
4263 /* Set TX PreEmphasis if needed */
4264 if ((params->feature_config_flags &
4265 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4266 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
4267 "TX_CTRL2 0x%x\n",
4268 params->xgxs_config_tx[0],
4269 params->xgxs_config_tx[1]);
4270 bnx2x_cl45_write(bp, params->port,
4271 ext_phy_type,
4272 ext_phy_addr,
4273 MDIO_PMA_DEVAD,
4274 MDIO_PMA_REG_8727_TX_CTRL1,
4275 params->xgxs_config_tx[0]);
4276
4277 bnx2x_cl45_write(bp, params->port,
4278 ext_phy_type,
4279 ext_phy_addr,
4280 MDIO_PMA_DEVAD,
4281 MDIO_PMA_REG_8727_TX_CTRL2,
4282 params->xgxs_config_tx[1]);
4283 }
4284
4285 break;
4286 }
4287
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004288 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004289 {
4290 u16 fw_ver1, fw_ver2;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004291 DP(NETIF_MSG_LINK,
4292 "Setting the SFX7101 LASI indication\n");
4293
4294 bnx2x_cl45_write(bp, params->port,
4295 ext_phy_type,
4296 ext_phy_addr,
4297 MDIO_PMA_DEVAD,
4298 MDIO_PMA_REG_LASI_CTRL, 0x1);
4299 DP(NETIF_MSG_LINK,
4300 "Setting the SFX7101 LED to blink on traffic\n");
4301 bnx2x_cl45_write(bp, params->port,
4302 ext_phy_type,
4303 ext_phy_addr,
4304 MDIO_PMA_DEVAD,
4305 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
4306
4307 bnx2x_ext_phy_set_pause(params, vars);
4308 /* Restart autoneg */
4309 bnx2x_cl45_read(bp, params->port,
4310 ext_phy_type,
4311 ext_phy_addr,
4312 MDIO_AN_DEVAD,
4313 MDIO_AN_REG_CTRL, &val);
4314 val |= 0x200;
4315 bnx2x_cl45_write(bp, params->port,
4316 ext_phy_type,
4317 ext_phy_addr,
4318 MDIO_AN_DEVAD,
4319 MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00004320
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004321 /* Save spirom version */
4322 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4323 ext_phy_addr, MDIO_PMA_DEVAD,
4324 MDIO_PMA_REG_7101_VER1, &fw_ver1);
4325
4326 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4327 ext_phy_addr, MDIO_PMA_DEVAD,
4328 MDIO_PMA_REG_7101_VER2, &fw_ver2);
4329
4330 bnx2x_save_spirom_version(params->bp, params->port,
4331 params->shmem_base,
4332 (u32)(fw_ver1<<16 | fw_ver2));
Eilon Greenstein28577182009-02-12 08:37:00 +00004333 break;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004334 }
Eilon Greenstein28577182009-02-12 08:37:00 +00004335 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Eilon Greenstein2f904462009-08-12 08:22:16 +00004336 /* This phy uses the NIG latch mechanism since link
4337 indication arrives through its LED4 and not via
4338 its LASI signal, so we get steady signal
4339 instead of clear on read */
4340 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
4341 1 << NIG_LATCH_BC_ENABLE_MI_INT);
Eilon Greenstein28577182009-02-12 08:37:00 +00004342
Eilon Greenstein2f904462009-08-12 08:22:16 +00004343 bnx2x_8481_set_led4(params, ext_phy_type, ext_phy_addr);
4344 if (params->req_line_speed == SPEED_AUTO_NEG) {
Eilon Greenstein28577182009-02-12 08:37:00 +00004345
Eilon Greenstein2f904462009-08-12 08:22:16 +00004346 u16 autoneg_val, an_1000_val, an_10_100_val;
4347 /* set 1000 speed advertisement */
4348 bnx2x_cl45_read(bp, params->port,
4349 ext_phy_type,
4350 ext_phy_addr,
4351 MDIO_AN_DEVAD,
4352 MDIO_AN_REG_8481_1000T_CTRL,
4353 &an_1000_val);
4354
4355 if (params->speed_cap_mask &
4356 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) {
4357 an_1000_val |= (1<<8);
4358 if (params->req_duplex == DUPLEX_FULL)
4359 an_1000_val |= (1<<9);
4360 DP(NETIF_MSG_LINK, "Advertising 1G\n");
4361 } else
4362 an_1000_val &= ~((1<<8) | (1<<9));
4363
4364 bnx2x_cl45_write(bp, params->port,
4365 ext_phy_type,
4366 ext_phy_addr,
4367 MDIO_AN_DEVAD,
4368 MDIO_AN_REG_8481_1000T_CTRL,
4369 an_1000_val);
4370
4371 /* set 100 speed advertisement */
4372 bnx2x_cl45_read(bp, params->port,
4373 ext_phy_type,
4374 ext_phy_addr,
4375 MDIO_AN_DEVAD,
4376 MDIO_AN_REG_8481_LEGACY_AN_ADV,
4377 &an_10_100_val);
4378
4379 if (params->speed_cap_mask &
4380 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
4381 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) {
4382 an_10_100_val |= (1<<7);
4383 if (params->req_duplex == DUPLEX_FULL)
4384 an_10_100_val |= (1<<8);
4385 DP(NETIF_MSG_LINK,
4386 "Advertising 100M\n");
4387 } else
4388 an_10_100_val &= ~((1<<7) | (1<<8));
4389
4390 /* set 10 speed advertisement */
4391 if (params->speed_cap_mask &
4392 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
4393 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) {
4394 an_10_100_val |= (1<<5);
4395 if (params->req_duplex == DUPLEX_FULL)
4396 an_10_100_val |= (1<<6);
4397 DP(NETIF_MSG_LINK, "Advertising 10M\n");
4398 }
4399 else
4400 an_10_100_val &= ~((1<<5) | (1<<6));
4401
4402 bnx2x_cl45_write(bp, params->port,
4403 ext_phy_type,
4404 ext_phy_addr,
4405 MDIO_AN_DEVAD,
4406 MDIO_AN_REG_8481_LEGACY_AN_ADV,
4407 an_10_100_val);
4408
4409 bnx2x_cl45_read(bp, params->port,
4410 ext_phy_type,
4411 ext_phy_addr,
4412 MDIO_AN_DEVAD,
4413 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4414 &autoneg_val);
4415
4416 /* Disable forced speed */
4417 autoneg_val &= ~(1<<6|1<<13);
4418
4419 /* Enable autoneg and restart autoneg
4420 for legacy speeds */
4421 autoneg_val |= (1<<9|1<<12);
4422
4423 if (params->req_duplex == DUPLEX_FULL)
4424 autoneg_val |= (1<<8);
4425 else
4426 autoneg_val &= ~(1<<8);
4427
4428 bnx2x_cl45_write(bp, params->port,
4429 ext_phy_type,
4430 ext_phy_addr,
4431 MDIO_AN_DEVAD,
4432 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4433 autoneg_val);
4434
4435 if (params->speed_cap_mask &
4436 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) {
4437 DP(NETIF_MSG_LINK, "Advertising 10G\n");
4438 /* Restart autoneg for 10G*/
Eilon Greenstein28577182009-02-12 08:37:00 +00004439 bnx2x_cl45_read(bp, params->port,
4440 ext_phy_type,
4441 ext_phy_addr,
4442 MDIO_AN_DEVAD,
4443 MDIO_AN_REG_CTRL, &val);
4444 val |= 0x200;
4445 bnx2x_cl45_write(bp, params->port,
4446 ext_phy_type,
4447 ext_phy_addr,
4448 MDIO_AN_DEVAD,
4449 MDIO_AN_REG_CTRL, val);
Eilon Greenstein2f904462009-08-12 08:22:16 +00004450 }
4451 } else {
4452 /* Force speed */
4453 u16 autoneg_ctrl, pma_ctrl;
4454 bnx2x_cl45_read(bp, params->port,
4455 ext_phy_type,
4456 ext_phy_addr,
4457 MDIO_AN_DEVAD,
4458 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4459 &autoneg_ctrl);
4460
4461 /* Disable autoneg */
4462 autoneg_ctrl &= ~(1<<12);
4463
4464 /* Set 1000 force */
4465 switch (params->req_line_speed) {
4466 case SPEED_10000:
4467 DP(NETIF_MSG_LINK,
4468 "Unable to set 10G force !\n");
4469 break;
4470 case SPEED_1000:
4471 bnx2x_cl45_read(bp, params->port,
4472 ext_phy_type,
4473 ext_phy_addr,
4474 MDIO_PMA_DEVAD,
4475 MDIO_PMA_REG_CTRL,
4476 &pma_ctrl);
4477 autoneg_ctrl &= ~(1<<13);
4478 autoneg_ctrl |= (1<<6);
4479 pma_ctrl &= ~(1<<13);
4480 pma_ctrl |= (1<<6);
4481 DP(NETIF_MSG_LINK,
4482 "Setting 1000M force\n");
4483 bnx2x_cl45_write(bp, params->port,
4484 ext_phy_type,
4485 ext_phy_addr,
4486 MDIO_PMA_DEVAD,
4487 MDIO_PMA_REG_CTRL,
4488 pma_ctrl);
4489 break;
4490 case SPEED_100:
4491 autoneg_ctrl |= (1<<13);
4492 autoneg_ctrl &= ~(1<<6);
4493 DP(NETIF_MSG_LINK,
4494 "Setting 100M force\n");
4495 break;
4496 case SPEED_10:
4497 autoneg_ctrl &= ~(1<<13);
4498 autoneg_ctrl &= ~(1<<6);
4499 DP(NETIF_MSG_LINK,
4500 "Setting 10M force\n");
4501 break;
4502 }
4503
4504 /* Duplex mode */
4505 if (params->req_duplex == DUPLEX_FULL) {
4506 autoneg_ctrl |= (1<<8);
4507 DP(NETIF_MSG_LINK,
4508 "Setting full duplex\n");
4509 } else
4510 autoneg_ctrl &= ~(1<<8);
4511
4512 /* Update autoneg ctrl and pma ctrl */
4513 bnx2x_cl45_write(bp, params->port,
4514 ext_phy_type,
4515 ext_phy_addr,
4516 MDIO_AN_DEVAD,
4517 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4518 autoneg_ctrl);
4519 }
Eilon Greenstein28577182009-02-12 08:37:00 +00004520
Eilon Greensteinb1607af2009-08-12 08:22:54 +00004521 /* Save spirom version */
4522 bnx2x_save_8481_spirom_version(bp, params->port,
4523 ext_phy_addr,
4524 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004525 break;
4526 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4527 DP(NETIF_MSG_LINK,
4528 "XGXS PHY Failure detected 0x%x\n",
4529 params->ext_phy_config);
4530 rc = -EINVAL;
4531 break;
4532 default:
4533 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
4534 params->ext_phy_config);
4535 rc = -EINVAL;
4536 break;
4537 }
4538
4539 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004540
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004541 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4542 switch (ext_phy_type) {
4543 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
4544 DP(NETIF_MSG_LINK, "SerDes Direct\n");
4545 break;
4546
4547 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
4548 DP(NETIF_MSG_LINK, "SerDes 5482\n");
4549 break;
4550
4551 default:
4552 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
4553 params->ext_phy_config);
4554 break;
4555 }
4556 }
4557 return rc;
4558}
4559
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004560static void bnx2x_8727_handle_mod_abs(struct link_params *params)
4561{
4562 struct bnx2x *bp = params->bp;
4563 u16 mod_abs, rx_alarm_status;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00004564 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004565 u32 val = REG_RD(bp, params->shmem_base +
4566 offsetof(struct shmem_region, dev_info.
4567 port_feature_config[params->port].
4568 config));
4569 bnx2x_cl45_read(bp, params->port,
4570 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4571 ext_phy_addr,
4572 MDIO_PMA_DEVAD,
4573 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4574 if (mod_abs & (1<<8)) {
4575
4576 /* Module is absent */
4577 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4578 "show module is absent\n");
4579
4580 /* 1. Set mod_abs to detect next module
4581 presence event
4582 2. Set EDC off by setting OPTXLOS signal input to low
4583 (bit 9).
4584 When the EDC is off it locks onto a reference clock and
4585 avoids becoming 'lost'.*/
4586 mod_abs &= ~((1<<8)|(1<<9));
4587 bnx2x_cl45_write(bp, params->port,
4588 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4589 ext_phy_addr,
4590 MDIO_PMA_DEVAD,
4591 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4592
4593 /* Clear RX alarm since it stays up as long as
4594 the mod_abs wasn't changed */
4595 bnx2x_cl45_read(bp, params->port,
4596 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4597 ext_phy_addr,
4598 MDIO_PMA_DEVAD,
4599 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4600
4601 } else {
4602 /* Module is present */
4603 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4604 "show module is present\n");
4605 /* First thing, disable transmitter,
4606 and if the module is ok, the
4607 module_detection will enable it*/
4608
4609 /* 1. Set mod_abs to detect next module
4610 absent event ( bit 8)
4611 2. Restore the default polarity of the OPRXLOS signal and
4612 this signal will then correctly indicate the presence or
4613 absence of the Rx signal. (bit 9) */
4614 mod_abs |= ((1<<8)|(1<<9));
4615 bnx2x_cl45_write(bp, params->port,
4616 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4617 ext_phy_addr,
4618 MDIO_PMA_DEVAD,
4619 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4620
4621 /* Clear RX alarm since it stays up as long as
4622 the mod_abs wasn't changed. This is need to be done
4623 before calling the module detection, otherwise it will clear
4624 the link update alarm */
4625 bnx2x_cl45_read(bp, params->port,
4626 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4627 ext_phy_addr,
4628 MDIO_PMA_DEVAD,
4629 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4630
4631
4632 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4633 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4634 bnx2x_sfp_set_transmitter(bp, params->port,
4635 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4636 ext_phy_addr, 0);
4637
4638 if (bnx2x_wait_for_sfp_module_initialized(params)
4639 == 0)
4640 bnx2x_sfp_module_detection(params);
4641 else
4642 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
4643 }
4644
4645 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
4646 rx_alarm_status);
4647 /* No need to check link status in case of
4648 module plugged in/out */
4649}
4650
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004651
4652static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00004653 struct link_vars *vars,
4654 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004655{
4656 struct bnx2x *bp = params->bp;
4657 u32 ext_phy_type;
4658 u8 ext_phy_addr;
4659 u16 val1 = 0, val2;
4660 u16 rx_sd, pcs_status;
4661 u8 ext_phy_link_up = 0;
4662 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004663
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004664 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00004665 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004666 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4667 switch (ext_phy_type) {
4668 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4669 DP(NETIF_MSG_LINK, "XGXS Direct\n");
4670 ext_phy_link_up = 1;
4671 break;
4672
4673 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4674 DP(NETIF_MSG_LINK, "XGXS 8705\n");
4675 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4676 ext_phy_addr,
4677 MDIO_WIS_DEVAD,
4678 MDIO_WIS_REG_LASI_STATUS, &val1);
4679 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4680
4681 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4682 ext_phy_addr,
4683 MDIO_WIS_DEVAD,
4684 MDIO_WIS_REG_LASI_STATUS, &val1);
4685 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4686
4687 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4688 ext_phy_addr,
4689 MDIO_PMA_DEVAD,
4690 MDIO_PMA_REG_RX_SD, &rx_sd);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004691
4692 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4693 ext_phy_addr,
4694 1,
4695 0xc809, &val1);
4696 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4697 ext_phy_addr,
4698 1,
4699 0xc809, &val1);
4700
4701 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
4702 ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9))
4703 && ((val1 & (1<<8)) == 0));
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004704 if (ext_phy_link_up)
4705 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004706 break;
4707
4708 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00004709 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4710 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
4711 /* Clear RX Alarm*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004712 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4713 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00004714 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
4715 &val2);
4716 /* clear LASI indication*/
4717 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4718 ext_phy_addr,
4719 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
4720 &val1);
4721 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4722 ext_phy_addr,
4723 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
4724 &val2);
4725 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
4726 "0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004727
4728 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4729 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00004730 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
4731 &rx_sd);
4732 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4733 ext_phy_addr,
4734 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
4735 &pcs_status);
4736 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4737 ext_phy_addr,
4738 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
4739 &val2);
4740 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4741 ext_phy_addr,
4742 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
4743 &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004744
Eilon Greenstein589abe32009-02-12 08:36:55 +00004745 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004746 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
4747 rx_sd, pcs_status, val2);
4748 /* link is up if both bit 0 of pmd_rx_sd and
4749 * bit 0 of pcs_status are set, or if the autoneg bit
4750 1 is set
4751 */
4752 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
4753 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004754 if (ext_phy_link_up) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00004755 if (ext_phy_type ==
4756 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
4757 /* If transmitter is disabled,
4758 ignore false link up indication */
4759 bnx2x_cl45_read(bp, params->port,
4760 ext_phy_type,
4761 ext_phy_addr,
4762 MDIO_PMA_DEVAD,
4763 MDIO_PMA_REG_PHY_IDENTIFIER,
4764 &val1);
4765 if (val1 & (1<<15)) {
4766 DP(NETIF_MSG_LINK, "Tx is "
4767 "disabled\n");
4768 ext_phy_link_up = 0;
4769 break;
4770 }
4771 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004772 if (val2 & (1<<1))
4773 vars->line_speed = SPEED_1000;
4774 else
4775 vars->line_speed = SPEED_10000;
4776 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004777 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004778
4779 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
4780 {
4781 u16 link_status = 0;
4782 u16 rx_alarm_status;
4783 /* Check the LASI */
4784 bnx2x_cl45_read(bp, params->port,
4785 ext_phy_type,
4786 ext_phy_addr,
4787 MDIO_PMA_DEVAD,
4788 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4789
4790 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
4791 rx_alarm_status);
4792
4793 bnx2x_cl45_read(bp, params->port,
4794 ext_phy_type,
4795 ext_phy_addr,
4796 MDIO_PMA_DEVAD,
4797 MDIO_PMA_REG_LASI_STATUS, &val1);
4798
4799 DP(NETIF_MSG_LINK,
4800 "8727 LASI status 0x%x\n",
4801 val1);
4802
4803 /* Clear MSG-OUT */
4804 bnx2x_cl45_read(bp, params->port,
4805 ext_phy_type,
4806 ext_phy_addr,
4807 MDIO_PMA_DEVAD,
4808 MDIO_PMA_REG_M8051_MSGOUT_REG,
4809 &val1);
4810
4811 /*
4812 * If a module is present and there is need to check
4813 * for over current
4814 */
4815 if (!(params->feature_config_flags &
4816 FEATURE_CONFIG_BCM8727_NOC) &&
4817 !(rx_alarm_status & (1<<5))) {
4818 /* Check over-current using 8727 GPIO0 input*/
4819 bnx2x_cl45_read(bp, params->port,
4820 ext_phy_type,
4821 ext_phy_addr,
4822 MDIO_PMA_DEVAD,
4823 MDIO_PMA_REG_8727_GPIO_CTRL,
4824 &val1);
4825
4826 if ((val1 & (1<<8)) == 0) {
4827 DP(NETIF_MSG_LINK, "8727 Power fault"
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004828 " has been detected on "
4829 "port %d\n",
4830 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004831 printk(KERN_ERR PFX "Error: Power"
4832 " fault on %s Port %d has"
4833 " been detected and the"
4834 " power to that SFP+ module"
4835 " has been removed to prevent"
4836 " failure of the card. Please"
4837 " remove the SFP+ module and"
4838 " restart the system to clear"
4839 " this error.\n"
4840 , bp->dev->name, params->port);
4841 /*
4842 * Disable all RX_ALARMs except for
4843 * mod_abs
4844 */
4845 bnx2x_cl45_write(bp, params->port,
4846 ext_phy_type,
4847 ext_phy_addr,
4848 MDIO_PMA_DEVAD,
4849 MDIO_PMA_REG_RX_ALARM_CTRL,
4850 (1<<5));
4851
4852 bnx2x_cl45_read(bp, params->port,
4853 ext_phy_type,
4854 ext_phy_addr,
4855 MDIO_PMA_DEVAD,
4856 MDIO_PMA_REG_PHY_IDENTIFIER,
4857 &val1);
4858 /* Wait for module_absent_event */
4859 val1 |= (1<<8);
4860 bnx2x_cl45_write(bp, params->port,
4861 ext_phy_type,
4862 ext_phy_addr,
4863 MDIO_PMA_DEVAD,
4864 MDIO_PMA_REG_PHY_IDENTIFIER,
4865 val1);
4866 /* Clear RX alarm */
4867 bnx2x_cl45_read(bp, params->port,
4868 ext_phy_type,
4869 ext_phy_addr,
4870 MDIO_PMA_DEVAD,
4871 MDIO_PMA_REG_RX_ALARM,
4872 &rx_alarm_status);
4873 break;
4874 }
4875 } /* Over current check */
4876
4877 /* When module absent bit is set, check module */
4878 if (rx_alarm_status & (1<<5)) {
4879 bnx2x_8727_handle_mod_abs(params);
4880 /* Enable all mod_abs and link detection bits */
4881 bnx2x_cl45_write(bp, params->port,
4882 ext_phy_type,
4883 ext_phy_addr,
4884 MDIO_PMA_DEVAD,
4885 MDIO_PMA_REG_RX_ALARM_CTRL,
4886 ((1<<5) | (1<<2)));
4887 }
4888
4889 /* If transmitter is disabled,
4890 ignore false link up indication */
4891 bnx2x_cl45_read(bp, params->port,
4892 ext_phy_type,
4893 ext_phy_addr,
4894 MDIO_PMA_DEVAD,
4895 MDIO_PMA_REG_PHY_IDENTIFIER,
4896 &val1);
4897 if (val1 & (1<<15)) {
4898 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4899 ext_phy_link_up = 0;
4900 break;
4901 }
4902
4903 bnx2x_cl45_read(bp, params->port,
4904 ext_phy_type,
4905 ext_phy_addr,
4906 MDIO_PMA_DEVAD,
4907 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4908 &link_status);
4909
4910 /* Bits 0..2 --> speed detected,
4911 bits 13..15--> link is down */
4912 if ((link_status & (1<<2)) &&
4913 (!(link_status & (1<<15)))) {
4914 ext_phy_link_up = 1;
4915 vars->line_speed = SPEED_10000;
4916 } else if ((link_status & (1<<0)) &&
4917 (!(link_status & (1<<13)))) {
4918 ext_phy_link_up = 1;
4919 vars->line_speed = SPEED_1000;
4920 DP(NETIF_MSG_LINK,
4921 "port %x: External link"
4922 " up in 1G\n", params->port);
4923 } else {
4924 ext_phy_link_up = 0;
4925 DP(NETIF_MSG_LINK,
4926 "port %x: External link"
4927 " is down\n", params->port);
4928 }
4929 break;
4930 }
4931
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004932 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4933 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4934 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004935 u16 link_status = 0;
4936 u16 an1000_status = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004937
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004938 if (ext_phy_type ==
4939 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
4940 bnx2x_cl45_read(bp, params->port,
4941 ext_phy_type,
4942 ext_phy_addr,
4943 MDIO_PCS_DEVAD,
4944 MDIO_PCS_REG_LASI_STATUS, &val1);
4945 bnx2x_cl45_read(bp, params->port,
4946 ext_phy_type,
4947 ext_phy_addr,
4948 MDIO_PCS_DEVAD,
4949 MDIO_PCS_REG_LASI_STATUS, &val2);
4950 DP(NETIF_MSG_LINK,
4951 "870x LASI status 0x%x->0x%x\n",
4952 val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004953 } else {
4954 /* In 8073, port1 is directed through emac0 and
4955 * port0 is directed through emac1
4956 */
4957 bnx2x_cl45_read(bp, params->port,
4958 ext_phy_type,
4959 ext_phy_addr,
4960 MDIO_PMA_DEVAD,
4961 MDIO_PMA_REG_LASI_STATUS, &val1);
4962
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004963 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004964 "8703 LASI status 0x%x\n",
4965 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004966 }
4967
4968 /* clear the interrupt LASI status register */
4969 bnx2x_cl45_read(bp, params->port,
4970 ext_phy_type,
4971 ext_phy_addr,
4972 MDIO_PCS_DEVAD,
4973 MDIO_PCS_REG_STATUS, &val2);
4974 bnx2x_cl45_read(bp, params->port,
4975 ext_phy_type,
4976 ext_phy_addr,
4977 MDIO_PCS_DEVAD,
4978 MDIO_PCS_REG_STATUS, &val1);
4979 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
4980 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004981 /* Clear MSG-OUT */
4982 bnx2x_cl45_read(bp, params->port,
4983 ext_phy_type,
4984 ext_phy_addr,
4985 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004986 MDIO_PMA_REG_M8051_MSGOUT_REG,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004987 &val1);
4988
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004989 /* Check the LASI */
4990 bnx2x_cl45_read(bp, params->port,
4991 ext_phy_type,
4992 ext_phy_addr,
4993 MDIO_PMA_DEVAD,
4994 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004995
4996 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
4997
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004998 /* Check the link status */
4999 bnx2x_cl45_read(bp, params->port,
5000 ext_phy_type,
5001 ext_phy_addr,
5002 MDIO_PCS_DEVAD,
5003 MDIO_PCS_REG_STATUS, &val2);
5004 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
5005
5006 bnx2x_cl45_read(bp, params->port,
5007 ext_phy_type,
5008 ext_phy_addr,
5009 MDIO_PMA_DEVAD,
5010 MDIO_PMA_REG_STATUS, &val2);
5011 bnx2x_cl45_read(bp, params->port,
5012 ext_phy_type,
5013 ext_phy_addr,
5014 MDIO_PMA_DEVAD,
5015 MDIO_PMA_REG_STATUS, &val1);
5016 ext_phy_link_up = ((val1 & 4) == 4);
5017 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
5018 if (ext_phy_type ==
5019 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005020
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005021 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005022 ((params->req_line_speed !=
5023 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005024 if (bnx2x_bcm8073_xaui_wa(params)
5025 != 0) {
5026 ext_phy_link_up = 0;
5027 break;
5028 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005029 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005030 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005031 ext_phy_type,
5032 ext_phy_addr,
5033 MDIO_AN_DEVAD,
5034 MDIO_AN_REG_LINK_STATUS,
5035 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005036 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005037 ext_phy_type,
5038 ext_phy_addr,
5039 MDIO_AN_DEVAD,
5040 MDIO_AN_REG_LINK_STATUS,
5041 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005042
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005043 /* Check the link status on 1.1.2 */
5044 bnx2x_cl45_read(bp, params->port,
5045 ext_phy_type,
5046 ext_phy_addr,
5047 MDIO_PMA_DEVAD,
5048 MDIO_PMA_REG_STATUS, &val2);
5049 bnx2x_cl45_read(bp, params->port,
5050 ext_phy_type,
5051 ext_phy_addr,
5052 MDIO_PMA_DEVAD,
5053 MDIO_PMA_REG_STATUS, &val1);
5054 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
5055 "an_link_status=0x%x\n",
5056 val2, val1, an1000_status);
5057
Eilon Greenstein356e2382009-02-12 08:38:32 +00005058 ext_phy_link_up = (((val1 & 4) == 4) ||
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005059 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005060 if (ext_phy_link_up &&
5061 bnx2x_8073_is_snr_needed(params)) {
5062 /* The SNR will improve about 2dbby
5063 changing the BW and FEE main tap.*/
5064
5065 /* The 1st write to change FFE main
5066 tap is set before restart AN */
5067 /* Change PLL Bandwidth in EDC
5068 register */
5069 bnx2x_cl45_write(bp, port, ext_phy_type,
5070 ext_phy_addr,
5071 MDIO_PMA_DEVAD,
5072 MDIO_PMA_REG_PLL_BANDWIDTH,
5073 0x26BC);
5074
5075 /* Change CDR Bandwidth in EDC
5076 register */
5077 bnx2x_cl45_write(bp, port, ext_phy_type,
5078 ext_phy_addr,
5079 MDIO_PMA_DEVAD,
5080 MDIO_PMA_REG_CDR_BANDWIDTH,
5081 0x0333);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005082 }
5083 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005084 ext_phy_type,
5085 ext_phy_addr,
5086 MDIO_PMA_DEVAD,
5087 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
5088 &link_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005089
5090 /* Bits 0..2 --> speed detected,
5091 bits 13..15--> link is down */
5092 if ((link_status & (1<<2)) &&
5093 (!(link_status & (1<<15)))) {
5094 ext_phy_link_up = 1;
5095 vars->line_speed = SPEED_10000;
5096 DP(NETIF_MSG_LINK,
5097 "port %x: External link"
5098 " up in 10G\n", params->port);
5099 } else if ((link_status & (1<<1)) &&
5100 (!(link_status & (1<<14)))) {
5101 ext_phy_link_up = 1;
5102 vars->line_speed = SPEED_2500;
5103 DP(NETIF_MSG_LINK,
5104 "port %x: External link"
5105 " up in 2.5G\n", params->port);
5106 } else if ((link_status & (1<<0)) &&
5107 (!(link_status & (1<<13)))) {
5108 ext_phy_link_up = 1;
5109 vars->line_speed = SPEED_1000;
5110 DP(NETIF_MSG_LINK,
5111 "port %x: External link"
5112 " up in 1G\n", params->port);
5113 } else {
5114 ext_phy_link_up = 0;
5115 DP(NETIF_MSG_LINK,
5116 "port %x: External link"
5117 " is down\n", params->port);
5118 }
5119 } else {
5120 /* See if 1G link is up for the 8072 */
5121 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005122 ext_phy_type,
5123 ext_phy_addr,
5124 MDIO_AN_DEVAD,
5125 MDIO_AN_REG_LINK_STATUS,
5126 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005127 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005128 ext_phy_type,
5129 ext_phy_addr,
5130 MDIO_AN_DEVAD,
5131 MDIO_AN_REG_LINK_STATUS,
5132 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005133 if (an1000_status & (1<<1)) {
5134 ext_phy_link_up = 1;
5135 vars->line_speed = SPEED_1000;
5136 DP(NETIF_MSG_LINK,
5137 "port %x: External link"
5138 " up in 1G\n", params->port);
5139 } else if (ext_phy_link_up) {
5140 ext_phy_link_up = 1;
5141 vars->line_speed = SPEED_10000;
5142 DP(NETIF_MSG_LINK,
5143 "port %x: External link"
5144 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005145 }
5146 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005147
5148
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005149 break;
5150 }
5151 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5152 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5153 ext_phy_addr,
5154 MDIO_PMA_DEVAD,
5155 MDIO_PMA_REG_LASI_STATUS, &val2);
5156 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5157 ext_phy_addr,
5158 MDIO_PMA_DEVAD,
5159 MDIO_PMA_REG_LASI_STATUS, &val1);
5160 DP(NETIF_MSG_LINK,
5161 "10G-base-T LASI status 0x%x->0x%x\n",
5162 val2, val1);
5163 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5164 ext_phy_addr,
5165 MDIO_PMA_DEVAD,
5166 MDIO_PMA_REG_STATUS, &val2);
5167 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5168 ext_phy_addr,
5169 MDIO_PMA_DEVAD,
5170 MDIO_PMA_REG_STATUS, &val1);
5171 DP(NETIF_MSG_LINK,
5172 "10G-base-T PMA status 0x%x->0x%x\n",
5173 val2, val1);
5174 ext_phy_link_up = ((val1 & 4) == 4);
5175 /* if link is up
5176 * print the AN outcome of the SFX7101 PHY
5177 */
5178 if (ext_phy_link_up) {
5179 bnx2x_cl45_read(bp, params->port,
5180 ext_phy_type,
5181 ext_phy_addr,
5182 MDIO_AN_DEVAD,
5183 MDIO_AN_REG_MASTER_STATUS,
5184 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005185 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005186 DP(NETIF_MSG_LINK,
5187 "SFX7101 AN status 0x%x->Master=%x\n",
5188 val2,
5189 (val2 & (1<<14)));
5190 }
5191 break;
Eilon Greenstein28577182009-02-12 08:37:00 +00005192 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Eilon Greenstein2f904462009-08-12 08:22:16 +00005193 /* Check 10G-BaseT link status */
5194 /* Check PMD signal ok */
5195 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5196 ext_phy_addr,
5197 MDIO_AN_DEVAD,
5198 0xFFFA,
5199 &val1);
5200 bnx2x_cl45_read(bp, params->port, ext_phy_type,
Eilon Greenstein28577182009-02-12 08:37:00 +00005201 ext_phy_addr,
5202 MDIO_PMA_DEVAD,
Eilon Greenstein2f904462009-08-12 08:22:16 +00005203 MDIO_PMA_REG_8481_PMD_SIGNAL,
5204 &val2);
5205 DP(NETIF_MSG_LINK, "PMD_SIGNAL 1.a811 = 0x%x\n", val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005206
Eilon Greenstein2f904462009-08-12 08:22:16 +00005207 /* Check link 10G */
5208 if (val2 & (1<<11)) {
Eilon Greenstein28577182009-02-12 08:37:00 +00005209 vars->line_speed = SPEED_10000;
5210 ext_phy_link_up = 1;
Eilon Greenstein2f904462009-08-12 08:22:16 +00005211 bnx2x_8481_set_10G_led_mode(params,
5212 ext_phy_type,
5213 ext_phy_addr);
5214 } else { /* Check Legacy speed link */
5215 u16 legacy_status, legacy_speed;
Eilon Greenstein28577182009-02-12 08:37:00 +00005216
Eilon Greenstein2f904462009-08-12 08:22:16 +00005217 /* Enable expansion register 0x42
5218 (Operation mode status) */
5219 bnx2x_cl45_write(bp, params->port,
5220 ext_phy_type,
5221 ext_phy_addr,
5222 MDIO_AN_DEVAD,
5223 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS,
5224 0xf42);
Eilon Greenstein28577182009-02-12 08:37:00 +00005225
Eilon Greenstein2f904462009-08-12 08:22:16 +00005226 /* Get legacy speed operation status */
5227 bnx2x_cl45_read(bp, params->port,
5228 ext_phy_type,
5229 ext_phy_addr,
5230 MDIO_AN_DEVAD,
5231 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
5232 &legacy_status);
5233
5234 DP(NETIF_MSG_LINK, "Legacy speed status"
5235 " = 0x%x\n", legacy_status);
5236 ext_phy_link_up = ((legacy_status & (1<<11))
5237 == (1<<11));
5238 if (ext_phy_link_up) {
5239 legacy_speed = (legacy_status & (3<<9));
5240 if (legacy_speed == (0<<9))
5241 vars->line_speed = SPEED_10;
5242 else if (legacy_speed == (1<<9))
5243 vars->line_speed =
5244 SPEED_100;
5245 else if (legacy_speed == (2<<9))
5246 vars->line_speed =
5247 SPEED_1000;
5248 else /* Should not happen */
5249 vars->line_speed = 0;
5250
5251 if (legacy_status & (1<<8))
5252 vars->duplex = DUPLEX_FULL;
5253 else
5254 vars->duplex = DUPLEX_HALF;
5255
5256 DP(NETIF_MSG_LINK, "Link is up "
5257 "in %dMbps, is_duplex_full"
5258 "= %d\n",
5259 vars->line_speed,
5260 (vars->duplex == DUPLEX_FULL));
5261 bnx2x_8481_set_legacy_led_mode(params,
5262 ext_phy_type,
5263 ext_phy_addr);
Eilon Greenstein28577182009-02-12 08:37:00 +00005264 }
5265 }
Eilon Greenstein28577182009-02-12 08:37:00 +00005266 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005267 default:
5268 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
5269 params->ext_phy_config);
5270 ext_phy_link_up = 0;
5271 break;
5272 }
Eilon Greenstein57937202009-08-12 08:23:53 +00005273 /* Set SGMII mode for external phy */
5274 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
5275 if (vars->line_speed < SPEED_1000)
5276 vars->phy_flags |= PHY_SGMII_FLAG;
5277 else
5278 vars->phy_flags &= ~PHY_SGMII_FLAG;
5279 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005280
5281 } else { /* SerDes */
5282 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5283 switch (ext_phy_type) {
5284 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
5285 DP(NETIF_MSG_LINK, "SerDes Direct\n");
5286 ext_phy_link_up = 1;
5287 break;
5288
5289 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
5290 DP(NETIF_MSG_LINK, "SerDes 5482\n");
5291 ext_phy_link_up = 1;
5292 break;
5293
5294 default:
5295 DP(NETIF_MSG_LINK,
5296 "BAD SerDes ext_phy_config 0x%x\n",
5297 params->ext_phy_config);
5298 ext_phy_link_up = 0;
5299 break;
5300 }
5301 }
5302
5303 return ext_phy_link_up;
5304}
5305
5306static void bnx2x_link_int_enable(struct link_params *params)
5307{
5308 u8 port = params->port;
5309 u32 ext_phy_type;
5310 u32 mask;
5311 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005312
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005313 /* setting the status to report on link up
5314 for either XGXS or SerDes */
5315
5316 if (params->switch_cfg == SWITCH_CFG_10G) {
5317 mask = (NIG_MASK_XGXS0_LINK10G |
5318 NIG_MASK_XGXS0_LINK_STATUS);
5319 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
5320 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
5321 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
5322 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
5323 (ext_phy_type !=
5324 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
5325 mask |= NIG_MASK_MI_INT;
5326 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5327 }
5328
5329 } else { /* SerDes */
5330 mask = NIG_MASK_SERDES0_LINK_STATUS;
5331 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
5332 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5333 if ((ext_phy_type !=
5334 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
5335 (ext_phy_type !=
5336 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
5337 mask |= NIG_MASK_MI_INT;
5338 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5339 }
5340 }
5341 bnx2x_bits_en(bp,
5342 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5343 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005344
5345 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005346 (params->switch_cfg == SWITCH_CFG_10G),
5347 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005348 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
5349 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5350 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
5351 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
5352 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5353 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5354 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5355}
5356
Eilon Greenstein2f904462009-08-12 08:22:16 +00005357static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port,
5358 u8 is_mi_int)
5359{
5360 u32 latch_status = 0, is_mi_int_status;
5361 /* Disable the MI INT ( external phy int )
5362 * by writing 1 to the status register. Link down indication
5363 * is high-active-signal, so in this case we need to write the
5364 * status to clear the XOR
5365 */
5366 /* Read Latched signals */
5367 latch_status = REG_RD(bp,
5368 NIG_REG_LATCH_STATUS_0 + port*8);
5369 is_mi_int_status = REG_RD(bp,
5370 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4);
5371 DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x,"
5372 "latch_status = 0x%x\n",
5373 is_mi_int, is_mi_int_status, latch_status);
5374 /* Handle only those with latched-signal=up.*/
5375 if (latch_status & 1) {
5376 /* For all latched-signal=up,Write original_signal to status */
5377 if (is_mi_int)
5378 bnx2x_bits_en(bp,
5379 NIG_REG_STATUS_INTERRUPT_PORT0
5380 + port*4,
5381 NIG_STATUS_EMAC0_MI_INT);
5382 else
5383 bnx2x_bits_dis(bp,
5384 NIG_REG_STATUS_INTERRUPT_PORT0
5385 + port*4,
5386 NIG_STATUS_EMAC0_MI_INT);
5387 /* For all latched-signal=up : Re-Arm Latch signals */
5388 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
5389 (latch_status & 0xfffe) | (latch_status & 1));
5390 }
5391}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005392/*
5393 * link management
5394 */
5395static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00005396 struct link_vars *vars, u8 is_10g,
5397 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005398{
5399 struct bnx2x *bp = params->bp;
5400 u8 port = params->port;
5401
5402 /* first reset all status
5403 * we assume only one line will be change at a time */
5404 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5405 (NIG_STATUS_XGXS0_LINK10G |
5406 NIG_STATUS_XGXS0_LINK_STATUS |
5407 NIG_STATUS_SERDES0_LINK_STATUS));
Eilon Greenstein2f904462009-08-12 08:22:16 +00005408 if (XGXS_EXT_PHY_TYPE(params->ext_phy_config)
5409 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) {
5410 bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int);
5411 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005412 if (vars->phy_link_up) {
5413 if (is_10g) {
5414 /* Disable the 10G link interrupt
5415 * by writing 1 to the status register
5416 */
5417 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
5418 bnx2x_bits_en(bp,
5419 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5420 NIG_STATUS_XGXS0_LINK10G);
5421
5422 } else if (params->switch_cfg == SWITCH_CFG_10G) {
5423 /* Disable the link interrupt
5424 * by writing 1 to the relevant lane
5425 * in the status register
5426 */
5427 u32 ser_lane = ((params->lane_config &
5428 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
5429 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
5430
Eilon Greenstein2f904462009-08-12 08:22:16 +00005431 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
5432 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005433 bnx2x_bits_en(bp,
5434 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5435 ((1 << ser_lane) <<
5436 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
5437
5438 } else { /* SerDes */
5439 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
5440 /* Disable the link interrupt
5441 * by writing 1 to the status register
5442 */
5443 bnx2x_bits_en(bp,
5444 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5445 NIG_STATUS_SERDES0_LINK_STATUS);
5446 }
5447
5448 } else { /* link_down */
5449 }
5450}
5451
5452static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
5453{
5454 u8 *str_ptr = str;
5455 u32 mask = 0xf0000000;
5456 u8 shift = 8*4;
5457 u8 digit;
5458 if (len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02005459 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005460 *str_ptr = '\0';
5461 return -EINVAL;
5462 }
5463 while (shift > 0) {
5464
5465 shift -= 4;
5466 digit = ((num & mask) >> shift);
5467 if (digit < 0xa)
5468 *str_ptr = digit + '0';
5469 else
5470 *str_ptr = digit - 0xa + 'a';
5471 str_ptr++;
5472 mask = mask >> 4;
5473 if (shift == 4*4) {
5474 *str_ptr = ':';
5475 str_ptr++;
5476 }
5477 }
5478 *str_ptr = '\0';
5479 return 0;
5480}
5481
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005482u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
5483 u8 *version, u16 len)
5484{
Julia Lawall0376d5b2009-07-19 05:26:35 +00005485 struct bnx2x *bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005486 u32 ext_phy_type = 0;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005487 u32 spirom_ver = 0;
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005488 u8 status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005489
5490 if (version == NULL || params == NULL)
5491 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00005492 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005493
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005494 spirom_ver = REG_RD(bp, params->shmem_base +
5495 offsetof(struct shmem_region,
5496 port_mb[params->port].ext_phy_fw_version));
5497
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005498 status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005499 /* reset the returned value to zero */
5500 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005501 switch (ext_phy_type) {
5502 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5503
5504 if (len < 5)
5505 return -EINVAL;
5506
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005507 version[0] = (spirom_ver & 0xFF);
5508 version[1] = (spirom_ver & 0xFF00) >> 8;
5509 version[2] = (spirom_ver & 0xFF0000) >> 16;
5510 version[3] = (spirom_ver & 0xFF000000) >> 24;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005511 version[4] = '\0';
5512
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005513 break;
5514 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5515 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein4d295db2009-07-21 05:47:47 +00005516 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005517 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00005518 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greensteinb1607af2009-08-12 08:22:54 +00005519 status = bnx2x_format_ver(spirom_ver, version, len);
5520 break;
Eilon Greenstein9223dea2009-03-02 08:00:15 +00005521 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Eilon Greensteinb1607af2009-08-12 08:22:54 +00005522 spirom_ver = ((spirom_ver & 0xF80) >> 7) << 16 |
5523 (spirom_ver & 0x7F);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005524 status = bnx2x_format_ver(spirom_ver, version, len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005525 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005526 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005527 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5528 version[0] = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005529 break;
5530
5531 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
5532 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
5533 " type is FAILURE!\n");
5534 status = -EINVAL;
5535 break;
5536
5537 default:
5538 break;
5539 }
5540 return status;
5541}
5542
5543static void bnx2x_set_xgxs_loopback(struct link_params *params,
5544 struct link_vars *vars,
5545 u8 is_10g)
5546{
5547 u8 port = params->port;
5548 struct bnx2x *bp = params->bp;
5549
5550 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07005551 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005552
5553 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
5554
5555 /* change the uni_phy_addr in the nig */
5556 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
5557 port*0x18));
5558
5559 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
5560
5561 bnx2x_cl45_write(bp, port, 0,
5562 params->phy_addr,
5563 5,
5564 (MDIO_REG_BANK_AER_BLOCK +
5565 (MDIO_AER_BLOCK_AER_REG & 0xf)),
5566 0x2800);
5567
5568 bnx2x_cl45_write(bp, port, 0,
5569 params->phy_addr,
5570 5,
5571 (MDIO_REG_BANK_CL73_IEEEB0 +
5572 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
5573 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00005574 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005575 /* set aer mmd back */
5576 bnx2x_set_aer_mmd(params, vars);
5577
5578 /* and md_devad */
5579 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
5580 md_devad);
5581
5582 } else {
5583 u16 mii_control;
5584
5585 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
5586
5587 CL45_RD_OVER_CL22(bp, port,
5588 params->phy_addr,
5589 MDIO_REG_BANK_COMBO_IEEE0,
5590 MDIO_COMBO_IEEE0_MII_CONTROL,
5591 &mii_control);
5592
5593 CL45_WR_OVER_CL22(bp, port,
5594 params->phy_addr,
5595 MDIO_REG_BANK_COMBO_IEEE0,
5596 MDIO_COMBO_IEEE0_MII_CONTROL,
5597 (mii_control |
5598 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
5599 }
5600}
5601
5602
5603static void bnx2x_ext_phy_loopback(struct link_params *params)
5604{
5605 struct bnx2x *bp = params->bp;
5606 u8 ext_phy_addr;
5607 u32 ext_phy_type;
5608
5609 if (params->switch_cfg == SWITCH_CFG_10G) {
5610 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00005611 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005612 /* CL37 Autoneg Enabled */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005613 switch (ext_phy_type) {
5614 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
5615 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
5616 DP(NETIF_MSG_LINK,
5617 "ext_phy_loopback: We should not get here\n");
5618 break;
5619 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5620 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
5621 break;
5622 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
5623 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
5624 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00005625 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5626 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
5627 bnx2x_cl45_write(bp, params->port, ext_phy_type,
5628 ext_phy_addr,
5629 MDIO_PMA_DEVAD,
5630 MDIO_PMA_REG_CTRL,
5631 0x0001);
5632 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005633 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5634 /* SFX7101_XGXS_TEST1 */
5635 bnx2x_cl45_write(bp, params->port, ext_phy_type,
5636 ext_phy_addr,
5637 MDIO_XS_DEVAD,
5638 MDIO_XS_SFX7101_XGXS_TEST1,
5639 0x100);
5640 DP(NETIF_MSG_LINK,
5641 "ext_phy_loopback: set ext phy loopback\n");
5642 break;
5643 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5644
5645 break;
5646 } /* switch external PHY type */
5647 } else {
5648 /* serdes */
5649 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5650 ext_phy_addr = (params->ext_phy_config &
5651 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
5652 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
5653 }
5654}
5655
5656
5657/*
5658 *------------------------------------------------------------------------
5659 * bnx2x_override_led_value -
5660 *
5661 * Override the led value of the requsted led
5662 *
5663 *------------------------------------------------------------------------
5664 */
5665u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
5666 u32 led_idx, u32 value)
5667{
5668 u32 reg_val;
5669
5670 /* If port 0 then use EMAC0, else use EMAC1*/
5671 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
5672
5673 DP(NETIF_MSG_LINK,
5674 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
5675 port, led_idx, value);
5676
5677 switch (led_idx) {
5678 case 0: /* 10MB led */
5679 /* Read the current value of the LED register in
5680 the EMAC block */
5681 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5682 /* Set the OVERRIDE bit to 1 */
5683 reg_val |= EMAC_LED_OVERRIDE;
5684 /* If value is 1, set the 10M_OVERRIDE bit,
5685 otherwise reset it.*/
5686 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
5687 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
5688 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5689 break;
5690 case 1: /*100MB led */
5691 /*Read the current value of the LED register in
5692 the EMAC block */
5693 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5694 /* Set the OVERRIDE bit to 1 */
5695 reg_val |= EMAC_LED_OVERRIDE;
5696 /* If value is 1, set the 100M_OVERRIDE bit,
5697 otherwise reset it.*/
5698 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
5699 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
5700 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5701 break;
5702 case 2: /* 1000MB led */
5703 /* Read the current value of the LED register in the
5704 EMAC block */
5705 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5706 /* Set the OVERRIDE bit to 1 */
5707 reg_val |= EMAC_LED_OVERRIDE;
5708 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
5709 reset it. */
5710 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
5711 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
5712 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5713 break;
5714 case 3: /* 2500MB led */
5715 /* Read the current value of the LED register in the
5716 EMAC block*/
5717 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5718 /* Set the OVERRIDE bit to 1 */
5719 reg_val |= EMAC_LED_OVERRIDE;
5720 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
5721 reset it.*/
5722 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
5723 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
5724 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5725 break;
5726 case 4: /*10G led */
5727 if (port == 0) {
5728 REG_WR(bp, NIG_REG_LED_10G_P0,
5729 value);
5730 } else {
5731 REG_WR(bp, NIG_REG_LED_10G_P1,
5732 value);
5733 }
5734 break;
5735 case 5: /* TRAFFIC led */
5736 /* Find if the traffic control is via BMAC or EMAC */
5737 if (port == 0)
5738 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
5739 else
5740 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
5741
5742 /* Override the traffic led in the EMAC:*/
5743 if (reg_val == 1) {
5744 /* Read the current value of the LED register in
5745 the EMAC block */
5746 reg_val = REG_RD(bp, emac_base +
5747 EMAC_REG_EMAC_LED);
5748 /* Set the TRAFFIC_OVERRIDE bit to 1 */
5749 reg_val |= EMAC_LED_OVERRIDE;
5750 /* If value is 1, set the TRAFFIC bit, otherwise
5751 reset it.*/
5752 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
5753 (reg_val & ~EMAC_LED_TRAFFIC);
5754 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5755 } else { /* Override the traffic led in the BMAC: */
5756 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
5757 + port*4, 1);
5758 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
5759 value);
5760 }
5761 break;
5762 default:
5763 DP(NETIF_MSG_LINK,
5764 "bnx2x_override_led_value() unknown led index %d "
5765 "(should be 0-5)\n", led_idx);
5766 return -EINVAL;
5767 }
5768
5769 return 0;
5770}
5771
5772
Yaniv Rosner7846e472009-11-05 19:18:07 +02005773u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005774{
Yaniv Rosner7846e472009-11-05 19:18:07 +02005775 u8 port = params->port;
5776 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005777 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005778 u32 tmp;
5779 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02005780 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
5781 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005782 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
5783 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
5784 speed, hw_led_mode);
5785 switch (mode) {
5786 case LED_MODE_OFF:
5787 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
5788 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
5789 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005790
5791 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005792 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005793 break;
5794
5795 case LED_MODE_OPER:
Yaniv Rosner7846e472009-11-05 19:18:07 +02005796 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
5797 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
5798 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
5799 } else {
5800 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
5801 hw_led_mode);
5802 }
5803
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005804 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
5805 port*4, 0);
5806 /* Set blinking rate to ~15.9Hz */
5807 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
5808 LED_BLINK_RATE_VAL);
5809 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
5810 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005811 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005812 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005813 (tmp & (~EMAC_LED_OVERRIDE)));
5814
Yaniv Rosner7846e472009-11-05 19:18:07 +02005815 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005816 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005817 (speed == SPEED_1000) ||
5818 (speed == SPEED_100) ||
5819 (speed == SPEED_10))) {
5820 /* On Everest 1 Ax chip versions for speeds less than
5821 10G LED scheme is different */
5822 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
5823 + port*4, 1);
5824 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
5825 port*4, 0);
5826 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
5827 port*4, 1);
5828 }
5829 break;
5830
5831 default:
5832 rc = -EINVAL;
5833 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
5834 mode);
5835 break;
5836 }
5837 return rc;
5838
5839}
5840
5841u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
5842{
5843 struct bnx2x *bp = params->bp;
5844 u16 gp_status = 0;
5845
5846 CL45_RD_OVER_CL22(bp, params->port,
5847 params->phy_addr,
5848 MDIO_REG_BANK_GP_STATUS,
5849 MDIO_GP_STATUS_TOP_AN_STATUS1,
5850 &gp_status);
5851 /* link is up only if both local phy and external phy are up */
5852 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
Eilon Greenstein2f904462009-08-12 08:22:16 +00005853 bnx2x_ext_phy_is_link_up(params, vars, 1))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005854 return 0;
5855
5856 return -ESRCH;
5857}
5858
5859static u8 bnx2x_link_initialize(struct link_params *params,
5860 struct link_vars *vars)
5861{
5862 struct bnx2x *bp = params->bp;
5863 u8 port = params->port;
5864 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005865 u8 non_ext_phy;
5866 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005867
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005868 /* Activate the external PHY */
5869 bnx2x_ext_phy_reset(params, vars);
5870
5871 bnx2x_set_aer_mmd(params, vars);
5872
5873 if (vars->phy_flags & PHY_XGXS_FLAG)
5874 bnx2x_set_master_ln(params);
5875
5876 rc = bnx2x_reset_unicore(params);
5877 /* reset the SerDes and wait for reset bit return low */
5878 if (rc != 0)
5879 return rc;
5880
5881 bnx2x_set_aer_mmd(params, vars);
5882
5883 /* setting the masterLn_def again after the reset */
5884 if (vars->phy_flags & PHY_XGXS_FLAG) {
5885 bnx2x_set_master_ln(params);
5886 bnx2x_set_swap_lanes(params);
5887 }
5888
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005889 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00005890 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005891 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00005892 (params->req_line_speed == SPEED_10))) ||
5893 (!params->req_line_speed &&
5894 (params->speed_cap_mask >=
5895 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
5896 (params->speed_cap_mask <
5897 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
5898 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005899 vars->phy_flags |= PHY_SGMII_FLAG;
5900 } else {
5901 vars->phy_flags &= ~PHY_SGMII_FLAG;
5902 }
5903 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005904 /* In case of external phy existance, the line speed would be the
5905 line speed linked up by the external phy. In case it is direct only,
5906 then the line_speed during initialization will be equal to the
5907 req_line_speed*/
5908 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005909
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005910 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005911
5912 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005913 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00005914 (params->loopback_mode == LOOPBACK_XGXS_10));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005915
5916 if (non_ext_phy ||
Eilon Greenstein589abe32009-02-12 08:36:55 +00005917 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Eilon Greenstein28577182009-02-12 08:37:00 +00005918 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00005919 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005920 if (params->req_line_speed == SPEED_AUTO_NEG)
5921 bnx2x_set_parallel_detection(params, vars->phy_flags);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005922 bnx2x_init_internal_phy(params, vars, non_ext_phy);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005923 }
5924
5925 if (!non_ext_phy)
5926 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005927
5928 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005929 (NIG_STATUS_XGXS0_LINK10G |
5930 NIG_STATUS_XGXS0_LINK_STATUS |
5931 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005932
5933 return rc;
5934
5935}
5936
5937
5938u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
5939{
5940 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005941 u32 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005942
5943 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
5944 DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n",
5945 params->req_line_speed, params->req_flow_ctrl);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005946 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005947 vars->phy_link_up = 0;
5948 vars->link_up = 0;
5949 vars->line_speed = 0;
5950 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005951 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005952 vars->mac_type = MAC_TYPE_NONE;
5953
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005954 if (params->switch_cfg == SWITCH_CFG_1G)
5955 vars->phy_flags = PHY_SERDES_FLAG;
5956 else
5957 vars->phy_flags = PHY_XGXS_FLAG;
5958
5959 /* disable attentions */
5960 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
5961 (NIG_MASK_XGXS0_LINK_STATUS |
5962 NIG_MASK_XGXS0_LINK10G |
5963 NIG_MASK_SERDES0_LINK_STATUS |
5964 NIG_MASK_MI_INT));
5965
5966 bnx2x_emac_init(params, vars);
5967
5968 if (CHIP_REV_IS_FPGA(bp)) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005969
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005970 vars->link_up = 1;
5971 vars->line_speed = SPEED_10000;
5972 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005973 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005974 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005975 /* enable on E1.5 FPGA */
5976 if (CHIP_IS_E1H(bp)) {
5977 vars->flow_ctrl |=
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005978 (BNX2X_FLOW_CTRL_TX |
5979 BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005980 vars->link_status |=
5981 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
5982 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
5983 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005984
5985 bnx2x_emac_enable(params, vars, 0);
5986 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5987 /* disable drain */
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005988 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005989
5990 /* update shared memory */
5991 bnx2x_update_mng(params, vars->link_status);
5992
5993 return 0;
5994
5995 } else
5996 if (CHIP_REV_IS_EMUL(bp)) {
5997
5998 vars->link_up = 1;
5999 vars->line_speed = SPEED_10000;
6000 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006001 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006002 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
6003
6004 bnx2x_bmac_enable(params, vars, 0);
6005
6006 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
6007 /* Disable drain */
6008 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
6009 + params->port*4, 0);
6010
6011 /* update shared memory */
6012 bnx2x_update_mng(params, vars->link_status);
6013
6014 return 0;
6015
6016 } else
6017 if (params->loopback_mode == LOOPBACK_BMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006018
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006019 vars->link_up = 1;
6020 vars->line_speed = SPEED_10000;
6021 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006022 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006023 vars->mac_type = MAC_TYPE_BMAC;
6024
6025 vars->phy_flags = PHY_XGXS_FLAG;
6026
6027 bnx2x_phy_deassert(params, vars->phy_flags);
6028 /* set bmac loopback */
6029 bnx2x_bmac_enable(params, vars, 1);
6030
6031 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6032 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006033
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006034 } else if (params->loopback_mode == LOOPBACK_EMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006035
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006036 vars->link_up = 1;
6037 vars->line_speed = SPEED_1000;
6038 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006039 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006040 vars->mac_type = MAC_TYPE_EMAC;
6041
6042 vars->phy_flags = PHY_XGXS_FLAG;
6043
6044 bnx2x_phy_deassert(params, vars->phy_flags);
6045 /* set bmac loopback */
6046 bnx2x_emac_enable(params, vars, 1);
6047 bnx2x_emac_program(params, vars->line_speed,
6048 vars->duplex);
6049 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6050 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006051
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006052 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006053 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
6054
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006055 vars->link_up = 1;
6056 vars->line_speed = SPEED_10000;
6057 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006058 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006059
6060 vars->phy_flags = PHY_XGXS_FLAG;
6061
6062 val = REG_RD(bp,
6063 NIG_REG_XGXS0_CTRL_PHY_ADDR+
6064 params->port*0x18);
6065 params->phy_addr = (u8)val;
6066
6067 bnx2x_phy_deassert(params, vars->phy_flags);
6068 bnx2x_link_initialize(params, vars);
6069
6070 vars->mac_type = MAC_TYPE_BMAC;
6071
6072 bnx2x_bmac_enable(params, vars, 0);
6073
6074 if (params->loopback_mode == LOOPBACK_XGXS_10) {
6075 /* set 10G XGXS loopback */
6076 bnx2x_set_xgxs_loopback(params, vars, 1);
6077 } else {
6078 /* set external phy loopback */
6079 bnx2x_ext_phy_loopback(params);
6080 }
6081 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6082 params->port*4, 0);
Eilon Greensteinba71d312009-07-21 05:47:49 +00006083
Yaniv Rosner7846e472009-11-05 19:18:07 +02006084 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006085 } else
6086 /* No loopback */
6087 {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006088 bnx2x_phy_deassert(params, vars->phy_flags);
6089 switch (params->switch_cfg) {
6090 case SWITCH_CFG_1G:
6091 vars->phy_flags |= PHY_SERDES_FLAG;
6092 if ((params->ext_phy_config &
6093 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
6094 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006095 vars->phy_flags |= PHY_SGMII_FLAG;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006096 }
6097
6098 val = REG_RD(bp,
6099 NIG_REG_SERDES0_CTRL_PHY_ADDR+
6100 params->port*0x10);
6101
6102 params->phy_addr = (u8)val;
6103
6104 break;
6105 case SWITCH_CFG_10G:
6106 vars->phy_flags |= PHY_XGXS_FLAG;
6107 val = REG_RD(bp,
6108 NIG_REG_XGXS0_CTRL_PHY_ADDR+
6109 params->port*0x18);
6110 params->phy_addr = (u8)val;
6111
6112 break;
6113 default:
6114 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
6115 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006116 }
Eilon Greensteinf5372252009-02-12 08:38:30 +00006117 DP(NETIF_MSG_LINK, "Phy address = 0x%x\n", params->phy_addr);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006118
6119 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006120 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006121 bnx2x_link_int_enable(params);
6122 }
6123 return 0;
6124}
6125
Eilon Greenstein589abe32009-02-12 08:36:55 +00006126static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
6127{
6128 DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
6129
6130 /* Set serial boot control for external load */
6131 bnx2x_cl45_write(bp, port,
6132 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
6133 MDIO_PMA_DEVAD,
6134 MDIO_PMA_REG_GEN_CTRL, 0x0001);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006135}
6136
6137u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
6138 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006139{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006140 struct bnx2x *bp = params->bp;
6141 u32 ext_phy_config = params->ext_phy_config;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006142 u8 port = params->port;
6143 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006144 u32 val = REG_RD(bp, params->shmem_base +
6145 offsetof(struct shmem_region, dev_info.
6146 port_feature_config[params->port].
6147 config));
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02006148 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006149 /* disable attentions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006150 vars->link_status = 0;
6151 bnx2x_update_mng(params, vars->link_status);
6152 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6153 (NIG_MASK_XGXS0_LINK_STATUS |
6154 NIG_MASK_XGXS0_LINK10G |
6155 NIG_MASK_SERDES0_LINK_STATUS |
6156 NIG_MASK_MI_INT));
6157
6158 /* activate nig drain */
6159 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6160
6161 /* disable nig egress interface */
6162 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6163 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6164
6165 /* Stop BigMac rx */
6166 bnx2x_bmac_rx_disable(bp, port);
6167
6168 /* disable emac */
6169 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6170
6171 msleep(10);
6172 /* The PHY reset is controled by GPIO 1
6173 * Hold it as vars low
6174 */
6175 /* clear link led */
Yaniv Rosner7846e472009-11-05 19:18:07 +02006176 bnx2x_set_led(params, LED_MODE_OFF, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006177 if (reset_ext_phy) {
6178 switch (ext_phy_type) {
6179 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
6180 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
6181 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006182
6183 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6184 {
6185
6186 /* Disable Transmitter */
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006187 u8 ext_phy_addr =
6188 XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006189 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
6190 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
6191 bnx2x_sfp_set_transmitter(bp, port,
6192 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6193 ext_phy_addr, 0);
6194 break;
6195 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00006196 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6197 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
6198 "low power mode\n",
6199 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006200 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07006201 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6202 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006203 break;
6204 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6205 {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006206 u8 ext_phy_addr =
6207 XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006208 /* Set soft reset */
6209 bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
6210 break;
6211 }
6212 default:
6213 /* HW reset */
6214 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
6215 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6216 port);
6217 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6218 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6219 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006220 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006221 }
6222 }
6223 /* reset the SerDes/XGXS */
6224 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
6225 (0x1ff << (port*16)));
6226
6227 /* reset BigMac */
6228 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
6229 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
6230
6231 /* disable nig ingress interface */
6232 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
6233 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
6234 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6235 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6236 vars->link_up = 0;
6237 return 0;
6238}
6239
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006240static u8 bnx2x_update_link_down(struct link_params *params,
6241 struct link_vars *vars)
6242{
6243 struct bnx2x *bp = params->bp;
6244 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006245
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006246 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7846e472009-11-05 19:18:07 +02006247 bnx2x_set_led(params, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006248
6249 /* indicate no mac active */
6250 vars->mac_type = MAC_TYPE_NONE;
6251
6252 /* update shared memory */
6253 vars->link_status = 0;
6254 vars->line_speed = 0;
6255 bnx2x_update_mng(params, vars->link_status);
6256
6257 /* activate nig drain */
6258 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6259
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006260 /* disable emac */
6261 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6262
6263 msleep(10);
6264
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006265 /* reset BigMac */
6266 bnx2x_bmac_rx_disable(bp, params->port);
6267 REG_WR(bp, GRCBASE_MISC +
6268 MISC_REGISTERS_RESET_REG_2_CLEAR,
6269 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
6270 return 0;
6271}
6272
6273static u8 bnx2x_update_link_up(struct link_params *params,
6274 struct link_vars *vars,
6275 u8 link_10g, u32 gp_status)
6276{
6277 struct bnx2x *bp = params->bp;
6278 u8 port = params->port;
6279 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006280
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006281 vars->link_status |= LINK_STATUS_LINK_UP;
6282 if (link_10g) {
6283 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7846e472009-11-05 19:18:07 +02006284 bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006285 } else {
6286 bnx2x_emac_enable(params, vars, 0);
6287 rc = bnx2x_emac_program(params, vars->line_speed,
6288 vars->duplex);
6289
6290 /* AN complete? */
6291 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
6292 if (!(vars->phy_flags &
6293 PHY_SGMII_FLAG))
Eilon Greensteined8680a2009-02-12 08:37:12 +00006294 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006295 }
6296 }
6297
6298 /* PBF - link up */
6299 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
6300 vars->line_speed);
6301
6302 /* disable drain */
6303 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
6304
6305 /* update shared memory */
6306 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006307 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006308 return rc;
6309}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006310/* This function should called upon link interrupt */
6311/* In case vars->link_up, driver needs to
6312 1. Update the pbf
6313 2. Disable drain
6314 3. Update the shared memory
6315 4. Indicate link up
6316 5. Set LEDs
6317 Otherwise,
6318 1. Update shared memory
6319 2. Reset BigMac
6320 3. Report link down
6321 4. Unset LEDs
6322*/
6323u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
6324{
6325 struct bnx2x *bp = params->bp;
6326 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006327 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006328 u8 link_10g;
6329 u8 ext_phy_link_up, rc = 0;
6330 u32 ext_phy_type;
Eilon Greenstein2f904462009-08-12 08:22:16 +00006331 u8 is_mi_int = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006332
6333 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006334 port, (vars->phy_flags & PHY_XGXS_FLAG),
6335 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006336
Eilon Greenstein2f904462009-08-12 08:22:16 +00006337 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
6338 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006339 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006340 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
6341 is_mi_int,
6342 REG_RD(bp,
6343 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006344
6345 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
6346 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
6347 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
6348
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006349 /* disable emac */
6350 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6351
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006352 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006353
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006354 /* Check external link change only for non-direct */
Eilon Greenstein2f904462009-08-12 08:22:16 +00006355 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars, is_mi_int);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006356
6357 /* Read gp_status */
6358 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
6359 MDIO_REG_BANK_GP_STATUS,
6360 MDIO_GP_STATUS_TOP_AN_STATUS1,
6361 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006362
Eilon Greenstein2f904462009-08-12 08:22:16 +00006363 rc = bnx2x_link_settings_status(params, vars, gp_status,
6364 ext_phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006365 if (rc != 0)
6366 return rc;
6367
6368 /* anything 10 and over uses the bmac */
6369 link_10g = ((vars->line_speed == SPEED_10000) ||
6370 (vars->line_speed == SPEED_12000) ||
6371 (vars->line_speed == SPEED_12500) ||
6372 (vars->line_speed == SPEED_13000) ||
6373 (vars->line_speed == SPEED_15000) ||
6374 (vars->line_speed == SPEED_16000));
6375
Eilon Greenstein2f904462009-08-12 08:22:16 +00006376 bnx2x_link_int_ack(params, vars, link_10g, is_mi_int);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006377
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006378 /* In case external phy link is up, and internal link is down
6379 ( not initialized yet probably after link initialization, it needs
6380 to be initialized.
6381 Note that after link down-up as result of cable plug,
6382 the xgxs link would probably become up again without the need to
6383 initialize it*/
6384
6385 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
6386 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
Eilon Greenstein589abe32009-02-12 08:36:55 +00006387 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006388 (ext_phy_link_up && !vars->phy_link_up))
Eilon Greenstein239d6862009-08-12 08:23:04 +00006389 bnx2x_init_internal_phy(params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006390
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006391 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006392 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006393
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006394 if (vars->link_up)
6395 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
6396 else
6397 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006398
6399 return rc;
6400}
6401
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006402static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6403{
6404 u8 ext_phy_addr[PORT_MAX];
6405 u16 val;
6406 s8 port;
6407
6408 /* PART1 - Reset both phys */
6409 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6410 /* Extract the ext phy address for the port */
6411 u32 ext_phy_config = REG_RD(bp, shmem_base +
6412 offsetof(struct shmem_region,
6413 dev_info.port_hw_config[port].external_phy_config));
6414
6415 /* disable attentions */
6416 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6417 (NIG_MASK_XGXS0_LINK_STATUS |
6418 NIG_MASK_XGXS0_LINK10G |
6419 NIG_MASK_SERDES0_LINK_STATUS |
6420 NIG_MASK_MI_INT));
6421
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006422 ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006423
6424 /* Need to take the phy out of low power mode in order
6425 to write to access its registers */
6426 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6427 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
6428
6429 /* Reset the phy */
6430 bnx2x_cl45_write(bp, port,
6431 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6432 ext_phy_addr[port],
6433 MDIO_PMA_DEVAD,
6434 MDIO_PMA_REG_CTRL,
6435 1<<15);
6436 }
6437
6438 /* Add delay of 150ms after reset */
6439 msleep(150);
6440
6441 /* PART2 - Download firmware to both phys */
6442 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6443 u16 fw_ver1;
6444
6445 bnx2x_bcm8073_external_rom_boot(bp, port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00006446 ext_phy_addr[port], shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006447
6448 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6449 ext_phy_addr[port],
6450 MDIO_PMA_DEVAD,
6451 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006452 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006453 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006454 "bnx2x_8073_common_init_phy port %x:"
6455 "Download failed. fw version = 0x%x\n",
6456 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006457 return -EINVAL;
6458 }
6459
6460 /* Only set bit 10 = 1 (Tx power down) */
6461 bnx2x_cl45_read(bp, port,
6462 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6463 ext_phy_addr[port],
6464 MDIO_PMA_DEVAD,
6465 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6466
6467 /* Phase1 of TX_POWER_DOWN reset */
6468 bnx2x_cl45_write(bp, port,
6469 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6470 ext_phy_addr[port],
6471 MDIO_PMA_DEVAD,
6472 MDIO_PMA_REG_TX_POWER_DOWN,
6473 (val | 1<<10));
6474 }
6475
6476 /* Toggle Transmitter: Power down and then up with 600ms
6477 delay between */
6478 msleep(600);
6479
6480 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
6481 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00006482 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006483 /* Release bit 10 (Release Tx power down) */
6484 bnx2x_cl45_read(bp, port,
6485 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6486 ext_phy_addr[port],
6487 MDIO_PMA_DEVAD,
6488 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6489
6490 bnx2x_cl45_write(bp, port,
6491 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6492 ext_phy_addr[port],
6493 MDIO_PMA_DEVAD,
6494 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
6495 msleep(15);
6496
6497 /* Read modify write the SPI-ROM version select register */
6498 bnx2x_cl45_read(bp, port,
6499 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6500 ext_phy_addr[port],
6501 MDIO_PMA_DEVAD,
6502 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
6503 bnx2x_cl45_write(bp, port,
6504 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6505 ext_phy_addr[port],
6506 MDIO_PMA_DEVAD,
6507 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
6508
6509 /* set GPIO2 back to LOW */
6510 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6511 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
6512 }
6513 return 0;
6514
6515}
6516
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006517static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6518{
6519 u8 ext_phy_addr[PORT_MAX];
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006520 s8 port, first_port, i;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006521 u32 swap_val, swap_override;
6522 DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
6523 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
6524 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
6525
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006526 bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006527 msleep(5);
6528
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006529 if (swap_val && swap_override)
6530 first_port = PORT_0;
6531 else
6532 first_port = PORT_1;
6533
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006534 /* PART1 - Reset both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006535 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006536 /* Extract the ext phy address for the port */
6537 u32 ext_phy_config = REG_RD(bp, shmem_base +
6538 offsetof(struct shmem_region,
6539 dev_info.port_hw_config[port].external_phy_config));
6540
6541 /* disable attentions */
6542 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6543 (NIG_MASK_XGXS0_LINK_STATUS |
6544 NIG_MASK_XGXS0_LINK10G |
6545 NIG_MASK_SERDES0_LINK_STATUS |
6546 NIG_MASK_MI_INT));
6547
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006548 ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006549
6550 /* Reset the phy */
6551 bnx2x_cl45_write(bp, port,
6552 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6553 ext_phy_addr[port],
6554 MDIO_PMA_DEVAD,
6555 MDIO_PMA_REG_CTRL,
6556 1<<15);
6557 }
6558
6559 /* Add delay of 150ms after reset */
6560 msleep(150);
6561
6562 /* PART2 - Download firmware to both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006563 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006564 u16 fw_ver1;
6565
6566 bnx2x_bcm8727_external_rom_boot(bp, port,
6567 ext_phy_addr[port], shmem_base);
6568
6569 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6570 ext_phy_addr[port],
6571 MDIO_PMA_DEVAD,
6572 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
6573 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
6574 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006575 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006576 "Download failed. fw version = 0x%x\n",
6577 port, fw_ver1);
6578 return -EINVAL;
6579 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006580 }
6581
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006582 return 0;
6583}
6584
Eilon Greenstein589abe32009-02-12 08:36:55 +00006585
6586static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6587{
6588 u8 ext_phy_addr;
6589 u32 val;
6590 s8 port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006591
Eilon Greenstein589abe32009-02-12 08:36:55 +00006592 /* Use port1 because of the static port-swap */
6593 /* Enable the module detection interrupt */
6594 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
6595 val |= ((1<<MISC_REGISTERS_GPIO_3)|
6596 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
6597 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
6598
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006599 bnx2x_ext_phy_hw_reset(bp, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006600 msleep(5);
6601 for (port = 0; port < PORT_MAX; port++) {
6602 /* Extract the ext phy address for the port */
6603 u32 ext_phy_config = REG_RD(bp, shmem_base +
6604 offsetof(struct shmem_region,
6605 dev_info.port_hw_config[port].external_phy_config));
6606
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006607 ext_phy_addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006608 DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
6609 ext_phy_addr);
6610
6611 bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
6612
6613 /* Set fault module detected LED on */
6614 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
6615 MISC_REGISTERS_GPIO_HIGH,
6616 port);
6617 }
6618
6619 return 0;
6620}
6621
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006622u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6623{
6624 u8 rc = 0;
6625 u32 ext_phy_type;
6626
Eilon Greensteinf5372252009-02-12 08:38:30 +00006627 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006628
6629 /* Read the ext_phy_type for arbitrary port(0) */
6630 ext_phy_type = XGXS_EXT_PHY_TYPE(
6631 REG_RD(bp, shmem_base +
6632 offsetof(struct shmem_region,
6633 dev_info.port_hw_config[0].external_phy_config)));
6634
6635 switch (ext_phy_type) {
6636 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6637 {
6638 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
6639 break;
6640 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006641
6642 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6643 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6644 rc = bnx2x_8727_common_init_phy(bp, shmem_base);
6645 break;
6646
Eilon Greenstein589abe32009-02-12 08:36:55 +00006647 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6648 /* GPIO1 affects both ports, so there's need to pull
6649 it for single port alone */
6650 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
6651
6652 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006653 default:
6654 DP(NETIF_MSG_LINK,
6655 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
6656 ext_phy_type);
6657 break;
6658 }
6659
6660 return rc;
6661}
6662
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006663void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006664{
6665 u16 val, cnt;
6666
6667 bnx2x_cl45_read(bp, port,
6668 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6669 phy_addr,
6670 MDIO_PMA_DEVAD,
6671 MDIO_PMA_REG_7101_RESET, &val);
6672
6673 for (cnt = 0; cnt < 10; cnt++) {
6674 msleep(50);
6675 /* Writes a self-clearing reset */
6676 bnx2x_cl45_write(bp, port,
6677 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6678 phy_addr,
6679 MDIO_PMA_DEVAD,
6680 MDIO_PMA_REG_7101_RESET,
6681 (val | (1<<15)));
6682 /* Wait for clear */
6683 bnx2x_cl45_read(bp, port,
6684 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6685 phy_addr,
6686 MDIO_PMA_DEVAD,
6687 MDIO_PMA_REG_7101_RESET, &val);
6688
6689 if ((val & (1<<15)) == 0)
6690 break;
6691 }
6692}