blob: 51d468d430ee868793d179148e2590054507754c [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
Joe Perches7995c642010-02-17 15:01:52 +000017#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070019#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/pci.h>
22#include <linux/netdevice.h>
23#include <linux/delay.h>
24#include <linux/ethtool.h>
25#include <linux/mutex.h>
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070026
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070027#include "bnx2x.h"
28
29/********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070030#define ETH_HLEN 14
Dmitry Kravkov523224a2010-10-06 03:23:26 +000031#define ETH_OVREHEAD (ETH_HLEN + 8 + 8)/* 16 for CRC + VLAN + LLC */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070032#define ETH_MIN_PACKET_SIZE 60
33#define ETH_MAX_PACKET_SIZE 1500
34#define ETH_MAX_JUMBO_PACKET_SIZE 9600
35#define MDIO_ACCESS_TIMEOUT 1000
36#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070037
38/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070039/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070040/***********************************************************/
41
Eilon Greenstein2f904462009-08-12 08:22:16 +000042#define NIG_LATCH_BC_ENABLE_MI_INT 0
43
44#define NIG_STATUS_EMAC0_MI_INT \
45 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070046#define NIG_STATUS_XGXS0_LINK10G \
47 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
48#define NIG_STATUS_XGXS0_LINK_STATUS \
49 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
50#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
51 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
52#define NIG_STATUS_SERDES0_LINK_STATUS \
53 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
54#define NIG_MASK_MI_INT \
55 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
56#define NIG_MASK_XGXS0_LINK10G \
57 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
58#define NIG_MASK_XGXS0_LINK_STATUS \
59 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
60#define NIG_MASK_SERDES0_LINK_STATUS \
61 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
62
63#define MDIO_AN_CL73_OR_37_COMPLETE \
64 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
65 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
66
67#define XGXS_RESET_BITS \
68 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
71 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
72 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
73
74#define SERDES_RESET_BITS \
75 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
77 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
78 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
79
80#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
81#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Eilon Greenstein3196a882008-08-13 15:58:49 -070082#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
83#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070084 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070085#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070086 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070087#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070088
89#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
90 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
91#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
92 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
93#define GP_STATUS_SPEED_MASK \
94 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
95#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
96#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
97#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
98#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
99#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
100#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
101#define GP_STATUS_10G_HIG \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
103#define GP_STATUS_10G_CX4 \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
105#define GP_STATUS_12G_HIG \
106 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
107#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
108#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
109#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
110#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
111#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
112#define GP_STATUS_10G_KX4 \
113 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
114
115#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
116#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
117#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
118#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
119#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
120#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
121#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
122#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
123#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
124#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
125#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
126#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
127#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
128#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
129#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
130#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
131#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
132#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
133#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
134#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
135#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
136#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
137#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
138
139#define PHY_XGXS_FLAG 0x1
140#define PHY_SGMII_FLAG 0x2
141#define PHY_SERDES_FLAG 0x4
142
Eilon Greenstein589abe32009-02-12 08:36:55 +0000143/* */
144#define SFP_EEPROM_CON_TYPE_ADDR 0x2
145 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
146 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
147
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000148
149#define SFP_EEPROM_COMP_CODE_ADDR 0x3
150 #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
151 #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
152 #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
153
Eilon Greenstein589abe32009-02-12 08:36:55 +0000154#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
155 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
156 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000157
Eilon Greenstein589abe32009-02-12 08:36:55 +0000158#define SFP_EEPROM_OPTIONS_ADDR 0x40
159 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
160#define SFP_EEPROM_OPTIONS_SIZE 2
161
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000162#define EDC_MODE_LINEAR 0x0022
163#define EDC_MODE_LIMITING 0x0044
164#define EDC_MODE_PASSIVE_DAC 0x0055
Eilon Greenstein589abe32009-02-12 08:36:55 +0000165
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000166
167
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700168/**********************************************************/
169/* INTERFACE */
170/**********************************************************/
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000171
172#define CL45_WR_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
173 bnx2x_cl45_write(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000174 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700175 (_bank + (_addr & 0xf)), \
176 _val)
177
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000178#define CL45_RD_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
179 bnx2x_cl45_read(_bp, _phy, \
Yaniv Rosner7aa07112010-09-07 11:41:01 +0000180 (_phy)->def_md_devad, \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700181 (_bank + (_addr & 0xf)), \
182 _val)
183
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700184static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
185{
186 u32 val = REG_RD(bp, reg);
187
188 val |= bits;
189 REG_WR(bp, reg, val);
190 return val;
191}
192
193static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
194{
195 u32 val = REG_RD(bp, reg);
196
197 val &= ~bits;
198 REG_WR(bp, reg, val);
199 return val;
200}
201
202static void bnx2x_emac_init(struct link_params *params,
203 struct link_vars *vars)
204{
205 /* reset and unreset the emac core */
206 struct bnx2x *bp = params->bp;
207 u8 port = params->port;
208 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
209 u32 val;
210 u16 timeout;
211
212 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
213 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
214 udelay(5);
215 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
216 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
217
218 /* init emac - use read-modify-write */
219 /* self clear reset */
220 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700221 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700222
223 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700224 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700225 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
226 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
227 if (!timeout) {
228 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
229 return;
230 }
231 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700232 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700233
234 /* Set mac address */
235 val = ((params->mac_addr[0] << 8) |
236 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700237 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700238
239 val = ((params->mac_addr[2] << 24) |
240 (params->mac_addr[3] << 16) |
241 (params->mac_addr[4] << 8) |
242 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700243 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700244}
245
246static u8 bnx2x_emac_enable(struct link_params *params,
247 struct link_vars *vars, u8 lb)
248{
249 struct bnx2x *bp = params->bp;
250 u8 port = params->port;
251 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
252 u32 val;
253
254 DP(NETIF_MSG_LINK, "enabling EMAC\n");
255
256 /* enable emac and not bmac */
257 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
258
259 /* for paladium */
260 if (CHIP_REV_IS_EMUL(bp)) {
261 /* Use lane 1 (of lanes 0-3) */
262 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
263 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
264 port*4, 1);
265 }
266 /* for fpga */
267 else
268
269 if (CHIP_REV_IS_FPGA(bp)) {
270 /* Use lane 1 (of lanes 0-3) */
271 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
272
273 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
274 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
275 0);
276 } else
277 /* ASIC */
278 if (vars->phy_flags & PHY_XGXS_FLAG) {
279 u32 ser_lane = ((params->lane_config &
280 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
281 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
282
283 DP(NETIF_MSG_LINK, "XGXS\n");
284 /* select the master lanes (out of 0-3) */
285 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
286 port*4, ser_lane);
287 /* select XGXS */
288 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
289 port*4, 1);
290
291 } else { /* SerDes */
292 DP(NETIF_MSG_LINK, "SerDes\n");
293 /* select SerDes */
294 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
295 port*4, 0);
296 }
297
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000298 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
299 EMAC_RX_MODE_RESET);
300 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
301 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700302
303 if (CHIP_REV_IS_SLOW(bp)) {
304 /* config GMII mode */
305 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700306 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700307 (val | EMAC_MODE_PORT_GMII));
308 } else { /* ASIC */
309 /* pause enable/disable */
310 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
311 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800312 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700313 bnx2x_bits_en(bp, emac_base +
314 EMAC_REG_EMAC_RX_MODE,
315 EMAC_RX_MODE_FLOW_EN);
316
317 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700318 (EMAC_TX_MODE_EXT_PAUSE_EN |
319 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800320 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700321 bnx2x_bits_en(bp, emac_base +
322 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700323 (EMAC_TX_MODE_EXT_PAUSE_EN |
324 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700325 }
326
327 /* KEEP_VLAN_TAG, promiscuous */
328 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
329 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700330 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700331
332 /* Set Loopback */
333 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
334 if (lb)
335 val |= 0x810;
336 else
337 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700338 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700339
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000340 /* enable emac */
341 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
342
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700343 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700344 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700345 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
346 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
347
348 /* strip CRC */
349 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
350
351 /* disable the NIG in/out to the bmac */
352 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
353 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
354 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
355
356 /* enable the NIG in/out to the emac */
357 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
358 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800359 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700360 val = 1;
361
362 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
363 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
364
365 if (CHIP_REV_IS_EMUL(bp)) {
366 /* take the BigMac out of reset */
367 REG_WR(bp,
368 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
369 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
370
371 /* enable access for bmac registers */
372 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
Eilon Greenstein6f654972009-08-12 08:23:51 +0000373 } else
374 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700375
376 vars->mac_type = MAC_TYPE_EMAC;
377 return 0;
378}
379
380
381
382static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
383 u8 is_lb)
384{
385 struct bnx2x *bp = params->bp;
386 u8 port = params->port;
387 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
388 NIG_REG_INGRESS_BMAC0_MEM;
389 u32 wb_data[2];
390 u32 val;
391
392 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
393 /* reset and unreset the BigMac */
394 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
395 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
396 msleep(1);
397
398 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
399 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
400
401 /* enable access for bmac registers */
402 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
403
404 /* XGXS control */
405 wb_data[0] = 0x3c;
406 wb_data[1] = 0;
407 REG_WR_DMAE(bp, bmac_addr +
408 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
409 wb_data, 2);
410
411 /* tx MAC SA */
412 wb_data[0] = ((params->mac_addr[2] << 24) |
413 (params->mac_addr[3] << 16) |
414 (params->mac_addr[4] << 8) |
415 params->mac_addr[5]);
416 wb_data[1] = ((params->mac_addr[0] << 8) |
417 params->mac_addr[1]);
418 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
419 wb_data, 2);
420
421 /* tx control */
422 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800423 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700424 val |= 0x800000;
425 wb_data[0] = val;
426 wb_data[1] = 0;
427 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
428 wb_data, 2);
429
430 /* mac control */
431 val = 0x3;
432 if (is_lb) {
433 val |= 0x4;
434 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
435 }
436 wb_data[0] = val;
437 wb_data[1] = 0;
438 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
439 wb_data, 2);
440
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700441 /* set rx mtu */
442 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
443 wb_data[1] = 0;
444 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
445 wb_data, 2);
446
447 /* rx control set to don't strip crc */
448 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800449 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700450 val |= 0x20;
451 wb_data[0] = val;
452 wb_data[1] = 0;
453 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
454 wb_data, 2);
455
456 /* set tx mtu */
457 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
458 wb_data[1] = 0;
459 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
460 wb_data, 2);
461
462 /* set cnt max size */
463 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
464 wb_data[1] = 0;
465 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
466 wb_data, 2);
467
468 /* configure safc */
469 wb_data[0] = 0x1000200;
470 wb_data[1] = 0;
471 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
472 wb_data, 2);
473 /* fix for emulation */
474 if (CHIP_REV_IS_EMUL(bp)) {
475 wb_data[0] = 0xf000;
476 wb_data[1] = 0;
477 REG_WR_DMAE(bp,
478 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
479 wb_data, 2);
480 }
481
482 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
483 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
484 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
485 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800486 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700487 val = 1;
488 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
489 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
490 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
491 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
492 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
493 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
494
495 vars->mac_type = MAC_TYPE_BMAC;
496 return 0;
497}
498
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700499
500static void bnx2x_update_mng(struct link_params *params, u32 link_status)
501{
502 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000503
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700504 REG_WR(bp, params->shmem_base +
505 offsetof(struct shmem_region,
506 port_mb[params->port].link_status),
507 link_status);
508}
509
510static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
511{
512 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
513 NIG_REG_INGRESS_BMAC0_MEM;
514 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700515 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700516
517 /* Only if the bmac is out of reset */
518 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
519 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
520 nig_bmac_enable) {
521
522 /* Clear Rx Enable bit in BMAC_CONTROL register */
523 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
524 wb_data, 2);
525 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
526 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
527 wb_data, 2);
528
529 msleep(1);
530 }
531}
532
533static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
534 u32 line_speed)
535{
536 struct bnx2x *bp = params->bp;
537 u8 port = params->port;
538 u32 init_crd, crd;
539 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700540
541 /* disable port */
542 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
543
544 /* wait for init credit */
545 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
546 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
547 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
548
549 while ((init_crd != crd) && count) {
550 msleep(5);
551
552 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
553 count--;
554 }
555 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
556 if (init_crd != crd) {
557 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
558 init_crd, crd);
559 return -EINVAL;
560 }
561
David S. Millerc0700f92008-12-16 23:53:20 -0800562 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700563 line_speed == SPEED_10 ||
564 line_speed == SPEED_100 ||
565 line_speed == SPEED_1000 ||
566 line_speed == SPEED_2500) {
567 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700568 /* update threshold */
569 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
570 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700571 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700572
573 } else {
574 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
575 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700576 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700577 /* update threshold */
578 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
579 /* update init credit */
580 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700581 case SPEED_10000:
582 init_crd = thresh + 553 - 22;
583 break;
584
585 case SPEED_12000:
586 init_crd = thresh + 664 - 22;
587 break;
588
589 case SPEED_13000:
590 init_crd = thresh + 742 - 22;
591 break;
592
593 case SPEED_16000:
594 init_crd = thresh + 778 - 22;
595 break;
596 default:
597 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
598 line_speed);
599 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700600 }
601 }
602 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
603 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
604 line_speed, init_crd);
605
606 /* probe the credit changes */
607 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
608 msleep(5);
609 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
610
611 /* enable port */
612 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
613 return 0;
614}
615
Yaniv Rosnerc18aa152010-09-07 11:41:07 +0000616static u32 bnx2x_get_emac_base(struct bnx2x *bp,
617 u32 mdc_mdio_access, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700618{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +0000619 u32 emac_base = 0;
620 switch (mdc_mdio_access) {
621 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
622 break;
623 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
624 if (REG_RD(bp, NIG_REG_PORT_SWAP))
625 emac_base = GRCBASE_EMAC1;
626 else
627 emac_base = GRCBASE_EMAC0;
628 break;
629 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000630 if (REG_RD(bp, NIG_REG_PORT_SWAP))
631 emac_base = GRCBASE_EMAC0;
632 else
633 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700634 break;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +0000635 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
636 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
637 break;
638 case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700639 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700640 break;
641 default:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700642 break;
643 }
644 return emac_base;
645
646}
647
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000648u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
649 u8 devad, u16 reg, u16 val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700650{
651 u32 tmp, saved_mode;
652 u8 i, rc = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700653
654 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
655 * (a value of 49==0x31) and make sure that the AUTO poll is off
656 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000657
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000658 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700659 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
660 EMAC_MDIO_MODE_CLOCK_CNT);
661 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
662 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000663 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
664 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700665 udelay(40);
666
667 /* address */
668
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000669 tmp = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700670 EMAC_MDIO_COMM_COMMAND_ADDRESS |
671 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000672 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700673
674 for (i = 0; i < 50; i++) {
675 udelay(10);
676
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000677 tmp = REG_RD(bp, phy->mdio_ctrl +
678 EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700679 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
680 udelay(5);
681 break;
682 }
683 }
684 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
685 DP(NETIF_MSG_LINK, "write phy register failed\n");
686 rc = -EFAULT;
687 } else {
688 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000689 tmp = ((phy->addr << 21) | (devad << 16) | val |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700690 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
691 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000692 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700693
694 for (i = 0; i < 50; i++) {
695 udelay(10);
696
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000697 tmp = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700698 EMAC_REG_EMAC_MDIO_COMM);
699 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
700 udelay(5);
701 break;
702 }
703 }
704 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
705 DP(NETIF_MSG_LINK, "write phy register failed\n");
706 rc = -EFAULT;
707 }
708 }
709
710 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000711 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700712
713 return rc;
714}
715
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000716u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
717 u8 devad, u16 reg, u16 *ret_val)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700718{
719 u32 val, saved_mode;
720 u16 i;
721 u8 rc = 0;
722
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700723 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
724 * (a value of 49==0x31) and make sure that the AUTO poll is off
725 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000726
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000727 saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
728 val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700729 EMAC_MDIO_MODE_CLOCK_CNT));
730 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000731 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000732 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
733 REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700734 udelay(40);
735
736 /* address */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000737 val = ((phy->addr << 21) | (devad << 16) | reg |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700738 EMAC_MDIO_COMM_COMMAND_ADDRESS |
739 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000740 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700741
742 for (i = 0; i < 50; i++) {
743 udelay(10);
744
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000745 val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700746 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
747 udelay(5);
748 break;
749 }
750 }
751 if (val & EMAC_MDIO_COMM_START_BUSY) {
752 DP(NETIF_MSG_LINK, "read phy register failed\n");
753
754 *ret_val = 0;
755 rc = -EFAULT;
756
757 } else {
758 /* data */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000759 val = ((phy->addr << 21) | (devad << 16) |
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700760 EMAC_MDIO_COMM_COMMAND_READ_45 |
761 EMAC_MDIO_COMM_START_BUSY);
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000762 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700763
764 for (i = 0; i < 50; i++) {
765 udelay(10);
766
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000767 val = REG_RD(bp, phy->mdio_ctrl +
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700768 EMAC_REG_EMAC_MDIO_COMM);
769 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
770 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
771 break;
772 }
773 }
774 if (val & EMAC_MDIO_COMM_START_BUSY) {
775 DP(NETIF_MSG_LINK, "read phy register failed\n");
776
777 *ret_val = 0;
778 rc = -EFAULT;
779 }
780 }
781
782 /* Restore the saved mode */
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000783 REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700784
785 return rc;
786}
787
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000788u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
789 u8 devad, u16 reg, u16 *ret_val)
790{
791 u8 phy_index;
792 /**
793 * Probe for the phy according to the given phy_addr, and execute
794 * the read request on it
795 */
796 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
797 if (params->phy[phy_index].addr == phy_addr) {
798 return bnx2x_cl45_read(params->bp,
799 &params->phy[phy_index], devad,
800 reg, ret_val);
801 }
802 }
803 return -EINVAL;
804}
805
806u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
807 u8 devad, u16 reg, u16 val)
808{
809 u8 phy_index;
810 /**
811 * Probe for the phy according to the given phy_addr, and execute
812 * the write request on it
813 */
814 for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
815 if (params->phy[phy_index].addr == phy_addr) {
816 return bnx2x_cl45_write(params->bp,
817 &params->phy[phy_index], devad,
818 reg, val);
819 }
820 }
821 return -EINVAL;
822}
823
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700824static void bnx2x_set_aer_mmd(struct link_params *params,
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000825 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700826{
827 struct bnx2x *bp = params->bp;
828 u32 ser_lane;
829 u16 offset;
830
831 ser_lane = ((params->lane_config &
832 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
833 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
834
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000835 offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
836 (phy->addr + ser_lane) : 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700837
Yaniv Rosnere10bc842010-09-07 11:40:50 +0000838 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700839 MDIO_REG_BANK_AER_BLOCK,
840 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
841}
842
Yaniv Rosnerde6eae12010-09-07 11:41:13 +0000843/******************************************************************/
844/* Internal phy section */
845/******************************************************************/
846
847static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
848{
849 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
850
851 /* Set Clause 22 */
852 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
853 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
854 udelay(500);
855 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
856 udelay(500);
857 /* Set Clause 45 */
858 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
859}
860
861static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
862{
863 u32 val;
864
865 DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
866
867 val = SERDES_RESET_BITS << (port*16);
868
869 /* reset and unreset the SerDes/XGXS */
870 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
871 udelay(500);
872 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
873
874 bnx2x_set_serdes_access(bp, port);
875
876 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
877 port*0x10,
878 DEFAULT_PHY_DEV_ADDR);
879}
880
881static void bnx2x_xgxs_deassert(struct link_params *params)
882{
883 struct bnx2x *bp = params->bp;
884 u8 port;
885 u32 val;
886 DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
887 port = params->port;
888
889 val = XGXS_RESET_BITS << (port*16);
890
891 /* reset and unreset the SerDes/XGXS */
892 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
893 udelay(500);
894 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
895
896 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
897 port*0x18, 0);
898 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
899 params->phy[INT_PHY].def_md_devad);
900}
901
Yaniv Rosnera22f0782010-09-07 11:41:20 +0000902
Yaniv Rosnerde6eae12010-09-07 11:41:13 +0000903void bnx2x_link_status_update(struct link_params *params,
904 struct link_vars *vars)
905{
906 struct bnx2x *bp = params->bp;
907 u8 link_10g;
908 u8 port = params->port;
909
Yaniv Rosnerde6eae12010-09-07 11:41:13 +0000910 vars->link_status = REG_RD(bp, params->shmem_base +
911 offsetof(struct shmem_region,
912 port_mb[port].link_status));
913
914 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
915
916 if (vars->link_up) {
917 DP(NETIF_MSG_LINK, "phy link up\n");
918
919 vars->phy_link_up = 1;
920 vars->duplex = DUPLEX_FULL;
921 switch (vars->link_status &
922 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
923 case LINK_10THD:
924 vars->duplex = DUPLEX_HALF;
925 /* fall thru */
926 case LINK_10TFD:
927 vars->line_speed = SPEED_10;
928 break;
929
930 case LINK_100TXHD:
931 vars->duplex = DUPLEX_HALF;
932 /* fall thru */
933 case LINK_100T4:
934 case LINK_100TXFD:
935 vars->line_speed = SPEED_100;
936 break;
937
938 case LINK_1000THD:
939 vars->duplex = DUPLEX_HALF;
940 /* fall thru */
941 case LINK_1000TFD:
942 vars->line_speed = SPEED_1000;
943 break;
944
945 case LINK_2500THD:
946 vars->duplex = DUPLEX_HALF;
947 /* fall thru */
948 case LINK_2500TFD:
949 vars->line_speed = SPEED_2500;
950 break;
951
952 case LINK_10GTFD:
953 vars->line_speed = SPEED_10000;
954 break;
955
956 case LINK_12GTFD:
957 vars->line_speed = SPEED_12000;
958 break;
959
960 case LINK_12_5GTFD:
961 vars->line_speed = SPEED_12500;
962 break;
963
964 case LINK_13GTFD:
965 vars->line_speed = SPEED_13000;
966 break;
967
968 case LINK_15GTFD:
969 vars->line_speed = SPEED_15000;
970 break;
971
972 case LINK_16GTFD:
973 vars->line_speed = SPEED_16000;
974 break;
975
976 default:
977 break;
978 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +0000979 vars->flow_ctrl = 0;
980 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
981 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
982
983 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
984 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
985
986 if (!vars->flow_ctrl)
987 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
988
989 if (vars->line_speed &&
990 ((vars->line_speed == SPEED_10) ||
991 (vars->line_speed == SPEED_100))) {
992 vars->phy_flags |= PHY_SGMII_FLAG;
993 } else {
994 vars->phy_flags &= ~PHY_SGMII_FLAG;
995 }
996
997 /* anything 10 and over uses the bmac */
998 link_10g = ((vars->line_speed == SPEED_10000) ||
999 (vars->line_speed == SPEED_12000) ||
1000 (vars->line_speed == SPEED_12500) ||
1001 (vars->line_speed == SPEED_13000) ||
1002 (vars->line_speed == SPEED_15000) ||
1003 (vars->line_speed == SPEED_16000));
1004 if (link_10g)
1005 vars->mac_type = MAC_TYPE_BMAC;
1006 else
1007 vars->mac_type = MAC_TYPE_EMAC;
1008
1009 } else { /* link down */
1010 DP(NETIF_MSG_LINK, "phy link down\n");
1011
1012 vars->phy_link_up = 0;
1013
1014 vars->line_speed = 0;
1015 vars->duplex = DUPLEX_FULL;
1016 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
1017
1018 /* indicate no mac active */
1019 vars->mac_type = MAC_TYPE_NONE;
1020 }
1021
1022 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
1023 vars->link_status, vars->phy_link_up);
1024 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
1025 vars->line_speed, vars->duplex, vars->flow_ctrl);
1026}
1027
1028
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001029static void bnx2x_set_master_ln(struct link_params *params,
1030 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001031{
1032 struct bnx2x *bp = params->bp;
1033 u16 new_master_ln, ser_lane;
1034 ser_lane = ((params->lane_config &
1035 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1036 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1037
1038 /* set the master_ln for AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001039 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001040 MDIO_REG_BANK_XGXS_BLOCK2,
1041 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1042 &new_master_ln);
1043
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001044 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001045 MDIO_REG_BANK_XGXS_BLOCK2 ,
1046 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1047 (new_master_ln | ser_lane));
1048}
1049
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001050static u8 bnx2x_reset_unicore(struct link_params *params,
1051 struct bnx2x_phy *phy,
1052 u8 set_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001053{
1054 struct bnx2x *bp = params->bp;
1055 u16 mii_control;
1056 u16 i;
1057
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001058 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001059 MDIO_REG_BANK_COMBO_IEEE0,
1060 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1061
1062 /* reset the unicore */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001063 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001064 MDIO_REG_BANK_COMBO_IEEE0,
1065 MDIO_COMBO_IEEE0_MII_CONTROL,
1066 (mii_control |
1067 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001068 if (set_serdes)
1069 bnx2x_set_serdes_access(bp, params->port);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001070
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001071 /* wait for the reset to self clear */
1072 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1073 udelay(5);
1074
1075 /* the reset erased the previous bank value */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001076 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001077 MDIO_REG_BANK_COMBO_IEEE0,
1078 MDIO_COMBO_IEEE0_MII_CONTROL,
1079 &mii_control);
1080
1081 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1082 udelay(5);
1083 return 0;
1084 }
1085 }
1086
1087 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1088 return -EINVAL;
1089
1090}
1091
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001092static void bnx2x_set_swap_lanes(struct link_params *params,
1093 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001094{
1095 struct bnx2x *bp = params->bp;
1096 /* Each two bits represents a lane number:
1097 No swap is 0123 => 0x1b no need to enable the swap */
1098 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1099
1100 ser_lane = ((params->lane_config &
1101 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1102 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1103 rx_lane_swap = ((params->lane_config &
1104 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1105 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1106 tx_lane_swap = ((params->lane_config &
1107 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1108 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1109
1110 if (rx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001111 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001112 MDIO_REG_BANK_XGXS_BLOCK2,
1113 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1114 (rx_lane_swap |
1115 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1116 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1117 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001118 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001119 MDIO_REG_BANK_XGXS_BLOCK2,
1120 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1121 }
1122
1123 if (tx_lane_swap != 0x1b) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001124 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001125 MDIO_REG_BANK_XGXS_BLOCK2,
1126 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1127 (tx_lane_swap |
1128 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1129 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001130 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001131 MDIO_REG_BANK_XGXS_BLOCK2,
1132 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1133 }
1134}
1135
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001136static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
1137 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001138{
1139 struct bnx2x *bp = params->bp;
1140 u16 control2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001141 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001142 MDIO_REG_BANK_SERDES_DIGITAL,
1143 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1144 &control2);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001145 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001146 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1147 else
1148 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001149 DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1150 phy->speed_cap_mask, control2);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001151 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001152 MDIO_REG_BANK_SERDES_DIGITAL,
1153 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1154 control2);
1155
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001156 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001157 (phy->speed_cap_mask &
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001158 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001159 DP(NETIF_MSG_LINK, "XGXS\n");
1160
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001161 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001162 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1163 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1164 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1165
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001166 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001167 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1168 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1169 &control2);
1170
1171
1172 control2 |=
1173 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1174
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001175 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001176 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1177 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1178 control2);
1179
1180 /* Disable parallel detection of HiG */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001181 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001182 MDIO_REG_BANK_XGXS_BLOCK2,
1183 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1184 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1185 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1186 }
1187}
1188
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001189static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
1190 struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001191 struct link_vars *vars,
1192 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001193{
1194 struct bnx2x *bp = params->bp;
1195 u16 reg_val;
1196
1197 /* CL37 Autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001198 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001199 MDIO_REG_BANK_COMBO_IEEE0,
1200 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1201
1202 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001203 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001204 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1205 else /* CL37 Autoneg Disabled */
1206 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1207 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1208
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001209 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001210 MDIO_REG_BANK_COMBO_IEEE0,
1211 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1212
1213 /* Enable/Disable Autodetection */
1214
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001215 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001216 MDIO_REG_BANK_SERDES_DIGITAL,
1217 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001218 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1219 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1220 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001221 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001222 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1223 else
1224 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1225
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001226 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001227 MDIO_REG_BANK_SERDES_DIGITAL,
1228 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1229
1230 /* Enable TetonII and BAM autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001231 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001232 MDIO_REG_BANK_BAM_NEXT_PAGE,
1233 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1234 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001235 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001236 /* Enable BAM aneg Mode and TetonII aneg Mode */
1237 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1238 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1239 } else {
1240 /* TetonII and BAM Autoneg Disabled */
1241 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1242 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1243 }
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001244 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001245 MDIO_REG_BANK_BAM_NEXT_PAGE,
1246 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1247 reg_val);
1248
Eilon Greenstein239d6862009-08-12 08:23:04 +00001249 if (enable_cl73) {
1250 /* Enable Cl73 FSM status bits */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001251 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001252 MDIO_REG_BANK_CL73_USERB0,
1253 MDIO_CL73_USERB0_CL73_UCTRL,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001254 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001255
1256 /* Enable BAM Station Manager*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001257 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001258 MDIO_REG_BANK_CL73_USERB0,
1259 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1260 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1261 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1262 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
1263
Yaniv Rosner7846e472009-11-05 19:18:07 +02001264 /* Advertise CL73 link speeds */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001265 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001266 MDIO_REG_BANK_CL73_IEEEB1,
1267 MDIO_CL73_IEEEB1_AN_ADV2,
1268 &reg_val);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001269 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02001270 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1271 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001272 if (phy->speed_cap_mask &
Yaniv Rosner7846e472009-11-05 19:18:07 +02001273 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1274 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001275
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001276 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001277 MDIO_REG_BANK_CL73_IEEEB1,
1278 MDIO_CL73_IEEEB1_AN_ADV2,
1279 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001280
Eilon Greenstein239d6862009-08-12 08:23:04 +00001281 /* CL73 Autoneg Enabled */
1282 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1283
1284 } else /* CL73 Autoneg Disabled */
1285 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001286
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001287 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001288 MDIO_REG_BANK_CL73_IEEEB0,
1289 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1290}
1291
1292/* program SerDes, forced speed */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001293static void bnx2x_program_serdes(struct bnx2x_phy *phy,
1294 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001295 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001296{
1297 struct bnx2x *bp = params->bp;
1298 u16 reg_val;
1299
Eilon Greenstein57937202009-08-12 08:23:53 +00001300 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001301 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001302 MDIO_REG_BANK_COMBO_IEEE0,
1303 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1304 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00001305 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1306 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001307 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001308 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001309 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001310 MDIO_REG_BANK_COMBO_IEEE0,
1311 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1312
1313 /* program speed
1314 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001315 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001316 MDIO_REG_BANK_SERDES_DIGITAL,
1317 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001318 /* clearing the speed value before setting the right speed */
1319 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1320
1321 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1322 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1323
1324 if (!((vars->line_speed == SPEED_1000) ||
1325 (vars->line_speed == SPEED_100) ||
1326 (vars->line_speed == SPEED_10))) {
1327
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001328 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1329 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001330 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001331 reg_val |=
1332 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001333 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001334 reg_val |=
1335 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001336 }
1337
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001338 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001339 MDIO_REG_BANK_SERDES_DIGITAL,
1340 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001341
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001342}
1343
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001344static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
1345 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001346{
1347 struct bnx2x *bp = params->bp;
1348 u16 val = 0;
1349
1350 /* configure the 48 bits for BAM AN */
1351
1352 /* set extended capabilities */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001353 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001354 val |= MDIO_OVER_1G_UP1_2_5G;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001355 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001356 val |= MDIO_OVER_1G_UP1_10G;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001357 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001358 MDIO_REG_BANK_OVER_1G,
1359 MDIO_OVER_1G_UP1, val);
1360
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001361 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001362 MDIO_REG_BANK_OVER_1G,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001363 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001364}
1365
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001366static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
1367 struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001368{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001369 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001370 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001371 /* resolve pause mode and advertisement
1372 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1373
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001374 switch (phy->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001375 case BNX2X_FLOW_CTRL_AUTO:
1376 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001377 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001378 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1379 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001380 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001381 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1382 }
1383 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001384 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001385 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001386 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1387 break;
1388
David S. Millerc0700f92008-12-16 23:53:20 -08001389 case BNX2X_FLOW_CTRL_RX:
1390 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001391 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001392 break;
1393
David S. Millerc0700f92008-12-16 23:53:20 -08001394 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001395 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001396 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001397 break;
1398 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001399 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001400}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001401
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001402static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
1403 struct link_params *params,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001404 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001405{
1406 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001407 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001408 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001409
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001410 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001411 MDIO_REG_BANK_COMBO_IEEE0,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001412 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001413 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001414 MDIO_REG_BANK_CL73_IEEEB1,
1415 MDIO_CL73_IEEEB1_AN_ADV1, &val);
1416 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
1417 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001418 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001419 MDIO_REG_BANK_CL73_IEEEB1,
1420 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001421}
1422
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001423static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
1424 struct link_params *params,
1425 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001426{
1427 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001428 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001429
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001430 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001431 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001432
Eilon Greenstein239d6862009-08-12 08:23:04 +00001433 if (enable_cl73) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001434 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001435 MDIO_REG_BANK_CL73_IEEEB0,
1436 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1437 &mii_control);
1438
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001439 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001440 MDIO_REG_BANK_CL73_IEEEB0,
1441 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1442 (mii_control |
1443 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1444 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1445 } else {
1446
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001447 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001448 MDIO_REG_BANK_COMBO_IEEE0,
1449 MDIO_COMBO_IEEE0_MII_CONTROL,
1450 &mii_control);
1451 DP(NETIF_MSG_LINK,
1452 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1453 mii_control);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001454 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001455 MDIO_REG_BANK_COMBO_IEEE0,
1456 MDIO_COMBO_IEEE0_MII_CONTROL,
1457 (mii_control |
1458 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1459 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1460 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001461}
1462
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001463static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
1464 struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001465 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001466{
1467 struct bnx2x *bp = params->bp;
1468 u16 control1;
1469
1470 /* in SGMII mode, the unicore is always slave */
1471
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001472 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001473 MDIO_REG_BANK_SERDES_DIGITAL,
1474 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1475 &control1);
1476 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1477 /* set sgmii mode (and not fiber) */
1478 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1479 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1480 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001481 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001482 MDIO_REG_BANK_SERDES_DIGITAL,
1483 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1484 control1);
1485
1486 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001487 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001488 /* set speed, disable autoneg */
1489 u16 mii_control;
1490
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001491 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001492 MDIO_REG_BANK_COMBO_IEEE0,
1493 MDIO_COMBO_IEEE0_MII_CONTROL,
1494 &mii_control);
1495 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1496 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1497 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1498
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001499 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001500 case SPEED_100:
1501 mii_control |=
1502 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1503 break;
1504 case SPEED_1000:
1505 mii_control |=
1506 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1507 break;
1508 case SPEED_10:
1509 /* there is nothing to set for 10M */
1510 break;
1511 default:
1512 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001513 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1514 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001515 break;
1516 }
1517
1518 /* setting the full duplex */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001519 if (phy->req_duplex == DUPLEX_FULL)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001520 mii_control |=
1521 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001522 CL45_WR_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001523 MDIO_REG_BANK_COMBO_IEEE0,
1524 MDIO_COMBO_IEEE0_MII_CONTROL,
1525 mii_control);
1526
1527 } else { /* AN mode */
1528 /* enable and restart AN */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001529 bnx2x_restart_autoneg(phy, params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001530 }
1531}
1532
1533
1534/*
1535 * link management
1536 */
1537
1538static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001539{ /* LD LP */
1540 switch (pause_result) { /* ASYM P ASYM P */
1541 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001542 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001543 break;
1544
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001545 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001546 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001547 break;
1548
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001549 case 0x5: /* 0 1 0 1 */
1550 case 0x7: /* 0 1 1 1 */
1551 case 0xd: /* 1 1 0 1 */
1552 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001553 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001554 break;
1555
1556 default:
1557 break;
1558 }
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001559 if (pause_result & (1<<0))
1560 vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
1561 if (pause_result & (1<<1))
1562 vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001563}
1564
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001565static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
1566 struct link_params *params)
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001567{
1568 struct bnx2x *bp = params->bp;
1569 u16 pd_10g, status2_1000x;
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001570 if (phy->req_line_speed != SPEED_AUTO_NEG)
1571 return 0;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001572 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001573 MDIO_REG_BANK_SERDES_DIGITAL,
1574 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1575 &status2_1000x);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001576 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001577 MDIO_REG_BANK_SERDES_DIGITAL,
1578 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1579 &status2_1000x);
1580 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
1581 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
1582 params->port);
1583 return 1;
1584 }
1585
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001586 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001587 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1588 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
1589 &pd_10g);
1590
1591 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
1592 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
1593 params->port);
1594 return 1;
1595 }
1596 return 0;
1597}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001598
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001599static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
1600 struct link_params *params,
1601 struct link_vars *vars,
1602 u32 gp_status)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001603{
1604 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001605 u16 ld_pause; /* local driver */
1606 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001607 u16 pause_result;
1608
David S. Millerc0700f92008-12-16 23:53:20 -08001609 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001610
1611 /* resolve from gp_status in case of AN complete and not sgmii */
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001612 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
1613 vars->flow_ctrl = phy->req_flow_ctrl;
1614 else if (phy->req_line_speed != SPEED_AUTO_NEG)
1615 vars->flow_ctrl = params->req_fc_auto_adv;
1616 else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1617 (!(vars->phy_flags & PHY_SGMII_FLAG))) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001618 if (bnx2x_direct_parallel_detect_used(phy, params)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001619 vars->flow_ctrl = params->req_fc_auto_adv;
1620 return;
1621 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02001622 if ((gp_status &
1623 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1624 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
1625 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1626 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
1627
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001628 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001629 MDIO_REG_BANK_CL73_IEEEB1,
1630 MDIO_CL73_IEEEB1_AN_ADV1,
1631 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001632 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001633 MDIO_REG_BANK_CL73_IEEEB1,
1634 MDIO_CL73_IEEEB1_AN_LP_ADV1,
1635 &lp_pause);
1636 pause_result = (ld_pause &
1637 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
1638 >> 8;
1639 pause_result |= (lp_pause &
1640 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
1641 >> 10;
1642 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
1643 pause_result);
1644 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001645 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001646 MDIO_REG_BANK_COMBO_IEEE0,
1647 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1648 &ld_pause);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001649 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001650 MDIO_REG_BANK_COMBO_IEEE0,
1651 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1652 &lp_pause);
1653 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001654 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001655 pause_result |= (lp_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001656 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001657 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
1658 pause_result);
1659 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001660 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001661 }
1662 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1663}
1664
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001665static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
1666 struct link_params *params)
Eilon Greenstein239d6862009-08-12 08:23:04 +00001667{
1668 struct bnx2x *bp = params->bp;
1669 u16 rx_status, ustat_val, cl37_fsm_recieved;
1670 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
1671 /* Step 1: Make sure signal is detected */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001672 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001673 MDIO_REG_BANK_RX0,
1674 MDIO_RX0_RX_STATUS,
1675 &rx_status);
1676 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
1677 (MDIO_RX0_RX_STATUS_SIGDET)) {
1678 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
1679 "rx_status(0x80b0) = 0x%x\n", rx_status);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001680 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001681 MDIO_REG_BANK_CL73_IEEEB0,
1682 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1683 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
1684 return;
1685 }
1686 /* Step 2: Check CL73 state machine */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001687 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001688 MDIO_REG_BANK_CL73_USERB0,
1689 MDIO_CL73_USERB0_CL73_USTAT1,
1690 &ustat_val);
1691 if ((ustat_val &
1692 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1693 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
1694 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1695 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
1696 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
1697 "ustat_val(0x8371) = 0x%x\n", ustat_val);
1698 return;
1699 }
1700 /* Step 3: Check CL37 Message Pages received to indicate LP
1701 supports only CL37 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001702 CL45_RD_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001703 MDIO_REG_BANK_REMOTE_PHY,
1704 MDIO_REMOTE_PHY_MISC_RX_STATUS,
1705 &cl37_fsm_recieved);
1706 if ((cl37_fsm_recieved &
1707 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1708 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
1709 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1710 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
1711 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
1712 "misc_rx_status(0x8330) = 0x%x\n",
1713 cl37_fsm_recieved);
1714 return;
1715 }
1716 /* The combined cl37/cl73 fsm state information indicating that we are
1717 connected to a device which does not support cl73, but does support
1718 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
1719 /* Disable CL73 */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001720 CL45_WR_OVER_CL22(bp, phy,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001721 MDIO_REG_BANK_CL73_IEEEB0,
1722 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1723 0);
1724 /* Restart CL37 autoneg */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001725 bnx2x_restart_autoneg(phy, params, 0);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001726 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
1727}
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001728
1729static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
1730 struct link_params *params,
1731 struct link_vars *vars,
1732 u32 gp_status)
1733{
1734 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
1735 vars->link_status |=
1736 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1737
1738 if (bnx2x_direct_parallel_detect_used(phy, params))
1739 vars->link_status |=
1740 LINK_STATUS_PARALLEL_DETECTION_USED;
1741}
1742
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001743static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
1744 struct link_params *params,
1745 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001746{
1747 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001748 u16 new_line_speed , gp_status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001749 u8 rc = 0;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001750
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001751 /* Read gp_status */
1752 CL45_RD_OVER_CL22(bp, phy,
1753 MDIO_REG_BANK_GP_STATUS,
1754 MDIO_GP_STATUS_TOP_AN_STATUS1,
1755 &gp_status);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00001756
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001757 if (phy->req_line_speed == SPEED_AUTO_NEG)
1758 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001759 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1760 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1761 gp_status);
1762
1763 vars->phy_link_up = 1;
1764 vars->link_status |= LINK_STATUS_LINK_UP;
1765
1766 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1767 vars->duplex = DUPLEX_FULL;
1768 else
1769 vars->duplex = DUPLEX_HALF;
1770
Yaniv Rosner7aa07112010-09-07 11:41:01 +00001771 if (SINGLE_MEDIA_DIRECT(params)) {
1772 bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
1773 if (phy->req_line_speed == SPEED_AUTO_NEG)
1774 bnx2x_xgxs_an_resolve(phy, params, vars,
1775 gp_status);
1776 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001777
1778 switch (gp_status & GP_STATUS_SPEED_MASK) {
1779 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001780 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001781 if (vars->duplex == DUPLEX_FULL)
1782 vars->link_status |= LINK_10TFD;
1783 else
1784 vars->link_status |= LINK_10THD;
1785 break;
1786
1787 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001788 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001789 if (vars->duplex == DUPLEX_FULL)
1790 vars->link_status |= LINK_100TXFD;
1791 else
1792 vars->link_status |= LINK_100TXHD;
1793 break;
1794
1795 case GP_STATUS_1G:
1796 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001797 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001798 if (vars->duplex == DUPLEX_FULL)
1799 vars->link_status |= LINK_1000TFD;
1800 else
1801 vars->link_status |= LINK_1000THD;
1802 break;
1803
1804 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001805 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001806 if (vars->duplex == DUPLEX_FULL)
1807 vars->link_status |= LINK_2500TFD;
1808 else
1809 vars->link_status |= LINK_2500THD;
1810 break;
1811
1812 case GP_STATUS_5G:
1813 case GP_STATUS_6G:
1814 DP(NETIF_MSG_LINK,
1815 "link speed unsupported gp_status 0x%x\n",
1816 gp_status);
1817 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001818
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001819 case GP_STATUS_10G_KX4:
1820 case GP_STATUS_10G_HIG:
1821 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001822 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001823 vars->link_status |= LINK_10GTFD;
1824 break;
1825
1826 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001827 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001828 vars->link_status |= LINK_12GTFD;
1829 break;
1830
1831 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001832 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001833 vars->link_status |= LINK_12_5GTFD;
1834 break;
1835
1836 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001837 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001838 vars->link_status |= LINK_13GTFD;
1839 break;
1840
1841 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001842 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001843 vars->link_status |= LINK_15GTFD;
1844 break;
1845
1846 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001847 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001848 vars->link_status |= LINK_16GTFD;
1849 break;
1850
1851 default:
1852 DP(NETIF_MSG_LINK,
1853 "link speed unsupported gp_status 0x%x\n",
1854 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001855 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001856 }
1857
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001858 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001859
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001860 } else { /* link_down */
1861 DP(NETIF_MSG_LINK, "phy link down\n");
1862
1863 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001864
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001865 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001866 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001867 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001868
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001869 if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
1870 SINGLE_MEDIA_DIRECT(params)) {
Eilon Greenstein239d6862009-08-12 08:23:04 +00001871 /* Check signal is detected */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00001872 bnx2x_check_fallback_to_cl37(phy, params);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001873 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001874 }
1875
Frans Pop2381a552010-03-24 07:57:36 +00001876 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001877 gp_status, vars->phy_link_up, vars->line_speed);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00001878 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
1879 vars->duplex, vars->flow_ctrl, vars->link_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001880 return rc;
1881}
1882
Eilon Greensteined8680a2009-02-12 08:37:12 +00001883static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001884{
1885 struct bnx2x *bp = params->bp;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001886 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001887 u16 lp_up2;
1888 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001889 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001890
1891 /* read precomp */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001892 CL45_RD_OVER_CL22(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001893 MDIO_REG_BANK_OVER_1G,
1894 MDIO_OVER_1G_LP_UP2, &lp_up2);
1895
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001896 /* bits [10:7] at lp_up2, positioned at [15:12] */
1897 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1898 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1899 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1900
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001901 if (lp_up2 == 0)
1902 return;
1903
1904 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
1905 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001906 CL45_RD_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001907 bank,
1908 MDIO_TX0_TX_DRIVER, &tx_driver);
1909
1910 /* replace tx_driver bits [15:12] */
1911 if (lp_up2 !=
1912 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
1913 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1914 tx_driver |= lp_up2;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00001915 CL45_WR_OVER_CL22(bp, phy,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001916 bank,
1917 MDIO_TX0_TX_DRIVER, tx_driver);
1918 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001919 }
1920}
1921
1922static u8 bnx2x_emac_program(struct link_params *params,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001923 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001924{
1925 struct bnx2x *bp = params->bp;
1926 u8 port = params->port;
1927 u16 mode = 0;
1928
1929 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1930 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1931 EMAC_REG_EMAC_MODE,
1932 (EMAC_MODE_25G_MODE |
1933 EMAC_MODE_PORT_MII_10M |
1934 EMAC_MODE_HALF_DUPLEX));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001935 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001936 case SPEED_10:
1937 mode |= EMAC_MODE_PORT_MII_10M;
1938 break;
1939
1940 case SPEED_100:
1941 mode |= EMAC_MODE_PORT_MII;
1942 break;
1943
1944 case SPEED_1000:
1945 mode |= EMAC_MODE_PORT_GMII;
1946 break;
1947
1948 case SPEED_2500:
1949 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
1950 break;
1951
1952 default:
1953 /* 10G not valid for EMAC */
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001954 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1955 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001956 return -EINVAL;
1957 }
1958
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00001959 if (vars->duplex == DUPLEX_HALF)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001960 mode |= EMAC_MODE_HALF_DUPLEX;
1961 bnx2x_bits_en(bp,
1962 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
1963 mode);
1964
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00001965 bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001966 return 0;
1967}
1968
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00001969static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
1970 struct link_params *params)
1971{
1972
1973 u16 bank, i = 0;
1974 struct bnx2x *bp = params->bp;
1975
1976 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
1977 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
1978 CL45_WR_OVER_CL22(bp, phy,
1979 bank,
1980 MDIO_RX0_RX_EQ_BOOST,
1981 phy->rx_preemphasis[i]);
1982 }
1983
1984 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
1985 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
1986 CL45_WR_OVER_CL22(bp, phy,
1987 bank,
1988 MDIO_TX0_TX_DRIVER,
1989 phy->tx_preemphasis[i]);
1990 }
1991}
1992
1993static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
1994 struct link_params *params,
1995 struct link_vars *vars)
1996{
1997 struct bnx2x *bp = params->bp;
1998 u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
1999 (params->loopback_mode == LOOPBACK_XGXS));
2000 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2001 if (SINGLE_MEDIA_DIRECT(params) &&
2002 (params->feature_config_flags &
2003 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
2004 bnx2x_set_preemphasis(phy, params);
2005
2006 /* forced speed requested? */
2007 if (vars->line_speed != SPEED_AUTO_NEG ||
2008 (SINGLE_MEDIA_DIRECT(params) &&
2009 params->loopback_mode == LOOPBACK_EXT)) {
2010 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2011
2012 /* disable autoneg */
2013 bnx2x_set_autoneg(phy, params, vars, 0);
2014
2015 /* program speed and duplex */
2016 bnx2x_program_serdes(phy, params, vars);
2017
2018 } else { /* AN_mode */
2019 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2020
2021 /* AN enabled */
2022 bnx2x_set_brcm_cl37_advertisment(phy, params);
2023
2024 /* program duplex & pause advertisement (for aneg) */
2025 bnx2x_set_ieee_aneg_advertisment(phy, params,
2026 vars->ieee_fc);
2027
2028 /* enable autoneg */
2029 bnx2x_set_autoneg(phy, params, vars, enable_cl73);
2030
2031 /* enable and restart AN */
2032 bnx2x_restart_autoneg(phy, params, enable_cl73);
2033 }
2034
2035 } else { /* SGMII mode */
2036 DP(NETIF_MSG_LINK, "SGMII\n");
2037
2038 bnx2x_initialize_sgmii_process(phy, params, vars);
2039 }
2040}
2041
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002042static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
2043 struct link_params *params,
2044 struct link_vars *vars)
2045{
2046 u8 rc;
2047 vars->phy_flags |= PHY_SGMII_FLAG;
2048 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
2049 bnx2x_set_aer_mmd(params, phy);
2050 rc = bnx2x_reset_unicore(params, phy, 1);
2051 /* reset the SerDes and wait for reset bit return low */
2052 if (rc != 0)
2053 return rc;
2054 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002055
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002056 return rc;
2057}
2058
2059static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
2060 struct link_params *params,
2061 struct link_vars *vars)
2062{
2063 u8 rc;
2064 vars->phy_flags = PHY_XGXS_FLAG;
2065 if ((phy->req_line_speed &&
2066 ((phy->req_line_speed == SPEED_100) ||
2067 (phy->req_line_speed == SPEED_10))) ||
2068 (!phy->req_line_speed &&
2069 (phy->speed_cap_mask >=
2070 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
2071 (phy->speed_cap_mask <
2072 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
2073 ))
2074 vars->phy_flags |= PHY_SGMII_FLAG;
2075 else
2076 vars->phy_flags &= ~PHY_SGMII_FLAG;
2077
2078 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
2079 bnx2x_set_aer_mmd(params, phy);
2080 bnx2x_set_master_ln(params, phy);
2081
2082 rc = bnx2x_reset_unicore(params, phy, 0);
2083 /* reset the SerDes and wait for reset bit return low */
2084 if (rc != 0)
2085 return rc;
2086
2087 bnx2x_set_aer_mmd(params, phy);
2088
2089 /* setting the masterLn_def again after the reset */
2090 bnx2x_set_master_ln(params, phy);
2091 bnx2x_set_swap_lanes(params, phy);
2092
2093 return rc;
2094}
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002095
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002096static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
2097 struct bnx2x_phy *phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002098{
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002099 u16 cnt, ctrl;
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002100 /* Wait for soft reset to get cleared upto 1 sec */
2101 for (cnt = 0; cnt < 1000; cnt++) {
2102 bnx2x_cl45_read(bp, phy,
2103 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
2104 if (!(ctrl & (1<<15)))
2105 break;
2106 msleep(1);
2107 }
2108 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
2109 return cnt;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002110}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002111
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002112static void bnx2x_link_int_enable(struct link_params *params)
2113{
2114 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002115 u32 mask;
2116 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002117
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002118 /* setting the status to report on link up
2119 for either XGXS or SerDes */
2120
2121 if (params->switch_cfg == SWITCH_CFG_10G) {
2122 mask = (NIG_MASK_XGXS0_LINK10G |
2123 NIG_MASK_XGXS0_LINK_STATUS);
2124 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002125 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2126 params->phy[INT_PHY].type !=
2127 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002128 mask |= NIG_MASK_MI_INT;
2129 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2130 }
2131
2132 } else { /* SerDes */
2133 mask = NIG_MASK_SERDES0_LINK_STATUS;
2134 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002135 if (!(SINGLE_MEDIA_DIRECT(params)) &&
2136 params->phy[INT_PHY].type !=
2137 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002138 mask |= NIG_MASK_MI_INT;
2139 DP(NETIF_MSG_LINK, "enabled external phy int\n");
2140 }
2141 }
2142 bnx2x_bits_en(bp,
2143 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
2144 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002145
2146 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002147 (params->switch_cfg == SWITCH_CFG_10G),
2148 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002149 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
2150 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
2151 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
2152 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
2153 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
2154 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
2155 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
2156}
2157
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002158static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
2159 u8 exp_mi_int)
Eilon Greenstein2f904462009-08-12 08:22:16 +00002160{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002161 u32 latch_status = 0;
2162
2163 /**
2164 * Disable the MI INT ( external phy int ) by writing 1 to the
2165 * status register. Link down indication is high-active-signal,
2166 * so in this case we need to write the status to clear the XOR
Eilon Greenstein2f904462009-08-12 08:22:16 +00002167 */
2168 /* Read Latched signals */
2169 latch_status = REG_RD(bp,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002170 NIG_REG_LATCH_STATUS_0 + port*8);
2171 DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
Eilon Greenstein2f904462009-08-12 08:22:16 +00002172 /* Handle only those with latched-signal=up.*/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002173 if (exp_mi_int)
2174 bnx2x_bits_en(bp,
2175 NIG_REG_STATUS_INTERRUPT_PORT0
2176 + port*4,
2177 NIG_STATUS_EMAC0_MI_INT);
2178 else
2179 bnx2x_bits_dis(bp,
2180 NIG_REG_STATUS_INTERRUPT_PORT0
2181 + port*4,
2182 NIG_STATUS_EMAC0_MI_INT);
2183
Eilon Greenstein2f904462009-08-12 08:22:16 +00002184 if (latch_status & 1) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002185
Eilon Greenstein2f904462009-08-12 08:22:16 +00002186 /* For all latched-signal=up : Re-Arm Latch signals */
2187 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002188 (latch_status & 0xfffe) | (latch_status & 1));
Eilon Greenstein2f904462009-08-12 08:22:16 +00002189 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002190 /* For all latched-signal=up,Write original_signal to status */
Eilon Greenstein2f904462009-08-12 08:22:16 +00002191}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002192
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002193static void bnx2x_link_int_ack(struct link_params *params,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002194 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002195{
2196 struct bnx2x *bp = params->bp;
2197 u8 port = params->port;
2198
2199 /* first reset all status
2200 * we assume only one line will be change at a time */
2201 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2202 (NIG_STATUS_XGXS0_LINK10G |
2203 NIG_STATUS_XGXS0_LINK_STATUS |
2204 NIG_STATUS_SERDES0_LINK_STATUS));
2205 if (vars->phy_link_up) {
2206 if (is_10g) {
2207 /* Disable the 10G link interrupt
2208 * by writing 1 to the status register
2209 */
2210 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
2211 bnx2x_bits_en(bp,
2212 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2213 NIG_STATUS_XGXS0_LINK10G);
2214
2215 } else if (params->switch_cfg == SWITCH_CFG_10G) {
2216 /* Disable the link interrupt
2217 * by writing 1 to the relevant lane
2218 * in the status register
2219 */
2220 u32 ser_lane = ((params->lane_config &
2221 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
2222 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
2223
Eilon Greenstein2f904462009-08-12 08:22:16 +00002224 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
2225 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002226 bnx2x_bits_en(bp,
2227 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2228 ((1 << ser_lane) <<
2229 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
2230
2231 } else { /* SerDes */
2232 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
2233 /* Disable the link interrupt
2234 * by writing 1 to the status register
2235 */
2236 bnx2x_bits_en(bp,
2237 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
2238 NIG_STATUS_SERDES0_LINK_STATUS);
2239 }
2240
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002241 }
2242}
2243
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002244static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002245{
2246 u8 *str_ptr = str;
2247 u32 mask = 0xf0000000;
2248 u8 shift = 8*4;
2249 u8 digit;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002250 u8 remove_leading_zeros = 1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002251 if (*len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02002252 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002253 *str_ptr = '\0';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002254 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002255 return -EINVAL;
2256 }
2257 while (shift > 0) {
2258
2259 shift -= 4;
2260 digit = ((num & mask) >> shift);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002261 if (digit == 0 && remove_leading_zeros) {
2262 mask = mask >> 4;
2263 continue;
2264 } else if (digit < 0xa)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002265 *str_ptr = digit + '0';
2266 else
2267 *str_ptr = digit - 0xa + 'a';
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002268 remove_leading_zeros = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002269 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002270 (*len)--;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002271 mask = mask >> 4;
2272 if (shift == 4*4) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002273 *str_ptr = '.';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002274 str_ptr++;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002275 (*len)--;
2276 remove_leading_zeros = 1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002277 }
2278 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002279 return 0;
2280}
2281
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002282
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002283static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
2284{
2285 str[0] = '\0';
2286 (*len)--;
2287 return 0;
2288}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002289
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002290u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
2291 u8 *version, u16 len)
2292{
Julia Lawall0376d5b2009-07-19 05:26:35 +00002293 struct bnx2x *bp;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002294 u32 spirom_ver = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002295 u8 status = 0;
2296 u8 *ver_p = version;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002297 u16 remain_len = len;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002298 if (version == NULL || params == NULL)
2299 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00002300 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002301
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002302 /* Extract first external phy*/
2303 version[0] = '\0';
2304 spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002305
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002306 if (params->phy[EXT_PHY1].format_fw_ver) {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002307 status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
2308 ver_p,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002309 &remain_len);
2310 ver_p += (len - remain_len);
2311 }
2312 if ((params->num_phys == MAX_PHYS) &&
2313 (params->phy[EXT_PHY2].ver_addr != 0)) {
2314 spirom_ver = REG_RD(bp,
2315 params->phy[EXT_PHY2].ver_addr);
2316 if (params->phy[EXT_PHY2].format_fw_ver) {
2317 *ver_p = '/';
2318 ver_p++;
2319 remain_len--;
2320 status |= params->phy[EXT_PHY2].format_fw_ver(
2321 spirom_ver,
2322 ver_p,
2323 &remain_len);
2324 ver_p = version + (len - remain_len);
2325 }
2326 }
2327 *ver_p = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002328 return status;
2329}
2330
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002331static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002332 struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002333{
2334 u8 port = params->port;
2335 struct bnx2x *bp = params->bp;
2336
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002337 if (phy->req_line_speed != SPEED_1000) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07002338 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002339
2340 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
2341
2342 /* change the uni_phy_addr in the nig */
2343 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
2344 port*0x18));
2345
2346 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
2347
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002348 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002349 5,
2350 (MDIO_REG_BANK_AER_BLOCK +
2351 (MDIO_AER_BLOCK_AER_REG & 0xf)),
2352 0x2800);
2353
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002354 bnx2x_cl45_write(bp, phy,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002355 5,
2356 (MDIO_REG_BANK_CL73_IEEEB0 +
2357 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
2358 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00002359 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002360 /* set aer mmd back */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002361 bnx2x_set_aer_mmd(params, phy);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002362
2363 /* and md_devad */
2364 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
2365 md_devad);
2366
2367 } else {
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002368 u16 mii_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002369 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002370 bnx2x_cl45_read(bp, phy, 5,
2371 (MDIO_REG_BANK_COMBO_IEEE0 +
2372 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
2373 &mii_ctrl);
2374 bnx2x_cl45_write(bp, phy, 5,
2375 (MDIO_REG_BANK_COMBO_IEEE0 +
2376 (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
2377 mii_ctrl |
2378 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002379 }
2380}
2381
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002382/*
2383 *------------------------------------------------------------------------
2384 * bnx2x_override_led_value -
2385 *
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002386 * Override the led value of the requested led
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002387 *
2388 *------------------------------------------------------------------------
2389 */
2390u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
2391 u32 led_idx, u32 value)
2392{
2393 u32 reg_val;
2394
2395 /* If port 0 then use EMAC0, else use EMAC1*/
2396 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
2397
2398 DP(NETIF_MSG_LINK,
2399 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
2400 port, led_idx, value);
2401
2402 switch (led_idx) {
2403 case 0: /* 10MB led */
2404 /* Read the current value of the LED register in
2405 the EMAC block */
2406 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2407 /* Set the OVERRIDE bit to 1 */
2408 reg_val |= EMAC_LED_OVERRIDE;
2409 /* If value is 1, set the 10M_OVERRIDE bit,
2410 otherwise reset it.*/
2411 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
2412 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
2413 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2414 break;
2415 case 1: /*100MB led */
2416 /*Read the current value of the LED register in
2417 the EMAC block */
2418 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2419 /* Set the OVERRIDE bit to 1 */
2420 reg_val |= EMAC_LED_OVERRIDE;
2421 /* If value is 1, set the 100M_OVERRIDE bit,
2422 otherwise reset it.*/
2423 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
2424 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
2425 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2426 break;
2427 case 2: /* 1000MB led */
2428 /* Read the current value of the LED register in the
2429 EMAC block */
2430 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2431 /* Set the OVERRIDE bit to 1 */
2432 reg_val |= EMAC_LED_OVERRIDE;
2433 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
2434 reset it. */
2435 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
2436 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
2437 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2438 break;
2439 case 3: /* 2500MB led */
2440 /* Read the current value of the LED register in the
2441 EMAC block*/
2442 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
2443 /* Set the OVERRIDE bit to 1 */
2444 reg_val |= EMAC_LED_OVERRIDE;
2445 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
2446 reset it.*/
2447 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
2448 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
2449 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2450 break;
2451 case 4: /*10G led */
2452 if (port == 0) {
2453 REG_WR(bp, NIG_REG_LED_10G_P0,
2454 value);
2455 } else {
2456 REG_WR(bp, NIG_REG_LED_10G_P1,
2457 value);
2458 }
2459 break;
2460 case 5: /* TRAFFIC led */
2461 /* Find if the traffic control is via BMAC or EMAC */
2462 if (port == 0)
2463 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
2464 else
2465 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
2466
2467 /* Override the traffic led in the EMAC:*/
2468 if (reg_val == 1) {
2469 /* Read the current value of the LED register in
2470 the EMAC block */
2471 reg_val = REG_RD(bp, emac_base +
2472 EMAC_REG_EMAC_LED);
2473 /* Set the TRAFFIC_OVERRIDE bit to 1 */
2474 reg_val |= EMAC_LED_OVERRIDE;
2475 /* If value is 1, set the TRAFFIC bit, otherwise
2476 reset it.*/
2477 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
2478 (reg_val & ~EMAC_LED_TRAFFIC);
2479 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
2480 } else { /* Override the traffic led in the BMAC: */
2481 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
2482 + port*4, 1);
2483 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
2484 value);
2485 }
2486 break;
2487 default:
2488 DP(NETIF_MSG_LINK,
2489 "bnx2x_override_led_value() unknown led index %d "
2490 "(should be 0-5)\n", led_idx);
2491 return -EINVAL;
2492 }
2493
2494 return 0;
2495}
2496
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002497
2498u8 bnx2x_set_led(struct link_params *params,
2499 struct link_vars *vars, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002500{
Yaniv Rosner7846e472009-11-05 19:18:07 +02002501 u8 port = params->port;
2502 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002503 u8 rc = 0, phy_idx;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002504 u32 tmp;
2505 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02002506 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002507 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
2508 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
2509 speed, hw_led_mode);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002510 /* In case */
2511 for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
2512 if (params->phy[phy_idx].set_link_led) {
2513 params->phy[phy_idx].set_link_led(
2514 &params->phy[phy_idx], params, mode);
2515 }
2516 }
2517
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002518 switch (mode) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002519 case LED_MODE_FRONT_PANEL_OFF:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002520 case LED_MODE_OFF:
2521 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
2522 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
2523 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002524
2525 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07002526 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002527 break;
2528
2529 case LED_MODE_OPER:
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002530 /**
2531 * For all other phys, OPER mode is same as ON, so in case
2532 * link is down, do nothing
2533 **/
2534 if (!vars->link_up)
2535 break;
2536 case LED_MODE_ON:
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002537 if (SINGLE_MEDIA_DIRECT(params)) {
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002538 /**
2539 * This is a work-around for HW issue found when link
2540 * is up in CL73
2541 */
Yaniv Rosner7846e472009-11-05 19:18:07 +02002542 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
2543 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
2544 } else {
2545 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
2546 hw_led_mode);
2547 }
2548
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002549 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
2550 port*4, 0);
2551 /* Set blinking rate to ~15.9Hz */
2552 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
2553 LED_BLINK_RATE_VAL);
2554 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
2555 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002556 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07002557 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07002558 (tmp & (~EMAC_LED_OVERRIDE)));
2559
Yaniv Rosner7846e472009-11-05 19:18:07 +02002560 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07002561 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002562 (speed == SPEED_1000) ||
2563 (speed == SPEED_100) ||
2564 (speed == SPEED_10))) {
2565 /* On Everest 1 Ax chip versions for speeds less than
2566 10G LED scheme is different */
2567 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
2568 + port*4, 1);
2569 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
2570 port*4, 0);
2571 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
2572 port*4, 1);
2573 }
2574 break;
2575
2576 default:
2577 rc = -EINVAL;
2578 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
2579 mode);
2580 break;
2581 }
2582 return rc;
2583
2584}
2585
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002586/**
2587 * This function comes to reflect the actual link state read DIRECTLY from the
2588 * HW
2589 */
2590u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars,
2591 u8 is_serdes)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002592{
2593 struct bnx2x *bp = params->bp;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002594 u16 gp_status = 0, phy_index = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002595 u8 ext_phy_link_up = 0, serdes_phy_type;
2596 struct link_vars temp_vars;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002597
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002598 CL45_RD_OVER_CL22(bp, &params->phy[INT_PHY],
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002599 MDIO_REG_BANK_GP_STATUS,
2600 MDIO_GP_STATUS_TOP_AN_STATUS1,
2601 &gp_status);
2602 /* link is up only if both local phy and external phy are up */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002603 if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
2604 return -ESRCH;
2605
2606 switch (params->num_phys) {
2607 case 1:
2608 /* No external PHY */
2609 return 0;
2610 case 2:
2611 ext_phy_link_up = params->phy[EXT_PHY1].read_status(
2612 &params->phy[EXT_PHY1],
2613 params, &temp_vars);
2614 break;
2615 case 3: /* Dual Media */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002616 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
2617 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002618 serdes_phy_type = ((params->phy[phy_index].media_type ==
2619 ETH_PHY_SFP_FIBER) ||
2620 (params->phy[phy_index].media_type ==
2621 ETH_PHY_XFP_FIBER));
2622
2623 if (is_serdes != serdes_phy_type)
2624 continue;
2625 if (params->phy[phy_index].read_status) {
2626 ext_phy_link_up |=
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002627 params->phy[phy_index].read_status(
2628 &params->phy[phy_index],
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002629 params, &temp_vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002630 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002631 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002632 break;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002633 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002634 if (ext_phy_link_up)
2635 return 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002636 return -ESRCH;
2637}
2638
2639static u8 bnx2x_link_initialize(struct link_params *params,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00002640 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002641{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002642 u8 rc = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002643 u8 phy_index, non_ext_phy;
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002644 struct bnx2x *bp = params->bp;
2645 /**
2646 * In case of external phy existence, the line speed would be the
2647 * line speed linked up by the external phy. In case it is direct
2648 * only, then the line_speed during initialization will be
2649 * equal to the req_line_speed
2650 */
2651 vars->line_speed = params->phy[INT_PHY].req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002652
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002653 /**
2654 * Initialize the internal phy in case this is a direct board
2655 * (no external phys), or this board has external phy which requires
2656 * to first.
2657 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002658
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002659 if (params->phy[INT_PHY].config_init)
2660 params->phy[INT_PHY].config_init(
2661 &params->phy[INT_PHY],
2662 params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002663
2664 /* init ext phy and enable link state int */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002665 non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002666 (params->loopback_mode == LOOPBACK_XGXS));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002667
2668 if (non_ext_phy ||
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002669 (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00002670 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002671 struct bnx2x_phy *phy = &params->phy[INT_PHY];
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002672 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002673 bnx2x_set_parallel_detection(phy, params);
2674 bnx2x_init_internal_phy(phy, params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002675 }
2676
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00002677 /* Init external phy*/
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002678 if (!non_ext_phy)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002679 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
2680 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002681 /**
2682 * No need to initialize second phy in case of first
2683 * phy only selection. In case of second phy, we do
2684 * need to initialize the first phy, since they are
2685 * connected.
2686 **/
2687 if (phy_index == EXT_PHY2 &&
2688 (bnx2x_phy_selection(params) ==
2689 PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
2690 DP(NETIF_MSG_LINK, "Not initializing"
2691 "second phy\n");
2692 continue;
2693 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002694 params->phy[phy_index].config_init(
2695 &params->phy[phy_index],
2696 params, vars);
2697 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002698
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00002699 /* Reset the interrupt indication after phy was initialized */
2700 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
2701 params->port*4,
2702 (NIG_STATUS_XGXS0_LINK10G |
2703 NIG_STATUS_XGXS0_LINK_STATUS |
2704 NIG_STATUS_SERDES0_LINK_STATUS |
2705 NIG_MASK_MI_INT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002706 return rc;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002707}
2708
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002709static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
2710 struct link_params *params)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002711{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00002712 /* reset the SerDes/XGXS */
2713 REG_WR(params->bp, GRCBASE_MISC +
2714 MISC_REGISTERS_RESET_REG_3_CLEAR,
2715 (0x1ff << (params->port*16)));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002716}
2717
2718static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
2719 struct link_params *params)
2720{
2721 struct bnx2x *bp = params->bp;
2722 u8 gpio_port;
2723 /* HW reset */
2724 gpio_port = params->port;
2725 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
2726 MISC_REGISTERS_GPIO_OUTPUT_LOW,
2727 gpio_port);
2728 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2729 MISC_REGISTERS_GPIO_OUTPUT_LOW,
2730 gpio_port);
2731 DP(NETIF_MSG_LINK, "reset external PHY\n");
2732}
2733
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002734static u8 bnx2x_update_link_down(struct link_params *params,
2735 struct link_vars *vars)
2736{
2737 struct bnx2x *bp = params->bp;
2738 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002739
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002740 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002741 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002742
2743 /* indicate no mac active */
2744 vars->mac_type = MAC_TYPE_NONE;
2745
2746 /* update shared memory */
2747 vars->link_status = 0;
2748 vars->line_speed = 0;
2749 bnx2x_update_mng(params, vars->link_status);
2750
2751 /* activate nig drain */
2752 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
2753
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002754 /* disable emac */
2755 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
2756
2757 msleep(10);
2758
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002759 /* reset BigMac */
2760 bnx2x_bmac_rx_disable(bp, params->port);
2761 REG_WR(bp, GRCBASE_MISC +
2762 MISC_REGISTERS_RESET_REG_2_CLEAR,
2763 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
2764 return 0;
2765}
2766
2767static u8 bnx2x_update_link_up(struct link_params *params,
2768 struct link_vars *vars,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002769 u8 link_10g)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002770{
2771 struct bnx2x *bp = params->bp;
2772 u8 port = params->port;
2773 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002774
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002775 vars->link_status |= LINK_STATUS_LINK_UP;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002776
Yaniv Rosner7aa07112010-09-07 11:41:01 +00002777 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
2778 vars->link_status |=
2779 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
2780
2781 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
2782 vars->link_status |=
2783 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002784
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002785 if (link_10g) {
2786 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00002787 bnx2x_set_led(params, vars,
2788 LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002789 } else {
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002790 rc = bnx2x_emac_program(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002791
Yaniv Rosner0c786f02009-11-05 19:18:32 +02002792 bnx2x_emac_enable(params, vars, 0);
2793
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002794 /* AN complete? */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00002795 if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
2796 && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
2797 SINGLE_MEDIA_DIRECT(params))
2798 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002799 }
2800
2801 /* PBF - link up */
2802 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
2803 vars->line_speed);
2804
2805 /* disable drain */
2806 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
2807
2808 /* update shared memory */
2809 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002810 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002811 return rc;
2812}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002813/**
2814 * The bnx2x_link_update function should be called upon link
2815 * interrupt.
2816 * Link is considered up as follows:
2817 * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
2818 * to be up
2819 * - SINGLE_MEDIA - The link between the 577xx and the external
2820 * phy (XGXS) need to up as well as the external link of the
2821 * phy (PHY_EXT1)
2822 * - DUAL_MEDIA - The link between the 577xx and the first
2823 * external phy needs to be up, and at least one of the 2
2824 * external phy link must be up.
Yaniv Rosner62b29a52010-09-07 11:40:58 +00002825 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002826u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
2827{
2828 struct bnx2x *bp = params->bp;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002829 struct link_vars phy_vars[MAX_PHYS];
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002830 u8 port = params->port;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002831 u8 link_10g, phy_index;
2832 u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
Eilon Greenstein2f904462009-08-12 08:22:16 +00002833 u8 is_mi_int = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002834 u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
2835 u8 active_external_phy = INT_PHY;
2836 vars->link_status = 0;
2837 for (phy_index = INT_PHY; phy_index < params->num_phys;
2838 phy_index++) {
2839 phy_vars[phy_index].flow_ctrl = 0;
2840 phy_vars[phy_index].link_status = 0;
2841 phy_vars[phy_index].line_speed = 0;
2842 phy_vars[phy_index].duplex = DUPLEX_FULL;
2843 phy_vars[phy_index].phy_link_up = 0;
2844 phy_vars[phy_index].link_up = 0;
2845 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002846
2847 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00002848 port, (vars->phy_flags & PHY_XGXS_FLAG),
2849 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002850
Eilon Greenstein2f904462009-08-12 08:22:16 +00002851 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
2852 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002853 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00002854 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
2855 is_mi_int,
2856 REG_RD(bp,
2857 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002858
2859 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
2860 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
2861 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
2862
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00002863 /* disable emac */
2864 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
2865
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002866 /**
2867 * Step 1:
2868 * Check external link change only for external phys, and apply
2869 * priority selection between them in case the link on both phys
2870 * is up. Note that the instead of the common vars, a temporary
2871 * vars argument is used since each phy may have different link/
2872 * speed/duplex result
2873 */
2874 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
2875 phy_index++) {
2876 struct bnx2x_phy *phy = &params->phy[phy_index];
2877 if (!phy->read_status)
2878 continue;
2879 /* Read link status and params of this ext phy */
2880 cur_link_up = phy->read_status(phy, params,
2881 &phy_vars[phy_index]);
2882 if (cur_link_up) {
2883 DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
2884 phy_index);
2885 } else {
2886 DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
2887 phy_index);
2888 continue;
2889 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002890
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002891 if (!ext_phy_link_up) {
2892 ext_phy_link_up = 1;
2893 active_external_phy = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002894 } else {
2895 switch (bnx2x_phy_selection(params)) {
2896 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
2897 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
2898 /**
2899 * In this option, the first PHY makes sure to pass the
2900 * traffic through itself only.
2901 * Its not clear how to reset the link on the second phy
2902 **/
2903 active_external_phy = EXT_PHY1;
2904 break;
2905 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
2906 /**
2907 * In this option, the first PHY makes sure to pass the
2908 * traffic through the second PHY.
2909 **/
2910 active_external_phy = EXT_PHY2;
2911 break;
2912 default:
2913 /**
2914 * Link indication on both PHYs with the following cases
2915 * is invalid:
2916 * - FIRST_PHY means that second phy wasn't initialized,
2917 * hence its link is expected to be down
2918 * - SECOND_PHY means that first phy should not be able
2919 * to link up by itself (using configuration)
2920 * - DEFAULT should be overriden during initialiazation
2921 **/
2922 DP(NETIF_MSG_LINK, "Invalid link indication"
2923 "mpc=0x%x. DISABLING LINK !!!\n",
2924 params->multi_phy_config);
2925 ext_phy_link_up = 0;
2926 break;
2927 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002928 }
2929 }
2930 prev_line_speed = vars->line_speed;
2931 /**
2932 * Step 2:
2933 * Read the status of the internal phy. In case of
2934 * DIRECT_SINGLE_MEDIA board, this link is the external link,
2935 * otherwise this is the link between the 577xx and the first
2936 * external phy
2937 */
2938 if (params->phy[INT_PHY].read_status)
2939 params->phy[INT_PHY].read_status(
2940 &params->phy[INT_PHY],
2941 params, vars);
2942 /**
2943 * The INT_PHY flow control reside in the vars. This include the
2944 * case where the speed or flow control are not set to AUTO.
2945 * Otherwise, the active external phy flow control result is set
2946 * to the vars. The ext_phy_line_speed is needed to check if the
2947 * speed is different between the internal phy and external phy.
2948 * This case may be result of intermediate link speed change.
2949 */
2950 if (active_external_phy > INT_PHY) {
2951 vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
2952 /**
2953 * Link speed is taken from the XGXS. AN and FC result from
2954 * the external phy.
2955 */
2956 vars->link_status |= phy_vars[active_external_phy].link_status;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002957
2958 /**
2959 * if active_external_phy is first PHY and link is up - disable
2960 * disable TX on second external PHY
2961 */
2962 if (active_external_phy == EXT_PHY1) {
2963 if (params->phy[EXT_PHY2].phy_specific_func) {
2964 DP(NETIF_MSG_LINK, "Disabling TX on"
2965 " EXT_PHY2\n");
2966 params->phy[EXT_PHY2].phy_specific_func(
2967 &params->phy[EXT_PHY2],
2968 params, DISABLE_TX);
2969 }
2970 }
2971
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002972 ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
2973 vars->duplex = phy_vars[active_external_phy].duplex;
2974 if (params->phy[active_external_phy].supported &
2975 SUPPORTED_FIBRE)
2976 vars->link_status |= LINK_STATUS_SERDES_LINK;
2977 DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
2978 active_external_phy);
2979 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00002980
2981 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
2982 phy_index++) {
2983 if (params->phy[phy_index].flags &
2984 FLAGS_REARM_LATCH_SIGNAL) {
2985 bnx2x_rearm_latch_signal(bp, port,
2986 phy_index ==
2987 active_external_phy);
2988 break;
2989 }
2990 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00002991 DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
2992 " ext_phy_line_speed = %d\n", vars->flow_ctrl,
2993 vars->link_status, ext_phy_line_speed);
2994 /**
2995 * Upon link speed change set the NIG into drain mode. Comes to
2996 * deals with possible FIFO glitch due to clk change when speed
2997 * is decreased without link down indicator
2998 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002999
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003000 if (vars->phy_link_up) {
3001 if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
3002 (ext_phy_line_speed != vars->line_speed)) {
3003 DP(NETIF_MSG_LINK, "Internal link speed %d is"
3004 " different than the external"
3005 " link speed %d\n", vars->line_speed,
3006 ext_phy_line_speed);
3007 vars->phy_link_up = 0;
3008 } else if (prev_line_speed != vars->line_speed) {
3009 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3010 + params->port*4, 0);
3011 msleep(1);
3012 }
3013 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003014
3015 /* anything 10 and over uses the bmac */
3016 link_10g = ((vars->line_speed == SPEED_10000) ||
3017 (vars->line_speed == SPEED_12000) ||
3018 (vars->line_speed == SPEED_12500) ||
3019 (vars->line_speed == SPEED_13000) ||
3020 (vars->line_speed == SPEED_15000) ||
3021 (vars->line_speed == SPEED_16000));
3022
Yaniv Rosnera22f0782010-09-07 11:41:20 +00003023 bnx2x_link_int_ack(params, vars, link_10g);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003024
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003025 /**
3026 * In case external phy link is up, and internal link is down
3027 * (not initialized yet probably after link initialization, it
3028 * needs to be initialized.
3029 * Note that after link down-up as result of cable plug, the xgxs
3030 * link would probably become up again without the need
3031 * initialize it
3032 */
3033 if (!(SINGLE_MEDIA_DIRECT(params))) {
3034 DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
3035 " init_preceding = %d\n", ext_phy_link_up,
3036 vars->phy_link_up,
3037 params->phy[EXT_PHY1].flags &
3038 FLAGS_INIT_XGXS_FIRST);
3039 if (!(params->phy[EXT_PHY1].flags &
3040 FLAGS_INIT_XGXS_FIRST)
3041 && ext_phy_link_up && !vars->phy_link_up) {
3042 vars->line_speed = ext_phy_line_speed;
3043 if (vars->line_speed < SPEED_1000)
3044 vars->phy_flags |= PHY_SGMII_FLAG;
3045 else
3046 vars->phy_flags &= ~PHY_SGMII_FLAG;
3047 bnx2x_init_internal_phy(&params->phy[INT_PHY],
3048 params,
3049 vars);
3050 }
3051 }
3052 /**
3053 * Link is up only if both local phy and external phy (in case of
3054 * non-direct board) are up
3055 */
3056 vars->link_up = (vars->phy_link_up &&
3057 (ext_phy_link_up ||
3058 SINGLE_MEDIA_DIRECT(params)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003059
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003060 if (vars->link_up)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003061 rc = bnx2x_update_link_up(params, vars, link_10g);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003062 else
3063 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003064
3065 return rc;
3066}
3067
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003068
3069/*****************************************************************************/
3070/* External Phy section */
3071/*****************************************************************************/
3072void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003073{
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003074 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3075 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
3076 msleep(1);
3077 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3078 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00003079}
3080
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00003081static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
3082 u32 spirom_ver, u32 ver_addr)
3083{
3084 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
3085 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
3086
3087 if (ver_addr)
3088 REG_WR(bp, ver_addr, spirom_ver);
3089}
3090
3091static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
3092 struct bnx2x_phy *phy,
3093 u8 port)
3094{
3095 u16 fw_ver1, fw_ver2;
3096
3097 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
3098 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
3099 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
3100 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
3101 bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
3102 phy->ver_addr);
3103}
3104
3105static void bnx2x_ext_phy_set_pause(struct link_params *params,
3106 struct bnx2x_phy *phy,
3107 struct link_vars *vars)
3108{
3109 u16 val;
3110 struct bnx2x *bp = params->bp;
3111 /* read modify write pause advertizing */
3112 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
3113
3114 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
3115
3116 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3117 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
3118 if ((vars->ieee_fc &
3119 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3120 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3121 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3122 }
3123 if ((vars->ieee_fc &
3124 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3125 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3126 val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
3127 }
3128 DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
3129 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
3130}
3131
3132static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
3133 struct link_params *params,
3134 struct link_vars *vars)
3135{
3136 struct bnx2x *bp = params->bp;
3137 u16 ld_pause; /* local */
3138 u16 lp_pause; /* link partner */
3139 u16 pause_result;
3140 u8 ret = 0;
3141 /* read twice */
3142
3143 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
3144
3145 if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
3146 vars->flow_ctrl = phy->req_flow_ctrl;
3147 else if (phy->req_line_speed != SPEED_AUTO_NEG)
3148 vars->flow_ctrl = params->req_fc_auto_adv;
3149 else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
3150 ret = 1;
3151 bnx2x_cl45_read(bp, phy,
3152 MDIO_AN_DEVAD,
3153 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
3154 bnx2x_cl45_read(bp, phy,
3155 MDIO_AN_DEVAD,
3156 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
3157 pause_result = (ld_pause &
3158 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
3159 pause_result |= (lp_pause &
3160 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
3161 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
3162 pause_result);
3163 bnx2x_pause_resolve(vars, pause_result);
3164 }
3165 return ret;
3166}
3167
3168static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
3169 struct bnx2x_phy *phy,
3170 struct link_vars *vars)
3171{
3172 u16 val;
3173 bnx2x_cl45_read(bp, phy,
3174 MDIO_AN_DEVAD,
3175 MDIO_AN_REG_STATUS, &val);
3176 bnx2x_cl45_read(bp, phy,
3177 MDIO_AN_DEVAD,
3178 MDIO_AN_REG_STATUS, &val);
3179 if (val & (1<<5))
3180 vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
3181 if ((val & (1<<0)) == 0)
3182 vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
3183}
3184
3185/******************************************************************/
3186/* common BCM8073/BCM8727 PHY SECTION */
3187/******************************************************************/
3188static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
3189 struct link_params *params,
3190 struct link_vars *vars)
3191{
3192 struct bnx2x *bp = params->bp;
3193 if (phy->req_line_speed == SPEED_10 ||
3194 phy->req_line_speed == SPEED_100) {
3195 vars->flow_ctrl = phy->req_flow_ctrl;
3196 return;
3197 }
3198
3199 if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
3200 (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
3201 u16 pause_result;
3202 u16 ld_pause; /* local */
3203 u16 lp_pause; /* link partner */
3204 bnx2x_cl45_read(bp, phy,
3205 MDIO_AN_DEVAD,
3206 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
3207
3208 bnx2x_cl45_read(bp, phy,
3209 MDIO_AN_DEVAD,
3210 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
3211 pause_result = (ld_pause &
3212 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
3213 pause_result |= (lp_pause &
3214 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
3215
3216 bnx2x_pause_resolve(vars, pause_result);
3217 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
3218 pause_result);
3219 }
3220}
3221
3222static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
3223 struct bnx2x_phy *phy,
3224 u8 port)
3225{
3226 /* Boot port from external ROM */
3227 /* EDC grst */
3228 bnx2x_cl45_write(bp, phy,
3229 MDIO_PMA_DEVAD,
3230 MDIO_PMA_REG_GEN_CTRL,
3231 0x0001);
3232
3233 /* ucode reboot and rst */
3234 bnx2x_cl45_write(bp, phy,
3235 MDIO_PMA_DEVAD,
3236 MDIO_PMA_REG_GEN_CTRL,
3237 0x008c);
3238
3239 bnx2x_cl45_write(bp, phy,
3240 MDIO_PMA_DEVAD,
3241 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
3242
3243 /* Reset internal microprocessor */
3244 bnx2x_cl45_write(bp, phy,
3245 MDIO_PMA_DEVAD,
3246 MDIO_PMA_REG_GEN_CTRL,
3247 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
3248
3249 /* Release srst bit */
3250 bnx2x_cl45_write(bp, phy,
3251 MDIO_PMA_DEVAD,
3252 MDIO_PMA_REG_GEN_CTRL,
3253 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
3254
3255 /* wait for 120ms for code download via SPI port */
3256 msleep(120);
3257
3258 /* Clear ser_boot_ctl bit */
3259 bnx2x_cl45_write(bp, phy,
3260 MDIO_PMA_DEVAD,
3261 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
3262 bnx2x_save_bcm_spirom_ver(bp, phy, port);
3263}
3264
3265static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
3266 struct bnx2x_phy *phy)
3267{
3268 u16 val;
3269 bnx2x_cl45_read(bp, phy,
3270 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, &val);
3271
3272 if (val == 0) {
3273 /* Mustn't set low power mode in 8073 A0 */
3274 return;
3275 }
3276
3277 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
3278 bnx2x_cl45_read(bp, phy,
3279 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
3280 val &= ~(1<<13);
3281 bnx2x_cl45_write(bp, phy,
3282 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3283
3284 /* PLL controls */
3285 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805E, 0x1077);
3286 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805D, 0x0000);
3287 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805C, 0x030B);
3288 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805B, 0x1240);
3289 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805A, 0x2490);
3290
3291 /* Tx Controls */
3292 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A7, 0x0C74);
3293 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A6, 0x9041);
3294 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A5, 0x4640);
3295
3296 /* Rx Controls */
3297 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FE, 0x01C4);
3298 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FD, 0x9249);
3299 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FC, 0x2015);
3300
3301 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
3302 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
3303 val |= (1<<13);
3304 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3305}
3306
3307/******************************************************************/
3308/* BCM8073 PHY SECTION */
3309/******************************************************************/
3310static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
3311{
3312 /* This is only required for 8073A1, version 102 only */
3313 u16 val;
3314
3315 /* Read 8073 HW revision*/
3316 bnx2x_cl45_read(bp, phy,
3317 MDIO_PMA_DEVAD,
3318 MDIO_PMA_REG_8073_CHIP_REV, &val);
3319
3320 if (val != 1) {
3321 /* No need to workaround in 8073 A1 */
3322 return 0;
3323 }
3324
3325 bnx2x_cl45_read(bp, phy,
3326 MDIO_PMA_DEVAD,
3327 MDIO_PMA_REG_ROM_VER2, &val);
3328
3329 /* SNR should be applied only for version 0x102 */
3330 if (val != 0x102)
3331 return 0;
3332
3333 return 1;
3334}
3335
3336static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
3337{
3338 u16 val, cnt, cnt1 ;
3339
3340 bnx2x_cl45_read(bp, phy,
3341 MDIO_PMA_DEVAD,
3342 MDIO_PMA_REG_8073_CHIP_REV, &val);
3343
3344 if (val > 0) {
3345 /* No need to workaround in 8073 A1 */
3346 return 0;
3347 }
3348 /* XAUI workaround in 8073 A0: */
3349
3350 /* After loading the boot ROM and restarting Autoneg,
3351 poll Dev1, Reg $C820: */
3352
3353 for (cnt = 0; cnt < 1000; cnt++) {
3354 bnx2x_cl45_read(bp, phy,
3355 MDIO_PMA_DEVAD,
3356 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
3357 &val);
3358 /* If bit [14] = 0 or bit [13] = 0, continue on with
3359 system initialization (XAUI work-around not required,
3360 as these bits indicate 2.5G or 1G link up). */
3361 if (!(val & (1<<14)) || !(val & (1<<13))) {
3362 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
3363 return 0;
3364 } else if (!(val & (1<<15))) {
3365 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
3366 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
3367 it's MSB (bit 15) goes to 1 (indicating that the
3368 XAUI workaround has completed),
3369 then continue on with system initialization.*/
3370 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
3371 bnx2x_cl45_read(bp, phy,
3372 MDIO_PMA_DEVAD,
3373 MDIO_PMA_REG_8073_XAUI_WA, &val);
3374 if (val & (1<<15)) {
3375 DP(NETIF_MSG_LINK,
3376 "XAUI workaround has completed\n");
3377 return 0;
3378 }
3379 msleep(3);
3380 }
3381 break;
3382 }
3383 msleep(3);
3384 }
3385 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
3386 return -EINVAL;
3387}
3388
3389static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
3390{
3391 /* Force KR or KX */
3392 bnx2x_cl45_write(bp, phy,
3393 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
3394 bnx2x_cl45_write(bp, phy,
3395 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
3396 bnx2x_cl45_write(bp, phy,
3397 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
3398 bnx2x_cl45_write(bp, phy,
3399 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
3400}
3401
3402static void bnx2x_8073_set_pause_cl37(struct link_params *params,
3403 struct bnx2x_phy *phy,
3404 struct link_vars *vars)
3405{
3406 u16 cl37_val;
3407 struct bnx2x *bp = params->bp;
3408 bnx2x_cl45_read(bp, phy,
3409 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
3410
3411 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3412 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3413 bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
3414 if ((vars->ieee_fc &
3415 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
3416 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
3417 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
3418 }
3419 if ((vars->ieee_fc &
3420 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3421 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3422 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3423 }
3424 if ((vars->ieee_fc &
3425 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3426 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3427 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3428 }
3429 DP(NETIF_MSG_LINK,
3430 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
3431
3432 bnx2x_cl45_write(bp, phy,
3433 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
3434 msleep(500);
3435}
3436
3437static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
3438 struct link_params *params,
3439 struct link_vars *vars)
3440{
3441 struct bnx2x *bp = params->bp;
3442 u16 val = 0, tmp1;
3443 u8 gpio_port;
3444 DP(NETIF_MSG_LINK, "Init 8073\n");
3445
3446 gpio_port = params->port;
3447 /* Restore normal power mode*/
3448 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3449 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3450
3451 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
3452 MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
3453
3454 /* enable LASI */
3455 bnx2x_cl45_write(bp, phy,
3456 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
3457 bnx2x_cl45_write(bp, phy,
3458 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x0004);
3459
3460 bnx2x_8073_set_pause_cl37(params, phy, vars);
3461
3462 bnx2x_8073_set_xaui_low_power_mode(bp, phy);
3463
3464 bnx2x_cl45_read(bp, phy,
3465 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
3466
3467 bnx2x_cl45_read(bp, phy,
3468 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
3469
3470 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
3471
3472 /* Enable CL37 BAM */
3473 bnx2x_cl45_read(bp, phy,
3474 MDIO_AN_DEVAD,
3475 MDIO_AN_REG_8073_BAM, &val);
3476 bnx2x_cl45_write(bp, phy,
3477 MDIO_AN_DEVAD,
3478 MDIO_AN_REG_8073_BAM, val | 1);
3479
3480 if (params->loopback_mode == LOOPBACK_EXT) {
3481 bnx2x_807x_force_10G(bp, phy);
3482 DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
3483 return 0;
3484 } else {
3485 bnx2x_cl45_write(bp, phy,
3486 MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
3487 }
3488 if (phy->req_line_speed != SPEED_AUTO_NEG) {
3489 if (phy->req_line_speed == SPEED_10000) {
3490 val = (1<<7);
3491 } else if (phy->req_line_speed == SPEED_2500) {
3492 val = (1<<5);
3493 /* Note that 2.5G works only
3494 when used with 1G advertisment */
3495 } else
3496 val = (1<<5);
3497 } else {
3498 val = 0;
3499 if (phy->speed_cap_mask &
3500 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3501 val |= (1<<7);
3502
3503 /* Note that 2.5G works only when
3504 used with 1G advertisment */
3505 if (phy->speed_cap_mask &
3506 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3507 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
3508 val |= (1<<5);
3509 DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
3510 }
3511
3512 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
3513 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
3514
3515 if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3516 (phy->req_line_speed == SPEED_AUTO_NEG)) ||
3517 (phy->req_line_speed == SPEED_2500)) {
3518 u16 phy_ver;
3519 /* Allow 2.5G for A1 and above */
3520 bnx2x_cl45_read(bp, phy,
3521 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
3522 &phy_ver);
3523 DP(NETIF_MSG_LINK, "Add 2.5G\n");
3524 if (phy_ver > 0)
3525 tmp1 |= 1;
3526 else
3527 tmp1 &= 0xfffe;
3528 } else {
3529 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
3530 tmp1 &= 0xfffe;
3531 }
3532
3533 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
3534 /* Add support for CL37 (passive mode) II */
3535
3536 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
3537 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
3538 (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
3539 0x20 : 0x40)));
3540
3541 /* Add support for CL37 (passive mode) III */
3542 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
3543
3544 /* The SNR will improve about 2db by changing
3545 BW and FEE main tap. Rest commands are executed
3546 after link is up*/
3547 if (bnx2x_8073_is_snr_needed(bp, phy))
3548 bnx2x_cl45_write(bp, phy,
3549 MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
3550 0xFB0C);
3551
3552 /* Enable FEC (Forware Error Correction) Request in the AN */
3553 bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
3554 tmp1 |= (1<<15);
3555 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
3556
3557 bnx2x_ext_phy_set_pause(params, phy, vars);
3558
3559 /* Restart autoneg */
3560 msleep(500);
3561 bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
3562 DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
3563 ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
3564 return 0;
3565}
3566
3567static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
3568 struct link_params *params,
3569 struct link_vars *vars)
3570{
3571 struct bnx2x *bp = params->bp;
3572 u8 link_up = 0;
3573 u16 val1, val2;
3574 u16 link_status = 0;
3575 u16 an1000_status = 0;
3576
3577 bnx2x_cl45_read(bp, phy,
3578 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
3579
3580 DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
3581
3582 /* clear the interrupt LASI status register */
3583 bnx2x_cl45_read(bp, phy,
3584 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
3585 bnx2x_cl45_read(bp, phy,
3586 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
3587 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
3588 /* Clear MSG-OUT */
3589 bnx2x_cl45_read(bp, phy,
3590 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
3591
3592 /* Check the LASI */
3593 bnx2x_cl45_read(bp, phy,
3594 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
3595
3596 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3597
3598 /* Check the link status */
3599 bnx2x_cl45_read(bp, phy,
3600 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
3601 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3602
3603 bnx2x_cl45_read(bp, phy,
3604 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
3605 bnx2x_cl45_read(bp, phy,
3606 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
3607 link_up = ((val1 & 4) == 4);
3608 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3609
3610 if (link_up &&
3611 ((phy->req_line_speed != SPEED_10000))) {
3612 if (bnx2x_8073_xaui_wa(bp, phy) != 0)
3613 return 0;
3614 }
3615 bnx2x_cl45_read(bp, phy,
3616 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
3617 bnx2x_cl45_read(bp, phy,
3618 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
3619
3620 /* Check the link status on 1.1.2 */
3621 bnx2x_cl45_read(bp, phy,
3622 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
3623 bnx2x_cl45_read(bp, phy,
3624 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
3625 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3626 "an_link_status=0x%x\n", val2, val1, an1000_status);
3627
3628 link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
3629 if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
3630 /* The SNR will improve about 2dbby
3631 changing the BW and FEE main tap.*/
3632 /* The 1st write to change FFE main
3633 tap is set before restart AN */
3634 /* Change PLL Bandwidth in EDC
3635 register */
3636 bnx2x_cl45_write(bp, phy,
3637 MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
3638 0x26BC);
3639
3640 /* Change CDR Bandwidth in EDC register */
3641 bnx2x_cl45_write(bp, phy,
3642 MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
3643 0x0333);
3644 }
3645 bnx2x_cl45_read(bp, phy,
3646 MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
3647 &link_status);
3648
3649 /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
3650 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
3651 link_up = 1;
3652 vars->line_speed = SPEED_10000;
3653 DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
3654 params->port);
3655 } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
3656 link_up = 1;
3657 vars->line_speed = SPEED_2500;
3658 DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
3659 params->port);
3660 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
3661 link_up = 1;
3662 vars->line_speed = SPEED_1000;
3663 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
3664 params->port);
3665 } else {
3666 link_up = 0;
3667 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
3668 params->port);
3669 }
3670
3671 if (link_up) {
3672 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
3673 bnx2x_8073_resolve_fc(phy, params, vars);
3674 }
3675 return link_up;
3676}
3677
3678static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
3679 struct link_params *params)
3680{
3681 struct bnx2x *bp = params->bp;
3682 u8 gpio_port;
3683 gpio_port = params->port;
3684 DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
3685 gpio_port);
3686 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3687 MISC_REGISTERS_GPIO_OUTPUT_LOW,
3688 gpio_port);
3689}
3690
3691/******************************************************************/
3692/* BCM8705 PHY SECTION */
3693/******************************************************************/
3694static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
3695 struct link_params *params,
3696 struct link_vars *vars)
3697{
3698 struct bnx2x *bp = params->bp;
3699 DP(NETIF_MSG_LINK, "init 8705\n");
3700 /* Restore normal power mode*/
3701 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
3702 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
3703 /* HW reset */
3704 bnx2x_ext_phy_hw_reset(bp, params->port);
3705 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
3706 bnx2x_wait_reset_complete(bp, phy);
3707
3708 bnx2x_cl45_write(bp, phy,
3709 MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
3710 bnx2x_cl45_write(bp, phy,
3711 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
3712 bnx2x_cl45_write(bp, phy,
3713 MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
3714 bnx2x_cl45_write(bp, phy,
3715 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
3716 /* BCM8705 doesn't have microcode, hence the 0 */
3717 bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
3718 return 0;
3719}
3720
3721static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
3722 struct link_params *params,
3723 struct link_vars *vars)
3724{
3725 u8 link_up = 0;
3726 u16 val1, rx_sd;
3727 struct bnx2x *bp = params->bp;
3728 DP(NETIF_MSG_LINK, "read status 8705\n");
3729 bnx2x_cl45_read(bp, phy,
3730 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3731 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3732
3733 bnx2x_cl45_read(bp, phy,
3734 MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
3735 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3736
3737 bnx2x_cl45_read(bp, phy,
3738 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
3739
3740 bnx2x_cl45_read(bp, phy,
3741 MDIO_PMA_DEVAD, 0xc809, &val1);
3742 bnx2x_cl45_read(bp, phy,
3743 MDIO_PMA_DEVAD, 0xc809, &val1);
3744
3745 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
3746 link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
3747 if (link_up) {
3748 vars->line_speed = SPEED_10000;
3749 bnx2x_ext_phy_resolve_fc(phy, params, vars);
3750 }
3751 return link_up;
3752}
3753
3754/******************************************************************/
3755/* SFP+ module Section */
3756/******************************************************************/
3757static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
3758 struct bnx2x_phy *phy,
3759 u8 port,
3760 u8 tx_en)
3761{
3762 u16 val;
3763
3764 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
3765 tx_en, port);
3766 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
3767 bnx2x_cl45_read(bp, phy,
3768 MDIO_PMA_DEVAD,
3769 MDIO_PMA_REG_PHY_IDENTIFIER,
3770 &val);
3771
3772 if (tx_en)
3773 val &= ~(1<<15);
3774 else
3775 val |= (1<<15);
3776
3777 bnx2x_cl45_write(bp, phy,
3778 MDIO_PMA_DEVAD,
3779 MDIO_PMA_REG_PHY_IDENTIFIER,
3780 val);
3781}
3782
3783static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
3784 struct link_params *params,
3785 u16 addr, u8 byte_cnt, u8 *o_buf)
3786{
3787 struct bnx2x *bp = params->bp;
3788 u16 val = 0;
3789 u16 i;
3790 if (byte_cnt > 16) {
3791 DP(NETIF_MSG_LINK, "Reading from eeprom is"
3792 " is limited to 0xf\n");
3793 return -EINVAL;
3794 }
3795 /* Set the read command byte count */
3796 bnx2x_cl45_write(bp, phy,
3797 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
3798 (byte_cnt | 0xa000));
3799
3800 /* Set the read command address */
3801 bnx2x_cl45_write(bp, phy,
3802 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
3803 addr);
3804
3805 /* Activate read command */
3806 bnx2x_cl45_write(bp, phy,
3807 MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
3808 0x2c0f);
3809
3810 /* Wait up to 500us for command complete status */
3811 for (i = 0; i < 100; i++) {
3812 bnx2x_cl45_read(bp, phy,
3813 MDIO_PMA_DEVAD,
3814 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
3815 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
3816 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
3817 break;
3818 udelay(5);
3819 }
3820
3821 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
3822 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
3823 DP(NETIF_MSG_LINK,
3824 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
3825 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
3826 return -EINVAL;
3827 }
3828
3829 /* Read the buffer */
3830 for (i = 0; i < byte_cnt; i++) {
3831 bnx2x_cl45_read(bp, phy,
3832 MDIO_PMA_DEVAD,
3833 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
3834 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
3835 }
3836
3837 for (i = 0; i < 100; i++) {
3838 bnx2x_cl45_read(bp, phy,
3839 MDIO_PMA_DEVAD,
3840 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
3841 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
3842 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
3843 return 0;;
3844 msleep(1);
3845 }
3846 return -EINVAL;
3847}
3848
3849static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
3850 struct link_params *params,
3851 u16 addr, u8 byte_cnt, u8 *o_buf)
3852{
3853 struct bnx2x *bp = params->bp;
3854 u16 val, i;
3855
3856 if (byte_cnt > 16) {
3857 DP(NETIF_MSG_LINK, "Reading from eeprom is"
3858 " is limited to 0xf\n");
3859 return -EINVAL;
3860 }
3861
3862 /* Need to read from 1.8000 to clear it */
3863 bnx2x_cl45_read(bp, phy,
3864 MDIO_PMA_DEVAD,
3865 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
3866 &val);
3867
3868 /* Set the read command byte count */
3869 bnx2x_cl45_write(bp, phy,
3870 MDIO_PMA_DEVAD,
3871 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
3872 ((byte_cnt < 2) ? 2 : byte_cnt));
3873
3874 /* Set the read command address */
3875 bnx2x_cl45_write(bp, phy,
3876 MDIO_PMA_DEVAD,
3877 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
3878 addr);
3879 /* Set the destination address */
3880 bnx2x_cl45_write(bp, phy,
3881 MDIO_PMA_DEVAD,
3882 0x8004,
3883 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
3884
3885 /* Activate read command */
3886 bnx2x_cl45_write(bp, phy,
3887 MDIO_PMA_DEVAD,
3888 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
3889 0x8002);
3890 /* Wait appropriate time for two-wire command to finish before
3891 polling the status register */
3892 msleep(1);
3893
3894 /* Wait up to 500us for command complete status */
3895 for (i = 0; i < 100; i++) {
3896 bnx2x_cl45_read(bp, phy,
3897 MDIO_PMA_DEVAD,
3898 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
3899 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
3900 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
3901 break;
3902 udelay(5);
3903 }
3904
3905 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
3906 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
3907 DP(NETIF_MSG_LINK,
3908 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
3909 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
3910 return -EINVAL;
3911 }
3912
3913 /* Read the buffer */
3914 for (i = 0; i < byte_cnt; i++) {
3915 bnx2x_cl45_read(bp, phy,
3916 MDIO_PMA_DEVAD,
3917 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
3918 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
3919 }
3920
3921 for (i = 0; i < 100; i++) {
3922 bnx2x_cl45_read(bp, phy,
3923 MDIO_PMA_DEVAD,
3924 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
3925 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
3926 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
3927 return 0;;
3928 msleep(1);
3929 }
3930
3931 return -EINVAL;
3932}
3933
3934u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
3935 struct link_params *params, u16 addr,
3936 u8 byte_cnt, u8 *o_buf)
3937{
3938 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
3939 return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
3940 byte_cnt, o_buf);
3941 else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
3942 return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
3943 byte_cnt, o_buf);
3944 return -EINVAL;
3945}
3946
3947static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
3948 struct link_params *params,
3949 u16 *edc_mode)
3950{
3951 struct bnx2x *bp = params->bp;
3952 u8 val, check_limiting_mode = 0;
3953 *edc_mode = EDC_MODE_LIMITING;
3954
3955 /* First check for copper cable */
3956 if (bnx2x_read_sfp_module_eeprom(phy,
3957 params,
3958 SFP_EEPROM_CON_TYPE_ADDR,
3959 1,
3960 &val) != 0) {
3961 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
3962 return -EINVAL;
3963 }
3964
3965 switch (val) {
3966 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
3967 {
3968 u8 copper_module_type;
3969
3970 /* Check if its active cable( includes SFP+ module)
3971 of passive cable*/
3972 if (bnx2x_read_sfp_module_eeprom(phy,
3973 params,
3974 SFP_EEPROM_FC_TX_TECH_ADDR,
3975 1,
3976 &copper_module_type) !=
3977 0) {
3978 DP(NETIF_MSG_LINK,
3979 "Failed to read copper-cable-type"
3980 " from SFP+ EEPROM\n");
3981 return -EINVAL;
3982 }
3983
3984 if (copper_module_type &
3985 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
3986 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
3987 check_limiting_mode = 1;
3988 } else if (copper_module_type &
3989 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
3990 DP(NETIF_MSG_LINK, "Passive Copper"
3991 " cable detected\n");
3992 *edc_mode =
3993 EDC_MODE_PASSIVE_DAC;
3994 } else {
3995 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
3996 "type 0x%x !!!\n", copper_module_type);
3997 return -EINVAL;
3998 }
3999 break;
4000 }
4001 case SFP_EEPROM_CON_TYPE_VAL_LC:
4002 DP(NETIF_MSG_LINK, "Optic module detected\n");
4003 check_limiting_mode = 1;
4004 break;
4005 default:
4006 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
4007 val);
4008 return -EINVAL;
4009 }
4010
4011 if (check_limiting_mode) {
4012 u8 options[SFP_EEPROM_OPTIONS_SIZE];
4013 if (bnx2x_read_sfp_module_eeprom(phy,
4014 params,
4015 SFP_EEPROM_OPTIONS_ADDR,
4016 SFP_EEPROM_OPTIONS_SIZE,
4017 options) != 0) {
4018 DP(NETIF_MSG_LINK, "Failed to read Option"
4019 " field from module EEPROM\n");
4020 return -EINVAL;
4021 }
4022 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
4023 *edc_mode = EDC_MODE_LINEAR;
4024 else
4025 *edc_mode = EDC_MODE_LIMITING;
4026 }
4027 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
4028 return 0;
4029}
4030/* This function read the relevant field from the module ( SFP+ ),
4031 and verify it is compliant with this board */
4032static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
4033 struct link_params *params)
4034{
4035 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004036 u32 val, cmd;
4037 u32 fw_resp, fw_cmd_param;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004038 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
4039 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004040 phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004041 val = REG_RD(bp, params->shmem_base +
4042 offsetof(struct shmem_region, dev_info.
4043 port_feature_config[params->port].config));
4044 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4045 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
4046 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
4047 return 0;
4048 }
4049
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004050 if (params->feature_config_flags &
4051 FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
4052 /* Use specific phy request */
4053 cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
4054 } else if (params->feature_config_flags &
4055 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
4056 /* Use first phy request only in case of non-dual media*/
4057 if (DUAL_MEDIA(params)) {
4058 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
4059 "verification\n");
4060 return -EINVAL;
4061 }
4062 cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
4063 } else {
4064 /* No support in OPT MDL detection */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004065 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004066 "verification\n");
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004067 return -EINVAL;
4068 }
Dmitry Kravkov523224a2010-10-06 03:23:26 +00004069
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004070 fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
4071 fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004072 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
4073 DP(NETIF_MSG_LINK, "Approved module\n");
4074 return 0;
4075 }
4076
4077 /* format the warning message */
4078 if (bnx2x_read_sfp_module_eeprom(phy,
4079 params,
4080 SFP_EEPROM_VENDOR_NAME_ADDR,
4081 SFP_EEPROM_VENDOR_NAME_SIZE,
4082 (u8 *)vendor_name))
4083 vendor_name[0] = '\0';
4084 else
4085 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
4086 if (bnx2x_read_sfp_module_eeprom(phy,
4087 params,
4088 SFP_EEPROM_PART_NO_ADDR,
4089 SFP_EEPROM_PART_NO_SIZE,
4090 (u8 *)vendor_pn))
4091 vendor_pn[0] = '\0';
4092 else
4093 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
4094
4095 netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected,"
4096 " Port %d from %s part number %s\n",
4097 params->port, vendor_name, vendor_pn);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004098 phy->flags |= FLAGS_SFP_NOT_APPROVED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004099 return -EINVAL;
4100}
4101
4102static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
4103 struct link_params *params)
4104
4105{
4106 u8 val;
4107 struct bnx2x *bp = params->bp;
4108 u16 timeout;
4109 /* Initialization time after hot-plug may take up to 300ms for some
4110 phys type ( e.g. JDSU ) */
4111 for (timeout = 0; timeout < 60; timeout++) {
4112 if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
4113 == 0) {
4114 DP(NETIF_MSG_LINK, "SFP+ module initialization "
4115 "took %d ms\n", timeout * 5);
4116 return 0;
4117 }
4118 msleep(5);
4119 }
4120 return -EINVAL;
4121}
4122
4123static void bnx2x_8727_power_module(struct bnx2x *bp,
4124 struct bnx2x_phy *phy,
4125 u8 is_power_up) {
4126 /* Make sure GPIOs are not using for LED mode */
4127 u16 val;
4128 /*
4129 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
4130 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
4131 * output
4132 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
4133 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
4134 * where the 1st bit is the over-current(only input), and 2nd bit is
4135 * for power( only output )
4136 */
4137
4138 /*
4139 * In case of NOC feature is disabled and power is up, set GPIO control
4140 * as input to enable listening of over-current indication
4141 */
4142 if (phy->flags & FLAGS_NOC)
4143 return;
4144 if (!(phy->flags &
4145 FLAGS_NOC) && is_power_up)
4146 val = (1<<4);
4147 else
4148 /*
4149 * Set GPIO control to OUTPUT, and set the power bit
4150 * to according to the is_power_up
4151 */
4152 val = ((!(is_power_up)) << 1);
4153
4154 bnx2x_cl45_write(bp, phy,
4155 MDIO_PMA_DEVAD,
4156 MDIO_PMA_REG_8727_GPIO_CTRL,
4157 val);
4158}
4159
4160static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
4161 struct bnx2x_phy *phy,
4162 u16 edc_mode)
4163{
4164 u16 cur_limiting_mode;
4165
4166 bnx2x_cl45_read(bp, phy,
4167 MDIO_PMA_DEVAD,
4168 MDIO_PMA_REG_ROM_VER2,
4169 &cur_limiting_mode);
4170 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
4171 cur_limiting_mode);
4172
4173 if (edc_mode == EDC_MODE_LIMITING) {
4174 DP(NETIF_MSG_LINK,
4175 "Setting LIMITING MODE\n");
4176 bnx2x_cl45_write(bp, phy,
4177 MDIO_PMA_DEVAD,
4178 MDIO_PMA_REG_ROM_VER2,
4179 EDC_MODE_LIMITING);
4180 } else { /* LRM mode ( default )*/
4181
4182 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
4183
4184 /* Changing to LRM mode takes quite few seconds.
4185 So do it only if current mode is limiting
4186 ( default is LRM )*/
4187 if (cur_limiting_mode != EDC_MODE_LIMITING)
4188 return 0;
4189
4190 bnx2x_cl45_write(bp, phy,
4191 MDIO_PMA_DEVAD,
4192 MDIO_PMA_REG_LRM_MODE,
4193 0);
4194 bnx2x_cl45_write(bp, phy,
4195 MDIO_PMA_DEVAD,
4196 MDIO_PMA_REG_ROM_VER2,
4197 0x128);
4198 bnx2x_cl45_write(bp, phy,
4199 MDIO_PMA_DEVAD,
4200 MDIO_PMA_REG_MISC_CTRL0,
4201 0x4008);
4202 bnx2x_cl45_write(bp, phy,
4203 MDIO_PMA_DEVAD,
4204 MDIO_PMA_REG_LRM_MODE,
4205 0xaaaa);
4206 }
4207 return 0;
4208}
4209
4210static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
4211 struct bnx2x_phy *phy,
4212 u16 edc_mode)
4213{
4214 u16 phy_identifier;
4215 u16 rom_ver2_val;
4216 bnx2x_cl45_read(bp, phy,
4217 MDIO_PMA_DEVAD,
4218 MDIO_PMA_REG_PHY_IDENTIFIER,
4219 &phy_identifier);
4220
4221 bnx2x_cl45_write(bp, phy,
4222 MDIO_PMA_DEVAD,
4223 MDIO_PMA_REG_PHY_IDENTIFIER,
4224 (phy_identifier & ~(1<<9)));
4225
4226 bnx2x_cl45_read(bp, phy,
4227 MDIO_PMA_DEVAD,
4228 MDIO_PMA_REG_ROM_VER2,
4229 &rom_ver2_val);
4230 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
4231 bnx2x_cl45_write(bp, phy,
4232 MDIO_PMA_DEVAD,
4233 MDIO_PMA_REG_ROM_VER2,
4234 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
4235
4236 bnx2x_cl45_write(bp, phy,
4237 MDIO_PMA_DEVAD,
4238 MDIO_PMA_REG_PHY_IDENTIFIER,
4239 (phy_identifier | (1<<9)));
4240
4241 return 0;
4242}
4243
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004244static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
4245 struct link_params *params,
4246 u32 action)
4247{
4248 struct bnx2x *bp = params->bp;
4249
4250 switch (action) {
4251 case DISABLE_TX:
4252 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4253 break;
4254 case ENABLE_TX:
4255 if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
4256 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
4257 break;
4258 default:
4259 DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
4260 action);
4261 return;
4262 }
4263}
4264
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004265static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
4266 struct link_params *params)
4267{
4268 struct bnx2x *bp = params->bp;
4269 u16 edc_mode;
4270 u8 rc = 0;
4271
4272 u32 val = REG_RD(bp, params->shmem_base +
4273 offsetof(struct shmem_region, dev_info.
4274 port_feature_config[params->port].config));
4275
4276 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
4277 params->port);
4278
4279 if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
4280 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
4281 return -EINVAL;
4282 } else if (bnx2x_verify_sfp_module(phy, params) !=
4283 0) {
4284 /* check SFP+ module compatibility */
4285 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
4286 rc = -EINVAL;
4287 /* Turn on fault module-detected led */
4288 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4289 MISC_REGISTERS_GPIO_HIGH,
4290 params->port);
4291 if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
4292 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4293 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
4294 /* Shutdown SFP+ module */
4295 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
4296 bnx2x_8727_power_module(bp, phy, 0);
4297 return rc;
4298 }
4299 } else {
4300 /* Turn off fault module-detected led */
4301 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
4302 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4303 MISC_REGISTERS_GPIO_LOW,
4304 params->port);
4305 }
4306
4307 /* power up the SFP module */
4308 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
4309 bnx2x_8727_power_module(bp, phy, 1);
4310
4311 /* Check and set limiting mode / LRM mode on 8726.
4312 On 8727 it is done automatically */
4313 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
4314 bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
4315 else
4316 bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
4317 /*
4318 * Enable transmit for this module if the module is approved, or
4319 * if unapproved modules should also enable the Tx laser
4320 */
4321 if (rc == 0 ||
4322 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
4323 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4324 bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
4325 else
4326 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4327
4328 return rc;
4329}
4330
4331void bnx2x_handle_module_detect_int(struct link_params *params)
4332{
4333 struct bnx2x *bp = params->bp;
4334 struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
4335 u32 gpio_val;
4336 u8 port = params->port;
4337
4338 /* Set valid module led off */
4339 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4340 MISC_REGISTERS_GPIO_HIGH,
4341 params->port);
4342
4343 /* Get current gpio val refelecting module plugged in / out*/
4344 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
4345
4346 /* Call the handling function in case module is detected */
4347 if (gpio_val == 0) {
4348
4349 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
4350 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
4351 port);
4352
4353 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
4354 bnx2x_sfp_module_detection(phy, params);
4355 else
4356 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
4357 } else {
4358 u32 val = REG_RD(bp, params->shmem_base +
4359 offsetof(struct shmem_region, dev_info.
4360 port_feature_config[params->port].
4361 config));
4362
4363 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
4364 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
4365 port);
4366 /* Module was plugged out. */
4367 /* Disable transmit for this module */
4368 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4369 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4370 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4371 }
4372}
4373
4374/******************************************************************/
4375/* common BCM8706/BCM8726 PHY SECTION */
4376/******************************************************************/
4377static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
4378 struct link_params *params,
4379 struct link_vars *vars)
4380{
4381 u8 link_up = 0;
4382 u16 val1, val2, rx_sd, pcs_status;
4383 struct bnx2x *bp = params->bp;
4384 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
4385 /* Clear RX Alarm*/
4386 bnx2x_cl45_read(bp, phy,
4387 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
4388 /* clear LASI indication*/
4389 bnx2x_cl45_read(bp, phy,
4390 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
4391 bnx2x_cl45_read(bp, phy,
4392 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
4393 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
4394
4395 bnx2x_cl45_read(bp, phy,
4396 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
4397 bnx2x_cl45_read(bp, phy,
4398 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
4399 bnx2x_cl45_read(bp, phy,
4400 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
4401 bnx2x_cl45_read(bp, phy,
4402 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
4403
4404 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
4405 " link_status 0x%x\n", rx_sd, pcs_status, val2);
4406 /* link is up if both bit 0 of pmd_rx_sd and
4407 * bit 0 of pcs_status are set, or if the autoneg bit
4408 * 1 is set
4409 */
4410 link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
4411 if (link_up) {
4412 if (val2 & (1<<1))
4413 vars->line_speed = SPEED_1000;
4414 else
4415 vars->line_speed = SPEED_10000;
4416 bnx2x_ext_phy_resolve_fc(phy, params, vars);
4417 }
4418 return link_up;
4419}
4420
4421/******************************************************************/
4422/* BCM8706 PHY SECTION */
4423/******************************************************************/
4424static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
4425 struct link_params *params,
4426 struct link_vars *vars)
4427{
4428 u16 cnt, val;
4429 struct bnx2x *bp = params->bp;
4430 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4431 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
4432 /* HW reset */
4433 bnx2x_ext_phy_hw_reset(bp, params->port);
4434 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
4435 bnx2x_wait_reset_complete(bp, phy);
4436
4437 /* Wait until fw is loaded */
4438 for (cnt = 0; cnt < 100; cnt++) {
4439 bnx2x_cl45_read(bp, phy,
4440 MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
4441 if (val)
4442 break;
4443 msleep(10);
4444 }
4445 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
4446 if ((params->feature_config_flags &
4447 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4448 u8 i;
4449 u16 reg;
4450 for (i = 0; i < 4; i++) {
4451 reg = MDIO_XS_8706_REG_BANK_RX0 +
4452 i*(MDIO_XS_8706_REG_BANK_RX1 -
4453 MDIO_XS_8706_REG_BANK_RX0);
4454 bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
4455 /* Clear first 3 bits of the control */
4456 val &= ~0x7;
4457 /* Set control bits according to configuration */
4458 val |= (phy->rx_preemphasis[i] & 0x7);
4459 DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
4460 " reg 0x%x <-- val 0x%x\n", reg, val);
4461 bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
4462 }
4463 }
4464 /* Force speed */
4465 if (phy->req_line_speed == SPEED_10000) {
4466 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
4467
4468 bnx2x_cl45_write(bp, phy,
4469 MDIO_PMA_DEVAD,
4470 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
4471 bnx2x_cl45_write(bp, phy,
4472 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
4473 } else {
4474 /* Force 1Gbps using autoneg with 1G advertisment */
4475
4476 /* Allow CL37 through CL73 */
4477 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
4478 bnx2x_cl45_write(bp, phy,
4479 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
4480
4481 /* Enable Full-Duplex advertisment on CL37 */
4482 bnx2x_cl45_write(bp, phy,
4483 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
4484 /* Enable CL37 AN */
4485 bnx2x_cl45_write(bp, phy,
4486 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4487 /* 1G support */
4488 bnx2x_cl45_write(bp, phy,
4489 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
4490
4491 /* Enable clause 73 AN */
4492 bnx2x_cl45_write(bp, phy,
4493 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4494 bnx2x_cl45_write(bp, phy,
4495 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4496 0x0400);
4497 bnx2x_cl45_write(bp, phy,
4498 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
4499 0x0004);
4500 }
4501 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
4502 return 0;
4503}
4504
4505static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
4506 struct link_params *params,
4507 struct link_vars *vars)
4508{
4509 return bnx2x_8706_8726_read_status(phy, params, vars);
4510}
4511
4512/******************************************************************/
4513/* BCM8726 PHY SECTION */
4514/******************************************************************/
4515static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
4516 struct link_params *params)
4517{
4518 struct bnx2x *bp = params->bp;
4519 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4520 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
4521}
4522
4523static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
4524 struct link_params *params)
4525{
4526 struct bnx2x *bp = params->bp;
4527 /* Need to wait 100ms after reset */
4528 msleep(100);
4529
4530 /* Micro controller re-boot */
4531 bnx2x_cl45_write(bp, phy,
4532 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
4533
4534 /* Set soft reset */
4535 bnx2x_cl45_write(bp, phy,
4536 MDIO_PMA_DEVAD,
4537 MDIO_PMA_REG_GEN_CTRL,
4538 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
4539
4540 bnx2x_cl45_write(bp, phy,
4541 MDIO_PMA_DEVAD,
4542 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
4543
4544 bnx2x_cl45_write(bp, phy,
4545 MDIO_PMA_DEVAD,
4546 MDIO_PMA_REG_GEN_CTRL,
4547 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
4548
4549 /* wait for 150ms for microcode load */
4550 msleep(150);
4551
4552 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
4553 bnx2x_cl45_write(bp, phy,
4554 MDIO_PMA_DEVAD,
4555 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
4556
4557 msleep(200);
4558 bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
4559}
4560
4561static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
4562 struct link_params *params,
4563 struct link_vars *vars)
4564{
4565 struct bnx2x *bp = params->bp;
4566 u16 val1;
4567 u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
4568 if (link_up) {
4569 bnx2x_cl45_read(bp, phy,
4570 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
4571 &val1);
4572 if (val1 & (1<<15)) {
4573 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4574 link_up = 0;
4575 vars->line_speed = 0;
4576 }
4577 }
4578 return link_up;
4579}
4580
4581
4582static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
4583 struct link_params *params,
4584 struct link_vars *vars)
4585{
4586 struct bnx2x *bp = params->bp;
4587 u32 val;
4588 u32 swap_val, swap_override, aeu_gpio_mask, offset;
4589 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
4590 /* Restore normal power mode*/
4591 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4592 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
4593
4594 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4595 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
4596
4597 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
4598 bnx2x_wait_reset_complete(bp, phy);
4599
4600 bnx2x_8726_external_rom_boot(phy, params);
4601
4602 /* Need to call module detected on initialization since
4603 the module detection triggered by actual module
4604 insertion might occur before driver is loaded, and when
4605 driver is loaded, it reset all registers, including the
4606 transmitter */
4607 bnx2x_sfp_module_detection(phy, params);
4608
4609 if (phy->req_line_speed == SPEED_1000) {
4610 DP(NETIF_MSG_LINK, "Setting 1G force\n");
4611 bnx2x_cl45_write(bp, phy,
4612 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
4613 bnx2x_cl45_write(bp, phy,
4614 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
4615 bnx2x_cl45_write(bp, phy,
4616 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
4617 bnx2x_cl45_write(bp, phy,
4618 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4619 0x400);
4620 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
4621 (phy->speed_cap_mask &
4622 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
4623 ((phy->speed_cap_mask &
4624 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
4625 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
4626 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
4627 /* Set Flow control */
4628 bnx2x_ext_phy_set_pause(params, phy, vars);
4629 bnx2x_cl45_write(bp, phy,
4630 MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
4631 bnx2x_cl45_write(bp, phy,
4632 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
4633 bnx2x_cl45_write(bp, phy,
4634 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
4635 bnx2x_cl45_write(bp, phy,
4636 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
4637 bnx2x_cl45_write(bp, phy,
4638 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
4639 /* Enable RX-ALARM control to receive
4640 interrupt for 1G speed change */
4641 bnx2x_cl45_write(bp, phy,
4642 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
4643 bnx2x_cl45_write(bp, phy,
4644 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4645 0x400);
4646
4647 } else { /* Default 10G. Set only LASI control */
4648 bnx2x_cl45_write(bp, phy,
4649 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
4650 }
4651
4652 /* Set TX PreEmphasis if needed */
4653 if ((params->feature_config_flags &
4654 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4655 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
4656 "TX_CTRL2 0x%x\n",
4657 phy->tx_preemphasis[0],
4658 phy->tx_preemphasis[1]);
4659 bnx2x_cl45_write(bp, phy,
4660 MDIO_PMA_DEVAD,
4661 MDIO_PMA_REG_8726_TX_CTRL1,
4662 phy->tx_preemphasis[0]);
4663
4664 bnx2x_cl45_write(bp, phy,
4665 MDIO_PMA_DEVAD,
4666 MDIO_PMA_REG_8726_TX_CTRL2,
4667 phy->tx_preemphasis[1]);
4668 }
4669
4670 /* Set GPIO3 to trigger SFP+ module insertion/removal */
4671 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
4672 MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port);
4673
4674 /* The GPIO should be swapped if the swap register is set and active */
4675 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
4676 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
4677
4678 /* Select function upon port-swap configuration */
4679 if (params->port == 0) {
4680 offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
4681 aeu_gpio_mask = (swap_val && swap_override) ?
4682 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
4683 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
4684 } else {
4685 offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
4686 aeu_gpio_mask = (swap_val && swap_override) ?
4687 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
4688 AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
4689 }
4690 val = REG_RD(bp, offset);
4691 /* add GPIO3 to group */
4692 val |= aeu_gpio_mask;
4693 REG_WR(bp, offset, val);
4694 return 0;
4695
4696}
4697
4698static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
4699 struct link_params *params)
4700{
4701 struct bnx2x *bp = params->bp;
4702 DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
4703 /* Set serial boot control for external load */
4704 bnx2x_cl45_write(bp, phy,
4705 MDIO_PMA_DEVAD,
4706 MDIO_PMA_REG_GEN_CTRL, 0x0001);
4707}
4708
4709/******************************************************************/
4710/* BCM8727 PHY SECTION */
4711/******************************************************************/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004712
4713static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
4714 struct link_params *params, u8 mode)
4715{
4716 struct bnx2x *bp = params->bp;
4717 u16 led_mode_bitmask = 0;
4718 u16 gpio_pins_bitmask = 0;
4719 u16 val;
4720 /* Only NOC flavor requires to set the LED specifically */
4721 if (!(phy->flags & FLAGS_NOC))
4722 return;
4723 switch (mode) {
4724 case LED_MODE_FRONT_PANEL_OFF:
4725 case LED_MODE_OFF:
4726 led_mode_bitmask = 0;
4727 gpio_pins_bitmask = 0x03;
4728 break;
4729 case LED_MODE_ON:
4730 led_mode_bitmask = 0;
4731 gpio_pins_bitmask = 0x02;
4732 break;
4733 case LED_MODE_OPER:
4734 led_mode_bitmask = 0x60;
4735 gpio_pins_bitmask = 0x11;
4736 break;
4737 }
4738 bnx2x_cl45_read(bp, phy,
4739 MDIO_PMA_DEVAD,
4740 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4741 &val);
4742 val &= 0xff8f;
4743 val |= led_mode_bitmask;
4744 bnx2x_cl45_write(bp, phy,
4745 MDIO_PMA_DEVAD,
4746 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4747 val);
4748 bnx2x_cl45_read(bp, phy,
4749 MDIO_PMA_DEVAD,
4750 MDIO_PMA_REG_8727_GPIO_CTRL,
4751 &val);
4752 val &= 0xffe0;
4753 val |= gpio_pins_bitmask;
4754 bnx2x_cl45_write(bp, phy,
4755 MDIO_PMA_DEVAD,
4756 MDIO_PMA_REG_8727_GPIO_CTRL,
4757 val);
4758}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00004759static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
4760 struct link_params *params) {
4761 u32 swap_val, swap_override;
4762 u8 port;
4763 /**
4764 * The PHY reset is controlled by GPIO 1. Fake the port number
4765 * to cancel the swap done in set_gpio()
4766 */
4767 struct bnx2x *bp = params->bp;
4768 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
4769 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
4770 port = (swap_val && swap_override) ^ 1;
4771 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4772 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
4773}
4774
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004775static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
4776 struct link_params *params,
4777 struct link_vars *vars)
4778{
4779 u16 tmp1, val, mod_abs;
4780 u16 rx_alarm_ctrl_val;
4781 u16 lasi_ctrl_val;
4782 struct bnx2x *bp = params->bp;
4783 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
4784
4785 bnx2x_wait_reset_complete(bp, phy);
4786 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
4787 lasi_ctrl_val = 0x0004;
4788
4789 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
4790 /* enable LASI */
4791 bnx2x_cl45_write(bp, phy,
4792 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
4793 rx_alarm_ctrl_val);
4794
4795 bnx2x_cl45_write(bp, phy,
4796 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
4797
4798 /* Initially configure MOD_ABS to interrupt when
4799 module is presence( bit 8) */
4800 bnx2x_cl45_read(bp, phy,
4801 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4802 /* Set EDC off by setting OPTXLOS signal input to low
4803 (bit 9).
4804 When the EDC is off it locks onto a reference clock and
4805 avoids becoming 'lost'.*/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004806 mod_abs &= ~(1<<8);
4807 if (!(phy->flags & FLAGS_NOC))
4808 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004809 bnx2x_cl45_write(bp, phy,
4810 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4811
4812
4813 /* Make MOD_ABS give interrupt on change */
4814 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4815 &val);
4816 val |= (1<<12);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004817 if (phy->flags & FLAGS_NOC)
4818 val |= (3<<5);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004819
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004820 /**
4821 * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
4822 * status which reflect SFP+ module over-current
4823 */
4824 if (!(phy->flags & FLAGS_NOC))
4825 val &= 0xff8f; /* Reset bits 4-6 */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004826 bnx2x_cl45_write(bp, phy,
4827 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
4828
4829 bnx2x_8727_power_module(bp, phy, 1);
4830
4831 bnx2x_cl45_read(bp, phy,
4832 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
4833
4834 bnx2x_cl45_read(bp, phy,
4835 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
4836
4837 /* Set option 1G speed */
4838 if (phy->req_line_speed == SPEED_1000) {
4839 DP(NETIF_MSG_LINK, "Setting 1G force\n");
4840 bnx2x_cl45_write(bp, phy,
4841 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
4842 bnx2x_cl45_write(bp, phy,
4843 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
4844 bnx2x_cl45_read(bp, phy,
4845 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
4846 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00004847 /**
4848 * Power down the XAUI until link is up in case of dual-media
4849 * and 1G
4850 */
4851 if (DUAL_MEDIA(params)) {
4852 bnx2x_cl45_read(bp, phy,
4853 MDIO_PMA_DEVAD,
4854 MDIO_PMA_REG_8727_PCS_GP, &val);
4855 val |= (3<<10);
4856 bnx2x_cl45_write(bp, phy,
4857 MDIO_PMA_DEVAD,
4858 MDIO_PMA_REG_8727_PCS_GP, val);
4859 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004860 } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
4861 ((phy->speed_cap_mask &
4862 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
4863 ((phy->speed_cap_mask &
4864 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
4865 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
4866
4867 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
4868 bnx2x_cl45_write(bp, phy,
4869 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
4870 bnx2x_cl45_write(bp, phy,
4871 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
4872 } else {
4873 /**
4874 * Since the 8727 has only single reset pin, need to set the 10G
4875 * registers although it is default
4876 */
4877 bnx2x_cl45_write(bp, phy,
4878 MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
4879 0x0020);
4880 bnx2x_cl45_write(bp, phy,
4881 MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
4882 bnx2x_cl45_write(bp, phy,
4883 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
4884 bnx2x_cl45_write(bp, phy,
4885 MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
4886 0x0008);
4887 }
4888
4889 /* Set 2-wire transfer rate of SFP+ module EEPROM
4890 * to 100Khz since some DACs(direct attached cables) do
4891 * not work at 400Khz.
4892 */
4893 bnx2x_cl45_write(bp, phy,
4894 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
4895 0xa001);
4896
4897 /* Set TX PreEmphasis if needed */
4898 if ((params->feature_config_flags &
4899 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4900 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
4901 phy->tx_preemphasis[0],
4902 phy->tx_preemphasis[1]);
4903 bnx2x_cl45_write(bp, phy,
4904 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
4905 phy->tx_preemphasis[0]);
4906
4907 bnx2x_cl45_write(bp, phy,
4908 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
4909 phy->tx_preemphasis[1]);
4910 }
4911
4912 return 0;
4913}
4914
4915static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
4916 struct link_params *params)
4917{
4918 struct bnx2x *bp = params->bp;
4919 u16 mod_abs, rx_alarm_status;
4920 u32 val = REG_RD(bp, params->shmem_base +
4921 offsetof(struct shmem_region, dev_info.
4922 port_feature_config[params->port].
4923 config));
4924 bnx2x_cl45_read(bp, phy,
4925 MDIO_PMA_DEVAD,
4926 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4927 if (mod_abs & (1<<8)) {
4928
4929 /* Module is absent */
4930 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4931 "show module is absent\n");
4932
4933 /* 1. Set mod_abs to detect next module
4934 presence event
4935 2. Set EDC off by setting OPTXLOS signal input to low
4936 (bit 9).
4937 When the EDC is off it locks onto a reference clock and
4938 avoids becoming 'lost'.*/
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004939 mod_abs &= ~(1<<8);
4940 if (!(phy->flags & FLAGS_NOC))
4941 mod_abs &= ~(1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004942 bnx2x_cl45_write(bp, phy,
4943 MDIO_PMA_DEVAD,
4944 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4945
4946 /* Clear RX alarm since it stays up as long as
4947 the mod_abs wasn't changed */
4948 bnx2x_cl45_read(bp, phy,
4949 MDIO_PMA_DEVAD,
4950 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4951
4952 } else {
4953 /* Module is present */
4954 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4955 "show module is present\n");
4956 /* First thing, disable transmitter,
4957 and if the module is ok, the
4958 module_detection will enable it*/
4959
4960 /* 1. Set mod_abs to detect next module
4961 absent event ( bit 8)
4962 2. Restore the default polarity of the OPRXLOS signal and
4963 this signal will then correctly indicate the presence or
4964 absence of the Rx signal. (bit 9) */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00004965 mod_abs |= (1<<8);
4966 if (!(phy->flags & FLAGS_NOC))
4967 mod_abs |= (1<<9);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00004968 bnx2x_cl45_write(bp, phy,
4969 MDIO_PMA_DEVAD,
4970 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4971
4972 /* Clear RX alarm since it stays up as long as
4973 the mod_abs wasn't changed. This is need to be done
4974 before calling the module detection, otherwise it will clear
4975 the link update alarm */
4976 bnx2x_cl45_read(bp, phy,
4977 MDIO_PMA_DEVAD,
4978 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4979
4980
4981 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4982 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4983 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
4984
4985 if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
4986 bnx2x_sfp_module_detection(phy, params);
4987 else
4988 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
4989 }
4990
4991 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
4992 rx_alarm_status);
4993 /* No need to check link status in case of
4994 module plugged in/out */
4995}
4996
4997static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
4998 struct link_params *params,
4999 struct link_vars *vars)
5000
5001{
5002 struct bnx2x *bp = params->bp;
5003 u8 link_up = 0;
5004 u16 link_status = 0;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005005 u16 rx_alarm_status, lasi_ctrl, val1;
5006
5007 /* If PHY is not initialized, do not check link status */
5008 bnx2x_cl45_read(bp, phy,
5009 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
5010 &lasi_ctrl);
5011 if (!lasi_ctrl)
5012 return 0;
5013
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005014 /* Check the LASI */
5015 bnx2x_cl45_read(bp, phy,
5016 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
5017 &rx_alarm_status);
5018 vars->line_speed = 0;
5019 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
5020
5021 bnx2x_cl45_read(bp, phy,
5022 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5023
5024 DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
5025
5026 /* Clear MSG-OUT */
5027 bnx2x_cl45_read(bp, phy,
5028 MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
5029
5030 /**
5031 * If a module is present and there is need to check
5032 * for over current
5033 */
5034 if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
5035 /* Check over-current using 8727 GPIO0 input*/
5036 bnx2x_cl45_read(bp, phy,
5037 MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
5038 &val1);
5039
5040 if ((val1 & (1<<8)) == 0) {
5041 DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
5042 " on port %d\n", params->port);
5043 netdev_err(bp->dev, "Error: Power fault on Port %d has"
5044 " been detected and the power to "
5045 "that SFP+ module has been removed"
5046 " to prevent failure of the card."
5047 " Please remove the SFP+ module and"
5048 " restart the system to clear this"
5049 " error.\n",
5050 params->port);
5051
5052 /*
5053 * Disable all RX_ALARMs except for
5054 * mod_abs
5055 */
5056 bnx2x_cl45_write(bp, phy,
5057 MDIO_PMA_DEVAD,
5058 MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
5059
5060 bnx2x_cl45_read(bp, phy,
5061 MDIO_PMA_DEVAD,
5062 MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
5063 /* Wait for module_absent_event */
5064 val1 |= (1<<8);
5065 bnx2x_cl45_write(bp, phy,
5066 MDIO_PMA_DEVAD,
5067 MDIO_PMA_REG_PHY_IDENTIFIER, val1);
5068 /* Clear RX alarm */
5069 bnx2x_cl45_read(bp, phy,
5070 MDIO_PMA_DEVAD,
5071 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
5072 return 0;
5073 }
5074 } /* Over current check */
5075
5076 /* When module absent bit is set, check module */
5077 if (rx_alarm_status & (1<<5)) {
5078 bnx2x_8727_handle_mod_abs(phy, params);
5079 /* Enable all mod_abs and link detection bits */
5080 bnx2x_cl45_write(bp, phy,
5081 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
5082 ((1<<5) | (1<<2)));
5083 }
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005084 DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
5085 bnx2x_8727_specific_func(phy, params, ENABLE_TX);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005086 /* If transmitter is disabled, ignore false link up indication */
5087 bnx2x_cl45_read(bp, phy,
5088 MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
5089 if (val1 & (1<<15)) {
5090 DP(NETIF_MSG_LINK, "Tx is disabled\n");
5091 return 0;
5092 }
5093
5094 bnx2x_cl45_read(bp, phy,
5095 MDIO_PMA_DEVAD,
5096 MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
5097
5098 /* Bits 0..2 --> speed detected,
5099 bits 13..15--> link is down */
5100 if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
5101 link_up = 1;
5102 vars->line_speed = SPEED_10000;
5103 } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
5104 link_up = 1;
5105 vars->line_speed = SPEED_1000;
5106 DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
5107 params->port);
5108 } else {
5109 link_up = 0;
5110 DP(NETIF_MSG_LINK, "port %x: External link is down\n",
5111 params->port);
5112 }
5113 if (link_up)
5114 bnx2x_ext_phy_resolve_fc(phy, params, vars);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005115
5116 if ((DUAL_MEDIA(params)) &&
5117 (phy->req_line_speed == SPEED_1000)) {
5118 bnx2x_cl45_read(bp, phy,
5119 MDIO_PMA_DEVAD,
5120 MDIO_PMA_REG_8727_PCS_GP, &val1);
5121 /**
5122 * In case of dual-media board and 1G, power up the XAUI side,
5123 * otherwise power it down. For 10G it is done automatically
5124 */
5125 if (link_up)
5126 val1 &= ~(3<<10);
5127 else
5128 val1 |= (3<<10);
5129 bnx2x_cl45_write(bp, phy,
5130 MDIO_PMA_DEVAD,
5131 MDIO_PMA_REG_8727_PCS_GP, val1);
5132 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005133 return link_up;
5134}
5135
5136static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
5137 struct link_params *params)
5138{
5139 struct bnx2x *bp = params->bp;
5140 /* Disable Transmitter */
5141 bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005142 /* Clear LASI */
5143 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
5144
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005145}
5146
5147/******************************************************************/
5148/* BCM8481/BCM84823/BCM84833 PHY SECTION */
5149/******************************************************************/
5150static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
5151 struct link_params *params)
5152{
5153 u16 val, fw_ver1, fw_ver2, cnt;
5154 struct bnx2x *bp = params->bp;
5155
5156 /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
5157 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
5158 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
5159 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
5160 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
5161 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
5162 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
5163
5164 for (cnt = 0; cnt < 100; cnt++) {
5165 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
5166 if (val & 1)
5167 break;
5168 udelay(5);
5169 }
5170 if (cnt == 100) {
5171 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
5172 bnx2x_save_spirom_version(bp, params->port, 0,
5173 phy->ver_addr);
5174 return;
5175 }
5176
5177
5178 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
5179 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
5180 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
5181 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
5182 for (cnt = 0; cnt < 100; cnt++) {
5183 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
5184 if (val & 1)
5185 break;
5186 udelay(5);
5187 }
5188 if (cnt == 100) {
5189 DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
5190 bnx2x_save_spirom_version(bp, params->port, 0,
5191 phy->ver_addr);
5192 return;
5193 }
5194
5195 /* lower 16 bits of the register SPI_FW_STATUS */
5196 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
5197 /* upper 16 bits of register SPI_FW_STATUS */
5198 bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
5199
5200 bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
5201 phy->ver_addr);
5202}
5203
5204static void bnx2x_848xx_set_led(struct bnx2x *bp,
5205 struct bnx2x_phy *phy)
5206{
5207 u16 val;
5208
5209 /* PHYC_CTL_LED_CTL */
5210 bnx2x_cl45_read(bp, phy,
5211 MDIO_PMA_DEVAD,
5212 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
5213 val &= 0xFE00;
5214 val |= 0x0092;
5215
5216 bnx2x_cl45_write(bp, phy,
5217 MDIO_PMA_DEVAD,
5218 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
5219
5220 bnx2x_cl45_write(bp, phy,
5221 MDIO_PMA_DEVAD,
5222 MDIO_PMA_REG_8481_LED1_MASK,
5223 0x80);
5224
5225 bnx2x_cl45_write(bp, phy,
5226 MDIO_PMA_DEVAD,
5227 MDIO_PMA_REG_8481_LED2_MASK,
5228 0x18);
5229
5230 bnx2x_cl45_write(bp, phy,
5231 MDIO_PMA_DEVAD,
5232 MDIO_PMA_REG_8481_LED3_MASK,
5233 0x0040);
5234
5235 /* 'Interrupt Mask' */
5236 bnx2x_cl45_write(bp, phy,
5237 MDIO_AN_DEVAD,
5238 0xFFFB, 0xFFFD);
5239}
5240
5241static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005242 struct link_params *params,
5243 struct link_vars *vars)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005244{
5245 struct bnx2x *bp = params->bp;
5246 u16 autoneg_val, an_1000_val, an_10_100_val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005247 bnx2x_wait_reset_complete(bp, phy);
5248 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
5249 1 << NIG_LATCH_BC_ENABLE_MI_INT);
5250
5251 bnx2x_cl45_write(bp, phy,
5252 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
5253
5254 bnx2x_848xx_set_led(bp, phy);
5255
5256 /* set 1000 speed advertisement */
5257 bnx2x_cl45_read(bp, phy,
5258 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
5259 &an_1000_val);
5260
5261 bnx2x_ext_phy_set_pause(params, phy, vars);
5262 bnx2x_cl45_read(bp, phy,
5263 MDIO_AN_DEVAD,
5264 MDIO_AN_REG_8481_LEGACY_AN_ADV,
5265 &an_10_100_val);
5266 bnx2x_cl45_read(bp, phy,
5267 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
5268 &autoneg_val);
5269 /* Disable forced speed */
5270 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
5271 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
5272
5273 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5274 (phy->speed_cap_mask &
5275 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
5276 (phy->req_line_speed == SPEED_1000)) {
5277 an_1000_val |= (1<<8);
5278 autoneg_val |= (1<<9 | 1<<12);
5279 if (phy->req_duplex == DUPLEX_FULL)
5280 an_1000_val |= (1<<9);
5281 DP(NETIF_MSG_LINK, "Advertising 1G\n");
5282 } else
5283 an_1000_val &= ~((1<<8) | (1<<9));
5284
5285 bnx2x_cl45_write(bp, phy,
5286 MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
5287 an_1000_val);
5288
5289 /* set 10 speed advertisement */
5290 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5291 (phy->speed_cap_mask &
5292 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
5293 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
5294 an_10_100_val |= (1<<7);
5295 /* Enable autoneg and restart autoneg for legacy speeds */
5296 autoneg_val |= (1<<9 | 1<<12);
5297
5298 if (phy->req_duplex == DUPLEX_FULL)
5299 an_10_100_val |= (1<<8);
5300 DP(NETIF_MSG_LINK, "Advertising 100M\n");
5301 }
5302 /* set 10 speed advertisement */
5303 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5304 (phy->speed_cap_mask &
5305 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
5306 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
5307 an_10_100_val |= (1<<5);
5308 autoneg_val |= (1<<9 | 1<<12);
5309 if (phy->req_duplex == DUPLEX_FULL)
5310 an_10_100_val |= (1<<6);
5311 DP(NETIF_MSG_LINK, "Advertising 10M\n");
5312 }
5313
5314 /* Only 10/100 are allowed to work in FORCE mode */
5315 if (phy->req_line_speed == SPEED_100) {
5316 autoneg_val |= (1<<13);
5317 /* Enabled AUTO-MDIX when autoneg is disabled */
5318 bnx2x_cl45_write(bp, phy,
5319 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
5320 (1<<15 | 1<<9 | 7<<0));
5321 DP(NETIF_MSG_LINK, "Setting 100M force\n");
5322 }
5323 if (phy->req_line_speed == SPEED_10) {
5324 /* Enabled AUTO-MDIX when autoneg is disabled */
5325 bnx2x_cl45_write(bp, phy,
5326 MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
5327 (1<<15 | 1<<9 | 7<<0));
5328 DP(NETIF_MSG_LINK, "Setting 10M force\n");
5329 }
5330
5331 bnx2x_cl45_write(bp, phy,
5332 MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
5333 an_10_100_val);
5334
5335 if (phy->req_duplex == DUPLEX_FULL)
5336 autoneg_val |= (1<<8);
5337
5338 bnx2x_cl45_write(bp, phy,
5339 MDIO_AN_DEVAD,
5340 MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
5341
5342 if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
5343 (phy->speed_cap_mask &
5344 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
5345 (phy->req_line_speed == SPEED_10000)) {
5346 DP(NETIF_MSG_LINK, "Advertising 10G\n");
5347 /* Restart autoneg for 10G*/
5348
5349 bnx2x_cl45_write(bp, phy,
5350 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
5351 0x3200);
5352 } else if (phy->req_line_speed != SPEED_10 &&
5353 phy->req_line_speed != SPEED_100) {
5354 bnx2x_cl45_write(bp, phy,
5355 MDIO_AN_DEVAD,
5356 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
5357 1);
5358 }
5359 /* Save spirom version */
5360 bnx2x_save_848xx_spirom_version(phy, params);
5361
5362 return 0;
5363}
5364
5365static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
5366 struct link_params *params,
5367 struct link_vars *vars)
5368{
5369 struct bnx2x *bp = params->bp;
5370 /* Restore normal power mode*/
5371 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5372 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5373
5374 /* HW reset */
5375 bnx2x_ext_phy_hw_reset(bp, params->port);
5376
5377 bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
5378 return bnx2x_848xx_cmn_config_init(phy, params, vars);
5379}
5380
5381static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
5382 struct link_params *params,
5383 struct link_vars *vars)
5384{
5385 struct bnx2x *bp = params->bp;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005386 u8 port = params->port, initialize = 1;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005387 u16 val;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005388 u16 temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005389 u32 actual_phy_selection;
5390 u8 rc = 0;
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005391
5392 /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
5393
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005394 msleep(1);
5395 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
5396 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005397 port);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005398 msleep(200); /* 100 is not enough */
5399
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005400 /* BCM84823 requires that XGXS links up first @ 10G for normal
5401 behavior */
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005402 temp = vars->line_speed;
5403 vars->line_speed = SPEED_10000;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005404 bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
5405 bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005406 vars->line_speed = temp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005407
5408 /* Set dual-media configuration according to configuration */
5409
5410 bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
5411 MDIO_CTL_REG_84823_MEDIA, &val);
5412 val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
5413 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
5414 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
5415 MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
5416 MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
5417 val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
5418 MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
5419
5420 actual_phy_selection = bnx2x_phy_selection(params);
5421
5422 switch (actual_phy_selection) {
5423 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
5424 /* Do nothing. Essentialy this is like the priority copper */
5425 break;
5426 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
5427 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
5428 break;
5429 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
5430 val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
5431 break;
5432 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
5433 /* Do nothing here. The first PHY won't be initialized at all */
5434 break;
5435 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
5436 val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
5437 initialize = 0;
5438 break;
5439 }
5440 if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
5441 val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
5442
5443 bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
5444 MDIO_CTL_REG_84823_MEDIA, val);
5445 DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
5446 params->multi_phy_config, val);
5447
5448 if (initialize)
5449 rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
5450 else
5451 bnx2x_save_848xx_spirom_version(phy, params);
5452 return rc;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005453}
5454
5455static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
5456 struct link_params *params,
5457 struct link_vars *vars)
5458{
5459 struct bnx2x *bp = params->bp;
5460 u16 val, val1, val2;
5461 u8 link_up = 0;
5462
5463 /* Check 10G-BaseT link status */
5464 /* Check PMD signal ok */
5465 bnx2x_cl45_read(bp, phy,
5466 MDIO_AN_DEVAD, 0xFFFA, &val1);
5467 bnx2x_cl45_read(bp, phy,
5468 MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
5469 &val2);
5470 DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
5471
5472 /* Check link 10G */
5473 if (val2 & (1<<11)) {
5474 vars->line_speed = SPEED_10000;
5475 link_up = 1;
5476 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
5477 } else { /* Check Legacy speed link */
5478 u16 legacy_status, legacy_speed;
5479
5480 /* Enable expansion register 0x42 (Operation mode status) */
5481 bnx2x_cl45_write(bp, phy,
5482 MDIO_AN_DEVAD,
5483 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
5484
5485 /* Get legacy speed operation status */
5486 bnx2x_cl45_read(bp, phy,
5487 MDIO_AN_DEVAD,
5488 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
5489 &legacy_status);
5490
5491 DP(NETIF_MSG_LINK, "Legacy speed status"
5492 " = 0x%x\n", legacy_status);
5493 link_up = ((legacy_status & (1<<11)) == (1<<11));
5494 if (link_up) {
5495 legacy_speed = (legacy_status & (3<<9));
5496 if (legacy_speed == (0<<9))
5497 vars->line_speed = SPEED_10;
5498 else if (legacy_speed == (1<<9))
5499 vars->line_speed = SPEED_100;
5500 else if (legacy_speed == (2<<9))
5501 vars->line_speed = SPEED_1000;
5502 else /* Should not happen */
5503 vars->line_speed = 0;
5504
5505 if (legacy_status & (1<<8))
5506 vars->duplex = DUPLEX_FULL;
5507 else
5508 vars->duplex = DUPLEX_HALF;
5509
5510 DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
5511 " is_duplex_full= %d\n", vars->line_speed,
5512 (vars->duplex == DUPLEX_FULL));
5513 /* Check legacy speed AN resolution */
5514 bnx2x_cl45_read(bp, phy,
5515 MDIO_AN_DEVAD,
5516 MDIO_AN_REG_8481_LEGACY_MII_STATUS,
5517 &val);
5518 if (val & (1<<5))
5519 vars->link_status |=
5520 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
5521 bnx2x_cl45_read(bp, phy,
5522 MDIO_AN_DEVAD,
5523 MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
5524 &val);
5525 if ((val & (1<<0)) == 0)
5526 vars->link_status |=
5527 LINK_STATUS_PARALLEL_DETECTION_USED;
5528 }
5529 }
5530 if (link_up) {
5531 DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
5532 vars->line_speed);
5533 bnx2x_ext_phy_resolve_fc(phy, params, vars);
5534 }
5535
5536 return link_up;
5537}
5538
5539static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
5540{
5541 u8 status = 0;
5542 u32 spirom_ver;
5543 spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
5544 status = bnx2x_format_ver(spirom_ver, str, len);
5545 return status;
5546}
5547
5548static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
5549 struct link_params *params)
5550{
5551 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5552 MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
5553 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5554 MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
5555}
5556
5557static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
5558 struct link_params *params)
5559{
5560 bnx2x_cl45_write(params->bp, phy,
5561 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
5562 bnx2x_cl45_write(params->bp, phy,
5563 MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
5564}
5565
5566static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
5567 struct link_params *params)
5568{
5569 struct bnx2x *bp = params->bp;
5570 u8 port = params->port;
5571 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
5572 MISC_REGISTERS_GPIO_OUTPUT_LOW,
5573 port);
5574}
5575
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005576static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
5577 struct link_params *params, u8 mode)
5578{
5579 struct bnx2x *bp = params->bp;
5580 u16 val;
5581
5582 switch (mode) {
5583 case LED_MODE_OFF:
5584
5585 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", params->port);
5586
5587 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
5588 SHARED_HW_CFG_LED_EXTPHY1) {
5589
5590 /* Set LED masks */
5591 bnx2x_cl45_write(bp, phy,
5592 MDIO_PMA_DEVAD,
5593 MDIO_PMA_REG_8481_LED1_MASK,
5594 0x0);
5595
5596 bnx2x_cl45_write(bp, phy,
5597 MDIO_PMA_DEVAD,
5598 MDIO_PMA_REG_8481_LED2_MASK,
5599 0x0);
5600
5601 bnx2x_cl45_write(bp, phy,
5602 MDIO_PMA_DEVAD,
5603 MDIO_PMA_REG_8481_LED3_MASK,
5604 0x0);
5605
5606 bnx2x_cl45_write(bp, phy,
5607 MDIO_PMA_DEVAD,
5608 MDIO_PMA_REG_8481_LED5_MASK,
5609 0x0);
5610
5611 } else {
5612 bnx2x_cl45_write(bp, phy,
5613 MDIO_PMA_DEVAD,
5614 MDIO_PMA_REG_8481_LED1_MASK,
5615 0x0);
5616 }
5617 break;
5618 case LED_MODE_FRONT_PANEL_OFF:
5619
5620 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
5621 params->port);
5622
5623 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
5624 SHARED_HW_CFG_LED_EXTPHY1) {
5625
5626 /* Set LED masks */
5627 bnx2x_cl45_write(bp, phy,
5628 MDIO_PMA_DEVAD,
5629 MDIO_PMA_REG_8481_LED1_MASK,
5630 0x0);
5631
5632 bnx2x_cl45_write(bp, phy,
5633 MDIO_PMA_DEVAD,
5634 MDIO_PMA_REG_8481_LED2_MASK,
5635 0x0);
5636
5637 bnx2x_cl45_write(bp, phy,
5638 MDIO_PMA_DEVAD,
5639 MDIO_PMA_REG_8481_LED3_MASK,
5640 0x0);
5641
5642 bnx2x_cl45_write(bp, phy,
5643 MDIO_PMA_DEVAD,
5644 MDIO_PMA_REG_8481_LED5_MASK,
5645 0x20);
5646
5647 } else {
5648 bnx2x_cl45_write(bp, phy,
5649 MDIO_PMA_DEVAD,
5650 MDIO_PMA_REG_8481_LED1_MASK,
5651 0x0);
5652 }
5653 break;
5654 case LED_MODE_ON:
5655
5656 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", params->port);
5657
5658 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
5659 SHARED_HW_CFG_LED_EXTPHY1) {
5660 /* Set control reg */
5661 bnx2x_cl45_read(bp, phy,
5662 MDIO_PMA_DEVAD,
5663 MDIO_PMA_REG_8481_LINK_SIGNAL,
5664 &val);
5665 val &= 0x8000;
5666 val |= 0x2492;
5667
5668 bnx2x_cl45_write(bp, phy,
5669 MDIO_PMA_DEVAD,
5670 MDIO_PMA_REG_8481_LINK_SIGNAL,
5671 val);
5672
5673 /* Set LED masks */
5674 bnx2x_cl45_write(bp, phy,
5675 MDIO_PMA_DEVAD,
5676 MDIO_PMA_REG_8481_LED1_MASK,
5677 0x0);
5678
5679 bnx2x_cl45_write(bp, phy,
5680 MDIO_PMA_DEVAD,
5681 MDIO_PMA_REG_8481_LED2_MASK,
5682 0x20);
5683
5684 bnx2x_cl45_write(bp, phy,
5685 MDIO_PMA_DEVAD,
5686 MDIO_PMA_REG_8481_LED3_MASK,
5687 0x20);
5688
5689 bnx2x_cl45_write(bp, phy,
5690 MDIO_PMA_DEVAD,
5691 MDIO_PMA_REG_8481_LED5_MASK,
5692 0x0);
5693 } else {
5694 bnx2x_cl45_write(bp, phy,
5695 MDIO_PMA_DEVAD,
5696 MDIO_PMA_REG_8481_LED1_MASK,
5697 0x20);
5698 }
5699 break;
5700
5701 case LED_MODE_OPER:
5702
5703 DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", params->port);
5704
5705 if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
5706 SHARED_HW_CFG_LED_EXTPHY1) {
5707
5708 /* Set control reg */
5709 bnx2x_cl45_read(bp, phy,
5710 MDIO_PMA_DEVAD,
5711 MDIO_PMA_REG_8481_LINK_SIGNAL,
5712 &val);
5713
5714 if (!((val &
5715 MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
5716 >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)){
5717 DP(NETIF_MSG_LINK, "Seting LINK_SIGNAL\n");
5718 bnx2x_cl45_write(bp, phy,
5719 MDIO_PMA_DEVAD,
5720 MDIO_PMA_REG_8481_LINK_SIGNAL,
5721 0xa492);
5722 }
5723
5724 /* Set LED masks */
5725 bnx2x_cl45_write(bp, phy,
5726 MDIO_PMA_DEVAD,
5727 MDIO_PMA_REG_8481_LED1_MASK,
5728 0x10);
5729
5730 bnx2x_cl45_write(bp, phy,
5731 MDIO_PMA_DEVAD,
5732 MDIO_PMA_REG_8481_LED2_MASK,
5733 0x80);
5734
5735 bnx2x_cl45_write(bp, phy,
5736 MDIO_PMA_DEVAD,
5737 MDIO_PMA_REG_8481_LED3_MASK,
5738 0x98);
5739
5740 bnx2x_cl45_write(bp, phy,
5741 MDIO_PMA_DEVAD,
5742 MDIO_PMA_REG_8481_LED5_MASK,
5743 0x40);
5744
5745 } else {
5746 bnx2x_cl45_write(bp, phy,
5747 MDIO_PMA_DEVAD,
5748 MDIO_PMA_REG_8481_LED1_MASK,
5749 0x80);
5750 }
5751 break;
5752 }
5753}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005754/******************************************************************/
5755/* SFX7101 PHY SECTION */
5756/******************************************************************/
5757static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
5758 struct link_params *params)
5759{
5760 struct bnx2x *bp = params->bp;
5761 /* SFX7101_XGXS_TEST1 */
5762 bnx2x_cl45_write(bp, phy,
5763 MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
5764}
5765
5766static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
5767 struct link_params *params,
5768 struct link_vars *vars)
5769{
5770 u16 fw_ver1, fw_ver2, val;
5771 struct bnx2x *bp = params->bp;
5772 DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
5773
5774 /* Restore normal power mode*/
5775 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5776 MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
5777 /* HW reset */
5778 bnx2x_ext_phy_hw_reset(bp, params->port);
5779 bnx2x_wait_reset_complete(bp, phy);
5780
5781 bnx2x_cl45_write(bp, phy,
5782 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
5783 DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
5784 bnx2x_cl45_write(bp, phy,
5785 MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
5786
5787 bnx2x_ext_phy_set_pause(params, phy, vars);
5788 /* Restart autoneg */
5789 bnx2x_cl45_read(bp, phy,
5790 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
5791 val |= 0x200;
5792 bnx2x_cl45_write(bp, phy,
5793 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
5794
5795 /* Save spirom version */
5796 bnx2x_cl45_read(bp, phy,
5797 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
5798
5799 bnx2x_cl45_read(bp, phy,
5800 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
5801 bnx2x_save_spirom_version(bp, params->port,
5802 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
5803 return 0;
5804}
5805
5806static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
5807 struct link_params *params,
5808 struct link_vars *vars)
5809{
5810 struct bnx2x *bp = params->bp;
5811 u8 link_up;
5812 u16 val1, val2;
5813 bnx2x_cl45_read(bp, phy,
5814 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
5815 bnx2x_cl45_read(bp, phy,
5816 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
5817 DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
5818 val2, val1);
5819 bnx2x_cl45_read(bp, phy,
5820 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
5821 bnx2x_cl45_read(bp, phy,
5822 MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
5823 DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
5824 val2, val1);
5825 link_up = ((val1 & 4) == 4);
5826 /* if link is up
5827 * print the AN outcome of the SFX7101 PHY
5828 */
5829 if (link_up) {
5830 bnx2x_cl45_read(bp, phy,
5831 MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
5832 &val2);
5833 vars->line_speed = SPEED_10000;
5834 DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
5835 val2, (val2 & (1<<14)));
5836 bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
5837 bnx2x_ext_phy_resolve_fc(phy, params, vars);
5838 }
5839 return link_up;
5840}
5841
5842
5843static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
5844{
5845 if (*len < 5)
5846 return -EINVAL;
5847 str[0] = (spirom_ver & 0xFF);
5848 str[1] = (spirom_ver & 0xFF00) >> 8;
5849 str[2] = (spirom_ver & 0xFF0000) >> 16;
5850 str[3] = (spirom_ver & 0xFF000000) >> 24;
5851 str[4] = '\0';
5852 *len -= 5;
5853 return 0;
5854}
5855
5856void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
5857{
5858 u16 val, cnt;
5859
5860 bnx2x_cl45_read(bp, phy,
5861 MDIO_PMA_DEVAD,
5862 MDIO_PMA_REG_7101_RESET, &val);
5863
5864 for (cnt = 0; cnt < 10; cnt++) {
5865 msleep(50);
5866 /* Writes a self-clearing reset */
5867 bnx2x_cl45_write(bp, phy,
5868 MDIO_PMA_DEVAD,
5869 MDIO_PMA_REG_7101_RESET,
5870 (val | (1<<15)));
5871 /* Wait for clear */
5872 bnx2x_cl45_read(bp, phy,
5873 MDIO_PMA_DEVAD,
5874 MDIO_PMA_REG_7101_RESET, &val);
5875
5876 if ((val & (1<<15)) == 0)
5877 break;
5878 }
5879}
5880
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005881static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
5882 struct link_params *params) {
5883 /* Low power mode is controlled by GPIO 2 */
5884 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
5885 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
5886 /* The PHY reset is controlled by GPIO 1 */
5887 bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
5888 MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
5889}
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00005890
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00005891static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
5892 struct link_params *params, u8 mode)
5893{
5894 u16 val = 0;
5895 struct bnx2x *bp = params->bp;
5896 switch (mode) {
5897 case LED_MODE_FRONT_PANEL_OFF:
5898 case LED_MODE_OFF:
5899 val = 2;
5900 break;
5901 case LED_MODE_ON:
5902 val = 1;
5903 break;
5904 case LED_MODE_OPER:
5905 val = 0;
5906 break;
5907 }
5908 bnx2x_cl45_write(bp, phy,
5909 MDIO_PMA_DEVAD,
5910 MDIO_PMA_REG_7107_LINK_LED_CNTL,
5911 val);
5912}
5913
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005914/******************************************************************/
5915/* STATIC PHY DECLARATION */
5916/******************************************************************/
5917
5918static struct bnx2x_phy phy_null = {
5919 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
5920 .addr = 0,
5921 .flags = FLAGS_INIT_XGXS_FIRST,
5922 .def_md_devad = 0,
5923 .reserved = 0,
5924 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5925 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5926 .mdio_ctrl = 0,
5927 .supported = 0,
5928 .media_type = ETH_PHY_NOT_PRESENT,
5929 .ver_addr = 0,
5930 .req_flow_ctrl = 0,
5931 .req_line_speed = 0,
5932 .speed_cap_mask = 0,
5933 .req_duplex = 0,
5934 .rsrv = 0,
5935 .config_init = (config_init_t)NULL,
5936 .read_status = (read_status_t)NULL,
5937 .link_reset = (link_reset_t)NULL,
5938 .config_loopback = (config_loopback_t)NULL,
5939 .format_fw_ver = (format_fw_ver_t)NULL,
5940 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005941 .set_link_led = (set_link_led_t)NULL,
5942 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005943};
5944
5945static struct bnx2x_phy phy_serdes = {
5946 .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
5947 .addr = 0xff,
5948 .flags = 0,
5949 .def_md_devad = 0,
5950 .reserved = 0,
5951 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5952 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5953 .mdio_ctrl = 0,
5954 .supported = (SUPPORTED_10baseT_Half |
5955 SUPPORTED_10baseT_Full |
5956 SUPPORTED_100baseT_Half |
5957 SUPPORTED_100baseT_Full |
5958 SUPPORTED_1000baseT_Full |
5959 SUPPORTED_2500baseX_Full |
5960 SUPPORTED_TP |
5961 SUPPORTED_Autoneg |
5962 SUPPORTED_Pause |
5963 SUPPORTED_Asym_Pause),
5964 .media_type = ETH_PHY_UNSPECIFIED,
5965 .ver_addr = 0,
5966 .req_flow_ctrl = 0,
5967 .req_line_speed = 0,
5968 .speed_cap_mask = 0,
5969 .req_duplex = 0,
5970 .rsrv = 0,
5971 .config_init = (config_init_t)bnx2x_init_serdes,
5972 .read_status = (read_status_t)bnx2x_link_settings_status,
5973 .link_reset = (link_reset_t)bnx2x_int_link_reset,
5974 .config_loopback = (config_loopback_t)NULL,
5975 .format_fw_ver = (format_fw_ver_t)NULL,
5976 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00005977 .set_link_led = (set_link_led_t)NULL,
5978 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00005979};
5980
5981static struct bnx2x_phy phy_xgxs = {
5982 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
5983 .addr = 0xff,
5984 .flags = 0,
5985 .def_md_devad = 0,
5986 .reserved = 0,
5987 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5988 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
5989 .mdio_ctrl = 0,
5990 .supported = (SUPPORTED_10baseT_Half |
5991 SUPPORTED_10baseT_Full |
5992 SUPPORTED_100baseT_Half |
5993 SUPPORTED_100baseT_Full |
5994 SUPPORTED_1000baseT_Full |
5995 SUPPORTED_2500baseX_Full |
5996 SUPPORTED_10000baseT_Full |
5997 SUPPORTED_FIBRE |
5998 SUPPORTED_Autoneg |
5999 SUPPORTED_Pause |
6000 SUPPORTED_Asym_Pause),
6001 .media_type = ETH_PHY_UNSPECIFIED,
6002 .ver_addr = 0,
6003 .req_flow_ctrl = 0,
6004 .req_line_speed = 0,
6005 .speed_cap_mask = 0,
6006 .req_duplex = 0,
6007 .rsrv = 0,
6008 .config_init = (config_init_t)bnx2x_init_xgxs,
6009 .read_status = (read_status_t)bnx2x_link_settings_status,
6010 .link_reset = (link_reset_t)bnx2x_int_link_reset,
6011 .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
6012 .format_fw_ver = (format_fw_ver_t)NULL,
6013 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006014 .set_link_led = (set_link_led_t)NULL,
6015 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006016};
6017
6018static struct bnx2x_phy phy_7101 = {
6019 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6020 .addr = 0xff,
6021 .flags = FLAGS_FAN_FAILURE_DET_REQ,
6022 .def_md_devad = 0,
6023 .reserved = 0,
6024 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6025 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6026 .mdio_ctrl = 0,
6027 .supported = (SUPPORTED_10000baseT_Full |
6028 SUPPORTED_TP |
6029 SUPPORTED_Autoneg |
6030 SUPPORTED_Pause |
6031 SUPPORTED_Asym_Pause),
6032 .media_type = ETH_PHY_BASE_T,
6033 .ver_addr = 0,
6034 .req_flow_ctrl = 0,
6035 .req_line_speed = 0,
6036 .speed_cap_mask = 0,
6037 .req_duplex = 0,
6038 .rsrv = 0,
6039 .config_init = (config_init_t)bnx2x_7101_config_init,
6040 .read_status = (read_status_t)bnx2x_7101_read_status,
6041 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6042 .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
6043 .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
6044 .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006045 .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006046 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006047};
6048static struct bnx2x_phy phy_8073 = {
6049 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6050 .addr = 0xff,
6051 .flags = FLAGS_HW_LOCK_REQUIRED,
6052 .def_md_devad = 0,
6053 .reserved = 0,
6054 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6055 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6056 .mdio_ctrl = 0,
6057 .supported = (SUPPORTED_10000baseT_Full |
6058 SUPPORTED_2500baseX_Full |
6059 SUPPORTED_1000baseT_Full |
6060 SUPPORTED_FIBRE |
6061 SUPPORTED_Autoneg |
6062 SUPPORTED_Pause |
6063 SUPPORTED_Asym_Pause),
6064 .media_type = ETH_PHY_UNSPECIFIED,
6065 .ver_addr = 0,
6066 .req_flow_ctrl = 0,
6067 .req_line_speed = 0,
6068 .speed_cap_mask = 0,
6069 .req_duplex = 0,
6070 .rsrv = 0,
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006071 .config_init = (config_init_t)bnx2x_8073_config_init,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006072 .read_status = (read_status_t)bnx2x_8073_read_status,
6073 .link_reset = (link_reset_t)bnx2x_8073_link_reset,
6074 .config_loopback = (config_loopback_t)NULL,
6075 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6076 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006077 .set_link_led = (set_link_led_t)NULL,
6078 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006079};
6080static struct bnx2x_phy phy_8705 = {
6081 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
6082 .addr = 0xff,
6083 .flags = FLAGS_INIT_XGXS_FIRST,
6084 .def_md_devad = 0,
6085 .reserved = 0,
6086 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6087 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6088 .mdio_ctrl = 0,
6089 .supported = (SUPPORTED_10000baseT_Full |
6090 SUPPORTED_FIBRE |
6091 SUPPORTED_Pause |
6092 SUPPORTED_Asym_Pause),
6093 .media_type = ETH_PHY_XFP_FIBER,
6094 .ver_addr = 0,
6095 .req_flow_ctrl = 0,
6096 .req_line_speed = 0,
6097 .speed_cap_mask = 0,
6098 .req_duplex = 0,
6099 .rsrv = 0,
6100 .config_init = (config_init_t)bnx2x_8705_config_init,
6101 .read_status = (read_status_t)bnx2x_8705_read_status,
6102 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6103 .config_loopback = (config_loopback_t)NULL,
6104 .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
6105 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006106 .set_link_led = (set_link_led_t)NULL,
6107 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006108};
6109static struct bnx2x_phy phy_8706 = {
6110 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
6111 .addr = 0xff,
6112 .flags = FLAGS_INIT_XGXS_FIRST,
6113 .def_md_devad = 0,
6114 .reserved = 0,
6115 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6116 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6117 .mdio_ctrl = 0,
6118 .supported = (SUPPORTED_10000baseT_Full |
6119 SUPPORTED_1000baseT_Full |
6120 SUPPORTED_FIBRE |
6121 SUPPORTED_Pause |
6122 SUPPORTED_Asym_Pause),
6123 .media_type = ETH_PHY_SFP_FIBER,
6124 .ver_addr = 0,
6125 .req_flow_ctrl = 0,
6126 .req_line_speed = 0,
6127 .speed_cap_mask = 0,
6128 .req_duplex = 0,
6129 .rsrv = 0,
6130 .config_init = (config_init_t)bnx2x_8706_config_init,
6131 .read_status = (read_status_t)bnx2x_8706_read_status,
6132 .link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
6133 .config_loopback = (config_loopback_t)NULL,
6134 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6135 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006136 .set_link_led = (set_link_led_t)NULL,
6137 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006138};
6139
6140static struct bnx2x_phy phy_8726 = {
6141 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
6142 .addr = 0xff,
6143 .flags = (FLAGS_HW_LOCK_REQUIRED |
6144 FLAGS_INIT_XGXS_FIRST),
6145 .def_md_devad = 0,
6146 .reserved = 0,
6147 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6148 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6149 .mdio_ctrl = 0,
6150 .supported = (SUPPORTED_10000baseT_Full |
6151 SUPPORTED_1000baseT_Full |
6152 SUPPORTED_Autoneg |
6153 SUPPORTED_FIBRE |
6154 SUPPORTED_Pause |
6155 SUPPORTED_Asym_Pause),
6156 .media_type = ETH_PHY_SFP_FIBER,
6157 .ver_addr = 0,
6158 .req_flow_ctrl = 0,
6159 .req_line_speed = 0,
6160 .speed_cap_mask = 0,
6161 .req_duplex = 0,
6162 .rsrv = 0,
6163 .config_init = (config_init_t)bnx2x_8726_config_init,
6164 .read_status = (read_status_t)bnx2x_8726_read_status,
6165 .link_reset = (link_reset_t)bnx2x_8726_link_reset,
6166 .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
6167 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6168 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006169 .set_link_led = (set_link_led_t)NULL,
6170 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006171};
6172
6173static struct bnx2x_phy phy_8727 = {
6174 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6175 .addr = 0xff,
6176 .flags = FLAGS_FAN_FAILURE_DET_REQ,
6177 .def_md_devad = 0,
6178 .reserved = 0,
6179 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6180 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6181 .mdio_ctrl = 0,
6182 .supported = (SUPPORTED_10000baseT_Full |
6183 SUPPORTED_1000baseT_Full |
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006184 SUPPORTED_FIBRE |
6185 SUPPORTED_Pause |
6186 SUPPORTED_Asym_Pause),
6187 .media_type = ETH_PHY_SFP_FIBER,
6188 .ver_addr = 0,
6189 .req_flow_ctrl = 0,
6190 .req_line_speed = 0,
6191 .speed_cap_mask = 0,
6192 .req_duplex = 0,
6193 .rsrv = 0,
6194 .config_init = (config_init_t)bnx2x_8727_config_init,
6195 .read_status = (read_status_t)bnx2x_8727_read_status,
6196 .link_reset = (link_reset_t)bnx2x_8727_link_reset,
6197 .config_loopback = (config_loopback_t)NULL,
6198 .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
6199 .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006200 .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006201 .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006202};
6203static struct bnx2x_phy phy_8481 = {
6204 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
6205 .addr = 0xff,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006206 .flags = FLAGS_FAN_FAILURE_DET_REQ |
6207 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006208 .def_md_devad = 0,
6209 .reserved = 0,
6210 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6211 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6212 .mdio_ctrl = 0,
6213 .supported = (SUPPORTED_10baseT_Half |
6214 SUPPORTED_10baseT_Full |
6215 SUPPORTED_100baseT_Half |
6216 SUPPORTED_100baseT_Full |
6217 SUPPORTED_1000baseT_Full |
6218 SUPPORTED_10000baseT_Full |
6219 SUPPORTED_TP |
6220 SUPPORTED_Autoneg |
6221 SUPPORTED_Pause |
6222 SUPPORTED_Asym_Pause),
6223 .media_type = ETH_PHY_BASE_T,
6224 .ver_addr = 0,
6225 .req_flow_ctrl = 0,
6226 .req_line_speed = 0,
6227 .speed_cap_mask = 0,
6228 .req_duplex = 0,
6229 .rsrv = 0,
6230 .config_init = (config_init_t)bnx2x_8481_config_init,
6231 .read_status = (read_status_t)bnx2x_848xx_read_status,
6232 .link_reset = (link_reset_t)bnx2x_8481_link_reset,
6233 .config_loopback = (config_loopback_t)NULL,
6234 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
6235 .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006236 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006237 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006238};
6239
6240static struct bnx2x_phy phy_84823 = {
6241 .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
6242 .addr = 0xff,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006243 .flags = FLAGS_FAN_FAILURE_DET_REQ |
6244 FLAGS_REARM_LATCH_SIGNAL,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006245 .def_md_devad = 0,
6246 .reserved = 0,
6247 .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6248 .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
6249 .mdio_ctrl = 0,
6250 .supported = (SUPPORTED_10baseT_Half |
6251 SUPPORTED_10baseT_Full |
6252 SUPPORTED_100baseT_Half |
6253 SUPPORTED_100baseT_Full |
6254 SUPPORTED_1000baseT_Full |
6255 SUPPORTED_10000baseT_Full |
6256 SUPPORTED_TP |
6257 SUPPORTED_Autoneg |
6258 SUPPORTED_Pause |
6259 SUPPORTED_Asym_Pause),
6260 .media_type = ETH_PHY_BASE_T,
6261 .ver_addr = 0,
6262 .req_flow_ctrl = 0,
6263 .req_line_speed = 0,
6264 .speed_cap_mask = 0,
6265 .req_duplex = 0,
6266 .rsrv = 0,
6267 .config_init = (config_init_t)bnx2x_848x3_config_init,
6268 .read_status = (read_status_t)bnx2x_848xx_read_status,
6269 .link_reset = (link_reset_t)bnx2x_848x3_link_reset,
6270 .config_loopback = (config_loopback_t)NULL,
6271 .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
6272 .hw_reset = (hw_reset_t)NULL,
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006273 .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006274 .phy_specific_func = (phy_specific_func_t)NULL
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006275};
6276
6277/*****************************************************************/
6278/* */
6279/* Populate the phy according. Main function: bnx2x_populate_phy */
6280/* */
6281/*****************************************************************/
6282
6283static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
6284 struct bnx2x_phy *phy, u8 port,
6285 u8 phy_index)
6286{
6287 /* Get the 4 lanes xgxs config rx and tx */
6288 u32 rx = 0, tx = 0, i;
6289 for (i = 0; i < 2; i++) {
6290 /**
6291 * INT_PHY and EXT_PHY1 share the same value location in the
6292 * shmem. When num_phys is greater than 1, than this value
6293 * applies only to EXT_PHY1
6294 */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006295 if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
6296 rx = REG_RD(bp, shmem_base +
6297 offsetof(struct shmem_region,
6298 dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006299
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006300 tx = REG_RD(bp, shmem_base +
6301 offsetof(struct shmem_region,
6302 dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
6303 } else {
6304 rx = REG_RD(bp, shmem_base +
6305 offsetof(struct shmem_region,
6306 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006307
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006308 tx = REG_RD(bp, shmem_base +
6309 offsetof(struct shmem_region,
6310 dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
6311 }
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006312
6313 phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
6314 phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
6315
6316 phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
6317 phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
6318 }
6319}
6320
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006321static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
6322 u8 phy_index, u8 port)
6323{
6324 u32 ext_phy_config = 0;
6325 switch (phy_index) {
6326 case EXT_PHY1:
6327 ext_phy_config = REG_RD(bp, shmem_base +
6328 offsetof(struct shmem_region,
6329 dev_info.port_hw_config[port].external_phy_config));
6330 break;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006331 case EXT_PHY2:
6332 ext_phy_config = REG_RD(bp, shmem_base +
6333 offsetof(struct shmem_region,
6334 dev_info.port_hw_config[port].external_phy_config2));
6335 break;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006336 default:
6337 DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
6338 return -EINVAL;
6339 }
6340
6341 return ext_phy_config;
6342}
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006343static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
6344 struct bnx2x_phy *phy)
6345{
6346 u32 phy_addr;
6347 u32 chip_id;
6348 u32 switch_cfg = (REG_RD(bp, shmem_base +
6349 offsetof(struct shmem_region,
6350 dev_info.port_feature_config[port].link_config)) &
6351 PORT_FEATURE_CONNECTED_SWITCH_MASK);
6352 chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
6353 switch (switch_cfg) {
6354 case SWITCH_CFG_1G:
6355 phy_addr = REG_RD(bp,
6356 NIG_REG_SERDES0_CTRL_PHY_ADDR +
6357 port * 0x10);
6358 *phy = phy_serdes;
6359 break;
6360 case SWITCH_CFG_10G:
6361 phy_addr = REG_RD(bp,
6362 NIG_REG_XGXS0_CTRL_PHY_ADDR +
6363 port * 0x18);
6364 *phy = phy_xgxs;
6365 break;
6366 default:
6367 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
6368 return -EINVAL;
6369 }
6370 phy->addr = (u8)phy_addr;
6371 phy->mdio_ctrl = bnx2x_get_emac_base(bp,
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006372 SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006373 port);
6374 phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
6375
6376 DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
6377 port, phy->addr, phy->mdio_ctrl);
6378
6379 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
6380 return 0;
6381}
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006382
6383static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
6384 u8 phy_index,
6385 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006386 u32 shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006387 u8 port,
6388 struct bnx2x_phy *phy)
6389{
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006390 u32 ext_phy_config, phy_type, config2;
6391 u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006392 ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
6393 phy_index, port);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006394 phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
6395 /* Select the phy type */
6396 switch (phy_type) {
6397 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006398 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006399 *phy = phy_8073;
6400 break;
6401 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
6402 *phy = phy_8705;
6403 break;
6404 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
6405 *phy = phy_8706;
6406 break;
6407 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006408 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006409 *phy = phy_8726;
6410 break;
6411 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6412 /* BCM8727_NOC => BCM8727 no over current */
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006413 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006414 *phy = phy_8727;
6415 phy->flags |= FLAGS_NOC;
6416 break;
6417 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006418 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006419 *phy = phy_8727;
6420 break;
6421 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
6422 *phy = phy_8481;
6423 break;
6424 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
6425 *phy = phy_84823;
6426 break;
6427 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
6428 *phy = phy_7101;
6429 break;
6430 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
6431 *phy = phy_null;
6432 return -EINVAL;
6433 default:
6434 *phy = phy_null;
6435 return 0;
6436 }
6437
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006438 phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006439 bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
Yaniv Rosner62b29a52010-09-07 11:40:58 +00006440
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006441 /**
6442 * The shmem address of the phy version is located on different
6443 * structures. In case this structure is too old, do not set
6444 * the address
6445 */
6446 config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
6447 dev_info.shared_hw_config.config2));
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006448 if (phy_index == EXT_PHY1) {
6449 phy->ver_addr = shmem_base + offsetof(struct shmem_region,
6450 port_mb[port].ext_phy_fw_version);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006451
6452 /* Check specific mdc mdio settings */
6453 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
6454 mdc_mdio_access = config2 &
6455 SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006456 } else {
6457 u32 size = REG_RD(bp, shmem2_base);
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006458
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006459 if (size >
6460 offsetof(struct shmem2_region, ext_phy_fw_version2)) {
6461 phy->ver_addr = shmem2_base +
6462 offsetof(struct shmem2_region,
6463 ext_phy_fw_version2[port]);
6464 }
6465 /* Check specific mdc mdio settings */
6466 if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
6467 mdc_mdio_access = (config2 &
6468 SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
6469 (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
6470 SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
6471 }
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006472 phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
6473
6474 /**
6475 * In case mdc/mdio_access of the external phy is different than the
6476 * mdc/mdio access of the XGXS, a HW lock must be taken in each access
6477 * to prevent one port interfere with another port's CL45 operations.
6478 */
6479 if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
6480 phy->flags |= FLAGS_HW_LOCK_REQUIRED;
6481 DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
6482 phy_type, port, phy_index);
6483 DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n",
6484 phy->addr, phy->mdio_ctrl);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006485 return 0;
6486}
6487
6488static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006489 u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006490{
6491 u8 status = 0;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006492 phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
6493 if (phy_index == INT_PHY)
6494 return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006495 status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006496 port, phy);
6497 return status;
6498}
6499
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006500static void bnx2x_phy_def_cfg(struct link_params *params,
6501 struct bnx2x_phy *phy,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006502 u8 phy_index)
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006503{
6504 struct bnx2x *bp = params->bp;
6505 u32 link_config;
6506 /* Populate the default phy configuration for MF mode */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006507 if (phy_index == EXT_PHY2) {
6508 link_config = REG_RD(bp, params->shmem_base +
6509 offsetof(struct shmem_region, dev_info.
6510 port_feature_config[params->port].link_config2));
6511 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
6512 offsetof(struct shmem_region, dev_info.
6513 port_hw_config[params->port].speed_capability_mask2));
6514 } else {
6515 link_config = REG_RD(bp, params->shmem_base +
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006516 offsetof(struct shmem_region, dev_info.
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006517 port_feature_config[params->port].link_config));
6518 phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
6519 offsetof(struct shmem_region, dev_info.
6520 port_hw_config[params->port].speed_capability_mask));
6521 }
6522 DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
6523 " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006524
6525 phy->req_duplex = DUPLEX_FULL;
6526 switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
6527 case PORT_FEATURE_LINK_SPEED_10M_HALF:
6528 phy->req_duplex = DUPLEX_HALF;
6529 case PORT_FEATURE_LINK_SPEED_10M_FULL:
6530 phy->req_line_speed = SPEED_10;
6531 break;
6532 case PORT_FEATURE_LINK_SPEED_100M_HALF:
6533 phy->req_duplex = DUPLEX_HALF;
6534 case PORT_FEATURE_LINK_SPEED_100M_FULL:
6535 phy->req_line_speed = SPEED_100;
6536 break;
6537 case PORT_FEATURE_LINK_SPEED_1G:
6538 phy->req_line_speed = SPEED_1000;
6539 break;
6540 case PORT_FEATURE_LINK_SPEED_2_5G:
6541 phy->req_line_speed = SPEED_2500;
6542 break;
6543 case PORT_FEATURE_LINK_SPEED_10G_CX4:
6544 phy->req_line_speed = SPEED_10000;
6545 break;
6546 default:
6547 phy->req_line_speed = SPEED_AUTO_NEG;
6548 break;
6549 }
6550
6551 switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
6552 case PORT_FEATURE_FLOW_CONTROL_AUTO:
6553 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
6554 break;
6555 case PORT_FEATURE_FLOW_CONTROL_TX:
6556 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
6557 break;
6558 case PORT_FEATURE_FLOW_CONTROL_RX:
6559 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
6560 break;
6561 case PORT_FEATURE_FLOW_CONTROL_BOTH:
6562 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
6563 break;
6564 default:
6565 phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6566 break;
6567 }
6568}
6569
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006570u32 bnx2x_phy_selection(struct link_params *params)
6571{
6572 u32 phy_config_swapped, prio_cfg;
6573 u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
6574
6575 phy_config_swapped = params->multi_phy_config &
6576 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
6577
6578 prio_cfg = params->multi_phy_config &
6579 PORT_HW_CFG_PHY_SELECTION_MASK;
6580
6581 if (phy_config_swapped) {
6582 switch (prio_cfg) {
6583 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
6584 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
6585 break;
6586 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
6587 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
6588 break;
6589 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
6590 return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
6591 break;
6592 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
6593 return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
6594 break;
6595 }
6596 } else
6597 return_cfg = prio_cfg;
6598
6599 return return_cfg;
6600}
6601
6602
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006603u8 bnx2x_phy_probe(struct link_params *params)
6604{
6605 u8 phy_index, actual_phy_idx, link_cfg_idx;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006606 u32 phy_config_swapped;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006607 struct bnx2x *bp = params->bp;
6608 struct bnx2x_phy *phy;
6609 params->num_phys = 0;
6610 DP(NETIF_MSG_LINK, "Begin phy probe\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006611 phy_config_swapped = params->multi_phy_config &
6612 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006613
6614 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
6615 phy_index++) {
6616 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
6617 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006618 if (phy_config_swapped) {
6619 if (phy_index == EXT_PHY1)
6620 actual_phy_idx = EXT_PHY2;
6621 else if (phy_index == EXT_PHY2)
6622 actual_phy_idx = EXT_PHY1;
6623 }
6624 DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
6625 " actual_phy_idx %x\n", phy_config_swapped,
6626 phy_index, actual_phy_idx);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006627 phy = &params->phy[actual_phy_idx];
6628 if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006629 params->shmem2_base, params->port,
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006630 phy) != 0) {
6631 params->num_phys = 0;
6632 DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
6633 phy_index);
6634 for (phy_index = INT_PHY;
6635 phy_index < MAX_PHYS;
6636 phy_index++)
6637 *phy = phy_null;
6638 return -EINVAL;
6639 }
6640 if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
6641 break;
6642
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006643 bnx2x_phy_def_cfg(params, phy, phy_index);
Yaniv Rosnerb7737c92010-09-07 11:40:54 +00006644 params->num_phys++;
6645 }
6646
6647 DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
6648 return 0;
6649}
6650
6651u32 bnx2x_supported_attr(struct link_params *params, u8 phy_idx)
6652{
6653 if (phy_idx < params->num_phys)
6654 return params->phy[phy_idx].supported;
6655 return 0;
6656}
6657
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006658static void set_phy_vars(struct link_params *params)
6659{
6660 struct bnx2x *bp = params->bp;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006661 u8 actual_phy_idx, phy_index, link_cfg_idx;
6662 u8 phy_config_swapped = params->multi_phy_config &
6663 PORT_HW_CFG_PHY_SWAPPED_ENABLED;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006664 for (phy_index = INT_PHY; phy_index < params->num_phys;
6665 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006666 link_cfg_idx = LINK_CONFIG_IDX(phy_index);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006667 actual_phy_idx = phy_index;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006668 if (phy_config_swapped) {
6669 if (phy_index == EXT_PHY1)
6670 actual_phy_idx = EXT_PHY2;
6671 else if (phy_index == EXT_PHY2)
6672 actual_phy_idx = EXT_PHY1;
6673 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006674 params->phy[actual_phy_idx].req_flow_ctrl =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006675 params->req_flow_ctrl[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006676
6677 params->phy[actual_phy_idx].req_line_speed =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006678 params->req_line_speed[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006679
6680 params->phy[actual_phy_idx].speed_cap_mask =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006681 params->speed_cap_mask[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006682
6683 params->phy[actual_phy_idx].req_duplex =
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006684 params->req_duplex[link_cfg_idx];
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006685
6686 DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
6687 " speed_cap_mask %x\n",
6688 params->phy[actual_phy_idx].req_flow_ctrl,
6689 params->phy[actual_phy_idx].req_line_speed,
6690 params->phy[actual_phy_idx].speed_cap_mask);
6691 }
6692}
6693
6694u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
6695{
6696 struct bnx2x *bp = params->bp;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006697 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006698 DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
6699 params->req_line_speed[0], params->req_flow_ctrl[0]);
6700 DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
6701 params->req_line_speed[1], params->req_flow_ctrl[1]);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006702 vars->link_status = 0;
6703 vars->phy_link_up = 0;
6704 vars->link_up = 0;
6705 vars->line_speed = 0;
6706 vars->duplex = DUPLEX_FULL;
6707 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6708 vars->mac_type = MAC_TYPE_NONE;
6709 vars->phy_flags = 0;
6710
6711 /* disable attentions */
6712 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
6713 (NIG_MASK_XGXS0_LINK_STATUS |
6714 NIG_MASK_XGXS0_LINK10G |
6715 NIG_MASK_SERDES0_LINK_STATUS |
6716 NIG_MASK_MI_INT));
6717
6718 bnx2x_emac_init(params, vars);
6719
6720 if (params->num_phys == 0) {
6721 DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
6722 return -EINVAL;
6723 }
6724 set_phy_vars(params);
6725
6726 DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
6727 if (CHIP_REV_IS_FPGA(bp)) {
6728
6729 vars->link_up = 1;
6730 vars->line_speed = SPEED_10000;
6731 vars->duplex = DUPLEX_FULL;
6732 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6733 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
6734 /* enable on E1.5 FPGA */
6735 if (CHIP_IS_E1H(bp)) {
6736 vars->flow_ctrl |=
6737 (BNX2X_FLOW_CTRL_TX |
6738 BNX2X_FLOW_CTRL_RX);
6739 vars->link_status |=
6740 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
6741 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
6742 }
6743
6744 bnx2x_emac_enable(params, vars, 0);
6745 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
6746 /* disable drain */
6747 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
6748
6749 /* update shared memory */
6750 bnx2x_update_mng(params, vars->link_status);
6751
6752 return 0;
6753
6754 } else
6755 if (CHIP_REV_IS_EMUL(bp)) {
6756
6757 vars->link_up = 1;
6758 vars->line_speed = SPEED_10000;
6759 vars->duplex = DUPLEX_FULL;
6760 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6761 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
6762
6763 bnx2x_bmac_enable(params, vars, 0);
6764
6765 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
6766 /* Disable drain */
6767 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
6768 + params->port*4, 0);
6769
6770 /* update shared memory */
6771 bnx2x_update_mng(params, vars->link_status);
6772
6773 return 0;
6774
6775 } else
6776 if (params->loopback_mode == LOOPBACK_BMAC) {
6777
6778 vars->link_up = 1;
6779 vars->line_speed = SPEED_10000;
6780 vars->duplex = DUPLEX_FULL;
6781 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6782 vars->mac_type = MAC_TYPE_BMAC;
6783
6784 vars->phy_flags = PHY_XGXS_FLAG;
6785
6786 bnx2x_xgxs_deassert(params);
6787
6788 /* set bmac loopback */
6789 bnx2x_bmac_enable(params, vars, 1);
6790
6791 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6792 params->port*4, 0);
6793
6794 } else if (params->loopback_mode == LOOPBACK_EMAC) {
6795
6796 vars->link_up = 1;
6797 vars->line_speed = SPEED_1000;
6798 vars->duplex = DUPLEX_FULL;
6799 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
6800 vars->mac_type = MAC_TYPE_EMAC;
6801
6802 vars->phy_flags = PHY_XGXS_FLAG;
6803
6804 bnx2x_xgxs_deassert(params);
6805 /* set bmac loopback */
6806 bnx2x_emac_enable(params, vars, 1);
6807 bnx2x_emac_program(params, vars);
6808 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6809 params->port*4, 0);
6810
6811 } else if ((params->loopback_mode == LOOPBACK_XGXS) ||
6812 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
6813
6814 vars->link_up = 1;
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006815 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006816 vars->duplex = DUPLEX_FULL;
6817 if (params->req_line_speed[0] == SPEED_1000) {
6818 vars->line_speed = SPEED_1000;
6819 vars->mac_type = MAC_TYPE_EMAC;
6820 } else {
6821 vars->line_speed = SPEED_10000;
6822 vars->mac_type = MAC_TYPE_BMAC;
6823 }
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006824
6825 bnx2x_xgxs_deassert(params);
6826 bnx2x_link_initialize(params, vars);
6827
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006828 if (params->req_line_speed[0] == SPEED_1000) {
6829 bnx2x_emac_program(params, vars);
6830 bnx2x_emac_enable(params, vars, 0);
6831 } else
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006832 bnx2x_bmac_enable(params, vars, 0);
6833
6834 if (params->loopback_mode == LOOPBACK_XGXS) {
6835 /* set 10G XGXS loopback */
6836 params->phy[INT_PHY].config_loopback(
6837 &params->phy[INT_PHY],
6838 params);
6839
6840 } else {
6841 /* set external phy loopback */
6842 u8 phy_index;
6843 for (phy_index = EXT_PHY1;
6844 phy_index < params->num_phys; phy_index++) {
6845 if (params->phy[phy_index].config_loopback)
6846 params->phy[phy_index].config_loopback(
6847 &params->phy[phy_index],
6848 params);
6849 }
6850 }
6851
6852 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6853 params->port*4, 0);
6854
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006855 bnx2x_set_led(params, vars,
6856 LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006857 } else
6858 /* No loopback */
6859 {
6860 if (params->switch_cfg == SWITCH_CFG_10G)
6861 bnx2x_xgxs_deassert(params);
6862 else
6863 bnx2x_serdes_deassert(bp, params->port);
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006864
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006865 bnx2x_link_initialize(params, vars);
6866 msleep(30);
6867 bnx2x_link_int_enable(params);
6868 }
6869 return 0;
6870}
6871u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
6872 u8 reset_ext_phy)
6873{
6874 struct bnx2x *bp = params->bp;
6875 u8 phy_index, port = params->port;
6876 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
6877 /* disable attentions */
6878 vars->link_status = 0;
6879 bnx2x_update_mng(params, vars->link_status);
6880 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6881 (NIG_MASK_XGXS0_LINK_STATUS |
6882 NIG_MASK_XGXS0_LINK10G |
6883 NIG_MASK_SERDES0_LINK_STATUS |
6884 NIG_MASK_MI_INT));
6885
6886 /* activate nig drain */
6887 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6888
6889 /* disable nig egress interface */
6890 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6891 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6892
6893 /* Stop BigMac rx */
6894 bnx2x_bmac_rx_disable(bp, port);
6895
6896 /* disable emac */
6897 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6898
6899 msleep(10);
6900 /* The PHY reset is controled by GPIO 1
6901 * Hold it as vars low
6902 */
6903 /* clear link led */
Yaniv Rosner7f02c4a2010-09-07 11:41:23 +00006904 bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
6905
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00006906 if (reset_ext_phy) {
6907 for (phy_index = EXT_PHY1; phy_index < params->num_phys;
6908 phy_index++) {
6909 if (params->phy[phy_index].link_reset)
6910 params->phy[phy_index].link_reset(
6911 &params->phy[phy_index],
6912 params);
6913 }
6914 }
6915
6916 if (params->phy[INT_PHY].link_reset)
6917 params->phy[INT_PHY].link_reset(
6918 &params->phy[INT_PHY], params);
6919 /* reset BigMac */
6920 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
6921 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
6922
6923 /* disable nig ingress interface */
6924 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
6925 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
6926 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6927 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6928 vars->link_up = 0;
6929 return 0;
6930}
6931
6932/****************************************************************************/
6933/* Common function */
6934/****************************************************************************/
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006935static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base, u8 phy_index)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006936{
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006937 struct bnx2x_phy phy[PORT_MAX];
6938 struct bnx2x_phy *phy_blk[PORT_MAX];
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006939 u16 val;
6940 s8 port;
6941
6942 /* PART1 - Reset both phys */
6943 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6944 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00006945 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006946 port, &phy[port]) !=
6947 0) {
6948 DP(NETIF_MSG_LINK, "populate_phy failed\n");
6949 return -EINVAL;
6950 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006951 /* disable attentions */
6952 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6953 (NIG_MASK_XGXS0_LINK_STATUS |
6954 NIG_MASK_XGXS0_LINK10G |
6955 NIG_MASK_SERDES0_LINK_STATUS |
6956 NIG_MASK_MI_INT));
6957
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006958 /* Need to take the phy out of low power mode in order
6959 to write to access its registers */
6960 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6961 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
6962
6963 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006964 bnx2x_cl45_write(bp, &phy[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006965 MDIO_PMA_DEVAD,
6966 MDIO_PMA_REG_CTRL,
6967 1<<15);
6968 }
6969
6970 /* Add delay of 150ms after reset */
6971 msleep(150);
6972
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006973 if (phy[PORT_0].addr & 0x1) {
6974 phy_blk[PORT_0] = &(phy[PORT_1]);
6975 phy_blk[PORT_1] = &(phy[PORT_0]);
6976 } else {
6977 phy_blk[PORT_0] = &(phy[PORT_0]);
6978 phy_blk[PORT_1] = &(phy[PORT_1]);
6979 }
6980
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006981 /* PART2 - Download firmware to both phys */
6982 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6983 u16 fw_ver1;
6984
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006985 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00006986 port);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006987
Yaniv Rosnere10bc842010-09-07 11:40:50 +00006988 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006989 MDIO_PMA_DEVAD,
6990 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006991 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006992 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006993 "bnx2x_8073_common_init_phy port %x:"
6994 "Download failed. fw version = 0x%x\n",
6995 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006996 return -EINVAL;
6997 }
6998
6999 /* Only set bit 10 = 1 (Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007000 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007001 MDIO_PMA_DEVAD,
7002 MDIO_PMA_REG_TX_POWER_DOWN, &val);
7003
7004 /* Phase1 of TX_POWER_DOWN reset */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007005 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007006 MDIO_PMA_DEVAD,
7007 MDIO_PMA_REG_TX_POWER_DOWN,
7008 (val | 1<<10));
7009 }
7010
7011 /* Toggle Transmitter: Power down and then up with 600ms
7012 delay between */
7013 msleep(600);
7014
7015 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
7016 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00007017 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007018 /* Release bit 10 (Release Tx power down) */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007019 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007020 MDIO_PMA_DEVAD,
7021 MDIO_PMA_REG_TX_POWER_DOWN, &val);
7022
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007023 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007024 MDIO_PMA_DEVAD,
7025 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
7026 msleep(15);
7027
7028 /* Read modify write the SPI-ROM version select register */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007029 bnx2x_cl45_read(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007030 MDIO_PMA_DEVAD,
7031 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007032 bnx2x_cl45_write(bp, phy_blk[port],
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007033 MDIO_PMA_DEVAD,
7034 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
7035
7036 /* set GPIO2 back to LOW */
7037 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
7038 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
7039 }
7040 return 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007041}
7042
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007043static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base,
7044 u32 shmem2_base, u8 phy_index)
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007045{
7046 u32 val;
7047 s8 port;
7048 struct bnx2x_phy phy;
7049 /* Use port1 because of the static port-swap */
7050 /* Enable the module detection interrupt */
7051 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
7052 val |= ((1<<MISC_REGISTERS_GPIO_3)|
7053 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
7054 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
7055
7056 bnx2x_ext_phy_hw_reset(bp, 1);
7057 msleep(5);
7058 for (port = 0; port < PORT_MAX; port++) {
7059 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007060 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerde6eae12010-09-07 11:41:13 +00007061 port, &phy) !=
7062 0) {
7063 DP(NETIF_MSG_LINK, "populate phy failed\n");
7064 return -EINVAL;
7065 }
7066
7067 /* Reset phy*/
7068 bnx2x_cl45_write(bp, &phy,
7069 MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
7070
7071
7072 /* Set fault module detected LED on */
7073 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
7074 MISC_REGISTERS_GPIO_HIGH,
7075 port);
7076 }
7077
7078 return 0;
7079}
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007080static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base,
7081 u32 shmem2_base, u8 phy_index)
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007082{
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007083 s8 port;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007084 u32 swap_val, swap_override;
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007085 struct bnx2x_phy phy[PORT_MAX];
7086 struct bnx2x_phy *phy_blk[PORT_MAX];
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007087 DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
7088 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
7089 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
7090
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007091 port = 1;
7092
7093 bnx2x_ext_phy_hw_reset(bp, port ^ (swap_val && swap_override));
7094
7095 /* Calculate the port based on port swap */
7096 port ^= (swap_val && swap_override);
7097
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007098 msleep(5);
7099
7100 /* PART1 - Reset both phys */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007101 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007102 /* Extract the ext phy address for the port */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007103 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007104 port, &phy[port]) !=
7105 0) {
7106 DP(NETIF_MSG_LINK, "populate phy failed\n");
7107 return -EINVAL;
7108 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007109 /* disable attentions */
7110 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
7111 (NIG_MASK_XGXS0_LINK_STATUS |
7112 NIG_MASK_XGXS0_LINK10G |
7113 NIG_MASK_SERDES0_LINK_STATUS |
7114 NIG_MASK_MI_INT));
7115
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007116
7117 /* Reset the phy */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007118 bnx2x_cl45_write(bp, &phy[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007119 MDIO_PMA_DEVAD,
7120 MDIO_PMA_REG_CTRL,
7121 1<<15);
7122 }
7123
7124 /* Add delay of 150ms after reset */
7125 msleep(150);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007126 if (phy[PORT_0].addr & 0x1) {
7127 phy_blk[PORT_0] = &(phy[PORT_1]);
7128 phy_blk[PORT_1] = &(phy[PORT_0]);
7129 } else {
7130 phy_blk[PORT_0] = &(phy[PORT_0]);
7131 phy_blk[PORT_1] = &(phy[PORT_1]);
7132 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007133 /* PART2 - Download firmware to both phys */
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007134 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007135 u16 fw_ver1;
7136
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007137 bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
Yaniv Rosnerc18aa152010-09-07 11:41:07 +00007138 port);
Yaniv Rosnere10bc842010-09-07 11:40:50 +00007139 bnx2x_cl45_read(bp, phy_blk[port],
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007140 MDIO_PMA_DEVAD,
7141 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
7142 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
7143 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00007144 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007145 "Download failed. fw version = 0x%x\n",
7146 port, fw_ver1);
7147 return -EINVAL;
7148 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007149 }
7150
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007151 return 0;
7152}
7153
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007154static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base,
7155 u32 shmem2_base, u8 phy_index,
7156 u32 ext_phy_type)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007157{
7158 u8 rc = 0;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007159
7160 switch (ext_phy_type) {
7161 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007162 rc = bnx2x_8073_common_init_phy(bp, shmem_base,
7163 shmem2_base, phy_index);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007164 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007165
7166 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
7167 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007168 rc = bnx2x_8727_common_init_phy(bp, shmem_base,
7169 shmem2_base, phy_index);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00007170 break;
7171
Eilon Greenstein589abe32009-02-12 08:36:55 +00007172 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
7173 /* GPIO1 affects both ports, so there's need to pull
7174 it for single port alone */
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007175 rc = bnx2x_8726_common_init_phy(bp, shmem_base,
7176 shmem2_base, phy_index);
7177 break;
7178 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
7179 rc = -EINVAL;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02007180 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07007181 default:
7182 DP(NETIF_MSG_LINK,
7183 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
7184 ext_phy_type);
7185 break;
7186 }
7187
7188 return rc;
7189}
7190
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007191u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base,
7192 u32 shmem2_base)
7193{
7194 u8 rc = 0;
7195 u8 phy_index;
7196 u32 ext_phy_type, ext_phy_config;
7197 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007198
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007199 if (CHIP_REV_IS_EMUL(bp))
7200 return 0;
7201
7202 /* Read the ext_phy_type for arbitrary port(0) */
7203 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7204 phy_index++) {
7205 ext_phy_config = bnx2x_get_ext_phy_config(bp,
7206 shmem_base,
7207 phy_index, 0);
7208 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
7209 rc |= bnx2x_ext_phy_common_init(bp, shmem_base,
7210 shmem2_base,
7211 phy_index, ext_phy_type);
7212 }
7213 return rc;
7214}
7215
7216u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007217{
7218 u8 phy_index;
7219 struct bnx2x_phy phy;
7220 for (phy_index = INT_PHY; phy_index < MAX_PHYS;
7221 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007222 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007223 0, &phy) != 0) {
7224 DP(NETIF_MSG_LINK, "populate phy failed\n");
7225 return 0;
7226 }
7227
7228 if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
7229 return 1;
7230 }
7231 return 0;
7232}
7233
7234u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
7235 u32 shmem_base,
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007236 u32 shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007237 u8 port)
7238{
7239 u8 phy_index, fan_failure_det_req = 0;
7240 struct bnx2x_phy phy;
7241 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7242 phy_index++) {
Yaniv Rosnera22f0782010-09-07 11:41:20 +00007243 if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
Yaniv Rosnerd90d96b2010-09-07 11:41:04 +00007244 port, &phy)
7245 != 0) {
7246 DP(NETIF_MSG_LINK, "populate phy failed\n");
7247 return 0;
7248 }
7249 fan_failure_det_req |= (phy.flags &
7250 FLAGS_FAN_FAILURE_DET_REQ);
7251 }
7252 return fan_failure_det_req;
7253}
7254
7255void bnx2x_hw_reset_phy(struct link_params *params)
7256{
7257 u8 phy_index;
7258 for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
7259 phy_index++) {
7260 if (params->phy[phy_index].hw_reset) {
7261 params->phy[phy_index].hw_reset(
7262 &params->phy[phy_index],
7263 params);
7264 params->phy[phy_index] = phy_null;
7265 }
7266 }
7267}