blob: 8b92c6ad0759107131e4d65211dad419c0b5e60f [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 */
Eilon Greenstein3196a882008-08-13 15:58:49 -070034#define ETH_HLEN 14
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070035#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/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070043/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070044/***********************************************************/
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
Eilon Greenstein3196a882008-08-13 15:58:49 -070082#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
83#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070084 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070085#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070086 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070087#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070088
89#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
90 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
91#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
92 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
93#define GP_STATUS_SPEED_MASK \
94 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
95#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
96#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
97#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
98#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
99#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
100#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
101#define GP_STATUS_10G_HIG \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
103#define GP_STATUS_10G_CX4 \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
105#define GP_STATUS_12G_HIG \
106 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
107#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
108#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
109#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
110#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
111#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
112#define GP_STATUS_10G_KX4 \
113 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
114
115#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
116#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
117#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
118#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
119#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
120#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
121#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
122#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
123#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
124#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
125#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
126#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
127#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
128#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
129#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
130#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
131#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
132#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
133#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
134#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
135#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
136#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
137#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
138
139#define PHY_XGXS_FLAG 0x1
140#define PHY_SGMII_FLAG 0x2
141#define PHY_SERDES_FLAG 0x4
142
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);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700204 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700205
206 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700207 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700208 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
209 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
210 if (!timeout) {
211 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
212 return;
213 }
214 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700215 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700216
217 /* Set mac address */
218 val = ((params->mac_addr[0] << 8) |
219 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700220 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700221
222 val = ((params->mac_addr[2] << 24) |
223 (params->mac_addr[3] << 16) |
224 (params->mac_addr[4] << 8) |
225 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700226 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700227}
228
229static u8 bnx2x_emac_enable(struct link_params *params,
230 struct link_vars *vars, u8 lb)
231{
232 struct bnx2x *bp = params->bp;
233 u8 port = params->port;
234 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
235 u32 val;
236
237 DP(NETIF_MSG_LINK, "enabling EMAC\n");
238
239 /* enable emac and not bmac */
240 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
241
242 /* for paladium */
243 if (CHIP_REV_IS_EMUL(bp)) {
244 /* Use lane 1 (of lanes 0-3) */
245 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
246 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
247 port*4, 1);
248 }
249 /* for fpga */
250 else
251
252 if (CHIP_REV_IS_FPGA(bp)) {
253 /* Use lane 1 (of lanes 0-3) */
254 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
255
256 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
257 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
258 0);
259 } else
260 /* ASIC */
261 if (vars->phy_flags & PHY_XGXS_FLAG) {
262 u32 ser_lane = ((params->lane_config &
263 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
264 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
265
266 DP(NETIF_MSG_LINK, "XGXS\n");
267 /* select the master lanes (out of 0-3) */
268 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
269 port*4, ser_lane);
270 /* select XGXS */
271 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
272 port*4, 1);
273
274 } else { /* SerDes */
275 DP(NETIF_MSG_LINK, "SerDes\n");
276 /* select SerDes */
277 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
278 port*4, 0);
279 }
280
281 /* enable emac */
282 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
283
284 if (CHIP_REV_IS_SLOW(bp)) {
285 /* config GMII mode */
286 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700287 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700288 (val | EMAC_MODE_PORT_GMII));
289 } else { /* ASIC */
290 /* pause enable/disable */
291 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
292 EMAC_RX_MODE_FLOW_EN);
293 if (vars->flow_ctrl & FLOW_CTRL_RX)
294 bnx2x_bits_en(bp, emac_base +
295 EMAC_REG_EMAC_RX_MODE,
296 EMAC_RX_MODE_FLOW_EN);
297
298 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700299 (EMAC_TX_MODE_EXT_PAUSE_EN |
300 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700301 if (vars->flow_ctrl & FLOW_CTRL_TX)
302 bnx2x_bits_en(bp, emac_base +
303 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700304 (EMAC_TX_MODE_EXT_PAUSE_EN |
305 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700306 }
307
308 /* KEEP_VLAN_TAG, promiscuous */
309 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
310 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700311 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700312
313 /* Set Loopback */
314 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
315 if (lb)
316 val |= 0x810;
317 else
318 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700319 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700320
321 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700322 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700323 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
324 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
325
326 /* strip CRC */
327 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
328
329 /* disable the NIG in/out to the bmac */
330 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
331 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
332 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
333
334 /* enable the NIG in/out to the emac */
335 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
336 val = 0;
337 if (vars->flow_ctrl & FLOW_CTRL_TX)
338 val = 1;
339
340 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
341 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
342
343 if (CHIP_REV_IS_EMUL(bp)) {
344 /* take the BigMac out of reset */
345 REG_WR(bp,
346 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
347 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
348
349 /* enable access for bmac registers */
350 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
351 }
352
353 vars->mac_type = MAC_TYPE_EMAC;
354 return 0;
355}
356
357
358
359static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
360 u8 is_lb)
361{
362 struct bnx2x *bp = params->bp;
363 u8 port = params->port;
364 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
365 NIG_REG_INGRESS_BMAC0_MEM;
366 u32 wb_data[2];
367 u32 val;
368
369 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
370 /* reset and unreset the BigMac */
371 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
372 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
373 msleep(1);
374
375 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
376 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
377
378 /* enable access for bmac registers */
379 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
380
381 /* XGXS control */
382 wb_data[0] = 0x3c;
383 wb_data[1] = 0;
384 REG_WR_DMAE(bp, bmac_addr +
385 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
386 wb_data, 2);
387
388 /* tx MAC SA */
389 wb_data[0] = ((params->mac_addr[2] << 24) |
390 (params->mac_addr[3] << 16) |
391 (params->mac_addr[4] << 8) |
392 params->mac_addr[5]);
393 wb_data[1] = ((params->mac_addr[0] << 8) |
394 params->mac_addr[1]);
395 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
396 wb_data, 2);
397
398 /* tx control */
399 val = 0xc0;
400 if (vars->flow_ctrl & FLOW_CTRL_TX)
401 val |= 0x800000;
402 wb_data[0] = val;
403 wb_data[1] = 0;
404 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
405 wb_data, 2);
406
407 /* mac control */
408 val = 0x3;
409 if (is_lb) {
410 val |= 0x4;
411 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
412 }
413 wb_data[0] = val;
414 wb_data[1] = 0;
415 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
416 wb_data, 2);
417
418
419 /* set rx mtu */
420 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
421 wb_data[1] = 0;
422 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
423 wb_data, 2);
424
425 /* rx control set to don't strip crc */
426 val = 0x14;
427 if (vars->flow_ctrl & FLOW_CTRL_RX)
428 val |= 0x20;
429 wb_data[0] = val;
430 wb_data[1] = 0;
431 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
432 wb_data, 2);
433
434 /* set tx mtu */
435 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
436 wb_data[1] = 0;
437 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
438 wb_data, 2);
439
440 /* set cnt max size */
441 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
442 wb_data[1] = 0;
443 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
444 wb_data, 2);
445
446 /* configure safc */
447 wb_data[0] = 0x1000200;
448 wb_data[1] = 0;
449 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
450 wb_data, 2);
451 /* fix for emulation */
452 if (CHIP_REV_IS_EMUL(bp)) {
453 wb_data[0] = 0xf000;
454 wb_data[1] = 0;
455 REG_WR_DMAE(bp,
456 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
457 wb_data, 2);
458 }
459
460 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
461 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
462 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
463 val = 0;
464 if (vars->flow_ctrl & FLOW_CTRL_TX)
465 val = 1;
466 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
467 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
468 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
469 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
470 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
471 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
472
473 vars->mac_type = MAC_TYPE_BMAC;
474 return 0;
475}
476
477static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
478{
479 struct bnx2x *bp = params->bp;
480 u32 val;
481
482 if (phy_flags & PHY_XGXS_FLAG) {
483 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
484 val = XGXS_RESET_BITS;
485
486 } else { /* SerDes */
487 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
488 val = SERDES_RESET_BITS;
489 }
490
491 val = val << (params->port*16);
492
493 /* reset and unreset the SerDes/XGXS */
494 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
495 val);
496 udelay(500);
497 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
498 val);
499 bnx2x_set_phy_mdio(params);
500}
501
502void bnx2x_link_status_update(struct link_params *params,
503 struct link_vars *vars)
504{
505 struct bnx2x *bp = params->bp;
506 u8 link_10g;
507 u8 port = params->port;
508
509 if (params->switch_cfg == SWITCH_CFG_1G)
510 vars->phy_flags = PHY_SERDES_FLAG;
511 else
512 vars->phy_flags = PHY_XGXS_FLAG;
513 vars->link_status = REG_RD(bp, params->shmem_base +
514 offsetof(struct shmem_region,
515 port_mb[port].link_status));
516
517 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
518
519 if (vars->link_up) {
520 DP(NETIF_MSG_LINK, "phy link up\n");
521
522 vars->phy_link_up = 1;
523 vars->duplex = DUPLEX_FULL;
524 switch (vars->link_status &
525 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
526 case LINK_10THD:
527 vars->duplex = DUPLEX_HALF;
528 /* fall thru */
529 case LINK_10TFD:
530 vars->line_speed = SPEED_10;
531 break;
532
533 case LINK_100TXHD:
534 vars->duplex = DUPLEX_HALF;
535 /* fall thru */
536 case LINK_100T4:
537 case LINK_100TXFD:
538 vars->line_speed = SPEED_100;
539 break;
540
541 case LINK_1000THD:
542 vars->duplex = DUPLEX_HALF;
543 /* fall thru */
544 case LINK_1000TFD:
545 vars->line_speed = SPEED_1000;
546 break;
547
548 case LINK_2500THD:
549 vars->duplex = DUPLEX_HALF;
550 /* fall thru */
551 case LINK_2500TFD:
552 vars->line_speed = SPEED_2500;
553 break;
554
555 case LINK_10GTFD:
556 vars->line_speed = SPEED_10000;
557 break;
558
559 case LINK_12GTFD:
560 vars->line_speed = SPEED_12000;
561 break;
562
563 case LINK_12_5GTFD:
564 vars->line_speed = SPEED_12500;
565 break;
566
567 case LINK_13GTFD:
568 vars->line_speed = SPEED_13000;
569 break;
570
571 case LINK_15GTFD:
572 vars->line_speed = SPEED_15000;
573 break;
574
575 case LINK_16GTFD:
576 vars->line_speed = SPEED_16000;
577 break;
578
579 default:
580 break;
581 }
582
583 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
584 vars->flow_ctrl |= FLOW_CTRL_TX;
585 else
586 vars->flow_ctrl &= ~FLOW_CTRL_TX;
587
588 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
589 vars->flow_ctrl |= FLOW_CTRL_RX;
590 else
591 vars->flow_ctrl &= ~FLOW_CTRL_RX;
592
593 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700594 if (vars->line_speed &&
595 ((vars->line_speed == SPEED_10) ||
596 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700597 vars->phy_flags |= PHY_SGMII_FLAG;
598 } else {
599 vars->phy_flags &= ~PHY_SGMII_FLAG;
600 }
601 }
602
603 /* anything 10 and over uses the bmac */
604 link_10g = ((vars->line_speed == SPEED_10000) ||
605 (vars->line_speed == SPEED_12000) ||
606 (vars->line_speed == SPEED_12500) ||
607 (vars->line_speed == SPEED_13000) ||
608 (vars->line_speed == SPEED_15000) ||
609 (vars->line_speed == SPEED_16000));
610 if (link_10g)
611 vars->mac_type = MAC_TYPE_BMAC;
612 else
613 vars->mac_type = MAC_TYPE_EMAC;
614
615 } else { /* link down */
616 DP(NETIF_MSG_LINK, "phy link down\n");
617
618 vars->phy_link_up = 0;
619
620 vars->line_speed = 0;
621 vars->duplex = DUPLEX_FULL;
622 vars->flow_ctrl = FLOW_CTRL_NONE;
623
624 /* indicate no mac active */
625 vars->mac_type = MAC_TYPE_NONE;
626 }
627
628 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
629 vars->link_status, vars->phy_link_up);
630 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
631 vars->line_speed, vars->duplex, vars->flow_ctrl);
632}
633
634static void bnx2x_update_mng(struct link_params *params, u32 link_status)
635{
636 struct bnx2x *bp = params->bp;
637 REG_WR(bp, params->shmem_base +
638 offsetof(struct shmem_region,
639 port_mb[params->port].link_status),
640 link_status);
641}
642
643static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
644{
645 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
646 NIG_REG_INGRESS_BMAC0_MEM;
647 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700648 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700649
650 /* Only if the bmac is out of reset */
651 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
652 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
653 nig_bmac_enable) {
654
655 /* Clear Rx Enable bit in BMAC_CONTROL register */
656 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
657 wb_data, 2);
658 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
659 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
660 wb_data, 2);
661
662 msleep(1);
663 }
664}
665
666static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
667 u32 line_speed)
668{
669 struct bnx2x *bp = params->bp;
670 u8 port = params->port;
671 u32 init_crd, crd;
672 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700673
674 /* disable port */
675 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
676
677 /* wait for init credit */
678 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
679 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
680 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
681
682 while ((init_crd != crd) && count) {
683 msleep(5);
684
685 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
686 count--;
687 }
688 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
689 if (init_crd != crd) {
690 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
691 init_crd, crd);
692 return -EINVAL;
693 }
694
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700695 if (flow_ctrl & FLOW_CTRL_RX ||
696 line_speed == SPEED_10 ||
697 line_speed == SPEED_100 ||
698 line_speed == SPEED_1000 ||
699 line_speed == SPEED_2500) {
700 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700701 /* update threshold */
702 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
703 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700704 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700705
706 } else {
707 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
708 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700709 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700710 /* update threshold */
711 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
712 /* update init credit */
713 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700714 case SPEED_10000:
715 init_crd = thresh + 553 - 22;
716 break;
717
718 case SPEED_12000:
719 init_crd = thresh + 664 - 22;
720 break;
721
722 case SPEED_13000:
723 init_crd = thresh + 742 - 22;
724 break;
725
726 case SPEED_16000:
727 init_crd = thresh + 778 - 22;
728 break;
729 default:
730 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
731 line_speed);
732 return -EINVAL;
733 break;
734 }
735 }
736 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
737 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
738 line_speed, init_crd);
739
740 /* probe the credit changes */
741 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
742 msleep(5);
743 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
744
745 /* enable port */
746 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
747 return 0;
748}
749
750static u32 bnx2x_get_emac_base(u32 ext_phy_type, u8 port)
751{
752 u32 emac_base;
753 switch (ext_phy_type) {
754 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
755 emac_base = GRCBASE_EMAC0;
756 break;
757 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700758 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700759 break;
760 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700761 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700762 break;
763 }
764 return emac_base;
765
766}
767
768u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
769 u8 phy_addr, u8 devad, u16 reg, u16 val)
770{
771 u32 tmp, saved_mode;
772 u8 i, rc = 0;
773 u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
774
775 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
776 * (a value of 49==0x31) and make sure that the AUTO poll is off
777 */
778 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
779 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
780 EMAC_MDIO_MODE_CLOCK_CNT);
781 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
782 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
783 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
784 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
785 udelay(40);
786
787 /* address */
788
789 tmp = ((phy_addr << 21) | (devad << 16) | reg |
790 EMAC_MDIO_COMM_COMMAND_ADDRESS |
791 EMAC_MDIO_COMM_START_BUSY);
792 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
793
794 for (i = 0; i < 50; i++) {
795 udelay(10);
796
797 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
798 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
799 udelay(5);
800 break;
801 }
802 }
803 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
804 DP(NETIF_MSG_LINK, "write phy register failed\n");
805 rc = -EFAULT;
806 } else {
807 /* data */
808 tmp = ((phy_addr << 21) | (devad << 16) | val |
809 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
810 EMAC_MDIO_COMM_START_BUSY);
811 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
812
813 for (i = 0; i < 50; i++) {
814 udelay(10);
815
816 tmp = REG_RD(bp, mdio_ctrl +
817 EMAC_REG_EMAC_MDIO_COMM);
818 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
819 udelay(5);
820 break;
821 }
822 }
823 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
824 DP(NETIF_MSG_LINK, "write phy register failed\n");
825 rc = -EFAULT;
826 }
827 }
828
829 /* Restore the saved mode */
830 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
831
832 return rc;
833}
834
835u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
836 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
837{
838 u32 val, saved_mode;
839 u16 i;
840 u8 rc = 0;
841
842 u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
843 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
844 * (a value of 49==0x31) and make sure that the AUTO poll is off
845 */
846 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
847 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
848 EMAC_MDIO_MODE_CLOCK_CNT));
849 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
850 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
851 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
852 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
853 udelay(40);
854
855 /* address */
856 val = ((phy_addr << 21) | (devad << 16) | reg |
857 EMAC_MDIO_COMM_COMMAND_ADDRESS |
858 EMAC_MDIO_COMM_START_BUSY);
859 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
860
861 for (i = 0; i < 50; i++) {
862 udelay(10);
863
864 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
865 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
866 udelay(5);
867 break;
868 }
869 }
870 if (val & EMAC_MDIO_COMM_START_BUSY) {
871 DP(NETIF_MSG_LINK, "read phy register failed\n");
872
873 *ret_val = 0;
874 rc = -EFAULT;
875
876 } else {
877 /* data */
878 val = ((phy_addr << 21) | (devad << 16) |
879 EMAC_MDIO_COMM_COMMAND_READ_45 |
880 EMAC_MDIO_COMM_START_BUSY);
881 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
882
883 for (i = 0; i < 50; i++) {
884 udelay(10);
885
886 val = REG_RD(bp, mdio_ctrl +
887 EMAC_REG_EMAC_MDIO_COMM);
888 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
889 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
890 break;
891 }
892 }
893 if (val & EMAC_MDIO_COMM_START_BUSY) {
894 DP(NETIF_MSG_LINK, "read phy register failed\n");
895
896 *ret_val = 0;
897 rc = -EFAULT;
898 }
899 }
900
901 /* Restore the saved mode */
902 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
903
904 return rc;
905}
906
907static void bnx2x_set_aer_mmd(struct link_params *params,
908 struct link_vars *vars)
909{
910 struct bnx2x *bp = params->bp;
911 u32 ser_lane;
912 u16 offset;
913
914 ser_lane = ((params->lane_config &
915 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
916 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
917
918 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
919 (params->phy_addr + ser_lane) : 0;
920
921 CL45_WR_OVER_CL22(bp, params->port,
922 params->phy_addr,
923 MDIO_REG_BANK_AER_BLOCK,
924 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
925}
926
927static void bnx2x_set_master_ln(struct link_params *params)
928{
929 struct bnx2x *bp = params->bp;
930 u16 new_master_ln, ser_lane;
931 ser_lane = ((params->lane_config &
932 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
933 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
934
935 /* set the master_ln for AN */
936 CL45_RD_OVER_CL22(bp, params->port,
937 params->phy_addr,
938 MDIO_REG_BANK_XGXS_BLOCK2,
939 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
940 &new_master_ln);
941
942 CL45_WR_OVER_CL22(bp, params->port,
943 params->phy_addr,
944 MDIO_REG_BANK_XGXS_BLOCK2 ,
945 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
946 (new_master_ln | ser_lane));
947}
948
949static u8 bnx2x_reset_unicore(struct link_params *params)
950{
951 struct bnx2x *bp = params->bp;
952 u16 mii_control;
953 u16 i;
954
955 CL45_RD_OVER_CL22(bp, params->port,
956 params->phy_addr,
957 MDIO_REG_BANK_COMBO_IEEE0,
958 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
959
960 /* reset the unicore */
961 CL45_WR_OVER_CL22(bp, params->port,
962 params->phy_addr,
963 MDIO_REG_BANK_COMBO_IEEE0,
964 MDIO_COMBO_IEEE0_MII_CONTROL,
965 (mii_control |
966 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
967
968 /* wait for the reset to self clear */
969 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
970 udelay(5);
971
972 /* the reset erased the previous bank value */
973 CL45_RD_OVER_CL22(bp, params->port,
974 params->phy_addr,
975 MDIO_REG_BANK_COMBO_IEEE0,
976 MDIO_COMBO_IEEE0_MII_CONTROL,
977 &mii_control);
978
979 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
980 udelay(5);
981 return 0;
982 }
983 }
984
985 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
986 return -EINVAL;
987
988}
989
990static void bnx2x_set_swap_lanes(struct link_params *params)
991{
992 struct bnx2x *bp = params->bp;
993 /* Each two bits represents a lane number:
994 No swap is 0123 => 0x1b no need to enable the swap */
995 u16 ser_lane, rx_lane_swap, tx_lane_swap;
996
997 ser_lane = ((params->lane_config &
998 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
999 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1000 rx_lane_swap = ((params->lane_config &
1001 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1002 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1003 tx_lane_swap = ((params->lane_config &
1004 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1005 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1006
1007 if (rx_lane_swap != 0x1b) {
1008 CL45_WR_OVER_CL22(bp, params->port,
1009 params->phy_addr,
1010 MDIO_REG_BANK_XGXS_BLOCK2,
1011 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1012 (rx_lane_swap |
1013 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1014 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1015 } else {
1016 CL45_WR_OVER_CL22(bp, params->port,
1017 params->phy_addr,
1018 MDIO_REG_BANK_XGXS_BLOCK2,
1019 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1020 }
1021
1022 if (tx_lane_swap != 0x1b) {
1023 CL45_WR_OVER_CL22(bp, params->port,
1024 params->phy_addr,
1025 MDIO_REG_BANK_XGXS_BLOCK2,
1026 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1027 (tx_lane_swap |
1028 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1029 } else {
1030 CL45_WR_OVER_CL22(bp, params->port,
1031 params->phy_addr,
1032 MDIO_REG_BANK_XGXS_BLOCK2,
1033 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1034 }
1035}
1036
1037static void bnx2x_set_parallel_detection(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07001038 u8 phy_flags)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001039{
1040 struct bnx2x *bp = params->bp;
1041 u16 control2;
1042
1043 CL45_RD_OVER_CL22(bp, params->port,
1044 params->phy_addr,
1045 MDIO_REG_BANK_SERDES_DIGITAL,
1046 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1047 &control2);
1048
1049
1050 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1051
1052
1053 CL45_WR_OVER_CL22(bp, params->port,
1054 params->phy_addr,
1055 MDIO_REG_BANK_SERDES_DIGITAL,
1056 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1057 control2);
1058
1059 if (phy_flags & PHY_XGXS_FLAG) {
1060 DP(NETIF_MSG_LINK, "XGXS\n");
1061
1062 CL45_WR_OVER_CL22(bp, params->port,
1063 params->phy_addr,
1064 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1065 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1066 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1067
1068 CL45_RD_OVER_CL22(bp, params->port,
1069 params->phy_addr,
1070 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1071 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1072 &control2);
1073
1074
1075 control2 |=
1076 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1077
1078 CL45_WR_OVER_CL22(bp, params->port,
1079 params->phy_addr,
1080 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1081 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1082 control2);
1083
1084 /* Disable parallel detection of HiG */
1085 CL45_WR_OVER_CL22(bp, params->port,
1086 params->phy_addr,
1087 MDIO_REG_BANK_XGXS_BLOCK2,
1088 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1089 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1090 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1091 }
1092}
1093
1094static void bnx2x_set_autoneg(struct link_params *params,
1095 struct link_vars *vars)
1096{
1097 struct bnx2x *bp = params->bp;
1098 u16 reg_val;
1099
1100 /* CL37 Autoneg */
1101
1102 CL45_RD_OVER_CL22(bp, params->port,
1103 params->phy_addr,
1104 MDIO_REG_BANK_COMBO_IEEE0,
1105 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1106
1107 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001108 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001109 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1110 else /* CL37 Autoneg Disabled */
1111 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1112 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1113
1114 CL45_WR_OVER_CL22(bp, params->port,
1115 params->phy_addr,
1116 MDIO_REG_BANK_COMBO_IEEE0,
1117 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1118
1119 /* Enable/Disable Autodetection */
1120
1121 CL45_RD_OVER_CL22(bp, params->port,
1122 params->phy_addr,
1123 MDIO_REG_BANK_SERDES_DIGITAL,
1124 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
1125 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001126 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001127 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1128 else
1129 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1130
1131 CL45_WR_OVER_CL22(bp, params->port,
1132 params->phy_addr,
1133 MDIO_REG_BANK_SERDES_DIGITAL,
1134 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1135
1136 /* Enable TetonII and BAM autoneg */
1137 CL45_RD_OVER_CL22(bp, params->port,
1138 params->phy_addr,
1139 MDIO_REG_BANK_BAM_NEXT_PAGE,
1140 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1141 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001142 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001143 /* Enable BAM aneg Mode and TetonII aneg Mode */
1144 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1145 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1146 } else {
1147 /* TetonII and BAM Autoneg Disabled */
1148 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1149 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1150 }
1151 CL45_WR_OVER_CL22(bp, params->port,
1152 params->phy_addr,
1153 MDIO_REG_BANK_BAM_NEXT_PAGE,
1154 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1155 reg_val);
1156
1157 /* Enable Clause 73 Aneg */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001158 if ((vars->line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001159 (SUPPORT_CL73)) {
1160 /* Enable BAM Station Manager */
1161
1162 CL45_WR_OVER_CL22(bp, params->port,
1163 params->phy_addr,
1164 MDIO_REG_BANK_CL73_USERB0,
1165 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1166 (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1167 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1168 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN));
1169
1170 /* Merge CL73 and CL37 aneg resolution */
1171 CL45_RD_OVER_CL22(bp, params->port,
1172 params->phy_addr,
1173 MDIO_REG_BANK_CL73_USERB0,
1174 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1175 &reg_val);
1176
1177 CL45_WR_OVER_CL22(bp, params->port,
1178 params->phy_addr,
1179 MDIO_REG_BANK_CL73_USERB0,
1180 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1181 (reg_val |
1182 MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR));
1183
1184 /* Set the CL73 AN speed */
1185
1186 CL45_RD_OVER_CL22(bp, params->port,
1187 params->phy_addr,
1188 MDIO_REG_BANK_CL73_IEEEB1,
1189 MDIO_CL73_IEEEB1_AN_ADV2, &reg_val);
1190 /* In the SerDes we support only the 1G.
1191 In the XGXS we support the 10G KX4
1192 but we currently do not support the KR */
1193 if (vars->phy_flags & PHY_XGXS_FLAG) {
1194 DP(NETIF_MSG_LINK, "XGXS\n");
1195 /* 10G KX4 */
1196 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1197 } else {
1198 DP(NETIF_MSG_LINK, "SerDes\n");
1199 /* 1000M KX */
1200 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
1201 }
1202 CL45_WR_OVER_CL22(bp, params->port,
1203 params->phy_addr,
1204 MDIO_REG_BANK_CL73_IEEEB1,
1205 MDIO_CL73_IEEEB1_AN_ADV2, reg_val);
1206
1207 /* CL73 Autoneg Enabled */
1208 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1209 } else {
1210 /* CL73 Autoneg Disabled */
1211 reg_val = 0;
1212 }
1213 CL45_WR_OVER_CL22(bp, params->port,
1214 params->phy_addr,
1215 MDIO_REG_BANK_CL73_IEEEB0,
1216 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1217}
1218
1219/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001220static void bnx2x_program_serdes(struct link_params *params,
1221 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001222{
1223 struct bnx2x *bp = params->bp;
1224 u16 reg_val;
1225
1226 /* program duplex, disable autoneg */
1227
1228 CL45_RD_OVER_CL22(bp, params->port,
1229 params->phy_addr,
1230 MDIO_REG_BANK_COMBO_IEEE0,
1231 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1232 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
1233 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN);
1234 if (params->req_duplex == DUPLEX_FULL)
1235 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1236 CL45_WR_OVER_CL22(bp, params->port,
1237 params->phy_addr,
1238 MDIO_REG_BANK_COMBO_IEEE0,
1239 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1240
1241 /* program speed
1242 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001243 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001244 params->phy_addr,
1245 MDIO_REG_BANK_SERDES_DIGITAL,
1246 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001247 /* clearing the speed value before setting the right speed */
1248 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1249
1250 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1251 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1252
1253 if (!((vars->line_speed == SPEED_1000) ||
1254 (vars->line_speed == SPEED_100) ||
1255 (vars->line_speed == SPEED_10))) {
1256
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001257 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1258 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001259 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001260 reg_val |=
1261 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001262 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001263 reg_val |=
1264 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001265 }
1266
1267 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001268 params->phy_addr,
1269 MDIO_REG_BANK_SERDES_DIGITAL,
1270 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001271
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001272}
1273
1274static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1275{
1276 struct bnx2x *bp = params->bp;
1277 u16 val = 0;
1278
1279 /* configure the 48 bits for BAM AN */
1280
1281 /* set extended capabilities */
1282 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1283 val |= MDIO_OVER_1G_UP1_2_5G;
1284 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1285 val |= MDIO_OVER_1G_UP1_10G;
1286 CL45_WR_OVER_CL22(bp, params->port,
1287 params->phy_addr,
1288 MDIO_REG_BANK_OVER_1G,
1289 MDIO_OVER_1G_UP1, val);
1290
1291 CL45_WR_OVER_CL22(bp, params->port,
1292 params->phy_addr,
1293 MDIO_REG_BANK_OVER_1G,
1294 MDIO_OVER_1G_UP3, 0);
1295}
1296
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001297static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001298{
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001299 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001300 /* resolve pause mode and advertisement
1301 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1302
1303 switch (params->req_flow_ctrl) {
1304 case FLOW_CTRL_AUTO:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001305 if (params->req_fc_auto_adv == FLOW_CTRL_BOTH) {
1306 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001307 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1308 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001309 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001310 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1311 }
1312 break;
1313 case FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001314 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001315 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1316 break;
1317
1318 case FLOW_CTRL_RX:
1319 case FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001320 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001321 break;
1322
1323 case FLOW_CTRL_NONE:
1324 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001325 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001326 break;
1327 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001328}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001329
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001330static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
1331 u32 ieee_fc)
1332{
1333 struct bnx2x *bp = params->bp;
1334 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001335
1336 CL45_WR_OVER_CL22(bp, params->port,
1337 params->phy_addr,
1338 MDIO_REG_BANK_COMBO_IEEE0,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001339 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001340}
1341
1342static void bnx2x_restart_autoneg(struct link_params *params)
1343{
1344 struct bnx2x *bp = params->bp;
1345 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
1346 if (SUPPORT_CL73) {
1347 /* enable and restart clause 73 aneg */
1348 u16 an_ctrl;
1349
1350 CL45_RD_OVER_CL22(bp, params->port,
1351 params->phy_addr,
1352 MDIO_REG_BANK_CL73_IEEEB0,
1353 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1354 &an_ctrl);
1355 CL45_WR_OVER_CL22(bp, params->port,
1356 params->phy_addr,
1357 MDIO_REG_BANK_CL73_IEEEB0,
1358 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1359 (an_ctrl |
1360 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1361 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1362
1363 } else {
1364 /* Enable and restart BAM/CL37 aneg */
1365 u16 mii_control;
1366
1367 CL45_RD_OVER_CL22(bp, params->port,
1368 params->phy_addr,
1369 MDIO_REG_BANK_COMBO_IEEE0,
1370 MDIO_COMBO_IEEE0_MII_CONTROL,
1371 &mii_control);
1372 DP(NETIF_MSG_LINK,
1373 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1374 mii_control);
1375 CL45_WR_OVER_CL22(bp, params->port,
1376 params->phy_addr,
1377 MDIO_REG_BANK_COMBO_IEEE0,
1378 MDIO_COMBO_IEEE0_MII_CONTROL,
1379 (mii_control |
1380 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1381 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1382 }
1383}
1384
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001385static void bnx2x_initialize_sgmii_process(struct link_params *params,
1386 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001387{
1388 struct bnx2x *bp = params->bp;
1389 u16 control1;
1390
1391 /* in SGMII mode, the unicore is always slave */
1392
1393 CL45_RD_OVER_CL22(bp, params->port,
1394 params->phy_addr,
1395 MDIO_REG_BANK_SERDES_DIGITAL,
1396 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1397 &control1);
1398 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1399 /* set sgmii mode (and not fiber) */
1400 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1401 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1402 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1403 CL45_WR_OVER_CL22(bp, params->port,
1404 params->phy_addr,
1405 MDIO_REG_BANK_SERDES_DIGITAL,
1406 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1407 control1);
1408
1409 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001410 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001411 /* set speed, disable autoneg */
1412 u16 mii_control;
1413
1414 CL45_RD_OVER_CL22(bp, params->port,
1415 params->phy_addr,
1416 MDIO_REG_BANK_COMBO_IEEE0,
1417 MDIO_COMBO_IEEE0_MII_CONTROL,
1418 &mii_control);
1419 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1420 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1421 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1422
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001423 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001424 case SPEED_100:
1425 mii_control |=
1426 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1427 break;
1428 case SPEED_1000:
1429 mii_control |=
1430 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1431 break;
1432 case SPEED_10:
1433 /* there is nothing to set for 10M */
1434 break;
1435 default:
1436 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001437 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1438 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001439 break;
1440 }
1441
1442 /* setting the full duplex */
1443 if (params->req_duplex == DUPLEX_FULL)
1444 mii_control |=
1445 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1446 CL45_WR_OVER_CL22(bp, params->port,
1447 params->phy_addr,
1448 MDIO_REG_BANK_COMBO_IEEE0,
1449 MDIO_COMBO_IEEE0_MII_CONTROL,
1450 mii_control);
1451
1452 } else { /* AN mode */
1453 /* enable and restart AN */
1454 bnx2x_restart_autoneg(params);
1455 }
1456}
1457
1458
1459/*
1460 * link management
1461 */
1462
1463static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001464{ /* LD LP */
1465 switch (pause_result) { /* ASYM P ASYM P */
1466 case 0xb: /* 1 0 1 1 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001467 vars->flow_ctrl = FLOW_CTRL_TX;
1468 break;
1469
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001470 case 0xe: /* 1 1 1 0 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001471 vars->flow_ctrl = FLOW_CTRL_RX;
1472 break;
1473
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001474 case 0x5: /* 0 1 0 1 */
1475 case 0x7: /* 0 1 1 1 */
1476 case 0xd: /* 1 1 0 1 */
1477 case 0xf: /* 1 1 1 1 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001478 vars->flow_ctrl = FLOW_CTRL_BOTH;
1479 break;
1480
1481 default:
1482 break;
1483 }
1484}
1485
1486static u8 bnx2x_ext_phy_resove_fc(struct link_params *params,
1487 struct link_vars *vars)
1488{
1489 struct bnx2x *bp = params->bp;
1490 u8 ext_phy_addr;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001491 u16 ld_pause; /* local */
1492 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001493 u16 an_complete; /* AN complete */
1494 u16 pause_result;
1495 u8 ret = 0;
1496 u32 ext_phy_type;
1497 u8 port = params->port;
1498 ext_phy_addr = ((params->ext_phy_config &
1499 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1500 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1501
1502 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1503 /* read twice */
1504
1505 bnx2x_cl45_read(bp, port,
1506 ext_phy_type,
1507 ext_phy_addr,
1508 MDIO_AN_DEVAD,
1509 MDIO_AN_REG_STATUS, &an_complete);
1510 bnx2x_cl45_read(bp, port,
1511 ext_phy_type,
1512 ext_phy_addr,
1513 MDIO_AN_DEVAD,
1514 MDIO_AN_REG_STATUS, &an_complete);
1515
1516 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1517 ret = 1;
1518 bnx2x_cl45_read(bp, port,
1519 ext_phy_type,
1520 ext_phy_addr,
1521 MDIO_AN_DEVAD,
1522 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1523 bnx2x_cl45_read(bp, port,
1524 ext_phy_type,
1525 ext_phy_addr,
1526 MDIO_AN_DEVAD,
1527 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1528 pause_result = (ld_pause &
1529 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1530 pause_result |= (lp_pause &
1531 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1532 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
1533 pause_result);
1534 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001535 if (vars->flow_ctrl == FLOW_CTRL_NONE &&
1536 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1537 bnx2x_cl45_read(bp, port,
1538 ext_phy_type,
1539 ext_phy_addr,
1540 MDIO_AN_DEVAD,
1541 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1542
1543 bnx2x_cl45_read(bp, port,
1544 ext_phy_type,
1545 ext_phy_addr,
1546 MDIO_AN_DEVAD,
1547 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1548 pause_result = (ld_pause &
1549 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1550 pause_result |= (lp_pause &
1551 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1552
1553 bnx2x_pause_resolve(vars, pause_result);
1554 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
1555 pause_result);
1556 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001557 }
1558 return ret;
1559}
1560
1561
1562static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1563 struct link_vars *vars,
1564 u32 gp_status)
1565{
1566 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001567 u16 ld_pause; /* local driver */
1568 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001569 u16 pause_result;
1570
1571 vars->flow_ctrl = FLOW_CTRL_NONE;
1572
1573 /* resolve from gp_status in case of AN complete and not sgmii */
1574 if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) &&
1575 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1576 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1577 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1578 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
1579 CL45_RD_OVER_CL22(bp, params->port,
1580 params->phy_addr,
1581 MDIO_REG_BANK_COMBO_IEEE0,
1582 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1583 &ld_pause);
1584 CL45_RD_OVER_CL22(bp, params->port,
1585 params->phy_addr,
1586 MDIO_REG_BANK_COMBO_IEEE0,
1587 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1588 &lp_pause);
1589 pause_result = (ld_pause &
1590 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
1591 pause_result |= (lp_pause &
1592 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
1593 DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
1594 bnx2x_pause_resolve(vars, pause_result);
1595 } else if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) &&
1596 (bnx2x_ext_phy_resove_fc(params, vars))) {
1597 return;
1598 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001599 if (params->req_flow_ctrl == FLOW_CTRL_AUTO)
1600 vars->flow_ctrl = params->req_fc_auto_adv;
1601 else
1602 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001603 }
1604 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1605}
1606
1607
1608static u8 bnx2x_link_settings_status(struct link_params *params,
1609 struct link_vars *vars,
1610 u32 gp_status)
1611{
1612 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001613
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001614 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,
Eilon Greenstein3196a882008-08-13 15:58:49 -07003306 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003307{
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) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07003552 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003553
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;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003772 u32 tmp;
3773 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003774 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
3775 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
3776 speed, hw_led_mode);
3777 switch (mode) {
3778 case LED_MODE_OFF:
3779 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
3780 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
3781 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003782
3783 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003784 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003785 break;
3786
3787 case LED_MODE_OPER:
3788 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
3789 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
3790 port*4, 0);
3791 /* Set blinking rate to ~15.9Hz */
3792 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
3793 LED_BLINK_RATE_VAL);
3794 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
3795 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003796 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003797 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003798 (tmp & (~EMAC_LED_OVERRIDE)));
3799
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003800 if (!CHIP_IS_E1H(bp) &&
3801 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003802 (speed == SPEED_1000) ||
3803 (speed == SPEED_100) ||
3804 (speed == SPEED_10))) {
3805 /* On Everest 1 Ax chip versions for speeds less than
3806 10G LED scheme is different */
3807 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
3808 + port*4, 1);
3809 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
3810 port*4, 0);
3811 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
3812 port*4, 1);
3813 }
3814 break;
3815
3816 default:
3817 rc = -EINVAL;
3818 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
3819 mode);
3820 break;
3821 }
3822 return rc;
3823
3824}
3825
3826u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
3827{
3828 struct bnx2x *bp = params->bp;
3829 u16 gp_status = 0;
3830
3831 CL45_RD_OVER_CL22(bp, params->port,
3832 params->phy_addr,
3833 MDIO_REG_BANK_GP_STATUS,
3834 MDIO_GP_STATUS_TOP_AN_STATUS1,
3835 &gp_status);
3836 /* link is up only if both local phy and external phy are up */
3837 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
3838 bnx2x_ext_phy_is_link_up(params, vars))
3839 return 0;
3840
3841 return -ESRCH;
3842}
3843
3844static u8 bnx2x_link_initialize(struct link_params *params,
3845 struct link_vars *vars)
3846{
3847 struct bnx2x *bp = params->bp;
3848 u8 port = params->port;
3849 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003850 u8 non_ext_phy;
3851 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003852 /* Activate the external PHY */
3853 bnx2x_ext_phy_reset(params, vars);
3854
3855 bnx2x_set_aer_mmd(params, vars);
3856
3857 if (vars->phy_flags & PHY_XGXS_FLAG)
3858 bnx2x_set_master_ln(params);
3859
3860 rc = bnx2x_reset_unicore(params);
3861 /* reset the SerDes and wait for reset bit return low */
3862 if (rc != 0)
3863 return rc;
3864
3865 bnx2x_set_aer_mmd(params, vars);
3866
3867 /* setting the masterLn_def again after the reset */
3868 if (vars->phy_flags & PHY_XGXS_FLAG) {
3869 bnx2x_set_master_ln(params);
3870 bnx2x_set_swap_lanes(params);
3871 }
3872
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003873 if (vars->phy_flags & PHY_XGXS_FLAG) {
3874 if (params->req_line_speed &&
3875 ((params->req_line_speed == SPEED_100) ||
3876 (params->req_line_speed == SPEED_10))) {
3877 vars->phy_flags |= PHY_SGMII_FLAG;
3878 } else {
3879 vars->phy_flags &= ~PHY_SGMII_FLAG;
3880 }
3881 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003882 /* In case of external phy existance, the line speed would be the
3883 line speed linked up by the external phy. In case it is direct only,
3884 then the line_speed during initialization will be equal to the
3885 req_line_speed*/
3886 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003887
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003888 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003889
3890 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003891 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
3892 (params->loopback_mode == LOOPBACK_XGXS_10) ||
3893 (params->loopback_mode == LOOPBACK_EXT_PHY));
3894
3895 if (non_ext_phy ||
3896 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705)) {
3897 if (params->req_line_speed == SPEED_AUTO_NEG)
3898 bnx2x_set_parallel_detection(params, vars->phy_flags);
3899 bnx2x_init_internal_phy(params, vars);
3900 }
3901
3902 if (!non_ext_phy)
3903 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003904
3905 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003906 (NIG_STATUS_XGXS0_LINK10G |
3907 NIG_STATUS_XGXS0_LINK_STATUS |
3908 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003909
3910 return rc;
3911
3912}
3913
3914
3915u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
3916{
3917 struct bnx2x *bp = params->bp;
3918
3919 u32 val;
Eilon Greenstein3196a882008-08-13 15:58:49 -07003920 DP(NETIF_MSG_LINK, "Phy Initialization started \n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003921 DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
3922 params->req_line_speed, params->req_flow_ctrl);
3923 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003924 vars->phy_link_up = 0;
3925 vars->link_up = 0;
3926 vars->line_speed = 0;
3927 vars->duplex = DUPLEX_FULL;
3928 vars->flow_ctrl = FLOW_CTRL_NONE;
3929 vars->mac_type = MAC_TYPE_NONE;
3930
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003931 if (params->switch_cfg == SWITCH_CFG_1G)
3932 vars->phy_flags = PHY_SERDES_FLAG;
3933 else
3934 vars->phy_flags = PHY_XGXS_FLAG;
3935
Eilon Greenstein3196a882008-08-13 15:58:49 -07003936
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003937 /* disable attentions */
3938 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
3939 (NIG_MASK_XGXS0_LINK_STATUS |
3940 NIG_MASK_XGXS0_LINK10G |
3941 NIG_MASK_SERDES0_LINK_STATUS |
3942 NIG_MASK_MI_INT));
3943
3944 bnx2x_emac_init(params, vars);
3945
3946 if (CHIP_REV_IS_FPGA(bp)) {
3947 vars->link_up = 1;
3948 vars->line_speed = SPEED_10000;
3949 vars->duplex = DUPLEX_FULL;
3950 vars->flow_ctrl = FLOW_CTRL_NONE;
3951 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003952 /* enable on E1.5 FPGA */
3953 if (CHIP_IS_E1H(bp)) {
3954 vars->flow_ctrl |=
3955 (FLOW_CTRL_TX | FLOW_CTRL_RX);
3956 vars->link_status |=
3957 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
3958 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
3959 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003960
3961 bnx2x_emac_enable(params, vars, 0);
3962 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
3963 /* disable drain */
3964 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3965 + params->port*4, 0);
3966
3967 /* update shared memory */
3968 bnx2x_update_mng(params, vars->link_status);
3969
3970 return 0;
3971
3972 } else
3973 if (CHIP_REV_IS_EMUL(bp)) {
3974
3975 vars->link_up = 1;
3976 vars->line_speed = SPEED_10000;
3977 vars->duplex = DUPLEX_FULL;
3978 vars->flow_ctrl = FLOW_CTRL_NONE;
3979 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
3980
3981 bnx2x_bmac_enable(params, vars, 0);
3982
3983 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
3984 /* Disable drain */
3985 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3986 + params->port*4, 0);
3987
3988 /* update shared memory */
3989 bnx2x_update_mng(params, vars->link_status);
3990
3991 return 0;
3992
3993 } else
3994 if (params->loopback_mode == LOOPBACK_BMAC) {
3995 vars->link_up = 1;
3996 vars->line_speed = SPEED_10000;
3997 vars->duplex = DUPLEX_FULL;
3998 vars->flow_ctrl = FLOW_CTRL_NONE;
3999 vars->mac_type = MAC_TYPE_BMAC;
4000
4001 vars->phy_flags = PHY_XGXS_FLAG;
4002
4003 bnx2x_phy_deassert(params, vars->phy_flags);
4004 /* set bmac loopback */
4005 bnx2x_bmac_enable(params, vars, 1);
4006
4007 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4008 params->port*4, 0);
4009 } else if (params->loopback_mode == LOOPBACK_EMAC) {
4010 vars->link_up = 1;
4011 vars->line_speed = SPEED_1000;
4012 vars->duplex = DUPLEX_FULL;
4013 vars->flow_ctrl = FLOW_CTRL_NONE;
4014 vars->mac_type = MAC_TYPE_EMAC;
4015
4016 vars->phy_flags = PHY_XGXS_FLAG;
4017
4018 bnx2x_phy_deassert(params, vars->phy_flags);
4019 /* set bmac loopback */
4020 bnx2x_emac_enable(params, vars, 1);
4021 bnx2x_emac_program(params, vars->line_speed,
4022 vars->duplex);
4023 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4024 params->port*4, 0);
4025 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
4026 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
4027 vars->link_up = 1;
4028 vars->line_speed = SPEED_10000;
4029 vars->duplex = DUPLEX_FULL;
4030 vars->flow_ctrl = FLOW_CTRL_NONE;
4031
4032 vars->phy_flags = PHY_XGXS_FLAG;
4033
4034 val = REG_RD(bp,
4035 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4036 params->port*0x18);
4037 params->phy_addr = (u8)val;
4038
4039 bnx2x_phy_deassert(params, vars->phy_flags);
4040 bnx2x_link_initialize(params, vars);
4041
4042 vars->mac_type = MAC_TYPE_BMAC;
4043
4044 bnx2x_bmac_enable(params, vars, 0);
4045
4046 if (params->loopback_mode == LOOPBACK_XGXS_10) {
4047 /* set 10G XGXS loopback */
4048 bnx2x_set_xgxs_loopback(params, vars, 1);
4049 } else {
4050 /* set external phy loopback */
4051 bnx2x_ext_phy_loopback(params);
4052 }
4053 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4054 params->port*4, 0);
4055 } else
4056 /* No loopback */
4057 {
4058
4059 bnx2x_phy_deassert(params, vars->phy_flags);
4060 switch (params->switch_cfg) {
4061 case SWITCH_CFG_1G:
4062 vars->phy_flags |= PHY_SERDES_FLAG;
4063 if ((params->ext_phy_config &
4064 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
4065 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
4066 vars->phy_flags |=
4067 PHY_SGMII_FLAG;
4068 }
4069
4070 val = REG_RD(bp,
4071 NIG_REG_SERDES0_CTRL_PHY_ADDR+
4072 params->port*0x10);
4073
4074 params->phy_addr = (u8)val;
4075
4076 break;
4077 case SWITCH_CFG_10G:
4078 vars->phy_flags |= PHY_XGXS_FLAG;
4079 val = REG_RD(bp,
4080 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4081 params->port*0x18);
4082 params->phy_addr = (u8)val;
4083
4084 break;
4085 default:
4086 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
4087 return -EINVAL;
4088 break;
4089 }
4090
4091 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004092 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004093 bnx2x_link_int_enable(params);
4094 }
4095 return 0;
4096}
4097
4098u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars)
4099{
4100
4101 struct bnx2x *bp = params->bp;
4102 u32 ext_phy_config = params->ext_phy_config;
4103 u16 hw_led_mode = params->hw_led_mode;
4104 u32 chip_id = params->chip_id;
4105 u8 port = params->port;
4106 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4107 /* disable attentions */
4108
4109 vars->link_status = 0;
4110 bnx2x_update_mng(params, vars->link_status);
4111 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4112 (NIG_MASK_XGXS0_LINK_STATUS |
4113 NIG_MASK_XGXS0_LINK10G |
4114 NIG_MASK_SERDES0_LINK_STATUS |
4115 NIG_MASK_MI_INT));
4116
4117 /* activate nig drain */
4118 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4119
4120 /* disable nig egress interface */
4121 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4122 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4123
4124 /* Stop BigMac rx */
4125 bnx2x_bmac_rx_disable(bp, port);
4126
4127 /* disable emac */
4128 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4129
4130 msleep(10);
4131 /* The PHY reset is controled by GPIO 1
4132 * Hold it as vars low
4133 */
4134 /* clear link led */
4135 bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
4136 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
4137 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
4138 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
4139 /* HW reset */
4140
4141 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004142 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4143 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004144
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 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004150 } else if (ext_phy_type ==
4151 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
4152 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004153 "low power mode\n",
4154 port);
4155 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004156 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4157 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004158 }
4159 }
4160 /* reset the SerDes/XGXS */
4161 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
4162 (0x1ff << (port*16)));
4163
4164 /* reset BigMac */
4165 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
4166 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4167
4168 /* disable nig ingress interface */
4169 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
4170 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
4171 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4172 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4173 vars->link_up = 0;
4174 return 0;
4175}
4176
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004177static u8 bnx2x_update_link_down(struct link_params *params,
4178 struct link_vars *vars)
4179{
4180 struct bnx2x *bp = params->bp;
4181 u8 port = params->port;
4182 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
4183 bnx2x_set_led(bp, port, LED_MODE_OFF,
4184 0, params->hw_led_mode,
4185 params->chip_id);
4186
4187 /* indicate no mac active */
4188 vars->mac_type = MAC_TYPE_NONE;
4189
4190 /* update shared memory */
4191 vars->link_status = 0;
4192 vars->line_speed = 0;
4193 bnx2x_update_mng(params, vars->link_status);
4194
4195 /* activate nig drain */
4196 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4197
4198 /* reset BigMac */
4199 bnx2x_bmac_rx_disable(bp, params->port);
4200 REG_WR(bp, GRCBASE_MISC +
4201 MISC_REGISTERS_RESET_REG_2_CLEAR,
4202 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4203 return 0;
4204}
4205
4206static u8 bnx2x_update_link_up(struct link_params *params,
4207 struct link_vars *vars,
4208 u8 link_10g, u32 gp_status)
4209{
4210 struct bnx2x *bp = params->bp;
4211 u8 port = params->port;
4212 u8 rc = 0;
4213 vars->link_status |= LINK_STATUS_LINK_UP;
4214 if (link_10g) {
4215 bnx2x_bmac_enable(params, vars, 0);
4216 bnx2x_set_led(bp, port, LED_MODE_OPER,
4217 SPEED_10000, params->hw_led_mode,
4218 params->chip_id);
4219
4220 } else {
4221 bnx2x_emac_enable(params, vars, 0);
4222 rc = bnx2x_emac_program(params, vars->line_speed,
4223 vars->duplex);
4224
4225 /* AN complete? */
4226 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
4227 if (!(vars->phy_flags &
4228 PHY_SGMII_FLAG))
4229 bnx2x_set_sgmii_tx_driver(params);
4230 }
4231 }
4232
4233 /* PBF - link up */
4234 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
4235 vars->line_speed);
4236
4237 /* disable drain */
4238 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
4239
4240 /* update shared memory */
4241 bnx2x_update_mng(params, vars->link_status);
4242 return rc;
4243}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004244/* This function should called upon link interrupt */
4245/* In case vars->link_up, driver needs to
4246 1. Update the pbf
4247 2. Disable drain
4248 3. Update the shared memory
4249 4. Indicate link up
4250 5. Set LEDs
4251 Otherwise,
4252 1. Update shared memory
4253 2. Reset BigMac
4254 3. Report link down
4255 4. Unset LEDs
4256*/
4257u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
4258{
4259 struct bnx2x *bp = params->bp;
4260 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004261 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004262 u8 link_10g;
4263 u8 ext_phy_link_up, rc = 0;
4264 u32 ext_phy_type;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004265
4266 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
4267 port,
4268 (vars->phy_flags & PHY_XGXS_FLAG),
4269 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
4270
4271 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
4272 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4273 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4274 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
4275
4276 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4277 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4278 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4279
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004280 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004281
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004282 /* Check external link change only for non-direct */
4283 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
4284
4285 /* Read gp_status */
4286 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
4287 MDIO_REG_BANK_GP_STATUS,
4288 MDIO_GP_STATUS_TOP_AN_STATUS1,
4289 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004290
4291 rc = bnx2x_link_settings_status(params, vars, gp_status);
4292 if (rc != 0)
4293 return rc;
4294
4295 /* anything 10 and over uses the bmac */
4296 link_10g = ((vars->line_speed == SPEED_10000) ||
4297 (vars->line_speed == SPEED_12000) ||
4298 (vars->line_speed == SPEED_12500) ||
4299 (vars->line_speed == SPEED_13000) ||
4300 (vars->line_speed == SPEED_15000) ||
4301 (vars->line_speed == SPEED_16000));
4302
4303 bnx2x_link_int_ack(params, vars, link_10g);
4304
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004305 /* In case external phy link is up, and internal link is down
4306 ( not initialized yet probably after link initialization, it needs
4307 to be initialized.
4308 Note that after link down-up as result of cable plug,
4309 the xgxs link would probably become up again without the need to
4310 initialize it*/
4311
4312 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
4313 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
4314 (ext_phy_link_up && !vars->phy_link_up))
4315 bnx2x_init_internal_phy(params, vars);
4316
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004317 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004318 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004319
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004320 if (vars->link_up)
4321 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
4322 else
4323 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004324
4325 return rc;
4326}
4327
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004328static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
4329{
4330 u8 ext_phy_addr[PORT_MAX];
4331 u16 val;
4332 s8 port;
4333
4334 /* PART1 - Reset both phys */
4335 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4336 /* Extract the ext phy address for the port */
4337 u32 ext_phy_config = REG_RD(bp, shmem_base +
4338 offsetof(struct shmem_region,
4339 dev_info.port_hw_config[port].external_phy_config));
4340
4341 /* disable attentions */
4342 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4343 (NIG_MASK_XGXS0_LINK_STATUS |
4344 NIG_MASK_XGXS0_LINK10G |
4345 NIG_MASK_SERDES0_LINK_STATUS |
4346 NIG_MASK_MI_INT));
4347
4348 ext_phy_addr[port] =
4349 ((ext_phy_config &
4350 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4351 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4352
4353 /* Need to take the phy out of low power mode in order
4354 to write to access its registers */
4355 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4356 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
4357
4358 /* Reset the phy */
4359 bnx2x_cl45_write(bp, port,
4360 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4361 ext_phy_addr[port],
4362 MDIO_PMA_DEVAD,
4363 MDIO_PMA_REG_CTRL,
4364 1<<15);
4365 }
4366
4367 /* Add delay of 150ms after reset */
4368 msleep(150);
4369
4370 /* PART2 - Download firmware to both phys */
4371 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4372 u16 fw_ver1;
4373
4374 bnx2x_bcm8073_external_rom_boot(bp, port,
4375 ext_phy_addr[port]);
4376
4377 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4378 ext_phy_addr[port],
4379 MDIO_PMA_DEVAD,
4380 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
4381 if (fw_ver1 == 0) {
4382 DP(NETIF_MSG_LINK,
4383 "bnx2x_8073_common_init_phy port %x "
4384 "fw Download failed\n", port);
4385 return -EINVAL;
4386 }
4387
4388 /* Only set bit 10 = 1 (Tx power down) */
4389 bnx2x_cl45_read(bp, port,
4390 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4391 ext_phy_addr[port],
4392 MDIO_PMA_DEVAD,
4393 MDIO_PMA_REG_TX_POWER_DOWN, &val);
4394
4395 /* Phase1 of TX_POWER_DOWN reset */
4396 bnx2x_cl45_write(bp, port,
4397 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4398 ext_phy_addr[port],
4399 MDIO_PMA_DEVAD,
4400 MDIO_PMA_REG_TX_POWER_DOWN,
4401 (val | 1<<10));
4402 }
4403
4404 /* Toggle Transmitter: Power down and then up with 600ms
4405 delay between */
4406 msleep(600);
4407
4408 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
4409 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4410 /* Phase2 of POWER_DOWN_RESET*/
4411 /* Release bit 10 (Release Tx power down) */
4412 bnx2x_cl45_read(bp, port,
4413 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4414 ext_phy_addr[port],
4415 MDIO_PMA_DEVAD,
4416 MDIO_PMA_REG_TX_POWER_DOWN, &val);
4417
4418 bnx2x_cl45_write(bp, port,
4419 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4420 ext_phy_addr[port],
4421 MDIO_PMA_DEVAD,
4422 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
4423 msleep(15);
4424
4425 /* Read modify write the SPI-ROM version select register */
4426 bnx2x_cl45_read(bp, port,
4427 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4428 ext_phy_addr[port],
4429 MDIO_PMA_DEVAD,
4430 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
4431 bnx2x_cl45_write(bp, port,
4432 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4433 ext_phy_addr[port],
4434 MDIO_PMA_DEVAD,
4435 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
4436
4437 /* set GPIO2 back to LOW */
4438 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4439 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
4440 }
4441 return 0;
4442
4443}
4444
4445u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
4446{
4447 u8 rc = 0;
4448 u32 ext_phy_type;
4449
4450 DP(NETIF_MSG_LINK, "bnx2x_common_init_phy\n");
4451
4452 /* Read the ext_phy_type for arbitrary port(0) */
4453 ext_phy_type = XGXS_EXT_PHY_TYPE(
4454 REG_RD(bp, shmem_base +
4455 offsetof(struct shmem_region,
4456 dev_info.port_hw_config[0].external_phy_config)));
4457
4458 switch (ext_phy_type) {
4459 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4460 {
4461 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
4462 break;
4463 }
4464 default:
4465 DP(NETIF_MSG_LINK,
4466 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
4467 ext_phy_type);
4468 break;
4469 }
4470
4471 return rc;
4472}
4473
4474
4475
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004476static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
4477{
4478 u16 val, cnt;
4479
4480 bnx2x_cl45_read(bp, port,
4481 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4482 phy_addr,
4483 MDIO_PMA_DEVAD,
4484 MDIO_PMA_REG_7101_RESET, &val);
4485
4486 for (cnt = 0; cnt < 10; cnt++) {
4487 msleep(50);
4488 /* Writes a self-clearing reset */
4489 bnx2x_cl45_write(bp, port,
4490 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4491 phy_addr,
4492 MDIO_PMA_DEVAD,
4493 MDIO_PMA_REG_7101_RESET,
4494 (val | (1<<15)));
4495 /* Wait for clear */
4496 bnx2x_cl45_read(bp, port,
4497 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4498 phy_addr,
4499 MDIO_PMA_DEVAD,
4500 MDIO_PMA_REG_7101_RESET, &val);
4501
4502 if ((val & (1<<15)) == 0)
4503 break;
4504 }
4505}
4506#define RESERVED_SIZE 256
4507/* max application is 160K bytes - data at end of RAM */
Eilon Greenstein6378c022008-08-13 15:59:25 -07004508#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004509
4510/* Header is 14 bytes */
4511#define HEADER_SIZE 14
4512#define DATA_OFFSET HEADER_SIZE
4513
4514#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \
4515 bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \
4516 ext_phy_addr, \
4517 MDIO_PCS_DEVAD, \
4518 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1)
4519
4520/* Programs an image to DSP's flash via the SPI port*/
4521static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port,
4522 u8 ext_phy_addr,
4523 char data[], u32 size)
4524{
4525 const u16 num_trans = size/4; /* 4 bytes can be sent at a time */
4526 /* Doesn't include last trans!*/
4527 const u16 last_trans_size = size%4; /* Num bytes on last trans */
4528 u16 trans_cnt, byte_cnt;
4529 u32 data_index;
4530 u16 tmp;
4531 u16 code_started = 0;
4532 u16 image_revision1, image_revision2;
4533 u16 cnt;
4534
4535 DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size);
4536 /* Going to flash*/
4537 if ((size-HEADER_SIZE) > MAX_APP_SIZE) {
4538 /* This very often will be the case, because the image is built
4539 with 160Kbytes size whereas the total image size must actually
4540 be 160Kbytes-RESERVED_SIZE */
4541 DP(NETIF_MSG_LINK, "Warning, file size was %d bytes "
4542 "truncated to %d bytes\n", size, MAX_APP_SIZE);
4543 size = MAX_APP_SIZE+HEADER_SIZE;
4544 }
4545 DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004546 DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004547 /* Put the DSP in download mode by setting FLASH_CFG[2] to 1
4548 and issuing a reset.*/
4549
4550 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004551 MISC_REGISTERS_GPIO_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004552
4553 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
4554
4555 /* wait 0.5 sec */
4556 for (cnt = 0; cnt < 100; cnt++)
4557 msleep(5);
4558
4559 /* Make sure we can access the DSP
4560 And it's in the correct mode (waiting for download) */
4561
4562 bnx2x_cl45_read(bp, port,
4563 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4564 ext_phy_addr,
4565 MDIO_PCS_DEVAD,
4566 MDIO_PCS_REG_7101_DSP_ACCESS, &tmp);
4567
4568 if (tmp != 0x000A) {
4569 DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. "
4570 "Expected 0x000A, read 0x%04X\n", tmp);
4571 DP(NETIF_MSG_LINK, "Download failed\n");
4572 return -EINVAL;
4573 }
4574
4575 /* Mux the SPI interface away from the internal processor */
4576 bnx2x_cl45_write(bp, port,
4577 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4578 ext_phy_addr,
4579 MDIO_PCS_DEVAD,
4580 MDIO_PCS_REG_7101_SPI_MUX, 1);
4581
4582 /* Reset the SPI port */
4583 bnx2x_cl45_write(bp, port,
4584 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4585 ext_phy_addr,
4586 MDIO_PCS_DEVAD,
4587 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
4588 bnx2x_cl45_write(bp, port,
4589 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4590 ext_phy_addr,
4591 MDIO_PCS_DEVAD,
4592 MDIO_PCS_REG_7101_SPI_CTRL_ADDR,
4593 (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT));
4594 bnx2x_cl45_write(bp, port,
4595 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4596 ext_phy_addr,
4597 MDIO_PCS_DEVAD,
4598 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
4599
4600 /* Erase the flash */
4601 bnx2x_cl45_write(bp, port,
4602 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4603 ext_phy_addr,
4604 MDIO_PCS_DEVAD,
4605 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4606 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4607
4608 bnx2x_cl45_write(bp, port,
4609 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4610 ext_phy_addr,
4611 MDIO_PCS_DEVAD,
4612 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4613 1);
4614
4615 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4616 bnx2x_cl45_write(bp, port,
4617 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4618 ext_phy_addr,
4619 MDIO_PCS_DEVAD,
4620 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4621 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD);
4622
4623 bnx2x_cl45_write(bp, port,
4624 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4625 ext_phy_addr,
4626 MDIO_PCS_DEVAD,
4627 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4628 1);
4629 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4630
4631 /* Wait 10 seconds, the maximum time for the erase to complete */
4632 DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n");
4633 for (cnt = 0; cnt < 1000; cnt++)
4634 msleep(10);
4635
4636 DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n");
4637 data_index = 0;
4638 for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) {
4639 bnx2x_cl45_write(bp, port,
4640 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4641 ext_phy_addr,
4642 MDIO_PCS_DEVAD,
4643 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4644 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4645
4646 bnx2x_cl45_write(bp, port,
4647 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4648 ext_phy_addr,
4649 MDIO_PCS_DEVAD,
4650 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4651 1);
4652 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4653
4654 bnx2x_cl45_write(bp, port,
4655 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4656 ext_phy_addr,
4657 MDIO_PCS_DEVAD,
4658 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4659 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
4660
4661 /* Bits 23-16 of address */
4662 bnx2x_cl45_write(bp, port,
4663 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4664 ext_phy_addr,
4665 MDIO_PCS_DEVAD,
4666 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4667 (data_index>>16));
4668 /* Bits 15-8 of address */
4669 bnx2x_cl45_write(bp, port,
4670 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4671 ext_phy_addr,
4672 MDIO_PCS_DEVAD,
4673 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4674 (data_index>>8));
4675
4676 /* Bits 7-0 of address */
4677 bnx2x_cl45_write(bp, port,
4678 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4679 ext_phy_addr,
4680 MDIO_PCS_DEVAD,
4681 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4682 ((u16)data_index));
4683
4684 byte_cnt = 0;
4685 while (byte_cnt < 4 && data_index < size) {
4686 bnx2x_cl45_write(bp, port,
4687 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4688 ext_phy_addr,
4689 MDIO_PCS_DEVAD,
4690 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4691 data[data_index++]);
4692 byte_cnt++;
4693 }
4694
4695 bnx2x_cl45_write(bp, port,
4696 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4697 ext_phy_addr,
4698 MDIO_PCS_DEVAD,
4699 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4700 byte_cnt+4);
4701
4702 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4703 msleep(5); /* Wait 5 ms minimum between transs */
4704
4705 /* Let the user know something's going on.*/
4706 /* a pacifier ever 4K */
4707 if ((data_index % 1023) == 0)
4708 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
4709 }
4710
4711 DP(NETIF_MSG_LINK, "\n");
4712 /* Transfer the last block if there is data remaining */
4713 if (last_trans_size) {
4714 bnx2x_cl45_write(bp, port,
4715 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4716 ext_phy_addr,
4717 MDIO_PCS_DEVAD,
4718 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4719 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4720
4721 bnx2x_cl45_write(bp, port,
4722 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4723 ext_phy_addr,
4724 MDIO_PCS_DEVAD,
4725 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4726 1);
4727
4728 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4729
4730 bnx2x_cl45_write(bp, port,
4731 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4732 ext_phy_addr,
4733 MDIO_PCS_DEVAD,
4734 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4735 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
4736
4737 /* Bits 23-16 of address */
4738 bnx2x_cl45_write(bp, port,
4739 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4740 ext_phy_addr,
4741 MDIO_PCS_DEVAD,
4742 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4743 (data_index>>16));
4744 /* Bits 15-8 of address */
4745 bnx2x_cl45_write(bp, port,
4746 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4747 ext_phy_addr,
4748 MDIO_PCS_DEVAD,
4749 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4750 (data_index>>8));
4751
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 ((u16)data_index));
4759
4760 byte_cnt = 0;
4761 while (byte_cnt < last_trans_size && data_index < size) {
4762 /* Bits 7-0 of address */
4763 bnx2x_cl45_write(bp, port,
4764 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4765 ext_phy_addr,
4766 MDIO_PCS_DEVAD,
4767 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4768 data[data_index++]);
4769 byte_cnt++;
4770 }
4771
4772 bnx2x_cl45_write(bp, port,
4773 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4774 ext_phy_addr,
4775 MDIO_PCS_DEVAD,
4776 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4777 byte_cnt+4);
4778
4779 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4780 }
4781
4782 /* DSP Remove Download Mode */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004783 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4784 MISC_REGISTERS_GPIO_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004785
4786 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
4787
4788 /* wait 0.5 sec to allow it to run */
4789 for (cnt = 0; cnt < 100; cnt++)
4790 msleep(5);
4791
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004792 bnx2x_hw_reset(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004793
4794 for (cnt = 0; cnt < 100; cnt++)
4795 msleep(5);
4796
4797 /* Check that the code is started. In case the download
4798 checksum failed, the code won't be started. */
4799 bnx2x_cl45_read(bp, port,
4800 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4801 ext_phy_addr,
4802 MDIO_PCS_DEVAD,
4803 MDIO_PCS_REG_7101_DSP_ACCESS,
4804 &tmp);
4805
4806 code_started = (tmp & (1<<4));
4807 if (!code_started) {
4808 DP(NETIF_MSG_LINK, "Download failed. Please check file.\n");
4809 return -EINVAL;
4810 }
4811
4812 /* Verify that the file revision is now equal to the image
4813 revision within the DSP */
4814 bnx2x_cl45_read(bp, port,
4815 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4816 ext_phy_addr,
4817 MDIO_PMA_DEVAD,
4818 MDIO_PMA_REG_7101_VER1,
4819 &image_revision1);
4820
4821 bnx2x_cl45_read(bp, port,
4822 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4823 ext_phy_addr,
4824 MDIO_PMA_DEVAD,
4825 MDIO_PMA_REG_7101_VER2,
4826 &image_revision2);
4827
Eilon Greenstein3196a882008-08-13 15:58:49 -07004828 if (data[0x14e] != (image_revision2&0xFF) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004829 data[0x14f] != ((image_revision2&0xFF00)>>8) ||
4830 data[0x150] != (image_revision1&0xFF) ||
4831 data[0x151] != ((image_revision1&0xFF00)>>8)) {
4832 DP(NETIF_MSG_LINK, "Download failed.\n");
4833 return -EINVAL;
4834 }
4835 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
4836 return 0;
4837}
4838
4839u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
4840 u8 driver_loaded, char data[], u32 size)
4841{
4842 u8 rc = 0;
4843 u32 ext_phy_type;
4844 u8 ext_phy_addr;
4845 ext_phy_addr = ((ext_phy_config &
4846 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4847 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4848
4849 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4850
4851 switch (ext_phy_type) {
4852 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4853 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4854 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4855 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
4856 DP(NETIF_MSG_LINK,
4857 "Flash download not supported for this ext phy\n");
4858 rc = -EINVAL;
4859 break;
4860 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4861 /* Take ext phy out of reset */
4862 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004863 bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004864 rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
4865 data, size);
4866 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004867 bnx2x_turn_off_sf(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004868 break;
4869 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4870 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4871 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
4872 default:
4873 DP(NETIF_MSG_LINK, "Invalid ext phy type\n");
4874 rc = -EINVAL;
4875 break;
4876 }
4877 return rc;
4878}
4879