blob: 7897fe13e61a021ba124fe0f67148dcef4320640 [file] [log] [blame]
Eilon Greensteind05c26c2009-01-17 23:26:13 -08001/* Copyright 2008-2009 Broadcom Corporation
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002 *
3 * Unless you and Broadcom execute a separate written software license
4 * agreement governing use of this software, this software is licensed to you
5 * under the terms of the GNU General Public License version 2, available
6 * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
7 *
8 * Notwithstanding the above, under no circumstances may you combine this
9 * software in any way with any other Broadcom software provided under a
10 * license other than the GPL, without Broadcom's express prior written
11 * consent.
12 *
13 * Written by Yaniv Rosner
14 *
15 */
16
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/pci.h>
20#include <linux/netdevice.h>
21#include <linux/delay.h>
22#include <linux/ethtool.h>
23#include <linux/mutex.h>
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070024
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070025#include "bnx2x.h"
26
27/********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070028#define ETH_HLEN 14
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070029#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
30#define ETH_MIN_PACKET_SIZE 60
31#define ETH_MAX_PACKET_SIZE 1500
32#define ETH_MAX_JUMBO_PACKET_SIZE 9600
33#define MDIO_ACCESS_TIMEOUT 1000
34#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070035
36/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070037/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070038/***********************************************************/
39
Eilon Greenstein2f904462009-08-12 08:22:16 +000040#define NIG_LATCH_BC_ENABLE_MI_INT 0
41
42#define NIG_STATUS_EMAC0_MI_INT \
43 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070044#define NIG_STATUS_XGXS0_LINK10G \
45 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
46#define NIG_STATUS_XGXS0_LINK_STATUS \
47 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
48#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
49 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
50#define NIG_STATUS_SERDES0_LINK_STATUS \
51 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
52#define NIG_MASK_MI_INT \
53 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
54#define NIG_MASK_XGXS0_LINK10G \
55 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
56#define NIG_MASK_XGXS0_LINK_STATUS \
57 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
58#define NIG_MASK_SERDES0_LINK_STATUS \
59 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
60
61#define MDIO_AN_CL73_OR_37_COMPLETE \
62 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
63 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
64
65#define XGXS_RESET_BITS \
66 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
67 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
68 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
71
72#define SERDES_RESET_BITS \
73 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
74 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
75 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
77
78#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
79#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Eilon Greenstein3196a882008-08-13 15:58:49 -070080#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
81#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070082 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070083#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070084 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070085#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070086
87#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
88 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
89#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
90 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
91#define GP_STATUS_SPEED_MASK \
92 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
93#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
94#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
95#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
96#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
97#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
98#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
99#define GP_STATUS_10G_HIG \
100 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
101#define GP_STATUS_10G_CX4 \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
103#define GP_STATUS_12G_HIG \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
105#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
106#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
107#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
108#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
109#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
110#define GP_STATUS_10G_KX4 \
111 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
112
113#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
114#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
115#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
116#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
117#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
118#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
119#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
120#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
121#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
122#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
123#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
124#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
125#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
126#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
127#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
128#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
129#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
130#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
131#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
132#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
133#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
134#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
135#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
136
137#define PHY_XGXS_FLAG 0x1
138#define PHY_SGMII_FLAG 0x2
139#define PHY_SERDES_FLAG 0x4
140
Eilon Greenstein589abe32009-02-12 08:36:55 +0000141/* */
142#define SFP_EEPROM_CON_TYPE_ADDR 0x2
143 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
144 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
145
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000146
147#define SFP_EEPROM_COMP_CODE_ADDR 0x3
148 #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
149 #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
150 #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
151
Eilon Greenstein589abe32009-02-12 08:36:55 +0000152#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
153 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
154 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000155
Eilon Greenstein589abe32009-02-12 08:36:55 +0000156#define SFP_EEPROM_OPTIONS_ADDR 0x40
157 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
158#define SFP_EEPROM_OPTIONS_SIZE 2
159
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000160#define EDC_MODE_LINEAR 0x0022
161#define EDC_MODE_LIMITING 0x0044
162#define EDC_MODE_PASSIVE_DAC 0x0055
Eilon Greenstein589abe32009-02-12 08:36:55 +0000163
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000164
165
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700166/**********************************************************/
167/* INTERFACE */
168/**********************************************************/
169#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
170 bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
171 DEFAULT_PHY_DEV_ADDR, \
172 (_bank + (_addr & 0xf)), \
173 _val)
174
175#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
176 bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
177 DEFAULT_PHY_DEV_ADDR, \
178 (_bank + (_addr & 0xf)), \
179 _val)
180
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000181static void bnx2x_set_serdes_access(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700182{
183 struct bnx2x *bp = params->bp;
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000184 u32 emac_base = (params->port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000185
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000186 /* Set Clause 22 */
187 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 1);
188 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
189 udelay(500);
190 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
191 udelay(500);
192 /* Set Clause 45 */
193 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 0);
194}
195static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags)
196{
197 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000198
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000199 if (phy_flags & PHY_XGXS_FLAG) {
200 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
201 params->port*0x18, 0);
202 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
203 DEFAULT_PHY_DEV_ADDR);
204 } else {
205 bnx2x_set_serdes_access(params);
206
207 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
208 params->port*0x10,
209 DEFAULT_PHY_DEV_ADDR);
210 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700211}
212
213static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
214{
215 u32 val = REG_RD(bp, reg);
216
217 val |= bits;
218 REG_WR(bp, reg, val);
219 return val;
220}
221
222static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
223{
224 u32 val = REG_RD(bp, reg);
225
226 val &= ~bits;
227 REG_WR(bp, reg, val);
228 return val;
229}
230
231static void bnx2x_emac_init(struct link_params *params,
232 struct link_vars *vars)
233{
234 /* reset and unreset the emac core */
235 struct bnx2x *bp = params->bp;
236 u8 port = params->port;
237 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
238 u32 val;
239 u16 timeout;
240
241 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
242 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
243 udelay(5);
244 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
245 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
246
247 /* init emac - use read-modify-write */
248 /* self clear reset */
249 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700250 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700251
252 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700253 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700254 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
255 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
256 if (!timeout) {
257 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
258 return;
259 }
260 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700261 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700262
263 /* Set mac address */
264 val = ((params->mac_addr[0] << 8) |
265 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700266 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700267
268 val = ((params->mac_addr[2] << 24) |
269 (params->mac_addr[3] << 16) |
270 (params->mac_addr[4] << 8) |
271 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700272 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700273}
274
275static u8 bnx2x_emac_enable(struct link_params *params,
276 struct link_vars *vars, u8 lb)
277{
278 struct bnx2x *bp = params->bp;
279 u8 port = params->port;
280 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
281 u32 val;
282
283 DP(NETIF_MSG_LINK, "enabling EMAC\n");
284
285 /* enable emac and not bmac */
286 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
287
288 /* for paladium */
289 if (CHIP_REV_IS_EMUL(bp)) {
290 /* Use lane 1 (of lanes 0-3) */
291 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
292 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
293 port*4, 1);
294 }
295 /* for fpga */
296 else
297
298 if (CHIP_REV_IS_FPGA(bp)) {
299 /* Use lane 1 (of lanes 0-3) */
300 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
301
302 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
303 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
304 0);
305 } else
306 /* ASIC */
307 if (vars->phy_flags & PHY_XGXS_FLAG) {
308 u32 ser_lane = ((params->lane_config &
309 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
310 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
311
312 DP(NETIF_MSG_LINK, "XGXS\n");
313 /* select the master lanes (out of 0-3) */
314 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
315 port*4, ser_lane);
316 /* select XGXS */
317 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
318 port*4, 1);
319
320 } else { /* SerDes */
321 DP(NETIF_MSG_LINK, "SerDes\n");
322 /* select SerDes */
323 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
324 port*4, 0);
325 }
326
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000327 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
328 EMAC_RX_MODE_RESET);
329 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
330 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700331
332 if (CHIP_REV_IS_SLOW(bp)) {
333 /* config GMII mode */
334 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700335 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700336 (val | EMAC_MODE_PORT_GMII));
337 } else { /* ASIC */
338 /* pause enable/disable */
339 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
340 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800341 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700342 bnx2x_bits_en(bp, emac_base +
343 EMAC_REG_EMAC_RX_MODE,
344 EMAC_RX_MODE_FLOW_EN);
345
346 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700347 (EMAC_TX_MODE_EXT_PAUSE_EN |
348 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800349 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700350 bnx2x_bits_en(bp, emac_base +
351 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700352 (EMAC_TX_MODE_EXT_PAUSE_EN |
353 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700354 }
355
356 /* KEEP_VLAN_TAG, promiscuous */
357 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
358 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700359 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700360
361 /* Set Loopback */
362 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
363 if (lb)
364 val |= 0x810;
365 else
366 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700367 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700368
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000369 /* enable emac */
370 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
371
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700372 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700373 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700374 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
375 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
376
377 /* strip CRC */
378 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
379
380 /* disable the NIG in/out to the bmac */
381 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
382 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
383 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
384
385 /* enable the NIG in/out to the emac */
386 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
387 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800388 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700389 val = 1;
390
391 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
392 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
393
394 if (CHIP_REV_IS_EMUL(bp)) {
395 /* take the BigMac out of reset */
396 REG_WR(bp,
397 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
398 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
399
400 /* enable access for bmac registers */
401 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
Eilon Greenstein6f654972009-08-12 08:23:51 +0000402 } else
403 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700404
405 vars->mac_type = MAC_TYPE_EMAC;
406 return 0;
407}
408
409
410
411static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
412 u8 is_lb)
413{
414 struct bnx2x *bp = params->bp;
415 u8 port = params->port;
416 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
417 NIG_REG_INGRESS_BMAC0_MEM;
418 u32 wb_data[2];
419 u32 val;
420
421 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
422 /* reset and unreset the BigMac */
423 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
424 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
425 msleep(1);
426
427 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
428 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
429
430 /* enable access for bmac registers */
431 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
432
433 /* XGXS control */
434 wb_data[0] = 0x3c;
435 wb_data[1] = 0;
436 REG_WR_DMAE(bp, bmac_addr +
437 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
438 wb_data, 2);
439
440 /* tx MAC SA */
441 wb_data[0] = ((params->mac_addr[2] << 24) |
442 (params->mac_addr[3] << 16) |
443 (params->mac_addr[4] << 8) |
444 params->mac_addr[5]);
445 wb_data[1] = ((params->mac_addr[0] << 8) |
446 params->mac_addr[1]);
447 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
448 wb_data, 2);
449
450 /* tx control */
451 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800452 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700453 val |= 0x800000;
454 wb_data[0] = val;
455 wb_data[1] = 0;
456 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
457 wb_data, 2);
458
459 /* mac control */
460 val = 0x3;
461 if (is_lb) {
462 val |= 0x4;
463 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
464 }
465 wb_data[0] = val;
466 wb_data[1] = 0;
467 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
468 wb_data, 2);
469
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700470 /* set rx mtu */
471 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
472 wb_data[1] = 0;
473 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
474 wb_data, 2);
475
476 /* rx control set to don't strip crc */
477 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800478 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700479 val |= 0x20;
480 wb_data[0] = val;
481 wb_data[1] = 0;
482 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
483 wb_data, 2);
484
485 /* set tx mtu */
486 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
487 wb_data[1] = 0;
488 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
489 wb_data, 2);
490
491 /* set cnt max size */
492 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
493 wb_data[1] = 0;
494 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
495 wb_data, 2);
496
497 /* configure safc */
498 wb_data[0] = 0x1000200;
499 wb_data[1] = 0;
500 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
501 wb_data, 2);
502 /* fix for emulation */
503 if (CHIP_REV_IS_EMUL(bp)) {
504 wb_data[0] = 0xf000;
505 wb_data[1] = 0;
506 REG_WR_DMAE(bp,
507 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
508 wb_data, 2);
509 }
510
511 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
512 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
513 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
514 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800515 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700516 val = 1;
517 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
518 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
519 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
520 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
521 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
522 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
523
524 vars->mac_type = MAC_TYPE_BMAC;
525 return 0;
526}
527
528static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
529{
530 struct bnx2x *bp = params->bp;
531 u32 val;
532
533 if (phy_flags & PHY_XGXS_FLAG) {
534 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
535 val = XGXS_RESET_BITS;
536
537 } else { /* SerDes */
538 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
539 val = SERDES_RESET_BITS;
540 }
541
542 val = val << (params->port*16);
543
544 /* reset and unreset the SerDes/XGXS */
545 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
546 val);
547 udelay(500);
548 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
549 val);
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000550 bnx2x_set_phy_mdio(params, phy_flags);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700551}
552
553void bnx2x_link_status_update(struct link_params *params,
554 struct link_vars *vars)
555{
556 struct bnx2x *bp = params->bp;
557 u8 link_10g;
558 u8 port = params->port;
559
560 if (params->switch_cfg == SWITCH_CFG_1G)
561 vars->phy_flags = PHY_SERDES_FLAG;
562 else
563 vars->phy_flags = PHY_XGXS_FLAG;
564 vars->link_status = REG_RD(bp, params->shmem_base +
565 offsetof(struct shmem_region,
566 port_mb[port].link_status));
567
568 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
569
570 if (vars->link_up) {
571 DP(NETIF_MSG_LINK, "phy link up\n");
572
573 vars->phy_link_up = 1;
574 vars->duplex = DUPLEX_FULL;
575 switch (vars->link_status &
576 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
577 case LINK_10THD:
578 vars->duplex = DUPLEX_HALF;
579 /* fall thru */
580 case LINK_10TFD:
581 vars->line_speed = SPEED_10;
582 break;
583
584 case LINK_100TXHD:
585 vars->duplex = DUPLEX_HALF;
586 /* fall thru */
587 case LINK_100T4:
588 case LINK_100TXFD:
589 vars->line_speed = SPEED_100;
590 break;
591
592 case LINK_1000THD:
593 vars->duplex = DUPLEX_HALF;
594 /* fall thru */
595 case LINK_1000TFD:
596 vars->line_speed = SPEED_1000;
597 break;
598
599 case LINK_2500THD:
600 vars->duplex = DUPLEX_HALF;
601 /* fall thru */
602 case LINK_2500TFD:
603 vars->line_speed = SPEED_2500;
604 break;
605
606 case LINK_10GTFD:
607 vars->line_speed = SPEED_10000;
608 break;
609
610 case LINK_12GTFD:
611 vars->line_speed = SPEED_12000;
612 break;
613
614 case LINK_12_5GTFD:
615 vars->line_speed = SPEED_12500;
616 break;
617
618 case LINK_13GTFD:
619 vars->line_speed = SPEED_13000;
620 break;
621
622 case LINK_15GTFD:
623 vars->line_speed = SPEED_15000;
624 break;
625
626 case LINK_16GTFD:
627 vars->line_speed = SPEED_16000;
628 break;
629
630 default:
631 break;
632 }
633
634 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800635 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700636 else
David S. Millerc0700f92008-12-16 23:53:20 -0800637 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700638
639 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800640 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700641 else
David S. Millerc0700f92008-12-16 23:53:20 -0800642 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700643
644 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700645 if (vars->line_speed &&
646 ((vars->line_speed == SPEED_10) ||
647 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700648 vars->phy_flags |= PHY_SGMII_FLAG;
649 } else {
650 vars->phy_flags &= ~PHY_SGMII_FLAG;
651 }
652 }
653
654 /* anything 10 and over uses the bmac */
655 link_10g = ((vars->line_speed == SPEED_10000) ||
656 (vars->line_speed == SPEED_12000) ||
657 (vars->line_speed == SPEED_12500) ||
658 (vars->line_speed == SPEED_13000) ||
659 (vars->line_speed == SPEED_15000) ||
660 (vars->line_speed == SPEED_16000));
661 if (link_10g)
662 vars->mac_type = MAC_TYPE_BMAC;
663 else
664 vars->mac_type = MAC_TYPE_EMAC;
665
666 } else { /* link down */
667 DP(NETIF_MSG_LINK, "phy link down\n");
668
669 vars->phy_link_up = 0;
670
671 vars->line_speed = 0;
672 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -0800673 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700674
675 /* indicate no mac active */
676 vars->mac_type = MAC_TYPE_NONE;
677 }
678
679 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
680 vars->link_status, vars->phy_link_up);
681 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
682 vars->line_speed, vars->duplex, vars->flow_ctrl);
683}
684
685static void bnx2x_update_mng(struct link_params *params, u32 link_status)
686{
687 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000688
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700689 REG_WR(bp, params->shmem_base +
690 offsetof(struct shmem_region,
691 port_mb[params->port].link_status),
692 link_status);
693}
694
695static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
696{
697 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
698 NIG_REG_INGRESS_BMAC0_MEM;
699 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700700 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700701
702 /* Only if the bmac is out of reset */
703 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
704 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
705 nig_bmac_enable) {
706
707 /* Clear Rx Enable bit in BMAC_CONTROL register */
708 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
709 wb_data, 2);
710 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
711 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
712 wb_data, 2);
713
714 msleep(1);
715 }
716}
717
718static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
719 u32 line_speed)
720{
721 struct bnx2x *bp = params->bp;
722 u8 port = params->port;
723 u32 init_crd, crd;
724 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700725
726 /* disable port */
727 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
728
729 /* wait for init credit */
730 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
731 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
732 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
733
734 while ((init_crd != crd) && count) {
735 msleep(5);
736
737 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
738 count--;
739 }
740 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
741 if (init_crd != crd) {
742 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
743 init_crd, crd);
744 return -EINVAL;
745 }
746
David S. Millerc0700f92008-12-16 23:53:20 -0800747 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700748 line_speed == SPEED_10 ||
749 line_speed == SPEED_100 ||
750 line_speed == SPEED_1000 ||
751 line_speed == SPEED_2500) {
752 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700753 /* update threshold */
754 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
755 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700756 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700757
758 } else {
759 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
760 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700761 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700762 /* update threshold */
763 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
764 /* update init credit */
765 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700766 case SPEED_10000:
767 init_crd = thresh + 553 - 22;
768 break;
769
770 case SPEED_12000:
771 init_crd = thresh + 664 - 22;
772 break;
773
774 case SPEED_13000:
775 init_crd = thresh + 742 - 22;
776 break;
777
778 case SPEED_16000:
779 init_crd = thresh + 778 - 22;
780 break;
781 default:
782 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
783 line_speed);
784 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700785 }
786 }
787 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
788 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
789 line_speed, init_crd);
790
791 /* probe the credit changes */
792 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
793 msleep(5);
794 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
795
796 /* enable port */
797 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
798 return 0;
799}
800
Eilon Greenstein589abe32009-02-12 08:36:55 +0000801static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700802{
803 u32 emac_base;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000804
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700805 switch (ext_phy_type) {
806 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000807 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greenstein4d295db2009-07-21 05:47:47 +0000808 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000809 /* All MDC/MDIO is directed through single EMAC */
810 if (REG_RD(bp, NIG_REG_PORT_SWAP))
811 emac_base = GRCBASE_EMAC0;
812 else
813 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700814 break;
815 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700816 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700817 break;
818 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700819 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700820 break;
821 }
822 return emac_base;
823
824}
825
826u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
827 u8 phy_addr, u8 devad, u16 reg, u16 val)
828{
829 u32 tmp, saved_mode;
830 u8 i, rc = 0;
Eilon Greenstein589abe32009-02-12 08:36:55 +0000831 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700832
833 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
834 * (a value of 49==0x31) and make sure that the AUTO poll is off
835 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000836
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700837 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
838 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
839 EMAC_MDIO_MODE_CLOCK_CNT);
840 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
841 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
842 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
843 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
844 udelay(40);
845
846 /* address */
847
848 tmp = ((phy_addr << 21) | (devad << 16) | reg |
849 EMAC_MDIO_COMM_COMMAND_ADDRESS |
850 EMAC_MDIO_COMM_START_BUSY);
851 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
852
853 for (i = 0; i < 50; i++) {
854 udelay(10);
855
856 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
857 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
858 udelay(5);
859 break;
860 }
861 }
862 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
863 DP(NETIF_MSG_LINK, "write phy register failed\n");
864 rc = -EFAULT;
865 } else {
866 /* data */
867 tmp = ((phy_addr << 21) | (devad << 16) | val |
868 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
869 EMAC_MDIO_COMM_START_BUSY);
870 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
871
872 for (i = 0; i < 50; i++) {
873 udelay(10);
874
875 tmp = REG_RD(bp, mdio_ctrl +
876 EMAC_REG_EMAC_MDIO_COMM);
877 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
878 udelay(5);
879 break;
880 }
881 }
882 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
883 DP(NETIF_MSG_LINK, "write phy register failed\n");
884 rc = -EFAULT;
885 }
886 }
887
888 /* Restore the saved mode */
889 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
890
891 return rc;
892}
893
894u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
895 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
896{
897 u32 val, saved_mode;
898 u16 i;
899 u8 rc = 0;
900
Eilon Greenstein589abe32009-02-12 08:36:55 +0000901 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700902 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
903 * (a value of 49==0x31) and make sure that the AUTO poll is off
904 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000905
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700906 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
907 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
908 EMAC_MDIO_MODE_CLOCK_CNT));
909 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +0000910 (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700911 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
912 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
913 udelay(40);
914
915 /* address */
916 val = ((phy_addr << 21) | (devad << 16) | reg |
917 EMAC_MDIO_COMM_COMMAND_ADDRESS |
918 EMAC_MDIO_COMM_START_BUSY);
919 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
920
921 for (i = 0; i < 50; i++) {
922 udelay(10);
923
924 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
925 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
926 udelay(5);
927 break;
928 }
929 }
930 if (val & EMAC_MDIO_COMM_START_BUSY) {
931 DP(NETIF_MSG_LINK, "read phy register failed\n");
932
933 *ret_val = 0;
934 rc = -EFAULT;
935
936 } else {
937 /* data */
938 val = ((phy_addr << 21) | (devad << 16) |
939 EMAC_MDIO_COMM_COMMAND_READ_45 |
940 EMAC_MDIO_COMM_START_BUSY);
941 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
942
943 for (i = 0; i < 50; i++) {
944 udelay(10);
945
946 val = REG_RD(bp, mdio_ctrl +
947 EMAC_REG_EMAC_MDIO_COMM);
948 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
949 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
950 break;
951 }
952 }
953 if (val & EMAC_MDIO_COMM_START_BUSY) {
954 DP(NETIF_MSG_LINK, "read phy register failed\n");
955
956 *ret_val = 0;
957 rc = -EFAULT;
958 }
959 }
960
961 /* Restore the saved mode */
962 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
963
964 return rc;
965}
966
967static void bnx2x_set_aer_mmd(struct link_params *params,
968 struct link_vars *vars)
969{
970 struct bnx2x *bp = params->bp;
971 u32 ser_lane;
972 u16 offset;
973
974 ser_lane = ((params->lane_config &
975 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
976 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
977
978 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
979 (params->phy_addr + ser_lane) : 0;
980
981 CL45_WR_OVER_CL22(bp, params->port,
982 params->phy_addr,
983 MDIO_REG_BANK_AER_BLOCK,
984 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
985}
986
987static void bnx2x_set_master_ln(struct link_params *params)
988{
989 struct bnx2x *bp = params->bp;
990 u16 new_master_ln, ser_lane;
991 ser_lane = ((params->lane_config &
992 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
993 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
994
995 /* set the master_ln for AN */
996 CL45_RD_OVER_CL22(bp, params->port,
997 params->phy_addr,
998 MDIO_REG_BANK_XGXS_BLOCK2,
999 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1000 &new_master_ln);
1001
1002 CL45_WR_OVER_CL22(bp, params->port,
1003 params->phy_addr,
1004 MDIO_REG_BANK_XGXS_BLOCK2 ,
1005 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
1006 (new_master_ln | ser_lane));
1007}
1008
1009static u8 bnx2x_reset_unicore(struct link_params *params)
1010{
1011 struct bnx2x *bp = params->bp;
1012 u16 mii_control;
1013 u16 i;
1014
1015 CL45_RD_OVER_CL22(bp, params->port,
1016 params->phy_addr,
1017 MDIO_REG_BANK_COMBO_IEEE0,
1018 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1019
1020 /* reset the unicore */
1021 CL45_WR_OVER_CL22(bp, params->port,
1022 params->phy_addr,
1023 MDIO_REG_BANK_COMBO_IEEE0,
1024 MDIO_COMBO_IEEE0_MII_CONTROL,
1025 (mii_control |
1026 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
Eilon Greenstein6f654972009-08-12 08:23:51 +00001027 if (params->switch_cfg == SWITCH_CFG_1G)
1028 bnx2x_set_serdes_access(params);
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001029
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001030 /* wait for the reset to self clear */
1031 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1032 udelay(5);
1033
1034 /* the reset erased the previous bank value */
1035 CL45_RD_OVER_CL22(bp, params->port,
1036 params->phy_addr,
1037 MDIO_REG_BANK_COMBO_IEEE0,
1038 MDIO_COMBO_IEEE0_MII_CONTROL,
1039 &mii_control);
1040
1041 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1042 udelay(5);
1043 return 0;
1044 }
1045 }
1046
1047 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1048 return -EINVAL;
1049
1050}
1051
1052static void bnx2x_set_swap_lanes(struct link_params *params)
1053{
1054 struct bnx2x *bp = params->bp;
1055 /* Each two bits represents a lane number:
1056 No swap is 0123 => 0x1b no need to enable the swap */
1057 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1058
1059 ser_lane = ((params->lane_config &
1060 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1061 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1062 rx_lane_swap = ((params->lane_config &
1063 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1064 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1065 tx_lane_swap = ((params->lane_config &
1066 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1067 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1068
1069 if (rx_lane_swap != 0x1b) {
1070 CL45_WR_OVER_CL22(bp, params->port,
1071 params->phy_addr,
1072 MDIO_REG_BANK_XGXS_BLOCK2,
1073 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1074 (rx_lane_swap |
1075 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1076 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1077 } else {
1078 CL45_WR_OVER_CL22(bp, params->port,
1079 params->phy_addr,
1080 MDIO_REG_BANK_XGXS_BLOCK2,
1081 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1082 }
1083
1084 if (tx_lane_swap != 0x1b) {
1085 CL45_WR_OVER_CL22(bp, params->port,
1086 params->phy_addr,
1087 MDIO_REG_BANK_XGXS_BLOCK2,
1088 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1089 (tx_lane_swap |
1090 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1091 } else {
1092 CL45_WR_OVER_CL22(bp, params->port,
1093 params->phy_addr,
1094 MDIO_REG_BANK_XGXS_BLOCK2,
1095 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1096 }
1097}
1098
1099static void bnx2x_set_parallel_detection(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07001100 u8 phy_flags)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001101{
1102 struct bnx2x *bp = params->bp;
1103 u16 control2;
1104
1105 CL45_RD_OVER_CL22(bp, params->port,
1106 params->phy_addr,
1107 MDIO_REG_BANK_SERDES_DIGITAL,
1108 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1109 &control2);
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001110 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1111 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1112 else
1113 control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1114 DP(NETIF_MSG_LINK, "params->speed_cap_mask = 0x%x, control2 = 0x%x\n",
1115 params->speed_cap_mask, control2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001116 CL45_WR_OVER_CL22(bp, params->port,
1117 params->phy_addr,
1118 MDIO_REG_BANK_SERDES_DIGITAL,
1119 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1120 control2);
1121
Yaniv Rosner18afb0a2009-11-05 19:18:04 +02001122 if ((phy_flags & PHY_XGXS_FLAG) &&
1123 (params->speed_cap_mask &
1124 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001125 DP(NETIF_MSG_LINK, "XGXS\n");
1126
1127 CL45_WR_OVER_CL22(bp, params->port,
1128 params->phy_addr,
1129 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1130 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1131 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1132
1133 CL45_RD_OVER_CL22(bp, params->port,
1134 params->phy_addr,
1135 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1136 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1137 &control2);
1138
1139
1140 control2 |=
1141 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1142
1143 CL45_WR_OVER_CL22(bp, params->port,
1144 params->phy_addr,
1145 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1146 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1147 control2);
1148
1149 /* Disable parallel detection of HiG */
1150 CL45_WR_OVER_CL22(bp, params->port,
1151 params->phy_addr,
1152 MDIO_REG_BANK_XGXS_BLOCK2,
1153 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1154 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1155 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1156 }
1157}
1158
1159static void bnx2x_set_autoneg(struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001160 struct link_vars *vars,
1161 u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001162{
1163 struct bnx2x *bp = params->bp;
1164 u16 reg_val;
1165
1166 /* CL37 Autoneg */
1167
1168 CL45_RD_OVER_CL22(bp, params->port,
1169 params->phy_addr,
1170 MDIO_REG_BANK_COMBO_IEEE0,
1171 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1172
1173 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001174 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001175 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1176 else /* CL37 Autoneg Disabled */
1177 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1178 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1179
1180 CL45_WR_OVER_CL22(bp, params->port,
1181 params->phy_addr,
1182 MDIO_REG_BANK_COMBO_IEEE0,
1183 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1184
1185 /* Enable/Disable Autodetection */
1186
1187 CL45_RD_OVER_CL22(bp, params->port,
1188 params->phy_addr,
1189 MDIO_REG_BANK_SERDES_DIGITAL,
1190 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001191 reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
1192 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT);
1193 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001194 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001195 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1196 else
1197 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1198
1199 CL45_WR_OVER_CL22(bp, params->port,
1200 params->phy_addr,
1201 MDIO_REG_BANK_SERDES_DIGITAL,
1202 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1203
1204 /* Enable TetonII and BAM autoneg */
1205 CL45_RD_OVER_CL22(bp, params->port,
1206 params->phy_addr,
1207 MDIO_REG_BANK_BAM_NEXT_PAGE,
1208 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1209 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001210 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001211 /* Enable BAM aneg Mode and TetonII aneg Mode */
1212 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1213 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1214 } else {
1215 /* TetonII and BAM Autoneg Disabled */
1216 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1217 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1218 }
1219 CL45_WR_OVER_CL22(bp, params->port,
1220 params->phy_addr,
1221 MDIO_REG_BANK_BAM_NEXT_PAGE,
1222 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1223 reg_val);
1224
Eilon Greenstein239d6862009-08-12 08:23:04 +00001225 if (enable_cl73) {
1226 /* Enable Cl73 FSM status bits */
1227 CL45_WR_OVER_CL22(bp, params->port,
1228 params->phy_addr,
1229 MDIO_REG_BANK_CL73_USERB0,
1230 MDIO_CL73_USERB0_CL73_UCTRL,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001231 0xe);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001232
1233 /* Enable BAM Station Manager*/
1234 CL45_WR_OVER_CL22(bp, params->port,
1235 params->phy_addr,
1236 MDIO_REG_BANK_CL73_USERB0,
1237 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1238 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1239 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1240 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
1241
Yaniv Rosner7846e472009-11-05 19:18:07 +02001242 /* Advertise CL73 link speeds */
Eilon Greenstein239d6862009-08-12 08:23:04 +00001243 CL45_RD_OVER_CL22(bp, params->port,
1244 params->phy_addr,
1245 MDIO_REG_BANK_CL73_IEEEB1,
1246 MDIO_CL73_IEEEB1_AN_ADV2,
1247 &reg_val);
Yaniv Rosner7846e472009-11-05 19:18:07 +02001248 if (params->speed_cap_mask &
1249 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1250 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1251 if (params->speed_cap_mask &
1252 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
1253 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001254
1255 CL45_WR_OVER_CL22(bp, params->port,
1256 params->phy_addr,
1257 MDIO_REG_BANK_CL73_IEEEB1,
1258 MDIO_CL73_IEEEB1_AN_ADV2,
Yaniv Rosner7846e472009-11-05 19:18:07 +02001259 reg_val);
Eilon Greenstein239d6862009-08-12 08:23:04 +00001260
Eilon Greenstein239d6862009-08-12 08:23:04 +00001261 /* CL73 Autoneg Enabled */
1262 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1263
1264 } else /* CL73 Autoneg Disabled */
1265 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001266
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001267 CL45_WR_OVER_CL22(bp, params->port,
1268 params->phy_addr,
1269 MDIO_REG_BANK_CL73_IEEEB0,
1270 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1271}
1272
1273/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001274static void bnx2x_program_serdes(struct link_params *params,
1275 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001276{
1277 struct bnx2x *bp = params->bp;
1278 u16 reg_val;
1279
Eilon Greenstein57937202009-08-12 08:23:53 +00001280 /* program duplex, disable autoneg and sgmii*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001281 CL45_RD_OVER_CL22(bp, params->port,
1282 params->phy_addr,
1283 MDIO_REG_BANK_COMBO_IEEE0,
1284 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1285 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
Eilon Greenstein57937202009-08-12 08:23:53 +00001286 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1287 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001288 if (params->req_duplex == DUPLEX_FULL)
1289 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1290 CL45_WR_OVER_CL22(bp, params->port,
1291 params->phy_addr,
1292 MDIO_REG_BANK_COMBO_IEEE0,
1293 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1294
1295 /* program speed
1296 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001297 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001298 params->phy_addr,
1299 MDIO_REG_BANK_SERDES_DIGITAL,
1300 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001301 /* clearing the speed value before setting the right speed */
1302 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1303
1304 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1305 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1306
1307 if (!((vars->line_speed == SPEED_1000) ||
1308 (vars->line_speed == SPEED_100) ||
1309 (vars->line_speed == SPEED_10))) {
1310
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001311 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1312 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001313 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001314 reg_val |=
1315 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001316 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001317 reg_val |=
1318 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001319 }
1320
1321 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001322 params->phy_addr,
1323 MDIO_REG_BANK_SERDES_DIGITAL,
1324 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001325
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001326}
1327
1328static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1329{
1330 struct bnx2x *bp = params->bp;
1331 u16 val = 0;
1332
1333 /* configure the 48 bits for BAM AN */
1334
1335 /* set extended capabilities */
1336 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1337 val |= MDIO_OVER_1G_UP1_2_5G;
1338 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1339 val |= MDIO_OVER_1G_UP1_10G;
1340 CL45_WR_OVER_CL22(bp, params->port,
1341 params->phy_addr,
1342 MDIO_REG_BANK_OVER_1G,
1343 MDIO_OVER_1G_UP1, val);
1344
1345 CL45_WR_OVER_CL22(bp, params->port,
1346 params->phy_addr,
1347 MDIO_REG_BANK_OVER_1G,
Eilon Greenstein239d6862009-08-12 08:23:04 +00001348 MDIO_OVER_1G_UP3, 0x400);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001349}
1350
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001351static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001352{
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001353 struct bnx2x *bp = params->bp;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001354 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001355 /* resolve pause mode and advertisement
1356 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1357
1358 switch (params->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001359 case BNX2X_FLOW_CTRL_AUTO:
1360 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001361 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001362 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1363 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001364 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001365 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1366 }
1367 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001368 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001369 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001370 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1371 break;
1372
David S. Millerc0700f92008-12-16 23:53:20 -08001373 case BNX2X_FLOW_CTRL_RX:
1374 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001375 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001376 break;
1377
David S. Millerc0700f92008-12-16 23:53:20 -08001378 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001379 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001380 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001381 break;
1382 }
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02001383 DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001384}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001385
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001386static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001387 u16 ieee_fc)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001388{
1389 struct bnx2x *bp = params->bp;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001390 u16 val;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001391 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001392
1393 CL45_WR_OVER_CL22(bp, params->port,
1394 params->phy_addr,
1395 MDIO_REG_BANK_COMBO_IEEE0,
Eilon Greenstein1ef70b92009-08-12 08:23:59 +00001396 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
Yaniv Rosner7846e472009-11-05 19:18:07 +02001397 CL45_RD_OVER_CL22(bp, params->port,
1398 params->phy_addr,
1399 MDIO_REG_BANK_CL73_IEEEB1,
1400 MDIO_CL73_IEEEB1_AN_ADV1, &val);
1401 val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
1402 val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
1403 CL45_WR_OVER_CL22(bp, params->port,
1404 params->phy_addr,
1405 MDIO_REG_BANK_CL73_IEEEB1,
1406 MDIO_CL73_IEEEB1_AN_ADV1, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001407}
1408
Eilon Greenstein239d6862009-08-12 08:23:04 +00001409static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001410{
1411 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001412 u16 mii_control;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001413
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001414 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001415 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001416
Eilon Greenstein239d6862009-08-12 08:23:04 +00001417 if (enable_cl73) {
1418 CL45_RD_OVER_CL22(bp, params->port,
1419 params->phy_addr,
1420 MDIO_REG_BANK_CL73_IEEEB0,
1421 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1422 &mii_control);
1423
1424 CL45_WR_OVER_CL22(bp, params->port,
1425 params->phy_addr,
1426 MDIO_REG_BANK_CL73_IEEEB0,
1427 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1428 (mii_control |
1429 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1430 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1431 } else {
1432
1433 CL45_RD_OVER_CL22(bp, params->port,
1434 params->phy_addr,
1435 MDIO_REG_BANK_COMBO_IEEE0,
1436 MDIO_COMBO_IEEE0_MII_CONTROL,
1437 &mii_control);
1438 DP(NETIF_MSG_LINK,
1439 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1440 mii_control);
1441 CL45_WR_OVER_CL22(bp, params->port,
1442 params->phy_addr,
1443 MDIO_REG_BANK_COMBO_IEEE0,
1444 MDIO_COMBO_IEEE0_MII_CONTROL,
1445 (mii_control |
1446 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1447 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1448 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001449}
1450
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001451static void bnx2x_initialize_sgmii_process(struct link_params *params,
1452 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001453{
1454 struct bnx2x *bp = params->bp;
1455 u16 control1;
1456
1457 /* in SGMII mode, the unicore is always slave */
1458
1459 CL45_RD_OVER_CL22(bp, params->port,
1460 params->phy_addr,
1461 MDIO_REG_BANK_SERDES_DIGITAL,
1462 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1463 &control1);
1464 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1465 /* set sgmii mode (and not fiber) */
1466 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1467 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1468 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1469 CL45_WR_OVER_CL22(bp, params->port,
1470 params->phy_addr,
1471 MDIO_REG_BANK_SERDES_DIGITAL,
1472 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1473 control1);
1474
1475 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001476 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001477 /* set speed, disable autoneg */
1478 u16 mii_control;
1479
1480 CL45_RD_OVER_CL22(bp, params->port,
1481 params->phy_addr,
1482 MDIO_REG_BANK_COMBO_IEEE0,
1483 MDIO_COMBO_IEEE0_MII_CONTROL,
1484 &mii_control);
1485 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1486 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1487 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1488
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001489 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001490 case SPEED_100:
1491 mii_control |=
1492 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1493 break;
1494 case SPEED_1000:
1495 mii_control |=
1496 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1497 break;
1498 case SPEED_10:
1499 /* there is nothing to set for 10M */
1500 break;
1501 default:
1502 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001503 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1504 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001505 break;
1506 }
1507
1508 /* setting the full duplex */
1509 if (params->req_duplex == DUPLEX_FULL)
1510 mii_control |=
1511 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1512 CL45_WR_OVER_CL22(bp, params->port,
1513 params->phy_addr,
1514 MDIO_REG_BANK_COMBO_IEEE0,
1515 MDIO_COMBO_IEEE0_MII_CONTROL,
1516 mii_control);
1517
1518 } else { /* AN mode */
1519 /* enable and restart AN */
Eilon Greenstein239d6862009-08-12 08:23:04 +00001520 bnx2x_restart_autoneg(params, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001521 }
1522}
1523
1524
1525/*
1526 * link management
1527 */
1528
1529static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001530{ /* LD LP */
1531 switch (pause_result) { /* ASYM P ASYM P */
1532 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001533 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001534 break;
1535
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001536 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001537 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001538 break;
1539
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001540 case 0x5: /* 0 1 0 1 */
1541 case 0x7: /* 0 1 1 1 */
1542 case 0xd: /* 1 1 0 1 */
1543 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001544 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001545 break;
1546
1547 default:
1548 break;
1549 }
1550}
1551
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001552static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001553 struct link_vars *vars)
1554{
1555 struct bnx2x *bp = params->bp;
1556 u8 ext_phy_addr;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001557 u16 ld_pause; /* local */
1558 u16 lp_pause; /* link partner */
1559 u16 an_complete; /* AN complete */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001560 u16 pause_result;
1561 u8 ret = 0;
1562 u32 ext_phy_type;
1563 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00001564 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001565 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1566 /* read twice */
1567
1568 bnx2x_cl45_read(bp, port,
1569 ext_phy_type,
1570 ext_phy_addr,
1571 MDIO_AN_DEVAD,
1572 MDIO_AN_REG_STATUS, &an_complete);
1573 bnx2x_cl45_read(bp, port,
1574 ext_phy_type,
1575 ext_phy_addr,
1576 MDIO_AN_DEVAD,
1577 MDIO_AN_REG_STATUS, &an_complete);
1578
1579 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1580 ret = 1;
1581 bnx2x_cl45_read(bp, port,
1582 ext_phy_type,
1583 ext_phy_addr,
1584 MDIO_AN_DEVAD,
1585 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1586 bnx2x_cl45_read(bp, port,
1587 ext_phy_type,
1588 ext_phy_addr,
1589 MDIO_AN_DEVAD,
1590 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1591 pause_result = (ld_pause &
1592 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1593 pause_result |= (lp_pause &
1594 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1595 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
1596 pause_result);
1597 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001598 if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001599 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1600 bnx2x_cl45_read(bp, port,
1601 ext_phy_type,
1602 ext_phy_addr,
1603 MDIO_AN_DEVAD,
1604 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1605
1606 bnx2x_cl45_read(bp, port,
1607 ext_phy_type,
1608 ext_phy_addr,
1609 MDIO_AN_DEVAD,
1610 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1611 pause_result = (ld_pause &
1612 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1613 pause_result |= (lp_pause &
1614 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1615
1616 bnx2x_pause_resolve(vars, pause_result);
1617 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
1618 pause_result);
1619 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001620 }
1621 return ret;
1622}
1623
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001624static u8 bnx2x_direct_parallel_detect_used(struct link_params *params)
1625{
1626 struct bnx2x *bp = params->bp;
1627 u16 pd_10g, status2_1000x;
1628 CL45_RD_OVER_CL22(bp, params->port,
1629 params->phy_addr,
1630 MDIO_REG_BANK_SERDES_DIGITAL,
1631 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1632 &status2_1000x);
1633 CL45_RD_OVER_CL22(bp, params->port,
1634 params->phy_addr,
1635 MDIO_REG_BANK_SERDES_DIGITAL,
1636 MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
1637 &status2_1000x);
1638 if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
1639 DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
1640 params->port);
1641 return 1;
1642 }
1643
1644 CL45_RD_OVER_CL22(bp, params->port,
1645 params->phy_addr,
1646 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1647 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
1648 &pd_10g);
1649
1650 if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
1651 DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
1652 params->port);
1653 return 1;
1654 }
1655 return 0;
1656}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001657
1658static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1659 struct link_vars *vars,
1660 u32 gp_status)
1661{
1662 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001663 u16 ld_pause; /* local driver */
1664 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001665 u16 pause_result;
1666
David S. Millerc0700f92008-12-16 23:53:20 -08001667 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001668
1669 /* resolve from gp_status in case of AN complete and not sgmii */
David S. Millerc0700f92008-12-16 23:53:20 -08001670 if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001671 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1672 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1673 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1674 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
Yaniv Rosner15ddd2d2009-11-05 19:18:12 +02001675 if (bnx2x_direct_parallel_detect_used(params)) {
1676 vars->flow_ctrl = params->req_fc_auto_adv;
1677 return;
1678 }
Yaniv Rosner7846e472009-11-05 19:18:07 +02001679 if ((gp_status &
1680 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1681 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
1682 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
1683 MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
1684
1685 CL45_RD_OVER_CL22(bp, params->port,
1686 params->phy_addr,
1687 MDIO_REG_BANK_CL73_IEEEB1,
1688 MDIO_CL73_IEEEB1_AN_ADV1,
1689 &ld_pause);
1690 CL45_RD_OVER_CL22(bp, params->port,
1691 params->phy_addr,
1692 MDIO_REG_BANK_CL73_IEEEB1,
1693 MDIO_CL73_IEEEB1_AN_LP_ADV1,
1694 &lp_pause);
1695 pause_result = (ld_pause &
1696 MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
1697 >> 8;
1698 pause_result |= (lp_pause &
1699 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
1700 >> 10;
1701 DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
1702 pause_result);
1703 } else {
1704
1705 CL45_RD_OVER_CL22(bp, params->port,
1706 params->phy_addr,
1707 MDIO_REG_BANK_COMBO_IEEE0,
1708 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1709 &ld_pause);
1710 CL45_RD_OVER_CL22(bp, params->port,
1711 params->phy_addr,
1712 MDIO_REG_BANK_COMBO_IEEE0,
1713 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1714 &lp_pause);
1715 pause_result = (ld_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001716 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001717 pause_result |= (lp_pause &
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001718 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
Yaniv Rosner7846e472009-11-05 19:18:07 +02001719 DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
1720 pause_result);
1721 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001722 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001723 } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001724 (bnx2x_ext_phy_resolve_fc(params, vars))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001725 return;
1726 } else {
David S. Millerc0700f92008-12-16 23:53:20 -08001727 if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001728 vars->flow_ctrl = params->req_fc_auto_adv;
1729 else
1730 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001731 }
1732 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1733}
1734
Eilon Greenstein239d6862009-08-12 08:23:04 +00001735static void bnx2x_check_fallback_to_cl37(struct link_params *params)
1736{
1737 struct bnx2x *bp = params->bp;
1738 u16 rx_status, ustat_val, cl37_fsm_recieved;
1739 DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
1740 /* Step 1: Make sure signal is detected */
1741 CL45_RD_OVER_CL22(bp, params->port,
1742 params->phy_addr,
1743 MDIO_REG_BANK_RX0,
1744 MDIO_RX0_RX_STATUS,
1745 &rx_status);
1746 if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
1747 (MDIO_RX0_RX_STATUS_SIGDET)) {
1748 DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
1749 "rx_status(0x80b0) = 0x%x\n", rx_status);
1750 CL45_WR_OVER_CL22(bp, params->port,
1751 params->phy_addr,
1752 MDIO_REG_BANK_CL73_IEEEB0,
1753 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1754 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
1755 return;
1756 }
1757 /* Step 2: Check CL73 state machine */
1758 CL45_RD_OVER_CL22(bp, params->port,
1759 params->phy_addr,
1760 MDIO_REG_BANK_CL73_USERB0,
1761 MDIO_CL73_USERB0_CL73_USTAT1,
1762 &ustat_val);
1763 if ((ustat_val &
1764 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1765 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
1766 (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
1767 MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
1768 DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. "
1769 "ustat_val(0x8371) = 0x%x\n", ustat_val);
1770 return;
1771 }
1772 /* Step 3: Check CL37 Message Pages received to indicate LP
1773 supports only CL37 */
1774 CL45_RD_OVER_CL22(bp, params->port,
1775 params->phy_addr,
1776 MDIO_REG_BANK_REMOTE_PHY,
1777 MDIO_REMOTE_PHY_MISC_RX_STATUS,
1778 &cl37_fsm_recieved);
1779 if ((cl37_fsm_recieved &
1780 (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
1781 MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
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 DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
1785 "misc_rx_status(0x8330) = 0x%x\n",
1786 cl37_fsm_recieved);
1787 return;
1788 }
1789 /* The combined cl37/cl73 fsm state information indicating that we are
1790 connected to a device which does not support cl73, but does support
1791 cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
1792 /* Disable CL73 */
1793 CL45_WR_OVER_CL22(bp, params->port,
1794 params->phy_addr,
1795 MDIO_REG_BANK_CL73_IEEEB0,
1796 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1797 0);
1798 /* Restart CL37 autoneg */
1799 bnx2x_restart_autoneg(params, 0);
1800 DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
1801}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001802static u8 bnx2x_link_settings_status(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00001803 struct link_vars *vars,
1804 u32 gp_status,
1805 u8 ext_phy_link_up)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001806{
1807 struct bnx2x *bp = params->bp;
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001808 u16 new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001809 u8 rc = 0;
1810 vars->link_status = 0;
1811
1812 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1813 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1814 gp_status);
1815
1816 vars->phy_link_up = 1;
1817 vars->link_status |= LINK_STATUS_LINK_UP;
1818
1819 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1820 vars->duplex = DUPLEX_FULL;
1821 else
1822 vars->duplex = DUPLEX_HALF;
1823
1824 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1825
1826 switch (gp_status & GP_STATUS_SPEED_MASK) {
1827 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001828 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001829 if (vars->duplex == DUPLEX_FULL)
1830 vars->link_status |= LINK_10TFD;
1831 else
1832 vars->link_status |= LINK_10THD;
1833 break;
1834
1835 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001836 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001837 if (vars->duplex == DUPLEX_FULL)
1838 vars->link_status |= LINK_100TXFD;
1839 else
1840 vars->link_status |= LINK_100TXHD;
1841 break;
1842
1843 case GP_STATUS_1G:
1844 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001845 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001846 if (vars->duplex == DUPLEX_FULL)
1847 vars->link_status |= LINK_1000TFD;
1848 else
1849 vars->link_status |= LINK_1000THD;
1850 break;
1851
1852 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001853 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001854 if (vars->duplex == DUPLEX_FULL)
1855 vars->link_status |= LINK_2500TFD;
1856 else
1857 vars->link_status |= LINK_2500THD;
1858 break;
1859
1860 case GP_STATUS_5G:
1861 case GP_STATUS_6G:
1862 DP(NETIF_MSG_LINK,
1863 "link speed unsupported gp_status 0x%x\n",
1864 gp_status);
1865 return -EINVAL;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001866
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001867 case GP_STATUS_10G_KX4:
1868 case GP_STATUS_10G_HIG:
1869 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001870 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001871 vars->link_status |= LINK_10GTFD;
1872 break;
1873
1874 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001875 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001876 vars->link_status |= LINK_12GTFD;
1877 break;
1878
1879 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001880 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001881 vars->link_status |= LINK_12_5GTFD;
1882 break;
1883
1884 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001885 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001886 vars->link_status |= LINK_13GTFD;
1887 break;
1888
1889 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001890 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001891 vars->link_status |= LINK_15GTFD;
1892 break;
1893
1894 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001895 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001896 vars->link_status |= LINK_16GTFD;
1897 break;
1898
1899 default:
1900 DP(NETIF_MSG_LINK,
1901 "link speed unsupported gp_status 0x%x\n",
1902 gp_status);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00001903 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001904 }
1905
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001906 /* Upon link speed change set the NIG into drain mode.
1907 Comes to deals with possible FIFO glitch due to clk change
1908 when speed is decreased without link down indicator */
1909 if (new_line_speed != vars->line_speed) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00001910 if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) !=
1911 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT &&
1912 ext_phy_link_up) {
1913 DP(NETIF_MSG_LINK, "Internal link speed %d is"
1914 " different than the external"
1915 " link speed %d\n", new_line_speed,
1916 vars->line_speed);
1917 vars->phy_link_up = 0;
1918 return 0;
1919 }
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001920 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
1921 + params->port*4, 0);
1922 msleep(1);
1923 }
1924 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001925 vars->link_status |= LINK_STATUS_SERDES_LINK;
1926
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001927 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1928 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1929 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1930 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein589abe32009-02-12 08:36:55 +00001931 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
1932 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02001933 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
1934 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein2f904462009-08-12 08:22:16 +00001935 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001936 vars->autoneg = AUTO_NEG_ENABLED;
1937
1938 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1939 vars->autoneg |= AUTO_NEG_COMPLETE;
1940 vars->link_status |=
1941 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1942 }
1943
1944 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1945 vars->link_status |=
1946 LINK_STATUS_PARALLEL_DETECTION_USED;
1947
1948 }
David S. Millerc0700f92008-12-16 23:53:20 -08001949 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001950 vars->link_status |=
1951 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001952
David S. Millerc0700f92008-12-16 23:53:20 -08001953 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001954 vars->link_status |=
1955 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001956
1957 } else { /* link_down */
1958 DP(NETIF_MSG_LINK, "phy link down\n");
1959
1960 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001961
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001962 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001963 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001964 vars->autoneg = AUTO_NEG_DISABLED;
1965 vars->mac_type = MAC_TYPE_NONE;
Eilon Greenstein239d6862009-08-12 08:23:04 +00001966
1967 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1968 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1969 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT))) {
1970 /* Check signal is detected */
1971 bnx2x_check_fallback_to_cl37(params);
1972 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001973 }
1974
1975 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n",
1976 gp_status, vars->phy_link_up, vars->line_speed);
1977 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1978 " autoneg 0x%x\n",
1979 vars->duplex,
1980 vars->flow_ctrl, vars->autoneg);
1981 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1982
1983 return rc;
1984}
1985
Eilon Greensteined8680a2009-02-12 08:37:12 +00001986static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001987{
1988 struct bnx2x *bp = params->bp;
1989 u16 lp_up2;
1990 u16 tx_driver;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001991 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001992
1993 /* read precomp */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001994 CL45_RD_OVER_CL22(bp, params->port,
1995 params->phy_addr,
1996 MDIO_REG_BANK_OVER_1G,
1997 MDIO_OVER_1G_LP_UP2, &lp_up2);
1998
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001999 /* bits [10:7] at lp_up2, positioned at [15:12] */
2000 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
2001 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
2002 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
2003
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002004 if (lp_up2 == 0)
2005 return;
2006
2007 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
2008 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
2009 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002010 params->phy_addr,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002011 bank,
2012 MDIO_TX0_TX_DRIVER, &tx_driver);
2013
2014 /* replace tx_driver bits [15:12] */
2015 if (lp_up2 !=
2016 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
2017 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
2018 tx_driver |= lp_up2;
2019 CL45_WR_OVER_CL22(bp, params->port,
2020 params->phy_addr,
2021 bank,
2022 MDIO_TX0_TX_DRIVER, tx_driver);
2023 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002024 }
2025}
2026
2027static u8 bnx2x_emac_program(struct link_params *params,
2028 u32 line_speed, u32 duplex)
2029{
2030 struct bnx2x *bp = params->bp;
2031 u8 port = params->port;
2032 u16 mode = 0;
2033
2034 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
2035 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
2036 EMAC_REG_EMAC_MODE,
2037 (EMAC_MODE_25G_MODE |
2038 EMAC_MODE_PORT_MII_10M |
2039 EMAC_MODE_HALF_DUPLEX));
2040 switch (line_speed) {
2041 case SPEED_10:
2042 mode |= EMAC_MODE_PORT_MII_10M;
2043 break;
2044
2045 case SPEED_100:
2046 mode |= EMAC_MODE_PORT_MII;
2047 break;
2048
2049 case SPEED_1000:
2050 mode |= EMAC_MODE_PORT_GMII;
2051 break;
2052
2053 case SPEED_2500:
2054 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
2055 break;
2056
2057 default:
2058 /* 10G not valid for EMAC */
2059 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
2060 return -EINVAL;
2061 }
2062
2063 if (duplex == DUPLEX_HALF)
2064 mode |= EMAC_MODE_HALF_DUPLEX;
2065 bnx2x_bits_en(bp,
2066 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
2067 mode);
2068
Yaniv Rosner7846e472009-11-05 19:18:07 +02002069 bnx2x_set_led(params, LED_MODE_OPER, line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002070 return 0;
2071}
2072
2073/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002074/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002075/*****************************************************************************/
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002076void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002077{
2078 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002079 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002080 msleep(1);
2081 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002082 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002083}
2084
2085static void bnx2x_ext_phy_reset(struct link_params *params,
2086 struct link_vars *vars)
2087{
2088 struct bnx2x *bp = params->bp;
2089 u32 ext_phy_type;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002090 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
2091
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002092 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
2093 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2094 /* The PHY reset is controled by GPIO 1
2095 * Give it 1ms of reset pulse
2096 */
2097 if (vars->phy_flags & PHY_XGXS_FLAG) {
2098
2099 switch (ext_phy_type) {
2100 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
2101 DP(NETIF_MSG_LINK, "XGXS Direct\n");
2102 break;
2103
2104 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2105 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2106 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
2107
2108 /* Restore normal power mode*/
2109 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002110 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2111 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002112
2113 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002114 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002115
2116 bnx2x_cl45_write(bp, params->port,
2117 ext_phy_type,
2118 ext_phy_addr,
2119 MDIO_PMA_DEVAD,
2120 MDIO_PMA_REG_CTRL, 0xa040);
2121 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002122
2123 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
2124 break;
2125
Eilon Greenstein589abe32009-02-12 08:36:55 +00002126 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
2127
2128 /* Restore normal power mode*/
2129 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2130 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2131 params->port);
2132
2133 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
2134 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2135 params->port);
2136
2137 bnx2x_cl45_write(bp, params->port,
2138 ext_phy_type,
2139 ext_phy_addr,
2140 MDIO_PMA_DEVAD,
2141 MDIO_PMA_REG_CTRL,
2142 1<<15);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002143 break;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002144
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002145 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002146 DP(NETIF_MSG_LINK, "XGXS 8072\n");
2147
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002148 /* Unset Low Power Mode and SW reset */
2149 /* Restore normal power mode*/
2150 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002151 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2152 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002153
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002154 bnx2x_cl45_write(bp, params->port,
2155 ext_phy_type,
2156 ext_phy_addr,
2157 MDIO_PMA_DEVAD,
2158 MDIO_PMA_REG_CTRL,
2159 1<<15);
2160 break;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002161
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002162 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002163 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002164
2165 /* Restore normal power mode*/
2166 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002167 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2168 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002169
2170 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002171 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2172 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002173 break;
2174
2175 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
2176 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
2177
2178 /* Restore normal power mode*/
2179 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002180 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2181 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002182
2183 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002184 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002185 break;
2186
Eilon Greenstein28577182009-02-12 08:37:00 +00002187 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Eilon Greenstein28577182009-02-12 08:37:00 +00002188 /* Restore normal power mode*/
2189 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2190 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2191 params->port);
2192
2193 /* HW reset */
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002194 bnx2x_ext_phy_hw_reset(bp, params->port);
Eilon Greenstein28577182009-02-12 08:37:00 +00002195
2196 bnx2x_cl45_write(bp, params->port,
2197 ext_phy_type,
2198 ext_phy_addr,
2199 MDIO_PMA_DEVAD,
2200 MDIO_PMA_REG_CTRL,
2201 1<<15);
2202 break;
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02002203 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
2204 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002205 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
2206 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
2207 break;
2208
2209 default:
2210 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
2211 params->ext_phy_config);
2212 break;
2213 }
2214
2215 } else { /* SerDes */
2216 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
2217 switch (ext_phy_type) {
2218 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
2219 DP(NETIF_MSG_LINK, "SerDes Direct\n");
2220 break;
2221
2222 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
2223 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greensteinf57a6022009-08-12 08:23:11 +00002224 bnx2x_ext_phy_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002225 break;
2226
2227 default:
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002228 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002229 params->ext_phy_config);
2230 break;
2231 }
2232 }
2233}
2234
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002235static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
2236 u32 shmem_base, u32 spirom_ver)
2237{
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002238 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
2239 (u16)(spirom_ver>>16), (u16)spirom_ver, port);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002240 REG_WR(bp, shmem_base +
2241 offsetof(struct shmem_region,
2242 port_mb[port].ext_phy_fw_version),
2243 spirom_ver);
2244}
2245
2246static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
2247 u32 ext_phy_type, u8 ext_phy_addr,
2248 u32 shmem_base)
2249{
2250 u16 fw_ver1, fw_ver2;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002251
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002252 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2253 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2254 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2255 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2256 bnx2x_save_spirom_version(bp, port, shmem_base,
2257 (u32)(fw_ver1<<16 | fw_ver2));
2258}
2259
Eilon Greensteinb1607af2009-08-12 08:22:54 +00002260
2261static void bnx2x_save_8481_spirom_version(struct bnx2x *bp, u8 port,
2262 u8 ext_phy_addr, u32 shmem_base)
2263{
2264 u16 val, fw_ver1, fw_ver2, cnt;
2265 /* For the 32 bits registers in 8481, access via MDIO2ARM interface.*/
2266 /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
2267 bnx2x_cl45_write(bp, port,
2268 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2269 ext_phy_addr, MDIO_PMA_DEVAD,
2270 0xA819, 0x0014);
2271 bnx2x_cl45_write(bp, port,
2272 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2273 ext_phy_addr,
2274 MDIO_PMA_DEVAD,
2275 0xA81A,
2276 0xc200);
2277 bnx2x_cl45_write(bp, port,
2278 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2279 ext_phy_addr,
2280 MDIO_PMA_DEVAD,
2281 0xA81B,
2282 0x0000);
2283 bnx2x_cl45_write(bp, port,
2284 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2285 ext_phy_addr,
2286 MDIO_PMA_DEVAD,
2287 0xA81C,
2288 0x0300);
2289 bnx2x_cl45_write(bp, port,
2290 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2291 ext_phy_addr,
2292 MDIO_PMA_DEVAD,
2293 0xA817,
2294 0x0009);
2295
2296 for (cnt = 0; cnt < 100; cnt++) {
2297 bnx2x_cl45_read(bp, port,
2298 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2299 ext_phy_addr,
2300 MDIO_PMA_DEVAD,
2301 0xA818,
2302 &val);
2303 if (val & 1)
2304 break;
2305 udelay(5);
2306 }
2307 if (cnt == 100) {
2308 DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n");
2309 bnx2x_save_spirom_version(bp, port,
2310 shmem_base, 0);
2311 return;
2312 }
2313
2314
2315 /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
2316 bnx2x_cl45_write(bp, port,
2317 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2318 ext_phy_addr, MDIO_PMA_DEVAD,
2319 0xA819, 0x0000);
2320 bnx2x_cl45_write(bp, port,
2321 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2322 ext_phy_addr, MDIO_PMA_DEVAD,
2323 0xA81A, 0xc200);
2324 bnx2x_cl45_write(bp, port,
2325 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2326 ext_phy_addr, MDIO_PMA_DEVAD,
2327 0xA817, 0x000A);
2328 for (cnt = 0; cnt < 100; cnt++) {
2329 bnx2x_cl45_read(bp, port,
2330 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2331 ext_phy_addr,
2332 MDIO_PMA_DEVAD,
2333 0xA818,
2334 &val);
2335 if (val & 1)
2336 break;
2337 udelay(5);
2338 }
2339 if (cnt == 100) {
2340 DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(2)\n");
2341 bnx2x_save_spirom_version(bp, port,
2342 shmem_base, 0);
2343 return;
2344 }
2345
2346 /* lower 16 bits of the register SPI_FW_STATUS */
2347 bnx2x_cl45_read(bp, port,
2348 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2349 ext_phy_addr,
2350 MDIO_PMA_DEVAD,
2351 0xA81B,
2352 &fw_ver1);
2353 /* upper 16 bits of register SPI_FW_STATUS */
2354 bnx2x_cl45_read(bp, port,
2355 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
2356 ext_phy_addr,
2357 MDIO_PMA_DEVAD,
2358 0xA81C,
2359 &fw_ver2);
2360
2361 bnx2x_save_spirom_version(bp, port,
2362 shmem_base, (fw_ver2<<16) | fw_ver1);
2363}
2364
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002365static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
2366{
2367 struct bnx2x *bp = params->bp;
2368 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002369 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002370 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002371
2372 /* Need to wait 200ms after reset */
2373 msleep(200);
2374 /* Boot port from external ROM
2375 * Set ser_boot_ctl bit in the MISC_CTRL1 register
2376 */
2377 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2378 MDIO_PMA_DEVAD,
2379 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2380
2381 /* Reset internal microprocessor */
2382 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2383 MDIO_PMA_DEVAD,
2384 MDIO_PMA_REG_GEN_CTRL,
2385 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2386 /* set micro reset = 0 */
2387 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2388 MDIO_PMA_DEVAD,
2389 MDIO_PMA_REG_GEN_CTRL,
2390 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2391 /* Reset internal microprocessor */
2392 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2393 MDIO_PMA_DEVAD,
2394 MDIO_PMA_REG_GEN_CTRL,
2395 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2396 /* wait for 100ms for code download via SPI port */
2397 msleep(100);
2398
2399 /* Clear ser_boot_ctl bit */
2400 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2401 MDIO_PMA_DEVAD,
2402 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2403 /* Wait 100ms */
2404 msleep(100);
2405
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002406 bnx2x_save_bcm_spirom_ver(bp, port,
2407 ext_phy_type,
2408 ext_phy_addr,
2409 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002410}
2411
2412static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2413{
2414 /* This is only required for 8073A1, version 102 only */
2415
2416 struct bnx2x *bp = params->bp;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002417 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002418 u16 val;
2419
2420 /* Read 8073 HW revision*/
2421 bnx2x_cl45_read(bp, params->port,
2422 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2423 ext_phy_addr,
2424 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002425 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002426
2427 if (val != 1) {
2428 /* No need to workaround in 8073 A1 */
2429 return 0;
2430 }
2431
2432 bnx2x_cl45_read(bp, params->port,
2433 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2434 ext_phy_addr,
2435 MDIO_PMA_DEVAD,
2436 MDIO_PMA_REG_ROM_VER2, &val);
2437
2438 /* SNR should be applied only for version 0x102 */
2439 if (val != 0x102)
2440 return 0;
2441
2442 return 1;
2443}
2444
2445static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2446{
2447 struct bnx2x *bp = params->bp;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002448 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002449 u16 val, cnt, cnt1 ;
2450
2451 bnx2x_cl45_read(bp, params->port,
2452 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2453 ext_phy_addr,
2454 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002455 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002456
2457 if (val > 0) {
2458 /* No need to workaround in 8073 A1 */
2459 return 0;
2460 }
2461 /* XAUI workaround in 8073 A0: */
2462
2463 /* After loading the boot ROM and restarting Autoneg,
2464 poll Dev1, Reg $C820: */
2465
2466 for (cnt = 0; cnt < 1000; cnt++) {
2467 bnx2x_cl45_read(bp, params->port,
2468 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2469 ext_phy_addr,
2470 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002471 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
2472 &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002473 /* If bit [14] = 0 or bit [13] = 0, continue on with
2474 system initialization (XAUI work-around not required,
2475 as these bits indicate 2.5G or 1G link up). */
2476 if (!(val & (1<<14)) || !(val & (1<<13))) {
2477 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2478 return 0;
2479 } else if (!(val & (1<<15))) {
2480 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2481 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2482 it's MSB (bit 15) goes to 1 (indicating that the
2483 XAUI workaround has completed),
2484 then continue on with system initialization.*/
2485 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2486 bnx2x_cl45_read(bp, params->port,
2487 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2488 ext_phy_addr,
2489 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002490 MDIO_PMA_REG_8073_XAUI_WA, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002491 if (val & (1<<15)) {
2492 DP(NETIF_MSG_LINK,
2493 "XAUI workaround has completed\n");
2494 return 0;
2495 }
2496 msleep(3);
2497 }
2498 break;
2499 }
2500 msleep(3);
2501 }
2502 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2503 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002504}
2505
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002506static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
2507 u8 ext_phy_addr,
2508 u32 ext_phy_type,
2509 u32 shmem_base)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002510{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002511 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002512 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002513 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002514 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002515 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002516 MDIO_PMA_DEVAD,
2517 MDIO_PMA_REG_GEN_CTRL,
2518 0x0001);
2519
2520 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002521 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002522 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002523 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002524 MDIO_PMA_DEVAD,
2525 MDIO_PMA_REG_GEN_CTRL,
2526 0x008c);
2527
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002528 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002529 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002530 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002531 MDIO_PMA_DEVAD,
2532 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2533
2534 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002535 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002536 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002537 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002538 MDIO_PMA_DEVAD,
2539 MDIO_PMA_REG_GEN_CTRL,
2540 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2541
2542 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002543 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002544 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002545 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002546 MDIO_PMA_DEVAD,
2547 MDIO_PMA_REG_GEN_CTRL,
2548 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2549
2550 /* wait for 100ms for code download via SPI port */
2551 msleep(100);
2552
2553 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002554 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002555 ext_phy_type,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002556 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002557 MDIO_PMA_DEVAD,
2558 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2559
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002560 bnx2x_save_bcm_spirom_ver(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002561 ext_phy_type,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002562 ext_phy_addr,
2563 shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002564}
2565
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002566static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
2567 u8 ext_phy_addr,
2568 u32 shmem_base)
2569{
2570 bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
2571 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2572 shmem_base);
2573}
2574
2575static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
2576 u8 ext_phy_addr,
2577 u32 shmem_base)
2578{
2579 bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
2580 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
2581 shmem_base);
2582
2583}
2584
Eilon Greenstein589abe32009-02-12 08:36:55 +00002585static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
2586{
2587 struct bnx2x *bp = params->bp;
2588 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002589 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002590 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2591
2592 /* Need to wait 100ms after reset */
2593 msleep(100);
2594
2595 /* Set serial boot control for external load */
2596 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2597 MDIO_PMA_DEVAD,
2598 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2599
2600 /* Micro controller re-boot */
2601 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2602 MDIO_PMA_DEVAD,
2603 MDIO_PMA_REG_GEN_CTRL,
2604 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2605
2606 /* Set soft reset */
2607 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2608 MDIO_PMA_DEVAD,
2609 MDIO_PMA_REG_GEN_CTRL,
2610 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2611
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002612 /* Set PLL register value to be same like in P13 ver */
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002613 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2614 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002615 MDIO_PMA_REG_PLL_CTRL,
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002616 0x73A0);
2617
Eilon Greenstein589abe32009-02-12 08:36:55 +00002618 /* Clear soft reset.
2619 Will automatically reset micro-controller re-boot */
2620 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2621 MDIO_PMA_DEVAD,
2622 MDIO_PMA_REG_GEN_CTRL,
2623 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2624
Eilon Greensteincc1cb002009-03-02 08:00:03 +00002625 /* wait for 150ms for microcode load */
2626 msleep(150);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002627
2628 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
2629 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2630 MDIO_PMA_DEVAD,
2631 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2632
2633 msleep(200);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002634 bnx2x_save_bcm_spirom_ver(bp, port,
2635 ext_phy_type,
2636 ext_phy_addr,
2637 params->shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002638}
2639
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002640static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
2641 u32 ext_phy_type, u8 ext_phy_addr,
2642 u8 tx_en)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002643{
2644 u16 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002645
Eilon Greenstein589abe32009-02-12 08:36:55 +00002646 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2647 tx_en, port);
2648 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
2649 bnx2x_cl45_read(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002650 ext_phy_type,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002651 ext_phy_addr,
2652 MDIO_PMA_DEVAD,
2653 MDIO_PMA_REG_PHY_IDENTIFIER,
2654 &val);
2655
2656 if (tx_en)
2657 val &= ~(1<<15);
2658 else
2659 val |= (1<<15);
2660
2661 bnx2x_cl45_write(bp, port,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002662 ext_phy_type,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002663 ext_phy_addr,
2664 MDIO_PMA_DEVAD,
2665 MDIO_PMA_REG_PHY_IDENTIFIER,
2666 val);
2667}
2668
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002669static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
2670 u16 addr, u8 byte_cnt, u8 *o_buf)
2671{
Eilon Greenstein589abe32009-02-12 08:36:55 +00002672 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002673 u16 val = 0;
2674 u16 i;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002675 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002676 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002677 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002678
Eilon Greenstein589abe32009-02-12 08:36:55 +00002679 if (byte_cnt > 16) {
2680 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2681 " is limited to 0xf\n");
2682 return -EINVAL;
2683 }
2684 /* Set the read command byte count */
2685 bnx2x_cl45_write(bp, port,
2686 ext_phy_type,
2687 ext_phy_addr,
2688 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002689 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002690 (byte_cnt | 0xa000));
2691
2692 /* Set the read command address */
2693 bnx2x_cl45_write(bp, port,
2694 ext_phy_type,
2695 ext_phy_addr,
2696 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002697 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002698 addr);
2699
2700 /* Activate read command */
2701 bnx2x_cl45_write(bp, port,
2702 ext_phy_type,
2703 ext_phy_addr,
2704 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002705 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
Eilon Greenstein589abe32009-02-12 08:36:55 +00002706 0x2c0f);
2707
2708 /* Wait up to 500us for command complete status */
2709 for (i = 0; i < 100; i++) {
2710 bnx2x_cl45_read(bp, port,
2711 ext_phy_type,
2712 ext_phy_addr,
2713 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002714 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2715 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2716 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002717 break;
2718 udelay(5);
2719 }
2720
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002721 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2722 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002723 DP(NETIF_MSG_LINK,
2724 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002725 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
Eilon Greenstein589abe32009-02-12 08:36:55 +00002726 return -EINVAL;
2727 }
2728
2729 /* Read the buffer */
2730 for (i = 0; i < byte_cnt; i++) {
2731 bnx2x_cl45_read(bp, port,
2732 ext_phy_type,
2733 ext_phy_addr,
2734 MDIO_PMA_DEVAD,
2735 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2736 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2737 }
2738
2739 for (i = 0; i < 100; i++) {
2740 bnx2x_cl45_read(bp, port,
2741 ext_phy_type,
2742 ext_phy_addr,
2743 MDIO_PMA_DEVAD,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002744 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2745 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2746 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002747 return 0;;
2748 msleep(1);
2749 }
2750 return -EINVAL;
2751}
2752
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002753static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
2754 u16 addr, u8 byte_cnt, u8 *o_buf)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002755{
2756 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002757 u16 val, i;
2758 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00002759 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002760 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2761
2762 if (byte_cnt > 16) {
2763 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2764 " is limited to 0xf\n");
2765 return -EINVAL;
2766 }
2767
2768 /* Need to read from 1.8000 to clear it */
2769 bnx2x_cl45_read(bp, port,
2770 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
2771 ext_phy_addr,
2772 MDIO_PMA_DEVAD,
2773 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2774 &val);
2775
2776 /* Set the read command byte count */
2777 bnx2x_cl45_write(bp, port,
2778 ext_phy_type,
2779 ext_phy_addr,
2780 MDIO_PMA_DEVAD,
2781 MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
2782 ((byte_cnt < 2) ? 2 : byte_cnt));
2783
2784 /* Set the read command address */
2785 bnx2x_cl45_write(bp, port,
2786 ext_phy_type,
2787 ext_phy_addr,
2788 MDIO_PMA_DEVAD,
2789 MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
2790 addr);
2791 /* Set the destination address */
2792 bnx2x_cl45_write(bp, port,
2793 ext_phy_type,
2794 ext_phy_addr,
2795 MDIO_PMA_DEVAD,
2796 0x8004,
2797 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
2798
2799 /* Activate read command */
2800 bnx2x_cl45_write(bp, port,
2801 ext_phy_type,
2802 ext_phy_addr,
2803 MDIO_PMA_DEVAD,
2804 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
2805 0x8002);
2806 /* Wait appropriate time for two-wire command to finish before
2807 polling the status register */
2808 msleep(1);
2809
2810 /* Wait up to 500us for command complete status */
2811 for (i = 0; i < 100; i++) {
2812 bnx2x_cl45_read(bp, port,
2813 ext_phy_type,
2814 ext_phy_addr,
2815 MDIO_PMA_DEVAD,
2816 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2817 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2818 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
2819 break;
2820 udelay(5);
2821 }
2822
2823 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
2824 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
2825 DP(NETIF_MSG_LINK,
2826 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2827 (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
2828 return -EINVAL;
2829 }
2830
2831 /* Read the buffer */
2832 for (i = 0; i < byte_cnt; i++) {
2833 bnx2x_cl45_read(bp, port,
2834 ext_phy_type,
2835 ext_phy_addr,
2836 MDIO_PMA_DEVAD,
2837 MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
2838 o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
2839 }
2840
2841 for (i = 0; i < 100; i++) {
2842 bnx2x_cl45_read(bp, port,
2843 ext_phy_type,
2844 ext_phy_addr,
2845 MDIO_PMA_DEVAD,
2846 MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
2847 if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
2848 MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
2849 return 0;;
2850 msleep(1);
2851 }
2852
2853 return -EINVAL;
2854}
2855
2856u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
2857 u8 byte_cnt, u8 *o_buf)
2858{
2859 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2860
2861 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
2862 return bnx2x_8726_read_sfp_module_eeprom(params, addr,
2863 byte_cnt, o_buf);
2864 else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
2865 return bnx2x_8727_read_sfp_module_eeprom(params, addr,
2866 byte_cnt, o_buf);
2867 return -EINVAL;
2868}
2869
2870static u8 bnx2x_get_edc_mode(struct link_params *params,
2871 u16 *edc_mode)
2872{
2873 struct bnx2x *bp = params->bp;
2874 u8 val, check_limiting_mode = 0;
2875 *edc_mode = EDC_MODE_LIMITING;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002876
2877 /* First check for copper cable */
2878 if (bnx2x_read_sfp_module_eeprom(params,
2879 SFP_EEPROM_CON_TYPE_ADDR,
2880 1,
2881 &val) != 0) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002882 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002883 return -EINVAL;
2884 }
2885
2886 switch (val) {
2887 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2888 {
2889 u8 copper_module_type;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00002890
Eilon Greenstein589abe32009-02-12 08:36:55 +00002891 /* Check if its active cable( includes SFP+ module)
2892 of passive cable*/
2893 if (bnx2x_read_sfp_module_eeprom(params,
2894 SFP_EEPROM_FC_TX_TECH_ADDR,
2895 1,
2896 &copper_module_type) !=
2897 0) {
2898 DP(NETIF_MSG_LINK,
2899 "Failed to read copper-cable-type"
2900 " from SFP+ EEPROM\n");
2901 return -EINVAL;
2902 }
2903
2904 if (copper_module_type &
2905 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2906 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002907 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002908 } else if (copper_module_type &
2909 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2910 DP(NETIF_MSG_LINK, "Passive Copper"
2911 " cable detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002912 *edc_mode =
2913 EDC_MODE_PASSIVE_DAC;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002914 } else {
2915 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2916 "type 0x%x !!!\n", copper_module_type);
2917 return -EINVAL;
2918 }
2919 break;
2920 }
2921 case SFP_EEPROM_CON_TYPE_VAL_LC:
2922 DP(NETIF_MSG_LINK, "Optic module detected\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002923 check_limiting_mode = 1;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002924 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00002925 default:
2926 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2927 val);
2928 return -EINVAL;
2929 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002930
2931 if (check_limiting_mode) {
2932 u8 options[SFP_EEPROM_OPTIONS_SIZE];
2933 if (bnx2x_read_sfp_module_eeprom(params,
2934 SFP_EEPROM_OPTIONS_ADDR,
2935 SFP_EEPROM_OPTIONS_SIZE,
2936 options) != 0) {
2937 DP(NETIF_MSG_LINK, "Failed to read Option"
2938 " field from module EEPROM\n");
2939 return -EINVAL;
2940 }
2941 if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
2942 *edc_mode = EDC_MODE_LINEAR;
2943 else
2944 *edc_mode = EDC_MODE_LIMITING;
2945 }
2946 DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002947 return 0;
2948}
2949
Eilon Greenstein589abe32009-02-12 08:36:55 +00002950/* This function read the relevant field from the module ( SFP+ ),
2951 and verify it is compliant with this board */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002952static u8 bnx2x_verify_sfp_module(struct link_params *params)
Eilon Greenstein589abe32009-02-12 08:36:55 +00002953{
2954 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002955 u32 val;
2956 u32 fw_resp;
2957 char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
2958 char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
Eilon Greenstein589abe32009-02-12 08:36:55 +00002959
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002960 val = REG_RD(bp, params->shmem_base +
2961 offsetof(struct shmem_region, dev_info.
2962 port_feature_config[params->port].config));
2963 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
2964 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00002965 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2966 return 0;
2967 }
2968
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002969 /* Ask the FW to validate the module */
2970 if (!(params->feature_config_flags &
2971 FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
2972 DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
2973 "verification\n");
2974 return -EINVAL;
2975 }
2976
2977 fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
2978 if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
2979 DP(NETIF_MSG_LINK, "Approved module\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00002980 return 0;
2981 }
2982
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002983 /* format the warning message */
Eilon Greenstein589abe32009-02-12 08:36:55 +00002984 if (bnx2x_read_sfp_module_eeprom(params,
2985 SFP_EEPROM_VENDOR_NAME_ADDR,
2986 SFP_EEPROM_VENDOR_NAME_SIZE,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002987 (u8 *)vendor_name))
2988 vendor_name[0] = '\0';
2989 else
2990 vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
2991 if (bnx2x_read_sfp_module_eeprom(params,
2992 SFP_EEPROM_PART_NO_ADDR,
2993 SFP_EEPROM_PART_NO_SIZE,
2994 (u8 *)vendor_pn))
2995 vendor_pn[0] = '\0';
2996 else
2997 vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
Eilon Greenstein589abe32009-02-12 08:36:55 +00002998
Eilon Greenstein4d295db2009-07-21 05:47:47 +00002999 printk(KERN_INFO PFX "Warning: "
3000 "Unqualified SFP+ module "
3001 "detected on %s, Port %d from %s part number %s\n"
3002 , bp->dev->name, params->port,
3003 vendor_name, vendor_pn);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003004 return -EINVAL;
3005}
3006
Eilon Greenstein589abe32009-02-12 08:36:55 +00003007static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003008 u16 edc_mode)
Eilon Greenstein589abe32009-02-12 08:36:55 +00003009{
3010 struct bnx2x *bp = params->bp;
3011 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003012 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greensteincc1cb002009-03-02 08:00:03 +00003013 u16 cur_limiting_mode;
Eilon Greensteincc1cb002009-03-02 08:00:03 +00003014
3015 bnx2x_cl45_read(bp, port,
3016 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3017 ext_phy_addr,
3018 MDIO_PMA_DEVAD,
3019 MDIO_PMA_REG_ROM_VER2,
3020 &cur_limiting_mode);
3021 DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
3022 cur_limiting_mode);
3023
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003024 if (edc_mode == EDC_MODE_LIMITING) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003025 DP(NETIF_MSG_LINK,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003026 "Setting LIMITING MODE\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00003027 bnx2x_cl45_write(bp, port,
3028 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3029 ext_phy_addr,
3030 MDIO_PMA_DEVAD,
3031 MDIO_PMA_REG_ROM_VER2,
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003032 EDC_MODE_LIMITING);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003033 } else { /* LRM mode ( default )*/
Eilon Greensteincc1cb002009-03-02 08:00:03 +00003034
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003035 DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
Eilon Greenstein589abe32009-02-12 08:36:55 +00003036
Eilon Greenstein589abe32009-02-12 08:36:55 +00003037 /* Changing to LRM mode takes quite few seconds.
3038 So do it only if current mode is limiting
3039 ( default is LRM )*/
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003040 if (cur_limiting_mode != EDC_MODE_LIMITING)
Eilon Greenstein589abe32009-02-12 08:36:55 +00003041 return 0;
3042
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_LRM_MODE,
3048 0);
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_ROM_VER2,
3054 0x128);
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_MISC_CTRL0,
3060 0x4008);
3061 bnx2x_cl45_write(bp, port,
3062 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
3063 ext_phy_addr,
3064 MDIO_PMA_DEVAD,
3065 MDIO_PMA_REG_LRM_MODE,
3066 0xaaaa);
3067 }
3068 return 0;
3069}
3070
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003071static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
3072 u16 edc_mode)
3073{
3074 struct bnx2x *bp = params->bp;
3075 u8 port = params->port;
3076 u16 phy_identifier;
3077 u16 rom_ver2_val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003078 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003079
3080 bnx2x_cl45_read(bp, port,
3081 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3082 ext_phy_addr,
3083 MDIO_PMA_DEVAD,
3084 MDIO_PMA_REG_PHY_IDENTIFIER,
3085 &phy_identifier);
3086
3087 bnx2x_cl45_write(bp, port,
3088 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3089 ext_phy_addr,
3090 MDIO_PMA_DEVAD,
3091 MDIO_PMA_REG_PHY_IDENTIFIER,
3092 (phy_identifier & ~(1<<9)));
3093
3094 bnx2x_cl45_read(bp, port,
3095 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3096 ext_phy_addr,
3097 MDIO_PMA_DEVAD,
3098 MDIO_PMA_REG_ROM_VER2,
3099 &rom_ver2_val);
3100 /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
3101 bnx2x_cl45_write(bp, port,
3102 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3103 ext_phy_addr,
3104 MDIO_PMA_DEVAD,
3105 MDIO_PMA_REG_ROM_VER2,
3106 (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
3107
3108 bnx2x_cl45_write(bp, port,
3109 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3110 ext_phy_addr,
3111 MDIO_PMA_DEVAD,
3112 MDIO_PMA_REG_PHY_IDENTIFIER,
3113 (phy_identifier | (1<<9)));
3114
3115 return 0;
3116}
3117
3118
Eilon Greenstein589abe32009-02-12 08:36:55 +00003119static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
3120{
3121 u8 val;
3122 struct bnx2x *bp = params->bp;
3123 u16 timeout;
3124 /* Initialization time after hot-plug may take up to 300ms for some
3125 phys type ( e.g. JDSU ) */
3126 for (timeout = 0; timeout < 60; timeout++) {
3127 if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
3128 == 0) {
3129 DP(NETIF_MSG_LINK, "SFP+ module initialization "
3130 "took %d ms\n", timeout * 5);
3131 return 0;
3132 }
3133 msleep(5);
3134 }
3135 return -EINVAL;
3136}
3137
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003138static void bnx2x_8727_power_module(struct bnx2x *bp,
3139 struct link_params *params,
3140 u8 ext_phy_addr, u8 is_power_up) {
3141 /* Make sure GPIOs are not using for LED mode */
3142 u16 val;
3143 u8 port = params->port;
3144 /*
3145 * In the GPIO register, bit 4 is use to detemine if the GPIOs are
3146 * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
3147 * output
3148 * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
3149 * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
3150 * where the 1st bit is the over-current(only input), and 2nd bit is
3151 * for power( only output )
3152 */
3153
3154 /*
3155 * In case of NOC feature is disabled and power is up, set GPIO control
3156 * as input to enable listening of over-current indication
3157 */
3158
3159 if (!(params->feature_config_flags &
3160 FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
3161 val = (1<<4);
3162 else
3163 /*
3164 * Set GPIO control to OUTPUT, and set the power bit
3165 * to according to the is_power_up
3166 */
3167 val = ((!(is_power_up)) << 1);
3168
3169 bnx2x_cl45_write(bp, port,
3170 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
3171 ext_phy_addr,
3172 MDIO_PMA_DEVAD,
3173 MDIO_PMA_REG_8727_GPIO_CTRL,
3174 val);
3175}
3176
Eilon Greenstein589abe32009-02-12 08:36:55 +00003177static u8 bnx2x_sfp_module_detection(struct link_params *params)
3178{
3179 struct bnx2x *bp = params->bp;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003180 u16 edc_mode;
3181 u8 rc = 0;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003182 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003183 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003184 u32 val = REG_RD(bp, params->shmem_base +
3185 offsetof(struct shmem_region, dev_info.
3186 port_feature_config[params->port].config));
Eilon Greenstein589abe32009-02-12 08:36:55 +00003187
3188 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
3189 params->port);
3190
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003191 if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003192 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003193 return -EINVAL;
3194 } else if (bnx2x_verify_sfp_module(params) !=
Eilon Greenstein589abe32009-02-12 08:36:55 +00003195 0) {
3196 /* check SFP+ module compatibility */
3197 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003198 rc = -EINVAL;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003199 /* Turn on fault module-detected led */
3200 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3201 MISC_REGISTERS_GPIO_HIGH,
3202 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003203 if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
3204 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3205 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
3206 /* Shutdown SFP+ module */
3207 DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
3208 bnx2x_8727_power_module(bp, params,
3209 ext_phy_addr, 0);
3210 return rc;
3211 }
3212 } else {
3213 /* Turn off fault module-detected led */
3214 DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
3215 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3216 MISC_REGISTERS_GPIO_LOW,
3217 params->port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003218 }
3219
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003220 /* power up the SFP module */
3221 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
3222 bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003223
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003224 /* Check and set limiting mode / LRM mode on 8726.
3225 On 8727 it is done automatically */
3226 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
3227 bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
3228 else
3229 bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
3230 /*
3231 * Enable transmit for this module if the module is approved, or
3232 * if unapproved modules should also enable the Tx laser
3233 */
3234 if (rc == 0 ||
3235 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
3236 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
3237 bnx2x_sfp_set_transmitter(bp, params->port,
3238 ext_phy_type, ext_phy_addr, 1);
3239 else
3240 bnx2x_sfp_set_transmitter(bp, params->port,
3241 ext_phy_type, ext_phy_addr, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003242
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003243 return rc;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003244}
3245
3246void bnx2x_handle_module_detect_int(struct link_params *params)
3247{
3248 struct bnx2x *bp = params->bp;
3249 u32 gpio_val;
3250 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003251
Eilon Greenstein589abe32009-02-12 08:36:55 +00003252 /* Set valid module led off */
3253 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
3254 MISC_REGISTERS_GPIO_HIGH,
3255 params->port);
3256
3257 /* Get current gpio val refelecting module plugged in / out*/
3258 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
3259
3260 /* Call the handling function in case module is detected */
3261 if (gpio_val == 0) {
3262
3263 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
3264 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
3265 port);
3266
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003267 if (bnx2x_wait_for_sfp_module_initialized(params) ==
3268 0)
Eilon Greenstein589abe32009-02-12 08:36:55 +00003269 bnx2x_sfp_module_detection(params);
3270 else
3271 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
3272 } else {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003273 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
3274
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003275 u32 ext_phy_type =
3276 XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3277 u32 val = REG_RD(bp, params->shmem_base +
3278 offsetof(struct shmem_region, dev_info.
3279 port_feature_config[params->port].
3280 config));
3281
Eilon Greenstein589abe32009-02-12 08:36:55 +00003282 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
3283 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
3284 port);
3285 /* Module was plugged out. */
3286 /* Disable transmit for this module */
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003287 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
3288 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
3289 bnx2x_sfp_set_transmitter(bp, params->port,
3290 ext_phy_type, ext_phy_addr, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003291 }
3292}
3293
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003294static void bnx2x_bcm807x_force_10G(struct link_params *params)
3295{
3296 struct bnx2x *bp = params->bp;
3297 u8 port = params->port;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003298 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003299 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3300
3301 /* Force KR or KX */
3302 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3303 MDIO_PMA_DEVAD,
3304 MDIO_PMA_REG_CTRL,
3305 0x2040);
3306 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3307 MDIO_PMA_DEVAD,
3308 MDIO_PMA_REG_10G_CTRL2,
3309 0x000b);
3310 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3311 MDIO_PMA_DEVAD,
3312 MDIO_PMA_REG_BCM_CTRL,
3313 0x0000);
3314 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3315 MDIO_AN_DEVAD,
3316 MDIO_AN_REG_CTRL,
3317 0x0000);
3318}
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003319
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003320static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
3321{
3322 struct bnx2x *bp = params->bp;
3323 u8 port = params->port;
3324 u16 val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003325 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003326 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3327
3328 bnx2x_cl45_read(bp, params->port,
3329 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
3330 ext_phy_addr,
3331 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003332 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003333
3334 if (val == 0) {
3335 /* Mustn't set low power mode in 8073 A0 */
3336 return;
3337 }
3338
3339 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
3340 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
3341 MDIO_XS_DEVAD,
3342 MDIO_XS_PLL_SEQUENCER, &val);
3343 val &= ~(1<<13);
3344 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3345 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3346
3347 /* PLL controls */
3348 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3349 MDIO_XS_DEVAD, 0x805E, 0x1077);
3350 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3351 MDIO_XS_DEVAD, 0x805D, 0x0000);
3352 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3353 MDIO_XS_DEVAD, 0x805C, 0x030B);
3354 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3355 MDIO_XS_DEVAD, 0x805B, 0x1240);
3356 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3357 MDIO_XS_DEVAD, 0x805A, 0x2490);
3358
3359 /* Tx Controls */
3360 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3361 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
3362 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3363 MDIO_XS_DEVAD, 0x80A6, 0x9041);
3364 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3365 MDIO_XS_DEVAD, 0x80A5, 0x4640);
3366
3367 /* Rx Controls */
3368 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3369 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
3370 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3371 MDIO_XS_DEVAD, 0x80FD, 0x9249);
3372 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3373 MDIO_XS_DEVAD, 0x80FC, 0x2015);
3374
3375 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
3376 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
3377 MDIO_XS_DEVAD,
3378 MDIO_XS_PLL_SEQUENCER, &val);
3379 val |= (1<<13);
3380 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
3381 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
3382}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003383
3384static void bnx2x_8073_set_pause_cl37(struct link_params *params,
3385 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003386{
3387 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003388 u16 cl37_val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003389 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003390 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3391
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003392 bnx2x_cl45_read(bp, params->port,
3393 ext_phy_type,
3394 ext_phy_addr,
3395 MDIO_AN_DEVAD,
3396 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
3397
3398 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3399 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3400
3401 if ((vars->ieee_fc &
3402 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
3403 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
3404 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
3405 }
3406 if ((vars->ieee_fc &
3407 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
3408 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3409 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
3410 }
3411 if ((vars->ieee_fc &
3412 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
3413 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3414 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
3415 }
3416 DP(NETIF_MSG_LINK,
3417 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
3418
3419 bnx2x_cl45_write(bp, params->port,
3420 ext_phy_type,
3421 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003422 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003423 MDIO_AN_REG_CL37_FC_LD, cl37_val);
3424 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003425}
3426
3427static void bnx2x_ext_phy_set_pause(struct link_params *params,
3428 struct link_vars *vars)
3429{
3430 struct bnx2x *bp = params->bp;
3431 u16 val;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003432 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003433 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3434
3435 /* read modify write pause advertizing */
3436 bnx2x_cl45_read(bp, params->port,
3437 ext_phy_type,
3438 ext_phy_addr,
3439 MDIO_AN_DEVAD,
3440 MDIO_AN_REG_ADV_PAUSE, &val);
3441
3442 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003443
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003444 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
3445
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003446 if ((vars->ieee_fc &
3447 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003448 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
3449 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
3450 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003451 if ((vars->ieee_fc &
3452 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003453 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
3454 val |=
3455 MDIO_AN_REG_ADV_PAUSE_PAUSE;
3456 }
3457 DP(NETIF_MSG_LINK,
3458 "Ext phy AN advertize 0x%x\n", val);
3459 bnx2x_cl45_write(bp, params->port,
3460 ext_phy_type,
3461 ext_phy_addr,
3462 MDIO_AN_DEVAD,
3463 MDIO_AN_REG_ADV_PAUSE, val);
3464}
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003465static void bnx2x_set_preemphasis(struct link_params *params)
3466{
3467 u16 bank, i = 0;
3468 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003469
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003470 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
3471 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
3472 CL45_WR_OVER_CL22(bp, params->port,
3473 params->phy_addr,
3474 bank,
3475 MDIO_RX0_RX_EQ_BOOST,
3476 params->xgxs_config_rx[i]);
3477 }
3478
3479 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
3480 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
3481 CL45_WR_OVER_CL22(bp, params->port,
3482 params->phy_addr,
3483 bank,
3484 MDIO_TX0_TX_DRIVER,
3485 params->xgxs_config_tx[i]);
3486 }
3487}
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003488
Eilon Greenstein2f904462009-08-12 08:22:16 +00003489
3490static void bnx2x_8481_set_led4(struct link_params *params,
3491 u32 ext_phy_type, u8 ext_phy_addr)
3492{
3493 struct bnx2x *bp = params->bp;
3494
3495 /* PHYC_CTL_LED_CTL */
3496 bnx2x_cl45_write(bp, params->port,
3497 ext_phy_type,
3498 ext_phy_addr,
3499 MDIO_PMA_DEVAD,
3500 MDIO_PMA_REG_8481_LINK_SIGNAL, 0xa482);
3501
3502 /* Unmask LED4 for 10G link */
3503 bnx2x_cl45_write(bp, params->port,
3504 ext_phy_type,
3505 ext_phy_addr,
3506 MDIO_PMA_DEVAD,
3507 MDIO_PMA_REG_8481_SIGNAL_MASK, (1<<6));
3508 /* 'Interrupt Mask' */
3509 bnx2x_cl45_write(bp, params->port,
3510 ext_phy_type,
3511 ext_phy_addr,
3512 MDIO_AN_DEVAD,
3513 0xFFFB, 0xFFFD);
3514}
3515static void bnx2x_8481_set_legacy_led_mode(struct link_params *params,
3516 u32 ext_phy_type, u8 ext_phy_addr)
3517{
3518 struct bnx2x *bp = params->bp;
3519
3520 /* LED1 (10G Link): Disable LED1 when 10/100/1000 link */
3521 /* LED2 (1G/100/10 Link): Enable LED2 when 10/100/1000 link) */
3522 bnx2x_cl45_write(bp, params->port,
3523 ext_phy_type,
3524 ext_phy_addr,
3525 MDIO_AN_DEVAD,
3526 MDIO_AN_REG_8481_LEGACY_SHADOW,
3527 (1<<15) | (0xd << 10) | (0xc<<4) | 0xe);
3528}
3529
3530static void bnx2x_8481_set_10G_led_mode(struct link_params *params,
3531 u32 ext_phy_type, u8 ext_phy_addr)
3532{
3533 struct bnx2x *bp = params->bp;
3534 u16 val1;
3535
3536 /* LED1 (10G Link) */
3537 /* Enable continuse based on source 7(10G-link) */
3538 bnx2x_cl45_read(bp, params->port,
3539 ext_phy_type,
3540 ext_phy_addr,
3541 MDIO_PMA_DEVAD,
3542 MDIO_PMA_REG_8481_LINK_SIGNAL,
3543 &val1);
3544 /* Set bit 2 to 0, and bits [1:0] to 10 */
3545 val1 &= ~((1<<0) | (1<<2)); /* Clear bits 0,2*/
3546 val1 |= (1<<1); /* Set bit 1 */
3547
3548 bnx2x_cl45_write(bp, params->port,
3549 ext_phy_type,
3550 ext_phy_addr,
3551 MDIO_PMA_DEVAD,
3552 MDIO_PMA_REG_8481_LINK_SIGNAL,
3553 val1);
3554
3555 /* Unmask LED1 for 10G link */
3556 bnx2x_cl45_read(bp, params->port,
3557 ext_phy_type,
3558 ext_phy_addr,
3559 MDIO_PMA_DEVAD,
3560 MDIO_PMA_REG_8481_LED1_MASK,
3561 &val1);
3562 /* Set bit 2 to 0, and bits [1:0] to 10 */
3563 val1 |= (1<<7);
3564 bnx2x_cl45_write(bp, params->port,
3565 ext_phy_type,
3566 ext_phy_addr,
3567 MDIO_PMA_DEVAD,
3568 MDIO_PMA_REG_8481_LED1_MASK,
3569 val1);
3570
3571 /* LED2 (1G/100/10G Link) */
3572 /* Mask LED2 for 10G link */
3573 bnx2x_cl45_write(bp, params->port,
3574 ext_phy_type,
3575 ext_phy_addr,
3576 MDIO_PMA_DEVAD,
3577 MDIO_PMA_REG_8481_LED2_MASK,
3578 0);
3579
3580 /* LED3 (10G/1G/100/10G Activity) */
3581 bnx2x_cl45_read(bp, params->port,
3582 ext_phy_type,
3583 ext_phy_addr,
3584 MDIO_PMA_DEVAD,
3585 MDIO_PMA_REG_8481_LINK_SIGNAL,
3586 &val1);
3587 /* Enable blink based on source 4(Activity) */
3588 val1 &= ~((1<<7) | (1<<8)); /* Clear bits 7,8 */
3589 val1 |= (1<<6); /* Set only bit 6 */
3590 bnx2x_cl45_write(bp, params->port,
3591 ext_phy_type,
3592 ext_phy_addr,
3593 MDIO_PMA_DEVAD,
3594 MDIO_PMA_REG_8481_LINK_SIGNAL,
3595 val1);
3596
3597 bnx2x_cl45_read(bp, params->port,
3598 ext_phy_type,
3599 ext_phy_addr,
3600 MDIO_PMA_DEVAD,
3601 MDIO_PMA_REG_8481_LED3_MASK,
3602 &val1);
3603 val1 |= (1<<4); /* Unmask LED3 for 10G link */
3604 bnx2x_cl45_write(bp, params->port,
3605 ext_phy_type,
3606 ext_phy_addr,
3607 MDIO_PMA_DEVAD,
3608 MDIO_PMA_REG_8481_LED3_MASK,
3609 val1);
3610}
3611
3612
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003613static void bnx2x_init_internal_phy(struct link_params *params,
Eilon Greenstein239d6862009-08-12 08:23:04 +00003614 struct link_vars *vars,
3615 u8 enable_cl73)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003616{
3617 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003618
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003619 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003620 if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
3621 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3622 (params->feature_config_flags &
3623 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
3624 bnx2x_set_preemphasis(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003625
3626 /* forced speed requested? */
Yaniv Rosner7846e472009-11-05 19:18:07 +02003627 if (vars->line_speed != SPEED_AUTO_NEG ||
3628 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
3629 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3630 params->loopback_mode == LOOPBACK_EXT)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003631 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
3632
3633 /* disable autoneg */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003634 bnx2x_set_autoneg(params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003635
3636 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003637 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003638
3639 } else { /* AN_mode */
3640 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
3641
3642 /* AN enabled */
3643 bnx2x_set_brcm_cl37_advertisment(params);
3644
3645 /* program duplex & pause advertisement (for aneg) */
3646 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003647 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003648
3649 /* enable autoneg */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003650 bnx2x_set_autoneg(params, vars, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003651
3652 /* enable and restart AN */
Eilon Greenstein239d6862009-08-12 08:23:04 +00003653 bnx2x_restart_autoneg(params, enable_cl73);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003654 }
3655
3656 } else { /* SGMII mode */
3657 DP(NETIF_MSG_LINK, "SGMII\n");
3658
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003659 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003660 }
3661}
3662
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003663static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
3664{
3665 struct bnx2x *bp = params->bp;
3666 u32 ext_phy_type;
3667 u8 ext_phy_addr;
3668 u16 cnt;
3669 u16 ctrl = 0;
3670 u16 val = 0;
3671 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003672
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003673 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00003674 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003675
3676 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3677 /* Make sure that the soft reset is off (expect for the 8072:
3678 * due to the lock, it will be done inside the specific
3679 * handling)
3680 */
3681 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3682 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3683 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
3684 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
3685 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
3686 /* Wait for soft reset to get cleared upto 1 sec */
3687 for (cnt = 0; cnt < 1000; cnt++) {
3688 bnx2x_cl45_read(bp, params->port,
3689 ext_phy_type,
3690 ext_phy_addr,
3691 MDIO_PMA_DEVAD,
3692 MDIO_PMA_REG_CTRL, &ctrl);
3693 if (!(ctrl & (1<<15)))
3694 break;
3695 msleep(1);
3696 }
3697 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
3698 ctrl, cnt);
3699 }
3700
3701 switch (ext_phy_type) {
3702 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003703 break;
3704
3705 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3706 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3707
3708 bnx2x_cl45_write(bp, params->port,
3709 ext_phy_type,
3710 ext_phy_addr,
3711 MDIO_PMA_DEVAD,
3712 MDIO_PMA_REG_MISC_CTRL,
3713 0x8288);
3714 bnx2x_cl45_write(bp, params->port,
3715 ext_phy_type,
3716 ext_phy_addr,
3717 MDIO_PMA_DEVAD,
3718 MDIO_PMA_REG_PHY_IDENTIFIER,
3719 0x7fbf);
3720 bnx2x_cl45_write(bp, params->port,
3721 ext_phy_type,
3722 ext_phy_addr,
3723 MDIO_PMA_DEVAD,
3724 MDIO_PMA_REG_CMU_PLL_BYPASS,
3725 0x0100);
3726 bnx2x_cl45_write(bp, params->port,
3727 ext_phy_type,
3728 ext_phy_addr,
3729 MDIO_WIS_DEVAD,
3730 MDIO_WIS_REG_LASI_CNTL, 0x1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003731
Eilon Greenstein3b313b62009-03-02 08:00:10 +00003732 /* BCM8705 doesn't have microcode, hence the 0 */
3733 bnx2x_save_spirom_version(bp, params->port,
3734 params->shmem_base, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003735 break;
3736
3737 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003738 /* Wait until fw is loaded */
3739 for (cnt = 0; cnt < 100; cnt++) {
3740 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3741 ext_phy_addr, MDIO_PMA_DEVAD,
3742 MDIO_PMA_REG_ROM_VER1, &val);
3743 if (val)
3744 break;
3745 msleep(10);
3746 }
3747 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized "
3748 "after %d ms\n", cnt);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003749 if ((params->feature_config_flags &
3750 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3751 u8 i;
3752 u16 reg;
3753 for (i = 0; i < 4; i++) {
3754 reg = MDIO_XS_8706_REG_BANK_RX0 +
3755 i*(MDIO_XS_8706_REG_BANK_RX1 -
3756 MDIO_XS_8706_REG_BANK_RX0);
3757 bnx2x_cl45_read(bp, params->port,
3758 ext_phy_type,
3759 ext_phy_addr,
3760 MDIO_XS_DEVAD,
3761 reg, &val);
3762 /* Clear first 3 bits of the control */
3763 val &= ~0x7;
3764 /* Set control bits according to
3765 configuation */
3766 val |= (params->xgxs_config_rx[i] &
3767 0x7);
3768 DP(NETIF_MSG_LINK, "Setting RX"
3769 "Equalizer to BCM8706 reg 0x%x"
3770 " <-- val 0x%x\n", reg, val);
3771 bnx2x_cl45_write(bp, params->port,
3772 ext_phy_type,
3773 ext_phy_addr,
3774 MDIO_XS_DEVAD,
3775 reg, val);
3776 }
3777 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003778 /* Force speed */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003779 if (params->req_line_speed == SPEED_10000) {
3780 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
3781
3782 bnx2x_cl45_write(bp, params->port,
3783 ext_phy_type,
3784 ext_phy_addr,
3785 MDIO_PMA_DEVAD,
3786 MDIO_PMA_REG_DIGITAL_CTRL,
3787 0x400);
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02003788 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3789 ext_phy_addr, MDIO_PMA_DEVAD,
3790 MDIO_PMA_REG_LASI_CTRL, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003791 } else {
3792 /* Force 1Gbps using autoneg with 1G
3793 advertisment */
3794
3795 /* Allow CL37 through CL73 */
3796 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3797 bnx2x_cl45_write(bp, params->port,
3798 ext_phy_type,
3799 ext_phy_addr,
3800 MDIO_AN_DEVAD,
3801 MDIO_AN_REG_CL37_CL73,
3802 0x040c);
3803
3804 /* Enable Full-Duplex advertisment on CL37 */
3805 bnx2x_cl45_write(bp, params->port,
3806 ext_phy_type,
3807 ext_phy_addr,
3808 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003809 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003810 0x0020);
3811 /* Enable CL37 AN */
3812 bnx2x_cl45_write(bp, params->port,
3813 ext_phy_type,
3814 ext_phy_addr,
3815 MDIO_AN_DEVAD,
3816 MDIO_AN_REG_CL37_AN,
3817 0x1000);
3818 /* 1G support */
3819 bnx2x_cl45_write(bp, params->port,
3820 ext_phy_type,
3821 ext_phy_addr,
3822 MDIO_AN_DEVAD,
3823 MDIO_AN_REG_ADV, (1<<5));
3824
3825 /* Enable clause 73 AN */
3826 bnx2x_cl45_write(bp, params->port,
3827 ext_phy_type,
3828 ext_phy_addr,
3829 MDIO_AN_DEVAD,
3830 MDIO_AN_REG_CTRL,
3831 0x1200);
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02003832 bnx2x_cl45_write(bp, params->port,
3833 ext_phy_type,
3834 ext_phy_addr,
3835 MDIO_PMA_DEVAD,
3836 MDIO_PMA_REG_RX_ALARM_CTRL,
3837 0x0400);
3838 bnx2x_cl45_write(bp, params->port,
3839 ext_phy_type,
3840 ext_phy_addr,
3841 MDIO_PMA_DEVAD,
3842 MDIO_PMA_REG_LASI_CTRL, 0x0004);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003843
3844 }
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003845 bnx2x_save_bcm_spirom_ver(bp, params->port,
3846 ext_phy_type,
3847 ext_phy_addr,
3848 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003849 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003850 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3851 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3852 bnx2x_bcm8726_external_rom_boot(params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003853
Eilon Greenstein589abe32009-02-12 08:36:55 +00003854 /* Need to call module detected on initialization since
3855 the module detection triggered by actual module
3856 insertion might occur before driver is loaded, and when
3857 driver is loaded, it reset all registers, including the
3858 transmitter */
3859 bnx2x_sfp_module_detection(params);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00003860
3861 /* Set Flow control */
3862 bnx2x_ext_phy_set_pause(params, vars);
Eilon Greenstein589abe32009-02-12 08:36:55 +00003863 if (params->req_line_speed == SPEED_1000) {
3864 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3865 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3866 ext_phy_addr, MDIO_PMA_DEVAD,
3867 MDIO_PMA_REG_CTRL, 0x40);
3868 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3869 ext_phy_addr, MDIO_PMA_DEVAD,
3870 MDIO_PMA_REG_10G_CTRL2, 0xD);
3871 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3872 ext_phy_addr, MDIO_PMA_DEVAD,
3873 MDIO_PMA_REG_LASI_CTRL, 0x5);
3874 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3875 ext_phy_addr, MDIO_PMA_DEVAD,
3876 MDIO_PMA_REG_RX_ALARM_CTRL,
3877 0x400);
3878 } else if ((params->req_line_speed ==
3879 SPEED_AUTO_NEG) &&
3880 ((params->speed_cap_mask &
3881 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
3882 DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
3883 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3884 ext_phy_addr, MDIO_AN_DEVAD,
3885 MDIO_AN_REG_ADV, 0x20);
3886 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3887 ext_phy_addr, MDIO_AN_DEVAD,
3888 MDIO_AN_REG_CL37_CL73, 0x040c);
3889 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3890 ext_phy_addr, MDIO_AN_DEVAD,
3891 MDIO_AN_REG_CL37_FC_LD, 0x0020);
3892 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3893 ext_phy_addr, MDIO_AN_DEVAD,
3894 MDIO_AN_REG_CL37_AN, 0x1000);
3895 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3896 ext_phy_addr, MDIO_AN_DEVAD,
3897 MDIO_AN_REG_CTRL, 0x1200);
3898
3899 /* Enable RX-ALARM control to receive
3900 interrupt for 1G speed change */
3901 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3902 ext_phy_addr, MDIO_PMA_DEVAD,
3903 MDIO_PMA_REG_LASI_CTRL, 0x4);
3904 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3905 ext_phy_addr, MDIO_PMA_DEVAD,
3906 MDIO_PMA_REG_RX_ALARM_CTRL,
3907 0x400);
3908
3909 } else { /* Default 10G. Set only LASI control */
3910 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3911 ext_phy_addr, MDIO_PMA_DEVAD,
3912 MDIO_PMA_REG_LASI_CTRL, 1);
3913 }
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003914
3915 /* Set TX PreEmphasis if needed */
3916 if ((params->feature_config_flags &
3917 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3918 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
3919 "TX_CTRL2 0x%x\n",
3920 params->xgxs_config_tx[0],
3921 params->xgxs_config_tx[1]);
3922 bnx2x_cl45_write(bp, params->port,
3923 ext_phy_type,
3924 ext_phy_addr,
3925 MDIO_PMA_DEVAD,
3926 MDIO_PMA_REG_8726_TX_CTRL1,
3927 params->xgxs_config_tx[0]);
3928
3929 bnx2x_cl45_write(bp, params->port,
3930 ext_phy_type,
3931 ext_phy_addr,
3932 MDIO_PMA_DEVAD,
3933 MDIO_PMA_REG_8726_TX_CTRL2,
3934 params->xgxs_config_tx[1]);
3935 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00003936 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003937 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3938 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3939 {
3940 u16 tmp1;
3941 u16 rx_alarm_ctrl_val;
3942 u16 lasi_ctrl_val;
3943 if (ext_phy_type ==
3944 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3945 rx_alarm_ctrl_val = 0x400;
3946 lasi_ctrl_val = 0x0004;
3947 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003948 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003949 lasi_ctrl_val = 0x0004;
3950 }
3951
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003952 /* enable LASI */
3953 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003954 ext_phy_type,
3955 ext_phy_addr,
3956 MDIO_PMA_DEVAD,
3957 MDIO_PMA_REG_RX_ALARM_CTRL,
3958 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003959
3960 bnx2x_cl45_write(bp, params->port,
3961 ext_phy_type,
3962 ext_phy_addr,
3963 MDIO_PMA_DEVAD,
3964 MDIO_PMA_REG_LASI_CTRL,
3965 lasi_ctrl_val);
3966
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003967 bnx2x_8073_set_pause_cl37(params, vars);
3968
3969 if (ext_phy_type ==
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003970 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072)
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003971 bnx2x_bcm8072_external_rom_boot(params);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00003972 else
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003973 /* In case of 8073 with long xaui lines,
3974 don't set the 8073 xaui low power*/
3975 bnx2x_bcm8073_set_xaui_low_power_mode(params);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003976
3977 bnx2x_cl45_read(bp, params->port,
3978 ext_phy_type,
3979 ext_phy_addr,
3980 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003981 MDIO_PMA_REG_M8051_MSGOUT_REG,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003982 &tmp1);
3983
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003984 bnx2x_cl45_read(bp, params->port,
3985 ext_phy_type,
3986 ext_phy_addr,
3987 MDIO_PMA_DEVAD,
3988 MDIO_PMA_REG_RX_ALARM, &tmp1);
3989
3990 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
3991 "0x%x\n", tmp1);
3992
3993 /* If this is forced speed, set to KR or KX
3994 * (all other are not supported)
3995 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003996 if (params->loopback_mode == LOOPBACK_EXT) {
3997 bnx2x_bcm807x_force_10G(params);
3998 DP(NETIF_MSG_LINK,
3999 "Forced speed 10G on 807X\n");
4000 break;
4001 } else {
4002 bnx2x_cl45_write(bp, params->port,
4003 ext_phy_type, ext_phy_addr,
4004 MDIO_PMA_DEVAD,
4005 MDIO_PMA_REG_BCM_CTRL,
4006 0x0002);
4007 }
4008 if (params->req_line_speed != SPEED_AUTO_NEG) {
4009 if (params->req_line_speed == SPEED_10000) {
4010 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004011 } else if (params->req_line_speed ==
4012 SPEED_2500) {
4013 val = (1<<5);
4014 /* Note that 2.5G works only
4015 when used with 1G advertisment */
4016 } else
4017 val = (1<<5);
4018 } else {
4019
4020 val = 0;
4021 if (params->speed_cap_mask &
4022 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
4023 val |= (1<<7);
4024
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004025 /* Note that 2.5G works only when
4026 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004027 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004028 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
4029 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004030 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004031 DP(NETIF_MSG_LINK,
4032 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004033 }
4034
4035 bnx2x_cl45_write(bp, params->port,
4036 ext_phy_type,
4037 ext_phy_addr,
4038 MDIO_AN_DEVAD,
4039 MDIO_AN_REG_ADV, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004040 if (ext_phy_type ==
4041 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004042 bnx2x_cl45_read(bp, params->port,
4043 ext_phy_type,
4044 ext_phy_addr,
4045 MDIO_AN_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004046 MDIO_AN_REG_8073_2_5G, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004047
4048 if (((params->speed_cap_mask &
4049 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
4050 (params->req_line_speed ==
4051 SPEED_AUTO_NEG)) ||
4052 (params->req_line_speed ==
4053 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004054 u16 phy_ver;
4055 /* Allow 2.5G for A1 and above */
4056 bnx2x_cl45_read(bp, params->port,
4057 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4058 ext_phy_addr,
4059 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004060 MDIO_PMA_REG_8073_CHIP_REV, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004061 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004062 if (phy_ver > 0)
4063 tmp1 |= 1;
4064 else
4065 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004066 } else {
4067 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004068 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004069 }
4070
4071 bnx2x_cl45_write(bp, params->port,
4072 ext_phy_type,
4073 ext_phy_addr,
4074 MDIO_AN_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00004075 MDIO_AN_REG_8073_2_5G, tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004076 }
4077
4078 /* Add support for CL37 (passive mode) II */
4079
4080 bnx2x_cl45_read(bp, params->port,
4081 ext_phy_type,
4082 ext_phy_addr,
4083 MDIO_AN_DEVAD,
4084 MDIO_AN_REG_CL37_FC_LD,
4085 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004086
4087 bnx2x_cl45_write(bp, params->port,
4088 ext_phy_type,
4089 ext_phy_addr,
4090 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004091 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
4092 ((params->req_duplex == DUPLEX_FULL) ?
4093 0x20 : 0x40)));
4094
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004095 /* Add support for CL37 (passive mode) III */
4096 bnx2x_cl45_write(bp, params->port,
4097 ext_phy_type,
4098 ext_phy_addr,
4099 MDIO_AN_DEVAD,
4100 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004101
4102 if (ext_phy_type ==
4103 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004104 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004105 BW and FEE main tap. Rest commands are executed
4106 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004107 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004108 if (bnx2x_8073_is_snr_needed(params))
4109 bnx2x_cl45_write(bp, params->port,
4110 ext_phy_type,
4111 ext_phy_addr,
4112 MDIO_PMA_DEVAD,
4113 MDIO_PMA_REG_EDC_FFE_MAIN,
4114 0xFB0C);
4115
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004116 /* Enable FEC (Forware Error Correction)
4117 Request in the AN */
4118 bnx2x_cl45_read(bp, params->port,
4119 ext_phy_type,
4120 ext_phy_addr,
4121 MDIO_AN_DEVAD,
4122 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004123
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004124 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004125
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004126 bnx2x_cl45_write(bp, params->port,
4127 ext_phy_type,
4128 ext_phy_addr,
4129 MDIO_AN_DEVAD,
4130 MDIO_AN_REG_ADV2, tmp1);
4131
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004132 }
4133
4134 bnx2x_ext_phy_set_pause(params, vars);
4135
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004136 /* Restart autoneg */
4137 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004138 bnx2x_cl45_write(bp, params->port,
4139 ext_phy_type,
4140 ext_phy_addr,
4141 MDIO_AN_DEVAD,
4142 MDIO_AN_REG_CTRL, 0x1200);
4143 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
4144 "Advertise 1G=%x, 10G=%x\n",
4145 ((val & (1<<5)) > 0),
4146 ((val & (1<<7)) > 0));
4147 break;
4148 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004149
4150 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
4151 {
4152 u16 tmp1;
4153 u16 rx_alarm_ctrl_val;
4154 u16 lasi_ctrl_val;
4155
4156 /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
4157
4158 u16 mod_abs;
4159 rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
4160 lasi_ctrl_val = 0x0004;
4161
4162 DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
4163 /* enable LASI */
4164 bnx2x_cl45_write(bp, params->port,
4165 ext_phy_type,
4166 ext_phy_addr,
4167 MDIO_PMA_DEVAD,
4168 MDIO_PMA_REG_RX_ALARM_CTRL,
4169 rx_alarm_ctrl_val);
4170
4171 bnx2x_cl45_write(bp, params->port,
4172 ext_phy_type,
4173 ext_phy_addr,
4174 MDIO_PMA_DEVAD,
4175 MDIO_PMA_REG_LASI_CTRL,
4176 lasi_ctrl_val);
4177
4178 /* Initially configure MOD_ABS to interrupt when
4179 module is presence( bit 8) */
4180 bnx2x_cl45_read(bp, params->port,
4181 ext_phy_type,
4182 ext_phy_addr,
4183 MDIO_PMA_DEVAD,
4184 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4185 /* Set EDC off by setting OPTXLOS signal input to low
4186 (bit 9).
4187 When the EDC is off it locks onto a reference clock and
4188 avoids becoming 'lost'.*/
4189 mod_abs &= ~((1<<8) | (1<<9));
4190 bnx2x_cl45_write(bp, params->port,
4191 ext_phy_type,
4192 ext_phy_addr,
4193 MDIO_PMA_DEVAD,
4194 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4195
4196 /* Make MOD_ABS give interrupt on change */
4197 bnx2x_cl45_read(bp, params->port,
4198 ext_phy_type,
4199 ext_phy_addr,
4200 MDIO_PMA_DEVAD,
4201 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4202 &val);
4203 val |= (1<<12);
4204 bnx2x_cl45_write(bp, params->port,
4205 ext_phy_type,
4206 ext_phy_addr,
4207 MDIO_PMA_DEVAD,
4208 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4209 val);
4210
4211 /* Set 8727 GPIOs to input to allow reading from the
4212 8727 GPIO0 status which reflect SFP+ module
4213 over-current */
4214
4215 bnx2x_cl45_read(bp, params->port,
4216 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4217 ext_phy_addr,
4218 MDIO_PMA_DEVAD,
4219 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4220 &val);
4221 val &= 0xff8f; /* Reset bits 4-6 */
4222 bnx2x_cl45_write(bp, params->port,
4223 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4224 ext_phy_addr,
4225 MDIO_PMA_DEVAD,
4226 MDIO_PMA_REG_8727_PCS_OPT_CTRL,
4227 val);
4228
4229 bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
4230 bnx2x_bcm8073_set_xaui_low_power_mode(params);
4231
4232 bnx2x_cl45_read(bp, params->port,
4233 ext_phy_type,
4234 ext_phy_addr,
4235 MDIO_PMA_DEVAD,
4236 MDIO_PMA_REG_M8051_MSGOUT_REG,
4237 &tmp1);
4238
4239 bnx2x_cl45_read(bp, params->port,
4240 ext_phy_type,
4241 ext_phy_addr,
4242 MDIO_PMA_DEVAD,
4243 MDIO_PMA_REG_RX_ALARM, &tmp1);
4244
4245 /* Set option 1G speed */
4246 if (params->req_line_speed == SPEED_1000) {
4247
4248 DP(NETIF_MSG_LINK, "Setting 1G force\n");
4249 bnx2x_cl45_write(bp, params->port,
4250 ext_phy_type,
4251 ext_phy_addr,
4252 MDIO_PMA_DEVAD,
4253 MDIO_PMA_REG_CTRL, 0x40);
4254 bnx2x_cl45_write(bp, params->port,
4255 ext_phy_type,
4256 ext_phy_addr,
4257 MDIO_PMA_DEVAD,
4258 MDIO_PMA_REG_10G_CTRL2, 0xD);
4259 bnx2x_cl45_read(bp, params->port,
4260 ext_phy_type,
4261 ext_phy_addr,
4262 MDIO_PMA_DEVAD,
4263 MDIO_PMA_REG_10G_CTRL2, &tmp1);
4264 DP(NETIF_MSG_LINK, "1.7 = 0x%x \n", tmp1);
4265
4266 } else if ((params->req_line_speed ==
4267 SPEED_AUTO_NEG) &&
4268 ((params->speed_cap_mask &
4269 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
4270
4271 DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
4272 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4273 ext_phy_addr, MDIO_AN_DEVAD,
4274 MDIO_PMA_REG_8727_MISC_CTRL, 0);
4275 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4276 ext_phy_addr, MDIO_AN_DEVAD,
4277 MDIO_AN_REG_CL37_AN, 0x1300);
4278 } else {
4279 /* Since the 8727 has only single reset pin,
4280 need to set the 10G registers although it is
4281 default */
4282 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4283 ext_phy_addr, MDIO_AN_DEVAD,
4284 MDIO_AN_REG_CTRL, 0x0020);
4285 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4286 ext_phy_addr, MDIO_AN_DEVAD,
4287 0x7, 0x0100);
4288 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4289 ext_phy_addr, MDIO_PMA_DEVAD,
4290 MDIO_PMA_REG_CTRL, 0x2040);
4291 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4292 ext_phy_addr, MDIO_PMA_DEVAD,
4293 MDIO_PMA_REG_10G_CTRL2, 0x0008);
4294 }
4295
4296 /* Set 2-wire transfer rate to 400Khz since 100Khz
4297 is not operational */
4298 bnx2x_cl45_write(bp, params->port,
4299 ext_phy_type,
4300 ext_phy_addr,
4301 MDIO_PMA_DEVAD,
4302 MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
4303 0xa101);
4304
4305 /* Set TX PreEmphasis if needed */
4306 if ((params->feature_config_flags &
4307 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
4308 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
4309 "TX_CTRL2 0x%x\n",
4310 params->xgxs_config_tx[0],
4311 params->xgxs_config_tx[1]);
4312 bnx2x_cl45_write(bp, params->port,
4313 ext_phy_type,
4314 ext_phy_addr,
4315 MDIO_PMA_DEVAD,
4316 MDIO_PMA_REG_8727_TX_CTRL1,
4317 params->xgxs_config_tx[0]);
4318
4319 bnx2x_cl45_write(bp, params->port,
4320 ext_phy_type,
4321 ext_phy_addr,
4322 MDIO_PMA_DEVAD,
4323 MDIO_PMA_REG_8727_TX_CTRL2,
4324 params->xgxs_config_tx[1]);
4325 }
4326
4327 break;
4328 }
4329
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004330 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004331 {
4332 u16 fw_ver1, fw_ver2;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004333 DP(NETIF_MSG_LINK,
4334 "Setting the SFX7101 LASI indication\n");
4335
4336 bnx2x_cl45_write(bp, params->port,
4337 ext_phy_type,
4338 ext_phy_addr,
4339 MDIO_PMA_DEVAD,
4340 MDIO_PMA_REG_LASI_CTRL, 0x1);
4341 DP(NETIF_MSG_LINK,
4342 "Setting the SFX7101 LED to blink on traffic\n");
4343 bnx2x_cl45_write(bp, params->port,
4344 ext_phy_type,
4345 ext_phy_addr,
4346 MDIO_PMA_DEVAD,
4347 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
4348
4349 bnx2x_ext_phy_set_pause(params, vars);
4350 /* Restart autoneg */
4351 bnx2x_cl45_read(bp, params->port,
4352 ext_phy_type,
4353 ext_phy_addr,
4354 MDIO_AN_DEVAD,
4355 MDIO_AN_REG_CTRL, &val);
4356 val |= 0x200;
4357 bnx2x_cl45_write(bp, params->port,
4358 ext_phy_type,
4359 ext_phy_addr,
4360 MDIO_AN_DEVAD,
4361 MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00004362
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004363 /* Save spirom version */
4364 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4365 ext_phy_addr, MDIO_PMA_DEVAD,
4366 MDIO_PMA_REG_7101_VER1, &fw_ver1);
4367
4368 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4369 ext_phy_addr, MDIO_PMA_DEVAD,
4370 MDIO_PMA_REG_7101_VER2, &fw_ver2);
4371
4372 bnx2x_save_spirom_version(params->bp, params->port,
4373 params->shmem_base,
4374 (u32)(fw_ver1<<16 | fw_ver2));
Eilon Greenstein28577182009-02-12 08:37:00 +00004375 break;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004376 }
Eilon Greenstein28577182009-02-12 08:37:00 +00004377 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004378 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
Eilon Greenstein2f904462009-08-12 08:22:16 +00004379 /* This phy uses the NIG latch mechanism since link
4380 indication arrives through its LED4 and not via
4381 its LASI signal, so we get steady signal
4382 instead of clear on read */
4383 bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
4384 1 << NIG_LATCH_BC_ENABLE_MI_INT);
Eilon Greenstein28577182009-02-12 08:37:00 +00004385
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02004386 bnx2x_cl45_write(bp, params->port,
4387 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
4388 ext_phy_addr,
4389 MDIO_PMA_DEVAD,
4390 MDIO_PMA_REG_CTRL, 0x0000);
4391
Eilon Greenstein2f904462009-08-12 08:22:16 +00004392 bnx2x_8481_set_led4(params, ext_phy_type, ext_phy_addr);
4393 if (params->req_line_speed == SPEED_AUTO_NEG) {
Eilon Greenstein28577182009-02-12 08:37:00 +00004394
Eilon Greenstein2f904462009-08-12 08:22:16 +00004395 u16 autoneg_val, an_1000_val, an_10_100_val;
4396 /* set 1000 speed advertisement */
4397 bnx2x_cl45_read(bp, params->port,
4398 ext_phy_type,
4399 ext_phy_addr,
4400 MDIO_AN_DEVAD,
4401 MDIO_AN_REG_8481_1000T_CTRL,
4402 &an_1000_val);
4403
4404 if (params->speed_cap_mask &
4405 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) {
4406 an_1000_val |= (1<<8);
4407 if (params->req_duplex == DUPLEX_FULL)
4408 an_1000_val |= (1<<9);
4409 DP(NETIF_MSG_LINK, "Advertising 1G\n");
4410 } else
4411 an_1000_val &= ~((1<<8) | (1<<9));
4412
4413 bnx2x_cl45_write(bp, params->port,
4414 ext_phy_type,
4415 ext_phy_addr,
4416 MDIO_AN_DEVAD,
4417 MDIO_AN_REG_8481_1000T_CTRL,
4418 an_1000_val);
4419
4420 /* set 100 speed advertisement */
4421 bnx2x_cl45_read(bp, params->port,
4422 ext_phy_type,
4423 ext_phy_addr,
4424 MDIO_AN_DEVAD,
4425 MDIO_AN_REG_8481_LEGACY_AN_ADV,
4426 &an_10_100_val);
4427
4428 if (params->speed_cap_mask &
4429 (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
4430 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) {
4431 an_10_100_val |= (1<<7);
4432 if (params->req_duplex == DUPLEX_FULL)
4433 an_10_100_val |= (1<<8);
4434 DP(NETIF_MSG_LINK,
4435 "Advertising 100M\n");
4436 } else
4437 an_10_100_val &= ~((1<<7) | (1<<8));
4438
4439 /* set 10 speed advertisement */
4440 if (params->speed_cap_mask &
4441 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
4442 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) {
4443 an_10_100_val |= (1<<5);
4444 if (params->req_duplex == DUPLEX_FULL)
4445 an_10_100_val |= (1<<6);
4446 DP(NETIF_MSG_LINK, "Advertising 10M\n");
4447 }
4448 else
4449 an_10_100_val &= ~((1<<5) | (1<<6));
4450
4451 bnx2x_cl45_write(bp, params->port,
4452 ext_phy_type,
4453 ext_phy_addr,
4454 MDIO_AN_DEVAD,
4455 MDIO_AN_REG_8481_LEGACY_AN_ADV,
4456 an_10_100_val);
4457
4458 bnx2x_cl45_read(bp, params->port,
4459 ext_phy_type,
4460 ext_phy_addr,
4461 MDIO_AN_DEVAD,
4462 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4463 &autoneg_val);
4464
4465 /* Disable forced speed */
4466 autoneg_val &= ~(1<<6|1<<13);
4467
4468 /* Enable autoneg and restart autoneg
4469 for legacy speeds */
4470 autoneg_val |= (1<<9|1<<12);
4471
4472 if (params->req_duplex == DUPLEX_FULL)
4473 autoneg_val |= (1<<8);
4474 else
4475 autoneg_val &= ~(1<<8);
4476
4477 bnx2x_cl45_write(bp, params->port,
4478 ext_phy_type,
4479 ext_phy_addr,
4480 MDIO_AN_DEVAD,
4481 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4482 autoneg_val);
4483
4484 if (params->speed_cap_mask &
4485 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) {
4486 DP(NETIF_MSG_LINK, "Advertising 10G\n");
4487 /* Restart autoneg for 10G*/
Eilon Greenstein28577182009-02-12 08:37:00 +00004488 bnx2x_cl45_read(bp, params->port,
4489 ext_phy_type,
4490 ext_phy_addr,
4491 MDIO_AN_DEVAD,
4492 MDIO_AN_REG_CTRL, &val);
4493 val |= 0x200;
4494 bnx2x_cl45_write(bp, params->port,
4495 ext_phy_type,
4496 ext_phy_addr,
4497 MDIO_AN_DEVAD,
4498 MDIO_AN_REG_CTRL, val);
Eilon Greenstein2f904462009-08-12 08:22:16 +00004499 }
4500 } else {
4501 /* Force speed */
4502 u16 autoneg_ctrl, pma_ctrl;
4503 bnx2x_cl45_read(bp, params->port,
4504 ext_phy_type,
4505 ext_phy_addr,
4506 MDIO_AN_DEVAD,
4507 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4508 &autoneg_ctrl);
4509
4510 /* Disable autoneg */
4511 autoneg_ctrl &= ~(1<<12);
4512
4513 /* Set 1000 force */
4514 switch (params->req_line_speed) {
4515 case SPEED_10000:
4516 DP(NETIF_MSG_LINK,
4517 "Unable to set 10G force !\n");
4518 break;
4519 case SPEED_1000:
4520 bnx2x_cl45_read(bp, params->port,
4521 ext_phy_type,
4522 ext_phy_addr,
4523 MDIO_PMA_DEVAD,
4524 MDIO_PMA_REG_CTRL,
4525 &pma_ctrl);
4526 autoneg_ctrl &= ~(1<<13);
4527 autoneg_ctrl |= (1<<6);
4528 pma_ctrl &= ~(1<<13);
4529 pma_ctrl |= (1<<6);
4530 DP(NETIF_MSG_LINK,
4531 "Setting 1000M force\n");
4532 bnx2x_cl45_write(bp, params->port,
4533 ext_phy_type,
4534 ext_phy_addr,
4535 MDIO_PMA_DEVAD,
4536 MDIO_PMA_REG_CTRL,
4537 pma_ctrl);
4538 break;
4539 case SPEED_100:
4540 autoneg_ctrl |= (1<<13);
4541 autoneg_ctrl &= ~(1<<6);
4542 DP(NETIF_MSG_LINK,
4543 "Setting 100M force\n");
4544 break;
4545 case SPEED_10:
4546 autoneg_ctrl &= ~(1<<13);
4547 autoneg_ctrl &= ~(1<<6);
4548 DP(NETIF_MSG_LINK,
4549 "Setting 10M force\n");
4550 break;
4551 }
4552
4553 /* Duplex mode */
4554 if (params->req_duplex == DUPLEX_FULL) {
4555 autoneg_ctrl |= (1<<8);
4556 DP(NETIF_MSG_LINK,
4557 "Setting full duplex\n");
4558 } else
4559 autoneg_ctrl &= ~(1<<8);
4560
4561 /* Update autoneg ctrl and pma ctrl */
4562 bnx2x_cl45_write(bp, params->port,
4563 ext_phy_type,
4564 ext_phy_addr,
4565 MDIO_AN_DEVAD,
4566 MDIO_AN_REG_8481_LEGACY_MII_CTRL,
4567 autoneg_ctrl);
4568 }
Eilon Greenstein28577182009-02-12 08:37:00 +00004569
Eilon Greensteinb1607af2009-08-12 08:22:54 +00004570 /* Save spirom version */
4571 bnx2x_save_8481_spirom_version(bp, params->port,
4572 ext_phy_addr,
4573 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004574 break;
4575 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4576 DP(NETIF_MSG_LINK,
4577 "XGXS PHY Failure detected 0x%x\n",
4578 params->ext_phy_config);
4579 rc = -EINVAL;
4580 break;
4581 default:
4582 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
4583 params->ext_phy_config);
4584 rc = -EINVAL;
4585 break;
4586 }
4587
4588 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004589
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004590 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4591 switch (ext_phy_type) {
4592 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
4593 DP(NETIF_MSG_LINK, "SerDes Direct\n");
4594 break;
4595
4596 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
4597 DP(NETIF_MSG_LINK, "SerDes 5482\n");
4598 break;
4599
4600 default:
4601 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
4602 params->ext_phy_config);
4603 break;
4604 }
4605 }
4606 return rc;
4607}
4608
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004609static void bnx2x_8727_handle_mod_abs(struct link_params *params)
4610{
4611 struct bnx2x *bp = params->bp;
4612 u16 mod_abs, rx_alarm_status;
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00004613 u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004614 u32 val = REG_RD(bp, params->shmem_base +
4615 offsetof(struct shmem_region, dev_info.
4616 port_feature_config[params->port].
4617 config));
4618 bnx2x_cl45_read(bp, params->port,
4619 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4620 ext_phy_addr,
4621 MDIO_PMA_DEVAD,
4622 MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
4623 if (mod_abs & (1<<8)) {
4624
4625 /* Module is absent */
4626 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4627 "show module is absent\n");
4628
4629 /* 1. Set mod_abs to detect next module
4630 presence event
4631 2. Set EDC off by setting OPTXLOS signal input to low
4632 (bit 9).
4633 When the EDC is off it locks onto a reference clock and
4634 avoids becoming 'lost'.*/
4635 mod_abs &= ~((1<<8)|(1<<9));
4636 bnx2x_cl45_write(bp, params->port,
4637 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4638 ext_phy_addr,
4639 MDIO_PMA_DEVAD,
4640 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4641
4642 /* Clear RX alarm since it stays up as long as
4643 the mod_abs wasn't changed */
4644 bnx2x_cl45_read(bp, params->port,
4645 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4646 ext_phy_addr,
4647 MDIO_PMA_DEVAD,
4648 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4649
4650 } else {
4651 /* Module is present */
4652 DP(NETIF_MSG_LINK, "MOD_ABS indication "
4653 "show module is present\n");
4654 /* First thing, disable transmitter,
4655 and if the module is ok, the
4656 module_detection will enable it*/
4657
4658 /* 1. Set mod_abs to detect next module
4659 absent event ( bit 8)
4660 2. Restore the default polarity of the OPRXLOS signal and
4661 this signal will then correctly indicate the presence or
4662 absence of the Rx signal. (bit 9) */
4663 mod_abs |= ((1<<8)|(1<<9));
4664 bnx2x_cl45_write(bp, params->port,
4665 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4666 ext_phy_addr,
4667 MDIO_PMA_DEVAD,
4668 MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
4669
4670 /* Clear RX alarm since it stays up as long as
4671 the mod_abs wasn't changed. This is need to be done
4672 before calling the module detection, otherwise it will clear
4673 the link update alarm */
4674 bnx2x_cl45_read(bp, params->port,
4675 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4676 ext_phy_addr,
4677 MDIO_PMA_DEVAD,
4678 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4679
4680
4681 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
4682 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
4683 bnx2x_sfp_set_transmitter(bp, params->port,
4684 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
4685 ext_phy_addr, 0);
4686
4687 if (bnx2x_wait_for_sfp_module_initialized(params)
4688 == 0)
4689 bnx2x_sfp_module_detection(params);
4690 else
4691 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
4692 }
4693
4694 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
4695 rx_alarm_status);
4696 /* No need to check link status in case of
4697 module plugged in/out */
4698}
4699
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004700
4701static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00004702 struct link_vars *vars,
4703 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004704{
4705 struct bnx2x *bp = params->bp;
4706 u32 ext_phy_type;
4707 u8 ext_phy_addr;
4708 u16 val1 = 0, val2;
4709 u16 rx_sd, pcs_status;
4710 u8 ext_phy_link_up = 0;
4711 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004712
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004713 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00004714 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004715 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4716 switch (ext_phy_type) {
4717 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4718 DP(NETIF_MSG_LINK, "XGXS Direct\n");
4719 ext_phy_link_up = 1;
4720 break;
4721
4722 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4723 DP(NETIF_MSG_LINK, "XGXS 8705\n");
4724 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4725 ext_phy_addr,
4726 MDIO_WIS_DEVAD,
4727 MDIO_WIS_REG_LASI_STATUS, &val1);
4728 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4729
4730 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4731 ext_phy_addr,
4732 MDIO_WIS_DEVAD,
4733 MDIO_WIS_REG_LASI_STATUS, &val1);
4734 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
4735
4736 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4737 ext_phy_addr,
4738 MDIO_PMA_DEVAD,
4739 MDIO_PMA_REG_RX_SD, &rx_sd);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004740
4741 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4742 ext_phy_addr,
4743 1,
4744 0xc809, &val1);
4745 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4746 ext_phy_addr,
4747 1,
4748 0xc809, &val1);
4749
4750 DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
4751 ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9))
4752 && ((val1 & (1<<8)) == 0));
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004753 if (ext_phy_link_up)
4754 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004755 break;
4756
4757 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00004758 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4759 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
4760 /* Clear RX Alarm*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004761 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4762 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00004763 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
4764 &val2);
4765 /* clear LASI indication*/
4766 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4767 ext_phy_addr,
4768 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
4769 &val1);
4770 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4771 ext_phy_addr,
4772 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
4773 &val2);
4774 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
4775 "0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004776
4777 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4778 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00004779 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
4780 &rx_sd);
4781 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4782 ext_phy_addr,
4783 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
4784 &pcs_status);
4785 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4786 ext_phy_addr,
4787 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
4788 &val2);
4789 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4790 ext_phy_addr,
4791 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
4792 &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004793
Eilon Greenstein589abe32009-02-12 08:36:55 +00004794 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004795 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
4796 rx_sd, pcs_status, val2);
4797 /* link is up if both bit 0 of pmd_rx_sd and
4798 * bit 0 of pcs_status are set, or if the autoneg bit
4799 1 is set
4800 */
4801 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
4802 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004803 if (ext_phy_link_up) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00004804 if (ext_phy_type ==
4805 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
4806 /* If transmitter is disabled,
4807 ignore false link up indication */
4808 bnx2x_cl45_read(bp, params->port,
4809 ext_phy_type,
4810 ext_phy_addr,
4811 MDIO_PMA_DEVAD,
4812 MDIO_PMA_REG_PHY_IDENTIFIER,
4813 &val1);
4814 if (val1 & (1<<15)) {
4815 DP(NETIF_MSG_LINK, "Tx is "
4816 "disabled\n");
4817 ext_phy_link_up = 0;
4818 break;
4819 }
4820 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004821 if (val2 & (1<<1))
4822 vars->line_speed = SPEED_1000;
4823 else
4824 vars->line_speed = SPEED_10000;
4825 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004826 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004827
4828 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
4829 {
4830 u16 link_status = 0;
4831 u16 rx_alarm_status;
4832 /* Check the LASI */
4833 bnx2x_cl45_read(bp, params->port,
4834 ext_phy_type,
4835 ext_phy_addr,
4836 MDIO_PMA_DEVAD,
4837 MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
4838
4839 DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
4840 rx_alarm_status);
4841
4842 bnx2x_cl45_read(bp, params->port,
4843 ext_phy_type,
4844 ext_phy_addr,
4845 MDIO_PMA_DEVAD,
4846 MDIO_PMA_REG_LASI_STATUS, &val1);
4847
4848 DP(NETIF_MSG_LINK,
4849 "8727 LASI status 0x%x\n",
4850 val1);
4851
4852 /* Clear MSG-OUT */
4853 bnx2x_cl45_read(bp, params->port,
4854 ext_phy_type,
4855 ext_phy_addr,
4856 MDIO_PMA_DEVAD,
4857 MDIO_PMA_REG_M8051_MSGOUT_REG,
4858 &val1);
4859
4860 /*
4861 * If a module is present and there is need to check
4862 * for over current
4863 */
4864 if (!(params->feature_config_flags &
4865 FEATURE_CONFIG_BCM8727_NOC) &&
4866 !(rx_alarm_status & (1<<5))) {
4867 /* Check over-current using 8727 GPIO0 input*/
4868 bnx2x_cl45_read(bp, params->port,
4869 ext_phy_type,
4870 ext_phy_addr,
4871 MDIO_PMA_DEVAD,
4872 MDIO_PMA_REG_8727_GPIO_CTRL,
4873 &val1);
4874
4875 if ((val1 & (1<<8)) == 0) {
4876 DP(NETIF_MSG_LINK, "8727 Power fault"
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004877 " has been detected on "
4878 "port %d\n",
4879 params->port);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00004880 printk(KERN_ERR PFX "Error: Power"
4881 " fault on %s Port %d has"
4882 " been detected and the"
4883 " power to that SFP+ module"
4884 " has been removed to prevent"
4885 " failure of the card. Please"
4886 " remove the SFP+ module and"
4887 " restart the system to clear"
4888 " this error.\n"
4889 , bp->dev->name, params->port);
4890 /*
4891 * Disable all RX_ALARMs except for
4892 * mod_abs
4893 */
4894 bnx2x_cl45_write(bp, params->port,
4895 ext_phy_type,
4896 ext_phy_addr,
4897 MDIO_PMA_DEVAD,
4898 MDIO_PMA_REG_RX_ALARM_CTRL,
4899 (1<<5));
4900
4901 bnx2x_cl45_read(bp, params->port,
4902 ext_phy_type,
4903 ext_phy_addr,
4904 MDIO_PMA_DEVAD,
4905 MDIO_PMA_REG_PHY_IDENTIFIER,
4906 &val1);
4907 /* Wait for module_absent_event */
4908 val1 |= (1<<8);
4909 bnx2x_cl45_write(bp, params->port,
4910 ext_phy_type,
4911 ext_phy_addr,
4912 MDIO_PMA_DEVAD,
4913 MDIO_PMA_REG_PHY_IDENTIFIER,
4914 val1);
4915 /* Clear RX alarm */
4916 bnx2x_cl45_read(bp, params->port,
4917 ext_phy_type,
4918 ext_phy_addr,
4919 MDIO_PMA_DEVAD,
4920 MDIO_PMA_REG_RX_ALARM,
4921 &rx_alarm_status);
4922 break;
4923 }
4924 } /* Over current check */
4925
4926 /* When module absent bit is set, check module */
4927 if (rx_alarm_status & (1<<5)) {
4928 bnx2x_8727_handle_mod_abs(params);
4929 /* Enable all mod_abs and link detection bits */
4930 bnx2x_cl45_write(bp, params->port,
4931 ext_phy_type,
4932 ext_phy_addr,
4933 MDIO_PMA_DEVAD,
4934 MDIO_PMA_REG_RX_ALARM_CTRL,
4935 ((1<<5) | (1<<2)));
4936 }
4937
4938 /* If transmitter is disabled,
4939 ignore false link up indication */
4940 bnx2x_cl45_read(bp, params->port,
4941 ext_phy_type,
4942 ext_phy_addr,
4943 MDIO_PMA_DEVAD,
4944 MDIO_PMA_REG_PHY_IDENTIFIER,
4945 &val1);
4946 if (val1 & (1<<15)) {
4947 DP(NETIF_MSG_LINK, "Tx is disabled\n");
4948 ext_phy_link_up = 0;
4949 break;
4950 }
4951
4952 bnx2x_cl45_read(bp, params->port,
4953 ext_phy_type,
4954 ext_phy_addr,
4955 MDIO_PMA_DEVAD,
4956 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
4957 &link_status);
4958
4959 /* Bits 0..2 --> speed detected,
4960 bits 13..15--> link is down */
4961 if ((link_status & (1<<2)) &&
4962 (!(link_status & (1<<15)))) {
4963 ext_phy_link_up = 1;
4964 vars->line_speed = SPEED_10000;
4965 } else if ((link_status & (1<<0)) &&
4966 (!(link_status & (1<<13)))) {
4967 ext_phy_link_up = 1;
4968 vars->line_speed = SPEED_1000;
4969 DP(NETIF_MSG_LINK,
4970 "port %x: External link"
4971 " up in 1G\n", params->port);
4972 } else {
4973 ext_phy_link_up = 0;
4974 DP(NETIF_MSG_LINK,
4975 "port %x: External link"
4976 " is down\n", params->port);
4977 }
4978 break;
4979 }
4980
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004981 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4982 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4983 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004984 u16 link_status = 0;
4985 u16 an1000_status = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00004986
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004987 if (ext_phy_type ==
4988 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
4989 bnx2x_cl45_read(bp, params->port,
4990 ext_phy_type,
4991 ext_phy_addr,
4992 MDIO_PCS_DEVAD,
4993 MDIO_PCS_REG_LASI_STATUS, &val1);
4994 bnx2x_cl45_read(bp, params->port,
4995 ext_phy_type,
4996 ext_phy_addr,
4997 MDIO_PCS_DEVAD,
4998 MDIO_PCS_REG_LASI_STATUS, &val2);
4999 DP(NETIF_MSG_LINK,
5000 "870x LASI status 0x%x->0x%x\n",
5001 val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005002 } else {
5003 /* In 8073, port1 is directed through emac0 and
5004 * port0 is directed through emac1
5005 */
5006 bnx2x_cl45_read(bp, params->port,
5007 ext_phy_type,
5008 ext_phy_addr,
5009 MDIO_PMA_DEVAD,
5010 MDIO_PMA_REG_LASI_STATUS, &val1);
5011
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005012 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005013 "8703 LASI status 0x%x\n",
5014 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005015 }
5016
5017 /* clear the interrupt LASI status register */
5018 bnx2x_cl45_read(bp, params->port,
5019 ext_phy_type,
5020 ext_phy_addr,
5021 MDIO_PCS_DEVAD,
5022 MDIO_PCS_REG_STATUS, &val2);
5023 bnx2x_cl45_read(bp, params->port,
5024 ext_phy_type,
5025 ext_phy_addr,
5026 MDIO_PCS_DEVAD,
5027 MDIO_PCS_REG_STATUS, &val1);
5028 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
5029 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005030 /* Clear MSG-OUT */
5031 bnx2x_cl45_read(bp, params->port,
5032 ext_phy_type,
5033 ext_phy_addr,
5034 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005035 MDIO_PMA_REG_M8051_MSGOUT_REG,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005036 &val1);
5037
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005038 /* Check the LASI */
5039 bnx2x_cl45_read(bp, params->port,
5040 ext_phy_type,
5041 ext_phy_addr,
5042 MDIO_PMA_DEVAD,
5043 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005044
5045 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
5046
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005047 /* Check the link status */
5048 bnx2x_cl45_read(bp, params->port,
5049 ext_phy_type,
5050 ext_phy_addr,
5051 MDIO_PCS_DEVAD,
5052 MDIO_PCS_REG_STATUS, &val2);
5053 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
5054
5055 bnx2x_cl45_read(bp, params->port,
5056 ext_phy_type,
5057 ext_phy_addr,
5058 MDIO_PMA_DEVAD,
5059 MDIO_PMA_REG_STATUS, &val2);
5060 bnx2x_cl45_read(bp, params->port,
5061 ext_phy_type,
5062 ext_phy_addr,
5063 MDIO_PMA_DEVAD,
5064 MDIO_PMA_REG_STATUS, &val1);
5065 ext_phy_link_up = ((val1 & 4) == 4);
5066 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
5067 if (ext_phy_type ==
5068 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005069
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005070 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005071 ((params->req_line_speed !=
5072 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005073 if (bnx2x_bcm8073_xaui_wa(params)
5074 != 0) {
5075 ext_phy_link_up = 0;
5076 break;
5077 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005078 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005079 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005080 ext_phy_type,
5081 ext_phy_addr,
5082 MDIO_AN_DEVAD,
5083 MDIO_AN_REG_LINK_STATUS,
5084 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005085 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005086 ext_phy_type,
5087 ext_phy_addr,
5088 MDIO_AN_DEVAD,
5089 MDIO_AN_REG_LINK_STATUS,
5090 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005091
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005092 /* Check the link status on 1.1.2 */
5093 bnx2x_cl45_read(bp, params->port,
5094 ext_phy_type,
5095 ext_phy_addr,
5096 MDIO_PMA_DEVAD,
5097 MDIO_PMA_REG_STATUS, &val2);
5098 bnx2x_cl45_read(bp, params->port,
5099 ext_phy_type,
5100 ext_phy_addr,
5101 MDIO_PMA_DEVAD,
5102 MDIO_PMA_REG_STATUS, &val1);
5103 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
5104 "an_link_status=0x%x\n",
5105 val2, val1, an1000_status);
5106
Eilon Greenstein356e2382009-02-12 08:38:32 +00005107 ext_phy_link_up = (((val1 & 4) == 4) ||
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005108 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005109 if (ext_phy_link_up &&
5110 bnx2x_8073_is_snr_needed(params)) {
5111 /* The SNR will improve about 2dbby
5112 changing the BW and FEE main tap.*/
5113
5114 /* The 1st write to change FFE main
5115 tap is set before restart AN */
5116 /* Change PLL Bandwidth in EDC
5117 register */
5118 bnx2x_cl45_write(bp, port, ext_phy_type,
5119 ext_phy_addr,
5120 MDIO_PMA_DEVAD,
5121 MDIO_PMA_REG_PLL_BANDWIDTH,
5122 0x26BC);
5123
5124 /* Change CDR Bandwidth in EDC
5125 register */
5126 bnx2x_cl45_write(bp, port, ext_phy_type,
5127 ext_phy_addr,
5128 MDIO_PMA_DEVAD,
5129 MDIO_PMA_REG_CDR_BANDWIDTH,
5130 0x0333);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005131 }
5132 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005133 ext_phy_type,
5134 ext_phy_addr,
5135 MDIO_PMA_DEVAD,
5136 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
5137 &link_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005138
5139 /* Bits 0..2 --> speed detected,
5140 bits 13..15--> link is down */
5141 if ((link_status & (1<<2)) &&
5142 (!(link_status & (1<<15)))) {
5143 ext_phy_link_up = 1;
5144 vars->line_speed = SPEED_10000;
5145 DP(NETIF_MSG_LINK,
5146 "port %x: External link"
5147 " up in 10G\n", params->port);
5148 } else if ((link_status & (1<<1)) &&
5149 (!(link_status & (1<<14)))) {
5150 ext_phy_link_up = 1;
5151 vars->line_speed = SPEED_2500;
5152 DP(NETIF_MSG_LINK,
5153 "port %x: External link"
5154 " up in 2.5G\n", params->port);
5155 } else if ((link_status & (1<<0)) &&
5156 (!(link_status & (1<<13)))) {
5157 ext_phy_link_up = 1;
5158 vars->line_speed = SPEED_1000;
5159 DP(NETIF_MSG_LINK,
5160 "port %x: External link"
5161 " up in 1G\n", params->port);
5162 } else {
5163 ext_phy_link_up = 0;
5164 DP(NETIF_MSG_LINK,
5165 "port %x: External link"
5166 " is down\n", params->port);
5167 }
5168 } else {
5169 /* See if 1G link is up for the 8072 */
5170 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005171 ext_phy_type,
5172 ext_phy_addr,
5173 MDIO_AN_DEVAD,
5174 MDIO_AN_REG_LINK_STATUS,
5175 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005176 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00005177 ext_phy_type,
5178 ext_phy_addr,
5179 MDIO_AN_DEVAD,
5180 MDIO_AN_REG_LINK_STATUS,
5181 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005182 if (an1000_status & (1<<1)) {
5183 ext_phy_link_up = 1;
5184 vars->line_speed = SPEED_1000;
5185 DP(NETIF_MSG_LINK,
5186 "port %x: External link"
5187 " up in 1G\n", params->port);
5188 } else if (ext_phy_link_up) {
5189 ext_phy_link_up = 1;
5190 vars->line_speed = SPEED_10000;
5191 DP(NETIF_MSG_LINK,
5192 "port %x: External link"
5193 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005194 }
5195 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005196
5197
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005198 break;
5199 }
5200 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5201 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5202 ext_phy_addr,
5203 MDIO_PMA_DEVAD,
5204 MDIO_PMA_REG_LASI_STATUS, &val2);
5205 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5206 ext_phy_addr,
5207 MDIO_PMA_DEVAD,
5208 MDIO_PMA_REG_LASI_STATUS, &val1);
5209 DP(NETIF_MSG_LINK,
5210 "10G-base-T LASI status 0x%x->0x%x\n",
5211 val2, val1);
5212 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5213 ext_phy_addr,
5214 MDIO_PMA_DEVAD,
5215 MDIO_PMA_REG_STATUS, &val2);
5216 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5217 ext_phy_addr,
5218 MDIO_PMA_DEVAD,
5219 MDIO_PMA_REG_STATUS, &val1);
5220 DP(NETIF_MSG_LINK,
5221 "10G-base-T PMA status 0x%x->0x%x\n",
5222 val2, val1);
5223 ext_phy_link_up = ((val1 & 4) == 4);
5224 /* if link is up
5225 * print the AN outcome of the SFX7101 PHY
5226 */
5227 if (ext_phy_link_up) {
5228 bnx2x_cl45_read(bp, params->port,
5229 ext_phy_type,
5230 ext_phy_addr,
5231 MDIO_AN_DEVAD,
5232 MDIO_AN_REG_MASTER_STATUS,
5233 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005234 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005235 DP(NETIF_MSG_LINK,
5236 "SFX7101 AN status 0x%x->Master=%x\n",
5237 val2,
5238 (val2 & (1<<14)));
5239 }
5240 break;
Eilon Greenstein28577182009-02-12 08:37:00 +00005241 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02005242 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
Eilon Greenstein2f904462009-08-12 08:22:16 +00005243 /* Check 10G-BaseT link status */
5244 /* Check PMD signal ok */
5245 bnx2x_cl45_read(bp, params->port, ext_phy_type,
5246 ext_phy_addr,
5247 MDIO_AN_DEVAD,
5248 0xFFFA,
5249 &val1);
5250 bnx2x_cl45_read(bp, params->port, ext_phy_type,
Eilon Greenstein28577182009-02-12 08:37:00 +00005251 ext_phy_addr,
5252 MDIO_PMA_DEVAD,
Eilon Greenstein2f904462009-08-12 08:22:16 +00005253 MDIO_PMA_REG_8481_PMD_SIGNAL,
5254 &val2);
5255 DP(NETIF_MSG_LINK, "PMD_SIGNAL 1.a811 = 0x%x\n", val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005256
Eilon Greenstein2f904462009-08-12 08:22:16 +00005257 /* Check link 10G */
5258 if (val2 & (1<<11)) {
Eilon Greenstein28577182009-02-12 08:37:00 +00005259 vars->line_speed = SPEED_10000;
5260 ext_phy_link_up = 1;
Eilon Greenstein2f904462009-08-12 08:22:16 +00005261 bnx2x_8481_set_10G_led_mode(params,
5262 ext_phy_type,
5263 ext_phy_addr);
5264 } else { /* Check Legacy speed link */
5265 u16 legacy_status, legacy_speed;
Eilon Greenstein28577182009-02-12 08:37:00 +00005266
Eilon Greenstein2f904462009-08-12 08:22:16 +00005267 /* Enable expansion register 0x42
5268 (Operation mode status) */
5269 bnx2x_cl45_write(bp, params->port,
5270 ext_phy_type,
5271 ext_phy_addr,
5272 MDIO_AN_DEVAD,
5273 MDIO_AN_REG_8481_EXPANSION_REG_ACCESS,
5274 0xf42);
Eilon Greenstein28577182009-02-12 08:37:00 +00005275
Eilon Greenstein2f904462009-08-12 08:22:16 +00005276 /* Get legacy speed operation status */
5277 bnx2x_cl45_read(bp, params->port,
5278 ext_phy_type,
5279 ext_phy_addr,
5280 MDIO_AN_DEVAD,
5281 MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
5282 &legacy_status);
5283
5284 DP(NETIF_MSG_LINK, "Legacy speed status"
5285 " = 0x%x\n", legacy_status);
5286 ext_phy_link_up = ((legacy_status & (1<<11))
5287 == (1<<11));
5288 if (ext_phy_link_up) {
5289 legacy_speed = (legacy_status & (3<<9));
5290 if (legacy_speed == (0<<9))
5291 vars->line_speed = SPEED_10;
5292 else if (legacy_speed == (1<<9))
5293 vars->line_speed =
5294 SPEED_100;
5295 else if (legacy_speed == (2<<9))
5296 vars->line_speed =
5297 SPEED_1000;
5298 else /* Should not happen */
5299 vars->line_speed = 0;
5300
5301 if (legacy_status & (1<<8))
5302 vars->duplex = DUPLEX_FULL;
5303 else
5304 vars->duplex = DUPLEX_HALF;
5305
5306 DP(NETIF_MSG_LINK, "Link is up "
5307 "in %dMbps, is_duplex_full"
5308 "= %d\n",
5309 vars->line_speed,
5310 (vars->duplex == DUPLEX_FULL));
5311 bnx2x_8481_set_legacy_led_mode(params,
5312 ext_phy_type,
5313 ext_phy_addr);
Eilon Greenstein28577182009-02-12 08:37:00 +00005314 }
5315 }
Eilon Greenstein28577182009-02-12 08:37:00 +00005316 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005317 default:
5318 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
5319 params->ext_phy_config);
5320 ext_phy_link_up = 0;
5321 break;
5322 }
Eilon Greenstein57937202009-08-12 08:23:53 +00005323 /* Set SGMII mode for external phy */
5324 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
5325 if (vars->line_speed < SPEED_1000)
5326 vars->phy_flags |= PHY_SGMII_FLAG;
5327 else
5328 vars->phy_flags &= ~PHY_SGMII_FLAG;
5329 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005330
5331 } else { /* SerDes */
5332 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5333 switch (ext_phy_type) {
5334 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
5335 DP(NETIF_MSG_LINK, "SerDes Direct\n");
5336 ext_phy_link_up = 1;
5337 break;
5338
5339 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
5340 DP(NETIF_MSG_LINK, "SerDes 5482\n");
5341 ext_phy_link_up = 1;
5342 break;
5343
5344 default:
5345 DP(NETIF_MSG_LINK,
5346 "BAD SerDes ext_phy_config 0x%x\n",
5347 params->ext_phy_config);
5348 ext_phy_link_up = 0;
5349 break;
5350 }
5351 }
5352
5353 return ext_phy_link_up;
5354}
5355
5356static void bnx2x_link_int_enable(struct link_params *params)
5357{
5358 u8 port = params->port;
5359 u32 ext_phy_type;
5360 u32 mask;
5361 struct bnx2x *bp = params->bp;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005362
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005363 /* setting the status to report on link up
5364 for either XGXS or SerDes */
5365
5366 if (params->switch_cfg == SWITCH_CFG_10G) {
5367 mask = (NIG_MASK_XGXS0_LINK10G |
5368 NIG_MASK_XGXS0_LINK_STATUS);
5369 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
5370 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
5371 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
5372 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
5373 (ext_phy_type !=
5374 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
5375 mask |= NIG_MASK_MI_INT;
5376 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5377 }
5378
5379 } else { /* SerDes */
5380 mask = NIG_MASK_SERDES0_LINK_STATUS;
5381 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
5382 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5383 if ((ext_phy_type !=
5384 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
5385 (ext_phy_type !=
5386 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
5387 mask |= NIG_MASK_MI_INT;
5388 DP(NETIF_MSG_LINK, "enabled external phy int\n");
5389 }
5390 }
5391 bnx2x_bits_en(bp,
5392 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5393 mask);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005394
5395 DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005396 (params->switch_cfg == SWITCH_CFG_10G),
5397 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005398 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
5399 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5400 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
5401 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
5402 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5403 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5404 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5405}
5406
Eilon Greenstein2f904462009-08-12 08:22:16 +00005407static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port,
5408 u8 is_mi_int)
5409{
5410 u32 latch_status = 0, is_mi_int_status;
5411 /* Disable the MI INT ( external phy int )
5412 * by writing 1 to the status register. Link down indication
5413 * is high-active-signal, so in this case we need to write the
5414 * status to clear the XOR
5415 */
5416 /* Read Latched signals */
5417 latch_status = REG_RD(bp,
5418 NIG_REG_LATCH_STATUS_0 + port*8);
5419 is_mi_int_status = REG_RD(bp,
5420 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4);
5421 DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x,"
5422 "latch_status = 0x%x\n",
5423 is_mi_int, is_mi_int_status, latch_status);
5424 /* Handle only those with latched-signal=up.*/
5425 if (latch_status & 1) {
5426 /* For all latched-signal=up,Write original_signal to status */
5427 if (is_mi_int)
5428 bnx2x_bits_en(bp,
5429 NIG_REG_STATUS_INTERRUPT_PORT0
5430 + port*4,
5431 NIG_STATUS_EMAC0_MI_INT);
5432 else
5433 bnx2x_bits_dis(bp,
5434 NIG_REG_STATUS_INTERRUPT_PORT0
5435 + port*4,
5436 NIG_STATUS_EMAC0_MI_INT);
5437 /* For all latched-signal=up : Re-Arm Latch signals */
5438 REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
5439 (latch_status & 0xfffe) | (latch_status & 1));
5440 }
5441}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005442/*
5443 * link management
5444 */
5445static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein2f904462009-08-12 08:22:16 +00005446 struct link_vars *vars, u8 is_10g,
5447 u8 is_mi_int)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005448{
5449 struct bnx2x *bp = params->bp;
5450 u8 port = params->port;
5451
5452 /* first reset all status
5453 * we assume only one line will be change at a time */
5454 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5455 (NIG_STATUS_XGXS0_LINK10G |
5456 NIG_STATUS_XGXS0_LINK_STATUS |
5457 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02005458 if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config)
5459 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) ||
5460 (XGXS_EXT_PHY_TYPE(params->ext_phy_config)
5461 == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) {
Eilon Greenstein2f904462009-08-12 08:22:16 +00005462 bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int);
5463 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005464 if (vars->phy_link_up) {
5465 if (is_10g) {
5466 /* Disable the 10G link interrupt
5467 * by writing 1 to the status register
5468 */
5469 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
5470 bnx2x_bits_en(bp,
5471 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5472 NIG_STATUS_XGXS0_LINK10G);
5473
5474 } else if (params->switch_cfg == SWITCH_CFG_10G) {
5475 /* Disable the link interrupt
5476 * by writing 1 to the relevant lane
5477 * in the status register
5478 */
5479 u32 ser_lane = ((params->lane_config &
5480 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
5481 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
5482
Eilon Greenstein2f904462009-08-12 08:22:16 +00005483 DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
5484 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005485 bnx2x_bits_en(bp,
5486 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5487 ((1 << ser_lane) <<
5488 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
5489
5490 } else { /* SerDes */
5491 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
5492 /* Disable the link interrupt
5493 * by writing 1 to the status register
5494 */
5495 bnx2x_bits_en(bp,
5496 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
5497 NIG_STATUS_SERDES0_LINK_STATUS);
5498 }
5499
5500 } else { /* link_down */
5501 }
5502}
5503
5504static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
5505{
5506 u8 *str_ptr = str;
5507 u32 mask = 0xf0000000;
5508 u8 shift = 8*4;
5509 u8 digit;
5510 if (len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02005511 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005512 *str_ptr = '\0';
5513 return -EINVAL;
5514 }
5515 while (shift > 0) {
5516
5517 shift -= 4;
5518 digit = ((num & mask) >> shift);
5519 if (digit < 0xa)
5520 *str_ptr = digit + '0';
5521 else
5522 *str_ptr = digit - 0xa + 'a';
5523 str_ptr++;
5524 mask = mask >> 4;
5525 if (shift == 4*4) {
5526 *str_ptr = ':';
5527 str_ptr++;
5528 }
5529 }
5530 *str_ptr = '\0';
5531 return 0;
5532}
5533
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005534u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
5535 u8 *version, u16 len)
5536{
Julia Lawall0376d5b2009-07-19 05:26:35 +00005537 struct bnx2x *bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005538 u32 ext_phy_type = 0;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005539 u32 spirom_ver = 0;
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005540 u8 status;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005541
5542 if (version == NULL || params == NULL)
5543 return -EINVAL;
Julia Lawall0376d5b2009-07-19 05:26:35 +00005544 bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005545
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005546 spirom_ver = REG_RD(bp, params->shmem_base +
5547 offsetof(struct shmem_region,
5548 port_mb[params->port].ext_phy_fw_version));
5549
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005550 status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005551 /* reset the returned value to zero */
5552 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005553 switch (ext_phy_type) {
5554 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5555
5556 if (len < 5)
5557 return -EINVAL;
5558
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005559 version[0] = (spirom_ver & 0xFF);
5560 version[1] = (spirom_ver & 0xFF00) >> 8;
5561 version[2] = (spirom_ver & 0xFF0000) >> 16;
5562 version[3] = (spirom_ver & 0xFF000000) >> 24;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005563 version[4] = '\0';
5564
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005565 break;
5566 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5567 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein4d295db2009-07-21 05:47:47 +00005568 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005569 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00005570 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greensteinb1607af2009-08-12 08:22:54 +00005571 status = bnx2x_format_ver(spirom_ver, version, len);
5572 break;
Eilon Greenstein9223dea2009-03-02 08:00:15 +00005573 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02005574 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
Eilon Greensteinb1607af2009-08-12 08:22:54 +00005575 spirom_ver = ((spirom_ver & 0xF80) >> 7) << 16 |
5576 (spirom_ver & 0x7F);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005577 status = bnx2x_format_ver(spirom_ver, version, len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005578 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005579 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Eilon Greenstein97b41da2009-08-12 08:22:59 +00005580 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5581 version[0] = '\0';
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005582 break;
5583
5584 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
5585 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
5586 " type is FAILURE!\n");
5587 status = -EINVAL;
5588 break;
5589
5590 default:
5591 break;
5592 }
5593 return status;
5594}
5595
5596static void bnx2x_set_xgxs_loopback(struct link_params *params,
5597 struct link_vars *vars,
5598 u8 is_10g)
5599{
5600 u8 port = params->port;
5601 struct bnx2x *bp = params->bp;
5602
5603 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07005604 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005605
5606 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
5607
5608 /* change the uni_phy_addr in the nig */
5609 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
5610 port*0x18));
5611
5612 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
5613
5614 bnx2x_cl45_write(bp, port, 0,
5615 params->phy_addr,
5616 5,
5617 (MDIO_REG_BANK_AER_BLOCK +
5618 (MDIO_AER_BLOCK_AER_REG & 0xf)),
5619 0x2800);
5620
5621 bnx2x_cl45_write(bp, port, 0,
5622 params->phy_addr,
5623 5,
5624 (MDIO_REG_BANK_CL73_IEEEB0 +
5625 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
5626 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00005627 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005628 /* set aer mmd back */
5629 bnx2x_set_aer_mmd(params, vars);
5630
5631 /* and md_devad */
5632 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
5633 md_devad);
5634
5635 } else {
5636 u16 mii_control;
5637
5638 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
5639
5640 CL45_RD_OVER_CL22(bp, port,
5641 params->phy_addr,
5642 MDIO_REG_BANK_COMBO_IEEE0,
5643 MDIO_COMBO_IEEE0_MII_CONTROL,
5644 &mii_control);
5645
5646 CL45_WR_OVER_CL22(bp, port,
5647 params->phy_addr,
5648 MDIO_REG_BANK_COMBO_IEEE0,
5649 MDIO_COMBO_IEEE0_MII_CONTROL,
5650 (mii_control |
5651 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
5652 }
5653}
5654
5655
5656static void bnx2x_ext_phy_loopback(struct link_params *params)
5657{
5658 struct bnx2x *bp = params->bp;
5659 u8 ext_phy_addr;
5660 u32 ext_phy_type;
5661
5662 if (params->switch_cfg == SWITCH_CFG_10G) {
5663 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00005664 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005665 /* CL37 Autoneg Enabled */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005666 switch (ext_phy_type) {
5667 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
5668 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
5669 DP(NETIF_MSG_LINK,
5670 "ext_phy_loopback: We should not get here\n");
5671 break;
5672 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5673 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
5674 break;
5675 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
5676 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
5677 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00005678 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5679 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
5680 bnx2x_cl45_write(bp, params->port, ext_phy_type,
5681 ext_phy_addr,
5682 MDIO_PMA_DEVAD,
5683 MDIO_PMA_REG_CTRL,
5684 0x0001);
5685 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005686 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5687 /* SFX7101_XGXS_TEST1 */
5688 bnx2x_cl45_write(bp, params->port, ext_phy_type,
5689 ext_phy_addr,
5690 MDIO_XS_DEVAD,
5691 MDIO_XS_SFX7101_XGXS_TEST1,
5692 0x100);
5693 DP(NETIF_MSG_LINK,
5694 "ext_phy_loopback: set ext phy loopback\n");
5695 break;
5696 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5697
5698 break;
5699 } /* switch external PHY type */
5700 } else {
5701 /* serdes */
5702 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
5703 ext_phy_addr = (params->ext_phy_config &
5704 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
5705 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
5706 }
5707}
5708
5709
5710/*
5711 *------------------------------------------------------------------------
5712 * bnx2x_override_led_value -
5713 *
5714 * Override the led value of the requsted led
5715 *
5716 *------------------------------------------------------------------------
5717 */
5718u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
5719 u32 led_idx, u32 value)
5720{
5721 u32 reg_val;
5722
5723 /* If port 0 then use EMAC0, else use EMAC1*/
5724 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
5725
5726 DP(NETIF_MSG_LINK,
5727 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
5728 port, led_idx, value);
5729
5730 switch (led_idx) {
5731 case 0: /* 10MB led */
5732 /* Read the current value of the LED register in
5733 the EMAC block */
5734 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5735 /* Set the OVERRIDE bit to 1 */
5736 reg_val |= EMAC_LED_OVERRIDE;
5737 /* If value is 1, set the 10M_OVERRIDE bit,
5738 otherwise reset it.*/
5739 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
5740 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
5741 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5742 break;
5743 case 1: /*100MB led */
5744 /*Read the current value of the LED register in
5745 the EMAC block */
5746 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5747 /* Set the OVERRIDE bit to 1 */
5748 reg_val |= EMAC_LED_OVERRIDE;
5749 /* If value is 1, set the 100M_OVERRIDE bit,
5750 otherwise reset it.*/
5751 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
5752 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
5753 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5754 break;
5755 case 2: /* 1000MB led */
5756 /* Read the current value of the LED register in the
5757 EMAC block */
5758 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5759 /* Set the OVERRIDE bit to 1 */
5760 reg_val |= EMAC_LED_OVERRIDE;
5761 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
5762 reset it. */
5763 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
5764 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
5765 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5766 break;
5767 case 3: /* 2500MB led */
5768 /* Read the current value of the LED register in the
5769 EMAC block*/
5770 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
5771 /* Set the OVERRIDE bit to 1 */
5772 reg_val |= EMAC_LED_OVERRIDE;
5773 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
5774 reset it.*/
5775 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
5776 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
5777 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5778 break;
5779 case 4: /*10G led */
5780 if (port == 0) {
5781 REG_WR(bp, NIG_REG_LED_10G_P0,
5782 value);
5783 } else {
5784 REG_WR(bp, NIG_REG_LED_10G_P1,
5785 value);
5786 }
5787 break;
5788 case 5: /* TRAFFIC led */
5789 /* Find if the traffic control is via BMAC or EMAC */
5790 if (port == 0)
5791 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
5792 else
5793 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
5794
5795 /* Override the traffic led in the EMAC:*/
5796 if (reg_val == 1) {
5797 /* Read the current value of the LED register in
5798 the EMAC block */
5799 reg_val = REG_RD(bp, emac_base +
5800 EMAC_REG_EMAC_LED);
5801 /* Set the TRAFFIC_OVERRIDE bit to 1 */
5802 reg_val |= EMAC_LED_OVERRIDE;
5803 /* If value is 1, set the TRAFFIC bit, otherwise
5804 reset it.*/
5805 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
5806 (reg_val & ~EMAC_LED_TRAFFIC);
5807 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
5808 } else { /* Override the traffic led in the BMAC: */
5809 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
5810 + port*4, 1);
5811 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
5812 value);
5813 }
5814 break;
5815 default:
5816 DP(NETIF_MSG_LINK,
5817 "bnx2x_override_led_value() unknown led index %d "
5818 "(should be 0-5)\n", led_idx);
5819 return -EINVAL;
5820 }
5821
5822 return 0;
5823}
5824
5825
Yaniv Rosner7846e472009-11-05 19:18:07 +02005826u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005827{
Yaniv Rosner7846e472009-11-05 19:18:07 +02005828 u8 port = params->port;
5829 u16 hw_led_mode = params->hw_led_mode;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005830 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005831 u32 tmp;
5832 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosner7846e472009-11-05 19:18:07 +02005833 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
5834 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005835 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
5836 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
5837 speed, hw_led_mode);
5838 switch (mode) {
5839 case LED_MODE_OFF:
5840 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
5841 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
5842 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005843
5844 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005845 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005846 break;
5847
5848 case LED_MODE_OPER:
Yaniv Rosner7846e472009-11-05 19:18:07 +02005849 if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
5850 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
5851 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
5852 } else {
5853 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
5854 hw_led_mode);
5855 }
5856
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005857 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
5858 port*4, 0);
5859 /* Set blinking rate to ~15.9Hz */
5860 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
5861 LED_BLINK_RATE_VAL);
5862 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
5863 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005864 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005865 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07005866 (tmp & (~EMAC_LED_OVERRIDE)));
5867
Yaniv Rosner7846e472009-11-05 19:18:07 +02005868 if (CHIP_IS_E1(bp) &&
Eilon Greenstein34f80b02008-06-23 20:33:01 -07005869 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005870 (speed == SPEED_1000) ||
5871 (speed == SPEED_100) ||
5872 (speed == SPEED_10))) {
5873 /* On Everest 1 Ax chip versions for speeds less than
5874 10G LED scheme is different */
5875 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
5876 + port*4, 1);
5877 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
5878 port*4, 0);
5879 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
5880 port*4, 1);
5881 }
5882 break;
5883
5884 default:
5885 rc = -EINVAL;
5886 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
5887 mode);
5888 break;
5889 }
5890 return rc;
5891
5892}
5893
5894u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
5895{
5896 struct bnx2x *bp = params->bp;
5897 u16 gp_status = 0;
5898
5899 CL45_RD_OVER_CL22(bp, params->port,
5900 params->phy_addr,
5901 MDIO_REG_BANK_GP_STATUS,
5902 MDIO_GP_STATUS_TOP_AN_STATUS1,
5903 &gp_status);
5904 /* link is up only if both local phy and external phy are up */
5905 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
Eilon Greenstein2f904462009-08-12 08:22:16 +00005906 bnx2x_ext_phy_is_link_up(params, vars, 1))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005907 return 0;
5908
5909 return -ESRCH;
5910}
5911
5912static u8 bnx2x_link_initialize(struct link_params *params,
5913 struct link_vars *vars)
5914{
5915 struct bnx2x *bp = params->bp;
5916 u8 port = params->port;
5917 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005918 u8 non_ext_phy;
5919 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005920
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005921 /* Activate the external PHY */
5922 bnx2x_ext_phy_reset(params, vars);
5923
5924 bnx2x_set_aer_mmd(params, vars);
5925
5926 if (vars->phy_flags & PHY_XGXS_FLAG)
5927 bnx2x_set_master_ln(params);
5928
5929 rc = bnx2x_reset_unicore(params);
5930 /* reset the SerDes and wait for reset bit return low */
5931 if (rc != 0)
5932 return rc;
5933
5934 bnx2x_set_aer_mmd(params, vars);
5935
5936 /* setting the masterLn_def again after the reset */
5937 if (vars->phy_flags & PHY_XGXS_FLAG) {
5938 bnx2x_set_master_ln(params);
5939 bnx2x_set_swap_lanes(params);
5940 }
5941
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005942 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00005943 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005944 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00005945 (params->req_line_speed == SPEED_10))) ||
5946 (!params->req_line_speed &&
5947 (params->speed_cap_mask >=
5948 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
5949 (params->speed_cap_mask <
5950 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
5951 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005952 vars->phy_flags |= PHY_SGMII_FLAG;
5953 } else {
5954 vars->phy_flags &= ~PHY_SGMII_FLAG;
5955 }
5956 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005957 /* In case of external phy existance, the line speed would be the
5958 line speed linked up by the external phy. In case it is direct only,
5959 then the line_speed during initialization will be equal to the
5960 req_line_speed*/
5961 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005962
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07005963 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005964
5965 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005966 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00005967 (params->loopback_mode == LOOPBACK_XGXS_10));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005968
5969 if (non_ext_phy ||
Eilon Greenstein589abe32009-02-12 08:36:55 +00005970 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02005971 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
Eilon Greenstein28577182009-02-12 08:37:00 +00005972 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
Eilon Greenstein8660d8c2009-03-02 08:01:02 +00005973 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005974 if (params->req_line_speed == SPEED_AUTO_NEG)
5975 bnx2x_set_parallel_detection(params, vars->phy_flags);
Eilon Greenstein239d6862009-08-12 08:23:04 +00005976 bnx2x_init_internal_phy(params, vars, non_ext_phy);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005977 }
5978
5979 if (!non_ext_phy)
5980 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005981
5982 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005983 (NIG_STATUS_XGXS0_LINK10G |
5984 NIG_STATUS_XGXS0_LINK_STATUS |
5985 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005986
5987 return rc;
5988
5989}
5990
5991
5992u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
5993{
5994 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005995 u32 val;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00005996
5997 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
5998 DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n",
5999 params->req_line_speed, params->req_flow_ctrl);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006000 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006001 vars->phy_link_up = 0;
6002 vars->link_up = 0;
6003 vars->line_speed = 0;
6004 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006005 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006006 vars->mac_type = MAC_TYPE_NONE;
6007
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006008 if (params->switch_cfg == SWITCH_CFG_1G)
6009 vars->phy_flags = PHY_SERDES_FLAG;
6010 else
6011 vars->phy_flags = PHY_XGXS_FLAG;
6012
6013 /* disable attentions */
6014 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
6015 (NIG_MASK_XGXS0_LINK_STATUS |
6016 NIG_MASK_XGXS0_LINK10G |
6017 NIG_MASK_SERDES0_LINK_STATUS |
6018 NIG_MASK_MI_INT));
6019
6020 bnx2x_emac_init(params, vars);
6021
6022 if (CHIP_REV_IS_FPGA(bp)) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006023
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006024 vars->link_up = 1;
6025 vars->line_speed = SPEED_10000;
6026 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006027 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006028 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07006029 /* enable on E1.5 FPGA */
6030 if (CHIP_IS_E1H(bp)) {
6031 vars->flow_ctrl |=
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006032 (BNX2X_FLOW_CTRL_TX |
6033 BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07006034 vars->link_status |=
6035 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
6036 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
6037 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006038
6039 bnx2x_emac_enable(params, vars, 0);
6040 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
6041 /* disable drain */
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006042 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006043
6044 /* update shared memory */
6045 bnx2x_update_mng(params, vars->link_status);
6046
6047 return 0;
6048
6049 } else
6050 if (CHIP_REV_IS_EMUL(bp)) {
6051
6052 vars->link_up = 1;
6053 vars->line_speed = SPEED_10000;
6054 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006055 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006056 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
6057
6058 bnx2x_bmac_enable(params, vars, 0);
6059
6060 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
6061 /* Disable drain */
6062 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
6063 + params->port*4, 0);
6064
6065 /* update shared memory */
6066 bnx2x_update_mng(params, vars->link_status);
6067
6068 return 0;
6069
6070 } else
6071 if (params->loopback_mode == LOOPBACK_BMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006072
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006073 vars->link_up = 1;
6074 vars->line_speed = SPEED_10000;
6075 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006076 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006077 vars->mac_type = MAC_TYPE_BMAC;
6078
6079 vars->phy_flags = PHY_XGXS_FLAG;
6080
6081 bnx2x_phy_deassert(params, vars->phy_flags);
6082 /* set bmac loopback */
6083 bnx2x_bmac_enable(params, vars, 1);
6084
6085 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6086 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006087
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006088 } else if (params->loopback_mode == LOOPBACK_EMAC) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006089
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006090 vars->link_up = 1;
6091 vars->line_speed = SPEED_1000;
6092 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006093 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006094 vars->mac_type = MAC_TYPE_EMAC;
6095
6096 vars->phy_flags = PHY_XGXS_FLAG;
6097
6098 bnx2x_phy_deassert(params, vars->phy_flags);
6099 /* set bmac loopback */
6100 bnx2x_emac_enable(params, vars, 1);
6101 bnx2x_emac_program(params, vars->line_speed,
6102 vars->duplex);
6103 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6104 params->port*4, 0);
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006105
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006106 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006107 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
6108
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006109 vars->link_up = 1;
6110 vars->line_speed = SPEED_10000;
6111 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08006112 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006113
6114 vars->phy_flags = PHY_XGXS_FLAG;
6115
6116 val = REG_RD(bp,
6117 NIG_REG_XGXS0_CTRL_PHY_ADDR+
6118 params->port*0x18);
6119 params->phy_addr = (u8)val;
6120
6121 bnx2x_phy_deassert(params, vars->phy_flags);
6122 bnx2x_link_initialize(params, vars);
6123
6124 vars->mac_type = MAC_TYPE_BMAC;
6125
6126 bnx2x_bmac_enable(params, vars, 0);
6127
6128 if (params->loopback_mode == LOOPBACK_XGXS_10) {
6129 /* set 10G XGXS loopback */
6130 bnx2x_set_xgxs_loopback(params, vars, 1);
6131 } else {
6132 /* set external phy loopback */
6133 bnx2x_ext_phy_loopback(params);
6134 }
6135 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
6136 params->port*4, 0);
Eilon Greensteinba71d312009-07-21 05:47:49 +00006137
Yaniv Rosner7846e472009-11-05 19:18:07 +02006138 bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006139 } else
6140 /* No loopback */
6141 {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006142 bnx2x_phy_deassert(params, vars->phy_flags);
6143 switch (params->switch_cfg) {
6144 case SWITCH_CFG_1G:
6145 vars->phy_flags |= PHY_SERDES_FLAG;
6146 if ((params->ext_phy_config &
6147 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
6148 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006149 vars->phy_flags |= PHY_SGMII_FLAG;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006150 }
6151
6152 val = REG_RD(bp,
6153 NIG_REG_SERDES0_CTRL_PHY_ADDR+
6154 params->port*0x10);
6155
6156 params->phy_addr = (u8)val;
6157
6158 break;
6159 case SWITCH_CFG_10G:
6160 vars->phy_flags |= PHY_XGXS_FLAG;
6161 val = REG_RD(bp,
6162 NIG_REG_XGXS0_CTRL_PHY_ADDR+
6163 params->port*0x18);
6164 params->phy_addr = (u8)val;
6165
6166 break;
6167 default:
6168 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
6169 return -EINVAL;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006170 }
Eilon Greensteinf5372252009-02-12 08:38:30 +00006171 DP(NETIF_MSG_LINK, "Phy address = 0x%x\n", params->phy_addr);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006172
6173 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006174 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006175 bnx2x_link_int_enable(params);
6176 }
6177 return 0;
6178}
6179
Eilon Greenstein589abe32009-02-12 08:36:55 +00006180static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
6181{
6182 DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
6183
6184 /* Set serial boot control for external load */
6185 bnx2x_cl45_write(bp, port,
6186 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
6187 MDIO_PMA_DEVAD,
6188 MDIO_PMA_REG_GEN_CTRL, 0x0001);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006189}
6190
6191u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
6192 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006193{
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006194 struct bnx2x *bp = params->bp;
6195 u32 ext_phy_config = params->ext_phy_config;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006196 u8 port = params->port;
6197 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006198 u32 val = REG_RD(bp, params->shmem_base +
6199 offsetof(struct shmem_region, dev_info.
6200 port_feature_config[params->port].
6201 config));
Yaniv Rosnerd5cb9e92009-11-05 19:18:10 +02006202 DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006203 /* disable attentions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006204 vars->link_status = 0;
6205 bnx2x_update_mng(params, vars->link_status);
6206 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6207 (NIG_MASK_XGXS0_LINK_STATUS |
6208 NIG_MASK_XGXS0_LINK10G |
6209 NIG_MASK_SERDES0_LINK_STATUS |
6210 NIG_MASK_MI_INT));
6211
6212 /* activate nig drain */
6213 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6214
6215 /* disable nig egress interface */
6216 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6217 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6218
6219 /* Stop BigMac rx */
6220 bnx2x_bmac_rx_disable(bp, port);
6221
6222 /* disable emac */
6223 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6224
6225 msleep(10);
6226 /* The PHY reset is controled by GPIO 1
6227 * Hold it as vars low
6228 */
6229 /* clear link led */
Yaniv Rosner7846e472009-11-05 19:18:07 +02006230 bnx2x_set_led(params, LED_MODE_OFF, 0);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006231 if (reset_ext_phy) {
6232 switch (ext_phy_type) {
6233 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
6234 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
6235 break;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006236
6237 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6238 {
6239
6240 /* Disable Transmitter */
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006241 u8 ext_phy_addr =
6242 XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006243 if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
6244 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
6245 bnx2x_sfp_set_transmitter(bp, port,
6246 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6247 ext_phy_addr, 0);
6248 break;
6249 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00006250 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6251 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
6252 "low power mode\n",
6253 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006254 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07006255 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6256 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006257 break;
6258 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6259 {
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006260 u8 ext_phy_addr =
6261 XGXS_EXT_PHY_ADDR(params->ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006262 /* Set soft reset */
6263 bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
6264 break;
6265 }
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006266 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
6267 {
6268 u8 ext_phy_addr =
6269 XGXS_EXT_PHY_ADDR(params->ext_phy_config);
6270 bnx2x_cl45_write(bp, port,
6271 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
6272 ext_phy_addr,
6273 MDIO_AN_DEVAD,
6274 MDIO_AN_REG_CTRL, 0x0000);
6275 bnx2x_cl45_write(bp, port,
6276 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
6277 ext_phy_addr,
6278 MDIO_PMA_DEVAD,
6279 MDIO_PMA_REG_CTRL, 1);
6280 break;
6281 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00006282 default:
6283 /* HW reset */
6284 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
6285 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6286 port);
6287 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6288 MISC_REGISTERS_GPIO_OUTPUT_LOW,
6289 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006290 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006291 }
6292 }
6293 /* reset the SerDes/XGXS */
6294 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
6295 (0x1ff << (port*16)));
6296
6297 /* reset BigMac */
6298 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
6299 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
6300
6301 /* disable nig ingress interface */
6302 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
6303 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
6304 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
6305 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
6306 vars->link_up = 0;
6307 return 0;
6308}
6309
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006310static u8 bnx2x_update_link_down(struct link_params *params,
6311 struct link_vars *vars)
6312{
6313 struct bnx2x *bp = params->bp;
6314 u8 port = params->port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006315
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006316 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
Yaniv Rosner7846e472009-11-05 19:18:07 +02006317 bnx2x_set_led(params, LED_MODE_OFF, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006318
6319 /* indicate no mac active */
6320 vars->mac_type = MAC_TYPE_NONE;
6321
6322 /* update shared memory */
6323 vars->link_status = 0;
6324 vars->line_speed = 0;
6325 bnx2x_update_mng(params, vars->link_status);
6326
6327 /* activate nig drain */
6328 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
6329
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006330 /* disable emac */
6331 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6332
6333 msleep(10);
6334
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006335 /* reset BigMac */
6336 bnx2x_bmac_rx_disable(bp, params->port);
6337 REG_WR(bp, GRCBASE_MISC +
6338 MISC_REGISTERS_RESET_REG_2_CLEAR,
6339 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
6340 return 0;
6341}
6342
6343static u8 bnx2x_update_link_up(struct link_params *params,
6344 struct link_vars *vars,
6345 u8 link_10g, u32 gp_status)
6346{
6347 struct bnx2x *bp = params->bp;
6348 u8 port = params->port;
6349 u8 rc = 0;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006350
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006351 vars->link_status |= LINK_STATUS_LINK_UP;
6352 if (link_10g) {
6353 bnx2x_bmac_enable(params, vars, 0);
Yaniv Rosner7846e472009-11-05 19:18:07 +02006354 bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006355 } else {
6356 bnx2x_emac_enable(params, vars, 0);
6357 rc = bnx2x_emac_program(params, vars->line_speed,
6358 vars->duplex);
6359
6360 /* AN complete? */
6361 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
6362 if (!(vars->phy_flags &
6363 PHY_SGMII_FLAG))
Eilon Greensteined8680a2009-02-12 08:37:12 +00006364 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006365 }
6366 }
6367
6368 /* PBF - link up */
6369 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
6370 vars->line_speed);
6371
6372 /* disable drain */
6373 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
6374
6375 /* update shared memory */
6376 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006377 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006378 return rc;
6379}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006380/* This function should called upon link interrupt */
6381/* In case vars->link_up, driver needs to
6382 1. Update the pbf
6383 2. Disable drain
6384 3. Update the shared memory
6385 4. Indicate link up
6386 5. Set LEDs
6387 Otherwise,
6388 1. Update shared memory
6389 2. Reset BigMac
6390 3. Report link down
6391 4. Unset LEDs
6392*/
6393u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
6394{
6395 struct bnx2x *bp = params->bp;
6396 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006397 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006398 u8 link_10g;
6399 u8 ext_phy_link_up, rc = 0;
6400 u32 ext_phy_type;
Eilon Greenstein2f904462009-08-12 08:22:16 +00006401 u8 is_mi_int = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006402
6403 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006404 port, (vars->phy_flags & PHY_XGXS_FLAG),
6405 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006406
Eilon Greenstein2f904462009-08-12 08:22:16 +00006407 is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
6408 port*0x18) > 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006409 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
Eilon Greenstein2f904462009-08-12 08:22:16 +00006410 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
6411 is_mi_int,
6412 REG_RD(bp,
6413 NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006414
6415 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
6416 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
6417 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
6418
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00006419 /* disable emac */
6420 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
6421
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006422 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006423
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006424 /* Check external link change only for non-direct */
Eilon Greenstein2f904462009-08-12 08:22:16 +00006425 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars, is_mi_int);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006426
6427 /* Read gp_status */
6428 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
6429 MDIO_REG_BANK_GP_STATUS,
6430 MDIO_GP_STATUS_TOP_AN_STATUS1,
6431 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006432
Eilon Greenstein2f904462009-08-12 08:22:16 +00006433 rc = bnx2x_link_settings_status(params, vars, gp_status,
6434 ext_phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006435 if (rc != 0)
6436 return rc;
6437
6438 /* anything 10 and over uses the bmac */
6439 link_10g = ((vars->line_speed == SPEED_10000) ||
6440 (vars->line_speed == SPEED_12000) ||
6441 (vars->line_speed == SPEED_12500) ||
6442 (vars->line_speed == SPEED_13000) ||
6443 (vars->line_speed == SPEED_15000) ||
6444 (vars->line_speed == SPEED_16000));
6445
Eilon Greenstein2f904462009-08-12 08:22:16 +00006446 bnx2x_link_int_ack(params, vars, link_10g, is_mi_int);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006447
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006448 /* In case external phy link is up, and internal link is down
6449 ( not initialized yet probably after link initialization, it needs
6450 to be initialized.
6451 Note that after link down-up as result of cable plug,
6452 the xgxs link would probably become up again without the need to
6453 initialize it*/
6454
6455 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
6456 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
Yaniv Rosnerb5bbf002009-11-05 19:18:21 +02006457 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) &&
Eilon Greenstein589abe32009-02-12 08:36:55 +00006458 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006459 (ext_phy_link_up && !vars->phy_link_up))
Eilon Greenstein239d6862009-08-12 08:23:04 +00006460 bnx2x_init_internal_phy(params, vars, 0);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006461
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006462 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006463 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006464
Yaniv Rosner57963ed2008-08-13 15:55:28 -07006465 if (vars->link_up)
6466 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
6467 else
6468 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006469
6470 return rc;
6471}
6472
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006473static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6474{
6475 u8 ext_phy_addr[PORT_MAX];
6476 u16 val;
6477 s8 port;
6478
6479 /* PART1 - Reset both phys */
6480 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6481 /* Extract the ext phy address for the port */
6482 u32 ext_phy_config = REG_RD(bp, shmem_base +
6483 offsetof(struct shmem_region,
6484 dev_info.port_hw_config[port].external_phy_config));
6485
6486 /* disable attentions */
6487 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6488 (NIG_MASK_XGXS0_LINK_STATUS |
6489 NIG_MASK_XGXS0_LINK10G |
6490 NIG_MASK_SERDES0_LINK_STATUS |
6491 NIG_MASK_MI_INT));
6492
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006493 ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006494
6495 /* Need to take the phy out of low power mode in order
6496 to write to access its registers */
6497 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6498 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
6499
6500 /* Reset the phy */
6501 bnx2x_cl45_write(bp, port,
6502 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6503 ext_phy_addr[port],
6504 MDIO_PMA_DEVAD,
6505 MDIO_PMA_REG_CTRL,
6506 1<<15);
6507 }
6508
6509 /* Add delay of 150ms after reset */
6510 msleep(150);
6511
6512 /* PART2 - Download firmware to both phys */
6513 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
6514 u16 fw_ver1;
6515
6516 bnx2x_bcm8073_external_rom_boot(bp, port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00006517 ext_phy_addr[port], shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006518
6519 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6520 ext_phy_addr[port],
6521 MDIO_PMA_DEVAD,
6522 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006523 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006524 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00006525 "bnx2x_8073_common_init_phy port %x:"
6526 "Download failed. fw version = 0x%x\n",
6527 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006528 return -EINVAL;
6529 }
6530
6531 /* Only set bit 10 = 1 (Tx power down) */
6532 bnx2x_cl45_read(bp, port,
6533 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6534 ext_phy_addr[port],
6535 MDIO_PMA_DEVAD,
6536 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6537
6538 /* Phase1 of TX_POWER_DOWN reset */
6539 bnx2x_cl45_write(bp, port,
6540 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6541 ext_phy_addr[port],
6542 MDIO_PMA_DEVAD,
6543 MDIO_PMA_REG_TX_POWER_DOWN,
6544 (val | 1<<10));
6545 }
6546
6547 /* Toggle Transmitter: Power down and then up with 600ms
6548 delay between */
6549 msleep(600);
6550
6551 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
6552 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
Eilon Greensteinf5372252009-02-12 08:38:30 +00006553 /* Phase2 of POWER_DOWN_RESET */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006554 /* Release bit 10 (Release Tx power down) */
6555 bnx2x_cl45_read(bp, port,
6556 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6557 ext_phy_addr[port],
6558 MDIO_PMA_DEVAD,
6559 MDIO_PMA_REG_TX_POWER_DOWN, &val);
6560
6561 bnx2x_cl45_write(bp, port,
6562 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6563 ext_phy_addr[port],
6564 MDIO_PMA_DEVAD,
6565 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
6566 msleep(15);
6567
6568 /* Read modify write the SPI-ROM version select register */
6569 bnx2x_cl45_read(bp, port,
6570 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6571 ext_phy_addr[port],
6572 MDIO_PMA_DEVAD,
6573 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
6574 bnx2x_cl45_write(bp, port,
6575 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
6576 ext_phy_addr[port],
6577 MDIO_PMA_DEVAD,
6578 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
6579
6580 /* set GPIO2 back to LOW */
6581 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
6582 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
6583 }
6584 return 0;
6585
6586}
6587
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006588static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6589{
6590 u8 ext_phy_addr[PORT_MAX];
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006591 s8 port, first_port, i;
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006592 u32 swap_val, swap_override;
6593 DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
6594 swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
6595 swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
6596
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006597 bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override));
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006598 msleep(5);
6599
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006600 if (swap_val && swap_override)
6601 first_port = PORT_0;
6602 else
6603 first_port = PORT_1;
6604
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006605 /* PART1 - Reset both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006606 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006607 /* Extract the ext phy address for the port */
6608 u32 ext_phy_config = REG_RD(bp, shmem_base +
6609 offsetof(struct shmem_region,
6610 dev_info.port_hw_config[port].external_phy_config));
6611
6612 /* disable attentions */
6613 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
6614 (NIG_MASK_XGXS0_LINK_STATUS |
6615 NIG_MASK_XGXS0_LINK10G |
6616 NIG_MASK_SERDES0_LINK_STATUS |
6617 NIG_MASK_MI_INT));
6618
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006619 ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006620
6621 /* Reset the phy */
6622 bnx2x_cl45_write(bp, port,
6623 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6624 ext_phy_addr[port],
6625 MDIO_PMA_DEVAD,
6626 MDIO_PMA_REG_CTRL,
6627 1<<15);
6628 }
6629
6630 /* Add delay of 150ms after reset */
6631 msleep(150);
6632
6633 /* PART2 - Download firmware to both phys */
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006634 for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006635 u16 fw_ver1;
6636
6637 bnx2x_bcm8727_external_rom_boot(bp, port,
6638 ext_phy_addr[port], shmem_base);
6639
6640 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
6641 ext_phy_addr[port],
6642 MDIO_PMA_DEVAD,
6643 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
6644 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
6645 DP(NETIF_MSG_LINK,
Eilon Greensteinbc7f0a02009-08-12 08:23:01 +00006646 "bnx2x_8727_common_init_phy port %x:"
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006647 "Download failed. fw version = 0x%x\n",
6648 port, fw_ver1);
6649 return -EINVAL;
6650 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006651 }
6652
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006653 return 0;
6654}
6655
Eilon Greenstein589abe32009-02-12 08:36:55 +00006656
6657static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6658{
6659 u8 ext_phy_addr;
6660 u32 val;
6661 s8 port;
Eilon Greensteinab6ad5a2009-08-12 08:24:29 +00006662
Eilon Greenstein589abe32009-02-12 08:36:55 +00006663 /* Use port1 because of the static port-swap */
6664 /* Enable the module detection interrupt */
6665 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
6666 val |= ((1<<MISC_REGISTERS_GPIO_3)|
6667 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
6668 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
6669
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006670 bnx2x_ext_phy_hw_reset(bp, 1);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006671 msleep(5);
6672 for (port = 0; port < PORT_MAX; port++) {
6673 /* Extract the ext phy address for the port */
6674 u32 ext_phy_config = REG_RD(bp, shmem_base +
6675 offsetof(struct shmem_region,
6676 dev_info.port_hw_config[port].external_phy_config));
6677
Eilon Greenstein659bc5c2009-08-12 08:24:02 +00006678 ext_phy_addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006679 DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
6680 ext_phy_addr);
6681
6682 bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
6683
6684 /* Set fault module detected LED on */
6685 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
6686 MISC_REGISTERS_GPIO_HIGH,
6687 port);
6688 }
6689
6690 return 0;
6691}
6692
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006693
6694static u8 bnx2x_84823_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6695{
6696 /* HW reset */
6697 bnx2x_ext_phy_hw_reset(bp, 1);
6698 return 0;
6699}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006700u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
6701{
6702 u8 rc = 0;
6703 u32 ext_phy_type;
6704
Eilon Greensteinf5372252009-02-12 08:38:30 +00006705 DP(NETIF_MSG_LINK, "Begin common phy init\n");
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006706
6707 /* Read the ext_phy_type for arbitrary port(0) */
6708 ext_phy_type = XGXS_EXT_PHY_TYPE(
6709 REG_RD(bp, shmem_base +
6710 offsetof(struct shmem_region,
6711 dev_info.port_hw_config[0].external_phy_config)));
6712
6713 switch (ext_phy_type) {
6714 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
6715 {
6716 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
6717 break;
6718 }
Eilon Greenstein4d295db2009-07-21 05:47:47 +00006719
6720 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
6721 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
6722 rc = bnx2x_8727_common_init_phy(bp, shmem_base);
6723 break;
6724
Eilon Greenstein589abe32009-02-12 08:36:55 +00006725 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
6726 /* GPIO1 affects both ports, so there's need to pull
6727 it for single port alone */
6728 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
Yaniv Rosner4f60dab2009-11-05 19:18:23 +02006729 break;
6730 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
6731 rc = bnx2x_84823_common_init_phy(bp, shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00006732 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07006733 default:
6734 DP(NETIF_MSG_LINK,
6735 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
6736 ext_phy_type);
6737 break;
6738 }
6739
6740 return rc;
6741}
6742
Eilon Greensteinf57a6022009-08-12 08:23:11 +00006743void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07006744{
6745 u16 val, cnt;
6746
6747 bnx2x_cl45_read(bp, port,
6748 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6749 phy_addr,
6750 MDIO_PMA_DEVAD,
6751 MDIO_PMA_REG_7101_RESET, &val);
6752
6753 for (cnt = 0; cnt < 10; cnt++) {
6754 msleep(50);
6755 /* Writes a self-clearing reset */
6756 bnx2x_cl45_write(bp, port,
6757 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6758 phy_addr,
6759 MDIO_PMA_DEVAD,
6760 MDIO_PMA_REG_7101_RESET,
6761 (val | (1<<15)));
6762 /* Wait for clear */
6763 bnx2x_cl45_read(bp, port,
6764 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
6765 phy_addr,
6766 MDIO_PMA_DEVAD,
6767 MDIO_PMA_REG_7101_RESET, &val);
6768
6769 if ((val & (1<<15)) == 0)
6770 break;
6771 }
6772}