blob: bed11b9c2c2d14214b510a9b9e6846a2d231c783 [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
25#include "bnx2x_reg.h"
26#include "bnx2x_fw_defs.h"
27#include "bnx2x_hsi.h"
28#include "bnx2x_link.h"
29#include "bnx2x.h"
30
31/********************************************************/
32#define SUPPORT_CL73 0 /* Currently no */
Eilon Greenstein3196a882008-08-13 15:58:49 -070033#define ETH_HLEN 14
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070034#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
35#define ETH_MIN_PACKET_SIZE 60
36#define ETH_MAX_PACKET_SIZE 1500
37#define ETH_MAX_JUMBO_PACKET_SIZE 9600
38#define MDIO_ACCESS_TIMEOUT 1000
39#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070040
41/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070042/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070043/***********************************************************/
44
45#define NIG_STATUS_XGXS0_LINK10G \
46 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
47#define NIG_STATUS_XGXS0_LINK_STATUS \
48 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
49#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
50 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
51#define NIG_STATUS_SERDES0_LINK_STATUS \
52 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
53#define NIG_MASK_MI_INT \
54 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
55#define NIG_MASK_XGXS0_LINK10G \
56 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
57#define NIG_MASK_XGXS0_LINK_STATUS \
58 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
59#define NIG_MASK_SERDES0_LINK_STATUS \
60 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
61
62#define MDIO_AN_CL73_OR_37_COMPLETE \
63 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
64 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
65
66#define XGXS_RESET_BITS \
67 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
68 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
71 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
72
73#define SERDES_RESET_BITS \
74 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
75 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
77 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
78
79#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
80#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Eilon Greenstein3196a882008-08-13 15:58:49 -070081#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
82#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070083 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070084#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070085 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070086#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070087
88#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
89 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
90#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
91 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
92#define GP_STATUS_SPEED_MASK \
93 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
94#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
95#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
96#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
97#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
98#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
99#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
100#define GP_STATUS_10G_HIG \
101 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
102#define GP_STATUS_10G_CX4 \
103 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
104#define GP_STATUS_12G_HIG \
105 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
106#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
107#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
108#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
109#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
110#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
111#define GP_STATUS_10G_KX4 \
112 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
113
114#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
115#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
116#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
117#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
118#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
119#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
120#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
121#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
122#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
123#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
124#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
125#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
126#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
127#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
128#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
129#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
130#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
131#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
132#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
133#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
134#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
135#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
136#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
137
138#define PHY_XGXS_FLAG 0x1
139#define PHY_SGMII_FLAG 0x2
140#define PHY_SERDES_FLAG 0x4
141
Eilon Greenstein589abe32009-02-12 08:36:55 +0000142/* */
143#define SFP_EEPROM_CON_TYPE_ADDR 0x2
144 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
145 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
146
147#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
148 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
149 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
150#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
151#define SFP_EEPROM_VENDOR_NAME_SIZE 16
152#define SFP_EEPROM_OPTIONS_ADDR 0x40
153 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
154#define SFP_EEPROM_OPTIONS_SIZE 2
155
156#define SFP_MODULE_TYPE_UNKNOWN 0x0
157#define SFP_MODULE_TYPE_LC 0x1
158#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE 0x2
159#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE 0x3
160
161#define SFP_LIMITING_MODE_VALUE 0x0044
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700162/**********************************************************/
163/* INTERFACE */
164/**********************************************************/
165#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
166 bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
167 DEFAULT_PHY_DEV_ADDR, \
168 (_bank + (_addr & 0xf)), \
169 _val)
170
171#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
172 bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
173 DEFAULT_PHY_DEV_ADDR, \
174 (_bank + (_addr & 0xf)), \
175 _val)
176
177static void bnx2x_set_phy_mdio(struct link_params *params)
178{
179 struct bnx2x *bp = params->bp;
180 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
181 params->port*0x18, 0);
182 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
183 DEFAULT_PHY_DEV_ADDR);
184}
185
186static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
187{
188 u32 val = REG_RD(bp, reg);
189
190 val |= bits;
191 REG_WR(bp, reg, val);
192 return val;
193}
194
195static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
196{
197 u32 val = REG_RD(bp, reg);
198
199 val &= ~bits;
200 REG_WR(bp, reg, val);
201 return val;
202}
203
204static void bnx2x_emac_init(struct link_params *params,
205 struct link_vars *vars)
206{
207 /* reset and unreset the emac core */
208 struct bnx2x *bp = params->bp;
209 u8 port = params->port;
210 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
211 u32 val;
212 u16 timeout;
213
214 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
215 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
216 udelay(5);
217 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
218 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
219
220 /* init emac - use read-modify-write */
221 /* self clear reset */
222 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700223 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700224
225 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700226 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700227 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
228 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
229 if (!timeout) {
230 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
231 return;
232 }
233 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700234 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700235
236 /* Set mac address */
237 val = ((params->mac_addr[0] << 8) |
238 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700239 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700240
241 val = ((params->mac_addr[2] << 24) |
242 (params->mac_addr[3] << 16) |
243 (params->mac_addr[4] << 8) |
244 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700245 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700246}
247
248static u8 bnx2x_emac_enable(struct link_params *params,
249 struct link_vars *vars, u8 lb)
250{
251 struct bnx2x *bp = params->bp;
252 u8 port = params->port;
253 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
254 u32 val;
255
256 DP(NETIF_MSG_LINK, "enabling EMAC\n");
257
258 /* enable emac and not bmac */
259 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
260
261 /* for paladium */
262 if (CHIP_REV_IS_EMUL(bp)) {
263 /* Use lane 1 (of lanes 0-3) */
264 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
265 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
266 port*4, 1);
267 }
268 /* for fpga */
269 else
270
271 if (CHIP_REV_IS_FPGA(bp)) {
272 /* Use lane 1 (of lanes 0-3) */
273 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
274
275 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
276 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
277 0);
278 } else
279 /* ASIC */
280 if (vars->phy_flags & PHY_XGXS_FLAG) {
281 u32 ser_lane = ((params->lane_config &
282 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
283 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
284
285 DP(NETIF_MSG_LINK, "XGXS\n");
286 /* select the master lanes (out of 0-3) */
287 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
288 port*4, ser_lane);
289 /* select XGXS */
290 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
291 port*4, 1);
292
293 } else { /* SerDes */
294 DP(NETIF_MSG_LINK, "SerDes\n");
295 /* select SerDes */
296 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
297 port*4, 0);
298 }
299
300 /* enable emac */
301 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
302
303 if (CHIP_REV_IS_SLOW(bp)) {
304 /* config GMII mode */
305 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700306 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700307 (val | EMAC_MODE_PORT_GMII));
308 } else { /* ASIC */
309 /* pause enable/disable */
310 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
311 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800312 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700313 bnx2x_bits_en(bp, emac_base +
314 EMAC_REG_EMAC_RX_MODE,
315 EMAC_RX_MODE_FLOW_EN);
316
317 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700318 (EMAC_TX_MODE_EXT_PAUSE_EN |
319 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800320 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700321 bnx2x_bits_en(bp, emac_base +
322 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700323 (EMAC_TX_MODE_EXT_PAUSE_EN |
324 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700325 }
326
327 /* KEEP_VLAN_TAG, promiscuous */
328 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
329 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700330 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700331
332 /* Set Loopback */
333 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
334 if (lb)
335 val |= 0x810;
336 else
337 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700338 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700339
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000340 /* enable emac */
341 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
342
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700343 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700344 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700345 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
346 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
347
348 /* strip CRC */
349 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
350
351 /* disable the NIG in/out to the bmac */
352 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
353 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
354 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
355
356 /* enable the NIG in/out to the emac */
357 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
358 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800359 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700360 val = 1;
361
362 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
363 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
364
365 if (CHIP_REV_IS_EMUL(bp)) {
366 /* take the BigMac out of reset */
367 REG_WR(bp,
368 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
369 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
370
371 /* enable access for bmac registers */
372 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
373 }
374
375 vars->mac_type = MAC_TYPE_EMAC;
376 return 0;
377}
378
379
380
381static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
382 u8 is_lb)
383{
384 struct bnx2x *bp = params->bp;
385 u8 port = params->port;
386 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
387 NIG_REG_INGRESS_BMAC0_MEM;
388 u32 wb_data[2];
389 u32 val;
390
391 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
392 /* reset and unreset the BigMac */
393 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
394 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
395 msleep(1);
396
397 REG_WR(bp, 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);
402
403 /* XGXS control */
404 wb_data[0] = 0x3c;
405 wb_data[1] = 0;
406 REG_WR_DMAE(bp, bmac_addr +
407 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
408 wb_data, 2);
409
410 /* tx MAC SA */
411 wb_data[0] = ((params->mac_addr[2] << 24) |
412 (params->mac_addr[3] << 16) |
413 (params->mac_addr[4] << 8) |
414 params->mac_addr[5]);
415 wb_data[1] = ((params->mac_addr[0] << 8) |
416 params->mac_addr[1]);
417 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
418 wb_data, 2);
419
420 /* tx control */
421 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800422 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700423 val |= 0x800000;
424 wb_data[0] = val;
425 wb_data[1] = 0;
426 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
427 wb_data, 2);
428
429 /* mac control */
430 val = 0x3;
431 if (is_lb) {
432 val |= 0x4;
433 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
434 }
435 wb_data[0] = val;
436 wb_data[1] = 0;
437 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
438 wb_data, 2);
439
440
441 /* set rx mtu */
442 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
443 wb_data[1] = 0;
444 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
445 wb_data, 2);
446
447 /* rx control set to don't strip crc */
448 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800449 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700450 val |= 0x20;
451 wb_data[0] = val;
452 wb_data[1] = 0;
453 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
454 wb_data, 2);
455
456 /* set tx mtu */
457 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
458 wb_data[1] = 0;
459 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
460 wb_data, 2);
461
462 /* set cnt max size */
463 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
464 wb_data[1] = 0;
465 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
466 wb_data, 2);
467
468 /* configure safc */
469 wb_data[0] = 0x1000200;
470 wb_data[1] = 0;
471 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
472 wb_data, 2);
473 /* fix for emulation */
474 if (CHIP_REV_IS_EMUL(bp)) {
475 wb_data[0] = 0xf000;
476 wb_data[1] = 0;
477 REG_WR_DMAE(bp,
478 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
479 wb_data, 2);
480 }
481
482 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
483 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
484 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
485 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800486 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700487 val = 1;
488 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
489 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
490 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
491 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
492 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
493 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
494
495 vars->mac_type = MAC_TYPE_BMAC;
496 return 0;
497}
498
499static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
500{
501 struct bnx2x *bp = params->bp;
502 u32 val;
503
504 if (phy_flags & PHY_XGXS_FLAG) {
505 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
506 val = XGXS_RESET_BITS;
507
508 } else { /* SerDes */
509 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
510 val = SERDES_RESET_BITS;
511 }
512
513 val = val << (params->port*16);
514
515 /* reset and unreset the SerDes/XGXS */
516 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
517 val);
518 udelay(500);
519 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
520 val);
521 bnx2x_set_phy_mdio(params);
522}
523
524void bnx2x_link_status_update(struct link_params *params,
525 struct link_vars *vars)
526{
527 struct bnx2x *bp = params->bp;
528 u8 link_10g;
529 u8 port = params->port;
530
531 if (params->switch_cfg == SWITCH_CFG_1G)
532 vars->phy_flags = PHY_SERDES_FLAG;
533 else
534 vars->phy_flags = PHY_XGXS_FLAG;
535 vars->link_status = REG_RD(bp, params->shmem_base +
536 offsetof(struct shmem_region,
537 port_mb[port].link_status));
538
539 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
540
541 if (vars->link_up) {
542 DP(NETIF_MSG_LINK, "phy link up\n");
543
544 vars->phy_link_up = 1;
545 vars->duplex = DUPLEX_FULL;
546 switch (vars->link_status &
547 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
548 case LINK_10THD:
549 vars->duplex = DUPLEX_HALF;
550 /* fall thru */
551 case LINK_10TFD:
552 vars->line_speed = SPEED_10;
553 break;
554
555 case LINK_100TXHD:
556 vars->duplex = DUPLEX_HALF;
557 /* fall thru */
558 case LINK_100T4:
559 case LINK_100TXFD:
560 vars->line_speed = SPEED_100;
561 break;
562
563 case LINK_1000THD:
564 vars->duplex = DUPLEX_HALF;
565 /* fall thru */
566 case LINK_1000TFD:
567 vars->line_speed = SPEED_1000;
568 break;
569
570 case LINK_2500THD:
571 vars->duplex = DUPLEX_HALF;
572 /* fall thru */
573 case LINK_2500TFD:
574 vars->line_speed = SPEED_2500;
575 break;
576
577 case LINK_10GTFD:
578 vars->line_speed = SPEED_10000;
579 break;
580
581 case LINK_12GTFD:
582 vars->line_speed = SPEED_12000;
583 break;
584
585 case LINK_12_5GTFD:
586 vars->line_speed = SPEED_12500;
587 break;
588
589 case LINK_13GTFD:
590 vars->line_speed = SPEED_13000;
591 break;
592
593 case LINK_15GTFD:
594 vars->line_speed = SPEED_15000;
595 break;
596
597 case LINK_16GTFD:
598 vars->line_speed = SPEED_16000;
599 break;
600
601 default:
602 break;
603 }
604
605 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800606 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700607 else
David S. Millerc0700f92008-12-16 23:53:20 -0800608 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700609
610 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800611 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700612 else
David S. Millerc0700f92008-12-16 23:53:20 -0800613 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700614
615 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700616 if (vars->line_speed &&
617 ((vars->line_speed == SPEED_10) ||
618 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700619 vars->phy_flags |= PHY_SGMII_FLAG;
620 } else {
621 vars->phy_flags &= ~PHY_SGMII_FLAG;
622 }
623 }
624
625 /* anything 10 and over uses the bmac */
626 link_10g = ((vars->line_speed == SPEED_10000) ||
627 (vars->line_speed == SPEED_12000) ||
628 (vars->line_speed == SPEED_12500) ||
629 (vars->line_speed == SPEED_13000) ||
630 (vars->line_speed == SPEED_15000) ||
631 (vars->line_speed == SPEED_16000));
632 if (link_10g)
633 vars->mac_type = MAC_TYPE_BMAC;
634 else
635 vars->mac_type = MAC_TYPE_EMAC;
636
637 } else { /* link down */
638 DP(NETIF_MSG_LINK, "phy link down\n");
639
640 vars->phy_link_up = 0;
641
642 vars->line_speed = 0;
643 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -0800644 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700645
646 /* indicate no mac active */
647 vars->mac_type = MAC_TYPE_NONE;
648 }
649
650 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
651 vars->link_status, vars->phy_link_up);
652 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
653 vars->line_speed, vars->duplex, vars->flow_ctrl);
654}
655
656static void bnx2x_update_mng(struct link_params *params, u32 link_status)
657{
658 struct bnx2x *bp = params->bp;
659 REG_WR(bp, params->shmem_base +
660 offsetof(struct shmem_region,
661 port_mb[params->port].link_status),
662 link_status);
663}
664
665static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
666{
667 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
668 NIG_REG_INGRESS_BMAC0_MEM;
669 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700670 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700671
672 /* Only if the bmac is out of reset */
673 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
674 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
675 nig_bmac_enable) {
676
677 /* Clear Rx Enable bit in BMAC_CONTROL register */
678 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
679 wb_data, 2);
680 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
681 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
682 wb_data, 2);
683
684 msleep(1);
685 }
686}
687
688static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
689 u32 line_speed)
690{
691 struct bnx2x *bp = params->bp;
692 u8 port = params->port;
693 u32 init_crd, crd;
694 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700695
696 /* disable port */
697 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
698
699 /* wait for init credit */
700 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
701 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
702 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
703
704 while ((init_crd != crd) && count) {
705 msleep(5);
706
707 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
708 count--;
709 }
710 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
711 if (init_crd != crd) {
712 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
713 init_crd, crd);
714 return -EINVAL;
715 }
716
David S. Millerc0700f92008-12-16 23:53:20 -0800717 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700718 line_speed == SPEED_10 ||
719 line_speed == SPEED_100 ||
720 line_speed == SPEED_1000 ||
721 line_speed == SPEED_2500) {
722 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700723 /* update threshold */
724 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
725 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700726 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700727
728 } else {
729 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
730 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700731 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700732 /* update threshold */
733 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
734 /* update init credit */
735 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700736 case SPEED_10000:
737 init_crd = thresh + 553 - 22;
738 break;
739
740 case SPEED_12000:
741 init_crd = thresh + 664 - 22;
742 break;
743
744 case SPEED_13000:
745 init_crd = thresh + 742 - 22;
746 break;
747
748 case SPEED_16000:
749 init_crd = thresh + 778 - 22;
750 break;
751 default:
752 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
753 line_speed);
754 return -EINVAL;
755 break;
756 }
757 }
758 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
759 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
760 line_speed, init_crd);
761
762 /* probe the credit changes */
763 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
764 msleep(5);
765 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
766
767 /* enable port */
768 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
769 return 0;
770}
771
Eilon Greenstein589abe32009-02-12 08:36:55 +0000772static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700773{
774 u32 emac_base;
775 switch (ext_phy_type) {
776 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000777 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
778 /* All MDC/MDIO is directed through single EMAC */
779 if (REG_RD(bp, NIG_REG_PORT_SWAP))
780 emac_base = GRCBASE_EMAC0;
781 else
782 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700783 break;
784 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700785 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700786 break;
787 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700788 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700789 break;
790 }
791 return emac_base;
792
793}
794
795u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
796 u8 phy_addr, u8 devad, u16 reg, u16 val)
797{
798 u32 tmp, saved_mode;
799 u8 i, rc = 0;
Eilon Greenstein589abe32009-02-12 08:36:55 +0000800 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700801
802 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
803 * (a value of 49==0x31) and make sure that the AUTO poll is off
804 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000805
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700806 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
807 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
808 EMAC_MDIO_MODE_CLOCK_CNT);
809 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
810 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
811 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
812 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
813 udelay(40);
814
815 /* address */
816
817 tmp = ((phy_addr << 21) | (devad << 16) | reg |
818 EMAC_MDIO_COMM_COMMAND_ADDRESS |
819 EMAC_MDIO_COMM_START_BUSY);
820 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
821
822 for (i = 0; i < 50; i++) {
823 udelay(10);
824
825 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
826 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
827 udelay(5);
828 break;
829 }
830 }
831 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
832 DP(NETIF_MSG_LINK, "write phy register failed\n");
833 rc = -EFAULT;
834 } else {
835 /* data */
836 tmp = ((phy_addr << 21) | (devad << 16) | val |
837 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
838 EMAC_MDIO_COMM_START_BUSY);
839 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
840
841 for (i = 0; i < 50; i++) {
842 udelay(10);
843
844 tmp = REG_RD(bp, mdio_ctrl +
845 EMAC_REG_EMAC_MDIO_COMM);
846 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
847 udelay(5);
848 break;
849 }
850 }
851 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
852 DP(NETIF_MSG_LINK, "write phy register failed\n");
853 rc = -EFAULT;
854 }
855 }
856
857 /* Restore the saved mode */
858 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
859
860 return rc;
861}
862
863u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
864 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
865{
866 u32 val, saved_mode;
867 u16 i;
868 u8 rc = 0;
869
Eilon Greenstein589abe32009-02-12 08:36:55 +0000870 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700871 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
872 * (a value of 49==0x31) and make sure that the AUTO poll is off
873 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000874
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700875 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
876 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
877 EMAC_MDIO_MODE_CLOCK_CNT));
878 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
879 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
880 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
881 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
882 udelay(40);
883
884 /* address */
885 val = ((phy_addr << 21) | (devad << 16) | reg |
886 EMAC_MDIO_COMM_COMMAND_ADDRESS |
887 EMAC_MDIO_COMM_START_BUSY);
888 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
889
890 for (i = 0; i < 50; i++) {
891 udelay(10);
892
893 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
894 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
895 udelay(5);
896 break;
897 }
898 }
899 if (val & EMAC_MDIO_COMM_START_BUSY) {
900 DP(NETIF_MSG_LINK, "read phy register failed\n");
901
902 *ret_val = 0;
903 rc = -EFAULT;
904
905 } else {
906 /* data */
907 val = ((phy_addr << 21) | (devad << 16) |
908 EMAC_MDIO_COMM_COMMAND_READ_45 |
909 EMAC_MDIO_COMM_START_BUSY);
910 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
911
912 for (i = 0; i < 50; i++) {
913 udelay(10);
914
915 val = REG_RD(bp, mdio_ctrl +
916 EMAC_REG_EMAC_MDIO_COMM);
917 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
918 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
919 break;
920 }
921 }
922 if (val & EMAC_MDIO_COMM_START_BUSY) {
923 DP(NETIF_MSG_LINK, "read phy register failed\n");
924
925 *ret_val = 0;
926 rc = -EFAULT;
927 }
928 }
929
930 /* Restore the saved mode */
931 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
932
933 return rc;
934}
935
936static void bnx2x_set_aer_mmd(struct link_params *params,
937 struct link_vars *vars)
938{
939 struct bnx2x *bp = params->bp;
940 u32 ser_lane;
941 u16 offset;
942
943 ser_lane = ((params->lane_config &
944 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
945 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
946
947 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
948 (params->phy_addr + ser_lane) : 0;
949
950 CL45_WR_OVER_CL22(bp, params->port,
951 params->phy_addr,
952 MDIO_REG_BANK_AER_BLOCK,
953 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
954}
955
956static void bnx2x_set_master_ln(struct link_params *params)
957{
958 struct bnx2x *bp = params->bp;
959 u16 new_master_ln, ser_lane;
960 ser_lane = ((params->lane_config &
961 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
962 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
963
964 /* set the master_ln for AN */
965 CL45_RD_OVER_CL22(bp, params->port,
966 params->phy_addr,
967 MDIO_REG_BANK_XGXS_BLOCK2,
968 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
969 &new_master_ln);
970
971 CL45_WR_OVER_CL22(bp, params->port,
972 params->phy_addr,
973 MDIO_REG_BANK_XGXS_BLOCK2 ,
974 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
975 (new_master_ln | ser_lane));
976}
977
978static u8 bnx2x_reset_unicore(struct link_params *params)
979{
980 struct bnx2x *bp = params->bp;
981 u16 mii_control;
982 u16 i;
983
984 CL45_RD_OVER_CL22(bp, params->port,
985 params->phy_addr,
986 MDIO_REG_BANK_COMBO_IEEE0,
987 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
988
989 /* reset the unicore */
990 CL45_WR_OVER_CL22(bp, params->port,
991 params->phy_addr,
992 MDIO_REG_BANK_COMBO_IEEE0,
993 MDIO_COMBO_IEEE0_MII_CONTROL,
994 (mii_control |
995 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
996
997 /* wait for the reset to self clear */
998 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
999 udelay(5);
1000
1001 /* the reset erased the previous bank value */
1002 CL45_RD_OVER_CL22(bp, params->port,
1003 params->phy_addr,
1004 MDIO_REG_BANK_COMBO_IEEE0,
1005 MDIO_COMBO_IEEE0_MII_CONTROL,
1006 &mii_control);
1007
1008 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1009 udelay(5);
1010 return 0;
1011 }
1012 }
1013
1014 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1015 return -EINVAL;
1016
1017}
1018
1019static void bnx2x_set_swap_lanes(struct link_params *params)
1020{
1021 struct bnx2x *bp = params->bp;
1022 /* Each two bits represents a lane number:
1023 No swap is 0123 => 0x1b no need to enable the swap */
1024 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1025
1026 ser_lane = ((params->lane_config &
1027 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1028 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1029 rx_lane_swap = ((params->lane_config &
1030 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1031 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1032 tx_lane_swap = ((params->lane_config &
1033 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1034 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1035
1036 if (rx_lane_swap != 0x1b) {
1037 CL45_WR_OVER_CL22(bp, params->port,
1038 params->phy_addr,
1039 MDIO_REG_BANK_XGXS_BLOCK2,
1040 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1041 (rx_lane_swap |
1042 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1043 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1044 } else {
1045 CL45_WR_OVER_CL22(bp, params->port,
1046 params->phy_addr,
1047 MDIO_REG_BANK_XGXS_BLOCK2,
1048 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1049 }
1050
1051 if (tx_lane_swap != 0x1b) {
1052 CL45_WR_OVER_CL22(bp, params->port,
1053 params->phy_addr,
1054 MDIO_REG_BANK_XGXS_BLOCK2,
1055 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1056 (tx_lane_swap |
1057 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1058 } else {
1059 CL45_WR_OVER_CL22(bp, params->port,
1060 params->phy_addr,
1061 MDIO_REG_BANK_XGXS_BLOCK2,
1062 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1063 }
1064}
1065
1066static void bnx2x_set_parallel_detection(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07001067 u8 phy_flags)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001068{
1069 struct bnx2x *bp = params->bp;
1070 u16 control2;
1071
1072 CL45_RD_OVER_CL22(bp, params->port,
1073 params->phy_addr,
1074 MDIO_REG_BANK_SERDES_DIGITAL,
1075 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1076 &control2);
1077
1078
1079 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1080
1081
1082 CL45_WR_OVER_CL22(bp, params->port,
1083 params->phy_addr,
1084 MDIO_REG_BANK_SERDES_DIGITAL,
1085 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1086 control2);
1087
1088 if (phy_flags & PHY_XGXS_FLAG) {
1089 DP(NETIF_MSG_LINK, "XGXS\n");
1090
1091 CL45_WR_OVER_CL22(bp, params->port,
1092 params->phy_addr,
1093 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1094 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1095 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1096
1097 CL45_RD_OVER_CL22(bp, params->port,
1098 params->phy_addr,
1099 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1100 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1101 &control2);
1102
1103
1104 control2 |=
1105 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1106
1107 CL45_WR_OVER_CL22(bp, params->port,
1108 params->phy_addr,
1109 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1110 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1111 control2);
1112
1113 /* Disable parallel detection of HiG */
1114 CL45_WR_OVER_CL22(bp, params->port,
1115 params->phy_addr,
1116 MDIO_REG_BANK_XGXS_BLOCK2,
1117 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1118 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1119 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1120 }
1121}
1122
1123static void bnx2x_set_autoneg(struct link_params *params,
1124 struct link_vars *vars)
1125{
1126 struct bnx2x *bp = params->bp;
1127 u16 reg_val;
1128
1129 /* CL37 Autoneg */
1130
1131 CL45_RD_OVER_CL22(bp, params->port,
1132 params->phy_addr,
1133 MDIO_REG_BANK_COMBO_IEEE0,
1134 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1135
1136 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001137 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001138 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1139 else /* CL37 Autoneg Disabled */
1140 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1141 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1142
1143 CL45_WR_OVER_CL22(bp, params->port,
1144 params->phy_addr,
1145 MDIO_REG_BANK_COMBO_IEEE0,
1146 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1147
1148 /* Enable/Disable Autodetection */
1149
1150 CL45_RD_OVER_CL22(bp, params->port,
1151 params->phy_addr,
1152 MDIO_REG_BANK_SERDES_DIGITAL,
1153 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
1154 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001155 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001156 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1157 else
1158 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1159
1160 CL45_WR_OVER_CL22(bp, params->port,
1161 params->phy_addr,
1162 MDIO_REG_BANK_SERDES_DIGITAL,
1163 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1164
1165 /* Enable TetonII and BAM autoneg */
1166 CL45_RD_OVER_CL22(bp, params->port,
1167 params->phy_addr,
1168 MDIO_REG_BANK_BAM_NEXT_PAGE,
1169 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1170 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001171 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001172 /* Enable BAM aneg Mode and TetonII aneg Mode */
1173 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1174 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1175 } else {
1176 /* TetonII and BAM Autoneg Disabled */
1177 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1178 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1179 }
1180 CL45_WR_OVER_CL22(bp, params->port,
1181 params->phy_addr,
1182 MDIO_REG_BANK_BAM_NEXT_PAGE,
1183 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1184 reg_val);
1185
1186 /* Enable Clause 73 Aneg */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001187 if ((vars->line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001188 (SUPPORT_CL73)) {
1189 /* Enable BAM Station Manager */
1190
1191 CL45_WR_OVER_CL22(bp, params->port,
1192 params->phy_addr,
1193 MDIO_REG_BANK_CL73_USERB0,
1194 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1195 (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1196 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1197 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN));
1198
1199 /* Merge CL73 and CL37 aneg resolution */
1200 CL45_RD_OVER_CL22(bp, params->port,
1201 params->phy_addr,
1202 MDIO_REG_BANK_CL73_USERB0,
1203 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1204 &reg_val);
1205
1206 CL45_WR_OVER_CL22(bp, params->port,
1207 params->phy_addr,
1208 MDIO_REG_BANK_CL73_USERB0,
1209 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1210 (reg_val |
1211 MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR));
1212
1213 /* Set the CL73 AN speed */
1214
1215 CL45_RD_OVER_CL22(bp, params->port,
1216 params->phy_addr,
1217 MDIO_REG_BANK_CL73_IEEEB1,
1218 MDIO_CL73_IEEEB1_AN_ADV2, &reg_val);
1219 /* In the SerDes we support only the 1G.
1220 In the XGXS we support the 10G KX4
1221 but we currently do not support the KR */
1222 if (vars->phy_flags & PHY_XGXS_FLAG) {
1223 DP(NETIF_MSG_LINK, "XGXS\n");
1224 /* 10G KX4 */
1225 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1226 } else {
1227 DP(NETIF_MSG_LINK, "SerDes\n");
1228 /* 1000M KX */
1229 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
1230 }
1231 CL45_WR_OVER_CL22(bp, params->port,
1232 params->phy_addr,
1233 MDIO_REG_BANK_CL73_IEEEB1,
1234 MDIO_CL73_IEEEB1_AN_ADV2, reg_val);
1235
1236 /* CL73 Autoneg Enabled */
1237 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1238 } else {
1239 /* CL73 Autoneg Disabled */
1240 reg_val = 0;
1241 }
1242 CL45_WR_OVER_CL22(bp, params->port,
1243 params->phy_addr,
1244 MDIO_REG_BANK_CL73_IEEEB0,
1245 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1246}
1247
1248/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001249static void bnx2x_program_serdes(struct link_params *params,
1250 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001251{
1252 struct bnx2x *bp = params->bp;
1253 u16 reg_val;
1254
1255 /* program duplex, disable autoneg */
1256
1257 CL45_RD_OVER_CL22(bp, params->port,
1258 params->phy_addr,
1259 MDIO_REG_BANK_COMBO_IEEE0,
1260 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1261 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
1262 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN);
1263 if (params->req_duplex == DUPLEX_FULL)
1264 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1265 CL45_WR_OVER_CL22(bp, params->port,
1266 params->phy_addr,
1267 MDIO_REG_BANK_COMBO_IEEE0,
1268 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1269
1270 /* program speed
1271 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001272 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001273 params->phy_addr,
1274 MDIO_REG_BANK_SERDES_DIGITAL,
1275 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001276 /* clearing the speed value before setting the right speed */
1277 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1278
1279 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1280 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1281
1282 if (!((vars->line_speed == SPEED_1000) ||
1283 (vars->line_speed == SPEED_100) ||
1284 (vars->line_speed == SPEED_10))) {
1285
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001286 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1287 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001288 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001289 reg_val |=
1290 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001291 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001292 reg_val |=
1293 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001294 }
1295
1296 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001297 params->phy_addr,
1298 MDIO_REG_BANK_SERDES_DIGITAL,
1299 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001300
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001301}
1302
1303static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1304{
1305 struct bnx2x *bp = params->bp;
1306 u16 val = 0;
1307
1308 /* configure the 48 bits for BAM AN */
1309
1310 /* set extended capabilities */
1311 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1312 val |= MDIO_OVER_1G_UP1_2_5G;
1313 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1314 val |= MDIO_OVER_1G_UP1_10G;
1315 CL45_WR_OVER_CL22(bp, params->port,
1316 params->phy_addr,
1317 MDIO_REG_BANK_OVER_1G,
1318 MDIO_OVER_1G_UP1, val);
1319
1320 CL45_WR_OVER_CL22(bp, params->port,
1321 params->phy_addr,
1322 MDIO_REG_BANK_OVER_1G,
1323 MDIO_OVER_1G_UP3, 0);
1324}
1325
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001326static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001327{
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001328 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001329 /* resolve pause mode and advertisement
1330 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1331
1332 switch (params->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001333 case BNX2X_FLOW_CTRL_AUTO:
1334 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001335 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001336 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1337 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001338 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001339 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1340 }
1341 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001342 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001343 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001344 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1345 break;
1346
David S. Millerc0700f92008-12-16 23:53:20 -08001347 case BNX2X_FLOW_CTRL_RX:
1348 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001349 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001350 break;
1351
David S. Millerc0700f92008-12-16 23:53:20 -08001352 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001353 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001354 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001355 break;
1356 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001357}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001358
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001359static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
1360 u32 ieee_fc)
1361{
1362 struct bnx2x *bp = params->bp;
1363 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001364
1365 CL45_WR_OVER_CL22(bp, params->port,
1366 params->phy_addr,
1367 MDIO_REG_BANK_COMBO_IEEE0,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001368 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001369}
1370
1371static void bnx2x_restart_autoneg(struct link_params *params)
1372{
1373 struct bnx2x *bp = params->bp;
1374 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
1375 if (SUPPORT_CL73) {
1376 /* enable and restart clause 73 aneg */
1377 u16 an_ctrl;
1378
1379 CL45_RD_OVER_CL22(bp, params->port,
1380 params->phy_addr,
1381 MDIO_REG_BANK_CL73_IEEEB0,
1382 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1383 &an_ctrl);
1384 CL45_WR_OVER_CL22(bp, params->port,
1385 params->phy_addr,
1386 MDIO_REG_BANK_CL73_IEEEB0,
1387 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1388 (an_ctrl |
1389 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1390 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1391
1392 } else {
1393 /* Enable and restart BAM/CL37 aneg */
1394 u16 mii_control;
1395
1396 CL45_RD_OVER_CL22(bp, params->port,
1397 params->phy_addr,
1398 MDIO_REG_BANK_COMBO_IEEE0,
1399 MDIO_COMBO_IEEE0_MII_CONTROL,
1400 &mii_control);
1401 DP(NETIF_MSG_LINK,
1402 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1403 mii_control);
1404 CL45_WR_OVER_CL22(bp, params->port,
1405 params->phy_addr,
1406 MDIO_REG_BANK_COMBO_IEEE0,
1407 MDIO_COMBO_IEEE0_MII_CONTROL,
1408 (mii_control |
1409 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1410 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1411 }
1412}
1413
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001414static void bnx2x_initialize_sgmii_process(struct link_params *params,
1415 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001416{
1417 struct bnx2x *bp = params->bp;
1418 u16 control1;
1419
1420 /* in SGMII mode, the unicore is always slave */
1421
1422 CL45_RD_OVER_CL22(bp, params->port,
1423 params->phy_addr,
1424 MDIO_REG_BANK_SERDES_DIGITAL,
1425 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1426 &control1);
1427 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1428 /* set sgmii mode (and not fiber) */
1429 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1430 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1431 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1432 CL45_WR_OVER_CL22(bp, params->port,
1433 params->phy_addr,
1434 MDIO_REG_BANK_SERDES_DIGITAL,
1435 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1436 control1);
1437
1438 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001439 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001440 /* set speed, disable autoneg */
1441 u16 mii_control;
1442
1443 CL45_RD_OVER_CL22(bp, params->port,
1444 params->phy_addr,
1445 MDIO_REG_BANK_COMBO_IEEE0,
1446 MDIO_COMBO_IEEE0_MII_CONTROL,
1447 &mii_control);
1448 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1449 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1450 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1451
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001452 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001453 case SPEED_100:
1454 mii_control |=
1455 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1456 break;
1457 case SPEED_1000:
1458 mii_control |=
1459 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1460 break;
1461 case SPEED_10:
1462 /* there is nothing to set for 10M */
1463 break;
1464 default:
1465 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001466 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1467 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001468 break;
1469 }
1470
1471 /* setting the full duplex */
1472 if (params->req_duplex == DUPLEX_FULL)
1473 mii_control |=
1474 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1475 CL45_WR_OVER_CL22(bp, params->port,
1476 params->phy_addr,
1477 MDIO_REG_BANK_COMBO_IEEE0,
1478 MDIO_COMBO_IEEE0_MII_CONTROL,
1479 mii_control);
1480
1481 } else { /* AN mode */
1482 /* enable and restart AN */
1483 bnx2x_restart_autoneg(params);
1484 }
1485}
1486
1487
1488/*
1489 * link management
1490 */
1491
1492static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001493{ /* LD LP */
1494 switch (pause_result) { /* ASYM P ASYM P */
1495 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001496 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001497 break;
1498
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001499 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001500 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001501 break;
1502
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001503 case 0x5: /* 0 1 0 1 */
1504 case 0x7: /* 0 1 1 1 */
1505 case 0xd: /* 1 1 0 1 */
1506 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001507 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001508 break;
1509
1510 default:
1511 break;
1512 }
1513}
1514
1515static u8 bnx2x_ext_phy_resove_fc(struct link_params *params,
1516 struct link_vars *vars)
1517{
1518 struct bnx2x *bp = params->bp;
1519 u8 ext_phy_addr;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001520 u16 ld_pause; /* local */
1521 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001522 u16 an_complete; /* AN complete */
1523 u16 pause_result;
1524 u8 ret = 0;
1525 u32 ext_phy_type;
1526 u8 port = params->port;
1527 ext_phy_addr = ((params->ext_phy_config &
1528 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1529 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1530
1531 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1532 /* read twice */
1533
1534 bnx2x_cl45_read(bp, port,
1535 ext_phy_type,
1536 ext_phy_addr,
1537 MDIO_AN_DEVAD,
1538 MDIO_AN_REG_STATUS, &an_complete);
1539 bnx2x_cl45_read(bp, port,
1540 ext_phy_type,
1541 ext_phy_addr,
1542 MDIO_AN_DEVAD,
1543 MDIO_AN_REG_STATUS, &an_complete);
1544
1545 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1546 ret = 1;
1547 bnx2x_cl45_read(bp, port,
1548 ext_phy_type,
1549 ext_phy_addr,
1550 MDIO_AN_DEVAD,
1551 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1552 bnx2x_cl45_read(bp, port,
1553 ext_phy_type,
1554 ext_phy_addr,
1555 MDIO_AN_DEVAD,
1556 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1557 pause_result = (ld_pause &
1558 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1559 pause_result |= (lp_pause &
1560 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1561 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
1562 pause_result);
1563 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001564 if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001565 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1566 bnx2x_cl45_read(bp, port,
1567 ext_phy_type,
1568 ext_phy_addr,
1569 MDIO_AN_DEVAD,
1570 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1571
1572 bnx2x_cl45_read(bp, port,
1573 ext_phy_type,
1574 ext_phy_addr,
1575 MDIO_AN_DEVAD,
1576 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1577 pause_result = (ld_pause &
1578 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1579 pause_result |= (lp_pause &
1580 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1581
1582 bnx2x_pause_resolve(vars, pause_result);
1583 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
1584 pause_result);
1585 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001586 }
1587 return ret;
1588}
1589
1590
1591static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1592 struct link_vars *vars,
1593 u32 gp_status)
1594{
1595 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001596 u16 ld_pause; /* local driver */
1597 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001598 u16 pause_result;
1599
David S. Millerc0700f92008-12-16 23:53:20 -08001600 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001601
1602 /* resolve from gp_status in case of AN complete and not sgmii */
David S. Millerc0700f92008-12-16 23:53:20 -08001603 if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001604 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1605 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1606 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1607 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
1608 CL45_RD_OVER_CL22(bp, params->port,
1609 params->phy_addr,
1610 MDIO_REG_BANK_COMBO_IEEE0,
1611 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1612 &ld_pause);
1613 CL45_RD_OVER_CL22(bp, params->port,
1614 params->phy_addr,
1615 MDIO_REG_BANK_COMBO_IEEE0,
1616 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1617 &lp_pause);
1618 pause_result = (ld_pause &
1619 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
1620 pause_result |= (lp_pause &
1621 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
1622 DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
1623 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001624 } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001625 (bnx2x_ext_phy_resove_fc(params, vars))) {
1626 return;
1627 } else {
David S. Millerc0700f92008-12-16 23:53:20 -08001628 if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001629 vars->flow_ctrl = params->req_fc_auto_adv;
1630 else
1631 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001632 }
1633 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1634}
1635
1636
1637static u8 bnx2x_link_settings_status(struct link_params *params,
1638 struct link_vars *vars,
1639 u32 gp_status)
1640{
1641 struct bnx2x *bp = params->bp;
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001642 u16 new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001643 u8 rc = 0;
1644 vars->link_status = 0;
1645
1646 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1647 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1648 gp_status);
1649
1650 vars->phy_link_up = 1;
1651 vars->link_status |= LINK_STATUS_LINK_UP;
1652
1653 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1654 vars->duplex = DUPLEX_FULL;
1655 else
1656 vars->duplex = DUPLEX_HALF;
1657
1658 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1659
1660 switch (gp_status & GP_STATUS_SPEED_MASK) {
1661 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001662 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001663 if (vars->duplex == DUPLEX_FULL)
1664 vars->link_status |= LINK_10TFD;
1665 else
1666 vars->link_status |= LINK_10THD;
1667 break;
1668
1669 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001670 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001671 if (vars->duplex == DUPLEX_FULL)
1672 vars->link_status |= LINK_100TXFD;
1673 else
1674 vars->link_status |= LINK_100TXHD;
1675 break;
1676
1677 case GP_STATUS_1G:
1678 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001679 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001680 if (vars->duplex == DUPLEX_FULL)
1681 vars->link_status |= LINK_1000TFD;
1682 else
1683 vars->link_status |= LINK_1000THD;
1684 break;
1685
1686 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001687 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001688 if (vars->duplex == DUPLEX_FULL)
1689 vars->link_status |= LINK_2500TFD;
1690 else
1691 vars->link_status |= LINK_2500THD;
1692 break;
1693
1694 case GP_STATUS_5G:
1695 case GP_STATUS_6G:
1696 DP(NETIF_MSG_LINK,
1697 "link speed unsupported gp_status 0x%x\n",
1698 gp_status);
1699 return -EINVAL;
1700 break;
1701 case GP_STATUS_10G_KX4:
1702 case GP_STATUS_10G_HIG:
1703 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001704 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001705 vars->link_status |= LINK_10GTFD;
1706 break;
1707
1708 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001709 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001710 vars->link_status |= LINK_12GTFD;
1711 break;
1712
1713 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001714 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001715 vars->link_status |= LINK_12_5GTFD;
1716 break;
1717
1718 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001719 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001720 vars->link_status |= LINK_13GTFD;
1721 break;
1722
1723 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001724 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001725 vars->link_status |= LINK_15GTFD;
1726 break;
1727
1728 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001729 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001730 vars->link_status |= LINK_16GTFD;
1731 break;
1732
1733 default:
1734 DP(NETIF_MSG_LINK,
1735 "link speed unsupported gp_status 0x%x\n",
1736 gp_status);
1737 return -EINVAL;
1738 break;
1739 }
1740
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001741 /* Upon link speed change set the NIG into drain mode.
1742 Comes to deals with possible FIFO glitch due to clk change
1743 when speed is decreased without link down indicator */
1744 if (new_line_speed != vars->line_speed) {
1745 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
1746 + params->port*4, 0);
1747 msleep(1);
1748 }
1749 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001750 vars->link_status |= LINK_STATUS_SERDES_LINK;
1751
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001752 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1753 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1754 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1755 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein589abe32009-02-12 08:36:55 +00001756 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
1757 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein28577182009-02-12 08:37:00 +00001758 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
1759 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1760 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001761 vars->autoneg = AUTO_NEG_ENABLED;
1762
1763 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1764 vars->autoneg |= AUTO_NEG_COMPLETE;
1765 vars->link_status |=
1766 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1767 }
1768
1769 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1770 vars->link_status |=
1771 LINK_STATUS_PARALLEL_DETECTION_USED;
1772
1773 }
David S. Millerc0700f92008-12-16 23:53:20 -08001774 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001775 vars->link_status |=
1776 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001777
David S. Millerc0700f92008-12-16 23:53:20 -08001778 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001779 vars->link_status |=
1780 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001781
1782 } else { /* link_down */
1783 DP(NETIF_MSG_LINK, "phy link down\n");
1784
1785 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001786
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001787 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001788 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001789 vars->autoneg = AUTO_NEG_DISABLED;
1790 vars->mac_type = MAC_TYPE_NONE;
1791 }
1792
1793 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n",
1794 gp_status, vars->phy_link_up, vars->line_speed);
1795 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1796 " autoneg 0x%x\n",
1797 vars->duplex,
1798 vars->flow_ctrl, vars->autoneg);
1799 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1800
1801 return rc;
1802}
1803
1804static void bnx2x_set_sgmii_tx_driver(struct link_params *params)
1805{
1806 struct bnx2x *bp = params->bp;
1807 u16 lp_up2;
1808 u16 tx_driver;
1809
1810 /* read precomp */
1811
1812 CL45_RD_OVER_CL22(bp, params->port,
1813 params->phy_addr,
1814 MDIO_REG_BANK_OVER_1G,
1815 MDIO_OVER_1G_LP_UP2, &lp_up2);
1816
1817 CL45_RD_OVER_CL22(bp, params->port,
1818 params->phy_addr,
1819 MDIO_REG_BANK_TX0,
1820 MDIO_TX0_TX_DRIVER, &tx_driver);
1821
1822 /* bits [10:7] at lp_up2, positioned at [15:12] */
1823 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1824 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1825 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1826
1827 if ((lp_up2 != 0) &&
1828 (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) {
1829 /* replace tx_driver bits [15:12] */
1830 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1831 tx_driver |= lp_up2;
1832 CL45_WR_OVER_CL22(bp, params->port,
1833 params->phy_addr,
1834 MDIO_REG_BANK_TX0,
1835 MDIO_TX0_TX_DRIVER, tx_driver);
1836 }
1837}
1838
1839static u8 bnx2x_emac_program(struct link_params *params,
1840 u32 line_speed, u32 duplex)
1841{
1842 struct bnx2x *bp = params->bp;
1843 u8 port = params->port;
1844 u16 mode = 0;
1845
1846 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1847 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1848 EMAC_REG_EMAC_MODE,
1849 (EMAC_MODE_25G_MODE |
1850 EMAC_MODE_PORT_MII_10M |
1851 EMAC_MODE_HALF_DUPLEX));
1852 switch (line_speed) {
1853 case SPEED_10:
1854 mode |= EMAC_MODE_PORT_MII_10M;
1855 break;
1856
1857 case SPEED_100:
1858 mode |= EMAC_MODE_PORT_MII;
1859 break;
1860
1861 case SPEED_1000:
1862 mode |= EMAC_MODE_PORT_GMII;
1863 break;
1864
1865 case SPEED_2500:
1866 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
1867 break;
1868
1869 default:
1870 /* 10G not valid for EMAC */
1871 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
1872 return -EINVAL;
1873 }
1874
1875 if (duplex == DUPLEX_HALF)
1876 mode |= EMAC_MODE_HALF_DUPLEX;
1877 bnx2x_bits_en(bp,
1878 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
1879 mode);
1880
1881 bnx2x_set_led(bp, params->port, LED_MODE_OPER,
1882 line_speed, params->hw_led_mode, params->chip_id);
1883 return 0;
1884}
1885
1886/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001887/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001888/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001889static void bnx2x_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001890{
1891 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001892 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001893 msleep(1);
1894 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001895 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001896}
1897
1898static void bnx2x_ext_phy_reset(struct link_params *params,
1899 struct link_vars *vars)
1900{
1901 struct bnx2x *bp = params->bp;
1902 u32 ext_phy_type;
1903 u8 ext_phy_addr = ((params->ext_phy_config &
1904 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1905 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1906 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
1907 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1908 /* The PHY reset is controled by GPIO 1
1909 * Give it 1ms of reset pulse
1910 */
1911 if (vars->phy_flags & PHY_XGXS_FLAG) {
1912
1913 switch (ext_phy_type) {
1914 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
1915 DP(NETIF_MSG_LINK, "XGXS Direct\n");
1916 break;
1917
1918 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
1919 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
1920 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
1921
1922 /* Restore normal power mode*/
1923 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001924 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1925 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001926
1927 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001928 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001929
1930 bnx2x_cl45_write(bp, params->port,
1931 ext_phy_type,
1932 ext_phy_addr,
1933 MDIO_PMA_DEVAD,
1934 MDIO_PMA_REG_CTRL, 0xa040);
1935 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00001936 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
1937
1938 /* Restore normal power mode*/
1939 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
1940 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1941 params->port);
1942
1943 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
1944 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1945 params->port);
1946
1947 bnx2x_cl45_write(bp, params->port,
1948 ext_phy_type,
1949 ext_phy_addr,
1950 MDIO_PMA_DEVAD,
1951 MDIO_PMA_REG_CTRL,
1952 1<<15);
1953
1954 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001955 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
1956 /* Unset Low Power Mode and SW reset */
1957 /* Restore normal power mode*/
1958 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001959 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1960 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001961
1962 DP(NETIF_MSG_LINK, "XGXS 8072\n");
1963 bnx2x_cl45_write(bp, params->port,
1964 ext_phy_type,
1965 ext_phy_addr,
1966 MDIO_PMA_DEVAD,
1967 MDIO_PMA_REG_CTRL,
1968 1<<15);
1969 break;
1970 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
1971 {
1972 u16 emac_base;
1973 emac_base = (params->port) ? GRCBASE_EMAC0 :
1974 GRCBASE_EMAC1;
1975
1976 /* Restore normal power mode*/
1977 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001978 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1979 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001980
1981 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001982 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1983 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001984
1985 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001986 }
1987 break;
1988
1989 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
1990 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
1991
1992 /* Restore normal power mode*/
1993 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001994 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1995 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001996
1997 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001998 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001999
2000 break;
2001
Eilon Greenstein28577182009-02-12 08:37:00 +00002002 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
2003
2004 /* Restore normal power mode*/
2005 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2006 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2007 params->port);
2008
2009 /* HW reset */
2010 bnx2x_hw_reset(bp, params->port);
2011
2012 bnx2x_cl45_write(bp, params->port,
2013 ext_phy_type,
2014 ext_phy_addr,
2015 MDIO_PMA_DEVAD,
2016 MDIO_PMA_REG_CTRL,
2017 1<<15);
2018 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002019 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
2020 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
2021 break;
2022
2023 default:
2024 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
2025 params->ext_phy_config);
2026 break;
2027 }
2028
2029 } else { /* SerDes */
2030 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
2031 switch (ext_phy_type) {
2032 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
2033 DP(NETIF_MSG_LINK, "SerDes Direct\n");
2034 break;
2035
2036 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
2037 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002038 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002039 break;
2040
2041 default:
2042 DP(NETIF_MSG_LINK,
2043 "BAD SerDes ext_phy_config 0x%x\n",
2044 params->ext_phy_config);
2045 break;
2046 }
2047 }
2048}
2049
2050static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
2051{
2052 struct bnx2x *bp = params->bp;
2053 u8 port = params->port;
2054 u8 ext_phy_addr = ((params->ext_phy_config &
2055 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2056 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2057 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2058 u16 fw_ver1, fw_ver2;
2059
2060 /* Need to wait 200ms after reset */
2061 msleep(200);
2062 /* Boot port from external ROM
2063 * Set ser_boot_ctl bit in the MISC_CTRL1 register
2064 */
2065 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2066 MDIO_PMA_DEVAD,
2067 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2068
2069 /* Reset internal microprocessor */
2070 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2071 MDIO_PMA_DEVAD,
2072 MDIO_PMA_REG_GEN_CTRL,
2073 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2074 /* set micro reset = 0 */
2075 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2076 MDIO_PMA_DEVAD,
2077 MDIO_PMA_REG_GEN_CTRL,
2078 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2079 /* Reset internal microprocessor */
2080 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2081 MDIO_PMA_DEVAD,
2082 MDIO_PMA_REG_GEN_CTRL,
2083 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2084 /* wait for 100ms for code download via SPI port */
2085 msleep(100);
2086
2087 /* Clear ser_boot_ctl bit */
2088 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2089 MDIO_PMA_DEVAD,
2090 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2091 /* Wait 100ms */
2092 msleep(100);
2093
2094 /* Print the PHY FW version */
2095 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2096 MDIO_PMA_DEVAD,
2097 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2098 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2099 MDIO_PMA_DEVAD,
2100 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2101 DP(NETIF_MSG_LINK, "8072 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
2102}
2103
2104static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2105{
2106 /* This is only required for 8073A1, version 102 only */
2107
2108 struct bnx2x *bp = params->bp;
2109 u8 ext_phy_addr = ((params->ext_phy_config &
2110 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2111 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2112 u16 val;
2113
2114 /* Read 8073 HW revision*/
2115 bnx2x_cl45_read(bp, params->port,
2116 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2117 ext_phy_addr,
2118 MDIO_PMA_DEVAD,
2119 0xc801, &val);
2120
2121 if (val != 1) {
2122 /* No need to workaround in 8073 A1 */
2123 return 0;
2124 }
2125
2126 bnx2x_cl45_read(bp, params->port,
2127 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2128 ext_phy_addr,
2129 MDIO_PMA_DEVAD,
2130 MDIO_PMA_REG_ROM_VER2, &val);
2131
2132 /* SNR should be applied only for version 0x102 */
2133 if (val != 0x102)
2134 return 0;
2135
2136 return 1;
2137}
2138
2139static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2140{
2141 struct bnx2x *bp = params->bp;
2142 u8 ext_phy_addr = ((params->ext_phy_config &
2143 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2144 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2145 u16 val, cnt, cnt1 ;
2146
2147 bnx2x_cl45_read(bp, params->port,
2148 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2149 ext_phy_addr,
2150 MDIO_PMA_DEVAD,
2151 0xc801, &val);
2152
2153 if (val > 0) {
2154 /* No need to workaround in 8073 A1 */
2155 return 0;
2156 }
2157 /* XAUI workaround in 8073 A0: */
2158
2159 /* After loading the boot ROM and restarting Autoneg,
2160 poll Dev1, Reg $C820: */
2161
2162 for (cnt = 0; cnt < 1000; cnt++) {
2163 bnx2x_cl45_read(bp, params->port,
2164 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2165 ext_phy_addr,
2166 MDIO_PMA_DEVAD,
2167 0xc820, &val);
2168 /* If bit [14] = 0 or bit [13] = 0, continue on with
2169 system initialization (XAUI work-around not required,
2170 as these bits indicate 2.5G or 1G link up). */
2171 if (!(val & (1<<14)) || !(val & (1<<13))) {
2172 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2173 return 0;
2174 } else if (!(val & (1<<15))) {
2175 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2176 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2177 it's MSB (bit 15) goes to 1 (indicating that the
2178 XAUI workaround has completed),
2179 then continue on with system initialization.*/
2180 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2181 bnx2x_cl45_read(bp, params->port,
2182 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2183 ext_phy_addr,
2184 MDIO_PMA_DEVAD,
2185 0xc841, &val);
2186 if (val & (1<<15)) {
2187 DP(NETIF_MSG_LINK,
2188 "XAUI workaround has completed\n");
2189 return 0;
2190 }
2191 msleep(3);
2192 }
2193 break;
2194 }
2195 msleep(3);
2196 }
2197 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2198 return -EINVAL;
2199
2200}
2201
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002202static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
2203 u8 ext_phy_addr)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002204{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002205 u16 fw_ver1, fw_ver2;
2206 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002207 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002208 bnx2x_cl45_write(bp, port,
2209 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2210 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002211 MDIO_PMA_DEVAD,
2212 MDIO_PMA_REG_GEN_CTRL,
2213 0x0001);
2214
2215 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002216 bnx2x_cl45_write(bp, port,
2217 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2218 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002219 MDIO_PMA_DEVAD,
2220 MDIO_PMA_REG_GEN_CTRL,
2221 0x008c);
2222
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002223 bnx2x_cl45_write(bp, port,
2224 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2225 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002226 MDIO_PMA_DEVAD,
2227 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2228
2229 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002230 bnx2x_cl45_write(bp, port,
2231 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2232 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002233 MDIO_PMA_DEVAD,
2234 MDIO_PMA_REG_GEN_CTRL,
2235 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2236
2237 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002238 bnx2x_cl45_write(bp, port,
2239 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2240 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002241 MDIO_PMA_DEVAD,
2242 MDIO_PMA_REG_GEN_CTRL,
2243 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2244
2245 /* wait for 100ms for code download via SPI port */
2246 msleep(100);
2247
2248 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002249 bnx2x_cl45_write(bp, port,
2250 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2251 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002252 MDIO_PMA_DEVAD,
2253 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2254
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002255 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2256 ext_phy_addr,
2257 MDIO_PMA_DEVAD,
2258 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2259 bnx2x_cl45_read(bp, port,
2260 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2261 ext_phy_addr,
2262 MDIO_PMA_DEVAD,
2263 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002264 DP(NETIF_MSG_LINK, "8073 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
2265
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002266}
2267
Eilon Greenstein589abe32009-02-12 08:36:55 +00002268static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
2269{
2270 struct bnx2x *bp = params->bp;
2271 u8 port = params->port;
2272 u8 ext_phy_addr = ((params->ext_phy_config &
2273 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2274 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2275 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2276
2277 /* Need to wait 100ms after reset */
2278 msleep(100);
2279
2280 /* Set serial boot control for external load */
2281 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2282 MDIO_PMA_DEVAD,
2283 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2284
2285 /* Micro controller re-boot */
2286 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2287 MDIO_PMA_DEVAD,
2288 MDIO_PMA_REG_GEN_CTRL,
2289 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2290
2291 /* Set soft reset */
2292 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2293 MDIO_PMA_DEVAD,
2294 MDIO_PMA_REG_GEN_CTRL,
2295 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2296
2297 /* Clear soft reset.
2298 Will automatically reset micro-controller re-boot */
2299 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2300 MDIO_PMA_DEVAD,
2301 MDIO_PMA_REG_GEN_CTRL,
2302 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2303
2304 /* wait for 100ms for microcode load */
2305 msleep(100);
2306
2307 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
2308 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2309 MDIO_PMA_DEVAD,
2310 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2311
2312 msleep(200);
2313}
2314
2315static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
2316 u8 ext_phy_addr, u8 tx_en)
2317{
2318 u16 val;
2319 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2320 tx_en, port);
2321 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
2322 bnx2x_cl45_read(bp, port,
2323 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2324 ext_phy_addr,
2325 MDIO_PMA_DEVAD,
2326 MDIO_PMA_REG_PHY_IDENTIFIER,
2327 &val);
2328
2329 if (tx_en)
2330 val &= ~(1<<15);
2331 else
2332 val |= (1<<15);
2333
2334 bnx2x_cl45_write(bp, port,
2335 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2336 ext_phy_addr,
2337 MDIO_PMA_DEVAD,
2338 MDIO_PMA_REG_PHY_IDENTIFIER,
2339 val);
2340}
2341
2342
2343static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
2344 u8 byte_cnt, u8 *o_buf) {
2345 struct bnx2x *bp = params->bp;
2346 u16 val, i;
2347 u8 port = params->port;
2348 u8 ext_phy_addr = ((params->ext_phy_config &
2349 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2350 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2351 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2352 if (byte_cnt > 16) {
2353 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2354 " is limited to 0xf\n");
2355 return -EINVAL;
2356 }
2357 /* Set the read command byte count */
2358 bnx2x_cl45_write(bp, port,
2359 ext_phy_type,
2360 ext_phy_addr,
2361 MDIO_PMA_DEVAD,
2362 MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
2363 (byte_cnt | 0xa000));
2364
2365 /* Set the read command address */
2366 bnx2x_cl45_write(bp, port,
2367 ext_phy_type,
2368 ext_phy_addr,
2369 MDIO_PMA_DEVAD,
2370 MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
2371 addr);
2372
2373 /* Activate read command */
2374 bnx2x_cl45_write(bp, port,
2375 ext_phy_type,
2376 ext_phy_addr,
2377 MDIO_PMA_DEVAD,
2378 MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
2379 0x2c0f);
2380
2381 /* Wait up to 500us for command complete status */
2382 for (i = 0; i < 100; i++) {
2383 bnx2x_cl45_read(bp, port,
2384 ext_phy_type,
2385 ext_phy_addr,
2386 MDIO_PMA_DEVAD,
2387 MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
2388 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
2389 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
2390 break;
2391 udelay(5);
2392 }
2393
2394 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
2395 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
2396 DP(NETIF_MSG_LINK,
2397 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2398 (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
2399 return -EINVAL;
2400 }
2401
2402 /* Read the buffer */
2403 for (i = 0; i < byte_cnt; i++) {
2404 bnx2x_cl45_read(bp, port,
2405 ext_phy_type,
2406 ext_phy_addr,
2407 MDIO_PMA_DEVAD,
2408 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2409 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2410 }
2411
2412 for (i = 0; i < 100; i++) {
2413 bnx2x_cl45_read(bp, port,
2414 ext_phy_type,
2415 ext_phy_addr,
2416 MDIO_PMA_DEVAD,
2417 MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
2418 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
2419 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
2420 return 0;;
2421 msleep(1);
2422 }
2423 return -EINVAL;
2424}
2425
2426
2427static u8 bnx2x_get_sfp_module_type(struct link_params *params,
2428 u8 *module_type)
2429{
2430 struct bnx2x *bp = params->bp;
2431 u8 val;
2432 *module_type = SFP_MODULE_TYPE_UNKNOWN;
2433
2434 /* First check for copper cable */
2435 if (bnx2x_read_sfp_module_eeprom(params,
2436 SFP_EEPROM_CON_TYPE_ADDR,
2437 1,
2438 &val) != 0) {
2439 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
2440 return -EINVAL;
2441 }
2442
2443 switch (val) {
2444 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2445 {
2446 u8 copper_module_type;
2447 /* Check if its active cable( includes SFP+ module)
2448 of passive cable*/
2449 if (bnx2x_read_sfp_module_eeprom(params,
2450 SFP_EEPROM_FC_TX_TECH_ADDR,
2451 1,
2452 &copper_module_type) !=
2453 0) {
2454 DP(NETIF_MSG_LINK,
2455 "Failed to read copper-cable-type"
2456 " from SFP+ EEPROM\n");
2457 return -EINVAL;
2458 }
2459
2460 if (copper_module_type &
2461 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2462 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
2463 *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
2464 } else if (copper_module_type &
2465 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2466 DP(NETIF_MSG_LINK, "Passive Copper"
2467 " cable detected\n");
2468 *module_type =
2469 SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
2470 } else {
2471 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2472 "type 0x%x !!!\n", copper_module_type);
2473 return -EINVAL;
2474 }
2475 break;
2476 }
2477 case SFP_EEPROM_CON_TYPE_VAL_LC:
2478 DP(NETIF_MSG_LINK, "Optic module detected\n");
2479 *module_type = SFP_MODULE_TYPE_LC;
2480 break;
2481
2482 default:
2483 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2484 val);
2485 return -EINVAL;
2486 }
2487 return 0;
2488}
2489
2490
2491/* This function read the relevant field from the module ( SFP+ ),
2492 and verify it is compliant with this board */
2493static u8 bnx2x_verify_sfp_module(struct link_params *params,
2494 u8 module_type)
2495{
2496 struct bnx2x *bp = params->bp;
2497 u8 *str_p, *tmp_buf;
2498 u16 i;
2499
2500#define COMPLIANCE_STR_CNT 6
2501 u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
2502 "FINISAR CORP. ", "Amphenol"};
2503 u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
2504 /* Passive Copper cables are allowed to participate,
2505 since the module is hardwired to the copper cable */
2506
2507 if (!(params->feature_config_flags &
2508 FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
2509 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2510 return 0;
2511 }
2512
2513 if (module_type != SFP_MODULE_TYPE_LC) {
2514 DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
2515 return 0;
2516 }
2517
2518 /* In case of non copper cable or Active copper cable,
2519 verify that the SFP+ module is compliant with this board*/
2520 if (bnx2x_read_sfp_module_eeprom(params,
2521 SFP_EEPROM_VENDOR_NAME_ADDR,
2522 SFP_EEPROM_VENDOR_NAME_SIZE,
2523 buf) != 0) {
2524 DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
2525 " module EEPROM\n");
2526 return -EINVAL;
2527 }
2528 for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
2529 str_p = compliance_str[i];
2530 tmp_buf = buf;
2531 while (*str_p) {
2532 if ((u8)(*tmp_buf) != (u8)(*str_p))
2533 break;
2534 str_p++;
2535 tmp_buf++;
2536 }
2537
2538 if (!(*str_p)) {
2539 DP(NETIF_MSG_LINK, "SFP+ Module verified, "
2540 "index=%x\n", i);
2541 return 0;
2542 }
2543 }
2544 DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
2545 return -EINVAL;
2546}
2547
2548
2549static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
2550 u8 module_type)
2551{
2552 struct bnx2x *bp = params->bp;
2553 u8 port = params->port;
2554 u8 options[SFP_EEPROM_OPTIONS_SIZE];
2555 u8 limiting_mode;
2556 u8 ext_phy_addr = ((params->ext_phy_config &
2557 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2558 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2559
2560 if (bnx2x_read_sfp_module_eeprom(params,
2561 SFP_EEPROM_OPTIONS_ADDR,
2562 SFP_EEPROM_OPTIONS_SIZE,
2563 options) != 0) {
2564 DP(NETIF_MSG_LINK, "Failed to read Option field from"
2565 " module EEPROM\n");
2566 return -EINVAL;
2567 }
2568 limiting_mode = !(options[0] &
2569 SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
2570 if (limiting_mode &&
2571 (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
2572 DP(NETIF_MSG_LINK,
2573 "Module options = 0x%x.Setting LIMITING MODE\n",
2574 options[0]);
2575 bnx2x_cl45_write(bp, port,
2576 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2577 ext_phy_addr,
2578 MDIO_PMA_DEVAD,
2579 MDIO_PMA_REG_ROM_VER2,
2580 SFP_LIMITING_MODE_VALUE);
2581 } else { /* LRM mode ( default )*/
2582 u16 cur_limiting_mode;
2583 DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
2584 options[0]);
2585
2586 bnx2x_cl45_read(bp, port,
2587 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2588 ext_phy_addr,
2589 MDIO_PMA_DEVAD,
2590 MDIO_PMA_REG_ROM_VER2,
2591 &cur_limiting_mode);
2592
2593 /* Changing to LRM mode takes quite few seconds.
2594 So do it only if current mode is limiting
2595 ( default is LRM )*/
2596 if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
2597 return 0;
2598
2599 bnx2x_cl45_write(bp, port,
2600 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2601 ext_phy_addr,
2602 MDIO_PMA_DEVAD,
2603 MDIO_PMA_REG_LRM_MODE,
2604 0);
2605 bnx2x_cl45_write(bp, port,
2606 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2607 ext_phy_addr,
2608 MDIO_PMA_DEVAD,
2609 MDIO_PMA_REG_ROM_VER2,
2610 0x128);
2611 bnx2x_cl45_write(bp, port,
2612 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2613 ext_phy_addr,
2614 MDIO_PMA_DEVAD,
2615 MDIO_PMA_REG_MISC_CTRL0,
2616 0x4008);
2617 bnx2x_cl45_write(bp, port,
2618 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2619 ext_phy_addr,
2620 MDIO_PMA_DEVAD,
2621 MDIO_PMA_REG_LRM_MODE,
2622 0xaaaa);
2623 }
2624 return 0;
2625}
2626
2627static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
2628{
2629 u8 val;
2630 struct bnx2x *bp = params->bp;
2631 u16 timeout;
2632 /* Initialization time after hot-plug may take up to 300ms for some
2633 phys type ( e.g. JDSU ) */
2634 for (timeout = 0; timeout < 60; timeout++) {
2635 if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
2636 == 0) {
2637 DP(NETIF_MSG_LINK, "SFP+ module initialization "
2638 "took %d ms\n", timeout * 5);
2639 return 0;
2640 }
2641 msleep(5);
2642 }
2643 return -EINVAL;
2644}
2645
2646static u8 bnx2x_sfp_module_detection(struct link_params *params)
2647{
2648 struct bnx2x *bp = params->bp;
2649 u8 module_type;
2650 u8 ext_phy_addr = ((params->ext_phy_config &
2651 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2652 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2653 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2654
2655 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
2656 DP(NETIF_MSG_LINK, "Module detection is not required "
2657 "for this phy\n");
2658 return 0;
2659 }
2660
2661 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
2662 params->port);
2663
2664 if (bnx2x_get_sfp_module_type(params,
2665 &module_type) != 0) {
2666 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
2667 if (!(params->feature_config_flags &
2668 FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
2669 /* In case module detection is disabled, it trys to
2670 link up. The issue that can happen here is LRM /
2671 LIMITING mode which set according to the module-type*/
2672 DP(NETIF_MSG_LINK, "Unable to read module-type."
2673 "Probably due to Bit Stretching."
2674 " Proceeding...\n");
2675 } else {
2676 return -EINVAL;
2677 }
2678 } else if (bnx2x_verify_sfp_module(params, module_type) !=
2679 0) {
2680 /* check SFP+ module compatibility */
2681 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
2682 /* Turn on fault module-detected led */
2683 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2684 MISC_REGISTERS_GPIO_HIGH,
2685 params->port);
2686 return -EINVAL;
2687 }
2688
2689 /* Turn off fault module-detected led */
2690 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2691 MISC_REGISTERS_GPIO_LOW,
2692 params->port);
2693
2694 /* Check and set limiting mode / LRM mode */
2695 if (bnx2x_bcm8726_set_limiting_mode(params, module_type)
2696 != 0) {
2697 DP(NETIF_MSG_LINK, "Setting limiting mode failed!!\n");
2698 return -EINVAL;
2699 }
2700
2701 /* Enable transmit for this module */
2702 bnx2x_bcm8726_set_transmitter(bp, params->port,
2703 ext_phy_addr, 1);
2704 return 0;
2705}
2706
2707void bnx2x_handle_module_detect_int(struct link_params *params)
2708{
2709 struct bnx2x *bp = params->bp;
2710 u32 gpio_val;
2711 u8 port = params->port;
2712 /* Set valid module led off */
2713 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2714 MISC_REGISTERS_GPIO_HIGH,
2715 params->port);
2716
2717 /* Get current gpio val refelecting module plugged in / out*/
2718 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
2719
2720 /* Call the handling function in case module is detected */
2721 if (gpio_val == 0) {
2722
2723 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
2724 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
2725 port);
2726
2727 if (bnx2x_wait_for_sfp_module_initialized(params)
2728 == 0)
2729 bnx2x_sfp_module_detection(params);
2730 else
2731 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
2732 } else {
2733 u8 ext_phy_addr = ((params->ext_phy_config &
2734 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2735 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2736 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
2737 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
2738 port);
2739 /* Module was plugged out. */
2740 /* Disable transmit for this module */
2741 bnx2x_bcm8726_set_transmitter(bp, params->port,
2742 ext_phy_addr, 0);
2743 }
2744}
2745
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002746static void bnx2x_bcm807x_force_10G(struct link_params *params)
2747{
2748 struct bnx2x *bp = params->bp;
2749 u8 port = params->port;
2750 u8 ext_phy_addr = ((params->ext_phy_config &
2751 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2752 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2753 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2754
2755 /* Force KR or KX */
2756 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2757 MDIO_PMA_DEVAD,
2758 MDIO_PMA_REG_CTRL,
2759 0x2040);
2760 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2761 MDIO_PMA_DEVAD,
2762 MDIO_PMA_REG_10G_CTRL2,
2763 0x000b);
2764 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2765 MDIO_PMA_DEVAD,
2766 MDIO_PMA_REG_BCM_CTRL,
2767 0x0000);
2768 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2769 MDIO_AN_DEVAD,
2770 MDIO_AN_REG_CTRL,
2771 0x0000);
2772}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002773static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
2774{
2775 struct bnx2x *bp = params->bp;
2776 u8 port = params->port;
2777 u16 val;
2778 u8 ext_phy_addr = ((params->ext_phy_config &
2779 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2780 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2781 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2782
2783 bnx2x_cl45_read(bp, params->port,
2784 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2785 ext_phy_addr,
2786 MDIO_PMA_DEVAD,
2787 0xc801, &val);
2788
2789 if (val == 0) {
2790 /* Mustn't set low power mode in 8073 A0 */
2791 return;
2792 }
2793
2794 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
2795 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2796 MDIO_XS_DEVAD,
2797 MDIO_XS_PLL_SEQUENCER, &val);
2798 val &= ~(1<<13);
2799 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2800 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2801
2802 /* PLL controls */
2803 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2804 MDIO_XS_DEVAD, 0x805E, 0x1077);
2805 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2806 MDIO_XS_DEVAD, 0x805D, 0x0000);
2807 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2808 MDIO_XS_DEVAD, 0x805C, 0x030B);
2809 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2810 MDIO_XS_DEVAD, 0x805B, 0x1240);
2811 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2812 MDIO_XS_DEVAD, 0x805A, 0x2490);
2813
2814 /* Tx Controls */
2815 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2816 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2817 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2818 MDIO_XS_DEVAD, 0x80A6, 0x9041);
2819 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2820 MDIO_XS_DEVAD, 0x80A5, 0x4640);
2821
2822 /* Rx Controls */
2823 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2824 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2825 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2826 MDIO_XS_DEVAD, 0x80FD, 0x9249);
2827 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2828 MDIO_XS_DEVAD, 0x80FC, 0x2015);
2829
2830 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
2831 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2832 MDIO_XS_DEVAD,
2833 MDIO_XS_PLL_SEQUENCER, &val);
2834 val |= (1<<13);
2835 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2836 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2837}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002838
2839static void bnx2x_8073_set_pause_cl37(struct link_params *params,
2840 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002841{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002842
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002843 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002844 u16 cl37_val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002845 u8 ext_phy_addr = ((params->ext_phy_config &
2846 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2847 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2848 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2849
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002850 bnx2x_cl45_read(bp, params->port,
2851 ext_phy_type,
2852 ext_phy_addr,
2853 MDIO_AN_DEVAD,
2854 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
2855
2856 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2857 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2858
2859 if ((vars->ieee_fc &
2860 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
2861 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
2862 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
2863 }
2864 if ((vars->ieee_fc &
2865 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2866 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2867 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2868 }
2869 if ((vars->ieee_fc &
2870 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2871 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2872 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2873 }
2874 DP(NETIF_MSG_LINK,
2875 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
2876
2877 bnx2x_cl45_write(bp, params->port,
2878 ext_phy_type,
2879 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002880 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002881 MDIO_AN_REG_CL37_FC_LD, cl37_val);
2882 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002883}
2884
2885static void bnx2x_ext_phy_set_pause(struct link_params *params,
2886 struct link_vars *vars)
2887{
2888 struct bnx2x *bp = params->bp;
2889 u16 val;
2890 u8 ext_phy_addr = ((params->ext_phy_config &
2891 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2892 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2893 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2894
2895 /* read modify write pause advertizing */
2896 bnx2x_cl45_read(bp, params->port,
2897 ext_phy_type,
2898 ext_phy_addr,
2899 MDIO_AN_DEVAD,
2900 MDIO_AN_REG_ADV_PAUSE, &val);
2901
2902 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002903
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002904 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2905
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002906 if ((vars->ieee_fc &
2907 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002908 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2909 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2910 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002911 if ((vars->ieee_fc &
2912 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002913 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2914 val |=
2915 MDIO_AN_REG_ADV_PAUSE_PAUSE;
2916 }
2917 DP(NETIF_MSG_LINK,
2918 "Ext phy AN advertize 0x%x\n", val);
2919 bnx2x_cl45_write(bp, params->port,
2920 ext_phy_type,
2921 ext_phy_addr,
2922 MDIO_AN_DEVAD,
2923 MDIO_AN_REG_ADV_PAUSE, val);
2924}
2925
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002926
2927static void bnx2x_init_internal_phy(struct link_params *params,
2928 struct link_vars *vars)
2929{
2930 struct bnx2x *bp = params->bp;
2931 u8 port = params->port;
2932 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2933 u16 bank, rx_eq;
2934
2935 rx_eq = ((params->serdes_config &
2936 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >>
2937 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT);
2938
2939 DP(NETIF_MSG_LINK, "setting rx eq to 0x%x\n", rx_eq);
2940 for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL;
2941 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0)) {
2942 CL45_WR_OVER_CL22(bp, port,
2943 params->phy_addr,
2944 bank ,
2945 MDIO_RX0_RX_EQ_BOOST,
2946 ((rx_eq &
2947 MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) |
2948 MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL));
2949 }
2950
2951 /* forced speed requested? */
2952 if (vars->line_speed != SPEED_AUTO_NEG) {
2953 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2954
2955 /* disable autoneg */
2956 bnx2x_set_autoneg(params, vars);
2957
2958 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002959 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002960
2961 } else { /* AN_mode */
2962 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2963
2964 /* AN enabled */
2965 bnx2x_set_brcm_cl37_advertisment(params);
2966
2967 /* program duplex & pause advertisement (for aneg) */
2968 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002969 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002970
2971 /* enable autoneg */
2972 bnx2x_set_autoneg(params, vars);
2973
2974 /* enable and restart AN */
2975 bnx2x_restart_autoneg(params);
2976 }
2977
2978 } else { /* SGMII mode */
2979 DP(NETIF_MSG_LINK, "SGMII\n");
2980
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002981 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002982 }
2983}
2984
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002985static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
2986{
2987 struct bnx2x *bp = params->bp;
2988 u32 ext_phy_type;
2989 u8 ext_phy_addr;
2990 u16 cnt;
2991 u16 ctrl = 0;
2992 u16 val = 0;
2993 u8 rc = 0;
2994 if (vars->phy_flags & PHY_XGXS_FLAG) {
2995 ext_phy_addr = ((params->ext_phy_config &
2996 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2997 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2998
2999 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3000 /* Make sure that the soft reset is off (expect for the 8072:
3001 * due to the lock, it will be done inside the specific
3002 * handling)
3003 */
3004 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3005 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3006 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
3007 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
3008 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
3009 /* Wait for soft reset to get cleared upto 1 sec */
3010 for (cnt = 0; cnt < 1000; cnt++) {
3011 bnx2x_cl45_read(bp, params->port,
3012 ext_phy_type,
3013 ext_phy_addr,
3014 MDIO_PMA_DEVAD,
3015 MDIO_PMA_REG_CTRL, &ctrl);
3016 if (!(ctrl & (1<<15)))
3017 break;
3018 msleep(1);
3019 }
3020 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
3021 ctrl, cnt);
3022 }
3023
3024 switch (ext_phy_type) {
3025 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003026 break;
3027
3028 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3029 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3030
3031 bnx2x_cl45_write(bp, params->port,
3032 ext_phy_type,
3033 ext_phy_addr,
3034 MDIO_PMA_DEVAD,
3035 MDIO_PMA_REG_MISC_CTRL,
3036 0x8288);
3037 bnx2x_cl45_write(bp, params->port,
3038 ext_phy_type,
3039 ext_phy_addr,
3040 MDIO_PMA_DEVAD,
3041 MDIO_PMA_REG_PHY_IDENTIFIER,
3042 0x7fbf);
3043 bnx2x_cl45_write(bp, params->port,
3044 ext_phy_type,
3045 ext_phy_addr,
3046 MDIO_PMA_DEVAD,
3047 MDIO_PMA_REG_CMU_PLL_BYPASS,
3048 0x0100);
3049 bnx2x_cl45_write(bp, params->port,
3050 ext_phy_type,
3051 ext_phy_addr,
3052 MDIO_WIS_DEVAD,
3053 MDIO_WIS_REG_LASI_CNTL, 0x1);
3054 break;
3055
3056 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
3057 DP(NETIF_MSG_LINK, "XGXS 8706\n");
3058
3059 msleep(10);
3060 /* Force speed */
3061 /* First enable LASI */
3062 bnx2x_cl45_write(bp, params->port,
3063 ext_phy_type,
3064 ext_phy_addr,
3065 MDIO_PMA_DEVAD,
3066 MDIO_PMA_REG_RX_ALARM_CTRL,
3067 0x0400);
3068 bnx2x_cl45_write(bp, params->port,
3069 ext_phy_type,
3070 ext_phy_addr,
3071 MDIO_PMA_DEVAD,
3072 MDIO_PMA_REG_LASI_CTRL, 0x0004);
3073
3074 if (params->req_line_speed == SPEED_10000) {
3075 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
3076
3077 bnx2x_cl45_write(bp, params->port,
3078 ext_phy_type,
3079 ext_phy_addr,
3080 MDIO_PMA_DEVAD,
3081 MDIO_PMA_REG_DIGITAL_CTRL,
3082 0x400);
3083 } else {
3084 /* Force 1Gbps using autoneg with 1G
3085 advertisment */
3086
3087 /* Allow CL37 through CL73 */
3088 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3089 bnx2x_cl45_write(bp, params->port,
3090 ext_phy_type,
3091 ext_phy_addr,
3092 MDIO_AN_DEVAD,
3093 MDIO_AN_REG_CL37_CL73,
3094 0x040c);
3095
3096 /* Enable Full-Duplex advertisment on CL37 */
3097 bnx2x_cl45_write(bp, params->port,
3098 ext_phy_type,
3099 ext_phy_addr,
3100 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003101 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003102 0x0020);
3103 /* Enable CL37 AN */
3104 bnx2x_cl45_write(bp, params->port,
3105 ext_phy_type,
3106 ext_phy_addr,
3107 MDIO_AN_DEVAD,
3108 MDIO_AN_REG_CL37_AN,
3109 0x1000);
3110 /* 1G support */
3111 bnx2x_cl45_write(bp, params->port,
3112 ext_phy_type,
3113 ext_phy_addr,
3114 MDIO_AN_DEVAD,
3115 MDIO_AN_REG_ADV, (1<<5));
3116
3117 /* Enable clause 73 AN */
3118 bnx2x_cl45_write(bp, params->port,
3119 ext_phy_type,
3120 ext_phy_addr,
3121 MDIO_AN_DEVAD,
3122 MDIO_AN_REG_CTRL,
3123 0x1200);
3124
3125 }
3126
3127 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003128 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3129 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3130 bnx2x_bcm8726_external_rom_boot(params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003131
Eilon Greenstein589abe32009-02-12 08:36:55 +00003132 /* Need to call module detected on initialization since
3133 the module detection triggered by actual module
3134 insertion might occur before driver is loaded, and when
3135 driver is loaded, it reset all registers, including the
3136 transmitter */
3137 bnx2x_sfp_module_detection(params);
3138 if (params->req_line_speed == SPEED_1000) {
3139 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3140 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3141 ext_phy_addr, MDIO_PMA_DEVAD,
3142 MDIO_PMA_REG_CTRL, 0x40);
3143 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3144 ext_phy_addr, MDIO_PMA_DEVAD,
3145 MDIO_PMA_REG_10G_CTRL2, 0xD);
3146 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3147 ext_phy_addr, MDIO_PMA_DEVAD,
3148 MDIO_PMA_REG_LASI_CTRL, 0x5);
3149 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3150 ext_phy_addr, MDIO_PMA_DEVAD,
3151 MDIO_PMA_REG_RX_ALARM_CTRL,
3152 0x400);
3153 } else if ((params->req_line_speed ==
3154 SPEED_AUTO_NEG) &&
3155 ((params->speed_cap_mask &
3156 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
3157 DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
3158 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3159 ext_phy_addr, MDIO_AN_DEVAD,
3160 MDIO_AN_REG_ADV, 0x20);
3161 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3162 ext_phy_addr, MDIO_AN_DEVAD,
3163 MDIO_AN_REG_CL37_CL73, 0x040c);
3164 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3165 ext_phy_addr, MDIO_AN_DEVAD,
3166 MDIO_AN_REG_CL37_FC_LD, 0x0020);
3167 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3168 ext_phy_addr, MDIO_AN_DEVAD,
3169 MDIO_AN_REG_CL37_AN, 0x1000);
3170 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3171 ext_phy_addr, MDIO_AN_DEVAD,
3172 MDIO_AN_REG_CTRL, 0x1200);
3173
3174 /* Enable RX-ALARM control to receive
3175 interrupt for 1G speed change */
3176 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3177 ext_phy_addr, MDIO_PMA_DEVAD,
3178 MDIO_PMA_REG_LASI_CTRL, 0x4);
3179 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3180 ext_phy_addr, MDIO_PMA_DEVAD,
3181 MDIO_PMA_REG_RX_ALARM_CTRL,
3182 0x400);
3183
3184 } else { /* Default 10G. Set only LASI control */
3185 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3186 ext_phy_addr, MDIO_PMA_DEVAD,
3187 MDIO_PMA_REG_LASI_CTRL, 1);
3188 }
3189 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003190 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3191 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3192 {
3193 u16 tmp1;
3194 u16 rx_alarm_ctrl_val;
3195 u16 lasi_ctrl_val;
3196 if (ext_phy_type ==
3197 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3198 rx_alarm_ctrl_val = 0x400;
3199 lasi_ctrl_val = 0x0004;
3200 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003201 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003202 lasi_ctrl_val = 0x0004;
3203 }
3204
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003205 /* enable LASI */
3206 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003207 ext_phy_type,
3208 ext_phy_addr,
3209 MDIO_PMA_DEVAD,
3210 MDIO_PMA_REG_RX_ALARM_CTRL,
3211 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003212
3213 bnx2x_cl45_write(bp, params->port,
3214 ext_phy_type,
3215 ext_phy_addr,
3216 MDIO_PMA_DEVAD,
3217 MDIO_PMA_REG_LASI_CTRL,
3218 lasi_ctrl_val);
3219
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003220 bnx2x_8073_set_pause_cl37(params, vars);
3221
3222 if (ext_phy_type ==
3223 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){
3224 bnx2x_bcm8072_external_rom_boot(params);
3225 } else {
3226
3227 /* In case of 8073 with long xaui lines,
3228 don't set the 8073 xaui low power*/
3229 bnx2x_bcm8073_set_xaui_low_power_mode(params);
3230 }
3231
3232 bnx2x_cl45_read(bp, params->port,
3233 ext_phy_type,
3234 ext_phy_addr,
3235 MDIO_PMA_DEVAD,
3236 0xca13,
3237 &tmp1);
3238
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003239 bnx2x_cl45_read(bp, params->port,
3240 ext_phy_type,
3241 ext_phy_addr,
3242 MDIO_PMA_DEVAD,
3243 MDIO_PMA_REG_RX_ALARM, &tmp1);
3244
3245 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
3246 "0x%x\n", tmp1);
3247
3248 /* If this is forced speed, set to KR or KX
3249 * (all other are not supported)
3250 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003251 if (params->loopback_mode == LOOPBACK_EXT) {
3252 bnx2x_bcm807x_force_10G(params);
3253 DP(NETIF_MSG_LINK,
3254 "Forced speed 10G on 807X\n");
3255 break;
3256 } else {
3257 bnx2x_cl45_write(bp, params->port,
3258 ext_phy_type, ext_phy_addr,
3259 MDIO_PMA_DEVAD,
3260 MDIO_PMA_REG_BCM_CTRL,
3261 0x0002);
3262 }
3263 if (params->req_line_speed != SPEED_AUTO_NEG) {
3264 if (params->req_line_speed == SPEED_10000) {
3265 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003266 } else if (params->req_line_speed ==
3267 SPEED_2500) {
3268 val = (1<<5);
3269 /* Note that 2.5G works only
3270 when used with 1G advertisment */
3271 } else
3272 val = (1<<5);
3273 } else {
3274
3275 val = 0;
3276 if (params->speed_cap_mask &
3277 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3278 val |= (1<<7);
3279
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003280 /* Note that 2.5G works only when
3281 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003282 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003283 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3284 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003285 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003286 DP(NETIF_MSG_LINK,
3287 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003288 }
3289
3290 bnx2x_cl45_write(bp, params->port,
3291 ext_phy_type,
3292 ext_phy_addr,
3293 MDIO_AN_DEVAD,
3294 MDIO_AN_REG_ADV, val);
3295
3296 if (ext_phy_type ==
3297 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003298
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003299 bnx2x_cl45_read(bp, params->port,
3300 ext_phy_type,
3301 ext_phy_addr,
3302 MDIO_AN_DEVAD,
3303 0x8329, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003304
3305 if (((params->speed_cap_mask &
3306 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3307 (params->req_line_speed ==
3308 SPEED_AUTO_NEG)) ||
3309 (params->req_line_speed ==
3310 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003311 u16 phy_ver;
3312 /* Allow 2.5G for A1 and above */
3313 bnx2x_cl45_read(bp, params->port,
3314 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
3315 ext_phy_addr,
3316 MDIO_PMA_DEVAD,
3317 0xc801, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003318 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003319 if (phy_ver > 0)
3320 tmp1 |= 1;
3321 else
3322 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003323 } else {
3324 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003325 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003326 }
3327
3328 bnx2x_cl45_write(bp, params->port,
3329 ext_phy_type,
3330 ext_phy_addr,
3331 MDIO_AN_DEVAD,
3332 0x8329, tmp1);
3333 }
3334
3335 /* Add support for CL37 (passive mode) II */
3336
3337 bnx2x_cl45_read(bp, params->port,
3338 ext_phy_type,
3339 ext_phy_addr,
3340 MDIO_AN_DEVAD,
3341 MDIO_AN_REG_CL37_FC_LD,
3342 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003343
3344 bnx2x_cl45_write(bp, params->port,
3345 ext_phy_type,
3346 ext_phy_addr,
3347 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003348 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
3349 ((params->req_duplex == DUPLEX_FULL) ?
3350 0x20 : 0x40)));
3351
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003352 /* Add support for CL37 (passive mode) III */
3353 bnx2x_cl45_write(bp, params->port,
3354 ext_phy_type,
3355 ext_phy_addr,
3356 MDIO_AN_DEVAD,
3357 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003358
3359 if (ext_phy_type ==
3360 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003361 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003362 BW and FEE main tap. Rest commands are executed
3363 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003364 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003365 if (bnx2x_8073_is_snr_needed(params))
3366 bnx2x_cl45_write(bp, params->port,
3367 ext_phy_type,
3368 ext_phy_addr,
3369 MDIO_PMA_DEVAD,
3370 MDIO_PMA_REG_EDC_FFE_MAIN,
3371 0xFB0C);
3372
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003373 /* Enable FEC (Forware Error Correction)
3374 Request in the AN */
3375 bnx2x_cl45_read(bp, params->port,
3376 ext_phy_type,
3377 ext_phy_addr,
3378 MDIO_AN_DEVAD,
3379 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003380
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003381 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003382
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003383 bnx2x_cl45_write(bp, params->port,
3384 ext_phy_type,
3385 ext_phy_addr,
3386 MDIO_AN_DEVAD,
3387 MDIO_AN_REG_ADV2, tmp1);
3388
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003389 }
3390
3391 bnx2x_ext_phy_set_pause(params, vars);
3392
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003393 /* Restart autoneg */
3394 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003395 bnx2x_cl45_write(bp, params->port,
3396 ext_phy_type,
3397 ext_phy_addr,
3398 MDIO_AN_DEVAD,
3399 MDIO_AN_REG_CTRL, 0x1200);
3400 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
3401 "Advertise 1G=%x, 10G=%x\n",
3402 ((val & (1<<5)) > 0),
3403 ((val & (1<<7)) > 0));
3404 break;
3405 }
3406 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3407 DP(NETIF_MSG_LINK,
3408 "Setting the SFX7101 LASI indication\n");
3409
3410 bnx2x_cl45_write(bp, params->port,
3411 ext_phy_type,
3412 ext_phy_addr,
3413 MDIO_PMA_DEVAD,
3414 MDIO_PMA_REG_LASI_CTRL, 0x1);
3415 DP(NETIF_MSG_LINK,
3416 "Setting the SFX7101 LED to blink on traffic\n");
3417 bnx2x_cl45_write(bp, params->port,
3418 ext_phy_type,
3419 ext_phy_addr,
3420 MDIO_PMA_DEVAD,
3421 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
3422
3423 bnx2x_ext_phy_set_pause(params, vars);
3424 /* Restart autoneg */
3425 bnx2x_cl45_read(bp, params->port,
3426 ext_phy_type,
3427 ext_phy_addr,
3428 MDIO_AN_DEVAD,
3429 MDIO_AN_REG_CTRL, &val);
3430 val |= 0x200;
3431 bnx2x_cl45_write(bp, params->port,
3432 ext_phy_type,
3433 ext_phy_addr,
3434 MDIO_AN_DEVAD,
3435 MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003436
3437 break;
3438 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
3439 DP(NETIF_MSG_LINK,
3440 "Setting the BCM8481 LASI control\n");
3441
3442 bnx2x_cl45_write(bp, params->port,
3443 ext_phy_type,
3444 ext_phy_addr,
3445 MDIO_PMA_DEVAD,
3446 MDIO_PMA_REG_LASI_CTRL, 0x1);
3447
3448 /* Restart autoneg */
3449 bnx2x_cl45_read(bp, params->port,
3450 ext_phy_type,
3451 ext_phy_addr,
3452 MDIO_AN_DEVAD,
3453 MDIO_AN_REG_CTRL, &val);
3454 val |= 0x200;
3455 bnx2x_cl45_write(bp, params->port,
3456 ext_phy_type,
3457 ext_phy_addr,
3458 MDIO_AN_DEVAD,
3459 MDIO_AN_REG_CTRL, val);
3460
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003461 break;
3462 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
3463 DP(NETIF_MSG_LINK,
3464 "XGXS PHY Failure detected 0x%x\n",
3465 params->ext_phy_config);
3466 rc = -EINVAL;
3467 break;
3468 default:
3469 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3470 params->ext_phy_config);
3471 rc = -EINVAL;
3472 break;
3473 }
3474
3475 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003476
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003477 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3478 switch (ext_phy_type) {
3479 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3480 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3481 break;
3482
3483 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3484 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3485 break;
3486
3487 default:
3488 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
3489 params->ext_phy_config);
3490 break;
3491 }
3492 }
3493 return rc;
3494}
3495
3496
3497static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003498 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003499{
3500 struct bnx2x *bp = params->bp;
3501 u32 ext_phy_type;
3502 u8 ext_phy_addr;
3503 u16 val1 = 0, val2;
3504 u16 rx_sd, pcs_status;
3505 u8 ext_phy_link_up = 0;
3506 u8 port = params->port;
3507 if (vars->phy_flags & PHY_XGXS_FLAG) {
3508 ext_phy_addr = ((params->ext_phy_config &
3509 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3510 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3511
3512 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3513 switch (ext_phy_type) {
3514 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3515 DP(NETIF_MSG_LINK, "XGXS Direct\n");
3516 ext_phy_link_up = 1;
3517 break;
3518
3519 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3520 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3521 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3522 ext_phy_addr,
3523 MDIO_WIS_DEVAD,
3524 MDIO_WIS_REG_LASI_STATUS, &val1);
3525 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3526
3527 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3528 ext_phy_addr,
3529 MDIO_WIS_DEVAD,
3530 MDIO_WIS_REG_LASI_STATUS, &val1);
3531 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3532
3533 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3534 ext_phy_addr,
3535 MDIO_PMA_DEVAD,
3536 MDIO_PMA_REG_RX_SD, &rx_sd);
3537 DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
3538 ext_phy_link_up = (rx_sd & 0x1);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003539 if (ext_phy_link_up)
3540 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003541 break;
3542
3543 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00003544 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3545 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
3546 /* Clear RX Alarm*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003547 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3548 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00003549 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
3550 &val2);
3551 /* clear LASI indication*/
3552 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3553 ext_phy_addr,
3554 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
3555 &val1);
3556 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3557 ext_phy_addr,
3558 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
3559 &val2);
3560 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
3561 "0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003562
3563 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3564 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00003565 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
3566 &rx_sd);
3567 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3568 ext_phy_addr,
3569 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
3570 &pcs_status);
3571 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3572 ext_phy_addr,
3573 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
3574 &val2);
3575 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3576 ext_phy_addr,
3577 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
3578 &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003579
Eilon Greenstein589abe32009-02-12 08:36:55 +00003580 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003581 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
3582 rx_sd, pcs_status, val2);
3583 /* link is up if both bit 0 of pmd_rx_sd and
3584 * bit 0 of pcs_status are set, or if the autoneg bit
3585 1 is set
3586 */
3587 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
3588 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003589 if (ext_phy_link_up) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003590 if (ext_phy_type ==
3591 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
3592 /* If transmitter is disabled,
3593 ignore false link up indication */
3594 bnx2x_cl45_read(bp, params->port,
3595 ext_phy_type,
3596 ext_phy_addr,
3597 MDIO_PMA_DEVAD,
3598 MDIO_PMA_REG_PHY_IDENTIFIER,
3599 &val1);
3600 if (val1 & (1<<15)) {
3601 DP(NETIF_MSG_LINK, "Tx is "
3602 "disabled\n");
3603 ext_phy_link_up = 0;
3604 break;
3605 }
3606 }
3607
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003608 if (val2 & (1<<1))
3609 vars->line_speed = SPEED_1000;
3610 else
3611 vars->line_speed = SPEED_10000;
3612 }
3613
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003614 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003615 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3616 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3617 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003618 u16 link_status = 0;
3619 u16 an1000_status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003620 if (ext_phy_type ==
3621 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3622 bnx2x_cl45_read(bp, params->port,
3623 ext_phy_type,
3624 ext_phy_addr,
3625 MDIO_PCS_DEVAD,
3626 MDIO_PCS_REG_LASI_STATUS, &val1);
3627 bnx2x_cl45_read(bp, params->port,
3628 ext_phy_type,
3629 ext_phy_addr,
3630 MDIO_PCS_DEVAD,
3631 MDIO_PCS_REG_LASI_STATUS, &val2);
3632 DP(NETIF_MSG_LINK,
3633 "870x LASI status 0x%x->0x%x\n",
3634 val1, val2);
3635
3636 } else {
3637 /* In 8073, port1 is directed through emac0 and
3638 * port0 is directed through emac1
3639 */
3640 bnx2x_cl45_read(bp, params->port,
3641 ext_phy_type,
3642 ext_phy_addr,
3643 MDIO_PMA_DEVAD,
3644 MDIO_PMA_REG_LASI_STATUS, &val1);
3645
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003646 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003647 "8703 LASI status 0x%x\n",
3648 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003649 }
3650
3651 /* clear the interrupt LASI status register */
3652 bnx2x_cl45_read(bp, params->port,
3653 ext_phy_type,
3654 ext_phy_addr,
3655 MDIO_PCS_DEVAD,
3656 MDIO_PCS_REG_STATUS, &val2);
3657 bnx2x_cl45_read(bp, params->port,
3658 ext_phy_type,
3659 ext_phy_addr,
3660 MDIO_PCS_DEVAD,
3661 MDIO_PCS_REG_STATUS, &val1);
3662 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
3663 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003664 /* Clear MSG-OUT */
3665 bnx2x_cl45_read(bp, params->port,
3666 ext_phy_type,
3667 ext_phy_addr,
3668 MDIO_PMA_DEVAD,
3669 0xca13,
3670 &val1);
3671
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003672 /* Check the LASI */
3673 bnx2x_cl45_read(bp, params->port,
3674 ext_phy_type,
3675 ext_phy_addr,
3676 MDIO_PMA_DEVAD,
3677 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003678
3679 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3680
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003681 /* Check the link status */
3682 bnx2x_cl45_read(bp, params->port,
3683 ext_phy_type,
3684 ext_phy_addr,
3685 MDIO_PCS_DEVAD,
3686 MDIO_PCS_REG_STATUS, &val2);
3687 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3688
3689 bnx2x_cl45_read(bp, params->port,
3690 ext_phy_type,
3691 ext_phy_addr,
3692 MDIO_PMA_DEVAD,
3693 MDIO_PMA_REG_STATUS, &val2);
3694 bnx2x_cl45_read(bp, params->port,
3695 ext_phy_type,
3696 ext_phy_addr,
3697 MDIO_PMA_DEVAD,
3698 MDIO_PMA_REG_STATUS, &val1);
3699 ext_phy_link_up = ((val1 & 4) == 4);
3700 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3701 if (ext_phy_type ==
3702 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003703
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003704 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003705 ((params->req_line_speed !=
3706 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003707 if (bnx2x_bcm8073_xaui_wa(params)
3708 != 0) {
3709 ext_phy_link_up = 0;
3710 break;
3711 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003712 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003713 bnx2x_cl45_read(bp, params->port,
3714 ext_phy_type,
3715 ext_phy_addr,
3716 MDIO_AN_DEVAD,
3717 0x8304,
3718 &an1000_status);
3719 bnx2x_cl45_read(bp, params->port,
3720 ext_phy_type,
3721 ext_phy_addr,
3722 MDIO_AN_DEVAD,
3723 0x8304,
3724 &an1000_status);
3725
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003726 /* Check the link status on 1.1.2 */
3727 bnx2x_cl45_read(bp, params->port,
3728 ext_phy_type,
3729 ext_phy_addr,
3730 MDIO_PMA_DEVAD,
3731 MDIO_PMA_REG_STATUS, &val2);
3732 bnx2x_cl45_read(bp, params->port,
3733 ext_phy_type,
3734 ext_phy_addr,
3735 MDIO_PMA_DEVAD,
3736 MDIO_PMA_REG_STATUS, &val1);
3737 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3738 "an_link_status=0x%x\n",
3739 val2, val1, an1000_status);
3740
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003741 ext_phy_link_up = (((val1 & 4) == 4) ||
3742 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003743 if (ext_phy_link_up &&
3744 bnx2x_8073_is_snr_needed(params)) {
3745 /* The SNR will improve about 2dbby
3746 changing the BW and FEE main tap.*/
3747
3748 /* The 1st write to change FFE main
3749 tap is set before restart AN */
3750 /* Change PLL Bandwidth in EDC
3751 register */
3752 bnx2x_cl45_write(bp, port, ext_phy_type,
3753 ext_phy_addr,
3754 MDIO_PMA_DEVAD,
3755 MDIO_PMA_REG_PLL_BANDWIDTH,
3756 0x26BC);
3757
3758 /* Change CDR Bandwidth in EDC
3759 register */
3760 bnx2x_cl45_write(bp, port, ext_phy_type,
3761 ext_phy_addr,
3762 MDIO_PMA_DEVAD,
3763 MDIO_PMA_REG_CDR_BANDWIDTH,
3764 0x0333);
3765
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003766
3767 }
3768 bnx2x_cl45_read(bp, params->port,
3769 ext_phy_type,
3770 ext_phy_addr,
3771 MDIO_PMA_DEVAD,
3772 0xc820,
3773 &link_status);
3774
3775 /* Bits 0..2 --> speed detected,
3776 bits 13..15--> link is down */
3777 if ((link_status & (1<<2)) &&
3778 (!(link_status & (1<<15)))) {
3779 ext_phy_link_up = 1;
3780 vars->line_speed = SPEED_10000;
3781 DP(NETIF_MSG_LINK,
3782 "port %x: External link"
3783 " up in 10G\n", params->port);
3784 } else if ((link_status & (1<<1)) &&
3785 (!(link_status & (1<<14)))) {
3786 ext_phy_link_up = 1;
3787 vars->line_speed = SPEED_2500;
3788 DP(NETIF_MSG_LINK,
3789 "port %x: External link"
3790 " up in 2.5G\n", params->port);
3791 } else if ((link_status & (1<<0)) &&
3792 (!(link_status & (1<<13)))) {
3793 ext_phy_link_up = 1;
3794 vars->line_speed = SPEED_1000;
3795 DP(NETIF_MSG_LINK,
3796 "port %x: External link"
3797 " up in 1G\n", params->port);
3798 } else {
3799 ext_phy_link_up = 0;
3800 DP(NETIF_MSG_LINK,
3801 "port %x: External link"
3802 " is down\n", params->port);
3803 }
3804 } else {
3805 /* See if 1G link is up for the 8072 */
3806 bnx2x_cl45_read(bp, params->port,
3807 ext_phy_type,
3808 ext_phy_addr,
3809 MDIO_AN_DEVAD,
3810 0x8304,
3811 &an1000_status);
3812 bnx2x_cl45_read(bp, params->port,
3813 ext_phy_type,
3814 ext_phy_addr,
3815 MDIO_AN_DEVAD,
3816 0x8304,
3817 &an1000_status);
3818 if (an1000_status & (1<<1)) {
3819 ext_phy_link_up = 1;
3820 vars->line_speed = SPEED_1000;
3821 DP(NETIF_MSG_LINK,
3822 "port %x: External link"
3823 " up in 1G\n", params->port);
3824 } else if (ext_phy_link_up) {
3825 ext_phy_link_up = 1;
3826 vars->line_speed = SPEED_10000;
3827 DP(NETIF_MSG_LINK,
3828 "port %x: External link"
3829 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003830 }
3831 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003832
3833
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003834 break;
3835 }
3836 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3837 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3838 ext_phy_addr,
3839 MDIO_PMA_DEVAD,
3840 MDIO_PMA_REG_LASI_STATUS, &val2);
3841 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3842 ext_phy_addr,
3843 MDIO_PMA_DEVAD,
3844 MDIO_PMA_REG_LASI_STATUS, &val1);
3845 DP(NETIF_MSG_LINK,
3846 "10G-base-T LASI status 0x%x->0x%x\n",
3847 val2, val1);
3848 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3849 ext_phy_addr,
3850 MDIO_PMA_DEVAD,
3851 MDIO_PMA_REG_STATUS, &val2);
3852 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3853 ext_phy_addr,
3854 MDIO_PMA_DEVAD,
3855 MDIO_PMA_REG_STATUS, &val1);
3856 DP(NETIF_MSG_LINK,
3857 "10G-base-T PMA status 0x%x->0x%x\n",
3858 val2, val1);
3859 ext_phy_link_up = ((val1 & 4) == 4);
3860 /* if link is up
3861 * print the AN outcome of the SFX7101 PHY
3862 */
3863 if (ext_phy_link_up) {
3864 bnx2x_cl45_read(bp, params->port,
3865 ext_phy_type,
3866 ext_phy_addr,
3867 MDIO_AN_DEVAD,
3868 MDIO_AN_REG_MASTER_STATUS,
3869 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003870 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003871 DP(NETIF_MSG_LINK,
3872 "SFX7101 AN status 0x%x->Master=%x\n",
3873 val2,
3874 (val2 & (1<<14)));
3875 }
3876 break;
Eilon Greenstein28577182009-02-12 08:37:00 +00003877 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
3878 /* Clear LASI interrupt */
3879 bnx2x_cl45_read(bp, params->port,
3880 ext_phy_type,
3881 ext_phy_addr,
3882 MDIO_PMA_DEVAD,
3883 MDIO_PMA_REG_LASI_STATUS, &val1);
3884 DP(NETIF_MSG_LINK, "8481 LASI status reg = 0x%x\n",
3885 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003886
Eilon Greenstein28577182009-02-12 08:37:00 +00003887 /* Check 10G-BaseT link status */
3888 /* Check Global PMD signal ok */
3889 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3890 ext_phy_addr,
3891 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
3892 &rx_sd);
3893 /* Check PCS block lock */
3894 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3895 ext_phy_addr,
3896 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
3897 &pcs_status);
3898 DP(NETIF_MSG_LINK, "8481 1.a = 0x%x, 1.20 = 0x%x\n",
3899 rx_sd, pcs_status);
3900 if (rx_sd & pcs_status & 0x1) {
3901 vars->line_speed = SPEED_10000;
3902 ext_phy_link_up = 1;
3903 } else {
3904
3905 /* Check 1000-BaseT link status */
3906 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3907 ext_phy_addr,
3908 MDIO_AN_DEVAD, 0xFFE1,
3909 &val1);
3910
3911 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3912 ext_phy_addr,
3913 MDIO_AN_DEVAD, 0xFFE1,
3914 &val2);
3915 DP(NETIF_MSG_LINK, "8481 7.FFE1 ="
3916 "0x%x-->0x%x\n", val1, val2);
3917 if (val2 & (1<<2)) {
3918 vars->line_speed = SPEED_1000;
3919 ext_phy_link_up = 1;
3920 }
3921 }
3922
3923 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003924 default:
3925 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3926 params->ext_phy_config);
3927 ext_phy_link_up = 0;
3928 break;
3929 }
3930
3931 } else { /* SerDes */
3932 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3933 switch (ext_phy_type) {
3934 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3935 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3936 ext_phy_link_up = 1;
3937 break;
3938
3939 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3940 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3941 ext_phy_link_up = 1;
3942 break;
3943
3944 default:
3945 DP(NETIF_MSG_LINK,
3946 "BAD SerDes ext_phy_config 0x%x\n",
3947 params->ext_phy_config);
3948 ext_phy_link_up = 0;
3949 break;
3950 }
3951 }
3952
3953 return ext_phy_link_up;
3954}
3955
3956static void bnx2x_link_int_enable(struct link_params *params)
3957{
3958 u8 port = params->port;
3959 u32 ext_phy_type;
3960 u32 mask;
3961 struct bnx2x *bp = params->bp;
3962 /* setting the status to report on link up
3963 for either XGXS or SerDes */
3964
3965 if (params->switch_cfg == SWITCH_CFG_10G) {
3966 mask = (NIG_MASK_XGXS0_LINK10G |
3967 NIG_MASK_XGXS0_LINK_STATUS);
3968 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
3969 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3970 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3971 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3972 (ext_phy_type !=
3973 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
3974 mask |= NIG_MASK_MI_INT;
3975 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3976 }
3977
3978 } else { /* SerDes */
3979 mask = NIG_MASK_SERDES0_LINK_STATUS;
3980 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
3981 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3982 if ((ext_phy_type !=
3983 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
3984 (ext_phy_type !=
3985 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
3986 mask |= NIG_MASK_MI_INT;
3987 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3988 }
3989 }
3990 bnx2x_bits_en(bp,
3991 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
3992 mask);
3993 DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port,
3994 (params->switch_cfg == SWITCH_CFG_10G),
3995 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
3996
3997 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
3998 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3999 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4000 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
4001 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4002 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4003 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4004}
4005
4006
4007/*
4008 * link management
4009 */
4010static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07004011 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004012{
4013 struct bnx2x *bp = params->bp;
4014 u8 port = params->port;
4015
4016 /* first reset all status
4017 * we assume only one line will be change at a time */
4018 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4019 (NIG_STATUS_XGXS0_LINK10G |
4020 NIG_STATUS_XGXS0_LINK_STATUS |
4021 NIG_STATUS_SERDES0_LINK_STATUS));
4022 if (vars->phy_link_up) {
4023 if (is_10g) {
4024 /* Disable the 10G link interrupt
4025 * by writing 1 to the status register
4026 */
4027 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
4028 bnx2x_bits_en(bp,
4029 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4030 NIG_STATUS_XGXS0_LINK10G);
4031
4032 } else if (params->switch_cfg == SWITCH_CFG_10G) {
4033 /* Disable the link interrupt
4034 * by writing 1 to the relevant lane
4035 * in the status register
4036 */
4037 u32 ser_lane = ((params->lane_config &
4038 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
4039 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
4040
4041 DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
4042 bnx2x_bits_en(bp,
4043 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4044 ((1 << ser_lane) <<
4045 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
4046
4047 } else { /* SerDes */
4048 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
4049 /* Disable the link interrupt
4050 * by writing 1 to the status register
4051 */
4052 bnx2x_bits_en(bp,
4053 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4054 NIG_STATUS_SERDES0_LINK_STATUS);
4055 }
4056
4057 } else { /* link_down */
4058 }
4059}
4060
4061static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
4062{
4063 u8 *str_ptr = str;
4064 u32 mask = 0xf0000000;
4065 u8 shift = 8*4;
4066 u8 digit;
4067 if (len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02004068 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004069 *str_ptr = '\0';
4070 return -EINVAL;
4071 }
4072 while (shift > 0) {
4073
4074 shift -= 4;
4075 digit = ((num & mask) >> shift);
4076 if (digit < 0xa)
4077 *str_ptr = digit + '0';
4078 else
4079 *str_ptr = digit - 0xa + 'a';
4080 str_ptr++;
4081 mask = mask >> 4;
4082 if (shift == 4*4) {
4083 *str_ptr = ':';
4084 str_ptr++;
4085 }
4086 }
4087 *str_ptr = '\0';
4088 return 0;
4089}
4090
4091
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004092static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr,
4093 u32 ext_phy_type)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004094{
4095 u32 cnt = 0;
4096 u16 ctrl = 0;
4097 /* Enable EMAC0 in to enable MDIO */
4098 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
4099 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
4100 msleep(5);
4101
4102 /* take ext phy out of reset */
4103 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004104 MISC_REGISTERS_GPIO_2,
4105 MISC_REGISTERS_GPIO_HIGH,
4106 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004107
4108 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004109 MISC_REGISTERS_GPIO_1,
4110 MISC_REGISTERS_GPIO_HIGH,
4111 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004112
4113 /* wait for 5ms */
4114 msleep(5);
4115
4116 for (cnt = 0; cnt < 1000; cnt++) {
4117 msleep(1);
4118 bnx2x_cl45_read(bp, port,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004119 ext_phy_type,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004120 ext_phy_addr,
4121 MDIO_PMA_DEVAD,
4122 MDIO_PMA_REG_CTRL,
4123 &ctrl);
4124 if (!(ctrl & (1<<15))) {
4125 DP(NETIF_MSG_LINK, "Reset completed\n\n");
4126 break;
4127 }
4128 }
4129}
4130
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004131static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004132{
4133 /* put sf to reset */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004134 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004135 MISC_REGISTERS_GPIO_1,
4136 MISC_REGISTERS_GPIO_LOW,
4137 port);
4138 bnx2x_set_gpio(bp,
4139 MISC_REGISTERS_GPIO_2,
4140 MISC_REGISTERS_GPIO_LOW,
4141 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004142}
4143
4144u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
4145 u8 *version, u16 len)
4146{
4147 struct bnx2x *bp = params->bp;
4148 u32 ext_phy_type = 0;
4149 u16 val = 0;
4150 u8 ext_phy_addr = 0 ;
4151 u8 status = 0 ;
4152 u32 ver_num;
4153
4154 if (version == NULL || params == NULL)
4155 return -EINVAL;
4156
4157 /* reset the returned value to zero */
4158 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4159 ext_phy_addr = ((params->ext_phy_config &
4160 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4161 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4162
4163 switch (ext_phy_type) {
4164 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4165
4166 if (len < 5)
4167 return -EINVAL;
4168
4169 /* Take ext phy out of reset */
4170 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004171 bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
4172 ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004173
4174 /* wait for 1ms */
4175 msleep(1);
4176
4177 bnx2x_cl45_read(bp, params->port,
4178 ext_phy_type,
4179 ext_phy_addr,
4180 MDIO_PMA_DEVAD,
4181 MDIO_PMA_REG_7101_VER1, &val);
4182 version[2] = (val & 0xFF);
4183 version[3] = ((val & 0xFF00)>>8);
4184
4185 bnx2x_cl45_read(bp, params->port,
4186 ext_phy_type,
4187 ext_phy_addr,
4188 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2,
4189 &val);
4190 version[0] = (val & 0xFF);
4191 version[1] = ((val & 0xFF00)>>8);
4192 version[4] = '\0';
4193
4194 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004195 bnx2x_turn_off_sf(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004196 break;
4197 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4198 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4199 {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004200 /* Take ext phy out of reset */
4201 if (!driver_loaded)
4202 bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
4203 ext_phy_type);
4204
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004205 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4206 ext_phy_addr,
4207 MDIO_PMA_DEVAD,
4208 MDIO_PMA_REG_ROM_VER1, &val);
4209 ver_num = val<<16;
4210 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4211 ext_phy_addr,
4212 MDIO_PMA_DEVAD,
4213 MDIO_PMA_REG_ROM_VER2, &val);
4214 ver_num |= val;
4215 status = bnx2x_format_ver(ver_num, version, len);
4216 break;
4217 }
4218 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4219 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00004220 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004221 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4222 ext_phy_addr,
4223 MDIO_PMA_DEVAD,
4224 MDIO_PMA_REG_ROM_VER1, &val);
4225 ver_num = val<<16;
4226 bnx2x_cl45_read(bp, params->port, ext_phy_type,
4227 ext_phy_addr,
4228 MDIO_PMA_DEVAD,
4229 MDIO_PMA_REG_ROM_VER2, &val);
4230 ver_num |= val;
4231 status = bnx2x_format_ver(ver_num, version, len);
4232 break;
4233
4234 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4235 break;
4236
4237 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4238 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
4239 " type is FAILURE!\n");
4240 status = -EINVAL;
4241 break;
4242
4243 default:
4244 break;
4245 }
4246 return status;
4247}
4248
4249static void bnx2x_set_xgxs_loopback(struct link_params *params,
4250 struct link_vars *vars,
4251 u8 is_10g)
4252{
4253 u8 port = params->port;
4254 struct bnx2x *bp = params->bp;
4255
4256 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07004257 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004258
4259 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
4260
4261 /* change the uni_phy_addr in the nig */
4262 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
4263 port*0x18));
4264
4265 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
4266
4267 bnx2x_cl45_write(bp, port, 0,
4268 params->phy_addr,
4269 5,
4270 (MDIO_REG_BANK_AER_BLOCK +
4271 (MDIO_AER_BLOCK_AER_REG & 0xf)),
4272 0x2800);
4273
4274 bnx2x_cl45_write(bp, port, 0,
4275 params->phy_addr,
4276 5,
4277 (MDIO_REG_BANK_CL73_IEEEB0 +
4278 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
4279 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00004280 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004281 /* set aer mmd back */
4282 bnx2x_set_aer_mmd(params, vars);
4283
4284 /* and md_devad */
4285 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
4286 md_devad);
4287
4288 } else {
4289 u16 mii_control;
4290
4291 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
4292
4293 CL45_RD_OVER_CL22(bp, port,
4294 params->phy_addr,
4295 MDIO_REG_BANK_COMBO_IEEE0,
4296 MDIO_COMBO_IEEE0_MII_CONTROL,
4297 &mii_control);
4298
4299 CL45_WR_OVER_CL22(bp, port,
4300 params->phy_addr,
4301 MDIO_REG_BANK_COMBO_IEEE0,
4302 MDIO_COMBO_IEEE0_MII_CONTROL,
4303 (mii_control |
4304 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
4305 }
4306}
4307
4308
4309static void bnx2x_ext_phy_loopback(struct link_params *params)
4310{
4311 struct bnx2x *bp = params->bp;
4312 u8 ext_phy_addr;
4313 u32 ext_phy_type;
4314
4315 if (params->switch_cfg == SWITCH_CFG_10G) {
4316 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4317 /* CL37 Autoneg Enabled */
4318 ext_phy_addr = ((params->ext_phy_config &
4319 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4320 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4321 switch (ext_phy_type) {
4322 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4323 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
4324 DP(NETIF_MSG_LINK,
4325 "ext_phy_loopback: We should not get here\n");
4326 break;
4327 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4328 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
4329 break;
4330 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
4331 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
4332 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00004333 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4334 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4335 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4336 ext_phy_addr,
4337 MDIO_PMA_DEVAD,
4338 MDIO_PMA_REG_CTRL,
4339 0x0001);
4340 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004341 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4342 /* SFX7101_XGXS_TEST1 */
4343 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4344 ext_phy_addr,
4345 MDIO_XS_DEVAD,
4346 MDIO_XS_SFX7101_XGXS_TEST1,
4347 0x100);
4348 DP(NETIF_MSG_LINK,
4349 "ext_phy_loopback: set ext phy loopback\n");
4350 break;
4351 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4352
4353 break;
4354 } /* switch external PHY type */
4355 } else {
4356 /* serdes */
4357 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4358 ext_phy_addr = (params->ext_phy_config &
4359 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
4360 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
4361 }
4362}
4363
4364
4365/*
4366 *------------------------------------------------------------------------
4367 * bnx2x_override_led_value -
4368 *
4369 * Override the led value of the requsted led
4370 *
4371 *------------------------------------------------------------------------
4372 */
4373u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
4374 u32 led_idx, u32 value)
4375{
4376 u32 reg_val;
4377
4378 /* If port 0 then use EMAC0, else use EMAC1*/
4379 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
4380
4381 DP(NETIF_MSG_LINK,
4382 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
4383 port, led_idx, value);
4384
4385 switch (led_idx) {
4386 case 0: /* 10MB led */
4387 /* Read the current value of the LED register in
4388 the EMAC block */
4389 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4390 /* Set the OVERRIDE bit to 1 */
4391 reg_val |= EMAC_LED_OVERRIDE;
4392 /* If value is 1, set the 10M_OVERRIDE bit,
4393 otherwise reset it.*/
4394 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
4395 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
4396 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4397 break;
4398 case 1: /*100MB led */
4399 /*Read the current value of the LED register in
4400 the EMAC block */
4401 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4402 /* Set the OVERRIDE bit to 1 */
4403 reg_val |= EMAC_LED_OVERRIDE;
4404 /* If value is 1, set the 100M_OVERRIDE bit,
4405 otherwise reset it.*/
4406 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
4407 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
4408 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4409 break;
4410 case 2: /* 1000MB led */
4411 /* Read the current value of the LED register in the
4412 EMAC block */
4413 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4414 /* Set the OVERRIDE bit to 1 */
4415 reg_val |= EMAC_LED_OVERRIDE;
4416 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
4417 reset it. */
4418 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
4419 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
4420 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4421 break;
4422 case 3: /* 2500MB led */
4423 /* Read the current value of the LED register in the
4424 EMAC block*/
4425 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4426 /* Set the OVERRIDE bit to 1 */
4427 reg_val |= EMAC_LED_OVERRIDE;
4428 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
4429 reset it.*/
4430 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
4431 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
4432 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4433 break;
4434 case 4: /*10G led */
4435 if (port == 0) {
4436 REG_WR(bp, NIG_REG_LED_10G_P0,
4437 value);
4438 } else {
4439 REG_WR(bp, NIG_REG_LED_10G_P1,
4440 value);
4441 }
4442 break;
4443 case 5: /* TRAFFIC led */
4444 /* Find if the traffic control is via BMAC or EMAC */
4445 if (port == 0)
4446 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
4447 else
4448 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
4449
4450 /* Override the traffic led in the EMAC:*/
4451 if (reg_val == 1) {
4452 /* Read the current value of the LED register in
4453 the EMAC block */
4454 reg_val = REG_RD(bp, emac_base +
4455 EMAC_REG_EMAC_LED);
4456 /* Set the TRAFFIC_OVERRIDE bit to 1 */
4457 reg_val |= EMAC_LED_OVERRIDE;
4458 /* If value is 1, set the TRAFFIC bit, otherwise
4459 reset it.*/
4460 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
4461 (reg_val & ~EMAC_LED_TRAFFIC);
4462 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4463 } else { /* Override the traffic led in the BMAC: */
4464 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4465 + port*4, 1);
4466 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
4467 value);
4468 }
4469 break;
4470 default:
4471 DP(NETIF_MSG_LINK,
4472 "bnx2x_override_led_value() unknown led index %d "
4473 "(should be 0-5)\n", led_idx);
4474 return -EINVAL;
4475 }
4476
4477 return 0;
4478}
4479
4480
4481u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
4482 u16 hw_led_mode, u32 chip_id)
4483{
4484 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004485 u32 tmp;
4486 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004487 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
4488 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
4489 speed, hw_led_mode);
4490 switch (mode) {
4491 case LED_MODE_OFF:
4492 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
4493 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4494 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004495
4496 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004497 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004498 break;
4499
4500 case LED_MODE_OPER:
4501 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
4502 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
4503 port*4, 0);
4504 /* Set blinking rate to ~15.9Hz */
4505 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
4506 LED_BLINK_RATE_VAL);
4507 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
4508 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004509 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004510 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004511 (tmp & (~EMAC_LED_OVERRIDE)));
4512
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004513 if (!CHIP_IS_E1H(bp) &&
4514 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004515 (speed == SPEED_1000) ||
4516 (speed == SPEED_100) ||
4517 (speed == SPEED_10))) {
4518 /* On Everest 1 Ax chip versions for speeds less than
4519 10G LED scheme is different */
4520 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4521 + port*4, 1);
4522 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
4523 port*4, 0);
4524 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
4525 port*4, 1);
4526 }
4527 break;
4528
4529 default:
4530 rc = -EINVAL;
4531 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
4532 mode);
4533 break;
4534 }
4535 return rc;
4536
4537}
4538
4539u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
4540{
4541 struct bnx2x *bp = params->bp;
4542 u16 gp_status = 0;
4543
4544 CL45_RD_OVER_CL22(bp, params->port,
4545 params->phy_addr,
4546 MDIO_REG_BANK_GP_STATUS,
4547 MDIO_GP_STATUS_TOP_AN_STATUS1,
4548 &gp_status);
4549 /* link is up only if both local phy and external phy are up */
4550 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
4551 bnx2x_ext_phy_is_link_up(params, vars))
4552 return 0;
4553
4554 return -ESRCH;
4555}
4556
4557static u8 bnx2x_link_initialize(struct link_params *params,
4558 struct link_vars *vars)
4559{
4560 struct bnx2x *bp = params->bp;
4561 u8 port = params->port;
4562 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004563 u8 non_ext_phy;
4564 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004565 /* Activate the external PHY */
4566 bnx2x_ext_phy_reset(params, vars);
4567
4568 bnx2x_set_aer_mmd(params, vars);
4569
4570 if (vars->phy_flags & PHY_XGXS_FLAG)
4571 bnx2x_set_master_ln(params);
4572
4573 rc = bnx2x_reset_unicore(params);
4574 /* reset the SerDes and wait for reset bit return low */
4575 if (rc != 0)
4576 return rc;
4577
4578 bnx2x_set_aer_mmd(params, vars);
4579
4580 /* setting the masterLn_def again after the reset */
4581 if (vars->phy_flags & PHY_XGXS_FLAG) {
4582 bnx2x_set_master_ln(params);
4583 bnx2x_set_swap_lanes(params);
4584 }
4585
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004586 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00004587 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004588 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00004589 (params->req_line_speed == SPEED_10))) ||
4590 (!params->req_line_speed &&
4591 (params->speed_cap_mask >=
4592 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
4593 (params->speed_cap_mask <
4594 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
4595 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004596 vars->phy_flags |= PHY_SGMII_FLAG;
4597 } else {
4598 vars->phy_flags &= ~PHY_SGMII_FLAG;
4599 }
4600 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004601 /* In case of external phy existance, the line speed would be the
4602 line speed linked up by the external phy. In case it is direct only,
4603 then the line_speed during initialization will be equal to the
4604 req_line_speed*/
4605 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004606
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004607 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004608
4609 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004610 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
4611 (params->loopback_mode == LOOPBACK_XGXS_10) ||
4612 (params->loopback_mode == LOOPBACK_EXT_PHY));
4613
4614 if (non_ext_phy ||
Eilon Greenstein589abe32009-02-12 08:36:55 +00004615 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Eilon Greenstein28577182009-02-12 08:37:00 +00004616 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
4617 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004618 if (params->req_line_speed == SPEED_AUTO_NEG)
4619 bnx2x_set_parallel_detection(params, vars->phy_flags);
4620 bnx2x_init_internal_phy(params, vars);
4621 }
4622
4623 if (!non_ext_phy)
4624 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004625
4626 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004627 (NIG_STATUS_XGXS0_LINK10G |
4628 NIG_STATUS_XGXS0_LINK_STATUS |
4629 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004630
4631 return rc;
4632
4633}
4634
4635
4636u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
4637{
4638 struct bnx2x *bp = params->bp;
4639
4640 u32 val;
Eilon Greenstein3196a882008-08-13 15:58:49 -07004641 DP(NETIF_MSG_LINK, "Phy Initialization started \n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004642 DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
4643 params->req_line_speed, params->req_flow_ctrl);
4644 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004645 vars->phy_link_up = 0;
4646 vars->link_up = 0;
4647 vars->line_speed = 0;
4648 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004649 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004650 vars->mac_type = MAC_TYPE_NONE;
4651
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004652 if (params->switch_cfg == SWITCH_CFG_1G)
4653 vars->phy_flags = PHY_SERDES_FLAG;
4654 else
4655 vars->phy_flags = PHY_XGXS_FLAG;
4656
Eilon Greenstein3196a882008-08-13 15:58:49 -07004657
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004658 /* disable attentions */
4659 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
4660 (NIG_MASK_XGXS0_LINK_STATUS |
4661 NIG_MASK_XGXS0_LINK10G |
4662 NIG_MASK_SERDES0_LINK_STATUS |
4663 NIG_MASK_MI_INT));
4664
4665 bnx2x_emac_init(params, vars);
4666
4667 if (CHIP_REV_IS_FPGA(bp)) {
4668 vars->link_up = 1;
4669 vars->line_speed = SPEED_10000;
4670 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004671 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004672 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004673 /* enable on E1.5 FPGA */
4674 if (CHIP_IS_E1H(bp)) {
4675 vars->flow_ctrl |=
David S. Millerc0700f92008-12-16 23:53:20 -08004676 (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004677 vars->link_status |=
4678 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
4679 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
4680 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004681
4682 bnx2x_emac_enable(params, vars, 0);
4683 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4684 /* disable drain */
4685 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4686 + params->port*4, 0);
4687
4688 /* update shared memory */
4689 bnx2x_update_mng(params, vars->link_status);
4690
4691 return 0;
4692
4693 } else
4694 if (CHIP_REV_IS_EMUL(bp)) {
4695
4696 vars->link_up = 1;
4697 vars->line_speed = SPEED_10000;
4698 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004699 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004700 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
4701
4702 bnx2x_bmac_enable(params, vars, 0);
4703
4704 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4705 /* Disable drain */
4706 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4707 + params->port*4, 0);
4708
4709 /* update shared memory */
4710 bnx2x_update_mng(params, vars->link_status);
4711
4712 return 0;
4713
4714 } else
4715 if (params->loopback_mode == LOOPBACK_BMAC) {
4716 vars->link_up = 1;
4717 vars->line_speed = SPEED_10000;
4718 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004719 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004720 vars->mac_type = MAC_TYPE_BMAC;
4721
4722 vars->phy_flags = PHY_XGXS_FLAG;
4723
4724 bnx2x_phy_deassert(params, vars->phy_flags);
4725 /* set bmac loopback */
4726 bnx2x_bmac_enable(params, vars, 1);
4727
4728 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4729 params->port*4, 0);
4730 } else if (params->loopback_mode == LOOPBACK_EMAC) {
4731 vars->link_up = 1;
4732 vars->line_speed = SPEED_1000;
4733 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004734 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004735 vars->mac_type = MAC_TYPE_EMAC;
4736
4737 vars->phy_flags = PHY_XGXS_FLAG;
4738
4739 bnx2x_phy_deassert(params, vars->phy_flags);
4740 /* set bmac loopback */
4741 bnx2x_emac_enable(params, vars, 1);
4742 bnx2x_emac_program(params, vars->line_speed,
4743 vars->duplex);
4744 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4745 params->port*4, 0);
4746 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
4747 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
4748 vars->link_up = 1;
4749 vars->line_speed = SPEED_10000;
4750 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004751 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004752
4753 vars->phy_flags = PHY_XGXS_FLAG;
4754
4755 val = REG_RD(bp,
4756 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4757 params->port*0x18);
4758 params->phy_addr = (u8)val;
4759
4760 bnx2x_phy_deassert(params, vars->phy_flags);
4761 bnx2x_link_initialize(params, vars);
4762
4763 vars->mac_type = MAC_TYPE_BMAC;
4764
4765 bnx2x_bmac_enable(params, vars, 0);
4766
4767 if (params->loopback_mode == LOOPBACK_XGXS_10) {
4768 /* set 10G XGXS loopback */
4769 bnx2x_set_xgxs_loopback(params, vars, 1);
4770 } else {
4771 /* set external phy loopback */
4772 bnx2x_ext_phy_loopback(params);
4773 }
4774 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4775 params->port*4, 0);
4776 } else
4777 /* No loopback */
4778 {
4779
4780 bnx2x_phy_deassert(params, vars->phy_flags);
4781 switch (params->switch_cfg) {
4782 case SWITCH_CFG_1G:
4783 vars->phy_flags |= PHY_SERDES_FLAG;
4784 if ((params->ext_phy_config &
4785 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
4786 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
4787 vars->phy_flags |=
4788 PHY_SGMII_FLAG;
4789 }
4790
4791 val = REG_RD(bp,
4792 NIG_REG_SERDES0_CTRL_PHY_ADDR+
4793 params->port*0x10);
4794
4795 params->phy_addr = (u8)val;
4796
4797 break;
4798 case SWITCH_CFG_10G:
4799 vars->phy_flags |= PHY_XGXS_FLAG;
4800 val = REG_RD(bp,
4801 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4802 params->port*0x18);
4803 params->phy_addr = (u8)val;
4804
4805 break;
4806 default:
4807 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
4808 return -EINVAL;
4809 break;
4810 }
4811
4812 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004813 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004814 bnx2x_link_int_enable(params);
4815 }
4816 return 0;
4817}
4818
Eilon Greenstein589abe32009-02-12 08:36:55 +00004819static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
4820{
4821 DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
4822
4823 /* Set serial boot control for external load */
4824 bnx2x_cl45_write(bp, port,
4825 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
4826 MDIO_PMA_DEVAD,
4827 MDIO_PMA_REG_GEN_CTRL, 0x0001);
4828
4829 /* Disable Transmitter */
4830 bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
4831
4832}
4833
4834u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
4835 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004836{
4837
4838 struct bnx2x *bp = params->bp;
4839 u32 ext_phy_config = params->ext_phy_config;
4840 u16 hw_led_mode = params->hw_led_mode;
4841 u32 chip_id = params->chip_id;
4842 u8 port = params->port;
4843 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4844 /* disable attentions */
4845
4846 vars->link_status = 0;
4847 bnx2x_update_mng(params, vars->link_status);
4848 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4849 (NIG_MASK_XGXS0_LINK_STATUS |
4850 NIG_MASK_XGXS0_LINK10G |
4851 NIG_MASK_SERDES0_LINK_STATUS |
4852 NIG_MASK_MI_INT));
4853
4854 /* activate nig drain */
4855 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4856
4857 /* disable nig egress interface */
4858 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4859 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4860
4861 /* Stop BigMac rx */
4862 bnx2x_bmac_rx_disable(bp, port);
4863
4864 /* disable emac */
4865 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4866
4867 msleep(10);
4868 /* The PHY reset is controled by GPIO 1
4869 * Hold it as vars low
4870 */
4871 /* clear link led */
4872 bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
Eilon Greenstein589abe32009-02-12 08:36:55 +00004873 if (reset_ext_phy) {
4874 switch (ext_phy_type) {
4875 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4876 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4877 break;
4878 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4879 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
4880 "low power mode\n",
4881 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004882 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004883 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4884 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00004885 break;
4886 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4887 {
4888 u8 ext_phy_addr = ((params->ext_phy_config &
4889 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4890 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4891 /* Set soft reset */
4892 bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
4893 break;
4894 }
4895 default:
4896 /* HW reset */
4897 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4898 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4899 port);
4900 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4901 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4902 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004903 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004904 }
4905 }
4906 /* reset the SerDes/XGXS */
4907 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
4908 (0x1ff << (port*16)));
4909
4910 /* reset BigMac */
4911 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
4912 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4913
4914 /* disable nig ingress interface */
4915 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
4916 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
4917 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4918 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4919 vars->link_up = 0;
4920 return 0;
4921}
4922
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004923static u8 bnx2x_update_link_down(struct link_params *params,
4924 struct link_vars *vars)
4925{
4926 struct bnx2x *bp = params->bp;
4927 u8 port = params->port;
4928 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
4929 bnx2x_set_led(bp, port, LED_MODE_OFF,
4930 0, params->hw_led_mode,
4931 params->chip_id);
4932
4933 /* indicate no mac active */
4934 vars->mac_type = MAC_TYPE_NONE;
4935
4936 /* update shared memory */
4937 vars->link_status = 0;
4938 vars->line_speed = 0;
4939 bnx2x_update_mng(params, vars->link_status);
4940
4941 /* activate nig drain */
4942 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4943
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004944 /* disable emac */
4945 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4946
4947 msleep(10);
4948
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004949 /* reset BigMac */
4950 bnx2x_bmac_rx_disable(bp, params->port);
4951 REG_WR(bp, GRCBASE_MISC +
4952 MISC_REGISTERS_RESET_REG_2_CLEAR,
4953 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4954 return 0;
4955}
4956
4957static u8 bnx2x_update_link_up(struct link_params *params,
4958 struct link_vars *vars,
4959 u8 link_10g, u32 gp_status)
4960{
4961 struct bnx2x *bp = params->bp;
4962 u8 port = params->port;
4963 u8 rc = 0;
4964 vars->link_status |= LINK_STATUS_LINK_UP;
4965 if (link_10g) {
4966 bnx2x_bmac_enable(params, vars, 0);
4967 bnx2x_set_led(bp, port, LED_MODE_OPER,
4968 SPEED_10000, params->hw_led_mode,
4969 params->chip_id);
4970
4971 } else {
4972 bnx2x_emac_enable(params, vars, 0);
4973 rc = bnx2x_emac_program(params, vars->line_speed,
4974 vars->duplex);
4975
4976 /* AN complete? */
4977 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
4978 if (!(vars->phy_flags &
4979 PHY_SGMII_FLAG))
4980 bnx2x_set_sgmii_tx_driver(params);
4981 }
4982 }
4983
4984 /* PBF - link up */
4985 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
4986 vars->line_speed);
4987
4988 /* disable drain */
4989 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
4990
4991 /* update shared memory */
4992 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004993 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004994 return rc;
4995}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004996/* This function should called upon link interrupt */
4997/* In case vars->link_up, driver needs to
4998 1. Update the pbf
4999 2. Disable drain
5000 3. Update the shared memory
5001 4. Indicate link up
5002 5. Set LEDs
5003 Otherwise,
5004 1. Update shared memory
5005 2. Reset BigMac
5006 3. Report link down
5007 4. Unset LEDs
5008*/
5009u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
5010{
5011 struct bnx2x *bp = params->bp;
5012 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005013 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005014 u8 link_10g;
5015 u8 ext_phy_link_up, rc = 0;
5016 u32 ext_phy_type;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005017
5018 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
5019 port,
5020 (vars->phy_flags & PHY_XGXS_FLAG),
5021 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
5022
5023 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
5024 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5025 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
5026 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
5027
5028 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5029 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5030 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5031
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005032 /* disable emac */
5033 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5034
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005035 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005036
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005037 /* Check external link change only for non-direct */
5038 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
5039
5040 /* Read gp_status */
5041 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
5042 MDIO_REG_BANK_GP_STATUS,
5043 MDIO_GP_STATUS_TOP_AN_STATUS1,
5044 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005045
5046 rc = bnx2x_link_settings_status(params, vars, gp_status);
5047 if (rc != 0)
5048 return rc;
5049
5050 /* anything 10 and over uses the bmac */
5051 link_10g = ((vars->line_speed == SPEED_10000) ||
5052 (vars->line_speed == SPEED_12000) ||
5053 (vars->line_speed == SPEED_12500) ||
5054 (vars->line_speed == SPEED_13000) ||
5055 (vars->line_speed == SPEED_15000) ||
5056 (vars->line_speed == SPEED_16000));
5057
5058 bnx2x_link_int_ack(params, vars, link_10g);
5059
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005060 /* In case external phy link is up, and internal link is down
5061 ( not initialized yet probably after link initialization, it needs
5062 to be initialized.
5063 Note that after link down-up as result of cable plug,
5064 the xgxs link would probably become up again without the need to
5065 initialize it*/
5066
5067 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
5068 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
Eilon Greenstein589abe32009-02-12 08:36:55 +00005069 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005070 (ext_phy_link_up && !vars->phy_link_up))
5071 bnx2x_init_internal_phy(params, vars);
5072
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005073 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005074 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005075
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005076 if (vars->link_up)
5077 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
5078 else
5079 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005080
5081 return rc;
5082}
5083
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005084static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5085{
5086 u8 ext_phy_addr[PORT_MAX];
5087 u16 val;
5088 s8 port;
5089
5090 /* PART1 - Reset both phys */
5091 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5092 /* Extract the ext phy address for the port */
5093 u32 ext_phy_config = REG_RD(bp, shmem_base +
5094 offsetof(struct shmem_region,
5095 dev_info.port_hw_config[port].external_phy_config));
5096
5097 /* disable attentions */
5098 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5099 (NIG_MASK_XGXS0_LINK_STATUS |
5100 NIG_MASK_XGXS0_LINK10G |
5101 NIG_MASK_SERDES0_LINK_STATUS |
5102 NIG_MASK_MI_INT));
5103
5104 ext_phy_addr[port] =
5105 ((ext_phy_config &
5106 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5107 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5108
5109 /* Need to take the phy out of low power mode in order
5110 to write to access its registers */
5111 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5112 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
5113
5114 /* Reset the phy */
5115 bnx2x_cl45_write(bp, port,
5116 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5117 ext_phy_addr[port],
5118 MDIO_PMA_DEVAD,
5119 MDIO_PMA_REG_CTRL,
5120 1<<15);
5121 }
5122
5123 /* Add delay of 150ms after reset */
5124 msleep(150);
5125
5126 /* PART2 - Download firmware to both phys */
5127 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5128 u16 fw_ver1;
5129
5130 bnx2x_bcm8073_external_rom_boot(bp, port,
5131 ext_phy_addr[port]);
5132
5133 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5134 ext_phy_addr[port],
5135 MDIO_PMA_DEVAD,
5136 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00005137 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005138 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00005139 "bnx2x_8073_common_init_phy port %x:"
5140 "Download failed. fw version = 0x%x\n",
5141 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005142 return -EINVAL;
5143 }
5144
5145 /* Only set bit 10 = 1 (Tx power down) */
5146 bnx2x_cl45_read(bp, port,
5147 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5148 ext_phy_addr[port],
5149 MDIO_PMA_DEVAD,
5150 MDIO_PMA_REG_TX_POWER_DOWN, &val);
5151
5152 /* Phase1 of TX_POWER_DOWN reset */
5153 bnx2x_cl45_write(bp, port,
5154 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5155 ext_phy_addr[port],
5156 MDIO_PMA_DEVAD,
5157 MDIO_PMA_REG_TX_POWER_DOWN,
5158 (val | 1<<10));
5159 }
5160
5161 /* Toggle Transmitter: Power down and then up with 600ms
5162 delay between */
5163 msleep(600);
5164
5165 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
5166 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5167 /* Phase2 of POWER_DOWN_RESET*/
5168 /* Release bit 10 (Release Tx power down) */
5169 bnx2x_cl45_read(bp, port,
5170 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5171 ext_phy_addr[port],
5172 MDIO_PMA_DEVAD,
5173 MDIO_PMA_REG_TX_POWER_DOWN, &val);
5174
5175 bnx2x_cl45_write(bp, port,
5176 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5177 ext_phy_addr[port],
5178 MDIO_PMA_DEVAD,
5179 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
5180 msleep(15);
5181
5182 /* Read modify write the SPI-ROM version select register */
5183 bnx2x_cl45_read(bp, port,
5184 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5185 ext_phy_addr[port],
5186 MDIO_PMA_DEVAD,
5187 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
5188 bnx2x_cl45_write(bp, port,
5189 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5190 ext_phy_addr[port],
5191 MDIO_PMA_DEVAD,
5192 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
5193
5194 /* set GPIO2 back to LOW */
5195 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5196 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
5197 }
5198 return 0;
5199
5200}
5201
Eilon Greenstein589abe32009-02-12 08:36:55 +00005202
5203static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5204{
5205 u8 ext_phy_addr;
5206 u32 val;
5207 s8 port;
5208 /* Use port1 because of the static port-swap */
5209 /* Enable the module detection interrupt */
5210 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
5211 val |= ((1<<MISC_REGISTERS_GPIO_3)|
5212 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
5213 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
5214
5215 bnx2x_hw_reset(bp, 1);
5216 msleep(5);
5217 for (port = 0; port < PORT_MAX; port++) {
5218 /* Extract the ext phy address for the port */
5219 u32 ext_phy_config = REG_RD(bp, shmem_base +
5220 offsetof(struct shmem_region,
5221 dev_info.port_hw_config[port].external_phy_config));
5222
5223 ext_phy_addr =
5224 ((ext_phy_config &
5225 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5226 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5227 DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
5228 ext_phy_addr);
5229
5230 bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
5231
5232 /* Set fault module detected LED on */
5233 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5234 MISC_REGISTERS_GPIO_HIGH,
5235 port);
5236 }
5237
5238 return 0;
5239}
5240
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005241u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5242{
5243 u8 rc = 0;
5244 u32 ext_phy_type;
5245
5246 DP(NETIF_MSG_LINK, "bnx2x_common_init_phy\n");
5247
5248 /* Read the ext_phy_type for arbitrary port(0) */
5249 ext_phy_type = XGXS_EXT_PHY_TYPE(
5250 REG_RD(bp, shmem_base +
5251 offsetof(struct shmem_region,
5252 dev_info.port_hw_config[0].external_phy_config)));
5253
5254 switch (ext_phy_type) {
5255 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
5256 {
5257 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
5258 break;
5259 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00005260 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5261 /* GPIO1 affects both ports, so there's need to pull
5262 it for single port alone */
5263 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
5264
5265 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005266 default:
5267 DP(NETIF_MSG_LINK,
5268 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
5269 ext_phy_type);
5270 break;
5271 }
5272
5273 return rc;
5274}
5275
5276
5277
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005278static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
5279{
5280 u16 val, cnt;
5281
5282 bnx2x_cl45_read(bp, port,
5283 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5284 phy_addr,
5285 MDIO_PMA_DEVAD,
5286 MDIO_PMA_REG_7101_RESET, &val);
5287
5288 for (cnt = 0; cnt < 10; cnt++) {
5289 msleep(50);
5290 /* Writes a self-clearing reset */
5291 bnx2x_cl45_write(bp, port,
5292 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5293 phy_addr,
5294 MDIO_PMA_DEVAD,
5295 MDIO_PMA_REG_7101_RESET,
5296 (val | (1<<15)));
5297 /* Wait for clear */
5298 bnx2x_cl45_read(bp, port,
5299 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5300 phy_addr,
5301 MDIO_PMA_DEVAD,
5302 MDIO_PMA_REG_7101_RESET, &val);
5303
5304 if ((val & (1<<15)) == 0)
5305 break;
5306 }
5307}
5308#define RESERVED_SIZE 256
5309/* max application is 160K bytes - data at end of RAM */
Eilon Greenstein6378c022008-08-13 15:59:25 -07005310#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005311
5312/* Header is 14 bytes */
5313#define HEADER_SIZE 14
5314#define DATA_OFFSET HEADER_SIZE
5315
5316#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \
5317 bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \
5318 ext_phy_addr, \
5319 MDIO_PCS_DEVAD, \
5320 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1)
5321
5322/* Programs an image to DSP's flash via the SPI port*/
5323static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port,
5324 u8 ext_phy_addr,
5325 char data[], u32 size)
5326{
5327 const u16 num_trans = size/4; /* 4 bytes can be sent at a time */
5328 /* Doesn't include last trans!*/
5329 const u16 last_trans_size = size%4; /* Num bytes on last trans */
5330 u16 trans_cnt, byte_cnt;
5331 u32 data_index;
5332 u16 tmp;
5333 u16 code_started = 0;
5334 u16 image_revision1, image_revision2;
5335 u16 cnt;
5336
5337 DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size);
5338 /* Going to flash*/
5339 if ((size-HEADER_SIZE) > MAX_APP_SIZE) {
5340 /* This very often will be the case, because the image is built
5341 with 160Kbytes size whereas the total image size must actually
5342 be 160Kbytes-RESERVED_SIZE */
5343 DP(NETIF_MSG_LINK, "Warning, file size was %d bytes "
5344 "truncated to %d bytes\n", size, MAX_APP_SIZE);
5345 size = MAX_APP_SIZE+HEADER_SIZE;
5346 }
5347 DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005348 DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005349 /* Put the DSP in download mode by setting FLASH_CFG[2] to 1
5350 and issuing a reset.*/
5351
5352 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005353 MISC_REGISTERS_GPIO_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005354
5355 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
5356
5357 /* wait 0.5 sec */
5358 for (cnt = 0; cnt < 100; cnt++)
5359 msleep(5);
5360
5361 /* Make sure we can access the DSP
5362 And it's in the correct mode (waiting for download) */
5363
5364 bnx2x_cl45_read(bp, port,
5365 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5366 ext_phy_addr,
5367 MDIO_PCS_DEVAD,
5368 MDIO_PCS_REG_7101_DSP_ACCESS, &tmp);
5369
5370 if (tmp != 0x000A) {
5371 DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. "
5372 "Expected 0x000A, read 0x%04X\n", tmp);
5373 DP(NETIF_MSG_LINK, "Download failed\n");
5374 return -EINVAL;
5375 }
5376
5377 /* Mux the SPI interface away from the internal processor */
5378 bnx2x_cl45_write(bp, port,
5379 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5380 ext_phy_addr,
5381 MDIO_PCS_DEVAD,
5382 MDIO_PCS_REG_7101_SPI_MUX, 1);
5383
5384 /* Reset the SPI port */
5385 bnx2x_cl45_write(bp, port,
5386 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5387 ext_phy_addr,
5388 MDIO_PCS_DEVAD,
5389 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
5390 bnx2x_cl45_write(bp, port,
5391 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5392 ext_phy_addr,
5393 MDIO_PCS_DEVAD,
5394 MDIO_PCS_REG_7101_SPI_CTRL_ADDR,
5395 (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT));
5396 bnx2x_cl45_write(bp, port,
5397 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5398 ext_phy_addr,
5399 MDIO_PCS_DEVAD,
5400 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
5401
5402 /* Erase the flash */
5403 bnx2x_cl45_write(bp, port,
5404 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5405 ext_phy_addr,
5406 MDIO_PCS_DEVAD,
5407 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5408 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5409
5410 bnx2x_cl45_write(bp, port,
5411 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5412 ext_phy_addr,
5413 MDIO_PCS_DEVAD,
5414 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5415 1);
5416
5417 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5418 bnx2x_cl45_write(bp, port,
5419 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5420 ext_phy_addr,
5421 MDIO_PCS_DEVAD,
5422 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5423 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD);
5424
5425 bnx2x_cl45_write(bp, port,
5426 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5427 ext_phy_addr,
5428 MDIO_PCS_DEVAD,
5429 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5430 1);
5431 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5432
5433 /* Wait 10 seconds, the maximum time for the erase to complete */
5434 DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n");
5435 for (cnt = 0; cnt < 1000; cnt++)
5436 msleep(10);
5437
5438 DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n");
5439 data_index = 0;
5440 for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) {
5441 bnx2x_cl45_write(bp, port,
5442 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5443 ext_phy_addr,
5444 MDIO_PCS_DEVAD,
5445 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5446 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5447
5448 bnx2x_cl45_write(bp, port,
5449 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5450 ext_phy_addr,
5451 MDIO_PCS_DEVAD,
5452 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5453 1);
5454 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5455
5456 bnx2x_cl45_write(bp, port,
5457 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5458 ext_phy_addr,
5459 MDIO_PCS_DEVAD,
5460 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5461 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
5462
5463 /* Bits 23-16 of address */
5464 bnx2x_cl45_write(bp, port,
5465 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5466 ext_phy_addr,
5467 MDIO_PCS_DEVAD,
5468 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5469 (data_index>>16));
5470 /* Bits 15-8 of address */
5471 bnx2x_cl45_write(bp, port,
5472 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5473 ext_phy_addr,
5474 MDIO_PCS_DEVAD,
5475 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5476 (data_index>>8));
5477
5478 /* Bits 7-0 of address */
5479 bnx2x_cl45_write(bp, port,
5480 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5481 ext_phy_addr,
5482 MDIO_PCS_DEVAD,
5483 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5484 ((u16)data_index));
5485
5486 byte_cnt = 0;
5487 while (byte_cnt < 4 && data_index < size) {
5488 bnx2x_cl45_write(bp, port,
5489 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5490 ext_phy_addr,
5491 MDIO_PCS_DEVAD,
5492 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5493 data[data_index++]);
5494 byte_cnt++;
5495 }
5496
5497 bnx2x_cl45_write(bp, port,
5498 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5499 ext_phy_addr,
5500 MDIO_PCS_DEVAD,
5501 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5502 byte_cnt+4);
5503
5504 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5505 msleep(5); /* Wait 5 ms minimum between transs */
5506
5507 /* Let the user know something's going on.*/
5508 /* a pacifier ever 4K */
5509 if ((data_index % 1023) == 0)
5510 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
5511 }
5512
5513 DP(NETIF_MSG_LINK, "\n");
5514 /* Transfer the last block if there is data remaining */
5515 if (last_trans_size) {
5516 bnx2x_cl45_write(bp, port,
5517 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5518 ext_phy_addr,
5519 MDIO_PCS_DEVAD,
5520 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5521 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5522
5523 bnx2x_cl45_write(bp, port,
5524 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5525 ext_phy_addr,
5526 MDIO_PCS_DEVAD,
5527 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5528 1);
5529
5530 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5531
5532 bnx2x_cl45_write(bp, port,
5533 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5534 ext_phy_addr,
5535 MDIO_PCS_DEVAD,
5536 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5537 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
5538
5539 /* Bits 23-16 of address */
5540 bnx2x_cl45_write(bp, port,
5541 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5542 ext_phy_addr,
5543 MDIO_PCS_DEVAD,
5544 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5545 (data_index>>16));
5546 /* Bits 15-8 of address */
5547 bnx2x_cl45_write(bp, port,
5548 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5549 ext_phy_addr,
5550 MDIO_PCS_DEVAD,
5551 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5552 (data_index>>8));
5553
5554 /* Bits 7-0 of address */
5555 bnx2x_cl45_write(bp, port,
5556 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5557 ext_phy_addr,
5558 MDIO_PCS_DEVAD,
5559 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5560 ((u16)data_index));
5561
5562 byte_cnt = 0;
5563 while (byte_cnt < last_trans_size && data_index < size) {
5564 /* Bits 7-0 of address */
5565 bnx2x_cl45_write(bp, port,
5566 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5567 ext_phy_addr,
5568 MDIO_PCS_DEVAD,
5569 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5570 data[data_index++]);
5571 byte_cnt++;
5572 }
5573
5574 bnx2x_cl45_write(bp, port,
5575 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5576 ext_phy_addr,
5577 MDIO_PCS_DEVAD,
5578 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5579 byte_cnt+4);
5580
5581 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5582 }
5583
5584 /* DSP Remove Download Mode */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005585 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5586 MISC_REGISTERS_GPIO_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005587
5588 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
5589
5590 /* wait 0.5 sec to allow it to run */
5591 for (cnt = 0; cnt < 100; cnt++)
5592 msleep(5);
5593
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005594 bnx2x_hw_reset(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005595
5596 for (cnt = 0; cnt < 100; cnt++)
5597 msleep(5);
5598
5599 /* Check that the code is started. In case the download
5600 checksum failed, the code won't be started. */
5601 bnx2x_cl45_read(bp, port,
5602 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5603 ext_phy_addr,
5604 MDIO_PCS_DEVAD,
5605 MDIO_PCS_REG_7101_DSP_ACCESS,
5606 &tmp);
5607
5608 code_started = (tmp & (1<<4));
5609 if (!code_started) {
5610 DP(NETIF_MSG_LINK, "Download failed. Please check file.\n");
5611 return -EINVAL;
5612 }
5613
5614 /* Verify that the file revision is now equal to the image
5615 revision within the DSP */
5616 bnx2x_cl45_read(bp, port,
5617 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5618 ext_phy_addr,
5619 MDIO_PMA_DEVAD,
5620 MDIO_PMA_REG_7101_VER1,
5621 &image_revision1);
5622
5623 bnx2x_cl45_read(bp, port,
5624 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5625 ext_phy_addr,
5626 MDIO_PMA_DEVAD,
5627 MDIO_PMA_REG_7101_VER2,
5628 &image_revision2);
5629
Eilon Greenstein3196a882008-08-13 15:58:49 -07005630 if (data[0x14e] != (image_revision2&0xFF) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005631 data[0x14f] != ((image_revision2&0xFF00)>>8) ||
5632 data[0x150] != (image_revision1&0xFF) ||
5633 data[0x151] != ((image_revision1&0xFF00)>>8)) {
5634 DP(NETIF_MSG_LINK, "Download failed.\n");
5635 return -EINVAL;
5636 }
5637 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
5638 return 0;
5639}
5640
5641u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
5642 u8 driver_loaded, char data[], u32 size)
5643{
5644 u8 rc = 0;
5645 u32 ext_phy_type;
5646 u8 ext_phy_addr;
5647 ext_phy_addr = ((ext_phy_config &
5648 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5649 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5650
5651 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
5652
5653 switch (ext_phy_type) {
5654 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5655 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
5656 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5657 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
5658 DP(NETIF_MSG_LINK,
5659 "Flash download not supported for this ext phy\n");
5660 rc = -EINVAL;
5661 break;
5662 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5663 /* Take ext phy out of reset */
5664 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005665 bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005666 rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
5667 data, size);
5668 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005669 bnx2x_turn_off_sf(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005670 break;
5671 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
5672 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
5673 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
5674 default:
5675 DP(NETIF_MSG_LINK, "Invalid ext phy type\n");
5676 rc = -EINVAL;
5677 break;
5678 }
5679 return rc;
5680}
5681