blob: 8fce54cd6ba5b4f75062de6cf481816e2a5eb98b [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
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070031#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
32#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/**********************************************************/
171#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
172 bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
173 DEFAULT_PHY_DEV_ADDR, \
174 (_bank + (_addr & 0xf)), \
175 _val)
176
177#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
178 bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
179 DEFAULT_PHY_DEV_ADDR, \
180 (_bank + (_addr & 0xf)), \
181 _val)
182
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000183static void bnx2x_set_serdes_access(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700184{
185 struct bnx2x *bp = params->bp;
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000186 u32 emac_base = (params->port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000187
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000188 /* Set Clause 22 */
189 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 1);
190 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
191 udelay(500);
192 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
193 udelay(500);
194 /* Set Clause 45 */
195 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 0);
196}
197static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags)
198{
199 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000200
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000201 if (phy_flags & PHY_XGXS_FLAG) {
202 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
203 params->port*0x18, 0);
204 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
205 DEFAULT_PHY_DEV_ADDR);
206 } else {
207 bnx2x_set_serdes_access(params);
208
209 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
210 params->port*0x10,
211 DEFAULT_PHY_DEV_ADDR);
212 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700213}
214
215static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
216{
217 u32 val = REG_RD(bp, reg);
218
219 val |= bits;
220 REG_WR(bp, reg, val);
221 return val;
222}
223
224static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
225{
226 u32 val = REG_RD(bp, reg);
227
228 val &= ~bits;
229 REG_WR(bp, reg, val);
230 return val;
231}
232
233static void bnx2x_emac_init(struct link_params *params,
234 struct link_vars *vars)
235{
236 /* reset and unreset the emac core */
237 struct bnx2x *bp = params->bp;
238 u8 port = params->port;
239 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
240 u32 val;
241 u16 timeout;
242
243 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
244 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
245 udelay(5);
246 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
247 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
248
249 /* init emac - use read-modify-write */
250 /* self clear reset */
251 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700252 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700253
254 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700255 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700256 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
257 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
258 if (!timeout) {
259 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
260 return;
261 }
262 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700263 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700264
265 /* Set mac address */
266 val = ((params->mac_addr[0] << 8) |
267 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700268 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700269
270 val = ((params->mac_addr[2] << 24) |
271 (params->mac_addr[3] << 16) |
272 (params->mac_addr[4] << 8) |
273 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700274 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700275}
276
277static u8 bnx2x_emac_enable(struct link_params *params,
278 struct link_vars *vars, u8 lb)
279{
280 struct bnx2x *bp = params->bp;
281 u8 port = params->port;
282 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
283 u32 val;
284
285 DP(NETIF_MSG_LINK, "enabling EMAC\n");
286
287 /* enable emac and not bmac */
288 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
289
290 /* for paladium */
291 if (CHIP_REV_IS_EMUL(bp)) {
292 /* Use lane 1 (of lanes 0-3) */
293 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
294 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
295 port*4, 1);
296 }
297 /* for fpga */
298 else
299
300 if (CHIP_REV_IS_FPGA(bp)) {
301 /* Use lane 1 (of lanes 0-3) */
302 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
303
304 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
305 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
306 0);
307 } else
308 /* ASIC */
309 if (vars->phy_flags & PHY_XGXS_FLAG) {
310 u32 ser_lane = ((params->lane_config &
311 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
312 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
313
314 DP(NETIF_MSG_LINK, "XGXS\n");
315 /* select the master lanes (out of 0-3) */
316 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
317 port*4, ser_lane);
318 /* select XGXS */
319 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
320 port*4, 1);
321
322 } else { /* SerDes */
323 DP(NETIF_MSG_LINK, "SerDes\n");
324 /* select SerDes */
325 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
326 port*4, 0);
327 }
328
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000329 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
330 EMAC_RX_MODE_RESET);
331 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
332 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700333
334 if (CHIP_REV_IS_SLOW(bp)) {
335 /* config GMII mode */
336 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700337 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700338 (val | EMAC_MODE_PORT_GMII));
339 } else { /* ASIC */
340 /* pause enable/disable */
341 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
342 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800343 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700344 bnx2x_bits_en(bp, emac_base +
345 EMAC_REG_EMAC_RX_MODE,
346 EMAC_RX_MODE_FLOW_EN);
347
348 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700349 (EMAC_TX_MODE_EXT_PAUSE_EN |
350 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800351 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700352 bnx2x_bits_en(bp, emac_base +
353 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700354 (EMAC_TX_MODE_EXT_PAUSE_EN |
355 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700356 }
357
358 /* KEEP_VLAN_TAG, promiscuous */
359 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
360 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700361 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700362
363 /* Set Loopback */
364 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
365 if (lb)
366 val |= 0x810;
367 else
368 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700369 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700370
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000371 /* enable emac */
372 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
373
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700374 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700375 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700376 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
377 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
378
379 /* strip CRC */
380 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
381
382 /* disable the NIG in/out to the bmac */
383 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
384 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
385 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
386
387 /* enable the NIG in/out to the emac */
388 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
389 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800390 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700391 val = 1;
392
393 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
394 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
395
396 if (CHIP_REV_IS_EMUL(bp)) {
397 /* take the BigMac out of reset */
398 REG_WR(bp,
399 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
400 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
401
402 /* enable access for bmac registers */
403 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
Eilon Greenstein6f654972009-08-12 08:23:51 +0000404 } else
405 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700406
407 vars->mac_type = MAC_TYPE_EMAC;
408 return 0;
409}
410
411
412
413static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
414 u8 is_lb)
415{
416 struct bnx2x *bp = params->bp;
417 u8 port = params->port;
418 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
419 NIG_REG_INGRESS_BMAC0_MEM;
420 u32 wb_data[2];
421 u32 val;
422
423 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
424 /* reset and unreset the BigMac */
425 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
426 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
427 msleep(1);
428
429 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
430 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
431
432 /* enable access for bmac registers */
433 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
434
435 /* XGXS control */
436 wb_data[0] = 0x3c;
437 wb_data[1] = 0;
438 REG_WR_DMAE(bp, bmac_addr +
439 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
440 wb_data, 2);
441
442 /* tx MAC SA */
443 wb_data[0] = ((params->mac_addr[2] << 24) |
444 (params->mac_addr[3] << 16) |
445 (params->mac_addr[4] << 8) |
446 params->mac_addr[5]);
447 wb_data[1] = ((params->mac_addr[0] << 8) |
448 params->mac_addr[1]);
449 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
450 wb_data, 2);
451
452 /* tx control */
453 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800454 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700455 val |= 0x800000;
456 wb_data[0] = val;
457 wb_data[1] = 0;
458 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
459 wb_data, 2);
460
461 /* mac control */
462 val = 0x3;
463 if (is_lb) {
464 val |= 0x4;
465 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
466 }
467 wb_data[0] = val;
468 wb_data[1] = 0;
469 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
470 wb_data, 2);
471
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700472 /* set rx mtu */
473 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
474 wb_data[1] = 0;
475 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
476 wb_data, 2);
477
478 /* rx control set to don't strip crc */
479 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800480 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700481 val |= 0x20;
482 wb_data[0] = val;
483 wb_data[1] = 0;
484 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
485 wb_data, 2);
486
487 /* set tx mtu */
488 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
489 wb_data[1] = 0;
490 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
491 wb_data, 2);
492
493 /* set cnt max size */
494 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
495 wb_data[1] = 0;
496 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
497 wb_data, 2);
498
499 /* configure safc */
500 wb_data[0] = 0x1000200;
501 wb_data[1] = 0;
502 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
503 wb_data, 2);
504 /* fix for emulation */
505 if (CHIP_REV_IS_EMUL(bp)) {
506 wb_data[0] = 0xf000;
507 wb_data[1] = 0;
508 REG_WR_DMAE(bp,
509 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
510 wb_data, 2);
511 }
512
513 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
514 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
515 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
516 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800517 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700518 val = 1;
519 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
520 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
521 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
522 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
523 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
524 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
525
526 vars->mac_type = MAC_TYPE_BMAC;
527 return 0;
528}
529
530static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
531{
532 struct bnx2x *bp = params->bp;
533 u32 val;
534
535 if (phy_flags & PHY_XGXS_FLAG) {
536 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
537 val = XGXS_RESET_BITS;
538
539 } else { /* SerDes */
540 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
541 val = SERDES_RESET_BITS;
542 }
543
544 val = val << (params->port*16);
545
546 /* reset and unreset the SerDes/XGXS */
547 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
548 val);
549 udelay(500);
550 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
551 val);
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000552 bnx2x_set_phy_mdio(params, phy_flags);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700553}
554
555void bnx2x_link_status_update(struct link_params *params,
556 struct link_vars *vars)
557{
558 struct bnx2x *bp = params->bp;
559 u8 link_10g;
560 u8 port = params->port;
561
562 if (params->switch_cfg == SWITCH_CFG_1G)
563 vars->phy_flags = PHY_SERDES_FLAG;
564 else
565 vars->phy_flags = PHY_XGXS_FLAG;
566 vars->link_status = REG_RD(bp, params->shmem_base +
567 offsetof(struct shmem_region,
568 port_mb[port].link_status));
569
570 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
571
572 if (vars->link_up) {
573 DP(NETIF_MSG_LINK, "phy link up\n");
574
575 vars->phy_link_up = 1;
576 vars->duplex = DUPLEX_FULL;
577 switch (vars->link_status &
578 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
579 case LINK_10THD:
580 vars->duplex = DUPLEX_HALF;
581 /* fall thru */
582 case LINK_10TFD:
583 vars->line_speed = SPEED_10;
584 break;
585
586 case LINK_100TXHD:
587 vars->duplex = DUPLEX_HALF;
588 /* fall thru */
589 case LINK_100T4:
590 case LINK_100TXFD:
591 vars->line_speed = SPEED_100;
592 break;
593
594 case LINK_1000THD:
595 vars->duplex = DUPLEX_HALF;
596 /* fall thru */
597 case LINK_1000TFD:
598 vars->line_speed = SPEED_1000;
599 break;
600
601 case LINK_2500THD:
602 vars->duplex = DUPLEX_HALF;
603 /* fall thru */
604 case LINK_2500TFD:
605 vars->line_speed = SPEED_2500;
606 break;
607
608 case LINK_10GTFD:
609 vars->line_speed = SPEED_10000;
610 break;
611
612 case LINK_12GTFD:
613 vars->line_speed = SPEED_12000;
614 break;
615
616 case LINK_12_5GTFD:
617 vars->line_speed = SPEED_12500;
618 break;
619
620 case LINK_13GTFD:
621 vars->line_speed = SPEED_13000;
622 break;
623
624 case LINK_15GTFD:
625 vars->line_speed = SPEED_15000;
626 break;
627
628 case LINK_16GTFD:
629 vars->line_speed = SPEED_16000;
630 break;
631
632 default:
633 break;
634 }
635
636 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800637 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700638 else
David S. Millerc0700f92008-12-16 23:53:20 -0800639 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700640
641 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800642 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700643 else
David S. Millerc0700f92008-12-16 23:53:20 -0800644 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700645
646 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700647 if (vars->line_speed &&
648 ((vars->line_speed == SPEED_10) ||
649 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700650 vars->phy_flags |= PHY_SGMII_FLAG;
651 } else {
652 vars->phy_flags &= ~PHY_SGMII_FLAG;
653 }
654 }
655
656 /* anything 10 and over uses the bmac */
657 link_10g = ((vars->line_speed == SPEED_10000) ||
658 (vars->line_speed == SPEED_12000) ||
659 (vars->line_speed == SPEED_12500) ||
660 (vars->line_speed == SPEED_13000) ||
661 (vars->line_speed == SPEED_15000) ||
662 (vars->line_speed == SPEED_16000));
663 if (link_10g)
664 vars->mac_type = MAC_TYPE_BMAC;
665 else
666 vars->mac_type = MAC_TYPE_EMAC;
667
668 } else { /* link down */
669 DP(NETIF_MSG_LINK, "phy link down\n");
670
671 vars->phy_link_up = 0;
672
673 vars->line_speed = 0;
674 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -0800675 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700676
677 /* indicate no mac active */
678 vars->mac_type = MAC_TYPE_NONE;
679 }
680
681 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
682 vars->link_status, vars->phy_link_up);
683 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
684 vars->line_speed, vars->duplex, vars->flow_ctrl);
685}
686
687static void bnx2x_update_mng(struct link_params *params, u32 link_status)
688{
689 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000690
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700691 REG_WR(bp, params->shmem_base +
692 offsetof(struct shmem_region,
693 port_mb[params->port].link_status),
694 link_status);
695}
696
697static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
698{
699 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
700 NIG_REG_INGRESS_BMAC0_MEM;
701 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700702 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700703
704 /* Only if the bmac is out of reset */
705 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
706 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
707 nig_bmac_enable) {
708
709 /* Clear Rx Enable bit in BMAC_CONTROL register */
710 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
711 wb_data, 2);
712 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
713 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
714 wb_data, 2);
715
716 msleep(1);
717 }
718}
719
720static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
721 u32 line_speed)
722{
723 struct bnx2x *bp = params->bp;
724 u8 port = params->port;
725 u32 init_crd, crd;
726 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700727
728 /* disable port */
729 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
730
731 /* wait for init credit */
732 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
733 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
734 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
735
736 while ((init_crd != crd) && count) {
737 msleep(5);
738
739 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
740 count--;
741 }
742 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
743 if (init_crd != crd) {
744 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
745 init_crd, crd);
746 return -EINVAL;
747 }
748
David S. Millerc0700f92008-12-16 23:53:20 -0800749 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700750 line_speed == SPEED_10 ||
751 line_speed == SPEED_100 ||
752 line_speed == SPEED_1000 ||
753 line_speed == SPEED_2500) {
754 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700755 /* update threshold */
756 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
757 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700758 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700759
760 } else {
761 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
762 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700763 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700764 /* update threshold */
765 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
766 /* update init credit */
767 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700768 case SPEED_10000:
769 init_crd = thresh + 553 - 22;
770 break;
771
772 case SPEED_12000:
773 init_crd = thresh + 664 - 22;
774 break;
775
776 case SPEED_13000:
777 init_crd = thresh + 742 - 22;
778 break;
779
780 case SPEED_16000:
781 init_crd = thresh + 778 - 22;
782 break;
783 default:
784 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
785 line_speed);
786 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700787 }
788 }
789 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
790 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
791 line_speed, init_crd);
792
793 /* probe the credit changes */
794 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
795 msleep(5);
796 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
797
798 /* enable port */
799 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
800 return 0;
801}
802
Eilon Greenstein589abe32009-02-12 08:36:55 +0000803static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700804{
805 u32 emac_base;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000806
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700807 switch (ext_phy_type) {
808 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000809 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000810 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000811 /* All MDC/MDIO is directed through single EMAC */
812 if (REG_RD(bp, NIG_REG_PORT_SWAP))
813 emac_base = GRCBASE_EMAC0;
814 else
815 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700816 break;
817 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700818 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700819 break;
820 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700821 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700822 break;
823 }
824 return emac_base;
825
826}
827
828u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
829 u8 phy_addr, u8 devad, u16 reg, u16 val)
830{
831 u32 tmp, saved_mode;
832 u8 i, rc = 0;
Eilon Greenstein589abe32009-02-12 08:36:55 +0000833 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700834
835 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
836 * (a value of 49==0x31) and make sure that the AUTO poll is off
837 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000838
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700839 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
840 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
841 EMAC_MDIO_MODE_CLOCK_CNT);
842 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
843 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
844 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
845 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
846 udelay(40);
847
848 /* address */
849
850 tmp = ((phy_addr << 21) | (devad << 16) | reg |
851 EMAC_MDIO_COMM_COMMAND_ADDRESS |
852 EMAC_MDIO_COMM_START_BUSY);
853 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
854
855 for (i = 0; i < 50; i++) {
856 udelay(10);
857
858 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
859 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
860 udelay(5);
861 break;
862 }
863 }
864 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
865 DP(NETIF_MSG_LINK, "write phy register failed\n");
866 rc = -EFAULT;
867 } else {
868 /* data */
869 tmp = ((phy_addr << 21) | (devad << 16) | val |
870 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
871 EMAC_MDIO_COMM_START_BUSY);
872 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
873
874 for (i = 0; i < 50; i++) {
875 udelay(10);
876
877 tmp = REG_RD(bp, mdio_ctrl +
878 EMAC_REG_EMAC_MDIO_COMM);
879 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
880 udelay(5);
881 break;
882 }
883 }
884 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
885 DP(NETIF_MSG_LINK, "write phy register failed\n");
886 rc = -EFAULT;
887 }
888 }
889
890 /* Restore the saved mode */
891 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
892
893 return rc;
894}
895
896u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
897 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
898{
899 u32 val, saved_mode;
900 u16 i;
901 u8 rc = 0;
902
Eilon Greenstein589abe32009-02-12 08:36:55 +0000903 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700904 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
905 * (a value of 49==0x31) and make sure that the AUTO poll is off
906 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000907
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700908 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
909 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
910 EMAC_MDIO_MODE_CLOCK_CNT));
911 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000912 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700913 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
914 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
915 udelay(40);
916
917 /* address */
918 val = ((phy_addr << 21) | (devad << 16) | reg |
919 EMAC_MDIO_COMM_COMMAND_ADDRESS |
920 EMAC_MDIO_COMM_START_BUSY);
921 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
922
923 for (i = 0; i < 50; i++) {
924 udelay(10);
925
926 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
927 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
928 udelay(5);
929 break;
930 }
931 }
932 if (val & EMAC_MDIO_COMM_START_BUSY) {
933 DP(NETIF_MSG_LINK, "read phy register failed\n");
934
935 *ret_val = 0;
936 rc = -EFAULT;
937
938 } else {
939 /* data */
940 val = ((phy_addr << 21) | (devad << 16) |
941 EMAC_MDIO_COMM_COMMAND_READ_45 |
942 EMAC_MDIO_COMM_START_BUSY);
943 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
944
945 for (i = 0; i < 50; i++) {
946 udelay(10);
947
948 val = REG_RD(bp, mdio_ctrl +
949 EMAC_REG_EMAC_MDIO_COMM);
950 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
951 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
952 break;
953 }
954 }
955 if (val & EMAC_MDIO_COMM_START_BUSY) {
956 DP(NETIF_MSG_LINK, "read phy register failed\n");
957
958 *ret_val = 0;
959 rc = -EFAULT;
960 }
961 }
962
963 /* Restore the saved mode */
964 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
965
966 return rc;
967}
968
969static void bnx2x_set_aer_mmd(struct link_params *params,
970 struct link_vars *vars)
971{
972 struct bnx2x *bp = params->bp;
973 u32 ser_lane;
974 u16 offset;
975
976 ser_lane = ((params->lane_config &
977 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
978 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
979
980 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
981 (params->phy_addr + ser_lane) : 0;
982
983 CL45_WR_OVER_CL22(bp, params->port,
984 params->phy_addr,
985 MDIO_REG_BANK_AER_BLOCK,
986 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
987}
988
989static void bnx2x_set_master_ln(struct link_params *params)
990{
991 struct bnx2x *bp = params->bp;
992 u16 new_master_ln, ser_lane;
993 ser_lane = ((params->lane_config &
994 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
995 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
996
997 /* set the master_ln for AN */
998 CL45_RD_OVER_CL22(bp, params->port,
999 params->phy_addr,
1000 MDIO_REG_BANK_XGXS_BLOCK2,
1001 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1002 &new_master_ln);
1003
1004 CL45_WR_OVER_CL22(bp, params->port,
1005 params->phy_addr,
1006 MDIO_REG_BANK_XGXS_BLOCK2 ,
1007 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1008 (new_master_ln | ser_lane));
1009}
1010
1011static u8 bnx2x_reset_unicore(struct link_params *params)
1012{
1013 struct bnx2x *bp = params->bp;
1014 u16 mii_control;
1015 u16 i;
1016
1017 CL45_RD_OVER_CL22(bp, params->port,
1018 params->phy_addr,
1019 MDIO_REG_BANK_COMBO_IEEE0,
1020 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1021
1022 /* reset the unicore */
1023 CL45_WR_OVER_CL22(bp, params->port,
1024 params->phy_addr,
1025 MDIO_REG_BANK_COMBO_IEEE0,
1026 MDIO_COMBO_IEEE0_MII_CONTROL,
1027 (mii_control |
1028 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Eilon Greenstein6f654972009-08-12 08:23:51 +00001029 if (params->switch_cfg == SWITCH_CFG_1G)
1030 bnx2x_set_serdes_access(params);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001031
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001032 /* wait for the reset to self clear */
1033 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1034 udelay(5);
1035
1036 /* the reset erased the previous bank value */
1037 CL45_RD_OVER_CL22(bp, params->port,
1038 params->phy_addr,
1039 MDIO_REG_BANK_COMBO_IEEE0,
1040 MDIO_COMBO_IEEE0_MII_CONTROL,
1041 &mii_control);
1042
1043 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1044 udelay(5);
1045 return 0;
1046 }
1047 }
1048
1049 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1050 return -EINVAL;
1051
1052}
1053
1054static void bnx2x_set_swap_lanes(struct link_params *params)
1055{
1056 struct bnx2x *bp = params->bp;
1057 /* Each two bits represents a lane number:
1058 No swap is 0123 => 0x1b no need to enable the swap */
1059 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1060
1061 ser_lane = ((params->lane_config &
1062 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1063 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1064 rx_lane_swap = ((params->lane_config &
1065 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1066 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1067 tx_lane_swap = ((params->lane_config &
1068 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1069 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1070
1071 if (rx_lane_swap != 0x1b) {
1072 CL45_WR_OVER_CL22(bp, params->port,
1073 params->phy_addr,
1074 MDIO_REG_BANK_XGXS_BLOCK2,
1075 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1076 (rx_lane_swap |
1077 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1078 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1079 } else {
1080 CL45_WR_OVER_CL22(bp, params->port,
1081 params->phy_addr,
1082 MDIO_REG_BANK_XGXS_BLOCK2,
1083 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1084 }
1085
1086 if (tx_lane_swap != 0x1b) {
1087 CL45_WR_OVER_CL22(bp, params->port,
1088 params->phy_addr,
1089 MDIO_REG_BANK_XGXS_BLOCK2,
1090 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1091 (tx_lane_swap |
1092 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1093 } else {
1094 CL45_WR_OVER_CL22(bp, params->port,
1095 params->phy_addr,
1096 MDIO_REG_BANK_XGXS_BLOCK2,
1097 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1098 }
1099}
1100
1101static void bnx2x_set_parallel_detection(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07001102 u8 phy_flags)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001103{
1104 struct bnx2x *bp = params->bp;
1105 u16 control2;
1106
1107 CL45_RD_OVER_CL22(bp, params->port,
1108 params->phy_addr,
1109 MDIO_REG_BANK_SERDES_DIGITAL,
1110 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1111 &control2);
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001112 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1113 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1114 else
1115 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1116 DP(NETIF_MSG_LINK, "params->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1117 params->speed_cap_mask, control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001118 CL45_WR_OVER_CL22(bp, params->port,
1119 params->phy_addr,
1120 MDIO_REG_BANK_SERDES_DIGITAL,
1121 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1122 control2);
1123
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001124 if ((phy_flags & PHY_XGXS_FLAG) &&
1125 (params->speed_cap_mask &
1126 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001127 DP(NETIF_MSG_LINK, "XGXS\n");
1128
1129 CL45_WR_OVER_CL22(bp, params->port,
1130 params->phy_addr,
1131 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1132 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1133 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1134
1135 CL45_RD_OVER_CL22(bp, params->port,
1136 params->phy_addr,
1137 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1138 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1139 &control2);
1140
1141
1142 control2 |=
1143 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1144
1145 CL45_WR_OVER_CL22(bp, params->port,
1146 params->phy_addr,
1147 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1148 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1149 control2);
1150
1151 /* Disable parallel detection of HiG */
1152 CL45_WR_OVER_CL22(bp, params->port,
1153 params->phy_addr,
1154 MDIO_REG_BANK_XGXS_BLOCK2,
1155 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1156 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1157 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1158 }
1159}
1160
1161static void bnx2x_set_autoneg(struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001162 struct link_vars *vars,
1163 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001164{
1165 struct bnx2x *bp = params->bp;
1166 u16 reg_val;
1167
1168 /* CL37 Autoneg */
1169
1170 CL45_RD_OVER_CL22(bp, params->port,
1171 params->phy_addr,
1172 MDIO_REG_BANK_COMBO_IEEE0,
1173 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1174
1175 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001176 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001177 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1178 else /* CL37 Autoneg Disabled */
1179 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1180 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1181
1182 CL45_WR_OVER_CL22(bp, params->port,
1183 params->phy_addr,
1184 MDIO_REG_BANK_COMBO_IEEE0,
1185 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1186
1187 /* Enable/Disable Autodetection */
1188
1189 CL45_RD_OVER_CL22(bp, params->port,
1190 params->phy_addr,
1191 MDIO_REG_BANK_SERDES_DIGITAL,
1192 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001193 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1194 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1195 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001196 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001197 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1198 else
1199 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1200
1201 CL45_WR_OVER_CL22(bp, params->port,
1202 params->phy_addr,
1203 MDIO_REG_BANK_SERDES_DIGITAL,
1204 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1205
1206 /* Enable TetonII and BAM autoneg */
1207 CL45_RD_OVER_CL22(bp, params->port,
1208 params->phy_addr,
1209 MDIO_REG_BANK_BAM_NEXT_PAGE,
1210 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1211 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001212 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001213 /* Enable BAM aneg Mode and TetonII aneg Mode */
1214 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1215 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1216 } else {
1217 /* TetonII and BAM Autoneg Disabled */
1218 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1219 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1220 }
1221 CL45_WR_OVER_CL22(bp, params->port,
1222 params->phy_addr,
1223 MDIO_REG_BANK_BAM_NEXT_PAGE,
1224 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1225 reg_val);
1226
Eilon Greenstein239d6862009-08-12 08:23:04 +00001227 if (enable_cl73) {
1228 /* Enable Cl73 FSM status bits */
1229 CL45_WR_OVER_CL22(bp, params->port,
1230 params->phy_addr,
1231 MDIO_REG_BANK_CL73_USERB0,
1232 MDIO_CL73_USERB0_CL73_UCTRL,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001233 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001234
1235 /* Enable BAM Station Manager*/
1236 CL45_WR_OVER_CL22(bp, params->port,
1237 params->phy_addr,
1238 MDIO_REG_BANK_CL73_USERB0,
1239 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1240 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1241 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1242 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
1243
Yaniv Rosner7846e472009-11-05 19:18:07 +02001244 /* Advertise CL73 link speeds */
Eilon Greenstein239d6862009-08-12 08:23:04 +00001245 CL45_RD_OVER_CL22(bp, params->port,
1246 params->phy_addr,
1247 MDIO_REG_BANK_CL73_IEEEB1,
1248 MDIO_CL73_IEEEB1_AN_ADV2,
1249 &reg_val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02001250 if (params->speed_cap_mask &
1251 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1252 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1253 if (params->speed_cap_mask &
1254 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1255 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001256
Julia Lawallcc817352010-08-05 10:26:38 +00001257 CL45_WR_OVER_CL22(bp, params->port,
1258 params->phy_addr,
1259 MDIO_REG_BANK_CL73_IEEEB1,
1260 MDIO_CL73_IEEEB1_AN_ADV2,
1261 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001262
Eilon Greenstein239d6862009-08-12 08:23:04 +00001263 /* CL73 Autoneg Enabled */
1264 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1265
1266 } else /* CL73 Autoneg Disabled */
1267 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001268
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001269 CL45_WR_OVER_CL22(bp, params->port,
1270 params->phy_addr,
1271 MDIO_REG_BANK_CL73_IEEEB0,
1272 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1273}
1274
1275/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001276static void bnx2x_program_serdes(struct link_params *params,
1277 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001278{
1279 struct bnx2x *bp = params->bp;
1280 u16 reg_val;
1281
Eilon Greenstein57937202009-08-12 08:23:53 +00001282 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001283 CL45_RD_OVER_CL22(bp, params->port,
1284 params->phy_addr,
1285 MDIO_REG_BANK_COMBO_IEEE0,
1286 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1287 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00001288 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1289 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001290 if (params->req_duplex == DUPLEX_FULL)
1291 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1292 CL45_WR_OVER_CL22(bp, params->port,
1293 params->phy_addr,
1294 MDIO_REG_BANK_COMBO_IEEE0,
1295 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1296
1297 /* program speed
1298 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001299 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001300 params->phy_addr,
1301 MDIO_REG_BANK_SERDES_DIGITAL,
1302 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001303 /* clearing the speed value before setting the right speed */
1304 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1305
1306 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1307 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1308
1309 if (!((vars->line_speed == SPEED_1000) ||
1310 (vars->line_speed == SPEED_100) ||
1311 (vars->line_speed == SPEED_10))) {
1312
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001313 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1314 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001315 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001316 reg_val |=
1317 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001318 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001319 reg_val |=
1320 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001321 }
1322
1323 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001324 params->phy_addr,
1325 MDIO_REG_BANK_SERDES_DIGITAL,
1326 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001327
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001328}
1329
1330static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1331{
1332 struct bnx2x *bp = params->bp;
1333 u16 val = 0;
1334
1335 /* configure the 48 bits for BAM AN */
1336
1337 /* set extended capabilities */
1338 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1339 val |= MDIO_OVER_1G_UP1_2_5G;
1340 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1341 val |= MDIO_OVER_1G_UP1_10G;
1342 CL45_WR_OVER_CL22(bp, params->port,
1343 params->phy_addr,
1344 MDIO_REG_BANK_OVER_1G,
1345 MDIO_OVER_1G_UP1, val);
1346
1347 CL45_WR_OVER_CL22(bp, params->port,
1348 params->phy_addr,
1349 MDIO_REG_BANK_OVER_1G,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001350 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001351}
1352
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001353static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001354{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001355 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001356 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001357 /* resolve pause mode and advertisement
1358 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1359
1360 switch (params->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001361 case BNX2X_FLOW_CTRL_AUTO:
1362 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001363 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001364 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1365 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001366 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001367 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1368 }
1369 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001370 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001371 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001372 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1373 break;
1374
David S. Millerc0700f92008-12-16 23:53:20 -08001375 case BNX2X_FLOW_CTRL_RX:
1376 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001377 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001378 break;
1379
David S. Millerc0700f92008-12-16 23:53:20 -08001380 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001381 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001382 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001383 break;
1384 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001385 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001386}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001387
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001388static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001389 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001390{
1391 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001392 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001393 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001394
1395 CL45_WR_OVER_CL22(bp, params->port,
1396 params->phy_addr,
1397 MDIO_REG_BANK_COMBO_IEEE0,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001398 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosner7846e472009-11-05 19:18:07 +02001399 CL45_RD_OVER_CL22(bp, params->port,
1400 params->phy_addr,
1401 MDIO_REG_BANK_CL73_IEEEB1,
1402 MDIO_CL73_IEEEB1_AN_ADV1, &val);
1403 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
1404 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
1405 CL45_WR_OVER_CL22(bp, params->port,
1406 params->phy_addr,
1407 MDIO_REG_BANK_CL73_IEEEB1,
1408 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001409}
1410
Eilon Greenstein239d6862009-08-12 08:23:04 +00001411static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001412{
1413 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001414 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001415
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001416 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001417 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001418
Eilon Greenstein239d6862009-08-12 08:23:04 +00001419 if (enable_cl73) {
1420 CL45_RD_OVER_CL22(bp, params->port,
1421 params->phy_addr,
1422 MDIO_REG_BANK_CL73_IEEEB0,
1423 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1424 &mii_control);
1425
1426 CL45_WR_OVER_CL22(bp, params->port,
1427 params->phy_addr,
1428 MDIO_REG_BANK_CL73_IEEEB0,
1429 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1430 (mii_control |
1431 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1432 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1433 } else {
1434
1435 CL45_RD_OVER_CL22(bp, params->port,
1436 params->phy_addr,
1437 MDIO_REG_BANK_COMBO_IEEE0,
1438 MDIO_COMBO_IEEE0_MII_CONTROL,
1439 &mii_control);
1440 DP(NETIF_MSG_LINK,
1441 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1442 mii_control);
1443 CL45_WR_OVER_CL22(bp, params->port,
1444 params->phy_addr,
1445 MDIO_REG_BANK_COMBO_IEEE0,
1446 MDIO_COMBO_IEEE0_MII_CONTROL,
1447 (mii_control |
1448 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1449 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1450 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001451}
1452
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001453static void bnx2x_initialize_sgmii_process(struct link_params *params,
1454 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001455{
1456 struct bnx2x *bp = params->bp;
1457 u16 control1;
1458
1459 /* in SGMII mode, the unicore is always slave */
1460
1461 CL45_RD_OVER_CL22(bp, params->port,
1462 params->phy_addr,
1463 MDIO_REG_BANK_SERDES_DIGITAL,
1464 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1465 &control1);
1466 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1467 /* set sgmii mode (and not fiber) */
1468 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1469 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1470 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1471 CL45_WR_OVER_CL22(bp, params->port,
1472 params->phy_addr,
1473 MDIO_REG_BANK_SERDES_DIGITAL,
1474 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1475 control1);
1476
1477 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001478 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001479 /* set speed, disable autoneg */
1480 u16 mii_control;
1481
1482 CL45_RD_OVER_CL22(bp, params->port,
1483 params->phy_addr,
1484 MDIO_REG_BANK_COMBO_IEEE0,
1485 MDIO_COMBO_IEEE0_MII_CONTROL,
1486 &mii_control);
1487 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1488 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1489 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1490
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001491 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001492 case SPEED_100:
1493 mii_control |=
1494 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1495 break;
1496 case SPEED_1000:
1497 mii_control |=
1498 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1499 break;
1500 case SPEED_10:
1501 /* there is nothing to set for 10M */
1502 break;
1503 default:
1504 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001505 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1506 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001507 break;
1508 }
1509
1510 /* setting the full duplex */
1511 if (params->req_duplex == DUPLEX_FULL)
1512 mii_control |=
1513 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1514 CL45_WR_OVER_CL22(bp, params->port,
1515 params->phy_addr,
1516 MDIO_REG_BANK_COMBO_IEEE0,
1517 MDIO_COMBO_IEEE0_MII_CONTROL,
1518 mii_control);
1519
1520 } else { /* AN mode */
1521 /* enable and restart AN */
Eilon Greenstein239d6862009-08-12 08:23:04 +00001522 bnx2x_restart_autoneg(params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001523 }
1524}
1525
1526
1527/*
1528 * link management
1529 */
1530
1531static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001532{ /* LD LP */
1533 switch (pause_result) { /* ASYM P ASYM P */
1534 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001535 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001536 break;
1537
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001538 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001539 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001540 break;
1541
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001542 case 0x5: /* 0 1 0 1 */
1543 case 0x7: /* 0 1 1 1 */
1544 case 0xd: /* 1 1 0 1 */
1545 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001546 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001547 break;
1548
1549 default:
1550 break;
1551 }
1552}
1553
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001554static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001555 struct link_vars *vars)
1556{
1557 struct bnx2x *bp = params->bp;
1558 u8 ext_phy_addr;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001559 u16 ld_pause; /* local */
1560 u16 lp_pause; /* link partner */
1561 u16 an_complete; /* AN complete */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001562 u16 pause_result;
1563 u8 ret = 0;
1564 u32 ext_phy_type;
1565 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00001566 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001567 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1568 /* read twice */
1569
1570 bnx2x_cl45_read(bp, port,
1571 ext_phy_type,
1572 ext_phy_addr,
1573 MDIO_AN_DEVAD,
1574 MDIO_AN_REG_STATUS, &an_complete);
1575 bnx2x_cl45_read(bp, port,
1576 ext_phy_type,
1577 ext_phy_addr,
1578 MDIO_AN_DEVAD,
1579 MDIO_AN_REG_STATUS, &an_complete);
1580
1581 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1582 ret = 1;
1583 bnx2x_cl45_read(bp, port,
1584 ext_phy_type,
1585 ext_phy_addr,
1586 MDIO_AN_DEVAD,
1587 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1588 bnx2x_cl45_read(bp, port,
1589 ext_phy_type,
1590 ext_phy_addr,
1591 MDIO_AN_DEVAD,
1592 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1593 pause_result = (ld_pause &
1594 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1595 pause_result |= (lp_pause &
1596 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
Frans Pop2381a552010-03-24 07:57:36 +00001597 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001598 pause_result);
1599 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001600 if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001601 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1602 bnx2x_cl45_read(bp, port,
1603 ext_phy_type,
1604 ext_phy_addr,
1605 MDIO_AN_DEVAD,
1606 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1607
1608 bnx2x_cl45_read(bp, port,
1609 ext_phy_type,
1610 ext_phy_addr,
1611 MDIO_AN_DEVAD,
1612 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1613 pause_result = (ld_pause &
1614 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1615 pause_result |= (lp_pause &
1616 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1617
1618 bnx2x_pause_resolve(vars, pause_result);
Frans Pop2381a552010-03-24 07:57:36 +00001619 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001620 pause_result);
1621 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001622 }
1623 return ret;
1624}
1625
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001626static u8 bnx2x_direct_parallel_detect_used(struct link_params *params)
1627{
1628 struct bnx2x *bp = params->bp;
1629 u16 pd_10g, status2_1000x;
1630 CL45_RD_OVER_CL22(bp, params->port,
1631 params->phy_addr,
1632 MDIO_REG_BANK_SERDES_DIGITAL,
1633 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1634 &status2_1000x);
1635 CL45_RD_OVER_CL22(bp, params->port,
1636 params->phy_addr,
1637 MDIO_REG_BANK_SERDES_DIGITAL,
1638 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1639 &status2_1000x);
1640 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
1641 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
1642 params->port);
1643 return 1;
1644 }
1645
1646 CL45_RD_OVER_CL22(bp, params->port,
1647 params->phy_addr,
1648 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1649 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
1650 &pd_10g);
1651
1652 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
1653 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
1654 params->port);
1655 return 1;
1656 }
1657 return 0;
1658}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001659
1660static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1661 struct link_vars *vars,
1662 u32 gp_status)
1663{
1664 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001665 u16 ld_pause; /* local driver */
1666 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001667 u16 pause_result;
1668
David S. Millerc0700f92008-12-16 23:53:20 -08001669 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001670
1671 /* resolve from gp_status in case of AN complete and not sgmii */
David S. Millerc0700f92008-12-16 23:53:20 -08001672 if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001673 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1674 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1675 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1676 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001677 if (bnx2x_direct_parallel_detect_used(params)) {
1678 vars->flow_ctrl = params->req_fc_auto_adv;
1679 return;
1680 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02001681 if ((gp_status &
1682 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1683 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
1684 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1685 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
1686
1687 CL45_RD_OVER_CL22(bp, params->port,
1688 params->phy_addr,
1689 MDIO_REG_BANK_CL73_IEEEB1,
1690 MDIO_CL73_IEEEB1_AN_ADV1,
1691 &ld_pause);
1692 CL45_RD_OVER_CL22(bp, params->port,
1693 params->phy_addr,
1694 MDIO_REG_BANK_CL73_IEEEB1,
1695 MDIO_CL73_IEEEB1_AN_LP_ADV1,
1696 &lp_pause);
1697 pause_result = (ld_pause &
1698 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
1699 >> 8;
1700 pause_result |= (lp_pause &
1701 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
1702 >> 10;
1703 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
1704 pause_result);
1705 } else {
1706
1707 CL45_RD_OVER_CL22(bp, params->port,
1708 params->phy_addr,
1709 MDIO_REG_BANK_COMBO_IEEE0,
1710 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1711 &ld_pause);
1712 CL45_RD_OVER_CL22(bp, params->port,
1713 params->phy_addr,
1714 MDIO_REG_BANK_COMBO_IEEE0,
1715 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1716 &lp_pause);
1717 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001718 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001719 pause_result |= (lp_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001720 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001721 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
1722 pause_result);
1723 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001724 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001725 } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001726 (bnx2x_ext_phy_resolve_fc(params, vars))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001727 return;
1728 } else {
David S. Millerc0700f92008-12-16 23:53:20 -08001729 if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001730 vars->flow_ctrl = params->req_fc_auto_adv;
1731 else
1732 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001733 }
1734 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1735}
1736
Eilon Greenstein239d6862009-08-12 08:23:04 +00001737static void bnx2x_check_fallback_to_cl37(struct link_params *params)
1738{
1739 struct bnx2x *bp = params->bp;
1740 u16 rx_status, ustat_val, cl37_fsm_recieved;
1741 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
1742 /* Step 1: Make sure signal is detected */
1743 CL45_RD_OVER_CL22(bp, params->port,
1744 params->phy_addr,
1745 MDIO_REG_BANK_RX0,
1746 MDIO_RX0_RX_STATUS,
1747 &rx_status);
1748 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
1749 (MDIO_RX0_RX_STATUS_SIGDET)) {
1750 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
1751 "rx_status(0x80b0) = 0x%x\n", rx_status);
1752 CL45_WR_OVER_CL22(bp, params->port,
1753 params->phy_addr,
1754 MDIO_REG_BANK_CL73_IEEEB0,
1755 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1756 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
1757 return;
1758 }
1759 /* Step 2: Check CL73 state machine */
1760 CL45_RD_OVER_CL22(bp, params->port,
1761 params->phy_addr,
1762 MDIO_REG_BANK_CL73_USERB0,
1763 MDIO_CL73_USERB0_CL73_USTAT1,
1764 &ustat_val);
1765 if ((ustat_val &
1766 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1767 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
1768 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1769 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
1770 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
1771 "ustat_val(0x8371) = 0x%x\n", ustat_val);
1772 return;
1773 }
1774 /* Step 3: Check CL37 Message Pages received to indicate LP
1775 supports only CL37 */
1776 CL45_RD_OVER_CL22(bp, params->port,
1777 params->phy_addr,
1778 MDIO_REG_BANK_REMOTE_PHY,
1779 MDIO_REMOTE_PHY_MISC_RX_STATUS,
1780 &cl37_fsm_recieved);
1781 if ((cl37_fsm_recieved &
1782 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1783 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
1784 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1785 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
1786 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
1787 "misc_rx_status(0x8330) = 0x%x\n",
1788 cl37_fsm_recieved);
1789 return;
1790 }
1791 /* The combined cl37/cl73 fsm state information indicating that we are
1792 connected to a device which does not support cl73, but does support
1793 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
1794 /* Disable CL73 */
1795 CL45_WR_OVER_CL22(bp, params->port,
1796 params->phy_addr,
1797 MDIO_REG_BANK_CL73_IEEEB0,
1798 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1799 0);
1800 /* Restart CL37 autoneg */
1801 bnx2x_restart_autoneg(params, 0);
1802 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
1803}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001804static u8 bnx2x_link_settings_status(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00001805 struct link_vars *vars,
1806 u32 gp_status,
1807 u8 ext_phy_link_up)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001808{
1809 struct bnx2x *bp = params->bp;
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001810 u16 new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001811 u8 rc = 0;
1812 vars->link_status = 0;
1813
1814 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1815 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1816 gp_status);
1817
1818 vars->phy_link_up = 1;
1819 vars->link_status |= LINK_STATUS_LINK_UP;
1820
1821 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1822 vars->duplex = DUPLEX_FULL;
1823 else
1824 vars->duplex = DUPLEX_HALF;
1825
1826 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1827
1828 switch (gp_status & GP_STATUS_SPEED_MASK) {
1829 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001830 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001831 if (vars->duplex == DUPLEX_FULL)
1832 vars->link_status |= LINK_10TFD;
1833 else
1834 vars->link_status |= LINK_10THD;
1835 break;
1836
1837 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001838 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001839 if (vars->duplex == DUPLEX_FULL)
1840 vars->link_status |= LINK_100TXFD;
1841 else
1842 vars->link_status |= LINK_100TXHD;
1843 break;
1844
1845 case GP_STATUS_1G:
1846 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001847 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001848 if (vars->duplex == DUPLEX_FULL)
1849 vars->link_status |= LINK_1000TFD;
1850 else
1851 vars->link_status |= LINK_1000THD;
1852 break;
1853
1854 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001855 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001856 if (vars->duplex == DUPLEX_FULL)
1857 vars->link_status |= LINK_2500TFD;
1858 else
1859 vars->link_status |= LINK_2500THD;
1860 break;
1861
1862 case GP_STATUS_5G:
1863 case GP_STATUS_6G:
1864 DP(NETIF_MSG_LINK,
1865 "link speed unsupported gp_status 0x%x\n",
1866 gp_status);
1867 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001868
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001869 case GP_STATUS_10G_KX4:
1870 case GP_STATUS_10G_HIG:
1871 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001872 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001873 vars->link_status |= LINK_10GTFD;
1874 break;
1875
1876 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001877 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001878 vars->link_status |= LINK_12GTFD;
1879 break;
1880
1881 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001882 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001883 vars->link_status |= LINK_12_5GTFD;
1884 break;
1885
1886 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001887 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001888 vars->link_status |= LINK_13GTFD;
1889 break;
1890
1891 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001892 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001893 vars->link_status |= LINK_15GTFD;
1894 break;
1895
1896 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001897 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001898 vars->link_status |= LINK_16GTFD;
1899 break;
1900
1901 default:
1902 DP(NETIF_MSG_LINK,
1903 "link speed unsupported gp_status 0x%x\n",
1904 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001905 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001906 }
1907
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001908 /* Upon link speed change set the NIG into drain mode.
1909 Comes to deals with possible FIFO glitch due to clk change
1910 when speed is decreased without link down indicator */
1911 if (new_line_speed != vars->line_speed) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00001912 if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) !=
1913 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT &&
1914 ext_phy_link_up) {
1915 DP(NETIF_MSG_LINK, "Internal link speed %d is"
1916 " different than the external"
1917 " link speed %d\n", new_line_speed,
1918 vars->line_speed);
1919 vars->phy_link_up = 0;
1920 return 0;
1921 }
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001922 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
1923 + params->port*4, 0);
1924 msleep(1);
1925 }
1926 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001927 vars->link_status |= LINK_STATUS_SERDES_LINK;
1928
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001929 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1930 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1931 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1932 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein589abe32009-02-12 08:36:55 +00001933 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
1934 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02001935 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
1936 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein2f904462009-08-12 08:22:16 +00001937 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001938 vars->autoneg = AUTO_NEG_ENABLED;
1939
1940 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1941 vars->autoneg |= AUTO_NEG_COMPLETE;
1942 vars->link_status |=
1943 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1944 }
1945
1946 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1947 vars->link_status |=
1948 LINK_STATUS_PARALLEL_DETECTION_USED;
1949
1950 }
David S. Millerc0700f92008-12-16 23:53:20 -08001951 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001952 vars->link_status |=
1953 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001954
David S. Millerc0700f92008-12-16 23:53:20 -08001955 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001956 vars->link_status |=
1957 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001958
1959 } else { /* link_down */
1960 DP(NETIF_MSG_LINK, "phy link down\n");
1961
1962 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001963
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001964 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001965 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001966 vars->autoneg = AUTO_NEG_DISABLED;
1967 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001968
1969 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1970 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1971 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT))) {
1972 /* Check signal is detected */
1973 bnx2x_check_fallback_to_cl37(params);
1974 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001975 }
1976
Frans Pop2381a552010-03-24 07:57:36 +00001977 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001978 gp_status, vars->phy_link_up, vars->line_speed);
1979 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1980 " autoneg 0x%x\n",
1981 vars->duplex,
1982 vars->flow_ctrl, vars->autoneg);
1983 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1984
1985 return rc;
1986}
1987
Eilon Greensteined8680a2009-02-12 08:37:12 +00001988static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001989{
1990 struct bnx2x *bp = params->bp;
1991 u16 lp_up2;
1992 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001993 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001994
1995 /* read precomp */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001996 CL45_RD_OVER_CL22(bp, params->port,
1997 params->phy_addr,
1998 MDIO_REG_BANK_OVER_1G,
1999 MDIO_OVER_1G_LP_UP2, &lp_up2);
2000
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002001 /* bits [10:7] at lp_up2, positioned at [15:12] */
2002 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
2003 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
2004 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
2005
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002006 if (lp_up2 == 0)
2007 return;
2008
2009 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
2010 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
2011 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002012 params->phy_addr,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002013 bank,
2014 MDIO_TX0_TX_DRIVER, &tx_driver);
2015
2016 /* replace tx_driver bits [15:12] */
2017 if (lp_up2 !=
2018 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
2019 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
2020 tx_driver |= lp_up2;
2021 CL45_WR_OVER_CL22(bp, params->port,
2022 params->phy_addr,
2023 bank,
2024 MDIO_TX0_TX_DRIVER, tx_driver);
2025 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002026 }
2027}
2028
2029static u8 bnx2x_emac_program(struct link_params *params,
2030 u32 line_speed, u32 duplex)
2031{
2032 struct bnx2x *bp = params->bp;
2033 u8 port = params->port;
2034 u16 mode = 0;
2035
2036 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
2037 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
2038 EMAC_REG_EMAC_MODE,
2039 (EMAC_MODE_25G_MODE |
2040 EMAC_MODE_PORT_MII_10M |
2041 EMAC_MODE_HALF_DUPLEX));
2042 switch (line_speed) {
2043 case SPEED_10:
2044 mode |= EMAC_MODE_PORT_MII_10M;
2045 break;
2046
2047 case SPEED_100:
2048 mode |= EMAC_MODE_PORT_MII;
2049 break;
2050
2051 case SPEED_1000:
2052 mode |= EMAC_MODE_PORT_GMII;
2053 break;
2054
2055 case SPEED_2500:
2056 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2057 break;
2058
2059 default:
2060 /* 10G not valid for EMAC */
2061 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
2062 return -EINVAL;
2063 }
2064
2065 if (duplex == DUPLEX_HALF)
2066 mode |= EMAC_MODE_HALF_DUPLEX;
2067 bnx2x_bits_en(bp,
2068 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2069 mode);
2070
Yaniv Rosner7846e472009-11-05 19:18:07 +02002071 bnx2x_set_led(params, LED_MODE_OPER, line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002072 return 0;
2073}
2074
2075/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002076/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002077/*****************************************************************************/
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002078void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002079{
2080 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002081 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002082 msleep(1);
2083 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002084 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002085}
2086
2087static void bnx2x_ext_phy_reset(struct link_params *params,
2088 struct link_vars *vars)
2089{
2090 struct bnx2x *bp = params->bp;
2091 u32 ext_phy_type;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002092 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
2093
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002094 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
2095 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2096 /* The PHY reset is controled by GPIO 1
2097 * Give it 1ms of reset pulse
2098 */
2099 if (vars->phy_flags & PHY_XGXS_FLAG) {
2100
2101 switch (ext_phy_type) {
2102 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
2103 DP(NETIF_MSG_LINK, "XGXS Direct\n");
2104 break;
2105
2106 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2107 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2108 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
2109
2110 /* Restore normal power mode*/
2111 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002112 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2113 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002114
2115 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002116 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002117
2118 bnx2x_cl45_write(bp, params->port,
2119 ext_phy_type,
2120 ext_phy_addr,
2121 MDIO_PMA_DEVAD,
2122 MDIO_PMA_REG_CTRL, 0xa040);
2123 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002124
2125 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
2126 break;
2127
Eilon Greenstein589abe32009-02-12 08:36:55 +00002128 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
2129
2130 /* Restore normal power mode*/
2131 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2132 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2133 params->port);
2134
2135 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
2136 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2137 params->port);
2138
2139 bnx2x_cl45_write(bp, params->port,
2140 ext_phy_type,
2141 ext_phy_addr,
2142 MDIO_PMA_DEVAD,
2143 MDIO_PMA_REG_CTRL,
2144 1<<15);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002145 break;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002146
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002147 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002148 DP(NETIF_MSG_LINK, "XGXS 8072\n");
2149
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002150 /* Unset Low Power Mode and SW reset */
2151 /* Restore normal power mode*/
2152 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002153 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2154 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002155
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002156 bnx2x_cl45_write(bp, params->port,
2157 ext_phy_type,
2158 ext_phy_addr,
2159 MDIO_PMA_DEVAD,
2160 MDIO_PMA_REG_CTRL,
2161 1<<15);
2162 break;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002163
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002164 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002165 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002166
2167 /* Restore normal power mode*/
2168 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002169 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2170 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002171
2172 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002173 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2174 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002175 break;
2176
2177 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
2178 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
2179
2180 /* Restore normal power mode*/
2181 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002182 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2183 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002184
2185 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002186 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002187 break;
2188
Eilon Greenstein28577182009-02-12 08:37:00 +00002189 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Eilon Greenstein28577182009-02-12 08:37:00 +00002190 /* Restore normal power mode*/
2191 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2192 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2193 params->port);
2194
2195 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002196 bnx2x_ext_phy_hw_reset(bp, params->port);
Eilon Greenstein28577182009-02-12 08:37:00 +00002197
2198 bnx2x_cl45_write(bp, params->port,
2199 ext_phy_type,
2200 ext_phy_addr,
2201 MDIO_PMA_DEVAD,
2202 MDIO_PMA_REG_CTRL,
2203 1<<15);
2204 break;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02002205 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00002206 msleep(1);
2207 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
2208 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2209 params->port);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02002210 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002211 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
2212 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
2213 break;
2214
2215 default:
2216 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
2217 params->ext_phy_config);
2218 break;
2219 }
2220
2221 } else { /* SerDes */
2222 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
2223 switch (ext_phy_type) {
2224 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
2225 DP(NETIF_MSG_LINK, "SerDes Direct\n");
2226 break;
2227
2228 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
2229 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002230 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002231 break;
2232
2233 default:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002234 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002235 params->ext_phy_config);
2236 break;
2237 }
2238 }
2239}
2240
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002241static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
2242 u32 shmem_base, u32 spirom_ver)
2243{
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002244 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
2245 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002246 REG_WR(bp, shmem_base +
2247 offsetof(struct shmem_region,
2248 port_mb[port].ext_phy_fw_version),
2249 spirom_ver);
2250}
2251
2252static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
2253 u32 ext_phy_type, u8 ext_phy_addr,
2254 u32 shmem_base)
2255{
2256 u16 fw_ver1, fw_ver2;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002257
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002258 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2259 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2260 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2261 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2262 bnx2x_save_spirom_version(bp, port, shmem_base,
2263 (u32)(fw_ver1<<16 | fw_ver2));
2264}
2265
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002266
2267static void bnx2x_save_8481_spirom_version(struct bnx2x *bp, u8 port,
2268 u8 ext_phy_addr, u32 shmem_base)
2269{
2270 u16 val, fw_ver1, fw_ver2, cnt;
2271 /* For the 32 bits registers in 8481, access via MDIO2ARM interface.*/
2272 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
2273 bnx2x_cl45_write(bp, port,
2274 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2275 ext_phy_addr, MDIO_PMA_DEVAD,
2276 0xA819, 0x0014);
2277 bnx2x_cl45_write(bp, port,
2278 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2279 ext_phy_addr,
2280 MDIO_PMA_DEVAD,
2281 0xA81A,
2282 0xc200);
2283 bnx2x_cl45_write(bp, port,
2284 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2285 ext_phy_addr,
2286 MDIO_PMA_DEVAD,
2287 0xA81B,
2288 0x0000);
2289 bnx2x_cl45_write(bp, port,
2290 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2291 ext_phy_addr,
2292 MDIO_PMA_DEVAD,
2293 0xA81C,
2294 0x0300);
2295 bnx2x_cl45_write(bp, port,
2296 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2297 ext_phy_addr,
2298 MDIO_PMA_DEVAD,
2299 0xA817,
2300 0x0009);
2301
2302 for (cnt = 0; cnt < 100; cnt++) {
2303 bnx2x_cl45_read(bp, port,
2304 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2305 ext_phy_addr,
2306 MDIO_PMA_DEVAD,
2307 0xA818,
2308 &val);
2309 if (val & 1)
2310 break;
2311 udelay(5);
2312 }
2313 if (cnt == 100) {
2314 DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n");
2315 bnx2x_save_spirom_version(bp, port,
2316 shmem_base, 0);
2317 return;
2318 }
2319
2320
2321 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
2322 bnx2x_cl45_write(bp, port,
2323 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2324 ext_phy_addr, MDIO_PMA_DEVAD,
2325 0xA819, 0x0000);
2326 bnx2x_cl45_write(bp, port,
2327 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2328 ext_phy_addr, MDIO_PMA_DEVAD,
2329 0xA81A, 0xc200);
2330 bnx2x_cl45_write(bp, port,
2331 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2332 ext_phy_addr, MDIO_PMA_DEVAD,
2333 0xA817, 0x000A);
2334 for (cnt = 0; cnt < 100; cnt++) {
2335 bnx2x_cl45_read(bp, port,
2336 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2337 ext_phy_addr,
2338 MDIO_PMA_DEVAD,
2339 0xA818,
2340 &val);
2341 if (val & 1)
2342 break;
2343 udelay(5);
2344 }
2345 if (cnt == 100) {
2346 DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(2)\n");
2347 bnx2x_save_spirom_version(bp, port,
2348 shmem_base, 0);
2349 return;
2350 }
2351
2352 /* lower 16 bits of the register SPI_FW_STATUS */
2353 bnx2x_cl45_read(bp, port,
2354 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2355 ext_phy_addr,
2356 MDIO_PMA_DEVAD,
2357 0xA81B,
2358 &fw_ver1);
2359 /* upper 16 bits of register SPI_FW_STATUS */
2360 bnx2x_cl45_read(bp, port,
2361 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2362 ext_phy_addr,
2363 MDIO_PMA_DEVAD,
2364 0xA81C,
2365 &fw_ver2);
2366
2367 bnx2x_save_spirom_version(bp, port,
2368 shmem_base, (fw_ver2<<16) | fw_ver1);
2369}
2370
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002371static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
2372{
2373 struct bnx2x *bp = params->bp;
2374 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002375 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002376 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002377
2378 /* Need to wait 200ms after reset */
2379 msleep(200);
2380 /* Boot port from external ROM
2381 * Set ser_boot_ctl bit in the MISC_CTRL1 register
2382 */
2383 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2384 MDIO_PMA_DEVAD,
2385 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2386
2387 /* Reset internal microprocessor */
2388 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2389 MDIO_PMA_DEVAD,
2390 MDIO_PMA_REG_GEN_CTRL,
2391 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2392 /* set micro reset = 0 */
2393 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2394 MDIO_PMA_DEVAD,
2395 MDIO_PMA_REG_GEN_CTRL,
2396 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2397 /* Reset internal microprocessor */
2398 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2399 MDIO_PMA_DEVAD,
2400 MDIO_PMA_REG_GEN_CTRL,
2401 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2402 /* wait for 100ms for code download via SPI port */
2403 msleep(100);
2404
2405 /* Clear ser_boot_ctl bit */
2406 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2407 MDIO_PMA_DEVAD,
2408 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2409 /* Wait 100ms */
2410 msleep(100);
2411
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002412 bnx2x_save_bcm_spirom_ver(bp, port,
2413 ext_phy_type,
2414 ext_phy_addr,
2415 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002416}
2417
2418static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2419{
2420 /* This is only required for 8073A1, version 102 only */
2421
2422 struct bnx2x *bp = params->bp;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002423 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002424 u16 val;
2425
2426 /* Read 8073 HW revision*/
2427 bnx2x_cl45_read(bp, params->port,
2428 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2429 ext_phy_addr,
2430 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002431 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002432
2433 if (val != 1) {
2434 /* No need to workaround in 8073 A1 */
2435 return 0;
2436 }
2437
2438 bnx2x_cl45_read(bp, params->port,
2439 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2440 ext_phy_addr,
2441 MDIO_PMA_DEVAD,
2442 MDIO_PMA_REG_ROM_VER2, &val);
2443
2444 /* SNR should be applied only for version 0x102 */
2445 if (val != 0x102)
2446 return 0;
2447
2448 return 1;
2449}
2450
2451static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2452{
2453 struct bnx2x *bp = params->bp;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002454 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002455 u16 val, cnt, cnt1 ;
2456
2457 bnx2x_cl45_read(bp, params->port,
2458 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2459 ext_phy_addr,
2460 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002461 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002462
2463 if (val > 0) {
2464 /* No need to workaround in 8073 A1 */
2465 return 0;
2466 }
2467 /* XAUI workaround in 8073 A0: */
2468
2469 /* After loading the boot ROM and restarting Autoneg,
2470 poll Dev1, Reg $C820: */
2471
2472 for (cnt = 0; cnt < 1000; cnt++) {
2473 bnx2x_cl45_read(bp, params->port,
2474 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2475 ext_phy_addr,
2476 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002477 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
2478 &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002479 /* If bit [14] = 0 or bit [13] = 0, continue on with
2480 system initialization (XAUI work-around not required,
2481 as these bits indicate 2.5G or 1G link up). */
2482 if (!(val & (1<<14)) || !(val & (1<<13))) {
2483 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2484 return 0;
2485 } else if (!(val & (1<<15))) {
2486 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2487 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2488 it's MSB (bit 15) goes to 1 (indicating that the
2489 XAUI workaround has completed),
2490 then continue on with system initialization.*/
2491 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2492 bnx2x_cl45_read(bp, params->port,
2493 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2494 ext_phy_addr,
2495 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002496 MDIO_PMA_REG_8073_XAUI_WA, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002497 if (val & (1<<15)) {
2498 DP(NETIF_MSG_LINK,
2499 "XAUI workaround has completed\n");
2500 return 0;
2501 }
2502 msleep(3);
2503 }
2504 break;
2505 }
2506 msleep(3);
2507 }
2508 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2509 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002510}
2511
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002512static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
2513 u8 ext_phy_addr,
2514 u32 ext_phy_type,
2515 u32 shmem_base)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002516{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002517 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002518 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002519 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002520 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002521 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002522 MDIO_PMA_DEVAD,
2523 MDIO_PMA_REG_GEN_CTRL,
2524 0x0001);
2525
2526 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002527 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002528 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002529 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002530 MDIO_PMA_DEVAD,
2531 MDIO_PMA_REG_GEN_CTRL,
2532 0x008c);
2533
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002534 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002535 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002536 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002537 MDIO_PMA_DEVAD,
2538 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2539
2540 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002541 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002542 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002543 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002544 MDIO_PMA_DEVAD,
2545 MDIO_PMA_REG_GEN_CTRL,
2546 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2547
2548 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002549 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002550 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002551 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002552 MDIO_PMA_DEVAD,
2553 MDIO_PMA_REG_GEN_CTRL,
2554 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2555
Yaniv Rosner8ca60a62010-09-01 09:51:17 +00002556 /* wait for 120ms for code download via SPI port */
2557 msleep(120);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002558
2559 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002560 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002561 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002562 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002563 MDIO_PMA_DEVAD,
2564 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2565
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002566 bnx2x_save_bcm_spirom_ver(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002567 ext_phy_type,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002568 ext_phy_addr,
2569 shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002570}
2571
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002572static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
2573 u8 ext_phy_addr,
2574 u32 shmem_base)
2575{
2576 bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
2577 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2578 shmem_base);
2579}
2580
2581static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
2582 u8 ext_phy_addr,
2583 u32 shmem_base)
2584{
2585 bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
2586 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
2587 shmem_base);
2588
2589}
2590
Eilon Greenstein589abe32009-02-12 08:36:55 +00002591static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
2592{
2593 struct bnx2x *bp = params->bp;
2594 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002595 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002596 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2597
2598 /* Need to wait 100ms after reset */
2599 msleep(100);
2600
Eilon Greenstein589abe32009-02-12 08:36:55 +00002601 /* Micro controller re-boot */
2602 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2603 MDIO_PMA_DEVAD,
2604 MDIO_PMA_REG_GEN_CTRL,
Yaniv Rosner93f72882009-11-05 19:18:26 +02002605 0x018B);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002606
2607 /* Set soft reset */
2608 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2609 MDIO_PMA_DEVAD,
2610 MDIO_PMA_REG_GEN_CTRL,
2611 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2612
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002613 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2614 MDIO_PMA_DEVAD,
Yaniv Rosner93f72882009-11-05 19:18:26 +02002615 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002616
Eilon Greenstein589abe32009-02-12 08:36:55 +00002617 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2618 MDIO_PMA_DEVAD,
2619 MDIO_PMA_REG_GEN_CTRL,
2620 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2621
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002622 /* wait for 150ms for microcode load */
2623 msleep(150);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002624
2625 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
2626 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2627 MDIO_PMA_DEVAD,
2628 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2629
2630 msleep(200);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002631 bnx2x_save_bcm_spirom_ver(bp, port,
2632 ext_phy_type,
2633 ext_phy_addr,
2634 params->shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002635}
2636
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002637static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
2638 u32 ext_phy_type, u8 ext_phy_addr,
2639 u8 tx_en)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002640{
2641 u16 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002642
Eilon Greenstein589abe32009-02-12 08:36:55 +00002643 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2644 tx_en, port);
2645 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
2646 bnx2x_cl45_read(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002647 ext_phy_type,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002648 ext_phy_addr,
2649 MDIO_PMA_DEVAD,
2650 MDIO_PMA_REG_PHY_IDENTIFIER,
2651 &val);
2652
2653 if (tx_en)
2654 val &= ~(1<<15);
2655 else
2656 val |= (1<<15);
2657
2658 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002659 ext_phy_type,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002660 ext_phy_addr,
2661 MDIO_PMA_DEVAD,
2662 MDIO_PMA_REG_PHY_IDENTIFIER,
2663 val);
2664}
2665
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002666static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
2667 u16 addr, u8 byte_cnt, u8 *o_buf)
2668{
Eilon Greenstein589abe32009-02-12 08:36:55 +00002669 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002670 u16 val = 0;
2671 u16 i;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002672 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002673 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002674 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002675
Eilon Greenstein589abe32009-02-12 08:36:55 +00002676 if (byte_cnt > 16) {
2677 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2678 " is limited to 0xf\n");
2679 return -EINVAL;
2680 }
2681 /* Set the read command byte count */
2682 bnx2x_cl45_write(bp, port,
2683 ext_phy_type,
2684 ext_phy_addr,
2685 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002686 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002687 (byte_cnt | 0xa000));
2688
2689 /* Set the read command address */
2690 bnx2x_cl45_write(bp, port,
2691 ext_phy_type,
2692 ext_phy_addr,
2693 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002694 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002695 addr);
2696
2697 /* Activate read command */
2698 bnx2x_cl45_write(bp, port,
2699 ext_phy_type,
2700 ext_phy_addr,
2701 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002702 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002703 0x2c0f);
2704
2705 /* Wait up to 500us for command complete status */
2706 for (i = 0; i < 100; i++) {
2707 bnx2x_cl45_read(bp, port,
2708 ext_phy_type,
2709 ext_phy_addr,
2710 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002711 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2712 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2713 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002714 break;
2715 udelay(5);
2716 }
2717
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002718 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2719 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002720 DP(NETIF_MSG_LINK,
2721 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002722 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Eilon Greenstein589abe32009-02-12 08:36:55 +00002723 return -EINVAL;
2724 }
2725
2726 /* Read the buffer */
2727 for (i = 0; i < byte_cnt; i++) {
2728 bnx2x_cl45_read(bp, port,
2729 ext_phy_type,
2730 ext_phy_addr,
2731 MDIO_PMA_DEVAD,
2732 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2733 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2734 }
2735
2736 for (i = 0; i < 100; i++) {
2737 bnx2x_cl45_read(bp, port,
2738 ext_phy_type,
2739 ext_phy_addr,
2740 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002741 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2742 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2743 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002744 return 0;;
2745 msleep(1);
2746 }
2747 return -EINVAL;
2748}
2749
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002750static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
2751 u16 addr, u8 byte_cnt, u8 *o_buf)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002752{
2753 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002754 u16 val, i;
2755 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002756 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002757 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2758
2759 if (byte_cnt > 16) {
2760 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2761 " is limited to 0xf\n");
2762 return -EINVAL;
2763 }
2764
2765 /* Need to read from 1.8000 to clear it */
2766 bnx2x_cl45_read(bp, port,
2767 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
2768 ext_phy_addr,
2769 MDIO_PMA_DEVAD,
2770 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2771 &val);
2772
2773 /* Set the read command byte count */
2774 bnx2x_cl45_write(bp, port,
2775 ext_phy_type,
2776 ext_phy_addr,
2777 MDIO_PMA_DEVAD,
2778 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
2779 ((byte_cnt < 2) ? 2 : byte_cnt));
2780
2781 /* Set the read command address */
2782 bnx2x_cl45_write(bp, port,
2783 ext_phy_type,
2784 ext_phy_addr,
2785 MDIO_PMA_DEVAD,
2786 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
2787 addr);
2788 /* Set the destination address */
2789 bnx2x_cl45_write(bp, port,
2790 ext_phy_type,
2791 ext_phy_addr,
2792 MDIO_PMA_DEVAD,
2793 0x8004,
2794 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
2795
2796 /* Activate read command */
2797 bnx2x_cl45_write(bp, port,
2798 ext_phy_type,
2799 ext_phy_addr,
2800 MDIO_PMA_DEVAD,
2801 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2802 0x8002);
2803 /* Wait appropriate time for two-wire command to finish before
2804 polling the status register */
2805 msleep(1);
2806
2807 /* Wait up to 500us for command complete status */
2808 for (i = 0; i < 100; i++) {
2809 bnx2x_cl45_read(bp, port,
2810 ext_phy_type,
2811 ext_phy_addr,
2812 MDIO_PMA_DEVAD,
2813 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2814 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2815 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
2816 break;
2817 udelay(5);
2818 }
2819
2820 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2821 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
2822 DP(NETIF_MSG_LINK,
2823 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2824 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
2825 return -EINVAL;
2826 }
2827
2828 /* Read the buffer */
2829 for (i = 0; i < byte_cnt; i++) {
2830 bnx2x_cl45_read(bp, port,
2831 ext_phy_type,
2832 ext_phy_addr,
2833 MDIO_PMA_DEVAD,
2834 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
2835 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
2836 }
2837
2838 for (i = 0; i < 100; i++) {
2839 bnx2x_cl45_read(bp, port,
2840 ext_phy_type,
2841 ext_phy_addr,
2842 MDIO_PMA_DEVAD,
2843 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2844 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2845 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
2846 return 0;;
2847 msleep(1);
2848 }
2849
2850 return -EINVAL;
2851}
2852
2853u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
2854 u8 byte_cnt, u8 *o_buf)
2855{
2856 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2857
2858 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
2859 return bnx2x_8726_read_sfp_module_eeprom(params, addr,
2860 byte_cnt, o_buf);
2861 else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
2862 return bnx2x_8727_read_sfp_module_eeprom(params, addr,
2863 byte_cnt, o_buf);
2864 return -EINVAL;
2865}
2866
2867static u8 bnx2x_get_edc_mode(struct link_params *params,
2868 u16 *edc_mode)
2869{
2870 struct bnx2x *bp = params->bp;
2871 u8 val, check_limiting_mode = 0;
2872 *edc_mode = EDC_MODE_LIMITING;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002873
2874 /* First check for copper cable */
2875 if (bnx2x_read_sfp_module_eeprom(params,
2876 SFP_EEPROM_CON_TYPE_ADDR,
2877 1,
2878 &val) != 0) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002879 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002880 return -EINVAL;
2881 }
2882
2883 switch (val) {
2884 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2885 {
2886 u8 copper_module_type;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002887
Eilon Greenstein589abe32009-02-12 08:36:55 +00002888 /* Check if its active cable( includes SFP+ module)
2889 of passive cable*/
2890 if (bnx2x_read_sfp_module_eeprom(params,
2891 SFP_EEPROM_FC_TX_TECH_ADDR,
2892 1,
2893 &copper_module_type) !=
2894 0) {
2895 DP(NETIF_MSG_LINK,
2896 "Failed to read copper-cable-type"
2897 " from SFP+ EEPROM\n");
2898 return -EINVAL;
2899 }
2900
2901 if (copper_module_type &
2902 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2903 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002904 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002905 } else if (copper_module_type &
2906 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2907 DP(NETIF_MSG_LINK, "Passive Copper"
2908 " cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002909 *edc_mode =
2910 EDC_MODE_PASSIVE_DAC;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002911 } else {
2912 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2913 "type 0x%x !!!\n", copper_module_type);
2914 return -EINVAL;
2915 }
2916 break;
2917 }
2918 case SFP_EEPROM_CON_TYPE_VAL_LC:
2919 DP(NETIF_MSG_LINK, "Optic module detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002920 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002921 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002922 default:
2923 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2924 val);
2925 return -EINVAL;
2926 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002927
2928 if (check_limiting_mode) {
2929 u8 options[SFP_EEPROM_OPTIONS_SIZE];
2930 if (bnx2x_read_sfp_module_eeprom(params,
2931 SFP_EEPROM_OPTIONS_ADDR,
2932 SFP_EEPROM_OPTIONS_SIZE,
2933 options) != 0) {
2934 DP(NETIF_MSG_LINK, "Failed to read Option"
2935 " field from module EEPROM\n");
2936 return -EINVAL;
2937 }
2938 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
2939 *edc_mode = EDC_MODE_LINEAR;
2940 else
2941 *edc_mode = EDC_MODE_LIMITING;
2942 }
2943 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002944 return 0;
2945}
2946
Eilon Greenstein589abe32009-02-12 08:36:55 +00002947/* This function read the relevant field from the module ( SFP+ ),
2948 and verify it is compliant with this board */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002949static u8 bnx2x_verify_sfp_module(struct link_params *params)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002950{
2951 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002952 u32 val;
2953 u32 fw_resp;
2954 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
2955 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Eilon Greenstein589abe32009-02-12 08:36:55 +00002956
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002957 val = REG_RD(bp, params->shmem_base +
2958 offsetof(struct shmem_region, dev_info.
2959 port_feature_config[params->port].config));
2960 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
2961 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002962 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2963 return 0;
2964 }
2965
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002966 /* Ask the FW to validate the module */
2967 if (!(params->feature_config_flags &
2968 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
2969 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
2970 "verification\n");
2971 return -EINVAL;
2972 }
2973
2974 fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
2975 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
2976 DP(NETIF_MSG_LINK, "Approved module\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002977 return 0;
2978 }
2979
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002980 /* format the warning message */
Eilon Greenstein589abe32009-02-12 08:36:55 +00002981 if (bnx2x_read_sfp_module_eeprom(params,
2982 SFP_EEPROM_VENDOR_NAME_ADDR,
2983 SFP_EEPROM_VENDOR_NAME_SIZE,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002984 (u8 *)vendor_name))
2985 vendor_name[0] = '\0';
2986 else
2987 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
2988 if (bnx2x_read_sfp_module_eeprom(params,
2989 SFP_EEPROM_PART_NO_ADDR,
2990 SFP_EEPROM_PART_NO_SIZE,
2991 (u8 *)vendor_pn))
2992 vendor_pn[0] = '\0';
2993 else
2994 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
Eilon Greenstein589abe32009-02-12 08:36:55 +00002995
Joe Perches7995c642010-02-17 15:01:52 +00002996 netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected, Port %d from %s part number %s\n",
2997 params->port, vendor_name, vendor_pn);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002998 return -EINVAL;
2999}
3000
Eilon Greenstein589abe32009-02-12 08:36:55 +00003001static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003002 u16 edc_mode)
Eilon Greenstein589abe32009-02-12 08:36:55 +00003003{
3004 struct bnx2x *bp = params->bp;
3005 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003006 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greensteincc1cb002009-03-02 08:00:03 +00003007 u16 cur_limiting_mode;
Eilon Greensteincc1cb002009-03-02 08:00:03 +00003008
3009 bnx2x_cl45_read(bp, port,
3010 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3011 ext_phy_addr,
3012 MDIO_PMA_DEVAD,
3013 MDIO_PMA_REG_ROM_VER2,
3014 &cur_limiting_mode);
3015 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
3016 cur_limiting_mode);
3017
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003018 if (edc_mode == EDC_MODE_LIMITING) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003019 DP(NETIF_MSG_LINK,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003020 "Setting LIMITING MODE\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00003021 bnx2x_cl45_write(bp, port,
3022 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3023 ext_phy_addr,
3024 MDIO_PMA_DEVAD,
3025 MDIO_PMA_REG_ROM_VER2,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003026 EDC_MODE_LIMITING);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003027 } else { /* LRM mode ( default )*/
Eilon Greensteincc1cb002009-03-02 08:00:03 +00003028
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003029 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00003030
Eilon Greenstein589abe32009-02-12 08:36:55 +00003031 /* Changing to LRM mode takes quite few seconds.
3032 So do it only if current mode is limiting
3033 ( default is LRM )*/
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003034 if (cur_limiting_mode != EDC_MODE_LIMITING)
Eilon Greenstein589abe32009-02-12 08:36:55 +00003035 return 0;
3036
3037 bnx2x_cl45_write(bp, port,
3038 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3039 ext_phy_addr,
3040 MDIO_PMA_DEVAD,
3041 MDIO_PMA_REG_LRM_MODE,
3042 0);
3043 bnx2x_cl45_write(bp, port,
3044 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3045 ext_phy_addr,
3046 MDIO_PMA_DEVAD,
3047 MDIO_PMA_REG_ROM_VER2,
3048 0x128);
3049 bnx2x_cl45_write(bp, port,
3050 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3051 ext_phy_addr,
3052 MDIO_PMA_DEVAD,
3053 MDIO_PMA_REG_MISC_CTRL0,
3054 0x4008);
3055 bnx2x_cl45_write(bp, port,
3056 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3057 ext_phy_addr,
3058 MDIO_PMA_DEVAD,
3059 MDIO_PMA_REG_LRM_MODE,
3060 0xaaaa);
3061 }
3062 return 0;
3063}
3064
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003065static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
3066 u16 edc_mode)
3067{
3068 struct bnx2x *bp = params->bp;
3069 u8 port = params->port;
3070 u16 phy_identifier;
3071 u16 rom_ver2_val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003072 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003073
3074 bnx2x_cl45_read(bp, port,
3075 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3076 ext_phy_addr,
3077 MDIO_PMA_DEVAD,
3078 MDIO_PMA_REG_PHY_IDENTIFIER,
3079 &phy_identifier);
3080
3081 bnx2x_cl45_write(bp, port,
3082 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3083 ext_phy_addr,
3084 MDIO_PMA_DEVAD,
3085 MDIO_PMA_REG_PHY_IDENTIFIER,
3086 (phy_identifier & ~(1<<9)));
3087
3088 bnx2x_cl45_read(bp, port,
3089 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3090 ext_phy_addr,
3091 MDIO_PMA_DEVAD,
3092 MDIO_PMA_REG_ROM_VER2,
3093 &rom_ver2_val);
3094 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
3095 bnx2x_cl45_write(bp, port,
3096 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3097 ext_phy_addr,
3098 MDIO_PMA_DEVAD,
3099 MDIO_PMA_REG_ROM_VER2,
3100 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
3101
3102 bnx2x_cl45_write(bp, port,
3103 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3104 ext_phy_addr,
3105 MDIO_PMA_DEVAD,
3106 MDIO_PMA_REG_PHY_IDENTIFIER,
3107 (phy_identifier | (1<<9)));
3108
3109 return 0;
3110}
3111
3112
Eilon Greenstein589abe32009-02-12 08:36:55 +00003113static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
3114{
3115 u8 val;
3116 struct bnx2x *bp = params->bp;
3117 u16 timeout;
3118 /* Initialization time after hot-plug may take up to 300ms for some
3119 phys type ( e.g. JDSU ) */
3120 for (timeout = 0; timeout < 60; timeout++) {
3121 if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
3122 == 0) {
3123 DP(NETIF_MSG_LINK, "SFP+ module initialization "
3124 "took %d ms\n", timeout * 5);
3125 return 0;
3126 }
3127 msleep(5);
3128 }
3129 return -EINVAL;
3130}
3131
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003132static void bnx2x_8727_power_module(struct bnx2x *bp,
3133 struct link_params *params,
3134 u8 ext_phy_addr, u8 is_power_up) {
3135 /* Make sure GPIOs are not using for LED mode */
3136 u16 val;
3137 u8 port = params->port;
3138 /*
3139 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
3140 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
3141 * output
3142 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
3143 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
3144 * where the 1st bit is the over-current(only input), and 2nd bit is
3145 * for power( only output )
3146 */
3147
3148 /*
3149 * In case of NOC feature is disabled and power is up, set GPIO control
3150 * as input to enable listening of over-current indication
3151 */
3152
3153 if (!(params->feature_config_flags &
3154 FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
3155 val = (1<<4);
3156 else
3157 /*
3158 * Set GPIO control to OUTPUT, and set the power bit
3159 * to according to the is_power_up
3160 */
3161 val = ((!(is_power_up)) << 1);
3162
3163 bnx2x_cl45_write(bp, port,
3164 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3165 ext_phy_addr,
3166 MDIO_PMA_DEVAD,
3167 MDIO_PMA_REG_8727_GPIO_CTRL,
3168 val);
3169}
3170
Eilon Greenstein589abe32009-02-12 08:36:55 +00003171static u8 bnx2x_sfp_module_detection(struct link_params *params)
3172{
3173 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003174 u16 edc_mode;
3175 u8 rc = 0;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003176 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003177 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003178 u32 val = REG_RD(bp, params->shmem_base +
3179 offsetof(struct shmem_region, dev_info.
3180 port_feature_config[params->port].config));
Eilon Greenstein589abe32009-02-12 08:36:55 +00003181
3182 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
3183 params->port);
3184
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003185 if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003186 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003187 return -EINVAL;
3188 } else if (bnx2x_verify_sfp_module(params) !=
Eilon Greenstein589abe32009-02-12 08:36:55 +00003189 0) {
3190 /* check SFP+ module compatibility */
3191 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003192 rc = -EINVAL;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003193 /* Turn on fault module-detected led */
3194 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3195 MISC_REGISTERS_GPIO_HIGH,
3196 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003197 if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
3198 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3199 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
3200 /* Shutdown SFP+ module */
3201 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
3202 bnx2x_8727_power_module(bp, params,
3203 ext_phy_addr, 0);
3204 return rc;
3205 }
3206 } else {
3207 /* Turn off fault module-detected led */
3208 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
3209 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3210 MISC_REGISTERS_GPIO_LOW,
3211 params->port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003212 }
3213
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003214 /* power up the SFP module */
3215 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
3216 bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003217
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003218 /* Check and set limiting mode / LRM mode on 8726.
3219 On 8727 it is done automatically */
3220 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
3221 bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
3222 else
3223 bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
3224 /*
3225 * Enable transmit for this module if the module is approved, or
3226 * if unapproved modules should also enable the Tx laser
3227 */
3228 if (rc == 0 ||
3229 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
3230 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
3231 bnx2x_sfp_set_transmitter(bp, params->port,
3232 ext_phy_type, ext_phy_addr, 1);
3233 else
3234 bnx2x_sfp_set_transmitter(bp, params->port,
3235 ext_phy_type, ext_phy_addr, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003236
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003237 return rc;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003238}
3239
3240void bnx2x_handle_module_detect_int(struct link_params *params)
3241{
3242 struct bnx2x *bp = params->bp;
3243 u32 gpio_val;
3244 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003245
Eilon Greenstein589abe32009-02-12 08:36:55 +00003246 /* Set valid module led off */
3247 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3248 MISC_REGISTERS_GPIO_HIGH,
3249 params->port);
3250
3251 /* Get current gpio val refelecting module plugged in / out*/
3252 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
3253
3254 /* Call the handling function in case module is detected */
3255 if (gpio_val == 0) {
3256
3257 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
3258 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
3259 port);
3260
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003261 if (bnx2x_wait_for_sfp_module_initialized(params) ==
3262 0)
Eilon Greenstein589abe32009-02-12 08:36:55 +00003263 bnx2x_sfp_module_detection(params);
3264 else
3265 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
3266 } else {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003267 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
3268
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003269 u32 ext_phy_type =
3270 XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3271 u32 val = REG_RD(bp, params->shmem_base +
3272 offsetof(struct shmem_region, dev_info.
3273 port_feature_config[params->port].
3274 config));
3275
Eilon Greenstein589abe32009-02-12 08:36:55 +00003276 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
3277 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
3278 port);
3279 /* Module was plugged out. */
3280 /* Disable transmit for this module */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003281 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3282 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
3283 bnx2x_sfp_set_transmitter(bp, params->port,
3284 ext_phy_type, ext_phy_addr, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003285 }
3286}
3287
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003288static void bnx2x_bcm807x_force_10G(struct link_params *params)
3289{
3290 struct bnx2x *bp = params->bp;
3291 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003292 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003293 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3294
3295 /* Force KR or KX */
3296 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3297 MDIO_PMA_DEVAD,
3298 MDIO_PMA_REG_CTRL,
3299 0x2040);
3300 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3301 MDIO_PMA_DEVAD,
3302 MDIO_PMA_REG_10G_CTRL2,
3303 0x000b);
3304 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3305 MDIO_PMA_DEVAD,
3306 MDIO_PMA_REG_BCM_CTRL,
3307 0x0000);
3308 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3309 MDIO_AN_DEVAD,
3310 MDIO_AN_REG_CTRL,
3311 0x0000);
3312}
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003313
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003314static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
3315{
3316 struct bnx2x *bp = params->bp;
3317 u8 port = params->port;
3318 u16 val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003319 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003320 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3321
3322 bnx2x_cl45_read(bp, params->port,
3323 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
3324 ext_phy_addr,
3325 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003326 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003327
3328 if (val == 0) {
3329 /* Mustn't set low power mode in 8073 A0 */
3330 return;
3331 }
3332
3333 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
3334 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
3335 MDIO_XS_DEVAD,
3336 MDIO_XS_PLL_SEQUENCER, &val);
3337 val &= ~(1<<13);
3338 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3339 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3340
3341 /* PLL controls */
3342 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3343 MDIO_XS_DEVAD, 0x805E, 0x1077);
3344 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3345 MDIO_XS_DEVAD, 0x805D, 0x0000);
3346 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3347 MDIO_XS_DEVAD, 0x805C, 0x030B);
3348 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3349 MDIO_XS_DEVAD, 0x805B, 0x1240);
3350 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3351 MDIO_XS_DEVAD, 0x805A, 0x2490);
3352
3353 /* Tx Controls */
3354 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3355 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
3356 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3357 MDIO_XS_DEVAD, 0x80A6, 0x9041);
3358 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3359 MDIO_XS_DEVAD, 0x80A5, 0x4640);
3360
3361 /* Rx Controls */
3362 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3363 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
3364 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3365 MDIO_XS_DEVAD, 0x80FD, 0x9249);
3366 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3367 MDIO_XS_DEVAD, 0x80FC, 0x2015);
3368
3369 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
3370 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
3371 MDIO_XS_DEVAD,
3372 MDIO_XS_PLL_SEQUENCER, &val);
3373 val |= (1<<13);
3374 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3375 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3376}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003377
3378static void bnx2x_8073_set_pause_cl37(struct link_params *params,
3379 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003380{
3381 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003382 u16 cl37_val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003383 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003384 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3385
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003386 bnx2x_cl45_read(bp, params->port,
3387 ext_phy_type,
3388 ext_phy_addr,
3389 MDIO_AN_DEVAD,
3390 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
3391
3392 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3393 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3394
3395 if ((vars->ieee_fc &
3396 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
3397 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
3398 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
3399 }
3400 if ((vars->ieee_fc &
3401 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3402 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3403 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3404 }
3405 if ((vars->ieee_fc &
3406 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3407 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3408 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3409 }
3410 DP(NETIF_MSG_LINK,
3411 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
3412
3413 bnx2x_cl45_write(bp, params->port,
3414 ext_phy_type,
3415 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003416 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003417 MDIO_AN_REG_CL37_FC_LD, cl37_val);
3418 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003419}
3420
3421static void bnx2x_ext_phy_set_pause(struct link_params *params,
3422 struct link_vars *vars)
3423{
3424 struct bnx2x *bp = params->bp;
3425 u16 val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003426 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003427 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3428
3429 /* read modify write pause advertizing */
3430 bnx2x_cl45_read(bp, params->port,
3431 ext_phy_type,
3432 ext_phy_addr,
3433 MDIO_AN_DEVAD,
3434 MDIO_AN_REG_ADV_PAUSE, &val);
3435
3436 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003437
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003438 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3439
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003440 if ((vars->ieee_fc &
3441 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003442 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3443 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3444 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003445 if ((vars->ieee_fc &
3446 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003447 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3448 val |=
3449 MDIO_AN_REG_ADV_PAUSE_PAUSE;
3450 }
3451 DP(NETIF_MSG_LINK,
3452 "Ext phy AN advertize 0x%x\n", val);
3453 bnx2x_cl45_write(bp, params->port,
3454 ext_phy_type,
3455 ext_phy_addr,
3456 MDIO_AN_DEVAD,
3457 MDIO_AN_REG_ADV_PAUSE, val);
3458}
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003459static void bnx2x_set_preemphasis(struct link_params *params)
3460{
3461 u16 bank, i = 0;
3462 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003463
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003464 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
3465 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
3466 CL45_WR_OVER_CL22(bp, params->port,
3467 params->phy_addr,
3468 bank,
3469 MDIO_RX0_RX_EQ_BOOST,
3470 params->xgxs_config_rx[i]);
3471 }
3472
3473 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
3474 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
3475 CL45_WR_OVER_CL22(bp, params->port,
3476 params->phy_addr,
3477 bank,
3478 MDIO_TX0_TX_DRIVER,
3479 params->xgxs_config_tx[i]);
3480 }
3481}
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003482
Eilon Greenstein2f904462009-08-12 08:22:16 +00003483
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003484static void bnx2x_8481_set_led(struct link_params *params,
3485 u32 ext_phy_type, u8 ext_phy_addr)
Eilon Greenstein2f904462009-08-12 08:22:16 +00003486{
3487 struct bnx2x *bp = params->bp;
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003488 u16 val;
3489 bnx2x_cl45_read(bp, params->port,
3490 ext_phy_type,
3491 ext_phy_addr,
3492 MDIO_PMA_DEVAD,
3493 MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
3494 val &= 0xFE00;
3495 val |= 0x0092;
Eilon Greenstein2f904462009-08-12 08:22:16 +00003496
Eilon Greenstein2f904462009-08-12 08:22:16 +00003497 bnx2x_cl45_write(bp, params->port,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003498 ext_phy_type,
3499 ext_phy_addr,
3500 MDIO_PMA_DEVAD,
3501 MDIO_PMA_REG_8481_LINK_SIGNAL, val);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003502
Eilon Greenstein2f904462009-08-12 08:22:16 +00003503 bnx2x_cl45_write(bp, params->port,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003504 ext_phy_type,
3505 ext_phy_addr,
3506 MDIO_PMA_DEVAD,
3507 MDIO_PMA_REG_8481_LED1_MASK,
3508 0x80);
3509
3510 bnx2x_cl45_write(bp, params->port,
3511 ext_phy_type,
3512 ext_phy_addr,
3513 MDIO_PMA_DEVAD,
3514 MDIO_PMA_REG_8481_LED2_MASK,
3515 0x18);
3516
3517 bnx2x_cl45_write(bp, params->port,
3518 ext_phy_type,
3519 ext_phy_addr,
3520 MDIO_PMA_DEVAD,
3521 MDIO_PMA_REG_8481_LED3_MASK,
3522 0x0040);
3523
Eilon Greenstein2f904462009-08-12 08:22:16 +00003524 /* 'Interrupt Mask' */
3525 bnx2x_cl45_write(bp, params->port,
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00003526 ext_phy_type,
3527 ext_phy_addr,
3528 MDIO_AN_DEVAD,
3529 0xFFFB, 0xFFFD);
Eilon Greenstein2f904462009-08-12 08:22:16 +00003530}
Eilon Greenstein2f904462009-08-12 08:22:16 +00003531
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003532static void bnx2x_init_internal_phy(struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00003533 struct link_vars *vars,
3534 u8 enable_cl73)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003535{
3536 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003537
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003538 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003539 if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
3540 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3541 (params->feature_config_flags &
3542 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
3543 bnx2x_set_preemphasis(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003544
3545 /* forced speed requested? */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003546 if (vars->line_speed != SPEED_AUTO_NEG ||
3547 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
3548 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3549 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003550 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
3551
3552 /* disable autoneg */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003553 bnx2x_set_autoneg(params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003554
3555 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003556 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003557
3558 } else { /* AN_mode */
3559 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
3560
3561 /* AN enabled */
3562 bnx2x_set_brcm_cl37_advertisment(params);
3563
3564 /* program duplex & pause advertisement (for aneg) */
3565 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003566 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003567
3568 /* enable autoneg */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003569 bnx2x_set_autoneg(params, vars, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003570
3571 /* enable and restart AN */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003572 bnx2x_restart_autoneg(params, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003573 }
3574
3575 } else { /* SGMII mode */
3576 DP(NETIF_MSG_LINK, "SGMII\n");
3577
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003578 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003579 }
3580}
3581
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003582static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
3583{
3584 struct bnx2x *bp = params->bp;
3585 u32 ext_phy_type;
3586 u8 ext_phy_addr;
3587 u16 cnt;
3588 u16 ctrl = 0;
3589 u16 val = 0;
3590 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003591
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003592 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003593 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003594
3595 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3596 /* Make sure that the soft reset is off (expect for the 8072:
3597 * due to the lock, it will be done inside the specific
3598 * handling)
3599 */
3600 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3601 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3602 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
3603 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
3604 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
3605 /* Wait for soft reset to get cleared upto 1 sec */
3606 for (cnt = 0; cnt < 1000; cnt++) {
3607 bnx2x_cl45_read(bp, params->port,
3608 ext_phy_type,
3609 ext_phy_addr,
3610 MDIO_PMA_DEVAD,
3611 MDIO_PMA_REG_CTRL, &ctrl);
3612 if (!(ctrl & (1<<15)))
3613 break;
3614 msleep(1);
3615 }
3616 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
3617 ctrl, cnt);
3618 }
3619
3620 switch (ext_phy_type) {
3621 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003622 break;
3623
3624 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3625 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3626
3627 bnx2x_cl45_write(bp, params->port,
3628 ext_phy_type,
3629 ext_phy_addr,
3630 MDIO_PMA_DEVAD,
3631 MDIO_PMA_REG_MISC_CTRL,
3632 0x8288);
3633 bnx2x_cl45_write(bp, params->port,
3634 ext_phy_type,
3635 ext_phy_addr,
3636 MDIO_PMA_DEVAD,
3637 MDIO_PMA_REG_PHY_IDENTIFIER,
3638 0x7fbf);
3639 bnx2x_cl45_write(bp, params->port,
3640 ext_phy_type,
3641 ext_phy_addr,
3642 MDIO_PMA_DEVAD,
3643 MDIO_PMA_REG_CMU_PLL_BYPASS,
3644 0x0100);
3645 bnx2x_cl45_write(bp, params->port,
3646 ext_phy_type,
3647 ext_phy_addr,
3648 MDIO_WIS_DEVAD,
3649 MDIO_WIS_REG_LASI_CNTL, 0x1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003650
Eilon Greenstein3b313b62009-03-02 08:00:10 +00003651 /* BCM8705 doesn't have microcode, hence the 0 */
3652 bnx2x_save_spirom_version(bp, params->port,
3653 params->shmem_base, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003654 break;
3655
3656 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003657 /* Wait until fw is loaded */
3658 for (cnt = 0; cnt < 100; cnt++) {
3659 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3660 ext_phy_addr, MDIO_PMA_DEVAD,
3661 MDIO_PMA_REG_ROM_VER1, &val);
3662 if (val)
3663 break;
3664 msleep(10);
3665 }
3666 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized "
3667 "after %d ms\n", cnt);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003668 if ((params->feature_config_flags &
3669 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3670 u8 i;
3671 u16 reg;
3672 for (i = 0; i < 4; i++) {
3673 reg = MDIO_XS_8706_REG_BANK_RX0 +
3674 i*(MDIO_XS_8706_REG_BANK_RX1 -
3675 MDIO_XS_8706_REG_BANK_RX0);
3676 bnx2x_cl45_read(bp, params->port,
3677 ext_phy_type,
3678 ext_phy_addr,
3679 MDIO_XS_DEVAD,
3680 reg, &val);
3681 /* Clear first 3 bits of the control */
3682 val &= ~0x7;
3683 /* Set control bits according to
3684 configuation */
3685 val |= (params->xgxs_config_rx[i] &
3686 0x7);
3687 DP(NETIF_MSG_LINK, "Setting RX"
3688 "Equalizer to BCM8706 reg 0x%x"
3689 " <-- val 0x%x\n", reg, val);
3690 bnx2x_cl45_write(bp, params->port,
3691 ext_phy_type,
3692 ext_phy_addr,
3693 MDIO_XS_DEVAD,
3694 reg, val);
3695 }
3696 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003697 /* Force speed */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003698 if (params->req_line_speed == SPEED_10000) {
3699 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
3700
3701 bnx2x_cl45_write(bp, params->port,
3702 ext_phy_type,
3703 ext_phy_addr,
3704 MDIO_PMA_DEVAD,
3705 MDIO_PMA_REG_DIGITAL_CTRL,
3706 0x400);
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02003707 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3708 ext_phy_addr, MDIO_PMA_DEVAD,
3709 MDIO_PMA_REG_LASI_CTRL, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003710 } else {
3711 /* Force 1Gbps using autoneg with 1G
3712 advertisment */
3713
3714 /* Allow CL37 through CL73 */
3715 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3716 bnx2x_cl45_write(bp, params->port,
3717 ext_phy_type,
3718 ext_phy_addr,
3719 MDIO_AN_DEVAD,
3720 MDIO_AN_REG_CL37_CL73,
3721 0x040c);
3722
3723 /* Enable Full-Duplex advertisment on CL37 */
3724 bnx2x_cl45_write(bp, params->port,
3725 ext_phy_type,
3726 ext_phy_addr,
3727 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003728 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003729 0x0020);
3730 /* Enable CL37 AN */
3731 bnx2x_cl45_write(bp, params->port,
3732 ext_phy_type,
3733 ext_phy_addr,
3734 MDIO_AN_DEVAD,
3735 MDIO_AN_REG_CL37_AN,
3736 0x1000);
3737 /* 1G support */
3738 bnx2x_cl45_write(bp, params->port,
3739 ext_phy_type,
3740 ext_phy_addr,
3741 MDIO_AN_DEVAD,
3742 MDIO_AN_REG_ADV, (1<<5));
3743
3744 /* Enable clause 73 AN */
3745 bnx2x_cl45_write(bp, params->port,
3746 ext_phy_type,
3747 ext_phy_addr,
3748 MDIO_AN_DEVAD,
3749 MDIO_AN_REG_CTRL,
3750 0x1200);
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02003751 bnx2x_cl45_write(bp, params->port,
3752 ext_phy_type,
3753 ext_phy_addr,
3754 MDIO_PMA_DEVAD,
3755 MDIO_PMA_REG_RX_ALARM_CTRL,
3756 0x0400);
3757 bnx2x_cl45_write(bp, params->port,
3758 ext_phy_type,
3759 ext_phy_addr,
3760 MDIO_PMA_DEVAD,
3761 MDIO_PMA_REG_LASI_CTRL, 0x0004);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003762
3763 }
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003764 bnx2x_save_bcm_spirom_ver(bp, params->port,
3765 ext_phy_type,
3766 ext_phy_addr,
3767 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003768 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003769 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3770 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3771 bnx2x_bcm8726_external_rom_boot(params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003772
Eilon Greenstein589abe32009-02-12 08:36:55 +00003773 /* Need to call module detected on initialization since
3774 the module detection triggered by actual module
3775 insertion might occur before driver is loaded, and when
3776 driver is loaded, it reset all registers, including the
3777 transmitter */
3778 bnx2x_sfp_module_detection(params);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003779
3780 /* Set Flow control */
3781 bnx2x_ext_phy_set_pause(params, vars);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003782 if (params->req_line_speed == SPEED_1000) {
3783 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3784 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3785 ext_phy_addr, MDIO_PMA_DEVAD,
3786 MDIO_PMA_REG_CTRL, 0x40);
3787 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3788 ext_phy_addr, MDIO_PMA_DEVAD,
3789 MDIO_PMA_REG_10G_CTRL2, 0xD);
3790 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3791 ext_phy_addr, MDIO_PMA_DEVAD,
3792 MDIO_PMA_REG_LASI_CTRL, 0x5);
3793 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3794 ext_phy_addr, MDIO_PMA_DEVAD,
3795 MDIO_PMA_REG_RX_ALARM_CTRL,
3796 0x400);
3797 } else if ((params->req_line_speed ==
3798 SPEED_AUTO_NEG) &&
3799 ((params->speed_cap_mask &
3800 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
Frans Pop2381a552010-03-24 07:57:36 +00003801 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00003802 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3803 ext_phy_addr, MDIO_AN_DEVAD,
3804 MDIO_AN_REG_ADV, 0x20);
3805 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3806 ext_phy_addr, MDIO_AN_DEVAD,
3807 MDIO_AN_REG_CL37_CL73, 0x040c);
3808 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3809 ext_phy_addr, MDIO_AN_DEVAD,
3810 MDIO_AN_REG_CL37_FC_LD, 0x0020);
3811 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3812 ext_phy_addr, MDIO_AN_DEVAD,
3813 MDIO_AN_REG_CL37_AN, 0x1000);
3814 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3815 ext_phy_addr, MDIO_AN_DEVAD,
3816 MDIO_AN_REG_CTRL, 0x1200);
3817
3818 /* Enable RX-ALARM control to receive
3819 interrupt for 1G speed change */
3820 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3821 ext_phy_addr, MDIO_PMA_DEVAD,
3822 MDIO_PMA_REG_LASI_CTRL, 0x4);
3823 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3824 ext_phy_addr, MDIO_PMA_DEVAD,
3825 MDIO_PMA_REG_RX_ALARM_CTRL,
3826 0x400);
3827
3828 } else { /* Default 10G. Set only LASI control */
3829 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3830 ext_phy_addr, MDIO_PMA_DEVAD,
3831 MDIO_PMA_REG_LASI_CTRL, 1);
3832 }
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003833
3834 /* Set TX PreEmphasis if needed */
3835 if ((params->feature_config_flags &
3836 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3837 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
3838 "TX_CTRL2 0x%x\n",
3839 params->xgxs_config_tx[0],
3840 params->xgxs_config_tx[1]);
3841 bnx2x_cl45_write(bp, params->port,
3842 ext_phy_type,
3843 ext_phy_addr,
3844 MDIO_PMA_DEVAD,
3845 MDIO_PMA_REG_8726_TX_CTRL1,
3846 params->xgxs_config_tx[0]);
3847
3848 bnx2x_cl45_write(bp, params->port,
3849 ext_phy_type,
3850 ext_phy_addr,
3851 MDIO_PMA_DEVAD,
3852 MDIO_PMA_REG_8726_TX_CTRL2,
3853 params->xgxs_config_tx[1]);
3854 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00003855 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003856 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3857 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3858 {
3859 u16 tmp1;
3860 u16 rx_alarm_ctrl_val;
3861 u16 lasi_ctrl_val;
3862 if (ext_phy_type ==
3863 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3864 rx_alarm_ctrl_val = 0x400;
3865 lasi_ctrl_val = 0x0004;
3866 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003867 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003868 lasi_ctrl_val = 0x0004;
3869 }
3870
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003871 /* enable LASI */
3872 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003873 ext_phy_type,
3874 ext_phy_addr,
3875 MDIO_PMA_DEVAD,
3876 MDIO_PMA_REG_RX_ALARM_CTRL,
3877 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003878
3879 bnx2x_cl45_write(bp, params->port,
3880 ext_phy_type,
3881 ext_phy_addr,
3882 MDIO_PMA_DEVAD,
3883 MDIO_PMA_REG_LASI_CTRL,
3884 lasi_ctrl_val);
3885
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003886 bnx2x_8073_set_pause_cl37(params, vars);
3887
3888 if (ext_phy_type ==
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003889 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003890 bnx2x_bcm8072_external_rom_boot(params);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003891 else
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003892 /* In case of 8073 with long xaui lines,
3893 don't set the 8073 xaui low power*/
3894 bnx2x_bcm8073_set_xaui_low_power_mode(params);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003895
3896 bnx2x_cl45_read(bp, params->port,
3897 ext_phy_type,
3898 ext_phy_addr,
3899 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003900 MDIO_PMA_REG_M8051_MSGOUT_REG,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003901 &tmp1);
3902
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003903 bnx2x_cl45_read(bp, params->port,
3904 ext_phy_type,
3905 ext_phy_addr,
3906 MDIO_PMA_DEVAD,
3907 MDIO_PMA_REG_RX_ALARM, &tmp1);
3908
3909 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
3910 "0x%x\n", tmp1);
3911
3912 /* If this is forced speed, set to KR or KX
3913 * (all other are not supported)
3914 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003915 if (params->loopback_mode == LOOPBACK_EXT) {
3916 bnx2x_bcm807x_force_10G(params);
3917 DP(NETIF_MSG_LINK,
3918 "Forced speed 10G on 807X\n");
3919 break;
3920 } else {
3921 bnx2x_cl45_write(bp, params->port,
3922 ext_phy_type, ext_phy_addr,
3923 MDIO_PMA_DEVAD,
3924 MDIO_PMA_REG_BCM_CTRL,
3925 0x0002);
3926 }
3927 if (params->req_line_speed != SPEED_AUTO_NEG) {
3928 if (params->req_line_speed == SPEED_10000) {
3929 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003930 } else if (params->req_line_speed ==
3931 SPEED_2500) {
3932 val = (1<<5);
3933 /* Note that 2.5G works only
3934 when used with 1G advertisment */
3935 } else
3936 val = (1<<5);
3937 } else {
3938
3939 val = 0;
3940 if (params->speed_cap_mask &
3941 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3942 val |= (1<<7);
3943
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003944 /* Note that 2.5G works only when
3945 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003946 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003947 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3948 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003949 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003950 DP(NETIF_MSG_LINK,
3951 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003952 }
3953
3954 bnx2x_cl45_write(bp, params->port,
3955 ext_phy_type,
3956 ext_phy_addr,
3957 MDIO_AN_DEVAD,
3958 MDIO_AN_REG_ADV, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003959 if (ext_phy_type ==
3960 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003961 bnx2x_cl45_read(bp, params->port,
3962 ext_phy_type,
3963 ext_phy_addr,
3964 MDIO_AN_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003965 MDIO_AN_REG_8073_2_5G, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003966
3967 if (((params->speed_cap_mask &
3968 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3969 (params->req_line_speed ==
3970 SPEED_AUTO_NEG)) ||
3971 (params->req_line_speed ==
3972 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003973 u16 phy_ver;
3974 /* Allow 2.5G for A1 and above */
3975 bnx2x_cl45_read(bp, params->port,
3976 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
3977 ext_phy_addr,
3978 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003979 MDIO_PMA_REG_8073_CHIP_REV, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003980 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003981 if (phy_ver > 0)
3982 tmp1 |= 1;
3983 else
3984 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003985 } else {
3986 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003987 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003988 }
3989
3990 bnx2x_cl45_write(bp, params->port,
3991 ext_phy_type,
3992 ext_phy_addr,
3993 MDIO_AN_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003994 MDIO_AN_REG_8073_2_5G, tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003995 }
3996
3997 /* Add support for CL37 (passive mode) II */
3998
3999 bnx2x_cl45_read(bp, params->port,
4000 ext_phy_type,
4001 ext_phy_addr,
4002 MDIO_AN_DEVAD,
4003 MDIO_AN_REG_CL37_FC_LD,
4004 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004005
4006 bnx2x_cl45_write(bp, params->port,
4007 ext_phy_type,
4008 ext_phy_addr,
4009 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004010 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
4011 ((params->req_duplex == DUPLEX_FULL) ?
4012 0x20 : 0x40)));
4013
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004014 /* Add support for CL37 (passive mode) III */
4015 bnx2x_cl45_write(bp, params->port,
4016 ext_phy_type,
4017 ext_phy_addr,
4018 MDIO_AN_DEVAD,
4019 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004020
4021 if (ext_phy_type ==
4022 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004023 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004024 BW and FEE main tap. Rest commands are executed
4025 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004026 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004027 if (bnx2x_8073_is_snr_needed(params))
4028 bnx2x_cl45_write(bp, params->port,
4029 ext_phy_type,
4030 ext_phy_addr,
4031 MDIO_PMA_DEVAD,
4032 MDIO_PMA_REG_EDC_FFE_MAIN,
4033 0xFB0C);
4034
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004035 /* Enable FEC (Forware Error Correction)
4036 Request in the AN */
4037 bnx2x_cl45_read(bp, params->port,
4038 ext_phy_type,
4039 ext_phy_addr,
4040 MDIO_AN_DEVAD,
4041 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004042
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004043 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004044
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004045 bnx2x_cl45_write(bp, params->port,
4046 ext_phy_type,
4047 ext_phy_addr,
4048 MDIO_AN_DEVAD,
4049 MDIO_AN_REG_ADV2, tmp1);
4050
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004051 }
4052
4053 bnx2x_ext_phy_set_pause(params, vars);
4054
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004055 /* Restart autoneg */
4056 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004057 bnx2x_cl45_write(bp, params->port,
4058 ext_phy_type,
4059 ext_phy_addr,
4060 MDIO_AN_DEVAD,
4061 MDIO_AN_REG_CTRL, 0x1200);
4062 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
4063 "Advertise 1G=%x, 10G=%x\n",
4064 ((val & (1<<5)) > 0),
4065 ((val & (1<<7)) > 0));
4066 break;
4067 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004068
4069 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
4070 {
4071 u16 tmp1;
4072 u16 rx_alarm_ctrl_val;
4073 u16 lasi_ctrl_val;
4074
4075 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
4076
4077 u16 mod_abs;
4078 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
4079 lasi_ctrl_val = 0x0004;
4080
4081 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
4082 /* enable LASI */
4083 bnx2x_cl45_write(bp, params->port,
4084 ext_phy_type,
4085 ext_phy_addr,
4086 MDIO_PMA_DEVAD,
4087 MDIO_PMA_REG_RX_ALARM_CTRL,
4088 rx_alarm_ctrl_val);
4089
4090 bnx2x_cl45_write(bp, params->port,
4091 ext_phy_type,
4092 ext_phy_addr,
4093 MDIO_PMA_DEVAD,
4094 MDIO_PMA_REG_LASI_CTRL,
4095 lasi_ctrl_val);
4096
4097 /* Initially configure MOD_ABS to interrupt when
4098 module is presence( bit 8) */
4099 bnx2x_cl45_read(bp, params->port,
4100 ext_phy_type,
4101 ext_phy_addr,
4102 MDIO_PMA_DEVAD,
4103 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4104 /* Set EDC off by setting OPTXLOS signal input to low
4105 (bit 9).
4106 When the EDC is off it locks onto a reference clock and
4107 avoids becoming 'lost'.*/
4108 mod_abs &= ~((1<<8) | (1<<9));
4109 bnx2x_cl45_write(bp, params->port,
4110 ext_phy_type,
4111 ext_phy_addr,
4112 MDIO_PMA_DEVAD,
4113 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4114
4115 /* Make MOD_ABS give interrupt on change */
4116 bnx2x_cl45_read(bp, params->port,
4117 ext_phy_type,
4118 ext_phy_addr,
4119 MDIO_PMA_DEVAD,
4120 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4121 &val);
4122 val |= (1<<12);
4123 bnx2x_cl45_write(bp, params->port,
4124 ext_phy_type,
4125 ext_phy_addr,
4126 MDIO_PMA_DEVAD,
4127 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4128 val);
4129
4130 /* Set 8727 GPIOs to input to allow reading from the
4131 8727 GPIO0 status which reflect SFP+ module
4132 over-current */
4133
4134 bnx2x_cl45_read(bp, params->port,
4135 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4136 ext_phy_addr,
4137 MDIO_PMA_DEVAD,
4138 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4139 &val);
4140 val &= 0xff8f; /* Reset bits 4-6 */
4141 bnx2x_cl45_write(bp, params->port,
4142 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4143 ext_phy_addr,
4144 MDIO_PMA_DEVAD,
4145 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4146 val);
4147
4148 bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004149
4150 bnx2x_cl45_read(bp, params->port,
4151 ext_phy_type,
4152 ext_phy_addr,
4153 MDIO_PMA_DEVAD,
4154 MDIO_PMA_REG_M8051_MSGOUT_REG,
4155 &tmp1);
4156
4157 bnx2x_cl45_read(bp, params->port,
4158 ext_phy_type,
4159 ext_phy_addr,
4160 MDIO_PMA_DEVAD,
4161 MDIO_PMA_REG_RX_ALARM, &tmp1);
4162
4163 /* Set option 1G speed */
4164 if (params->req_line_speed == SPEED_1000) {
4165
4166 DP(NETIF_MSG_LINK, "Setting 1G force\n");
4167 bnx2x_cl45_write(bp, params->port,
4168 ext_phy_type,
4169 ext_phy_addr,
4170 MDIO_PMA_DEVAD,
4171 MDIO_PMA_REG_CTRL, 0x40);
4172 bnx2x_cl45_write(bp, params->port,
4173 ext_phy_type,
4174 ext_phy_addr,
4175 MDIO_PMA_DEVAD,
4176 MDIO_PMA_REG_10G_CTRL2, 0xD);
4177 bnx2x_cl45_read(bp, params->port,
4178 ext_phy_type,
4179 ext_phy_addr,
4180 MDIO_PMA_DEVAD,
4181 MDIO_PMA_REG_10G_CTRL2, &tmp1);
Frans Pop2381a552010-03-24 07:57:36 +00004182 DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004183
4184 } else if ((params->req_line_speed ==
4185 SPEED_AUTO_NEG) &&
4186 ((params->speed_cap_mask &
Yaniv Rosnereb80ce72010-09-01 09:51:20 +00004187 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
4188 ((params->speed_cap_mask &
4189 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
4190 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Frans Pop2381a552010-03-24 07:57:36 +00004191 DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004192 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4193 ext_phy_addr, MDIO_AN_DEVAD,
4194 MDIO_PMA_REG_8727_MISC_CTRL, 0);
4195 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4196 ext_phy_addr, MDIO_AN_DEVAD,
4197 MDIO_AN_REG_CL37_AN, 0x1300);
4198 } else {
4199 /* Since the 8727 has only single reset pin,
4200 need to set the 10G registers although it is
4201 default */
4202 bnx2x_cl45_write(bp, params->port, ext_phy_type,
Yaniv Rosnereb80ce72010-09-01 09:51:20 +00004203 ext_phy_addr, MDIO_AN_DEVAD,
4204 MDIO_AN_REG_8727_MISC_CTRL,
4205 0x0020);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004206 bnx2x_cl45_write(bp, params->port, ext_phy_type,
Yaniv Rosnereb80ce72010-09-01 09:51:20 +00004207 ext_phy_addr, MDIO_AN_DEVAD,
4208 MDIO_AN_REG_CL37_AN, 0x0100);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004209 bnx2x_cl45_write(bp, params->port, ext_phy_type,
Yaniv Rosnereb80ce72010-09-01 09:51:20 +00004210 ext_phy_addr, MDIO_PMA_DEVAD,
4211 MDIO_PMA_REG_CTRL, 0x2040);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004212 bnx2x_cl45_write(bp, params->port, ext_phy_type,
Yaniv Rosnereb80ce72010-09-01 09:51:20 +00004213 ext_phy_addr, MDIO_PMA_DEVAD,
4214 MDIO_PMA_REG_10G_CTRL2, 0x0008);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004215 }
4216
Yaniv Rosner1ab6c162010-06-14 23:25:19 -07004217 /* Set 2-wire transfer rate of SFP+ module EEPROM
4218 * to 100Khz since some DACs(direct attached cables) do
4219 * not work at 400Khz.
4220 */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004221 bnx2x_cl45_write(bp, params->port,
4222 ext_phy_type,
4223 ext_phy_addr,
4224 MDIO_PMA_DEVAD,
4225 MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
Yaniv Rosner1ab6c162010-06-14 23:25:19 -07004226 0xa001);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004227
4228 /* Set TX PreEmphasis if needed */
4229 if ((params->feature_config_flags &
4230 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4231 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
4232 "TX_CTRL2 0x%x\n",
4233 params->xgxs_config_tx[0],
4234 params->xgxs_config_tx[1]);
4235 bnx2x_cl45_write(bp, params->port,
4236 ext_phy_type,
4237 ext_phy_addr,
4238 MDIO_PMA_DEVAD,
4239 MDIO_PMA_REG_8727_TX_CTRL1,
4240 params->xgxs_config_tx[0]);
4241
4242 bnx2x_cl45_write(bp, params->port,
4243 ext_phy_type,
4244 ext_phy_addr,
4245 MDIO_PMA_DEVAD,
4246 MDIO_PMA_REG_8727_TX_CTRL2,
4247 params->xgxs_config_tx[1]);
4248 }
4249
4250 break;
4251 }
4252
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004253 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004254 {
4255 u16 fw_ver1, fw_ver2;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004256 DP(NETIF_MSG_LINK,
4257 "Setting the SFX7101 LASI indication\n");
4258
4259 bnx2x_cl45_write(bp, params->port,
4260 ext_phy_type,
4261 ext_phy_addr,
4262 MDIO_PMA_DEVAD,
4263 MDIO_PMA_REG_LASI_CTRL, 0x1);
4264 DP(NETIF_MSG_LINK,
4265 "Setting the SFX7101 LED to blink on traffic\n");
4266 bnx2x_cl45_write(bp, params->port,
4267 ext_phy_type,
4268 ext_phy_addr,
4269 MDIO_PMA_DEVAD,
4270 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
4271
4272 bnx2x_ext_phy_set_pause(params, vars);
4273 /* Restart autoneg */
4274 bnx2x_cl45_read(bp, params->port,
4275 ext_phy_type,
4276 ext_phy_addr,
4277 MDIO_AN_DEVAD,
4278 MDIO_AN_REG_CTRL, &val);
4279 val |= 0x200;
4280 bnx2x_cl45_write(bp, params->port,
4281 ext_phy_type,
4282 ext_phy_addr,
4283 MDIO_AN_DEVAD,
4284 MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00004285
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004286 /* Save spirom version */
4287 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4288 ext_phy_addr, MDIO_PMA_DEVAD,
4289 MDIO_PMA_REG_7101_VER1, &fw_ver1);
4290
4291 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4292 ext_phy_addr, MDIO_PMA_DEVAD,
4293 MDIO_PMA_REG_7101_VER2, &fw_ver2);
4294
4295 bnx2x_save_spirom_version(params->bp, params->port,
4296 params->shmem_base,
4297 (u32)(fw_ver1<<16 | fw_ver2));
Eilon Greenstein28577182009-02-12 08:37:00 +00004298 break;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004299 }
Eilon Greenstein28577182009-02-12 08:37:00 +00004300 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004301 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004302 {
Eilon Greenstein2f904462009-08-12 08:22:16 +00004303 /* This phy uses the NIG latch mechanism since link
4304 indication arrives through its LED4 and not via
4305 its LASI signal, so we get steady signal
4306 instead of clear on read */
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00004307 u16 autoneg_val, an_1000_val, an_10_100_val, temp;
4308 temp = vars->line_speed;
4309 vars->line_speed = SPEED_10000;
4310 bnx2x_set_autoneg(params, vars, 0);
4311 bnx2x_program_serdes(params, vars);
4312 vars->line_speed = temp;
4313
Eilon Greenstein2f904462009-08-12 08:22:16 +00004314 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004315 1 << NIG_LATCH_BC_ENABLE_MI_INT);
Eilon Greenstein28577182009-02-12 08:37:00 +00004316
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004317 bnx2x_cl45_write(bp, params->port,
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004318 ext_phy_type,
4319 ext_phy_addr,
4320 MDIO_PMA_DEVAD,
4321 MDIO_PMA_REG_CTRL, 0x0000);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004322
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00004323 bnx2x_8481_set_led(params, ext_phy_type, ext_phy_addr);
Eilon Greenstein28577182009-02-12 08:37:00 +00004324
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004325 bnx2x_cl45_read(bp, params->port,
4326 ext_phy_type,
4327 ext_phy_addr,
4328 MDIO_AN_DEVAD,
4329 MDIO_AN_REG_8481_1000T_CTRL,
4330 &an_1000_val);
4331 bnx2x_ext_phy_set_pause(params, vars);
4332 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4333 ext_phy_addr, MDIO_AN_DEVAD,
4334 MDIO_AN_REG_8481_LEGACY_AN_ADV,
4335 &an_10_100_val);
4336 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4337 ext_phy_addr, MDIO_AN_DEVAD,
4338 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4339 &autoneg_val);
4340 /* Disable forced speed */
4341 autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) |
4342 (1<<13));
4343 an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
Eilon Greenstein2f904462009-08-12 08:22:16 +00004344
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004345 if (((params->req_line_speed == SPEED_AUTO_NEG) &&
4346 (params->speed_cap_mask &
4347 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
4348 (params->req_line_speed == SPEED_1000)) {
4349 an_1000_val |= (1<<8);
4350 autoneg_val |= (1<<9 | 1<<12);
Eilon Greenstein2f904462009-08-12 08:22:16 +00004351 if (params->req_duplex == DUPLEX_FULL)
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004352 an_1000_val |= (1<<9);
4353 DP(NETIF_MSG_LINK, "Advertising 1G\n");
4354 } else
4355 an_1000_val &= ~((1<<8) | (1<<9));
Yaniv Rosner46d15cc2009-11-05 19:18:30 +02004356
Eilon Greenstein28577182009-02-12 08:37:00 +00004357 bnx2x_cl45_write(bp, params->port,
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004358 ext_phy_type,
4359 ext_phy_addr,
4360 MDIO_AN_DEVAD,
4361 MDIO_AN_REG_8481_1000T_CTRL,
4362 an_1000_val);
Eilon Greenstein2f904462009-08-12 08:22:16 +00004363
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004364 /* set 10 speed advertisement */
4365 if (((params->req_line_speed == SPEED_AUTO_NEG) &&
4366 (params->speed_cap_mask &
4367 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
4368 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
4369 an_10_100_val |= (1<<7);
4370 /*
4371 * Enable autoneg and restart autoneg for
4372 * legacy speeds
4373 */
4374 autoneg_val |= (1<<9 | 1<<12);
Eilon Greenstein2f904462009-08-12 08:22:16 +00004375
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004376 if (params->req_duplex == DUPLEX_FULL)
4377 an_10_100_val |= (1<<8);
4378 DP(NETIF_MSG_LINK, "Advertising 100M\n");
Eilon Greenstein2f904462009-08-12 08:22:16 +00004379 }
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004380 /* set 10 speed advertisement */
4381 if (((params->req_line_speed == SPEED_AUTO_NEG) &&
4382 (params->speed_cap_mask &
4383 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
4384 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
4385 an_10_100_val |= (1<<5);
4386 autoneg_val |= (1<<9 | 1<<12);
4387 if (params->req_duplex == DUPLEX_FULL)
4388 an_10_100_val |= (1<<6);
4389 DP(NETIF_MSG_LINK, "Advertising 10M\n");
4390 }
4391
4392 /* Only 10/100 are allowed to work in FORCE mode */
4393 if (params->req_line_speed == SPEED_100) {
4394 autoneg_val |= (1<<13);
4395 /* Enabled AUTO-MDIX when autoneg is disabled */
4396 bnx2x_cl45_write(bp, params->port,
4397 ext_phy_type,
4398 ext_phy_addr,
4399 MDIO_AN_DEVAD,
4400 MDIO_AN_REG_8481_AUX_CTRL,
4401 (1<<15 | 1<<9 | 7<<0));
4402 DP(NETIF_MSG_LINK, "Setting 100M force\n");
4403 }
4404 if (params->req_line_speed == SPEED_10) {
4405 /* Enabled AUTO-MDIX when autoneg is disabled */
4406 bnx2x_cl45_write(bp, params->port,
4407 ext_phy_type,
4408 ext_phy_addr,
4409 MDIO_AN_DEVAD,
4410 MDIO_AN_REG_8481_AUX_CTRL,
4411 (1<<15 | 1<<9 | 7<<0));
4412 DP(NETIF_MSG_LINK, "Setting 10M force\n");
4413 }
4414
4415 bnx2x_cl45_write(bp, params->port,
4416 ext_phy_type,
4417 ext_phy_addr,
4418 MDIO_AN_DEVAD,
4419 MDIO_AN_REG_8481_LEGACY_AN_ADV,
4420 an_10_100_val);
4421
4422 if (params->req_duplex == DUPLEX_FULL)
4423 autoneg_val |= (1<<8);
4424
4425 bnx2x_cl45_write(bp, params->port,
4426 ext_phy_type,
4427 ext_phy_addr,
4428 MDIO_AN_DEVAD,
4429 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4430 autoneg_val);
4431
4432 if (((params->req_line_speed == SPEED_AUTO_NEG) &&
4433 (params->speed_cap_mask &
4434 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
4435 (params->req_line_speed == SPEED_10000)) {
4436 DP(NETIF_MSG_LINK, "Advertising 10G\n");
4437 /* Restart autoneg for 10G*/
4438
4439 bnx2x_cl45_write(bp, params->port,
4440 ext_phy_type,
4441 ext_phy_addr,
4442 MDIO_AN_DEVAD,
4443 MDIO_AN_REG_CTRL,
4444 0x3200);
4445
4446 } else if (params->req_line_speed != SPEED_10 &&
4447 params->req_line_speed != SPEED_100)
4448 bnx2x_cl45_write(bp, params->port,
4449 ext_phy_type,
4450 ext_phy_addr,
4451 MDIO_AN_DEVAD,
4452 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
4453 1);
Eilon Greenstein28577182009-02-12 08:37:00 +00004454
Eilon Greensteinb1607af2009-08-12 08:22:54 +00004455 /* Save spirom version */
4456 bnx2x_save_8481_spirom_version(bp, params->port,
4457 ext_phy_addr,
4458 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004459 break;
Yaniv Rosnerac4d9442010-09-01 09:51:25 +00004460 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004461 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4462 DP(NETIF_MSG_LINK,
4463 "XGXS PHY Failure detected 0x%x\n",
4464 params->ext_phy_config);
4465 rc = -EINVAL;
4466 break;
4467 default:
4468 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
4469 params->ext_phy_config);
4470 rc = -EINVAL;
4471 break;
4472 }
4473
4474 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004475
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004476 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4477 switch (ext_phy_type) {
4478 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
4479 DP(NETIF_MSG_LINK, "SerDes Direct\n");
4480 break;
4481
4482 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
4483 DP(NETIF_MSG_LINK, "SerDes 5482\n");
4484 break;
4485
4486 default:
4487 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
4488 params->ext_phy_config);
4489 break;
4490 }
4491 }
4492 return rc;
4493}
4494
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004495static void bnx2x_8727_handle_mod_abs(struct link_params *params)
4496{
4497 struct bnx2x *bp = params->bp;
4498 u16 mod_abs, rx_alarm_status;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00004499 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004500 u32 val = REG_RD(bp, params->shmem_base +
4501 offsetof(struct shmem_region, dev_info.
4502 port_feature_config[params->port].
4503 config));
4504 bnx2x_cl45_read(bp, params->port,
4505 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4506 ext_phy_addr,
4507 MDIO_PMA_DEVAD,
4508 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4509 if (mod_abs & (1<<8)) {
4510
4511 /* Module is absent */
4512 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4513 "show module is absent\n");
4514
4515 /* 1. Set mod_abs to detect next module
4516 presence event
4517 2. Set EDC off by setting OPTXLOS signal input to low
4518 (bit 9).
4519 When the EDC is off it locks onto a reference clock and
4520 avoids becoming 'lost'.*/
4521 mod_abs &= ~((1<<8)|(1<<9));
4522 bnx2x_cl45_write(bp, params->port,
4523 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4524 ext_phy_addr,
4525 MDIO_PMA_DEVAD,
4526 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4527
4528 /* Clear RX alarm since it stays up as long as
4529 the mod_abs wasn't changed */
4530 bnx2x_cl45_read(bp, params->port,
4531 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4532 ext_phy_addr,
4533 MDIO_PMA_DEVAD,
4534 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4535
4536 } else {
4537 /* Module is present */
4538 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4539 "show module is present\n");
4540 /* First thing, disable transmitter,
4541 and if the module is ok, the
4542 module_detection will enable it*/
4543
4544 /* 1. Set mod_abs to detect next module
4545 absent event ( bit 8)
4546 2. Restore the default polarity of the OPRXLOS signal and
4547 this signal will then correctly indicate the presence or
4548 absence of the Rx signal. (bit 9) */
4549 mod_abs |= ((1<<8)|(1<<9));
4550 bnx2x_cl45_write(bp, params->port,
4551 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4552 ext_phy_addr,
4553 MDIO_PMA_DEVAD,
4554 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4555
4556 /* Clear RX alarm since it stays up as long as
4557 the mod_abs wasn't changed. This is need to be done
4558 before calling the module detection, otherwise it will clear
4559 the link update alarm */
4560 bnx2x_cl45_read(bp, params->port,
4561 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4562 ext_phy_addr,
4563 MDIO_PMA_DEVAD,
4564 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4565
4566
4567 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4568 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4569 bnx2x_sfp_set_transmitter(bp, params->port,
4570 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4571 ext_phy_addr, 0);
4572
4573 if (bnx2x_wait_for_sfp_module_initialized(params)
4574 == 0)
4575 bnx2x_sfp_module_detection(params);
4576 else
4577 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
4578 }
4579
4580 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
4581 rx_alarm_status);
4582 /* No need to check link status in case of
4583 module plugged in/out */
4584}
4585
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004586
4587static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00004588 struct link_vars *vars,
4589 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004590{
4591 struct bnx2x *bp = params->bp;
4592 u32 ext_phy_type;
4593 u8 ext_phy_addr;
4594 u16 val1 = 0, val2;
4595 u16 rx_sd, pcs_status;
4596 u8 ext_phy_link_up = 0;
4597 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004598
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004599 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00004600 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004601 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4602 switch (ext_phy_type) {
4603 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4604 DP(NETIF_MSG_LINK, "XGXS Direct\n");
4605 ext_phy_link_up = 1;
4606 break;
4607
4608 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4609 DP(NETIF_MSG_LINK, "XGXS 8705\n");
4610 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4611 ext_phy_addr,
4612 MDIO_WIS_DEVAD,
4613 MDIO_WIS_REG_LASI_STATUS, &val1);
4614 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4615
4616 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4617 ext_phy_addr,
4618 MDIO_WIS_DEVAD,
4619 MDIO_WIS_REG_LASI_STATUS, &val1);
4620 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4621
4622 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4623 ext_phy_addr,
4624 MDIO_PMA_DEVAD,
4625 MDIO_PMA_REG_RX_SD, &rx_sd);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004626
4627 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4628 ext_phy_addr,
4629 1,
4630 0xc809, &val1);
4631 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4632 ext_phy_addr,
4633 1,
4634 0xc809, &val1);
4635
4636 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
Joe Perches8e95a202009-12-03 07:58:21 +00004637 ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) &&
4638 ((val1 & (1<<8)) == 0));
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004639 if (ext_phy_link_up)
4640 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004641 break;
4642
4643 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00004644 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4645 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
4646 /* Clear RX Alarm*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004647 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4648 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00004649 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
4650 &val2);
4651 /* clear LASI indication*/
4652 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4653 ext_phy_addr,
4654 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
4655 &val1);
4656 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4657 ext_phy_addr,
4658 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
4659 &val2);
4660 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
4661 "0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004662
4663 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4664 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00004665 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
4666 &rx_sd);
4667 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4668 ext_phy_addr,
4669 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
4670 &pcs_status);
4671 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4672 ext_phy_addr,
4673 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
4674 &val2);
4675 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4676 ext_phy_addr,
4677 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
4678 &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004679
Eilon Greenstein589abe32009-02-12 08:36:55 +00004680 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004681 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
4682 rx_sd, pcs_status, val2);
4683 /* link is up if both bit 0 of pmd_rx_sd and
4684 * bit 0 of pcs_status are set, or if the autoneg bit
4685 1 is set
4686 */
4687 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
4688 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004689 if (ext_phy_link_up) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00004690 if (ext_phy_type ==
4691 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
4692 /* If transmitter is disabled,
4693 ignore false link up indication */
4694 bnx2x_cl45_read(bp, params->port,
4695 ext_phy_type,
4696 ext_phy_addr,
4697 MDIO_PMA_DEVAD,
4698 MDIO_PMA_REG_PHY_IDENTIFIER,
4699 &val1);
4700 if (val1 & (1<<15)) {
4701 DP(NETIF_MSG_LINK, "Tx is "
4702 "disabled\n");
4703 ext_phy_link_up = 0;
4704 break;
4705 }
4706 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004707 if (val2 & (1<<1))
4708 vars->line_speed = SPEED_1000;
4709 else
4710 vars->line_speed = SPEED_10000;
4711 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004712 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004713
4714 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
4715 {
4716 u16 link_status = 0;
4717 u16 rx_alarm_status;
4718 /* Check the LASI */
4719 bnx2x_cl45_read(bp, params->port,
4720 ext_phy_type,
4721 ext_phy_addr,
4722 MDIO_PMA_DEVAD,
4723 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4724
4725 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
4726 rx_alarm_status);
4727
4728 bnx2x_cl45_read(bp, params->port,
4729 ext_phy_type,
4730 ext_phy_addr,
4731 MDIO_PMA_DEVAD,
4732 MDIO_PMA_REG_LASI_STATUS, &val1);
4733
4734 DP(NETIF_MSG_LINK,
4735 "8727 LASI status 0x%x\n",
4736 val1);
4737
4738 /* Clear MSG-OUT */
4739 bnx2x_cl45_read(bp, params->port,
4740 ext_phy_type,
4741 ext_phy_addr,
4742 MDIO_PMA_DEVAD,
4743 MDIO_PMA_REG_M8051_MSGOUT_REG,
4744 &val1);
4745
4746 /*
4747 * If a module is present and there is need to check
4748 * for over current
4749 */
4750 if (!(params->feature_config_flags &
4751 FEATURE_CONFIG_BCM8727_NOC) &&
4752 !(rx_alarm_status & (1<<5))) {
4753 /* Check over-current using 8727 GPIO0 input*/
4754 bnx2x_cl45_read(bp, params->port,
4755 ext_phy_type,
4756 ext_phy_addr,
4757 MDIO_PMA_DEVAD,
4758 MDIO_PMA_REG_8727_GPIO_CTRL,
4759 &val1);
4760
4761 if ((val1 & (1<<8)) == 0) {
4762 DP(NETIF_MSG_LINK, "8727 Power fault"
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004763 " has been detected on "
4764 "port %d\n",
4765 params->port);
Joe Perches7995c642010-02-17 15:01:52 +00004766 netdev_err(bp->dev, "Error: Power fault on Port %d has been detected and the power to that SFP+ module has been removed to prevent failure of the card. Please remove the SFP+ module and restart the system to clear this error.\n",
4767 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004768 /*
4769 * Disable all RX_ALARMs except for
4770 * mod_abs
4771 */
4772 bnx2x_cl45_write(bp, params->port,
4773 ext_phy_type,
4774 ext_phy_addr,
4775 MDIO_PMA_DEVAD,
4776 MDIO_PMA_REG_RX_ALARM_CTRL,
4777 (1<<5));
4778
4779 bnx2x_cl45_read(bp, params->port,
4780 ext_phy_type,
4781 ext_phy_addr,
4782 MDIO_PMA_DEVAD,
4783 MDIO_PMA_REG_PHY_IDENTIFIER,
4784 &val1);
4785 /* Wait for module_absent_event */
4786 val1 |= (1<<8);
4787 bnx2x_cl45_write(bp, params->port,
4788 ext_phy_type,
4789 ext_phy_addr,
4790 MDIO_PMA_DEVAD,
4791 MDIO_PMA_REG_PHY_IDENTIFIER,
4792 val1);
4793 /* Clear RX alarm */
4794 bnx2x_cl45_read(bp, params->port,
4795 ext_phy_type,
4796 ext_phy_addr,
4797 MDIO_PMA_DEVAD,
4798 MDIO_PMA_REG_RX_ALARM,
4799 &rx_alarm_status);
4800 break;
4801 }
4802 } /* Over current check */
4803
4804 /* When module absent bit is set, check module */
4805 if (rx_alarm_status & (1<<5)) {
4806 bnx2x_8727_handle_mod_abs(params);
4807 /* Enable all mod_abs and link detection bits */
4808 bnx2x_cl45_write(bp, params->port,
4809 ext_phy_type,
4810 ext_phy_addr,
4811 MDIO_PMA_DEVAD,
4812 MDIO_PMA_REG_RX_ALARM_CTRL,
4813 ((1<<5) | (1<<2)));
4814 }
4815
4816 /* If transmitter is disabled,
4817 ignore false link up indication */
4818 bnx2x_cl45_read(bp, params->port,
4819 ext_phy_type,
4820 ext_phy_addr,
4821 MDIO_PMA_DEVAD,
4822 MDIO_PMA_REG_PHY_IDENTIFIER,
4823 &val1);
4824 if (val1 & (1<<15)) {
4825 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4826 ext_phy_link_up = 0;
4827 break;
4828 }
4829
4830 bnx2x_cl45_read(bp, params->port,
4831 ext_phy_type,
4832 ext_phy_addr,
4833 MDIO_PMA_DEVAD,
4834 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4835 &link_status);
4836
4837 /* Bits 0..2 --> speed detected,
4838 bits 13..15--> link is down */
4839 if ((link_status & (1<<2)) &&
4840 (!(link_status & (1<<15)))) {
4841 ext_phy_link_up = 1;
4842 vars->line_speed = SPEED_10000;
4843 } else if ((link_status & (1<<0)) &&
4844 (!(link_status & (1<<13)))) {
4845 ext_phy_link_up = 1;
4846 vars->line_speed = SPEED_1000;
4847 DP(NETIF_MSG_LINK,
4848 "port %x: External link"
4849 " up in 1G\n", params->port);
4850 } else {
4851 ext_phy_link_up = 0;
4852 DP(NETIF_MSG_LINK,
4853 "port %x: External link"
4854 " is down\n", params->port);
4855 }
4856 break;
4857 }
4858
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004859 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4860 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4861 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004862 u16 link_status = 0;
4863 u16 an1000_status = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004864
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004865 if (ext_phy_type ==
4866 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
4867 bnx2x_cl45_read(bp, params->port,
4868 ext_phy_type,
4869 ext_phy_addr,
4870 MDIO_PCS_DEVAD,
4871 MDIO_PCS_REG_LASI_STATUS, &val1);
4872 bnx2x_cl45_read(bp, params->port,
4873 ext_phy_type,
4874 ext_phy_addr,
4875 MDIO_PCS_DEVAD,
4876 MDIO_PCS_REG_LASI_STATUS, &val2);
4877 DP(NETIF_MSG_LINK,
4878 "870x LASI status 0x%x->0x%x\n",
4879 val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004880 } else {
4881 /* In 8073, port1 is directed through emac0 and
4882 * port0 is directed through emac1
4883 */
4884 bnx2x_cl45_read(bp, params->port,
4885 ext_phy_type,
4886 ext_phy_addr,
4887 MDIO_PMA_DEVAD,
4888 MDIO_PMA_REG_LASI_STATUS, &val1);
4889
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004890 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004891 "8703 LASI status 0x%x\n",
4892 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004893 }
4894
4895 /* clear the interrupt LASI status register */
4896 bnx2x_cl45_read(bp, params->port,
4897 ext_phy_type,
4898 ext_phy_addr,
4899 MDIO_PCS_DEVAD,
4900 MDIO_PCS_REG_STATUS, &val2);
4901 bnx2x_cl45_read(bp, params->port,
4902 ext_phy_type,
4903 ext_phy_addr,
4904 MDIO_PCS_DEVAD,
4905 MDIO_PCS_REG_STATUS, &val1);
4906 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
4907 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004908 /* Clear MSG-OUT */
4909 bnx2x_cl45_read(bp, params->port,
4910 ext_phy_type,
4911 ext_phy_addr,
4912 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004913 MDIO_PMA_REG_M8051_MSGOUT_REG,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004914 &val1);
4915
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004916 /* Check the LASI */
4917 bnx2x_cl45_read(bp, params->port,
4918 ext_phy_type,
4919 ext_phy_addr,
4920 MDIO_PMA_DEVAD,
4921 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004922
4923 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
4924
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004925 /* Check the link status */
4926 bnx2x_cl45_read(bp, params->port,
4927 ext_phy_type,
4928 ext_phy_addr,
4929 MDIO_PCS_DEVAD,
4930 MDIO_PCS_REG_STATUS, &val2);
4931 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
4932
4933 bnx2x_cl45_read(bp, params->port,
4934 ext_phy_type,
4935 ext_phy_addr,
4936 MDIO_PMA_DEVAD,
4937 MDIO_PMA_REG_STATUS, &val2);
4938 bnx2x_cl45_read(bp, params->port,
4939 ext_phy_type,
4940 ext_phy_addr,
4941 MDIO_PMA_DEVAD,
4942 MDIO_PMA_REG_STATUS, &val1);
4943 ext_phy_link_up = ((val1 & 4) == 4);
4944 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
4945 if (ext_phy_type ==
4946 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004947
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004948 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004949 ((params->req_line_speed !=
4950 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004951 if (bnx2x_bcm8073_xaui_wa(params)
4952 != 0) {
4953 ext_phy_link_up = 0;
4954 break;
4955 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004956 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004957 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004958 ext_phy_type,
4959 ext_phy_addr,
4960 MDIO_AN_DEVAD,
4961 MDIO_AN_REG_LINK_STATUS,
4962 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004963 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004964 ext_phy_type,
4965 ext_phy_addr,
4966 MDIO_AN_DEVAD,
4967 MDIO_AN_REG_LINK_STATUS,
4968 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004969
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004970 /* Check the link status on 1.1.2 */
4971 bnx2x_cl45_read(bp, params->port,
4972 ext_phy_type,
4973 ext_phy_addr,
4974 MDIO_PMA_DEVAD,
4975 MDIO_PMA_REG_STATUS, &val2);
4976 bnx2x_cl45_read(bp, params->port,
4977 ext_phy_type,
4978 ext_phy_addr,
4979 MDIO_PMA_DEVAD,
4980 MDIO_PMA_REG_STATUS, &val1);
4981 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
4982 "an_link_status=0x%x\n",
4983 val2, val1, an1000_status);
4984
Eilon Greenstein356e2382009-02-12 08:38:32 +00004985 ext_phy_link_up = (((val1 & 4) == 4) ||
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004986 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004987 if (ext_phy_link_up &&
4988 bnx2x_8073_is_snr_needed(params)) {
4989 /* The SNR will improve about 2dbby
4990 changing the BW and FEE main tap.*/
4991
4992 /* The 1st write to change FFE main
4993 tap is set before restart AN */
4994 /* Change PLL Bandwidth in EDC
4995 register */
4996 bnx2x_cl45_write(bp, port, ext_phy_type,
4997 ext_phy_addr,
4998 MDIO_PMA_DEVAD,
4999 MDIO_PMA_REG_PLL_BANDWIDTH,
5000 0x26BC);
5001
5002 /* Change CDR Bandwidth in EDC
5003 register */
5004 bnx2x_cl45_write(bp, port, ext_phy_type,
5005 ext_phy_addr,
5006 MDIO_PMA_DEVAD,
5007 MDIO_PMA_REG_CDR_BANDWIDTH,
5008 0x0333);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005009 }
5010 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005011 ext_phy_type,
5012 ext_phy_addr,
5013 MDIO_PMA_DEVAD,
5014 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
5015 &link_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005016
5017 /* Bits 0..2 --> speed detected,
5018 bits 13..15--> link is down */
5019 if ((link_status & (1<<2)) &&
5020 (!(link_status & (1<<15)))) {
5021 ext_phy_link_up = 1;
5022 vars->line_speed = SPEED_10000;
5023 DP(NETIF_MSG_LINK,
5024 "port %x: External link"
5025 " up in 10G\n", params->port);
5026 } else if ((link_status & (1<<1)) &&
5027 (!(link_status & (1<<14)))) {
5028 ext_phy_link_up = 1;
5029 vars->line_speed = SPEED_2500;
5030 DP(NETIF_MSG_LINK,
5031 "port %x: External link"
5032 " up in 2.5G\n", params->port);
5033 } else if ((link_status & (1<<0)) &&
5034 (!(link_status & (1<<13)))) {
5035 ext_phy_link_up = 1;
5036 vars->line_speed = SPEED_1000;
5037 DP(NETIF_MSG_LINK,
5038 "port %x: External link"
5039 " up in 1G\n", params->port);
5040 } else {
5041 ext_phy_link_up = 0;
5042 DP(NETIF_MSG_LINK,
5043 "port %x: External link"
5044 " is down\n", params->port);
5045 }
5046 } else {
5047 /* See if 1G link is up for the 8072 */
5048 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005049 ext_phy_type,
5050 ext_phy_addr,
5051 MDIO_AN_DEVAD,
5052 MDIO_AN_REG_LINK_STATUS,
5053 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005054 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005055 ext_phy_type,
5056 ext_phy_addr,
5057 MDIO_AN_DEVAD,
5058 MDIO_AN_REG_LINK_STATUS,
5059 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005060 if (an1000_status & (1<<1)) {
5061 ext_phy_link_up = 1;
5062 vars->line_speed = SPEED_1000;
5063 DP(NETIF_MSG_LINK,
5064 "port %x: External link"
5065 " up in 1G\n", params->port);
5066 } else if (ext_phy_link_up) {
5067 ext_phy_link_up = 1;
5068 vars->line_speed = SPEED_10000;
5069 DP(NETIF_MSG_LINK,
5070 "port %x: External link"
5071 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005072 }
5073 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005074
5075
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005076 break;
5077 }
5078 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5079 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5080 ext_phy_addr,
5081 MDIO_PMA_DEVAD,
5082 MDIO_PMA_REG_LASI_STATUS, &val2);
5083 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5084 ext_phy_addr,
5085 MDIO_PMA_DEVAD,
5086 MDIO_PMA_REG_LASI_STATUS, &val1);
5087 DP(NETIF_MSG_LINK,
5088 "10G-base-T LASI status 0x%x->0x%x\n",
5089 val2, val1);
5090 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5091 ext_phy_addr,
5092 MDIO_PMA_DEVAD,
5093 MDIO_PMA_REG_STATUS, &val2);
5094 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5095 ext_phy_addr,
5096 MDIO_PMA_DEVAD,
5097 MDIO_PMA_REG_STATUS, &val1);
5098 DP(NETIF_MSG_LINK,
5099 "10G-base-T PMA status 0x%x->0x%x\n",
5100 val2, val1);
5101 ext_phy_link_up = ((val1 & 4) == 4);
5102 /* if link is up
5103 * print the AN outcome of the SFX7101 PHY
5104 */
5105 if (ext_phy_link_up) {
5106 bnx2x_cl45_read(bp, params->port,
5107 ext_phy_type,
5108 ext_phy_addr,
5109 MDIO_AN_DEVAD,
5110 MDIO_AN_REG_MASTER_STATUS,
5111 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005112 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005113 DP(NETIF_MSG_LINK,
5114 "SFX7101 AN status 0x%x->Master=%x\n",
5115 val2,
5116 (val2 & (1<<14)));
5117 }
5118 break;
Eilon Greenstein28577182009-02-12 08:37:00 +00005119 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02005120 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
Eilon Greenstein2f904462009-08-12 08:22:16 +00005121 /* Check 10G-BaseT link status */
5122 /* Check PMD signal ok */
5123 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5124 ext_phy_addr,
5125 MDIO_AN_DEVAD,
5126 0xFFFA,
5127 &val1);
5128 bnx2x_cl45_read(bp, params->port, ext_phy_type,
Eilon Greenstein28577182009-02-12 08:37:00 +00005129 ext_phy_addr,
5130 MDIO_PMA_DEVAD,
Eilon Greenstein2f904462009-08-12 08:22:16 +00005131 MDIO_PMA_REG_8481_PMD_SIGNAL,
5132 &val2);
5133 DP(NETIF_MSG_LINK, "PMD_SIGNAL 1.a811 = 0x%x\n", val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005134
Eilon Greenstein2f904462009-08-12 08:22:16 +00005135 /* Check link 10G */
5136 if (val2 & (1<<11)) {
Eilon Greenstein28577182009-02-12 08:37:00 +00005137 vars->line_speed = SPEED_10000;
5138 ext_phy_link_up = 1;
Eilon Greenstein2f904462009-08-12 08:22:16 +00005139 } else { /* Check Legacy speed link */
5140 u16 legacy_status, legacy_speed;
Eilon Greenstein28577182009-02-12 08:37:00 +00005141
Eilon Greenstein2f904462009-08-12 08:22:16 +00005142 /* Enable expansion register 0x42
5143 (Operation mode status) */
5144 bnx2x_cl45_write(bp, params->port,
5145 ext_phy_type,
5146 ext_phy_addr,
5147 MDIO_AN_DEVAD,
5148 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS,
5149 0xf42);
Eilon Greenstein28577182009-02-12 08:37:00 +00005150
Eilon Greenstein2f904462009-08-12 08:22:16 +00005151 /* Get legacy speed operation status */
5152 bnx2x_cl45_read(bp, params->port,
5153 ext_phy_type,
5154 ext_phy_addr,
5155 MDIO_AN_DEVAD,
5156 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
5157 &legacy_status);
5158
5159 DP(NETIF_MSG_LINK, "Legacy speed status"
5160 " = 0x%x\n", legacy_status);
5161 ext_phy_link_up = ((legacy_status & (1<<11))
5162 == (1<<11));
5163 if (ext_phy_link_up) {
5164 legacy_speed = (legacy_status & (3<<9));
5165 if (legacy_speed == (0<<9))
5166 vars->line_speed = SPEED_10;
5167 else if (legacy_speed == (1<<9))
5168 vars->line_speed =
5169 SPEED_100;
5170 else if (legacy_speed == (2<<9))
5171 vars->line_speed =
5172 SPEED_1000;
5173 else /* Should not happen */
5174 vars->line_speed = 0;
5175
5176 if (legacy_status & (1<<8))
5177 vars->duplex = DUPLEX_FULL;
5178 else
5179 vars->duplex = DUPLEX_HALF;
5180
5181 DP(NETIF_MSG_LINK, "Link is up "
5182 "in %dMbps, is_duplex_full"
5183 "= %d\n",
5184 vars->line_speed,
5185 (vars->duplex == DUPLEX_FULL));
Eilon Greenstein28577182009-02-12 08:37:00 +00005186 }
5187 }
Eilon Greenstein28577182009-02-12 08:37:00 +00005188 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005189 default:
5190 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
5191 params->ext_phy_config);
5192 ext_phy_link_up = 0;
5193 break;
5194 }
Eilon Greenstein57937202009-08-12 08:23:53 +00005195 /* Set SGMII mode for external phy */
5196 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
5197 if (vars->line_speed < SPEED_1000)
5198 vars->phy_flags |= PHY_SGMII_FLAG;
5199 else
5200 vars->phy_flags &= ~PHY_SGMII_FLAG;
5201 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005202
5203 } else { /* SerDes */
5204 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5205 switch (ext_phy_type) {
5206 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
5207 DP(NETIF_MSG_LINK, "SerDes Direct\n");
5208 ext_phy_link_up = 1;
5209 break;
5210
5211 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
5212 DP(NETIF_MSG_LINK, "SerDes 5482\n");
5213 ext_phy_link_up = 1;
5214 break;
5215
5216 default:
5217 DP(NETIF_MSG_LINK,
5218 "BAD SerDes ext_phy_config 0x%x\n",
5219 params->ext_phy_config);
5220 ext_phy_link_up = 0;
5221 break;
5222 }
5223 }
5224
5225 return ext_phy_link_up;
5226}
5227
5228static void bnx2x_link_int_enable(struct link_params *params)
5229{
5230 u8 port = params->port;
5231 u32 ext_phy_type;
5232 u32 mask;
5233 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005234
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005235 /* setting the status to report on link up
5236 for either XGXS or SerDes */
5237
5238 if (params->switch_cfg == SWITCH_CFG_10G) {
5239 mask = (NIG_MASK_XGXS0_LINK10G |
5240 NIG_MASK_XGXS0_LINK_STATUS);
5241 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
5242 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
5243 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
5244 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
5245 (ext_phy_type !=
5246 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
5247 mask |= NIG_MASK_MI_INT;
5248 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5249 }
5250
5251 } else { /* SerDes */
5252 mask = NIG_MASK_SERDES0_LINK_STATUS;
5253 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
5254 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5255 if ((ext_phy_type !=
5256 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
5257 (ext_phy_type !=
5258 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
5259 mask |= NIG_MASK_MI_INT;
5260 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5261 }
5262 }
5263 bnx2x_bits_en(bp,
5264 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5265 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005266
5267 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005268 (params->switch_cfg == SWITCH_CFG_10G),
5269 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005270 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
5271 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5272 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
5273 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
5274 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5275 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5276 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5277}
5278
Eilon Greenstein2f904462009-08-12 08:22:16 +00005279static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port,
5280 u8 is_mi_int)
5281{
5282 u32 latch_status = 0, is_mi_int_status;
5283 /* Disable the MI INT ( external phy int )
5284 * by writing 1 to the status register. Link down indication
5285 * is high-active-signal, so in this case we need to write the
5286 * status to clear the XOR
5287 */
5288 /* Read Latched signals */
5289 latch_status = REG_RD(bp,
5290 NIG_REG_LATCH_STATUS_0 + port*8);
5291 is_mi_int_status = REG_RD(bp,
5292 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4);
5293 DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x,"
5294 "latch_status = 0x%x\n",
5295 is_mi_int, is_mi_int_status, latch_status);
5296 /* Handle only those with latched-signal=up.*/
5297 if (latch_status & 1) {
5298 /* For all latched-signal=up,Write original_signal to status */
5299 if (is_mi_int)
5300 bnx2x_bits_en(bp,
5301 NIG_REG_STATUS_INTERRUPT_PORT0
5302 + port*4,
5303 NIG_STATUS_EMAC0_MI_INT);
5304 else
5305 bnx2x_bits_dis(bp,
5306 NIG_REG_STATUS_INTERRUPT_PORT0
5307 + port*4,
5308 NIG_STATUS_EMAC0_MI_INT);
5309 /* For all latched-signal=up : Re-Arm Latch signals */
5310 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
5311 (latch_status & 0xfffe) | (latch_status & 1));
5312 }
5313}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005314/*
5315 * link management
5316 */
5317static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00005318 struct link_vars *vars, u8 is_10g,
5319 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005320{
5321 struct bnx2x *bp = params->bp;
5322 u8 port = params->port;
5323
5324 /* first reset all status
5325 * we assume only one line will be change at a time */
5326 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5327 (NIG_STATUS_XGXS0_LINK10G |
5328 NIG_STATUS_XGXS0_LINK_STATUS |
5329 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02005330 if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config)
5331 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) ||
5332 (XGXS_EXT_PHY_TYPE(params->ext_phy_config)
5333 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00005334 bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int);
5335 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005336 if (vars->phy_link_up) {
5337 if (is_10g) {
5338 /* Disable the 10G link interrupt
5339 * by writing 1 to the status register
5340 */
5341 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
5342 bnx2x_bits_en(bp,
5343 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5344 NIG_STATUS_XGXS0_LINK10G);
5345
5346 } else if (params->switch_cfg == SWITCH_CFG_10G) {
5347 /* Disable the link interrupt
5348 * by writing 1 to the relevant lane
5349 * in the status register
5350 */
5351 u32 ser_lane = ((params->lane_config &
5352 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
5353 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
5354
Eilon Greenstein2f904462009-08-12 08:22:16 +00005355 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
5356 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005357 bnx2x_bits_en(bp,
5358 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5359 ((1 << ser_lane) <<
5360 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
5361
5362 } else { /* SerDes */
5363 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
5364 /* Disable the link interrupt
5365 * by writing 1 to the status register
5366 */
5367 bnx2x_bits_en(bp,
5368 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5369 NIG_STATUS_SERDES0_LINK_STATUS);
5370 }
5371
5372 } else { /* link_down */
5373 }
5374}
5375
5376static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
5377{
5378 u8 *str_ptr = str;
5379 u32 mask = 0xf0000000;
5380 u8 shift = 8*4;
5381 u8 digit;
5382 if (len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02005383 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005384 *str_ptr = '\0';
5385 return -EINVAL;
5386 }
5387 while (shift > 0) {
5388
5389 shift -= 4;
5390 digit = ((num & mask) >> shift);
5391 if (digit < 0xa)
5392 *str_ptr = digit + '0';
5393 else
5394 *str_ptr = digit - 0xa + 'a';
5395 str_ptr++;
5396 mask = mask >> 4;
5397 if (shift == 4*4) {
5398 *str_ptr = ':';
5399 str_ptr++;
5400 }
5401 }
5402 *str_ptr = '\0';
5403 return 0;
5404}
5405
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005406u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
5407 u8 *version, u16 len)
5408{
Julia Lawall0376d5b2009-07-19 05:26:35 +00005409 struct bnx2x *bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005410 u32 ext_phy_type = 0;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005411 u32 spirom_ver = 0;
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005412 u8 status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005413
5414 if (version == NULL || params == NULL)
5415 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00005416 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005417
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005418 spirom_ver = REG_RD(bp, params->shmem_base +
5419 offsetof(struct shmem_region,
5420 port_mb[params->port].ext_phy_fw_version));
5421
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005422 status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005423 /* reset the returned value to zero */
5424 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005425 switch (ext_phy_type) {
5426 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5427
5428 if (len < 5)
5429 return -EINVAL;
5430
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005431 version[0] = (spirom_ver & 0xFF);
5432 version[1] = (spirom_ver & 0xFF00) >> 8;
5433 version[2] = (spirom_ver & 0xFF0000) >> 16;
5434 version[3] = (spirom_ver & 0xFF000000) >> 24;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005435 version[4] = '\0';
5436
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005437 break;
5438 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5439 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein4d295db2009-07-21 05:47:47 +00005440 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005441 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00005442 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greensteinb1607af2009-08-12 08:22:54 +00005443 status = bnx2x_format_ver(spirom_ver, version, len);
5444 break;
Eilon Greenstein9223dea2009-03-02 08:00:15 +00005445 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02005446 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
Eilon Greensteinb1607af2009-08-12 08:22:54 +00005447 spirom_ver = ((spirom_ver & 0xF80) >> 7) << 16 |
5448 (spirom_ver & 0x7F);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005449 status = bnx2x_format_ver(spirom_ver, version, len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005450 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005451 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005452 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5453 version[0] = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005454 break;
5455
5456 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
5457 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
5458 " type is FAILURE!\n");
5459 status = -EINVAL;
5460 break;
5461
5462 default:
5463 break;
5464 }
5465 return status;
5466}
5467
5468static void bnx2x_set_xgxs_loopback(struct link_params *params,
5469 struct link_vars *vars,
5470 u8 is_10g)
5471{
5472 u8 port = params->port;
5473 struct bnx2x *bp = params->bp;
5474
5475 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07005476 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005477
5478 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
5479
5480 /* change the uni_phy_addr in the nig */
5481 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
5482 port*0x18));
5483
5484 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
5485
5486 bnx2x_cl45_write(bp, port, 0,
5487 params->phy_addr,
5488 5,
5489 (MDIO_REG_BANK_AER_BLOCK +
5490 (MDIO_AER_BLOCK_AER_REG & 0xf)),
5491 0x2800);
5492
5493 bnx2x_cl45_write(bp, port, 0,
5494 params->phy_addr,
5495 5,
5496 (MDIO_REG_BANK_CL73_IEEEB0 +
5497 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
5498 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00005499 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005500 /* set aer mmd back */
5501 bnx2x_set_aer_mmd(params, vars);
5502
5503 /* and md_devad */
5504 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
5505 md_devad);
5506
5507 } else {
5508 u16 mii_control;
5509
5510 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
5511
5512 CL45_RD_OVER_CL22(bp, port,
5513 params->phy_addr,
5514 MDIO_REG_BANK_COMBO_IEEE0,
5515 MDIO_COMBO_IEEE0_MII_CONTROL,
5516 &mii_control);
5517
5518 CL45_WR_OVER_CL22(bp, port,
5519 params->phy_addr,
5520 MDIO_REG_BANK_COMBO_IEEE0,
5521 MDIO_COMBO_IEEE0_MII_CONTROL,
5522 (mii_control |
5523 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
5524 }
5525}
5526
5527
5528static void bnx2x_ext_phy_loopback(struct link_params *params)
5529{
5530 struct bnx2x *bp = params->bp;
5531 u8 ext_phy_addr;
5532 u32 ext_phy_type;
5533
5534 if (params->switch_cfg == SWITCH_CFG_10G) {
5535 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00005536 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005537 /* CL37 Autoneg Enabled */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005538 switch (ext_phy_type) {
5539 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
5540 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
5541 DP(NETIF_MSG_LINK,
5542 "ext_phy_loopback: We should not get here\n");
5543 break;
5544 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5545 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
5546 break;
5547 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
5548 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
5549 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00005550 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5551 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
5552 bnx2x_cl45_write(bp, params->port, ext_phy_type,
5553 ext_phy_addr,
5554 MDIO_PMA_DEVAD,
5555 MDIO_PMA_REG_CTRL,
5556 0x0001);
5557 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005558 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5559 /* SFX7101_XGXS_TEST1 */
5560 bnx2x_cl45_write(bp, params->port, ext_phy_type,
5561 ext_phy_addr,
5562 MDIO_XS_DEVAD,
5563 MDIO_XS_SFX7101_XGXS_TEST1,
5564 0x100);
5565 DP(NETIF_MSG_LINK,
5566 "ext_phy_loopback: set ext phy loopback\n");
5567 break;
5568 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5569
5570 break;
5571 } /* switch external PHY type */
5572 } else {
5573 /* serdes */
5574 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5575 ext_phy_addr = (params->ext_phy_config &
5576 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
5577 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
5578 }
5579}
5580
5581
5582/*
5583 *------------------------------------------------------------------------
5584 * bnx2x_override_led_value -
5585 *
5586 * Override the led value of the requsted led
5587 *
5588 *------------------------------------------------------------------------
5589 */
5590u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
5591 u32 led_idx, u32 value)
5592{
5593 u32 reg_val;
5594
5595 /* If port 0 then use EMAC0, else use EMAC1*/
5596 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
5597
5598 DP(NETIF_MSG_LINK,
5599 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
5600 port, led_idx, value);
5601
5602 switch (led_idx) {
5603 case 0: /* 10MB led */
5604 /* Read the current value of the LED register in
5605 the EMAC block */
5606 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5607 /* Set the OVERRIDE bit to 1 */
5608 reg_val |= EMAC_LED_OVERRIDE;
5609 /* If value is 1, set the 10M_OVERRIDE bit,
5610 otherwise reset it.*/
5611 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
5612 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
5613 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5614 break;
5615 case 1: /*100MB led */
5616 /*Read the current value of the LED register in
5617 the EMAC block */
5618 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5619 /* Set the OVERRIDE bit to 1 */
5620 reg_val |= EMAC_LED_OVERRIDE;
5621 /* If value is 1, set the 100M_OVERRIDE bit,
5622 otherwise reset it.*/
5623 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
5624 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
5625 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5626 break;
5627 case 2: /* 1000MB led */
5628 /* Read the current value of the LED register in the
5629 EMAC block */
5630 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5631 /* Set the OVERRIDE bit to 1 */
5632 reg_val |= EMAC_LED_OVERRIDE;
5633 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
5634 reset it. */
5635 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
5636 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
5637 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5638 break;
5639 case 3: /* 2500MB led */
5640 /* Read the current value of the LED register in the
5641 EMAC block*/
5642 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5643 /* Set the OVERRIDE bit to 1 */
5644 reg_val |= EMAC_LED_OVERRIDE;
5645 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
5646 reset it.*/
5647 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
5648 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
5649 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5650 break;
5651 case 4: /*10G led */
5652 if (port == 0) {
5653 REG_WR(bp, NIG_REG_LED_10G_P0,
5654 value);
5655 } else {
5656 REG_WR(bp, NIG_REG_LED_10G_P1,
5657 value);
5658 }
5659 break;
5660 case 5: /* TRAFFIC led */
5661 /* Find if the traffic control is via BMAC or EMAC */
5662 if (port == 0)
5663 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
5664 else
5665 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
5666
5667 /* Override the traffic led in the EMAC:*/
5668 if (reg_val == 1) {
5669 /* Read the current value of the LED register in
5670 the EMAC block */
5671 reg_val = REG_RD(bp, emac_base +
5672 EMAC_REG_EMAC_LED);
5673 /* Set the TRAFFIC_OVERRIDE bit to 1 */
5674 reg_val |= EMAC_LED_OVERRIDE;
5675 /* If value is 1, set the TRAFFIC bit, otherwise
5676 reset it.*/
5677 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
5678 (reg_val & ~EMAC_LED_TRAFFIC);
5679 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5680 } else { /* Override the traffic led in the BMAC: */
5681 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
5682 + port*4, 1);
5683 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
5684 value);
5685 }
5686 break;
5687 default:
5688 DP(NETIF_MSG_LINK,
5689 "bnx2x_override_led_value() unknown led index %d "
5690 "(should be 0-5)\n", led_idx);
5691 return -EINVAL;
5692 }
5693
5694 return 0;
5695}
5696
5697
Yaniv Rosner7846e472009-11-05 19:18:07 +02005698u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005699{
Yaniv Rosner7846e472009-11-05 19:18:07 +02005700 u8 port = params->port;
5701 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005702 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005703 u32 tmp;
5704 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02005705 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
5706 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005707 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
5708 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
5709 speed, hw_led_mode);
5710 switch (mode) {
5711 case LED_MODE_OFF:
5712 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
5713 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
5714 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005715
5716 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005717 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005718 break;
5719
5720 case LED_MODE_OPER:
Yaniv Rosner7846e472009-11-05 19:18:07 +02005721 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
5722 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
5723 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
5724 } else {
5725 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
5726 hw_led_mode);
5727 }
5728
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005729 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
5730 port*4, 0);
5731 /* Set blinking rate to ~15.9Hz */
5732 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
5733 LED_BLINK_RATE_VAL);
5734 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
5735 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005736 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005737 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005738 (tmp & (~EMAC_LED_OVERRIDE)));
5739
Yaniv Rosner7846e472009-11-05 19:18:07 +02005740 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005741 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005742 (speed == SPEED_1000) ||
5743 (speed == SPEED_100) ||
5744 (speed == SPEED_10))) {
5745 /* On Everest 1 Ax chip versions for speeds less than
5746 10G LED scheme is different */
5747 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
5748 + port*4, 1);
5749 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
5750 port*4, 0);
5751 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
5752 port*4, 1);
5753 }
5754 break;
5755
5756 default:
5757 rc = -EINVAL;
5758 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
5759 mode);
5760 break;
5761 }
5762 return rc;
5763
5764}
5765
5766u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
5767{
5768 struct bnx2x *bp = params->bp;
5769 u16 gp_status = 0;
5770
5771 CL45_RD_OVER_CL22(bp, params->port,
5772 params->phy_addr,
5773 MDIO_REG_BANK_GP_STATUS,
5774 MDIO_GP_STATUS_TOP_AN_STATUS1,
5775 &gp_status);
5776 /* link is up only if both local phy and external phy are up */
5777 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
Eilon Greenstein2f904462009-08-12 08:22:16 +00005778 bnx2x_ext_phy_is_link_up(params, vars, 1))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005779 return 0;
5780
5781 return -ESRCH;
5782}
5783
5784static u8 bnx2x_link_initialize(struct link_params *params,
5785 struct link_vars *vars)
5786{
5787 struct bnx2x *bp = params->bp;
5788 u8 port = params->port;
5789 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005790 u8 non_ext_phy;
5791 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005792
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005793 /* Activate the external PHY */
5794 bnx2x_ext_phy_reset(params, vars);
5795
5796 bnx2x_set_aer_mmd(params, vars);
5797
5798 if (vars->phy_flags & PHY_XGXS_FLAG)
5799 bnx2x_set_master_ln(params);
5800
5801 rc = bnx2x_reset_unicore(params);
5802 /* reset the SerDes and wait for reset bit return low */
5803 if (rc != 0)
5804 return rc;
5805
5806 bnx2x_set_aer_mmd(params, vars);
5807
5808 /* setting the masterLn_def again after the reset */
5809 if (vars->phy_flags & PHY_XGXS_FLAG) {
5810 bnx2x_set_master_ln(params);
5811 bnx2x_set_swap_lanes(params);
5812 }
5813
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005814 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00005815 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005816 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00005817 (params->req_line_speed == SPEED_10))) ||
5818 (!params->req_line_speed &&
5819 (params->speed_cap_mask >=
5820 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
5821 (params->speed_cap_mask <
5822 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
5823 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005824 vars->phy_flags |= PHY_SGMII_FLAG;
5825 } else {
5826 vars->phy_flags &= ~PHY_SGMII_FLAG;
5827 }
5828 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005829 /* In case of external phy existance, the line speed would be the
5830 line speed linked up by the external phy. In case it is direct only,
5831 then the line_speed during initialization will be equal to the
5832 req_line_speed*/
5833 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005834
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005835 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005836
5837 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005838 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00005839 (params->loopback_mode == LOOPBACK_XGXS_10));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005840
5841 if (non_ext_phy ||
Eilon Greenstein589abe32009-02-12 08:36:55 +00005842 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02005843 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
Eilon Greenstein28577182009-02-12 08:37:00 +00005844 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00005845 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005846 if (params->req_line_speed == SPEED_AUTO_NEG)
5847 bnx2x_set_parallel_detection(params, vars->phy_flags);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005848 bnx2x_init_internal_phy(params, vars, non_ext_phy);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005849 }
5850
5851 if (!non_ext_phy)
5852 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005853
5854 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005855 (NIG_STATUS_XGXS0_LINK10G |
5856 NIG_STATUS_XGXS0_LINK_STATUS |
5857 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005858
5859 return rc;
5860
5861}
5862
5863
5864u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
5865{
5866 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005867 u32 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005868
5869 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
5870 DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n",
5871 params->req_line_speed, params->req_flow_ctrl);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005872 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005873 vars->phy_link_up = 0;
5874 vars->link_up = 0;
5875 vars->line_speed = 0;
5876 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005877 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005878 vars->mac_type = MAC_TYPE_NONE;
5879
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005880 if (params->switch_cfg == SWITCH_CFG_1G)
5881 vars->phy_flags = PHY_SERDES_FLAG;
5882 else
5883 vars->phy_flags = PHY_XGXS_FLAG;
5884
5885 /* disable attentions */
5886 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
5887 (NIG_MASK_XGXS0_LINK_STATUS |
5888 NIG_MASK_XGXS0_LINK10G |
5889 NIG_MASK_SERDES0_LINK_STATUS |
5890 NIG_MASK_MI_INT));
5891
5892 bnx2x_emac_init(params, vars);
5893
5894 if (CHIP_REV_IS_FPGA(bp)) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005895
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005896 vars->link_up = 1;
5897 vars->line_speed = SPEED_10000;
5898 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005899 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005900 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005901 /* enable on E1.5 FPGA */
5902 if (CHIP_IS_E1H(bp)) {
5903 vars->flow_ctrl |=
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005904 (BNX2X_FLOW_CTRL_TX |
5905 BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005906 vars->link_status |=
5907 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
5908 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
5909 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005910
5911 bnx2x_emac_enable(params, vars, 0);
5912 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5913 /* disable drain */
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005914 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005915
5916 /* update shared memory */
5917 bnx2x_update_mng(params, vars->link_status);
5918
5919 return 0;
5920
5921 } else
5922 if (CHIP_REV_IS_EMUL(bp)) {
5923
5924 vars->link_up = 1;
5925 vars->line_speed = SPEED_10000;
5926 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005927 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005928 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
5929
5930 bnx2x_bmac_enable(params, vars, 0);
5931
5932 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
5933 /* Disable drain */
5934 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
5935 + params->port*4, 0);
5936
5937 /* update shared memory */
5938 bnx2x_update_mng(params, vars->link_status);
5939
5940 return 0;
5941
5942 } else
5943 if (params->loopback_mode == LOOPBACK_BMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005944
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005945 vars->link_up = 1;
5946 vars->line_speed = SPEED_10000;
5947 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005948 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005949 vars->mac_type = MAC_TYPE_BMAC;
5950
5951 vars->phy_flags = PHY_XGXS_FLAG;
5952
5953 bnx2x_phy_deassert(params, vars->phy_flags);
5954 /* set bmac loopback */
5955 bnx2x_bmac_enable(params, vars, 1);
5956
5957 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5958 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005959
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005960 } else if (params->loopback_mode == LOOPBACK_EMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005961
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005962 vars->link_up = 1;
5963 vars->line_speed = SPEED_1000;
5964 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005965 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005966 vars->mac_type = MAC_TYPE_EMAC;
5967
5968 vars->phy_flags = PHY_XGXS_FLAG;
5969
5970 bnx2x_phy_deassert(params, vars->phy_flags);
5971 /* set bmac loopback */
5972 bnx2x_emac_enable(params, vars, 1);
5973 bnx2x_emac_program(params, vars->line_speed,
5974 vars->duplex);
5975 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
5976 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005977
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005978 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005979 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
5980
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005981 vars->link_up = 1;
5982 vars->line_speed = SPEED_10000;
5983 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08005984 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005985
5986 vars->phy_flags = PHY_XGXS_FLAG;
5987
5988 val = REG_RD(bp,
5989 NIG_REG_XGXS0_CTRL_PHY_ADDR+
5990 params->port*0x18);
5991 params->phy_addr = (u8)val;
5992
5993 bnx2x_phy_deassert(params, vars->phy_flags);
5994 bnx2x_link_initialize(params, vars);
5995
5996 vars->mac_type = MAC_TYPE_BMAC;
5997
5998 bnx2x_bmac_enable(params, vars, 0);
5999
6000 if (params->loopback_mode == LOOPBACK_XGXS_10) {
6001 /* set 10G XGXS loopback */
6002 bnx2x_set_xgxs_loopback(params, vars, 1);
6003 } else {
6004 /* set external phy loopback */
6005 bnx2x_ext_phy_loopback(params);
6006 }
6007 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6008 params->port*4, 0);
Eilon Greensteinba71d312009-07-21 05:47:49 +00006009
Yaniv Rosner7846e472009-11-05 19:18:07 +02006010 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006011 } else
6012 /* No loopback */
6013 {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006014 bnx2x_phy_deassert(params, vars->phy_flags);
6015 switch (params->switch_cfg) {
6016 case SWITCH_CFG_1G:
6017 vars->phy_flags |= PHY_SERDES_FLAG;
6018 if ((params->ext_phy_config &
6019 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
6020 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006021 vars->phy_flags |= PHY_SGMII_FLAG;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006022 }
6023
6024 val = REG_RD(bp,
6025 NIG_REG_SERDES0_CTRL_PHY_ADDR+
6026 params->port*0x10);
6027
6028 params->phy_addr = (u8)val;
6029
6030 break;
6031 case SWITCH_CFG_10G:
6032 vars->phy_flags |= PHY_XGXS_FLAG;
6033 val = REG_RD(bp,
6034 NIG_REG_XGXS0_CTRL_PHY_ADDR+
6035 params->port*0x18);
6036 params->phy_addr = (u8)val;
6037
6038 break;
6039 default:
6040 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
6041 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006042 }
Eilon Greensteinf5372252009-02-12 08:38:30 +00006043 DP(NETIF_MSG_LINK, "Phy address = 0x%x\n", params->phy_addr);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006044
6045 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006046 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006047 bnx2x_link_int_enable(params);
6048 }
6049 return 0;
6050}
6051
Eilon Greenstein589abe32009-02-12 08:36:55 +00006052static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
6053{
6054 DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
6055
6056 /* Set serial boot control for external load */
6057 bnx2x_cl45_write(bp, port,
6058 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
6059 MDIO_PMA_DEVAD,
6060 MDIO_PMA_REG_GEN_CTRL, 0x0001);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006061}
6062
6063u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
6064 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006065{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006066 struct bnx2x *bp = params->bp;
6067 u32 ext_phy_config = params->ext_phy_config;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006068 u8 port = params->port;
6069 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006070 u32 val = REG_RD(bp, params->shmem_base +
6071 offsetof(struct shmem_region, dev_info.
6072 port_feature_config[params->port].
6073 config));
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02006074 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006075 /* disable attentions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006076 vars->link_status = 0;
6077 bnx2x_update_mng(params, vars->link_status);
6078 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6079 (NIG_MASK_XGXS0_LINK_STATUS |
6080 NIG_MASK_XGXS0_LINK10G |
6081 NIG_MASK_SERDES0_LINK_STATUS |
6082 NIG_MASK_MI_INT));
6083
6084 /* activate nig drain */
6085 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6086
6087 /* disable nig egress interface */
6088 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6089 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6090
6091 /* Stop BigMac rx */
6092 bnx2x_bmac_rx_disable(bp, port);
6093
6094 /* disable emac */
6095 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6096
6097 msleep(10);
6098 /* The PHY reset is controled by GPIO 1
6099 * Hold it as vars low
6100 */
6101 /* clear link led */
Yaniv Rosner7846e472009-11-05 19:18:07 +02006102 bnx2x_set_led(params, LED_MODE_OFF, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006103 if (reset_ext_phy) {
6104 switch (ext_phy_type) {
6105 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
6106 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
6107 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006108
6109 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6110 {
6111
6112 /* Disable Transmitter */
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006113 u8 ext_phy_addr =
6114 XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006115 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
6116 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
6117 bnx2x_sfp_set_transmitter(bp, port,
6118 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6119 ext_phy_addr, 0);
6120 break;
6121 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00006122 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6123 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
6124 "low power mode\n",
6125 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006126 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07006127 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6128 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006129 break;
6130 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6131 {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006132 u8 ext_phy_addr =
6133 XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006134 /* Set soft reset */
6135 bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
6136 break;
6137 }
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006138 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
6139 {
Yaniv Rosnera1e4be32010-09-01 09:51:33 +00006140 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
6141 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6142 params->port);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006143 break;
6144 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00006145 default:
6146 /* HW reset */
6147 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
6148 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6149 port);
6150 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6151 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6152 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006153 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006154 }
6155 }
6156 /* reset the SerDes/XGXS */
6157 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
6158 (0x1ff << (port*16)));
6159
6160 /* reset BigMac */
6161 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
6162 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
6163
6164 /* disable nig ingress interface */
6165 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
6166 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
6167 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6168 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6169 vars->link_up = 0;
6170 return 0;
6171}
6172
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006173static u8 bnx2x_update_link_down(struct link_params *params,
6174 struct link_vars *vars)
6175{
6176 struct bnx2x *bp = params->bp;
6177 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006178
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006179 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7846e472009-11-05 19:18:07 +02006180 bnx2x_set_led(params, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006181
6182 /* indicate no mac active */
6183 vars->mac_type = MAC_TYPE_NONE;
6184
6185 /* update shared memory */
6186 vars->link_status = 0;
6187 vars->line_speed = 0;
6188 bnx2x_update_mng(params, vars->link_status);
6189
6190 /* activate nig drain */
6191 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6192
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006193 /* disable emac */
6194 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6195
6196 msleep(10);
6197
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006198 /* reset BigMac */
6199 bnx2x_bmac_rx_disable(bp, params->port);
6200 REG_WR(bp, GRCBASE_MISC +
6201 MISC_REGISTERS_RESET_REG_2_CLEAR,
6202 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
6203 return 0;
6204}
6205
6206static u8 bnx2x_update_link_up(struct link_params *params,
6207 struct link_vars *vars,
6208 u8 link_10g, u32 gp_status)
6209{
6210 struct bnx2x *bp = params->bp;
6211 u8 port = params->port;
6212 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006213
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006214 vars->link_status |= LINK_STATUS_LINK_UP;
6215 if (link_10g) {
6216 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7846e472009-11-05 19:18:07 +02006217 bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006218 } else {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006219 rc = bnx2x_emac_program(params, vars->line_speed,
6220 vars->duplex);
6221
Yaniv Rosner0c786f02009-11-05 19:18:32 +02006222 bnx2x_emac_enable(params, vars, 0);
6223
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006224 /* AN complete? */
6225 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
6226 if (!(vars->phy_flags &
6227 PHY_SGMII_FLAG))
Eilon Greensteined8680a2009-02-12 08:37:12 +00006228 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006229 }
6230 }
6231
6232 /* PBF - link up */
6233 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
6234 vars->line_speed);
6235
6236 /* disable drain */
6237 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
6238
6239 /* update shared memory */
6240 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006241 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006242 return rc;
6243}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006244/* This function should called upon link interrupt */
6245/* In case vars->link_up, driver needs to
6246 1. Update the pbf
6247 2. Disable drain
6248 3. Update the shared memory
6249 4. Indicate link up
6250 5. Set LEDs
6251 Otherwise,
6252 1. Update shared memory
6253 2. Reset BigMac
6254 3. Report link down
6255 4. Unset LEDs
6256*/
6257u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
6258{
6259 struct bnx2x *bp = params->bp;
6260 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006261 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006262 u8 link_10g;
6263 u8 ext_phy_link_up, rc = 0;
6264 u32 ext_phy_type;
Eilon Greenstein2f904462009-08-12 08:22:16 +00006265 u8 is_mi_int = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006266
6267 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006268 port, (vars->phy_flags & PHY_XGXS_FLAG),
6269 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006270
Eilon Greenstein2f904462009-08-12 08:22:16 +00006271 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
6272 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006273 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006274 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
6275 is_mi_int,
6276 REG_RD(bp,
6277 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006278
6279 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
6280 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
6281 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
6282
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006283 /* disable emac */
6284 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6285
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006286 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006287
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006288 /* Check external link change only for non-direct */
Eilon Greenstein2f904462009-08-12 08:22:16 +00006289 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars, is_mi_int);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006290
6291 /* Read gp_status */
6292 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
6293 MDIO_REG_BANK_GP_STATUS,
6294 MDIO_GP_STATUS_TOP_AN_STATUS1,
6295 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006296
Eilon Greenstein2f904462009-08-12 08:22:16 +00006297 rc = bnx2x_link_settings_status(params, vars, gp_status,
6298 ext_phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006299 if (rc != 0)
6300 return rc;
6301
6302 /* anything 10 and over uses the bmac */
6303 link_10g = ((vars->line_speed == SPEED_10000) ||
6304 (vars->line_speed == SPEED_12000) ||
6305 (vars->line_speed == SPEED_12500) ||
6306 (vars->line_speed == SPEED_13000) ||
6307 (vars->line_speed == SPEED_15000) ||
6308 (vars->line_speed == SPEED_16000));
6309
Eilon Greenstein2f904462009-08-12 08:22:16 +00006310 bnx2x_link_int_ack(params, vars, link_10g, is_mi_int);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006311
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006312 /* In case external phy link is up, and internal link is down
6313 ( not initialized yet probably after link initialization, it needs
6314 to be initialized.
6315 Note that after link down-up as result of cable plug,
6316 the xgxs link would probably become up again without the need to
6317 initialize it*/
6318
6319 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
6320 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02006321 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) &&
Eilon Greenstein589abe32009-02-12 08:36:55 +00006322 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006323 (ext_phy_link_up && !vars->phy_link_up))
Eilon Greenstein239d6862009-08-12 08:23:04 +00006324 bnx2x_init_internal_phy(params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006325
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006326 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006327 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006328
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006329 if (vars->link_up)
6330 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
6331 else
6332 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006333
6334 return rc;
6335}
6336
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006337static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6338{
6339 u8 ext_phy_addr[PORT_MAX];
6340 u16 val;
6341 s8 port;
6342
6343 /* PART1 - Reset both phys */
6344 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6345 /* Extract the ext phy address for the port */
6346 u32 ext_phy_config = REG_RD(bp, shmem_base +
6347 offsetof(struct shmem_region,
6348 dev_info.port_hw_config[port].external_phy_config));
6349
6350 /* disable attentions */
6351 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6352 (NIG_MASK_XGXS0_LINK_STATUS |
6353 NIG_MASK_XGXS0_LINK10G |
6354 NIG_MASK_SERDES0_LINK_STATUS |
6355 NIG_MASK_MI_INT));
6356
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006357 ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006358
6359 /* Need to take the phy out of low power mode in order
6360 to write to access its registers */
6361 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6362 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
6363
6364 /* Reset the phy */
6365 bnx2x_cl45_write(bp, port,
6366 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6367 ext_phy_addr[port],
6368 MDIO_PMA_DEVAD,
6369 MDIO_PMA_REG_CTRL,
6370 1<<15);
6371 }
6372
6373 /* Add delay of 150ms after reset */
6374 msleep(150);
6375
6376 /* PART2 - Download firmware to both phys */
6377 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6378 u16 fw_ver1;
6379
6380 bnx2x_bcm8073_external_rom_boot(bp, port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00006381 ext_phy_addr[port], shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006382
6383 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6384 ext_phy_addr[port],
6385 MDIO_PMA_DEVAD,
6386 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006387 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006388 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006389 "bnx2x_8073_common_init_phy port %x:"
6390 "Download failed. fw version = 0x%x\n",
6391 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006392 return -EINVAL;
6393 }
6394
6395 /* Only set bit 10 = 1 (Tx power down) */
6396 bnx2x_cl45_read(bp, port,
6397 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6398 ext_phy_addr[port],
6399 MDIO_PMA_DEVAD,
6400 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6401
6402 /* Phase1 of TX_POWER_DOWN reset */
6403 bnx2x_cl45_write(bp, port,
6404 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6405 ext_phy_addr[port],
6406 MDIO_PMA_DEVAD,
6407 MDIO_PMA_REG_TX_POWER_DOWN,
6408 (val | 1<<10));
6409 }
6410
6411 /* Toggle Transmitter: Power down and then up with 600ms
6412 delay between */
6413 msleep(600);
6414
6415 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
6416 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00006417 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006418 /* Release bit 10 (Release Tx power down) */
6419 bnx2x_cl45_read(bp, port,
6420 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6421 ext_phy_addr[port],
6422 MDIO_PMA_DEVAD,
6423 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6424
6425 bnx2x_cl45_write(bp, port,
6426 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6427 ext_phy_addr[port],
6428 MDIO_PMA_DEVAD,
6429 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
6430 msleep(15);
6431
6432 /* Read modify write the SPI-ROM version select register */
6433 bnx2x_cl45_read(bp, port,
6434 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6435 ext_phy_addr[port],
6436 MDIO_PMA_DEVAD,
6437 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
6438 bnx2x_cl45_write(bp, port,
6439 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6440 ext_phy_addr[port],
6441 MDIO_PMA_DEVAD,
6442 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
6443
6444 /* set GPIO2 back to LOW */
6445 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6446 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
6447 }
6448 return 0;
6449
6450}
6451
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006452static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6453{
6454 u8 ext_phy_addr[PORT_MAX];
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006455 s8 port, first_port, i;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006456 u32 swap_val, swap_override;
6457 DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
6458 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
6459 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
6460
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006461 bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006462 msleep(5);
6463
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006464 if (swap_val && swap_override)
6465 first_port = PORT_0;
6466 else
6467 first_port = PORT_1;
6468
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006469 /* PART1 - Reset both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006470 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006471 /* Extract the ext phy address for the port */
6472 u32 ext_phy_config = REG_RD(bp, shmem_base +
6473 offsetof(struct shmem_region,
6474 dev_info.port_hw_config[port].external_phy_config));
6475
6476 /* disable attentions */
6477 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6478 (NIG_MASK_XGXS0_LINK_STATUS |
6479 NIG_MASK_XGXS0_LINK10G |
6480 NIG_MASK_SERDES0_LINK_STATUS |
6481 NIG_MASK_MI_INT));
6482
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006483 ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006484
6485 /* Reset the phy */
6486 bnx2x_cl45_write(bp, port,
6487 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6488 ext_phy_addr[port],
6489 MDIO_PMA_DEVAD,
6490 MDIO_PMA_REG_CTRL,
6491 1<<15);
6492 }
6493
6494 /* Add delay of 150ms after reset */
6495 msleep(150);
6496
6497 /* PART2 - Download firmware to both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006498 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006499 u16 fw_ver1;
6500
6501 bnx2x_bcm8727_external_rom_boot(bp, port,
6502 ext_phy_addr[port], shmem_base);
6503
6504 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6505 ext_phy_addr[port],
6506 MDIO_PMA_DEVAD,
6507 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
6508 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
6509 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006510 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006511 "Download failed. fw version = 0x%x\n",
6512 port, fw_ver1);
6513 return -EINVAL;
6514 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006515 }
6516
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006517 return 0;
6518}
6519
Eilon Greenstein589abe32009-02-12 08:36:55 +00006520
6521static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6522{
6523 u8 ext_phy_addr;
6524 u32 val;
6525 s8 port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006526
Eilon Greenstein589abe32009-02-12 08:36:55 +00006527 /* Use port1 because of the static port-swap */
6528 /* Enable the module detection interrupt */
6529 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
6530 val |= ((1<<MISC_REGISTERS_GPIO_3)|
6531 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
6532 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
6533
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006534 bnx2x_ext_phy_hw_reset(bp, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006535 msleep(5);
6536 for (port = 0; port < PORT_MAX; port++) {
6537 /* Extract the ext phy address for the port */
6538 u32 ext_phy_config = REG_RD(bp, shmem_base +
6539 offsetof(struct shmem_region,
6540 dev_info.port_hw_config[port].external_phy_config));
6541
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006542 ext_phy_addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006543 DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
6544 ext_phy_addr);
6545
6546 bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
6547
6548 /* Set fault module detected LED on */
6549 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
6550 MISC_REGISTERS_GPIO_HIGH,
6551 port);
6552 }
6553
6554 return 0;
6555}
6556
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006557u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6558{
6559 u8 rc = 0;
6560 u32 ext_phy_type;
6561
Eilon Greensteinf5372252009-02-12 08:38:30 +00006562 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006563
6564 /* Read the ext_phy_type for arbitrary port(0) */
6565 ext_phy_type = XGXS_EXT_PHY_TYPE(
6566 REG_RD(bp, shmem_base +
6567 offsetof(struct shmem_region,
6568 dev_info.port_hw_config[0].external_phy_config)));
6569
6570 switch (ext_phy_type) {
6571 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6572 {
6573 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
6574 break;
6575 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006576
6577 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6578 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6579 rc = bnx2x_8727_common_init_phy(bp, shmem_base);
6580 break;
6581
Eilon Greenstein589abe32009-02-12 08:36:55 +00006582 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6583 /* GPIO1 affects both ports, so there's need to pull
6584 it for single port alone */
6585 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006586 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006587 default:
6588 DP(NETIF_MSG_LINK,
6589 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
6590 ext_phy_type);
6591 break;
6592 }
6593
6594 return rc;
6595}
6596
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006597void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006598{
6599 u16 val, cnt;
6600
6601 bnx2x_cl45_read(bp, port,
6602 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6603 phy_addr,
6604 MDIO_PMA_DEVAD,
6605 MDIO_PMA_REG_7101_RESET, &val);
6606
6607 for (cnt = 0; cnt < 10; cnt++) {
6608 msleep(50);
6609 /* Writes a self-clearing reset */
6610 bnx2x_cl45_write(bp, port,
6611 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6612 phy_addr,
6613 MDIO_PMA_DEVAD,
6614 MDIO_PMA_REG_7101_RESET,
6615 (val | (1<<15)));
6616 /* Wait for clear */
6617 bnx2x_cl45_read(bp, port,
6618 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6619 phy_addr,
6620 MDIO_PMA_DEVAD,
6621 MDIO_PMA_REG_7101_RESET, &val);
6622
6623 if ((val & (1<<15)) == 0)
6624 break;
6625 }
6626}