blob: 693efce7cda5f0dbf5aed18983d63ec3f8b55a06 [file] [log] [blame]
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001/* Copyright 2008 Broadcom Corporation
2 *
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>
24#include <linux/version.h>
25
26#include "bnx2x_reg.h"
27#include "bnx2x_fw_defs.h"
28#include "bnx2x_hsi.h"
29#include "bnx2x_link.h"
30#include "bnx2x.h"
31
32/********************************************************/
33#define SUPPORT_CL73 0 /* Currently no */
34#define ETH_HLEN 14
35#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
36#define ETH_MIN_PACKET_SIZE 60
37#define ETH_MAX_PACKET_SIZE 1500
38#define ETH_MAX_JUMBO_PACKET_SIZE 9600
39#define MDIO_ACCESS_TIMEOUT 1000
40#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070041
42/***********************************************************/
43/* Shortcut definitions */
44/***********************************************************/
45
46#define NIG_STATUS_XGXS0_LINK10G \
47 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
48#define NIG_STATUS_XGXS0_LINK_STATUS \
49 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
50#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
51 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
52#define NIG_STATUS_SERDES0_LINK_STATUS \
53 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
54#define NIG_MASK_MI_INT \
55 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
56#define NIG_MASK_XGXS0_LINK10G \
57 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
58#define NIG_MASK_XGXS0_LINK_STATUS \
59 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
60#define NIG_MASK_SERDES0_LINK_STATUS \
61 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
62
63#define MDIO_AN_CL73_OR_37_COMPLETE \
64 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
65 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
66
67#define XGXS_RESET_BITS \
68 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
71 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
72 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
73
74#define SERDES_RESET_BITS \
75 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
77 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
78 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
79
80#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
81#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
82#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
83#define AUTONEG_PARALLEL \
84 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
85#define AUTONEG_SGMII_FIBER_AUTODET \
86 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
87#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
88
89#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
90 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
91#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
92 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
93#define GP_STATUS_SPEED_MASK \
94 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
95#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
96#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
97#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
98#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
99#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
100#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
101#define GP_STATUS_10G_HIG \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
103#define GP_STATUS_10G_CX4 \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
105#define GP_STATUS_12G_HIG \
106 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
107#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
108#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
109#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
110#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
111#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
112#define GP_STATUS_10G_KX4 \
113 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
114
115#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
116#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
117#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
118#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
119#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
120#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
121#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
122#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
123#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
124#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
125#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
126#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
127#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
128#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
129#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
130#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
131#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
132#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
133#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
134#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
135#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
136#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
137#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
138
139#define PHY_XGXS_FLAG 0x1
140#define PHY_SGMII_FLAG 0x2
141#define PHY_SERDES_FLAG 0x4
142
143/**********************************************************/
144/* INTERFACE */
145/**********************************************************/
146#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
147 bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
148 DEFAULT_PHY_DEV_ADDR, \
149 (_bank + (_addr & 0xf)), \
150 _val)
151
152#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
153 bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
154 DEFAULT_PHY_DEV_ADDR, \
155 (_bank + (_addr & 0xf)), \
156 _val)
157
158static void bnx2x_set_phy_mdio(struct link_params *params)
159{
160 struct bnx2x *bp = params->bp;
161 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
162 params->port*0x18, 0);
163 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
164 DEFAULT_PHY_DEV_ADDR);
165}
166
167static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
168{
169 u32 val = REG_RD(bp, reg);
170
171 val |= bits;
172 REG_WR(bp, reg, val);
173 return val;
174}
175
176static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
177{
178 u32 val = REG_RD(bp, reg);
179
180 val &= ~bits;
181 REG_WR(bp, reg, val);
182 return val;
183}
184
185static void bnx2x_emac_init(struct link_params *params,
186 struct link_vars *vars)
187{
188 /* reset and unreset the emac core */
189 struct bnx2x *bp = params->bp;
190 u8 port = params->port;
191 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
192 u32 val;
193 u16 timeout;
194
195 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
196 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
197 udelay(5);
198 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
199 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
200
201 /* init emac - use read-modify-write */
202 /* self clear reset */
203 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
204 EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
205
206 timeout = 200;
207 do
208 {
209 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
210 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
211 if (!timeout) {
212 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
213 return;
214 }
215 timeout--;
216 }while (val & EMAC_MODE_RESET);
217
218 /* Set mac address */
219 val = ((params->mac_addr[0] << 8) |
220 params->mac_addr[1]);
221 EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val);
222
223 val = ((params->mac_addr[2] << 24) |
224 (params->mac_addr[3] << 16) |
225 (params->mac_addr[4] << 8) |
226 params->mac_addr[5]);
227 EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val);
228}
229
230static u8 bnx2x_emac_enable(struct link_params *params,
231 struct link_vars *vars, u8 lb)
232{
233 struct bnx2x *bp = params->bp;
234 u8 port = params->port;
235 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
236 u32 val;
237
238 DP(NETIF_MSG_LINK, "enabling EMAC\n");
239
240 /* enable emac and not bmac */
241 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
242
243 /* for paladium */
244 if (CHIP_REV_IS_EMUL(bp)) {
245 /* Use lane 1 (of lanes 0-3) */
246 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
247 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
248 port*4, 1);
249 }
250 /* for fpga */
251 else
252
253 if (CHIP_REV_IS_FPGA(bp)) {
254 /* Use lane 1 (of lanes 0-3) */
255 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
256
257 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
258 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
259 0);
260 } else
261 /* ASIC */
262 if (vars->phy_flags & PHY_XGXS_FLAG) {
263 u32 ser_lane = ((params->lane_config &
264 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
265 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
266
267 DP(NETIF_MSG_LINK, "XGXS\n");
268 /* select the master lanes (out of 0-3) */
269 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
270 port*4, ser_lane);
271 /* select XGXS */
272 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
273 port*4, 1);
274
275 } else { /* SerDes */
276 DP(NETIF_MSG_LINK, "SerDes\n");
277 /* select SerDes */
278 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
279 port*4, 0);
280 }
281
282 /* enable emac */
283 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
284
285 if (CHIP_REV_IS_SLOW(bp)) {
286 /* config GMII mode */
287 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
288 EMAC_WR(EMAC_REG_EMAC_MODE,
289 (val | EMAC_MODE_PORT_GMII));
290 } else { /* ASIC */
291 /* pause enable/disable */
292 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
293 EMAC_RX_MODE_FLOW_EN);
294 if (vars->flow_ctrl & FLOW_CTRL_RX)
295 bnx2x_bits_en(bp, emac_base +
296 EMAC_REG_EMAC_RX_MODE,
297 EMAC_RX_MODE_FLOW_EN);
298
299 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700300 (EMAC_TX_MODE_EXT_PAUSE_EN |
301 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700302 if (vars->flow_ctrl & FLOW_CTRL_TX)
303 bnx2x_bits_en(bp, emac_base +
304 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700305 (EMAC_TX_MODE_EXT_PAUSE_EN |
306 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700307 }
308
309 /* KEEP_VLAN_TAG, promiscuous */
310 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
311 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
312 EMAC_WR(EMAC_REG_EMAC_RX_MODE, val);
313
314 /* Set Loopback */
315 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
316 if (lb)
317 val |= 0x810;
318 else
319 val &= ~0x810;
320 EMAC_WR(EMAC_REG_EMAC_MODE, val);
321
322 /* enable emac for jumbo packets */
323 EMAC_WR(EMAC_REG_EMAC_RX_MTU_SIZE,
324 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
325 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
326
327 /* strip CRC */
328 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
329
330 /* disable the NIG in/out to the bmac */
331 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
332 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
333 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
334
335 /* enable the NIG in/out to the emac */
336 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
337 val = 0;
338 if (vars->flow_ctrl & FLOW_CTRL_TX)
339 val = 1;
340
341 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
342 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
343
344 if (CHIP_REV_IS_EMUL(bp)) {
345 /* take the BigMac out of reset */
346 REG_WR(bp,
347 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
348 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
349
350 /* enable access for bmac registers */
351 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
352 }
353
354 vars->mac_type = MAC_TYPE_EMAC;
355 return 0;
356}
357
358
359
360static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
361 u8 is_lb)
362{
363 struct bnx2x *bp = params->bp;
364 u8 port = params->port;
365 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
366 NIG_REG_INGRESS_BMAC0_MEM;
367 u32 wb_data[2];
368 u32 val;
369
370 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
371 /* reset and unreset the BigMac */
372 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
373 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
374 msleep(1);
375
376 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
377 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
378
379 /* enable access for bmac registers */
380 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
381
382 /* XGXS control */
383 wb_data[0] = 0x3c;
384 wb_data[1] = 0;
385 REG_WR_DMAE(bp, bmac_addr +
386 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
387 wb_data, 2);
388
389 /* tx MAC SA */
390 wb_data[0] = ((params->mac_addr[2] << 24) |
391 (params->mac_addr[3] << 16) |
392 (params->mac_addr[4] << 8) |
393 params->mac_addr[5]);
394 wb_data[1] = ((params->mac_addr[0] << 8) |
395 params->mac_addr[1]);
396 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
397 wb_data, 2);
398
399 /* tx control */
400 val = 0xc0;
401 if (vars->flow_ctrl & FLOW_CTRL_TX)
402 val |= 0x800000;
403 wb_data[0] = val;
404 wb_data[1] = 0;
405 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
406 wb_data, 2);
407
408 /* mac control */
409 val = 0x3;
410 if (is_lb) {
411 val |= 0x4;
412 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
413 }
414 wb_data[0] = val;
415 wb_data[1] = 0;
416 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
417 wb_data, 2);
418
419
420 /* set rx mtu */
421 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
422 wb_data[1] = 0;
423 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
424 wb_data, 2);
425
426 /* rx control set to don't strip crc */
427 val = 0x14;
428 if (vars->flow_ctrl & FLOW_CTRL_RX)
429 val |= 0x20;
430 wb_data[0] = val;
431 wb_data[1] = 0;
432 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
433 wb_data, 2);
434
435 /* set tx mtu */
436 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
437 wb_data[1] = 0;
438 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
439 wb_data, 2);
440
441 /* set cnt max size */
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_CNT_MAX_SIZE,
445 wb_data, 2);
446
447 /* configure safc */
448 wb_data[0] = 0x1000200;
449 wb_data[1] = 0;
450 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
451 wb_data, 2);
452 /* fix for emulation */
453 if (CHIP_REV_IS_EMUL(bp)) {
454 wb_data[0] = 0xf000;
455 wb_data[1] = 0;
456 REG_WR_DMAE(bp,
457 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
458 wb_data, 2);
459 }
460
461 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
462 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
463 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
464 val = 0;
465 if (vars->flow_ctrl & FLOW_CTRL_TX)
466 val = 1;
467 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
468 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
469 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
470 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
471 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
472 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
473
474 vars->mac_type = MAC_TYPE_BMAC;
475 return 0;
476}
477
478static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
479{
480 struct bnx2x *bp = params->bp;
481 u32 val;
482
483 if (phy_flags & PHY_XGXS_FLAG) {
484 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
485 val = XGXS_RESET_BITS;
486
487 } else { /* SerDes */
488 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
489 val = SERDES_RESET_BITS;
490 }
491
492 val = val << (params->port*16);
493
494 /* reset and unreset the SerDes/XGXS */
495 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
496 val);
497 udelay(500);
498 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
499 val);
500 bnx2x_set_phy_mdio(params);
501}
502
503void bnx2x_link_status_update(struct link_params *params,
504 struct link_vars *vars)
505{
506 struct bnx2x *bp = params->bp;
507 u8 link_10g;
508 u8 port = params->port;
509
510 if (params->switch_cfg == SWITCH_CFG_1G)
511 vars->phy_flags = PHY_SERDES_FLAG;
512 else
513 vars->phy_flags = PHY_XGXS_FLAG;
514 vars->link_status = REG_RD(bp, params->shmem_base +
515 offsetof(struct shmem_region,
516 port_mb[port].link_status));
517
518 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
519
520 if (vars->link_up) {
521 DP(NETIF_MSG_LINK, "phy link up\n");
522
523 vars->phy_link_up = 1;
524 vars->duplex = DUPLEX_FULL;
525 switch (vars->link_status &
526 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
527 case LINK_10THD:
528 vars->duplex = DUPLEX_HALF;
529 /* fall thru */
530 case LINK_10TFD:
531 vars->line_speed = SPEED_10;
532 break;
533
534 case LINK_100TXHD:
535 vars->duplex = DUPLEX_HALF;
536 /* fall thru */
537 case LINK_100T4:
538 case LINK_100TXFD:
539 vars->line_speed = SPEED_100;
540 break;
541
542 case LINK_1000THD:
543 vars->duplex = DUPLEX_HALF;
544 /* fall thru */
545 case LINK_1000TFD:
546 vars->line_speed = SPEED_1000;
547 break;
548
549 case LINK_2500THD:
550 vars->duplex = DUPLEX_HALF;
551 /* fall thru */
552 case LINK_2500TFD:
553 vars->line_speed = SPEED_2500;
554 break;
555
556 case LINK_10GTFD:
557 vars->line_speed = SPEED_10000;
558 break;
559
560 case LINK_12GTFD:
561 vars->line_speed = SPEED_12000;
562 break;
563
564 case LINK_12_5GTFD:
565 vars->line_speed = SPEED_12500;
566 break;
567
568 case LINK_13GTFD:
569 vars->line_speed = SPEED_13000;
570 break;
571
572 case LINK_15GTFD:
573 vars->line_speed = SPEED_15000;
574 break;
575
576 case LINK_16GTFD:
577 vars->line_speed = SPEED_16000;
578 break;
579
580 default:
581 break;
582 }
583
584 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
585 vars->flow_ctrl |= FLOW_CTRL_TX;
586 else
587 vars->flow_ctrl &= ~FLOW_CTRL_TX;
588
589 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
590 vars->flow_ctrl |= FLOW_CTRL_RX;
591 else
592 vars->flow_ctrl &= ~FLOW_CTRL_RX;
593
594 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700595 if (vars->line_speed &&
596 ((vars->line_speed == SPEED_10) ||
597 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700598 vars->phy_flags |= PHY_SGMII_FLAG;
599 } else {
600 vars->phy_flags &= ~PHY_SGMII_FLAG;
601 }
602 }
603
604 /* anything 10 and over uses the bmac */
605 link_10g = ((vars->line_speed == SPEED_10000) ||
606 (vars->line_speed == SPEED_12000) ||
607 (vars->line_speed == SPEED_12500) ||
608 (vars->line_speed == SPEED_13000) ||
609 (vars->line_speed == SPEED_15000) ||
610 (vars->line_speed == SPEED_16000));
611 if (link_10g)
612 vars->mac_type = MAC_TYPE_BMAC;
613 else
614 vars->mac_type = MAC_TYPE_EMAC;
615
616 } else { /* link down */
617 DP(NETIF_MSG_LINK, "phy link down\n");
618
619 vars->phy_link_up = 0;
620
621 vars->line_speed = 0;
622 vars->duplex = DUPLEX_FULL;
623 vars->flow_ctrl = FLOW_CTRL_NONE;
624
625 /* indicate no mac active */
626 vars->mac_type = MAC_TYPE_NONE;
627 }
628
629 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
630 vars->link_status, vars->phy_link_up);
631 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
632 vars->line_speed, vars->duplex, vars->flow_ctrl);
633}
634
635static void bnx2x_update_mng(struct link_params *params, u32 link_status)
636{
637 struct bnx2x *bp = params->bp;
638 REG_WR(bp, params->shmem_base +
639 offsetof(struct shmem_region,
640 port_mb[params->port].link_status),
641 link_status);
642}
643
644static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
645{
646 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
647 NIG_REG_INGRESS_BMAC0_MEM;
648 u32 wb_data[2];
649 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
650
651 /* Only if the bmac is out of reset */
652 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
653 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
654 nig_bmac_enable) {
655
656 /* Clear Rx Enable bit in BMAC_CONTROL register */
657 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
658 wb_data, 2);
659 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
660 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
661 wb_data, 2);
662
663 msleep(1);
664 }
665}
666
667static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
668 u32 line_speed)
669{
670 struct bnx2x *bp = params->bp;
671 u8 port = params->port;
672 u32 init_crd, crd;
673 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700674
675 /* disable port */
676 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
677
678 /* wait for init credit */
679 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
680 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
681 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
682
683 while ((init_crd != crd) && count) {
684 msleep(5);
685
686 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
687 count--;
688 }
689 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
690 if (init_crd != crd) {
691 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
692 init_crd, crd);
693 return -EINVAL;
694 }
695
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700696 if (flow_ctrl & FLOW_CTRL_RX ||
697 line_speed == SPEED_10 ||
698 line_speed == SPEED_100 ||
699 line_speed == SPEED_1000 ||
700 line_speed == SPEED_2500) {
701 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700702 /* update threshold */
703 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
704 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700705 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700706
707 } else {
708 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
709 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700710 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700711 /* update threshold */
712 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
713 /* update init credit */
714 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700715 case SPEED_10000:
716 init_crd = thresh + 553 - 22;
717 break;
718
719 case SPEED_12000:
720 init_crd = thresh + 664 - 22;
721 break;
722
723 case SPEED_13000:
724 init_crd = thresh + 742 - 22;
725 break;
726
727 case SPEED_16000:
728 init_crd = thresh + 778 - 22;
729 break;
730 default:
731 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
732 line_speed);
733 return -EINVAL;
734 break;
735 }
736 }
737 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
738 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
739 line_speed, init_crd);
740
741 /* probe the credit changes */
742 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
743 msleep(5);
744 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
745
746 /* enable port */
747 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
748 return 0;
749}
750
751static u32 bnx2x_get_emac_base(u32 ext_phy_type, u8 port)
752{
753 u32 emac_base;
754 switch (ext_phy_type) {
755 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
756 emac_base = GRCBASE_EMAC0;
757 break;
758 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
759 emac_base = (port) ? GRCBASE_EMAC0: GRCBASE_EMAC1;
760 break;
761 default:
762 emac_base = (port) ? GRCBASE_EMAC1: GRCBASE_EMAC0;
763 break;
764 }
765 return emac_base;
766
767}
768
769u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
770 u8 phy_addr, u8 devad, u16 reg, u16 val)
771{
772 u32 tmp, saved_mode;
773 u8 i, rc = 0;
774 u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
775
776 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
777 * (a value of 49==0x31) and make sure that the AUTO poll is off
778 */
779 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
780 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
781 EMAC_MDIO_MODE_CLOCK_CNT);
782 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
783 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
784 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
785 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
786 udelay(40);
787
788 /* address */
789
790 tmp = ((phy_addr << 21) | (devad << 16) | reg |
791 EMAC_MDIO_COMM_COMMAND_ADDRESS |
792 EMAC_MDIO_COMM_START_BUSY);
793 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
794
795 for (i = 0; i < 50; i++) {
796 udelay(10);
797
798 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
799 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
800 udelay(5);
801 break;
802 }
803 }
804 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
805 DP(NETIF_MSG_LINK, "write phy register failed\n");
806 rc = -EFAULT;
807 } else {
808 /* data */
809 tmp = ((phy_addr << 21) | (devad << 16) | val |
810 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
811 EMAC_MDIO_COMM_START_BUSY);
812 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
813
814 for (i = 0; i < 50; i++) {
815 udelay(10);
816
817 tmp = REG_RD(bp, mdio_ctrl +
818 EMAC_REG_EMAC_MDIO_COMM);
819 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
820 udelay(5);
821 break;
822 }
823 }
824 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
825 DP(NETIF_MSG_LINK, "write phy register failed\n");
826 rc = -EFAULT;
827 }
828 }
829
830 /* Restore the saved mode */
831 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
832
833 return rc;
834}
835
836u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
837 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
838{
839 u32 val, saved_mode;
840 u16 i;
841 u8 rc = 0;
842
843 u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
844 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
845 * (a value of 49==0x31) and make sure that the AUTO poll is off
846 */
847 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
848 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
849 EMAC_MDIO_MODE_CLOCK_CNT));
850 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
851 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
852 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
853 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
854 udelay(40);
855
856 /* address */
857 val = ((phy_addr << 21) | (devad << 16) | reg |
858 EMAC_MDIO_COMM_COMMAND_ADDRESS |
859 EMAC_MDIO_COMM_START_BUSY);
860 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
861
862 for (i = 0; i < 50; i++) {
863 udelay(10);
864
865 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
866 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
867 udelay(5);
868 break;
869 }
870 }
871 if (val & EMAC_MDIO_COMM_START_BUSY) {
872 DP(NETIF_MSG_LINK, "read phy register failed\n");
873
874 *ret_val = 0;
875 rc = -EFAULT;
876
877 } else {
878 /* data */
879 val = ((phy_addr << 21) | (devad << 16) |
880 EMAC_MDIO_COMM_COMMAND_READ_45 |
881 EMAC_MDIO_COMM_START_BUSY);
882 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
883
884 for (i = 0; i < 50; i++) {
885 udelay(10);
886
887 val = REG_RD(bp, mdio_ctrl +
888 EMAC_REG_EMAC_MDIO_COMM);
889 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
890 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
891 break;
892 }
893 }
894 if (val & EMAC_MDIO_COMM_START_BUSY) {
895 DP(NETIF_MSG_LINK, "read phy register failed\n");
896
897 *ret_val = 0;
898 rc = -EFAULT;
899 }
900 }
901
902 /* Restore the saved mode */
903 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
904
905 return rc;
906}
907
908static void bnx2x_set_aer_mmd(struct link_params *params,
909 struct link_vars *vars)
910{
911 struct bnx2x *bp = params->bp;
912 u32 ser_lane;
913 u16 offset;
914
915 ser_lane = ((params->lane_config &
916 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
917 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
918
919 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
920 (params->phy_addr + ser_lane) : 0;
921
922 CL45_WR_OVER_CL22(bp, params->port,
923 params->phy_addr,
924 MDIO_REG_BANK_AER_BLOCK,
925 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
926}
927
928static void bnx2x_set_master_ln(struct link_params *params)
929{
930 struct bnx2x *bp = params->bp;
931 u16 new_master_ln, ser_lane;
932 ser_lane = ((params->lane_config &
933 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
934 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
935
936 /* set the master_ln for AN */
937 CL45_RD_OVER_CL22(bp, params->port,
938 params->phy_addr,
939 MDIO_REG_BANK_XGXS_BLOCK2,
940 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
941 &new_master_ln);
942
943 CL45_WR_OVER_CL22(bp, params->port,
944 params->phy_addr,
945 MDIO_REG_BANK_XGXS_BLOCK2 ,
946 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
947 (new_master_ln | ser_lane));
948}
949
950static u8 bnx2x_reset_unicore(struct link_params *params)
951{
952 struct bnx2x *bp = params->bp;
953 u16 mii_control;
954 u16 i;
955
956 CL45_RD_OVER_CL22(bp, params->port,
957 params->phy_addr,
958 MDIO_REG_BANK_COMBO_IEEE0,
959 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
960
961 /* reset the unicore */
962 CL45_WR_OVER_CL22(bp, params->port,
963 params->phy_addr,
964 MDIO_REG_BANK_COMBO_IEEE0,
965 MDIO_COMBO_IEEE0_MII_CONTROL,
966 (mii_control |
967 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
968
969 /* wait for the reset to self clear */
970 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
971 udelay(5);
972
973 /* the reset erased the previous bank value */
974 CL45_RD_OVER_CL22(bp, params->port,
975 params->phy_addr,
976 MDIO_REG_BANK_COMBO_IEEE0,
977 MDIO_COMBO_IEEE0_MII_CONTROL,
978 &mii_control);
979
980 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
981 udelay(5);
982 return 0;
983 }
984 }
985
986 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
987 return -EINVAL;
988
989}
990
991static void bnx2x_set_swap_lanes(struct link_params *params)
992{
993 struct bnx2x *bp = params->bp;
994 /* Each two bits represents a lane number:
995 No swap is 0123 => 0x1b no need to enable the swap */
996 u16 ser_lane, rx_lane_swap, tx_lane_swap;
997
998 ser_lane = ((params->lane_config &
999 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1000 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1001 rx_lane_swap = ((params->lane_config &
1002 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1003 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1004 tx_lane_swap = ((params->lane_config &
1005 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1006 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1007
1008 if (rx_lane_swap != 0x1b) {
1009 CL45_WR_OVER_CL22(bp, params->port,
1010 params->phy_addr,
1011 MDIO_REG_BANK_XGXS_BLOCK2,
1012 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1013 (rx_lane_swap |
1014 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1015 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1016 } else {
1017 CL45_WR_OVER_CL22(bp, params->port,
1018 params->phy_addr,
1019 MDIO_REG_BANK_XGXS_BLOCK2,
1020 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1021 }
1022
1023 if (tx_lane_swap != 0x1b) {
1024 CL45_WR_OVER_CL22(bp, params->port,
1025 params->phy_addr,
1026 MDIO_REG_BANK_XGXS_BLOCK2,
1027 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1028 (tx_lane_swap |
1029 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1030 } else {
1031 CL45_WR_OVER_CL22(bp, params->port,
1032 params->phy_addr,
1033 MDIO_REG_BANK_XGXS_BLOCK2,
1034 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1035 }
1036}
1037
1038static void bnx2x_set_parallel_detection(struct link_params *params,
1039 u8 phy_flags)
1040{
1041 struct bnx2x *bp = params->bp;
1042 u16 control2;
1043
1044 CL45_RD_OVER_CL22(bp, params->port,
1045 params->phy_addr,
1046 MDIO_REG_BANK_SERDES_DIGITAL,
1047 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1048 &control2);
1049
1050
1051 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1052
1053
1054 CL45_WR_OVER_CL22(bp, params->port,
1055 params->phy_addr,
1056 MDIO_REG_BANK_SERDES_DIGITAL,
1057 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1058 control2);
1059
1060 if (phy_flags & PHY_XGXS_FLAG) {
1061 DP(NETIF_MSG_LINK, "XGXS\n");
1062
1063 CL45_WR_OVER_CL22(bp, params->port,
1064 params->phy_addr,
1065 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1066 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1067 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1068
1069 CL45_RD_OVER_CL22(bp, params->port,
1070 params->phy_addr,
1071 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1072 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1073 &control2);
1074
1075
1076 control2 |=
1077 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1078
1079 CL45_WR_OVER_CL22(bp, params->port,
1080 params->phy_addr,
1081 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1082 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1083 control2);
1084
1085 /* Disable parallel detection of HiG */
1086 CL45_WR_OVER_CL22(bp, params->port,
1087 params->phy_addr,
1088 MDIO_REG_BANK_XGXS_BLOCK2,
1089 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1090 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1091 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1092 }
1093}
1094
1095static void bnx2x_set_autoneg(struct link_params *params,
1096 struct link_vars *vars)
1097{
1098 struct bnx2x *bp = params->bp;
1099 u16 reg_val;
1100
1101 /* CL37 Autoneg */
1102
1103 CL45_RD_OVER_CL22(bp, params->port,
1104 params->phy_addr,
1105 MDIO_REG_BANK_COMBO_IEEE0,
1106 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1107
1108 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001109 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001110 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1111 else /* CL37 Autoneg Disabled */
1112 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1113 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1114
1115 CL45_WR_OVER_CL22(bp, params->port,
1116 params->phy_addr,
1117 MDIO_REG_BANK_COMBO_IEEE0,
1118 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1119
1120 /* Enable/Disable Autodetection */
1121
1122 CL45_RD_OVER_CL22(bp, params->port,
1123 params->phy_addr,
1124 MDIO_REG_BANK_SERDES_DIGITAL,
1125 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
1126 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001127 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001128 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1129 else
1130 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1131
1132 CL45_WR_OVER_CL22(bp, params->port,
1133 params->phy_addr,
1134 MDIO_REG_BANK_SERDES_DIGITAL,
1135 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1136
1137 /* Enable TetonII and BAM autoneg */
1138 CL45_RD_OVER_CL22(bp, params->port,
1139 params->phy_addr,
1140 MDIO_REG_BANK_BAM_NEXT_PAGE,
1141 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1142 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001143 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001144 /* Enable BAM aneg Mode and TetonII aneg Mode */
1145 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1146 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1147 } else {
1148 /* TetonII and BAM Autoneg Disabled */
1149 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1150 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1151 }
1152 CL45_WR_OVER_CL22(bp, params->port,
1153 params->phy_addr,
1154 MDIO_REG_BANK_BAM_NEXT_PAGE,
1155 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1156 reg_val);
1157
1158 /* Enable Clause 73 Aneg */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001159 if ((vars->line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001160 (SUPPORT_CL73)) {
1161 /* Enable BAM Station Manager */
1162
1163 CL45_WR_OVER_CL22(bp, params->port,
1164 params->phy_addr,
1165 MDIO_REG_BANK_CL73_USERB0,
1166 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1167 (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1168 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1169 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN));
1170
1171 /* Merge CL73 and CL37 aneg resolution */
1172 CL45_RD_OVER_CL22(bp, params->port,
1173 params->phy_addr,
1174 MDIO_REG_BANK_CL73_USERB0,
1175 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1176 &reg_val);
1177
1178 CL45_WR_OVER_CL22(bp, params->port,
1179 params->phy_addr,
1180 MDIO_REG_BANK_CL73_USERB0,
1181 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1182 (reg_val |
1183 MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR));
1184
1185 /* Set the CL73 AN speed */
1186
1187 CL45_RD_OVER_CL22(bp, params->port,
1188 params->phy_addr,
1189 MDIO_REG_BANK_CL73_IEEEB1,
1190 MDIO_CL73_IEEEB1_AN_ADV2, &reg_val);
1191 /* In the SerDes we support only the 1G.
1192 In the XGXS we support the 10G KX4
1193 but we currently do not support the KR */
1194 if (vars->phy_flags & PHY_XGXS_FLAG) {
1195 DP(NETIF_MSG_LINK, "XGXS\n");
1196 /* 10G KX4 */
1197 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1198 } else {
1199 DP(NETIF_MSG_LINK, "SerDes\n");
1200 /* 1000M KX */
1201 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
1202 }
1203 CL45_WR_OVER_CL22(bp, params->port,
1204 params->phy_addr,
1205 MDIO_REG_BANK_CL73_IEEEB1,
1206 MDIO_CL73_IEEEB1_AN_ADV2, reg_val);
1207
1208 /* CL73 Autoneg Enabled */
1209 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1210 } else {
1211 /* CL73 Autoneg Disabled */
1212 reg_val = 0;
1213 }
1214 CL45_WR_OVER_CL22(bp, params->port,
1215 params->phy_addr,
1216 MDIO_REG_BANK_CL73_IEEEB0,
1217 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1218}
1219
1220/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001221static void bnx2x_program_serdes(struct link_params *params,
1222 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001223{
1224 struct bnx2x *bp = params->bp;
1225 u16 reg_val;
1226
1227 /* program duplex, disable autoneg */
1228
1229 CL45_RD_OVER_CL22(bp, params->port,
1230 params->phy_addr,
1231 MDIO_REG_BANK_COMBO_IEEE0,
1232 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1233 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
1234 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN);
1235 if (params->req_duplex == DUPLEX_FULL)
1236 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1237 CL45_WR_OVER_CL22(bp, params->port,
1238 params->phy_addr,
1239 MDIO_REG_BANK_COMBO_IEEE0,
1240 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1241
1242 /* program speed
1243 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001244 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001245 params->phy_addr,
1246 MDIO_REG_BANK_SERDES_DIGITAL,
1247 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001248 /* clearing the speed value before setting the right speed */
1249 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1250
1251 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1252 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1253
1254 if (!((vars->line_speed == SPEED_1000) ||
1255 (vars->line_speed == SPEED_100) ||
1256 (vars->line_speed == SPEED_10))) {
1257
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001258 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1259 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001260 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001261 reg_val |=
1262 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001263 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001264 reg_val |=
1265 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001266 }
1267
1268 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001269 params->phy_addr,
1270 MDIO_REG_BANK_SERDES_DIGITAL,
1271 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001272
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001273}
1274
1275static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1276{
1277 struct bnx2x *bp = params->bp;
1278 u16 val = 0;
1279
1280 /* configure the 48 bits for BAM AN */
1281
1282 /* set extended capabilities */
1283 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1284 val |= MDIO_OVER_1G_UP1_2_5G;
1285 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1286 val |= MDIO_OVER_1G_UP1_10G;
1287 CL45_WR_OVER_CL22(bp, params->port,
1288 params->phy_addr,
1289 MDIO_REG_BANK_OVER_1G,
1290 MDIO_OVER_1G_UP1, val);
1291
1292 CL45_WR_OVER_CL22(bp, params->port,
1293 params->phy_addr,
1294 MDIO_REG_BANK_OVER_1G,
1295 MDIO_OVER_1G_UP3, 0);
1296}
1297
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001298static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001299{
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001300 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001301 /* resolve pause mode and advertisement
1302 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1303
1304 switch (params->req_flow_ctrl) {
1305 case FLOW_CTRL_AUTO:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001306 if (params->req_fc_auto_adv == FLOW_CTRL_BOTH) {
1307 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001308 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1309 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001310 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001311 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1312 }
1313 break;
1314 case FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001315 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001316 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1317 break;
1318
1319 case FLOW_CTRL_RX:
1320 case FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001321 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001322 break;
1323
1324 case FLOW_CTRL_NONE:
1325 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001326 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001327 break;
1328 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001329}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001330
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001331static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
1332 u32 ieee_fc)
1333{
1334 struct bnx2x *bp = params->bp;
1335 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001336
1337 CL45_WR_OVER_CL22(bp, params->port,
1338 params->phy_addr,
1339 MDIO_REG_BANK_COMBO_IEEE0,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001340 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001341}
1342
1343static void bnx2x_restart_autoneg(struct link_params *params)
1344{
1345 struct bnx2x *bp = params->bp;
1346 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
1347 if (SUPPORT_CL73) {
1348 /* enable and restart clause 73 aneg */
1349 u16 an_ctrl;
1350
1351 CL45_RD_OVER_CL22(bp, params->port,
1352 params->phy_addr,
1353 MDIO_REG_BANK_CL73_IEEEB0,
1354 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1355 &an_ctrl);
1356 CL45_WR_OVER_CL22(bp, params->port,
1357 params->phy_addr,
1358 MDIO_REG_BANK_CL73_IEEEB0,
1359 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1360 (an_ctrl |
1361 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1362 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1363
1364 } else {
1365 /* Enable and restart BAM/CL37 aneg */
1366 u16 mii_control;
1367
1368 CL45_RD_OVER_CL22(bp, params->port,
1369 params->phy_addr,
1370 MDIO_REG_BANK_COMBO_IEEE0,
1371 MDIO_COMBO_IEEE0_MII_CONTROL,
1372 &mii_control);
1373 DP(NETIF_MSG_LINK,
1374 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1375 mii_control);
1376 CL45_WR_OVER_CL22(bp, params->port,
1377 params->phy_addr,
1378 MDIO_REG_BANK_COMBO_IEEE0,
1379 MDIO_COMBO_IEEE0_MII_CONTROL,
1380 (mii_control |
1381 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1382 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1383 }
1384}
1385
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001386static void bnx2x_initialize_sgmii_process(struct link_params *params,
1387 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001388{
1389 struct bnx2x *bp = params->bp;
1390 u16 control1;
1391
1392 /* in SGMII mode, the unicore is always slave */
1393
1394 CL45_RD_OVER_CL22(bp, params->port,
1395 params->phy_addr,
1396 MDIO_REG_BANK_SERDES_DIGITAL,
1397 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1398 &control1);
1399 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1400 /* set sgmii mode (and not fiber) */
1401 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1402 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1403 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1404 CL45_WR_OVER_CL22(bp, params->port,
1405 params->phy_addr,
1406 MDIO_REG_BANK_SERDES_DIGITAL,
1407 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1408 control1);
1409
1410 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001411 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001412 /* set speed, disable autoneg */
1413 u16 mii_control;
1414
1415 CL45_RD_OVER_CL22(bp, params->port,
1416 params->phy_addr,
1417 MDIO_REG_BANK_COMBO_IEEE0,
1418 MDIO_COMBO_IEEE0_MII_CONTROL,
1419 &mii_control);
1420 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1421 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1422 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1423
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001424 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001425 case SPEED_100:
1426 mii_control |=
1427 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1428 break;
1429 case SPEED_1000:
1430 mii_control |=
1431 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1432 break;
1433 case SPEED_10:
1434 /* there is nothing to set for 10M */
1435 break;
1436 default:
1437 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001438 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1439 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001440 break;
1441 }
1442
1443 /* setting the full duplex */
1444 if (params->req_duplex == DUPLEX_FULL)
1445 mii_control |=
1446 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1447 CL45_WR_OVER_CL22(bp, params->port,
1448 params->phy_addr,
1449 MDIO_REG_BANK_COMBO_IEEE0,
1450 MDIO_COMBO_IEEE0_MII_CONTROL,
1451 mii_control);
1452
1453 } else { /* AN mode */
1454 /* enable and restart AN */
1455 bnx2x_restart_autoneg(params);
1456 }
1457}
1458
1459
1460/*
1461 * link management
1462 */
1463
1464static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001465{ /* LD LP */
1466 switch (pause_result) { /* ASYM P ASYM P */
1467 case 0xb: /* 1 0 1 1 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001468 vars->flow_ctrl = FLOW_CTRL_TX;
1469 break;
1470
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001471 case 0xe: /* 1 1 1 0 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001472 vars->flow_ctrl = FLOW_CTRL_RX;
1473 break;
1474
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001475 case 0x5: /* 0 1 0 1 */
1476 case 0x7: /* 0 1 1 1 */
1477 case 0xd: /* 1 1 0 1 */
1478 case 0xf: /* 1 1 1 1 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001479 vars->flow_ctrl = FLOW_CTRL_BOTH;
1480 break;
1481
1482 default:
1483 break;
1484 }
1485}
1486
1487static u8 bnx2x_ext_phy_resove_fc(struct link_params *params,
1488 struct link_vars *vars)
1489{
1490 struct bnx2x *bp = params->bp;
1491 u8 ext_phy_addr;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001492 u16 ld_pause; /* local */
1493 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001494 u16 an_complete; /* AN complete */
1495 u16 pause_result;
1496 u8 ret = 0;
1497 u32 ext_phy_type;
1498 u8 port = params->port;
1499 ext_phy_addr = ((params->ext_phy_config &
1500 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1501 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1502
1503 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1504 /* read twice */
1505
1506 bnx2x_cl45_read(bp, port,
1507 ext_phy_type,
1508 ext_phy_addr,
1509 MDIO_AN_DEVAD,
1510 MDIO_AN_REG_STATUS, &an_complete);
1511 bnx2x_cl45_read(bp, port,
1512 ext_phy_type,
1513 ext_phy_addr,
1514 MDIO_AN_DEVAD,
1515 MDIO_AN_REG_STATUS, &an_complete);
1516
1517 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1518 ret = 1;
1519 bnx2x_cl45_read(bp, port,
1520 ext_phy_type,
1521 ext_phy_addr,
1522 MDIO_AN_DEVAD,
1523 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1524 bnx2x_cl45_read(bp, port,
1525 ext_phy_type,
1526 ext_phy_addr,
1527 MDIO_AN_DEVAD,
1528 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1529 pause_result = (ld_pause &
1530 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1531 pause_result |= (lp_pause &
1532 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1533 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
1534 pause_result);
1535 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001536 if (vars->flow_ctrl == FLOW_CTRL_NONE &&
1537 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1538 bnx2x_cl45_read(bp, port,
1539 ext_phy_type,
1540 ext_phy_addr,
1541 MDIO_AN_DEVAD,
1542 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1543
1544 bnx2x_cl45_read(bp, port,
1545 ext_phy_type,
1546 ext_phy_addr,
1547 MDIO_AN_DEVAD,
1548 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1549 pause_result = (ld_pause &
1550 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1551 pause_result |= (lp_pause &
1552 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1553
1554 bnx2x_pause_resolve(vars, pause_result);
1555 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
1556 pause_result);
1557 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001558 }
1559 return ret;
1560}
1561
1562
1563static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1564 struct link_vars *vars,
1565 u32 gp_status)
1566{
1567 struct bnx2x *bp = params->bp;
1568 u16 ld_pause; /* local driver */
1569 u16 lp_pause; /* link partner */
1570 u16 pause_result;
1571
1572 vars->flow_ctrl = FLOW_CTRL_NONE;
1573
1574 /* resolve from gp_status in case of AN complete and not sgmii */
1575 if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) &&
1576 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1577 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1578 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1579 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
1580 CL45_RD_OVER_CL22(bp, params->port,
1581 params->phy_addr,
1582 MDIO_REG_BANK_COMBO_IEEE0,
1583 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1584 &ld_pause);
1585 CL45_RD_OVER_CL22(bp, params->port,
1586 params->phy_addr,
1587 MDIO_REG_BANK_COMBO_IEEE0,
1588 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1589 &lp_pause);
1590 pause_result = (ld_pause &
1591 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
1592 pause_result |= (lp_pause &
1593 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
1594 DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
1595 bnx2x_pause_resolve(vars, pause_result);
1596 } else if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) &&
1597 (bnx2x_ext_phy_resove_fc(params, vars))) {
1598 return;
1599 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001600 if (params->req_flow_ctrl == FLOW_CTRL_AUTO)
1601 vars->flow_ctrl = params->req_fc_auto_adv;
1602 else
1603 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001604 }
1605 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1606}
1607
1608
1609static u8 bnx2x_link_settings_status(struct link_params *params,
1610 struct link_vars *vars,
1611 u32 gp_status)
1612{
1613 struct bnx2x *bp = params->bp;
1614 u8 rc = 0;
1615 vars->link_status = 0;
1616
1617 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1618 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1619 gp_status);
1620
1621 vars->phy_link_up = 1;
1622 vars->link_status |= LINK_STATUS_LINK_UP;
1623
1624 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1625 vars->duplex = DUPLEX_FULL;
1626 else
1627 vars->duplex = DUPLEX_HALF;
1628
1629 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1630
1631 switch (gp_status & GP_STATUS_SPEED_MASK) {
1632 case GP_STATUS_10M:
1633 vars->line_speed = SPEED_10;
1634 if (vars->duplex == DUPLEX_FULL)
1635 vars->link_status |= LINK_10TFD;
1636 else
1637 vars->link_status |= LINK_10THD;
1638 break;
1639
1640 case GP_STATUS_100M:
1641 vars->line_speed = SPEED_100;
1642 if (vars->duplex == DUPLEX_FULL)
1643 vars->link_status |= LINK_100TXFD;
1644 else
1645 vars->link_status |= LINK_100TXHD;
1646 break;
1647
1648 case GP_STATUS_1G:
1649 case GP_STATUS_1G_KX:
1650 vars->line_speed = SPEED_1000;
1651 if (vars->duplex == DUPLEX_FULL)
1652 vars->link_status |= LINK_1000TFD;
1653 else
1654 vars->link_status |= LINK_1000THD;
1655 break;
1656
1657 case GP_STATUS_2_5G:
1658 vars->line_speed = SPEED_2500;
1659 if (vars->duplex == DUPLEX_FULL)
1660 vars->link_status |= LINK_2500TFD;
1661 else
1662 vars->link_status |= LINK_2500THD;
1663 break;
1664
1665 case GP_STATUS_5G:
1666 case GP_STATUS_6G:
1667 DP(NETIF_MSG_LINK,
1668 "link speed unsupported gp_status 0x%x\n",
1669 gp_status);
1670 return -EINVAL;
1671 break;
1672 case GP_STATUS_10G_KX4:
1673 case GP_STATUS_10G_HIG:
1674 case GP_STATUS_10G_CX4:
1675 vars->line_speed = SPEED_10000;
1676 vars->link_status |= LINK_10GTFD;
1677 break;
1678
1679 case GP_STATUS_12G_HIG:
1680 vars->line_speed = SPEED_12000;
1681 vars->link_status |= LINK_12GTFD;
1682 break;
1683
1684 case GP_STATUS_12_5G:
1685 vars->line_speed = SPEED_12500;
1686 vars->link_status |= LINK_12_5GTFD;
1687 break;
1688
1689 case GP_STATUS_13G:
1690 vars->line_speed = SPEED_13000;
1691 vars->link_status |= LINK_13GTFD;
1692 break;
1693
1694 case GP_STATUS_15G:
1695 vars->line_speed = SPEED_15000;
1696 vars->link_status |= LINK_15GTFD;
1697 break;
1698
1699 case GP_STATUS_16G:
1700 vars->line_speed = SPEED_16000;
1701 vars->link_status |= LINK_16GTFD;
1702 break;
1703
1704 default:
1705 DP(NETIF_MSG_LINK,
1706 "link speed unsupported gp_status 0x%x\n",
1707 gp_status);
1708 return -EINVAL;
1709 break;
1710 }
1711
1712 vars->link_status |= LINK_STATUS_SERDES_LINK;
1713
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001714 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1715 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1716 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1717 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1718 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001719 vars->autoneg = AUTO_NEG_ENABLED;
1720
1721 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1722 vars->autoneg |= AUTO_NEG_COMPLETE;
1723 vars->link_status |=
1724 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1725 }
1726
1727 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1728 vars->link_status |=
1729 LINK_STATUS_PARALLEL_DETECTION_USED;
1730
1731 }
1732 if (vars->flow_ctrl & FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001733 vars->link_status |=
1734 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001735
1736 if (vars->flow_ctrl & FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001737 vars->link_status |=
1738 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001739
1740 } else { /* link_down */
1741 DP(NETIF_MSG_LINK, "phy link down\n");
1742
1743 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001744
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001745 vars->duplex = DUPLEX_FULL;
1746 vars->flow_ctrl = FLOW_CTRL_NONE;
1747 vars->autoneg = AUTO_NEG_DISABLED;
1748 vars->mac_type = MAC_TYPE_NONE;
1749 }
1750
1751 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n",
1752 gp_status, vars->phy_link_up, vars->line_speed);
1753 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1754 " autoneg 0x%x\n",
1755 vars->duplex,
1756 vars->flow_ctrl, vars->autoneg);
1757 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1758
1759 return rc;
1760}
1761
1762static void bnx2x_set_sgmii_tx_driver(struct link_params *params)
1763{
1764 struct bnx2x *bp = params->bp;
1765 u16 lp_up2;
1766 u16 tx_driver;
1767
1768 /* read precomp */
1769
1770 CL45_RD_OVER_CL22(bp, params->port,
1771 params->phy_addr,
1772 MDIO_REG_BANK_OVER_1G,
1773 MDIO_OVER_1G_LP_UP2, &lp_up2);
1774
1775 CL45_RD_OVER_CL22(bp, params->port,
1776 params->phy_addr,
1777 MDIO_REG_BANK_TX0,
1778 MDIO_TX0_TX_DRIVER, &tx_driver);
1779
1780 /* bits [10:7] at lp_up2, positioned at [15:12] */
1781 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1782 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1783 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1784
1785 if ((lp_up2 != 0) &&
1786 (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) {
1787 /* replace tx_driver bits [15:12] */
1788 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1789 tx_driver |= lp_up2;
1790 CL45_WR_OVER_CL22(bp, params->port,
1791 params->phy_addr,
1792 MDIO_REG_BANK_TX0,
1793 MDIO_TX0_TX_DRIVER, tx_driver);
1794 }
1795}
1796
1797static u8 bnx2x_emac_program(struct link_params *params,
1798 u32 line_speed, u32 duplex)
1799{
1800 struct bnx2x *bp = params->bp;
1801 u8 port = params->port;
1802 u16 mode = 0;
1803
1804 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1805 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1806 EMAC_REG_EMAC_MODE,
1807 (EMAC_MODE_25G_MODE |
1808 EMAC_MODE_PORT_MII_10M |
1809 EMAC_MODE_HALF_DUPLEX));
1810 switch (line_speed) {
1811 case SPEED_10:
1812 mode |= EMAC_MODE_PORT_MII_10M;
1813 break;
1814
1815 case SPEED_100:
1816 mode |= EMAC_MODE_PORT_MII;
1817 break;
1818
1819 case SPEED_1000:
1820 mode |= EMAC_MODE_PORT_GMII;
1821 break;
1822
1823 case SPEED_2500:
1824 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
1825 break;
1826
1827 default:
1828 /* 10G not valid for EMAC */
1829 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
1830 return -EINVAL;
1831 }
1832
1833 if (duplex == DUPLEX_HALF)
1834 mode |= EMAC_MODE_HALF_DUPLEX;
1835 bnx2x_bits_en(bp,
1836 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
1837 mode);
1838
1839 bnx2x_set_led(bp, params->port, LED_MODE_OPER,
1840 line_speed, params->hw_led_mode, params->chip_id);
1841 return 0;
1842}
1843
1844/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001845/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001846/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001847static void bnx2x_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001848{
1849 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001850 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001851 msleep(1);
1852 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001853 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001854}
1855
1856static void bnx2x_ext_phy_reset(struct link_params *params,
1857 struct link_vars *vars)
1858{
1859 struct bnx2x *bp = params->bp;
1860 u32 ext_phy_type;
1861 u8 ext_phy_addr = ((params->ext_phy_config &
1862 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1863 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1864 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
1865 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1866 /* The PHY reset is controled by GPIO 1
1867 * Give it 1ms of reset pulse
1868 */
1869 if (vars->phy_flags & PHY_XGXS_FLAG) {
1870
1871 switch (ext_phy_type) {
1872 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
1873 DP(NETIF_MSG_LINK, "XGXS Direct\n");
1874 break;
1875
1876 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
1877 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
1878 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
1879
1880 /* Restore normal power mode*/
1881 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001882 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1883 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001884
1885 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001886 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001887
1888 bnx2x_cl45_write(bp, params->port,
1889 ext_phy_type,
1890 ext_phy_addr,
1891 MDIO_PMA_DEVAD,
1892 MDIO_PMA_REG_CTRL, 0xa040);
1893 break;
1894 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
1895 /* Unset Low Power Mode and SW reset */
1896 /* Restore normal power mode*/
1897 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001898 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1899 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001900
1901 DP(NETIF_MSG_LINK, "XGXS 8072\n");
1902 bnx2x_cl45_write(bp, params->port,
1903 ext_phy_type,
1904 ext_phy_addr,
1905 MDIO_PMA_DEVAD,
1906 MDIO_PMA_REG_CTRL,
1907 1<<15);
1908 break;
1909 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
1910 {
1911 u16 emac_base;
1912 emac_base = (params->port) ? GRCBASE_EMAC0 :
1913 GRCBASE_EMAC1;
1914
1915 /* Restore normal power mode*/
1916 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001917 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1918 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001919
1920 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001921 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1922 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001923
1924 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001925 }
1926 break;
1927
1928 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
1929 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
1930
1931 /* Restore normal power mode*/
1932 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001933 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1934 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001935
1936 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001937 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001938
1939 break;
1940
1941 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
1942 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
1943 break;
1944
1945 default:
1946 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
1947 params->ext_phy_config);
1948 break;
1949 }
1950
1951 } else { /* SerDes */
1952 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
1953 switch (ext_phy_type) {
1954 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
1955 DP(NETIF_MSG_LINK, "SerDes Direct\n");
1956 break;
1957
1958 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
1959 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001960 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001961 break;
1962
1963 default:
1964 DP(NETIF_MSG_LINK,
1965 "BAD SerDes ext_phy_config 0x%x\n",
1966 params->ext_phy_config);
1967 break;
1968 }
1969 }
1970}
1971
1972static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
1973{
1974 struct bnx2x *bp = params->bp;
1975 u8 port = params->port;
1976 u8 ext_phy_addr = ((params->ext_phy_config &
1977 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1978 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1979 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1980 u16 fw_ver1, fw_ver2;
1981
1982 /* Need to wait 200ms after reset */
1983 msleep(200);
1984 /* Boot port from external ROM
1985 * Set ser_boot_ctl bit in the MISC_CTRL1 register
1986 */
1987 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
1988 MDIO_PMA_DEVAD,
1989 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
1990
1991 /* Reset internal microprocessor */
1992 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
1993 MDIO_PMA_DEVAD,
1994 MDIO_PMA_REG_GEN_CTRL,
1995 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
1996 /* set micro reset = 0 */
1997 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
1998 MDIO_PMA_DEVAD,
1999 MDIO_PMA_REG_GEN_CTRL,
2000 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2001 /* Reset internal microprocessor */
2002 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2003 MDIO_PMA_DEVAD,
2004 MDIO_PMA_REG_GEN_CTRL,
2005 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2006 /* wait for 100ms for code download via SPI port */
2007 msleep(100);
2008
2009 /* Clear ser_boot_ctl bit */
2010 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2011 MDIO_PMA_DEVAD,
2012 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2013 /* Wait 100ms */
2014 msleep(100);
2015
2016 /* Print the PHY FW version */
2017 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2018 MDIO_PMA_DEVAD,
2019 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2020 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2021 MDIO_PMA_DEVAD,
2022 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2023 DP(NETIF_MSG_LINK, "8072 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
2024}
2025
2026static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2027{
2028 /* This is only required for 8073A1, version 102 only */
2029
2030 struct bnx2x *bp = params->bp;
2031 u8 ext_phy_addr = ((params->ext_phy_config &
2032 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2033 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2034 u16 val;
2035
2036 /* Read 8073 HW revision*/
2037 bnx2x_cl45_read(bp, params->port,
2038 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2039 ext_phy_addr,
2040 MDIO_PMA_DEVAD,
2041 0xc801, &val);
2042
2043 if (val != 1) {
2044 /* No need to workaround in 8073 A1 */
2045 return 0;
2046 }
2047
2048 bnx2x_cl45_read(bp, params->port,
2049 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2050 ext_phy_addr,
2051 MDIO_PMA_DEVAD,
2052 MDIO_PMA_REG_ROM_VER2, &val);
2053
2054 /* SNR should be applied only for version 0x102 */
2055 if (val != 0x102)
2056 return 0;
2057
2058 return 1;
2059}
2060
2061static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2062{
2063 struct bnx2x *bp = params->bp;
2064 u8 ext_phy_addr = ((params->ext_phy_config &
2065 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2066 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2067 u16 val, cnt, cnt1 ;
2068
2069 bnx2x_cl45_read(bp, params->port,
2070 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2071 ext_phy_addr,
2072 MDIO_PMA_DEVAD,
2073 0xc801, &val);
2074
2075 if (val > 0) {
2076 /* No need to workaround in 8073 A1 */
2077 return 0;
2078 }
2079 /* XAUI workaround in 8073 A0: */
2080
2081 /* After loading the boot ROM and restarting Autoneg,
2082 poll Dev1, Reg $C820: */
2083
2084 for (cnt = 0; cnt < 1000; cnt++) {
2085 bnx2x_cl45_read(bp, params->port,
2086 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2087 ext_phy_addr,
2088 MDIO_PMA_DEVAD,
2089 0xc820, &val);
2090 /* If bit [14] = 0 or bit [13] = 0, continue on with
2091 system initialization (XAUI work-around not required,
2092 as these bits indicate 2.5G or 1G link up). */
2093 if (!(val & (1<<14)) || !(val & (1<<13))) {
2094 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2095 return 0;
2096 } else if (!(val & (1<<15))) {
2097 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2098 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2099 it's MSB (bit 15) goes to 1 (indicating that the
2100 XAUI workaround has completed),
2101 then continue on with system initialization.*/
2102 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2103 bnx2x_cl45_read(bp, params->port,
2104 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2105 ext_phy_addr,
2106 MDIO_PMA_DEVAD,
2107 0xc841, &val);
2108 if (val & (1<<15)) {
2109 DP(NETIF_MSG_LINK,
2110 "XAUI workaround has completed\n");
2111 return 0;
2112 }
2113 msleep(3);
2114 }
2115 break;
2116 }
2117 msleep(3);
2118 }
2119 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2120 return -EINVAL;
2121
2122}
2123
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002124static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
2125 u8 ext_phy_addr)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002126{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002127 u16 fw_ver1, fw_ver2;
2128 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002129 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002130 bnx2x_cl45_write(bp, port,
2131 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2132 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002133 MDIO_PMA_DEVAD,
2134 MDIO_PMA_REG_GEN_CTRL,
2135 0x0001);
2136
2137 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002138 bnx2x_cl45_write(bp, port,
2139 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2140 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002141 MDIO_PMA_DEVAD,
2142 MDIO_PMA_REG_GEN_CTRL,
2143 0x008c);
2144
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002145 bnx2x_cl45_write(bp, port,
2146 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2147 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002148 MDIO_PMA_DEVAD,
2149 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2150
2151 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002152 bnx2x_cl45_write(bp, port,
2153 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2154 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002155 MDIO_PMA_DEVAD,
2156 MDIO_PMA_REG_GEN_CTRL,
2157 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2158
2159 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002160 bnx2x_cl45_write(bp, port,
2161 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2162 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002163 MDIO_PMA_DEVAD,
2164 MDIO_PMA_REG_GEN_CTRL,
2165 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2166
2167 /* wait for 100ms for code download via SPI port */
2168 msleep(100);
2169
2170 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002171 bnx2x_cl45_write(bp, port,
2172 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2173 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002174 MDIO_PMA_DEVAD,
2175 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2176
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002177 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2178 ext_phy_addr,
2179 MDIO_PMA_DEVAD,
2180 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2181 bnx2x_cl45_read(bp, port,
2182 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2183 ext_phy_addr,
2184 MDIO_PMA_DEVAD,
2185 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002186 DP(NETIF_MSG_LINK, "8073 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
2187
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002188}
2189
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002190static void bnx2x_bcm807x_force_10G(struct link_params *params)
2191{
2192 struct bnx2x *bp = params->bp;
2193 u8 port = params->port;
2194 u8 ext_phy_addr = ((params->ext_phy_config &
2195 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2196 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2197 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2198
2199 /* Force KR or KX */
2200 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2201 MDIO_PMA_DEVAD,
2202 MDIO_PMA_REG_CTRL,
2203 0x2040);
2204 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2205 MDIO_PMA_DEVAD,
2206 MDIO_PMA_REG_10G_CTRL2,
2207 0x000b);
2208 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2209 MDIO_PMA_DEVAD,
2210 MDIO_PMA_REG_BCM_CTRL,
2211 0x0000);
2212 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2213 MDIO_AN_DEVAD,
2214 MDIO_AN_REG_CTRL,
2215 0x0000);
2216}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002217static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
2218{
2219 struct bnx2x *bp = params->bp;
2220 u8 port = params->port;
2221 u16 val;
2222 u8 ext_phy_addr = ((params->ext_phy_config &
2223 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2224 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2225 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2226
2227 bnx2x_cl45_read(bp, params->port,
2228 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2229 ext_phy_addr,
2230 MDIO_PMA_DEVAD,
2231 0xc801, &val);
2232
2233 if (val == 0) {
2234 /* Mustn't set low power mode in 8073 A0 */
2235 return;
2236 }
2237
2238 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
2239 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2240 MDIO_XS_DEVAD,
2241 MDIO_XS_PLL_SEQUENCER, &val);
2242 val &= ~(1<<13);
2243 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2244 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2245
2246 /* PLL controls */
2247 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2248 MDIO_XS_DEVAD, 0x805E, 0x1077);
2249 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2250 MDIO_XS_DEVAD, 0x805D, 0x0000);
2251 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2252 MDIO_XS_DEVAD, 0x805C, 0x030B);
2253 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2254 MDIO_XS_DEVAD, 0x805B, 0x1240);
2255 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2256 MDIO_XS_DEVAD, 0x805A, 0x2490);
2257
2258 /* Tx Controls */
2259 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2260 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2261 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2262 MDIO_XS_DEVAD, 0x80A6, 0x9041);
2263 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2264 MDIO_XS_DEVAD, 0x80A5, 0x4640);
2265
2266 /* Rx Controls */
2267 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2268 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2269 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2270 MDIO_XS_DEVAD, 0x80FD, 0x9249);
2271 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2272 MDIO_XS_DEVAD, 0x80FC, 0x2015);
2273
2274 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
2275 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2276 MDIO_XS_DEVAD,
2277 MDIO_XS_PLL_SEQUENCER, &val);
2278 val |= (1<<13);
2279 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2280 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2281}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002282
2283static void bnx2x_8073_set_pause_cl37(struct link_params *params,
2284 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002285{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002286
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002287 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002288 u16 cl37_val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002289 u8 ext_phy_addr = ((params->ext_phy_config &
2290 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2291 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2292 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2293
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002294 bnx2x_cl45_read(bp, params->port,
2295 ext_phy_type,
2296 ext_phy_addr,
2297 MDIO_AN_DEVAD,
2298 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
2299
2300 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2301 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2302
2303 if ((vars->ieee_fc &
2304 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
2305 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
2306 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
2307 }
2308 if ((vars->ieee_fc &
2309 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2310 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2311 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2312 }
2313 if ((vars->ieee_fc &
2314 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2315 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2316 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2317 }
2318 DP(NETIF_MSG_LINK,
2319 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
2320
2321 bnx2x_cl45_write(bp, params->port,
2322 ext_phy_type,
2323 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002324 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002325 MDIO_AN_REG_CL37_FC_LD, cl37_val);
2326 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002327}
2328
2329static void bnx2x_ext_phy_set_pause(struct link_params *params,
2330 struct link_vars *vars)
2331{
2332 struct bnx2x *bp = params->bp;
2333 u16 val;
2334 u8 ext_phy_addr = ((params->ext_phy_config &
2335 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2336 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2337 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2338
2339 /* read modify write pause advertizing */
2340 bnx2x_cl45_read(bp, params->port,
2341 ext_phy_type,
2342 ext_phy_addr,
2343 MDIO_AN_DEVAD,
2344 MDIO_AN_REG_ADV_PAUSE, &val);
2345
2346 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002347
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002348 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2349
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002350 if ((vars->ieee_fc &
2351 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002352 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2353 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2354 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002355 if ((vars->ieee_fc &
2356 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002357 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2358 val |=
2359 MDIO_AN_REG_ADV_PAUSE_PAUSE;
2360 }
2361 DP(NETIF_MSG_LINK,
2362 "Ext phy AN advertize 0x%x\n", val);
2363 bnx2x_cl45_write(bp, params->port,
2364 ext_phy_type,
2365 ext_phy_addr,
2366 MDIO_AN_DEVAD,
2367 MDIO_AN_REG_ADV_PAUSE, val);
2368}
2369
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002370
2371static void bnx2x_init_internal_phy(struct link_params *params,
2372 struct link_vars *vars)
2373{
2374 struct bnx2x *bp = params->bp;
2375 u8 port = params->port;
2376 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2377 u16 bank, rx_eq;
2378
2379 rx_eq = ((params->serdes_config &
2380 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >>
2381 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT);
2382
2383 DP(NETIF_MSG_LINK, "setting rx eq to 0x%x\n", rx_eq);
2384 for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL;
2385 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0)) {
2386 CL45_WR_OVER_CL22(bp, port,
2387 params->phy_addr,
2388 bank ,
2389 MDIO_RX0_RX_EQ_BOOST,
2390 ((rx_eq &
2391 MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) |
2392 MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL));
2393 }
2394
2395 /* forced speed requested? */
2396 if (vars->line_speed != SPEED_AUTO_NEG) {
2397 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2398
2399 /* disable autoneg */
2400 bnx2x_set_autoneg(params, vars);
2401
2402 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002403 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002404
2405 } else { /* AN_mode */
2406 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2407
2408 /* AN enabled */
2409 bnx2x_set_brcm_cl37_advertisment(params);
2410
2411 /* program duplex & pause advertisement (for aneg) */
2412 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002413 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002414
2415 /* enable autoneg */
2416 bnx2x_set_autoneg(params, vars);
2417
2418 /* enable and restart AN */
2419 bnx2x_restart_autoneg(params);
2420 }
2421
2422 } else { /* SGMII mode */
2423 DP(NETIF_MSG_LINK, "SGMII\n");
2424
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002425 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002426 }
2427}
2428
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002429static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
2430{
2431 struct bnx2x *bp = params->bp;
2432 u32 ext_phy_type;
2433 u8 ext_phy_addr;
2434 u16 cnt;
2435 u16 ctrl = 0;
2436 u16 val = 0;
2437 u8 rc = 0;
2438 if (vars->phy_flags & PHY_XGXS_FLAG) {
2439 ext_phy_addr = ((params->ext_phy_config &
2440 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2441 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2442
2443 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2444 /* Make sure that the soft reset is off (expect for the 8072:
2445 * due to the lock, it will be done inside the specific
2446 * handling)
2447 */
2448 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
2449 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
2450 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
2451 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
2452 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
2453 /* Wait for soft reset to get cleared upto 1 sec */
2454 for (cnt = 0; cnt < 1000; cnt++) {
2455 bnx2x_cl45_read(bp, params->port,
2456 ext_phy_type,
2457 ext_phy_addr,
2458 MDIO_PMA_DEVAD,
2459 MDIO_PMA_REG_CTRL, &ctrl);
2460 if (!(ctrl & (1<<15)))
2461 break;
2462 msleep(1);
2463 }
2464 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
2465 ctrl, cnt);
2466 }
2467
2468 switch (ext_phy_type) {
2469 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002470 break;
2471
2472 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2473 DP(NETIF_MSG_LINK, "XGXS 8705\n");
2474
2475 bnx2x_cl45_write(bp, params->port,
2476 ext_phy_type,
2477 ext_phy_addr,
2478 MDIO_PMA_DEVAD,
2479 MDIO_PMA_REG_MISC_CTRL,
2480 0x8288);
2481 bnx2x_cl45_write(bp, params->port,
2482 ext_phy_type,
2483 ext_phy_addr,
2484 MDIO_PMA_DEVAD,
2485 MDIO_PMA_REG_PHY_IDENTIFIER,
2486 0x7fbf);
2487 bnx2x_cl45_write(bp, params->port,
2488 ext_phy_type,
2489 ext_phy_addr,
2490 MDIO_PMA_DEVAD,
2491 MDIO_PMA_REG_CMU_PLL_BYPASS,
2492 0x0100);
2493 bnx2x_cl45_write(bp, params->port,
2494 ext_phy_type,
2495 ext_phy_addr,
2496 MDIO_WIS_DEVAD,
2497 MDIO_WIS_REG_LASI_CNTL, 0x1);
2498 break;
2499
2500 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2501 DP(NETIF_MSG_LINK, "XGXS 8706\n");
2502
2503 msleep(10);
2504 /* Force speed */
2505 /* First enable LASI */
2506 bnx2x_cl45_write(bp, params->port,
2507 ext_phy_type,
2508 ext_phy_addr,
2509 MDIO_PMA_DEVAD,
2510 MDIO_PMA_REG_RX_ALARM_CTRL,
2511 0x0400);
2512 bnx2x_cl45_write(bp, params->port,
2513 ext_phy_type,
2514 ext_phy_addr,
2515 MDIO_PMA_DEVAD,
2516 MDIO_PMA_REG_LASI_CTRL, 0x0004);
2517
2518 if (params->req_line_speed == SPEED_10000) {
2519 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
2520
2521 bnx2x_cl45_write(bp, params->port,
2522 ext_phy_type,
2523 ext_phy_addr,
2524 MDIO_PMA_DEVAD,
2525 MDIO_PMA_REG_DIGITAL_CTRL,
2526 0x400);
2527 } else {
2528 /* Force 1Gbps using autoneg with 1G
2529 advertisment */
2530
2531 /* Allow CL37 through CL73 */
2532 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
2533 bnx2x_cl45_write(bp, params->port,
2534 ext_phy_type,
2535 ext_phy_addr,
2536 MDIO_AN_DEVAD,
2537 MDIO_AN_REG_CL37_CL73,
2538 0x040c);
2539
2540 /* Enable Full-Duplex advertisment on CL37 */
2541 bnx2x_cl45_write(bp, params->port,
2542 ext_phy_type,
2543 ext_phy_addr,
2544 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002545 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002546 0x0020);
2547 /* Enable CL37 AN */
2548 bnx2x_cl45_write(bp, params->port,
2549 ext_phy_type,
2550 ext_phy_addr,
2551 MDIO_AN_DEVAD,
2552 MDIO_AN_REG_CL37_AN,
2553 0x1000);
2554 /* 1G support */
2555 bnx2x_cl45_write(bp, params->port,
2556 ext_phy_type,
2557 ext_phy_addr,
2558 MDIO_AN_DEVAD,
2559 MDIO_AN_REG_ADV, (1<<5));
2560
2561 /* Enable clause 73 AN */
2562 bnx2x_cl45_write(bp, params->port,
2563 ext_phy_type,
2564 ext_phy_addr,
2565 MDIO_AN_DEVAD,
2566 MDIO_AN_REG_CTRL,
2567 0x1200);
2568
2569 }
2570
2571 break;
2572
2573 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
2574 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
2575 {
2576 u16 tmp1;
2577 u16 rx_alarm_ctrl_val;
2578 u16 lasi_ctrl_val;
2579 if (ext_phy_type ==
2580 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
2581 rx_alarm_ctrl_val = 0x400;
2582 lasi_ctrl_val = 0x0004;
2583 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002584 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002585 lasi_ctrl_val = 0x0004;
2586 }
2587
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002588 /* enable LASI */
2589 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002590 ext_phy_type,
2591 ext_phy_addr,
2592 MDIO_PMA_DEVAD,
2593 MDIO_PMA_REG_RX_ALARM_CTRL,
2594 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002595
2596 bnx2x_cl45_write(bp, params->port,
2597 ext_phy_type,
2598 ext_phy_addr,
2599 MDIO_PMA_DEVAD,
2600 MDIO_PMA_REG_LASI_CTRL,
2601 lasi_ctrl_val);
2602
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002603 bnx2x_8073_set_pause_cl37(params, vars);
2604
2605 if (ext_phy_type ==
2606 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){
2607 bnx2x_bcm8072_external_rom_boot(params);
2608 } else {
2609
2610 /* In case of 8073 with long xaui lines,
2611 don't set the 8073 xaui low power*/
2612 bnx2x_bcm8073_set_xaui_low_power_mode(params);
2613 }
2614
2615 bnx2x_cl45_read(bp, params->port,
2616 ext_phy_type,
2617 ext_phy_addr,
2618 MDIO_PMA_DEVAD,
2619 0xca13,
2620 &tmp1);
2621
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002622 bnx2x_cl45_read(bp, params->port,
2623 ext_phy_type,
2624 ext_phy_addr,
2625 MDIO_PMA_DEVAD,
2626 MDIO_PMA_REG_RX_ALARM, &tmp1);
2627
2628 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
2629 "0x%x\n", tmp1);
2630
2631 /* If this is forced speed, set to KR or KX
2632 * (all other are not supported)
2633 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002634 if (params->loopback_mode == LOOPBACK_EXT) {
2635 bnx2x_bcm807x_force_10G(params);
2636 DP(NETIF_MSG_LINK,
2637 "Forced speed 10G on 807X\n");
2638 break;
2639 } else {
2640 bnx2x_cl45_write(bp, params->port,
2641 ext_phy_type, ext_phy_addr,
2642 MDIO_PMA_DEVAD,
2643 MDIO_PMA_REG_BCM_CTRL,
2644 0x0002);
2645 }
2646 if (params->req_line_speed != SPEED_AUTO_NEG) {
2647 if (params->req_line_speed == SPEED_10000) {
2648 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002649 } else if (params->req_line_speed ==
2650 SPEED_2500) {
2651 val = (1<<5);
2652 /* Note that 2.5G works only
2653 when used with 1G advertisment */
2654 } else
2655 val = (1<<5);
2656 } else {
2657
2658 val = 0;
2659 if (params->speed_cap_mask &
2660 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
2661 val |= (1<<7);
2662
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002663 /* Note that 2.5G works only when
2664 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002665 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002666 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
2667 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002668 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002669 DP(NETIF_MSG_LINK,
2670 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002671 }
2672
2673 bnx2x_cl45_write(bp, params->port,
2674 ext_phy_type,
2675 ext_phy_addr,
2676 MDIO_AN_DEVAD,
2677 MDIO_AN_REG_ADV, val);
2678
2679 if (ext_phy_type ==
2680 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002681
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002682 bnx2x_cl45_read(bp, params->port,
2683 ext_phy_type,
2684 ext_phy_addr,
2685 MDIO_AN_DEVAD,
2686 0x8329, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002687
2688 if (((params->speed_cap_mask &
2689 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
2690 (params->req_line_speed ==
2691 SPEED_AUTO_NEG)) ||
2692 (params->req_line_speed ==
2693 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002694 u16 phy_ver;
2695 /* Allow 2.5G for A1 and above */
2696 bnx2x_cl45_read(bp, params->port,
2697 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2698 ext_phy_addr,
2699 MDIO_PMA_DEVAD,
2700 0xc801, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002701 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002702 if (phy_ver > 0)
2703 tmp1 |= 1;
2704 else
2705 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002706 } else {
2707 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002708 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002709 }
2710
2711 bnx2x_cl45_write(bp, params->port,
2712 ext_phy_type,
2713 ext_phy_addr,
2714 MDIO_AN_DEVAD,
2715 0x8329, tmp1);
2716 }
2717
2718 /* Add support for CL37 (passive mode) II */
2719
2720 bnx2x_cl45_read(bp, params->port,
2721 ext_phy_type,
2722 ext_phy_addr,
2723 MDIO_AN_DEVAD,
2724 MDIO_AN_REG_CL37_FC_LD,
2725 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002726
2727 bnx2x_cl45_write(bp, params->port,
2728 ext_phy_type,
2729 ext_phy_addr,
2730 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002731 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
2732 ((params->req_duplex == DUPLEX_FULL) ?
2733 0x20 : 0x40)));
2734
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002735 /* Add support for CL37 (passive mode) III */
2736 bnx2x_cl45_write(bp, params->port,
2737 ext_phy_type,
2738 ext_phy_addr,
2739 MDIO_AN_DEVAD,
2740 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002741
2742 if (ext_phy_type ==
2743 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002744 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002745 BW and FEE main tap. Rest commands are executed
2746 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002747 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002748 if (bnx2x_8073_is_snr_needed(params))
2749 bnx2x_cl45_write(bp, params->port,
2750 ext_phy_type,
2751 ext_phy_addr,
2752 MDIO_PMA_DEVAD,
2753 MDIO_PMA_REG_EDC_FFE_MAIN,
2754 0xFB0C);
2755
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002756 /* Enable FEC (Forware Error Correction)
2757 Request in the AN */
2758 bnx2x_cl45_read(bp, params->port,
2759 ext_phy_type,
2760 ext_phy_addr,
2761 MDIO_AN_DEVAD,
2762 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002763
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002764 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002765
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002766 bnx2x_cl45_write(bp, params->port,
2767 ext_phy_type,
2768 ext_phy_addr,
2769 MDIO_AN_DEVAD,
2770 MDIO_AN_REG_ADV2, tmp1);
2771
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002772 }
2773
2774 bnx2x_ext_phy_set_pause(params, vars);
2775
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002776 /* Restart autoneg */
2777 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002778 bnx2x_cl45_write(bp, params->port,
2779 ext_phy_type,
2780 ext_phy_addr,
2781 MDIO_AN_DEVAD,
2782 MDIO_AN_REG_CTRL, 0x1200);
2783 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
2784 "Advertise 1G=%x, 10G=%x\n",
2785 ((val & (1<<5)) > 0),
2786 ((val & (1<<7)) > 0));
2787 break;
2788 }
2789 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
2790 DP(NETIF_MSG_LINK,
2791 "Setting the SFX7101 LASI indication\n");
2792
2793 bnx2x_cl45_write(bp, params->port,
2794 ext_phy_type,
2795 ext_phy_addr,
2796 MDIO_PMA_DEVAD,
2797 MDIO_PMA_REG_LASI_CTRL, 0x1);
2798 DP(NETIF_MSG_LINK,
2799 "Setting the SFX7101 LED to blink on traffic\n");
2800 bnx2x_cl45_write(bp, params->port,
2801 ext_phy_type,
2802 ext_phy_addr,
2803 MDIO_PMA_DEVAD,
2804 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
2805
2806 bnx2x_ext_phy_set_pause(params, vars);
2807 /* Restart autoneg */
2808 bnx2x_cl45_read(bp, params->port,
2809 ext_phy_type,
2810 ext_phy_addr,
2811 MDIO_AN_DEVAD,
2812 MDIO_AN_REG_CTRL, &val);
2813 val |= 0x200;
2814 bnx2x_cl45_write(bp, params->port,
2815 ext_phy_type,
2816 ext_phy_addr,
2817 MDIO_AN_DEVAD,
2818 MDIO_AN_REG_CTRL, val);
2819 break;
2820 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
2821 DP(NETIF_MSG_LINK,
2822 "XGXS PHY Failure detected 0x%x\n",
2823 params->ext_phy_config);
2824 rc = -EINVAL;
2825 break;
2826 default:
2827 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
2828 params->ext_phy_config);
2829 rc = -EINVAL;
2830 break;
2831 }
2832
2833 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002834
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002835 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
2836 switch (ext_phy_type) {
2837 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
2838 DP(NETIF_MSG_LINK, "SerDes Direct\n");
2839 break;
2840
2841 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
2842 DP(NETIF_MSG_LINK, "SerDes 5482\n");
2843 break;
2844
2845 default:
2846 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
2847 params->ext_phy_config);
2848 break;
2849 }
2850 }
2851 return rc;
2852}
2853
2854
2855static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002856 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002857{
2858 struct bnx2x *bp = params->bp;
2859 u32 ext_phy_type;
2860 u8 ext_phy_addr;
2861 u16 val1 = 0, val2;
2862 u16 rx_sd, pcs_status;
2863 u8 ext_phy_link_up = 0;
2864 u8 port = params->port;
2865 if (vars->phy_flags & PHY_XGXS_FLAG) {
2866 ext_phy_addr = ((params->ext_phy_config &
2867 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2868 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2869
2870 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2871 switch (ext_phy_type) {
2872 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
2873 DP(NETIF_MSG_LINK, "XGXS Direct\n");
2874 ext_phy_link_up = 1;
2875 break;
2876
2877 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2878 DP(NETIF_MSG_LINK, "XGXS 8705\n");
2879 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2880 ext_phy_addr,
2881 MDIO_WIS_DEVAD,
2882 MDIO_WIS_REG_LASI_STATUS, &val1);
2883 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
2884
2885 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2886 ext_phy_addr,
2887 MDIO_WIS_DEVAD,
2888 MDIO_WIS_REG_LASI_STATUS, &val1);
2889 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
2890
2891 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2892 ext_phy_addr,
2893 MDIO_PMA_DEVAD,
2894 MDIO_PMA_REG_RX_SD, &rx_sd);
2895 DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
2896 ext_phy_link_up = (rx_sd & 0x1);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002897 if (ext_phy_link_up)
2898 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002899 break;
2900
2901 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2902 DP(NETIF_MSG_LINK, "XGXS 8706\n");
2903 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2904 ext_phy_addr,
2905 MDIO_PMA_DEVAD,
2906 MDIO_PMA_REG_LASI_STATUS, &val1);
2907 DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
2908
2909 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2910 ext_phy_addr,
2911 MDIO_PMA_DEVAD,
2912 MDIO_PMA_REG_LASI_STATUS, &val1);
2913 DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
2914
2915 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2916 ext_phy_addr,
2917 MDIO_PMA_DEVAD,
2918 MDIO_PMA_REG_RX_SD, &rx_sd);
2919 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2920 ext_phy_addr,
2921 MDIO_PCS_DEVAD,
2922 MDIO_PCS_REG_STATUS, &pcs_status);
2923
2924 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2925 ext_phy_addr,
2926 MDIO_AN_DEVAD,
2927 MDIO_AN_REG_LINK_STATUS, &val2);
2928 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2929 ext_phy_addr,
2930 MDIO_AN_DEVAD,
2931 MDIO_AN_REG_LINK_STATUS, &val2);
2932
2933 DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x"
2934 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
2935 rx_sd, pcs_status, val2);
2936 /* link is up if both bit 0 of pmd_rx_sd and
2937 * bit 0 of pcs_status are set, or if the autoneg bit
2938 1 is set
2939 */
2940 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
2941 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002942 if (ext_phy_link_up) {
2943 if (val2 & (1<<1))
2944 vars->line_speed = SPEED_1000;
2945 else
2946 vars->line_speed = SPEED_10000;
2947 }
2948
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002949 /* clear LASI indication*/
2950 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2951 ext_phy_addr,
2952 MDIO_PMA_DEVAD,
2953 MDIO_PMA_REG_RX_ALARM, &val2);
2954 break;
2955
2956 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
2957 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
2958 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002959 u16 link_status = 0;
2960 u16 an1000_status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002961 if (ext_phy_type ==
2962 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
2963 bnx2x_cl45_read(bp, params->port,
2964 ext_phy_type,
2965 ext_phy_addr,
2966 MDIO_PCS_DEVAD,
2967 MDIO_PCS_REG_LASI_STATUS, &val1);
2968 bnx2x_cl45_read(bp, params->port,
2969 ext_phy_type,
2970 ext_phy_addr,
2971 MDIO_PCS_DEVAD,
2972 MDIO_PCS_REG_LASI_STATUS, &val2);
2973 DP(NETIF_MSG_LINK,
2974 "870x LASI status 0x%x->0x%x\n",
2975 val1, val2);
2976
2977 } else {
2978 /* In 8073, port1 is directed through emac0 and
2979 * port0 is directed through emac1
2980 */
2981 bnx2x_cl45_read(bp, params->port,
2982 ext_phy_type,
2983 ext_phy_addr,
2984 MDIO_PMA_DEVAD,
2985 MDIO_PMA_REG_LASI_STATUS, &val1);
2986
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002987 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002988 "8703 LASI status 0x%x\n",
2989 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002990 }
2991
2992 /* clear the interrupt LASI status register */
2993 bnx2x_cl45_read(bp, params->port,
2994 ext_phy_type,
2995 ext_phy_addr,
2996 MDIO_PCS_DEVAD,
2997 MDIO_PCS_REG_STATUS, &val2);
2998 bnx2x_cl45_read(bp, params->port,
2999 ext_phy_type,
3000 ext_phy_addr,
3001 MDIO_PCS_DEVAD,
3002 MDIO_PCS_REG_STATUS, &val1);
3003 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
3004 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003005 /* Clear MSG-OUT */
3006 bnx2x_cl45_read(bp, params->port,
3007 ext_phy_type,
3008 ext_phy_addr,
3009 MDIO_PMA_DEVAD,
3010 0xca13,
3011 &val1);
3012
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003013 /* Check the LASI */
3014 bnx2x_cl45_read(bp, params->port,
3015 ext_phy_type,
3016 ext_phy_addr,
3017 MDIO_PMA_DEVAD,
3018 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003019
3020 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3021
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003022 /* Check the link status */
3023 bnx2x_cl45_read(bp, params->port,
3024 ext_phy_type,
3025 ext_phy_addr,
3026 MDIO_PCS_DEVAD,
3027 MDIO_PCS_REG_STATUS, &val2);
3028 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3029
3030 bnx2x_cl45_read(bp, params->port,
3031 ext_phy_type,
3032 ext_phy_addr,
3033 MDIO_PMA_DEVAD,
3034 MDIO_PMA_REG_STATUS, &val2);
3035 bnx2x_cl45_read(bp, params->port,
3036 ext_phy_type,
3037 ext_phy_addr,
3038 MDIO_PMA_DEVAD,
3039 MDIO_PMA_REG_STATUS, &val1);
3040 ext_phy_link_up = ((val1 & 4) == 4);
3041 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3042 if (ext_phy_type ==
3043 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003044
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003045 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003046 ((params->req_line_speed !=
3047 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003048 if (bnx2x_bcm8073_xaui_wa(params)
3049 != 0) {
3050 ext_phy_link_up = 0;
3051 break;
3052 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003053 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003054 bnx2x_cl45_read(bp, params->port,
3055 ext_phy_type,
3056 ext_phy_addr,
3057 MDIO_AN_DEVAD,
3058 0x8304,
3059 &an1000_status);
3060 bnx2x_cl45_read(bp, params->port,
3061 ext_phy_type,
3062 ext_phy_addr,
3063 MDIO_AN_DEVAD,
3064 0x8304,
3065 &an1000_status);
3066
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003067 /* Check the link status on 1.1.2 */
3068 bnx2x_cl45_read(bp, params->port,
3069 ext_phy_type,
3070 ext_phy_addr,
3071 MDIO_PMA_DEVAD,
3072 MDIO_PMA_REG_STATUS, &val2);
3073 bnx2x_cl45_read(bp, params->port,
3074 ext_phy_type,
3075 ext_phy_addr,
3076 MDIO_PMA_DEVAD,
3077 MDIO_PMA_REG_STATUS, &val1);
3078 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3079 "an_link_status=0x%x\n",
3080 val2, val1, an1000_status);
3081
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003082 ext_phy_link_up = (((val1 & 4) == 4) ||
3083 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003084 if (ext_phy_link_up &&
3085 bnx2x_8073_is_snr_needed(params)) {
3086 /* The SNR will improve about 2dbby
3087 changing the BW and FEE main tap.*/
3088
3089 /* The 1st write to change FFE main
3090 tap is set before restart AN */
3091 /* Change PLL Bandwidth in EDC
3092 register */
3093 bnx2x_cl45_write(bp, port, ext_phy_type,
3094 ext_phy_addr,
3095 MDIO_PMA_DEVAD,
3096 MDIO_PMA_REG_PLL_BANDWIDTH,
3097 0x26BC);
3098
3099 /* Change CDR Bandwidth in EDC
3100 register */
3101 bnx2x_cl45_write(bp, port, ext_phy_type,
3102 ext_phy_addr,
3103 MDIO_PMA_DEVAD,
3104 MDIO_PMA_REG_CDR_BANDWIDTH,
3105 0x0333);
3106
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003107
3108 }
3109 bnx2x_cl45_read(bp, params->port,
3110 ext_phy_type,
3111 ext_phy_addr,
3112 MDIO_PMA_DEVAD,
3113 0xc820,
3114 &link_status);
3115
3116 /* Bits 0..2 --> speed detected,
3117 bits 13..15--> link is down */
3118 if ((link_status & (1<<2)) &&
3119 (!(link_status & (1<<15)))) {
3120 ext_phy_link_up = 1;
3121 vars->line_speed = SPEED_10000;
3122 DP(NETIF_MSG_LINK,
3123 "port %x: External link"
3124 " up in 10G\n", params->port);
3125 } else if ((link_status & (1<<1)) &&
3126 (!(link_status & (1<<14)))) {
3127 ext_phy_link_up = 1;
3128 vars->line_speed = SPEED_2500;
3129 DP(NETIF_MSG_LINK,
3130 "port %x: External link"
3131 " up in 2.5G\n", params->port);
3132 } else if ((link_status & (1<<0)) &&
3133 (!(link_status & (1<<13)))) {
3134 ext_phy_link_up = 1;
3135 vars->line_speed = SPEED_1000;
3136 DP(NETIF_MSG_LINK,
3137 "port %x: External link"
3138 " up in 1G\n", params->port);
3139 } else {
3140 ext_phy_link_up = 0;
3141 DP(NETIF_MSG_LINK,
3142 "port %x: External link"
3143 " is down\n", params->port);
3144 }
3145 } else {
3146 /* See if 1G link is up for the 8072 */
3147 bnx2x_cl45_read(bp, params->port,
3148 ext_phy_type,
3149 ext_phy_addr,
3150 MDIO_AN_DEVAD,
3151 0x8304,
3152 &an1000_status);
3153 bnx2x_cl45_read(bp, params->port,
3154 ext_phy_type,
3155 ext_phy_addr,
3156 MDIO_AN_DEVAD,
3157 0x8304,
3158 &an1000_status);
3159 if (an1000_status & (1<<1)) {
3160 ext_phy_link_up = 1;
3161 vars->line_speed = SPEED_1000;
3162 DP(NETIF_MSG_LINK,
3163 "port %x: External link"
3164 " up in 1G\n", params->port);
3165 } else if (ext_phy_link_up) {
3166 ext_phy_link_up = 1;
3167 vars->line_speed = SPEED_10000;
3168 DP(NETIF_MSG_LINK,
3169 "port %x: External link"
3170 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003171 }
3172 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003173
3174
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003175 break;
3176 }
3177 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3178 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3179 ext_phy_addr,
3180 MDIO_PMA_DEVAD,
3181 MDIO_PMA_REG_LASI_STATUS, &val2);
3182 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3183 ext_phy_addr,
3184 MDIO_PMA_DEVAD,
3185 MDIO_PMA_REG_LASI_STATUS, &val1);
3186 DP(NETIF_MSG_LINK,
3187 "10G-base-T LASI status 0x%x->0x%x\n",
3188 val2, val1);
3189 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3190 ext_phy_addr,
3191 MDIO_PMA_DEVAD,
3192 MDIO_PMA_REG_STATUS, &val2);
3193 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3194 ext_phy_addr,
3195 MDIO_PMA_DEVAD,
3196 MDIO_PMA_REG_STATUS, &val1);
3197 DP(NETIF_MSG_LINK,
3198 "10G-base-T PMA status 0x%x->0x%x\n",
3199 val2, val1);
3200 ext_phy_link_up = ((val1 & 4) == 4);
3201 /* if link is up
3202 * print the AN outcome of the SFX7101 PHY
3203 */
3204 if (ext_phy_link_up) {
3205 bnx2x_cl45_read(bp, params->port,
3206 ext_phy_type,
3207 ext_phy_addr,
3208 MDIO_AN_DEVAD,
3209 MDIO_AN_REG_MASTER_STATUS,
3210 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003211 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003212 DP(NETIF_MSG_LINK,
3213 "SFX7101 AN status 0x%x->Master=%x\n",
3214 val2,
3215 (val2 & (1<<14)));
3216 }
3217 break;
3218
3219 default:
3220 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3221 params->ext_phy_config);
3222 ext_phy_link_up = 0;
3223 break;
3224 }
3225
3226 } else { /* SerDes */
3227 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3228 switch (ext_phy_type) {
3229 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3230 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3231 ext_phy_link_up = 1;
3232 break;
3233
3234 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3235 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3236 ext_phy_link_up = 1;
3237 break;
3238
3239 default:
3240 DP(NETIF_MSG_LINK,
3241 "BAD SerDes ext_phy_config 0x%x\n",
3242 params->ext_phy_config);
3243 ext_phy_link_up = 0;
3244 break;
3245 }
3246 }
3247
3248 return ext_phy_link_up;
3249}
3250
3251static void bnx2x_link_int_enable(struct link_params *params)
3252{
3253 u8 port = params->port;
3254 u32 ext_phy_type;
3255 u32 mask;
3256 struct bnx2x *bp = params->bp;
3257 /* setting the status to report on link up
3258 for either XGXS or SerDes */
3259
3260 if (params->switch_cfg == SWITCH_CFG_10G) {
3261 mask = (NIG_MASK_XGXS0_LINK10G |
3262 NIG_MASK_XGXS0_LINK_STATUS);
3263 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
3264 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3265 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3266 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3267 (ext_phy_type !=
3268 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
3269 mask |= NIG_MASK_MI_INT;
3270 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3271 }
3272
3273 } else { /* SerDes */
3274 mask = NIG_MASK_SERDES0_LINK_STATUS;
3275 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
3276 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3277 if ((ext_phy_type !=
3278 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
3279 (ext_phy_type !=
3280 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
3281 mask |= NIG_MASK_MI_INT;
3282 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3283 }
3284 }
3285 bnx2x_bits_en(bp,
3286 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
3287 mask);
3288 DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port,
3289 (params->switch_cfg == SWITCH_CFG_10G),
3290 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
3291
3292 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
3293 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3294 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
3295 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
3296 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
3297 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
3298 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
3299}
3300
3301
3302/*
3303 * link management
3304 */
3305static void bnx2x_link_int_ack(struct link_params *params,
3306 struct link_vars *vars, u16 is_10g)
3307{
3308 struct bnx2x *bp = params->bp;
3309 u8 port = params->port;
3310
3311 /* first reset all status
3312 * we assume only one line will be change at a time */
3313 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3314 (NIG_STATUS_XGXS0_LINK10G |
3315 NIG_STATUS_XGXS0_LINK_STATUS |
3316 NIG_STATUS_SERDES0_LINK_STATUS));
3317 if (vars->phy_link_up) {
3318 if (is_10g) {
3319 /* Disable the 10G link interrupt
3320 * by writing 1 to the status register
3321 */
3322 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
3323 bnx2x_bits_en(bp,
3324 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3325 NIG_STATUS_XGXS0_LINK10G);
3326
3327 } else if (params->switch_cfg == SWITCH_CFG_10G) {
3328 /* Disable the link interrupt
3329 * by writing 1 to the relevant lane
3330 * in the status register
3331 */
3332 u32 ser_lane = ((params->lane_config &
3333 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
3334 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
3335
3336 DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
3337 bnx2x_bits_en(bp,
3338 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3339 ((1 << ser_lane) <<
3340 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
3341
3342 } else { /* SerDes */
3343 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
3344 /* Disable the link interrupt
3345 * by writing 1 to the status register
3346 */
3347 bnx2x_bits_en(bp,
3348 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3349 NIG_STATUS_SERDES0_LINK_STATUS);
3350 }
3351
3352 } else { /* link_down */
3353 }
3354}
3355
3356static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
3357{
3358 u8 *str_ptr = str;
3359 u32 mask = 0xf0000000;
3360 u8 shift = 8*4;
3361 u8 digit;
3362 if (len < 10) {
3363 /* Need more then 10chars for this format */
3364 *str_ptr = '\0';
3365 return -EINVAL;
3366 }
3367 while (shift > 0) {
3368
3369 shift -= 4;
3370 digit = ((num & mask) >> shift);
3371 if (digit < 0xa)
3372 *str_ptr = digit + '0';
3373 else
3374 *str_ptr = digit - 0xa + 'a';
3375 str_ptr++;
3376 mask = mask >> 4;
3377 if (shift == 4*4) {
3378 *str_ptr = ':';
3379 str_ptr++;
3380 }
3381 }
3382 *str_ptr = '\0';
3383 return 0;
3384}
3385
3386
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003387static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr,
3388 u32 ext_phy_type)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003389{
3390 u32 cnt = 0;
3391 u16 ctrl = 0;
3392 /* Enable EMAC0 in to enable MDIO */
3393 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
3394 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
3395 msleep(5);
3396
3397 /* take ext phy out of reset */
3398 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003399 MISC_REGISTERS_GPIO_2,
3400 MISC_REGISTERS_GPIO_HIGH,
3401 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003402
3403 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003404 MISC_REGISTERS_GPIO_1,
3405 MISC_REGISTERS_GPIO_HIGH,
3406 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003407
3408 /* wait for 5ms */
3409 msleep(5);
3410
3411 for (cnt = 0; cnt < 1000; cnt++) {
3412 msleep(1);
3413 bnx2x_cl45_read(bp, port,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003414 ext_phy_type,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003415 ext_phy_addr,
3416 MDIO_PMA_DEVAD,
3417 MDIO_PMA_REG_CTRL,
3418 &ctrl);
3419 if (!(ctrl & (1<<15))) {
3420 DP(NETIF_MSG_LINK, "Reset completed\n\n");
3421 break;
3422 }
3423 }
3424}
3425
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003426static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003427{
3428 /* put sf to reset */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003429 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003430 MISC_REGISTERS_GPIO_1,
3431 MISC_REGISTERS_GPIO_LOW,
3432 port);
3433 bnx2x_set_gpio(bp,
3434 MISC_REGISTERS_GPIO_2,
3435 MISC_REGISTERS_GPIO_LOW,
3436 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003437}
3438
3439u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
3440 u8 *version, u16 len)
3441{
3442 struct bnx2x *bp = params->bp;
3443 u32 ext_phy_type = 0;
3444 u16 val = 0;
3445 u8 ext_phy_addr = 0 ;
3446 u8 status = 0 ;
3447 u32 ver_num;
3448
3449 if (version == NULL || params == NULL)
3450 return -EINVAL;
3451
3452 /* reset the returned value to zero */
3453 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3454 ext_phy_addr = ((params->ext_phy_config &
3455 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3456 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3457
3458 switch (ext_phy_type) {
3459 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3460
3461 if (len < 5)
3462 return -EINVAL;
3463
3464 /* Take ext phy out of reset */
3465 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003466 bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
3467 ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003468
3469 /* wait for 1ms */
3470 msleep(1);
3471
3472 bnx2x_cl45_read(bp, params->port,
3473 ext_phy_type,
3474 ext_phy_addr,
3475 MDIO_PMA_DEVAD,
3476 MDIO_PMA_REG_7101_VER1, &val);
3477 version[2] = (val & 0xFF);
3478 version[3] = ((val & 0xFF00)>>8);
3479
3480 bnx2x_cl45_read(bp, params->port,
3481 ext_phy_type,
3482 ext_phy_addr,
3483 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2,
3484 &val);
3485 version[0] = (val & 0xFF);
3486 version[1] = ((val & 0xFF00)>>8);
3487 version[4] = '\0';
3488
3489 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003490 bnx2x_turn_off_sf(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003491 break;
3492 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3493 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3494 {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003495 /* Take ext phy out of reset */
3496 if (!driver_loaded)
3497 bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
3498 ext_phy_type);
3499
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003500 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3501 ext_phy_addr,
3502 MDIO_PMA_DEVAD,
3503 MDIO_PMA_REG_ROM_VER1, &val);
3504 ver_num = val<<16;
3505 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3506 ext_phy_addr,
3507 MDIO_PMA_DEVAD,
3508 MDIO_PMA_REG_ROM_VER2, &val);
3509 ver_num |= val;
3510 status = bnx2x_format_ver(ver_num, version, len);
3511 break;
3512 }
3513 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3514 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
3515
3516 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3517 ext_phy_addr,
3518 MDIO_PMA_DEVAD,
3519 MDIO_PMA_REG_ROM_VER1, &val);
3520 ver_num = val<<16;
3521 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3522 ext_phy_addr,
3523 MDIO_PMA_DEVAD,
3524 MDIO_PMA_REG_ROM_VER2, &val);
3525 ver_num |= val;
3526 status = bnx2x_format_ver(ver_num, version, len);
3527 break;
3528
3529 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3530 break;
3531
3532 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
3533 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
3534 " type is FAILURE!\n");
3535 status = -EINVAL;
3536 break;
3537
3538 default:
3539 break;
3540 }
3541 return status;
3542}
3543
3544static void bnx2x_set_xgxs_loopback(struct link_params *params,
3545 struct link_vars *vars,
3546 u8 is_10g)
3547{
3548 u8 port = params->port;
3549 struct bnx2x *bp = params->bp;
3550
3551 if (is_10g) {
3552 u32 md_devad;
3553
3554 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
3555
3556 /* change the uni_phy_addr in the nig */
3557 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
3558 port*0x18));
3559
3560 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
3561
3562 bnx2x_cl45_write(bp, port, 0,
3563 params->phy_addr,
3564 5,
3565 (MDIO_REG_BANK_AER_BLOCK +
3566 (MDIO_AER_BLOCK_AER_REG & 0xf)),
3567 0x2800);
3568
3569 bnx2x_cl45_write(bp, port, 0,
3570 params->phy_addr,
3571 5,
3572 (MDIO_REG_BANK_CL73_IEEEB0 +
3573 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
3574 0x6041);
3575
3576 /* set aer mmd back */
3577 bnx2x_set_aer_mmd(params, vars);
3578
3579 /* and md_devad */
3580 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
3581 md_devad);
3582
3583 } else {
3584 u16 mii_control;
3585
3586 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
3587
3588 CL45_RD_OVER_CL22(bp, port,
3589 params->phy_addr,
3590 MDIO_REG_BANK_COMBO_IEEE0,
3591 MDIO_COMBO_IEEE0_MII_CONTROL,
3592 &mii_control);
3593
3594 CL45_WR_OVER_CL22(bp, port,
3595 params->phy_addr,
3596 MDIO_REG_BANK_COMBO_IEEE0,
3597 MDIO_COMBO_IEEE0_MII_CONTROL,
3598 (mii_control |
3599 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
3600 }
3601}
3602
3603
3604static void bnx2x_ext_phy_loopback(struct link_params *params)
3605{
3606 struct bnx2x *bp = params->bp;
3607 u8 ext_phy_addr;
3608 u32 ext_phy_type;
3609
3610 if (params->switch_cfg == SWITCH_CFG_10G) {
3611 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3612 /* CL37 Autoneg Enabled */
3613 ext_phy_addr = ((params->ext_phy_config &
3614 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3615 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3616 switch (ext_phy_type) {
3617 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3618 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
3619 DP(NETIF_MSG_LINK,
3620 "ext_phy_loopback: We should not get here\n");
3621 break;
3622 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3623 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
3624 break;
3625 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
3626 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
3627 break;
3628 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3629 /* SFX7101_XGXS_TEST1 */
3630 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3631 ext_phy_addr,
3632 MDIO_XS_DEVAD,
3633 MDIO_XS_SFX7101_XGXS_TEST1,
3634 0x100);
3635 DP(NETIF_MSG_LINK,
3636 "ext_phy_loopback: set ext phy loopback\n");
3637 break;
3638 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3639
3640 break;
3641 } /* switch external PHY type */
3642 } else {
3643 /* serdes */
3644 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3645 ext_phy_addr = (params->ext_phy_config &
3646 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
3647 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
3648 }
3649}
3650
3651
3652/*
3653 *------------------------------------------------------------------------
3654 * bnx2x_override_led_value -
3655 *
3656 * Override the led value of the requsted led
3657 *
3658 *------------------------------------------------------------------------
3659 */
3660u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
3661 u32 led_idx, u32 value)
3662{
3663 u32 reg_val;
3664
3665 /* If port 0 then use EMAC0, else use EMAC1*/
3666 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
3667
3668 DP(NETIF_MSG_LINK,
3669 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
3670 port, led_idx, value);
3671
3672 switch (led_idx) {
3673 case 0: /* 10MB led */
3674 /* Read the current value of the LED register in
3675 the EMAC block */
3676 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3677 /* Set the OVERRIDE bit to 1 */
3678 reg_val |= EMAC_LED_OVERRIDE;
3679 /* If value is 1, set the 10M_OVERRIDE bit,
3680 otherwise reset it.*/
3681 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
3682 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
3683 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3684 break;
3685 case 1: /*100MB led */
3686 /*Read the current value of the LED register in
3687 the EMAC block */
3688 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3689 /* Set the OVERRIDE bit to 1 */
3690 reg_val |= EMAC_LED_OVERRIDE;
3691 /* If value is 1, set the 100M_OVERRIDE bit,
3692 otherwise reset it.*/
3693 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
3694 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
3695 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3696 break;
3697 case 2: /* 1000MB led */
3698 /* Read the current value of the LED register in the
3699 EMAC block */
3700 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3701 /* Set the OVERRIDE bit to 1 */
3702 reg_val |= EMAC_LED_OVERRIDE;
3703 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
3704 reset it. */
3705 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
3706 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
3707 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3708 break;
3709 case 3: /* 2500MB led */
3710 /* Read the current value of the LED register in the
3711 EMAC block*/
3712 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3713 /* Set the OVERRIDE bit to 1 */
3714 reg_val |= EMAC_LED_OVERRIDE;
3715 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
3716 reset it.*/
3717 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
3718 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
3719 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3720 break;
3721 case 4: /*10G led */
3722 if (port == 0) {
3723 REG_WR(bp, NIG_REG_LED_10G_P0,
3724 value);
3725 } else {
3726 REG_WR(bp, NIG_REG_LED_10G_P1,
3727 value);
3728 }
3729 break;
3730 case 5: /* TRAFFIC led */
3731 /* Find if the traffic control is via BMAC or EMAC */
3732 if (port == 0)
3733 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
3734 else
3735 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
3736
3737 /* Override the traffic led in the EMAC:*/
3738 if (reg_val == 1) {
3739 /* Read the current value of the LED register in
3740 the EMAC block */
3741 reg_val = REG_RD(bp, emac_base +
3742 EMAC_REG_EMAC_LED);
3743 /* Set the TRAFFIC_OVERRIDE bit to 1 */
3744 reg_val |= EMAC_LED_OVERRIDE;
3745 /* If value is 1, set the TRAFFIC bit, otherwise
3746 reset it.*/
3747 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
3748 (reg_val & ~EMAC_LED_TRAFFIC);
3749 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3750 } else { /* Override the traffic led in the BMAC: */
3751 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
3752 + port*4, 1);
3753 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
3754 value);
3755 }
3756 break;
3757 default:
3758 DP(NETIF_MSG_LINK,
3759 "bnx2x_override_led_value() unknown led index %d "
3760 "(should be 0-5)\n", led_idx);
3761 return -EINVAL;
3762 }
3763
3764 return 0;
3765}
3766
3767
3768u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
3769 u16 hw_led_mode, u32 chip_id)
3770{
3771 u8 rc = 0;
3772 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
3773 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
3774 speed, hw_led_mode);
3775 switch (mode) {
3776 case LED_MODE_OFF:
3777 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
3778 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
3779 SHARED_HW_CFG_LED_MAC1);
3780 break;
3781
3782 case LED_MODE_OPER:
3783 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
3784 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
3785 port*4, 0);
3786 /* Set blinking rate to ~15.9Hz */
3787 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
3788 LED_BLINK_RATE_VAL);
3789 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
3790 port*4, 1);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003791 if (!CHIP_IS_E1H(bp) &&
3792 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003793 (speed == SPEED_1000) ||
3794 (speed == SPEED_100) ||
3795 (speed == SPEED_10))) {
3796 /* On Everest 1 Ax chip versions for speeds less than
3797 10G LED scheme is different */
3798 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
3799 + port*4, 1);
3800 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
3801 port*4, 0);
3802 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
3803 port*4, 1);
3804 }
3805 break;
3806
3807 default:
3808 rc = -EINVAL;
3809 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
3810 mode);
3811 break;
3812 }
3813 return rc;
3814
3815}
3816
3817u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
3818{
3819 struct bnx2x *bp = params->bp;
3820 u16 gp_status = 0;
3821
3822 CL45_RD_OVER_CL22(bp, params->port,
3823 params->phy_addr,
3824 MDIO_REG_BANK_GP_STATUS,
3825 MDIO_GP_STATUS_TOP_AN_STATUS1,
3826 &gp_status);
3827 /* link is up only if both local phy and external phy are up */
3828 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
3829 bnx2x_ext_phy_is_link_up(params, vars))
3830 return 0;
3831
3832 return -ESRCH;
3833}
3834
3835static u8 bnx2x_link_initialize(struct link_params *params,
3836 struct link_vars *vars)
3837{
3838 struct bnx2x *bp = params->bp;
3839 u8 port = params->port;
3840 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003841 u8 non_ext_phy;
3842 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003843 /* Activate the external PHY */
3844 bnx2x_ext_phy_reset(params, vars);
3845
3846 bnx2x_set_aer_mmd(params, vars);
3847
3848 if (vars->phy_flags & PHY_XGXS_FLAG)
3849 bnx2x_set_master_ln(params);
3850
3851 rc = bnx2x_reset_unicore(params);
3852 /* reset the SerDes and wait for reset bit return low */
3853 if (rc != 0)
3854 return rc;
3855
3856 bnx2x_set_aer_mmd(params, vars);
3857
3858 /* setting the masterLn_def again after the reset */
3859 if (vars->phy_flags & PHY_XGXS_FLAG) {
3860 bnx2x_set_master_ln(params);
3861 bnx2x_set_swap_lanes(params);
3862 }
3863
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003864 if (vars->phy_flags & PHY_XGXS_FLAG) {
3865 if (params->req_line_speed &&
3866 ((params->req_line_speed == SPEED_100) ||
3867 (params->req_line_speed == SPEED_10))) {
3868 vars->phy_flags |= PHY_SGMII_FLAG;
3869 } else {
3870 vars->phy_flags &= ~PHY_SGMII_FLAG;
3871 }
3872 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003873 /* In case of external phy existance, the line speed would be the
3874 line speed linked up by the external phy. In case it is direct only,
3875 then the line_speed during initialization will be equal to the
3876 req_line_speed*/
3877 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003878
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003879 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003880
3881 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003882 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
3883 (params->loopback_mode == LOOPBACK_XGXS_10) ||
3884 (params->loopback_mode == LOOPBACK_EXT_PHY));
3885
3886 if (non_ext_phy ||
3887 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705)) {
3888 if (params->req_line_speed == SPEED_AUTO_NEG)
3889 bnx2x_set_parallel_detection(params, vars->phy_flags);
3890 bnx2x_init_internal_phy(params, vars);
3891 }
3892
3893 if (!non_ext_phy)
3894 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003895
3896 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003897 (NIG_STATUS_XGXS0_LINK10G |
3898 NIG_STATUS_XGXS0_LINK_STATUS |
3899 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003900
3901 return rc;
3902
3903}
3904
3905
3906u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
3907{
3908 struct bnx2x *bp = params->bp;
3909
3910 u32 val;
3911 DP(NETIF_MSG_LINK, "Phy Initialization started\n");
3912 DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
3913 params->req_line_speed, params->req_flow_ctrl);
3914 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003915 vars->phy_link_up = 0;
3916 vars->link_up = 0;
3917 vars->line_speed = 0;
3918 vars->duplex = DUPLEX_FULL;
3919 vars->flow_ctrl = FLOW_CTRL_NONE;
3920 vars->mac_type = MAC_TYPE_NONE;
3921
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003922 if (params->switch_cfg == SWITCH_CFG_1G)
3923 vars->phy_flags = PHY_SERDES_FLAG;
3924 else
3925 vars->phy_flags = PHY_XGXS_FLAG;
3926
3927 /* disable attentions */
3928 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
3929 (NIG_MASK_XGXS0_LINK_STATUS |
3930 NIG_MASK_XGXS0_LINK10G |
3931 NIG_MASK_SERDES0_LINK_STATUS |
3932 NIG_MASK_MI_INT));
3933
3934 bnx2x_emac_init(params, vars);
3935
3936 if (CHIP_REV_IS_FPGA(bp)) {
3937 vars->link_up = 1;
3938 vars->line_speed = SPEED_10000;
3939 vars->duplex = DUPLEX_FULL;
3940 vars->flow_ctrl = FLOW_CTRL_NONE;
3941 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003942 /* enable on E1.5 FPGA */
3943 if (CHIP_IS_E1H(bp)) {
3944 vars->flow_ctrl |=
3945 (FLOW_CTRL_TX | FLOW_CTRL_RX);
3946 vars->link_status |=
3947 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
3948 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
3949 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003950
3951 bnx2x_emac_enable(params, vars, 0);
3952 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
3953 /* disable drain */
3954 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3955 + params->port*4, 0);
3956
3957 /* update shared memory */
3958 bnx2x_update_mng(params, vars->link_status);
3959
3960 return 0;
3961
3962 } else
3963 if (CHIP_REV_IS_EMUL(bp)) {
3964
3965 vars->link_up = 1;
3966 vars->line_speed = SPEED_10000;
3967 vars->duplex = DUPLEX_FULL;
3968 vars->flow_ctrl = FLOW_CTRL_NONE;
3969 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
3970
3971 bnx2x_bmac_enable(params, vars, 0);
3972
3973 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
3974 /* Disable drain */
3975 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3976 + params->port*4, 0);
3977
3978 /* update shared memory */
3979 bnx2x_update_mng(params, vars->link_status);
3980
3981 return 0;
3982
3983 } else
3984 if (params->loopback_mode == LOOPBACK_BMAC) {
3985 vars->link_up = 1;
3986 vars->line_speed = SPEED_10000;
3987 vars->duplex = DUPLEX_FULL;
3988 vars->flow_ctrl = FLOW_CTRL_NONE;
3989 vars->mac_type = MAC_TYPE_BMAC;
3990
3991 vars->phy_flags = PHY_XGXS_FLAG;
3992
3993 bnx2x_phy_deassert(params, vars->phy_flags);
3994 /* set bmac loopback */
3995 bnx2x_bmac_enable(params, vars, 1);
3996
3997 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
3998 params->port*4, 0);
3999 } else if (params->loopback_mode == LOOPBACK_EMAC) {
4000 vars->link_up = 1;
4001 vars->line_speed = SPEED_1000;
4002 vars->duplex = DUPLEX_FULL;
4003 vars->flow_ctrl = FLOW_CTRL_NONE;
4004 vars->mac_type = MAC_TYPE_EMAC;
4005
4006 vars->phy_flags = PHY_XGXS_FLAG;
4007
4008 bnx2x_phy_deassert(params, vars->phy_flags);
4009 /* set bmac loopback */
4010 bnx2x_emac_enable(params, vars, 1);
4011 bnx2x_emac_program(params, vars->line_speed,
4012 vars->duplex);
4013 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4014 params->port*4, 0);
4015 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
4016 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
4017 vars->link_up = 1;
4018 vars->line_speed = SPEED_10000;
4019 vars->duplex = DUPLEX_FULL;
4020 vars->flow_ctrl = FLOW_CTRL_NONE;
4021
4022 vars->phy_flags = PHY_XGXS_FLAG;
4023
4024 val = REG_RD(bp,
4025 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4026 params->port*0x18);
4027 params->phy_addr = (u8)val;
4028
4029 bnx2x_phy_deassert(params, vars->phy_flags);
4030 bnx2x_link_initialize(params, vars);
4031
4032 vars->mac_type = MAC_TYPE_BMAC;
4033
4034 bnx2x_bmac_enable(params, vars, 0);
4035
4036 if (params->loopback_mode == LOOPBACK_XGXS_10) {
4037 /* set 10G XGXS loopback */
4038 bnx2x_set_xgxs_loopback(params, vars, 1);
4039 } else {
4040 /* set external phy loopback */
4041 bnx2x_ext_phy_loopback(params);
4042 }
4043 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4044 params->port*4, 0);
4045 } else
4046 /* No loopback */
4047 {
4048
4049 bnx2x_phy_deassert(params, vars->phy_flags);
4050 switch (params->switch_cfg) {
4051 case SWITCH_CFG_1G:
4052 vars->phy_flags |= PHY_SERDES_FLAG;
4053 if ((params->ext_phy_config &
4054 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
4055 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
4056 vars->phy_flags |=
4057 PHY_SGMII_FLAG;
4058 }
4059
4060 val = REG_RD(bp,
4061 NIG_REG_SERDES0_CTRL_PHY_ADDR+
4062 params->port*0x10);
4063
4064 params->phy_addr = (u8)val;
4065
4066 break;
4067 case SWITCH_CFG_10G:
4068 vars->phy_flags |= PHY_XGXS_FLAG;
4069 val = REG_RD(bp,
4070 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4071 params->port*0x18);
4072 params->phy_addr = (u8)val;
4073
4074 break;
4075 default:
4076 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
4077 return -EINVAL;
4078 break;
4079 }
4080
4081 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004082 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004083 bnx2x_link_int_enable(params);
4084 }
4085 return 0;
4086}
4087
4088u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars)
4089{
4090
4091 struct bnx2x *bp = params->bp;
4092 u32 ext_phy_config = params->ext_phy_config;
4093 u16 hw_led_mode = params->hw_led_mode;
4094 u32 chip_id = params->chip_id;
4095 u8 port = params->port;
4096 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4097 /* disable attentions */
4098
4099 vars->link_status = 0;
4100 bnx2x_update_mng(params, vars->link_status);
4101 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4102 (NIG_MASK_XGXS0_LINK_STATUS |
4103 NIG_MASK_XGXS0_LINK10G |
4104 NIG_MASK_SERDES0_LINK_STATUS |
4105 NIG_MASK_MI_INT));
4106
4107 /* activate nig drain */
4108 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4109
4110 /* disable nig egress interface */
4111 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4112 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4113
4114 /* Stop BigMac rx */
4115 bnx2x_bmac_rx_disable(bp, port);
4116
4117 /* disable emac */
4118 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4119
4120 msleep(10);
4121 /* The PHY reset is controled by GPIO 1
4122 * Hold it as vars low
4123 */
4124 /* clear link led */
4125 bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
4126 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
4127 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
4128 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
4129 /* HW reset */
4130
4131 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004132 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4133 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004134
4135 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004136 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4137 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004138
4139 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004140 } else if (ext_phy_type ==
4141 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
4142 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004143 "low power mode\n",
4144 port);
4145 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004146 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4147 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004148 }
4149 }
4150 /* reset the SerDes/XGXS */
4151 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
4152 (0x1ff << (port*16)));
4153
4154 /* reset BigMac */
4155 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
4156 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4157
4158 /* disable nig ingress interface */
4159 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
4160 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
4161 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4162 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4163 vars->link_up = 0;
4164 return 0;
4165}
4166
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004167static u8 bnx2x_update_link_down(struct link_params *params,
4168 struct link_vars *vars)
4169{
4170 struct bnx2x *bp = params->bp;
4171 u8 port = params->port;
4172 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
4173 bnx2x_set_led(bp, port, LED_MODE_OFF,
4174 0, params->hw_led_mode,
4175 params->chip_id);
4176
4177 /* indicate no mac active */
4178 vars->mac_type = MAC_TYPE_NONE;
4179
4180 /* update shared memory */
4181 vars->link_status = 0;
4182 vars->line_speed = 0;
4183 bnx2x_update_mng(params, vars->link_status);
4184
4185 /* activate nig drain */
4186 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4187
4188 /* reset BigMac */
4189 bnx2x_bmac_rx_disable(bp, params->port);
4190 REG_WR(bp, GRCBASE_MISC +
4191 MISC_REGISTERS_RESET_REG_2_CLEAR,
4192 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4193 return 0;
4194}
4195
4196static u8 bnx2x_update_link_up(struct link_params *params,
4197 struct link_vars *vars,
4198 u8 link_10g, u32 gp_status)
4199{
4200 struct bnx2x *bp = params->bp;
4201 u8 port = params->port;
4202 u8 rc = 0;
4203 vars->link_status |= LINK_STATUS_LINK_UP;
4204 if (link_10g) {
4205 bnx2x_bmac_enable(params, vars, 0);
4206 bnx2x_set_led(bp, port, LED_MODE_OPER,
4207 SPEED_10000, params->hw_led_mode,
4208 params->chip_id);
4209
4210 } else {
4211 bnx2x_emac_enable(params, vars, 0);
4212 rc = bnx2x_emac_program(params, vars->line_speed,
4213 vars->duplex);
4214
4215 /* AN complete? */
4216 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
4217 if (!(vars->phy_flags &
4218 PHY_SGMII_FLAG))
4219 bnx2x_set_sgmii_tx_driver(params);
4220 }
4221 }
4222
4223 /* PBF - link up */
4224 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
4225 vars->line_speed);
4226
4227 /* disable drain */
4228 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
4229
4230 /* update shared memory */
4231 bnx2x_update_mng(params, vars->link_status);
4232 return rc;
4233}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004234/* This function should called upon link interrupt */
4235/* In case vars->link_up, driver needs to
4236 1. Update the pbf
4237 2. Disable drain
4238 3. Update the shared memory
4239 4. Indicate link up
4240 5. Set LEDs
4241 Otherwise,
4242 1. Update shared memory
4243 2. Reset BigMac
4244 3. Report link down
4245 4. Unset LEDs
4246*/
4247u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
4248{
4249 struct bnx2x *bp = params->bp;
4250 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004251 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004252 u8 link_10g;
4253 u8 ext_phy_link_up, rc = 0;
4254 u32 ext_phy_type;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004255
4256 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
4257 port,
4258 (vars->phy_flags & PHY_XGXS_FLAG),
4259 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
4260
4261 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
4262 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4263 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4264 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
4265
4266 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4267 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4268 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4269
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004270 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004271
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004272 /* Check external link change only for non-direct */
4273 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
4274
4275 /* Read gp_status */
4276 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
4277 MDIO_REG_BANK_GP_STATUS,
4278 MDIO_GP_STATUS_TOP_AN_STATUS1,
4279 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004280
4281 rc = bnx2x_link_settings_status(params, vars, gp_status);
4282 if (rc != 0)
4283 return rc;
4284
4285 /* anything 10 and over uses the bmac */
4286 link_10g = ((vars->line_speed == SPEED_10000) ||
4287 (vars->line_speed == SPEED_12000) ||
4288 (vars->line_speed == SPEED_12500) ||
4289 (vars->line_speed == SPEED_13000) ||
4290 (vars->line_speed == SPEED_15000) ||
4291 (vars->line_speed == SPEED_16000));
4292
4293 bnx2x_link_int_ack(params, vars, link_10g);
4294
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004295 /* In case external phy link is up, and internal link is down
4296 ( not initialized yet probably after link initialization, it needs
4297 to be initialized.
4298 Note that after link down-up as result of cable plug,
4299 the xgxs link would probably become up again without the need to
4300 initialize it*/
4301
4302 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
4303 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
4304 (ext_phy_link_up && !vars->phy_link_up))
4305 bnx2x_init_internal_phy(params, vars);
4306
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004307 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004308 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004309
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004310 if (vars->link_up)
4311 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
4312 else
4313 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004314
4315 return rc;
4316}
4317
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004318static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
4319{
4320 u8 ext_phy_addr[PORT_MAX];
4321 u16 val;
4322 s8 port;
4323
4324 /* PART1 - Reset both phys */
4325 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4326 /* Extract the ext phy address for the port */
4327 u32 ext_phy_config = REG_RD(bp, shmem_base +
4328 offsetof(struct shmem_region,
4329 dev_info.port_hw_config[port].external_phy_config));
4330
4331 /* disable attentions */
4332 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4333 (NIG_MASK_XGXS0_LINK_STATUS |
4334 NIG_MASK_XGXS0_LINK10G |
4335 NIG_MASK_SERDES0_LINK_STATUS |
4336 NIG_MASK_MI_INT));
4337
4338 ext_phy_addr[port] =
4339 ((ext_phy_config &
4340 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4341 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4342
4343 /* Need to take the phy out of low power mode in order
4344 to write to access its registers */
4345 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4346 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
4347
4348 /* Reset the phy */
4349 bnx2x_cl45_write(bp, port,
4350 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4351 ext_phy_addr[port],
4352 MDIO_PMA_DEVAD,
4353 MDIO_PMA_REG_CTRL,
4354 1<<15);
4355 }
4356
4357 /* Add delay of 150ms after reset */
4358 msleep(150);
4359
4360 /* PART2 - Download firmware to both phys */
4361 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4362 u16 fw_ver1;
4363
4364 bnx2x_bcm8073_external_rom_boot(bp, port,
4365 ext_phy_addr[port]);
4366
4367 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4368 ext_phy_addr[port],
4369 MDIO_PMA_DEVAD,
4370 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
4371 if (fw_ver1 == 0) {
4372 DP(NETIF_MSG_LINK,
4373 "bnx2x_8073_common_init_phy port %x "
4374 "fw Download failed\n", port);
4375 return -EINVAL;
4376 }
4377
4378 /* Only set bit 10 = 1 (Tx power down) */
4379 bnx2x_cl45_read(bp, port,
4380 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4381 ext_phy_addr[port],
4382 MDIO_PMA_DEVAD,
4383 MDIO_PMA_REG_TX_POWER_DOWN, &val);
4384
4385 /* Phase1 of TX_POWER_DOWN reset */
4386 bnx2x_cl45_write(bp, port,
4387 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4388 ext_phy_addr[port],
4389 MDIO_PMA_DEVAD,
4390 MDIO_PMA_REG_TX_POWER_DOWN,
4391 (val | 1<<10));
4392 }
4393
4394 /* Toggle Transmitter: Power down and then up with 600ms
4395 delay between */
4396 msleep(600);
4397
4398 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
4399 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4400 /* Phase2 of POWER_DOWN_RESET*/
4401 /* Release bit 10 (Release Tx power down) */
4402 bnx2x_cl45_read(bp, port,
4403 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4404 ext_phy_addr[port],
4405 MDIO_PMA_DEVAD,
4406 MDIO_PMA_REG_TX_POWER_DOWN, &val);
4407
4408 bnx2x_cl45_write(bp, port,
4409 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4410 ext_phy_addr[port],
4411 MDIO_PMA_DEVAD,
4412 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
4413 msleep(15);
4414
4415 /* Read modify write the SPI-ROM version select register */
4416 bnx2x_cl45_read(bp, port,
4417 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4418 ext_phy_addr[port],
4419 MDIO_PMA_DEVAD,
4420 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
4421 bnx2x_cl45_write(bp, port,
4422 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4423 ext_phy_addr[port],
4424 MDIO_PMA_DEVAD,
4425 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
4426
4427 /* set GPIO2 back to LOW */
4428 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4429 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
4430 }
4431 return 0;
4432
4433}
4434
4435u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
4436{
4437 u8 rc = 0;
4438 u32 ext_phy_type;
4439
4440 DP(NETIF_MSG_LINK, "bnx2x_common_init_phy\n");
4441
4442 /* Read the ext_phy_type for arbitrary port(0) */
4443 ext_phy_type = XGXS_EXT_PHY_TYPE(
4444 REG_RD(bp, shmem_base +
4445 offsetof(struct shmem_region,
4446 dev_info.port_hw_config[0].external_phy_config)));
4447
4448 switch (ext_phy_type) {
4449 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4450 {
4451 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
4452 break;
4453 }
4454 default:
4455 DP(NETIF_MSG_LINK,
4456 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
4457 ext_phy_type);
4458 break;
4459 }
4460
4461 return rc;
4462}
4463
4464
4465
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004466static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
4467{
4468 u16 val, cnt;
4469
4470 bnx2x_cl45_read(bp, port,
4471 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4472 phy_addr,
4473 MDIO_PMA_DEVAD,
4474 MDIO_PMA_REG_7101_RESET, &val);
4475
4476 for (cnt = 0; cnt < 10; cnt++) {
4477 msleep(50);
4478 /* Writes a self-clearing reset */
4479 bnx2x_cl45_write(bp, port,
4480 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4481 phy_addr,
4482 MDIO_PMA_DEVAD,
4483 MDIO_PMA_REG_7101_RESET,
4484 (val | (1<<15)));
4485 /* Wait for clear */
4486 bnx2x_cl45_read(bp, port,
4487 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4488 phy_addr,
4489 MDIO_PMA_DEVAD,
4490 MDIO_PMA_REG_7101_RESET, &val);
4491
4492 if ((val & (1<<15)) == 0)
4493 break;
4494 }
4495}
4496#define RESERVED_SIZE 256
4497/* max application is 160K bytes - data at end of RAM */
4498#define MAX_APP_SIZE 160*1024 - RESERVED_SIZE
4499
4500/* Header is 14 bytes */
4501#define HEADER_SIZE 14
4502#define DATA_OFFSET HEADER_SIZE
4503
4504#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \
4505 bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \
4506 ext_phy_addr, \
4507 MDIO_PCS_DEVAD, \
4508 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1)
4509
4510/* Programs an image to DSP's flash via the SPI port*/
4511static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port,
4512 u8 ext_phy_addr,
4513 char data[], u32 size)
4514{
4515 const u16 num_trans = size/4; /* 4 bytes can be sent at a time */
4516 /* Doesn't include last trans!*/
4517 const u16 last_trans_size = size%4; /* Num bytes on last trans */
4518 u16 trans_cnt, byte_cnt;
4519 u32 data_index;
4520 u16 tmp;
4521 u16 code_started = 0;
4522 u16 image_revision1, image_revision2;
4523 u16 cnt;
4524
4525 DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size);
4526 /* Going to flash*/
4527 if ((size-HEADER_SIZE) > MAX_APP_SIZE) {
4528 /* This very often will be the case, because the image is built
4529 with 160Kbytes size whereas the total image size must actually
4530 be 160Kbytes-RESERVED_SIZE */
4531 DP(NETIF_MSG_LINK, "Warning, file size was %d bytes "
4532 "truncated to %d bytes\n", size, MAX_APP_SIZE);
4533 size = MAX_APP_SIZE+HEADER_SIZE;
4534 }
4535 DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]);
4536 DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]);
4537 /* Put the DSP in download mode by setting FLASH_CFG[2] to 1
4538 and issuing a reset.*/
4539
4540 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004541 MISC_REGISTERS_GPIO_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004542
4543 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
4544
4545 /* wait 0.5 sec */
4546 for (cnt = 0; cnt < 100; cnt++)
4547 msleep(5);
4548
4549 /* Make sure we can access the DSP
4550 And it's in the correct mode (waiting for download) */
4551
4552 bnx2x_cl45_read(bp, port,
4553 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4554 ext_phy_addr,
4555 MDIO_PCS_DEVAD,
4556 MDIO_PCS_REG_7101_DSP_ACCESS, &tmp);
4557
4558 if (tmp != 0x000A) {
4559 DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. "
4560 "Expected 0x000A, read 0x%04X\n", tmp);
4561 DP(NETIF_MSG_LINK, "Download failed\n");
4562 return -EINVAL;
4563 }
4564
4565 /* Mux the SPI interface away from the internal processor */
4566 bnx2x_cl45_write(bp, port,
4567 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4568 ext_phy_addr,
4569 MDIO_PCS_DEVAD,
4570 MDIO_PCS_REG_7101_SPI_MUX, 1);
4571
4572 /* Reset the SPI port */
4573 bnx2x_cl45_write(bp, port,
4574 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4575 ext_phy_addr,
4576 MDIO_PCS_DEVAD,
4577 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
4578 bnx2x_cl45_write(bp, port,
4579 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4580 ext_phy_addr,
4581 MDIO_PCS_DEVAD,
4582 MDIO_PCS_REG_7101_SPI_CTRL_ADDR,
4583 (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT));
4584 bnx2x_cl45_write(bp, port,
4585 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4586 ext_phy_addr,
4587 MDIO_PCS_DEVAD,
4588 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
4589
4590 /* Erase the flash */
4591 bnx2x_cl45_write(bp, port,
4592 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4593 ext_phy_addr,
4594 MDIO_PCS_DEVAD,
4595 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4596 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4597
4598 bnx2x_cl45_write(bp, port,
4599 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4600 ext_phy_addr,
4601 MDIO_PCS_DEVAD,
4602 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4603 1);
4604
4605 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4606 bnx2x_cl45_write(bp, port,
4607 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4608 ext_phy_addr,
4609 MDIO_PCS_DEVAD,
4610 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4611 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD);
4612
4613 bnx2x_cl45_write(bp, port,
4614 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4615 ext_phy_addr,
4616 MDIO_PCS_DEVAD,
4617 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4618 1);
4619 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4620
4621 /* Wait 10 seconds, the maximum time for the erase to complete */
4622 DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n");
4623 for (cnt = 0; cnt < 1000; cnt++)
4624 msleep(10);
4625
4626 DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n");
4627 data_index = 0;
4628 for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) {
4629 bnx2x_cl45_write(bp, port,
4630 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4631 ext_phy_addr,
4632 MDIO_PCS_DEVAD,
4633 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4634 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4635
4636 bnx2x_cl45_write(bp, port,
4637 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4638 ext_phy_addr,
4639 MDIO_PCS_DEVAD,
4640 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4641 1);
4642 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4643
4644 bnx2x_cl45_write(bp, port,
4645 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4646 ext_phy_addr,
4647 MDIO_PCS_DEVAD,
4648 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4649 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
4650
4651 /* Bits 23-16 of address */
4652 bnx2x_cl45_write(bp, port,
4653 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4654 ext_phy_addr,
4655 MDIO_PCS_DEVAD,
4656 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4657 (data_index>>16));
4658 /* Bits 15-8 of address */
4659 bnx2x_cl45_write(bp, port,
4660 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4661 ext_phy_addr,
4662 MDIO_PCS_DEVAD,
4663 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4664 (data_index>>8));
4665
4666 /* Bits 7-0 of address */
4667 bnx2x_cl45_write(bp, port,
4668 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4669 ext_phy_addr,
4670 MDIO_PCS_DEVAD,
4671 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4672 ((u16)data_index));
4673
4674 byte_cnt = 0;
4675 while (byte_cnt < 4 && data_index < size) {
4676 bnx2x_cl45_write(bp, port,
4677 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4678 ext_phy_addr,
4679 MDIO_PCS_DEVAD,
4680 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4681 data[data_index++]);
4682 byte_cnt++;
4683 }
4684
4685 bnx2x_cl45_write(bp, port,
4686 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4687 ext_phy_addr,
4688 MDIO_PCS_DEVAD,
4689 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4690 byte_cnt+4);
4691
4692 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4693 msleep(5); /* Wait 5 ms minimum between transs */
4694
4695 /* Let the user know something's going on.*/
4696 /* a pacifier ever 4K */
4697 if ((data_index % 1023) == 0)
4698 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
4699 }
4700
4701 DP(NETIF_MSG_LINK, "\n");
4702 /* Transfer the last block if there is data remaining */
4703 if (last_trans_size) {
4704 bnx2x_cl45_write(bp, port,
4705 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4706 ext_phy_addr,
4707 MDIO_PCS_DEVAD,
4708 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4709 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4710
4711 bnx2x_cl45_write(bp, port,
4712 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4713 ext_phy_addr,
4714 MDIO_PCS_DEVAD,
4715 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4716 1);
4717
4718 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4719
4720 bnx2x_cl45_write(bp, port,
4721 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4722 ext_phy_addr,
4723 MDIO_PCS_DEVAD,
4724 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4725 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
4726
4727 /* Bits 23-16 of address */
4728 bnx2x_cl45_write(bp, port,
4729 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4730 ext_phy_addr,
4731 MDIO_PCS_DEVAD,
4732 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4733 (data_index>>16));
4734 /* Bits 15-8 of address */
4735 bnx2x_cl45_write(bp, port,
4736 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4737 ext_phy_addr,
4738 MDIO_PCS_DEVAD,
4739 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4740 (data_index>>8));
4741
4742 /* Bits 7-0 of address */
4743 bnx2x_cl45_write(bp, port,
4744 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4745 ext_phy_addr,
4746 MDIO_PCS_DEVAD,
4747 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4748 ((u16)data_index));
4749
4750 byte_cnt = 0;
4751 while (byte_cnt < last_trans_size && data_index < size) {
4752 /* Bits 7-0 of address */
4753 bnx2x_cl45_write(bp, port,
4754 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4755 ext_phy_addr,
4756 MDIO_PCS_DEVAD,
4757 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4758 data[data_index++]);
4759 byte_cnt++;
4760 }
4761
4762 bnx2x_cl45_write(bp, port,
4763 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4764 ext_phy_addr,
4765 MDIO_PCS_DEVAD,
4766 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4767 byte_cnt+4);
4768
4769 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4770 }
4771
4772 /* DSP Remove Download Mode */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004773 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4774 MISC_REGISTERS_GPIO_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004775
4776 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
4777
4778 /* wait 0.5 sec to allow it to run */
4779 for (cnt = 0; cnt < 100; cnt++)
4780 msleep(5);
4781
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004782 bnx2x_hw_reset(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004783
4784 for (cnt = 0; cnt < 100; cnt++)
4785 msleep(5);
4786
4787 /* Check that the code is started. In case the download
4788 checksum failed, the code won't be started. */
4789 bnx2x_cl45_read(bp, port,
4790 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4791 ext_phy_addr,
4792 MDIO_PCS_DEVAD,
4793 MDIO_PCS_REG_7101_DSP_ACCESS,
4794 &tmp);
4795
4796 code_started = (tmp & (1<<4));
4797 if (!code_started) {
4798 DP(NETIF_MSG_LINK, "Download failed. Please check file.\n");
4799 return -EINVAL;
4800 }
4801
4802 /* Verify that the file revision is now equal to the image
4803 revision within the DSP */
4804 bnx2x_cl45_read(bp, port,
4805 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4806 ext_phy_addr,
4807 MDIO_PMA_DEVAD,
4808 MDIO_PMA_REG_7101_VER1,
4809 &image_revision1);
4810
4811 bnx2x_cl45_read(bp, port,
4812 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4813 ext_phy_addr,
4814 MDIO_PMA_DEVAD,
4815 MDIO_PMA_REG_7101_VER2,
4816 &image_revision2);
4817
4818 if (data[0x14e] != (image_revision2&0xFF) ||
4819 data[0x14f] != ((image_revision2&0xFF00)>>8) ||
4820 data[0x150] != (image_revision1&0xFF) ||
4821 data[0x151] != ((image_revision1&0xFF00)>>8)) {
4822 DP(NETIF_MSG_LINK, "Download failed.\n");
4823 return -EINVAL;
4824 }
4825 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
4826 return 0;
4827}
4828
4829u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
4830 u8 driver_loaded, char data[], u32 size)
4831{
4832 u8 rc = 0;
4833 u32 ext_phy_type;
4834 u8 ext_phy_addr;
4835 ext_phy_addr = ((ext_phy_config &
4836 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4837 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4838
4839 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4840
4841 switch (ext_phy_type) {
4842 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4843 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4844 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4845 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
4846 DP(NETIF_MSG_LINK,
4847 "Flash download not supported for this ext phy\n");
4848 rc = -EINVAL;
4849 break;
4850 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4851 /* Take ext phy out of reset */
4852 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004853 bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004854 rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
4855 data, size);
4856 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004857 bnx2x_turn_off_sf(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004858 break;
4859 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4860 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4861 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
4862 default:
4863 DP(NETIF_MSG_LINK, "Invalid ext phy type\n");
4864 rc = -EINVAL;
4865 break;
4866 }
4867 return rc;
4868}
4869