blob: aea26b4dc45327bd7bcdd3bb0e347fc34e688cfd [file] [log] [blame]
Eilon Greensteind05c26c2009-01-17 23:26:13 -08001/* Copyright 2008-2009 Broadcom Corporation
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002 *
3 * Unless you and Broadcom execute a separate written software license
4 * agreement governing use of this software, this software is licensed to you
5 * under the terms of the GNU General Public License version 2, available
6 * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
7 *
8 * Notwithstanding the above, under no circumstances may you combine this
9 * software in any way with any other Broadcom software provided under a
10 * license other than the GPL, without Broadcom's express prior written
11 * consent.
12 *
13 * Written by Yaniv Rosner
14 *
15 */
16
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/pci.h>
20#include <linux/netdevice.h>
21#include <linux/delay.h>
22#include <linux/ethtool.h>
23#include <linux/mutex.h>
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070024
25#include "bnx2x_reg.h"
26#include "bnx2x_fw_defs.h"
27#include "bnx2x_hsi.h"
28#include "bnx2x_link.h"
29#include "bnx2x.h"
30
31/********************************************************/
32#define SUPPORT_CL73 0 /* Currently no */
Eilon Greenstein3196a882008-08-13 15:58:49 -070033#define ETH_HLEN 14
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070034#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
35#define ETH_MIN_PACKET_SIZE 60
36#define ETH_MAX_PACKET_SIZE 1500
37#define ETH_MAX_JUMBO_PACKET_SIZE 9600
38#define MDIO_ACCESS_TIMEOUT 1000
39#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070040
41/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070042/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070043/***********************************************************/
44
45#define NIG_STATUS_XGXS0_LINK10G \
46 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
47#define NIG_STATUS_XGXS0_LINK_STATUS \
48 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
49#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
50 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
51#define NIG_STATUS_SERDES0_LINK_STATUS \
52 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
53#define NIG_MASK_MI_INT \
54 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
55#define NIG_MASK_XGXS0_LINK10G \
56 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
57#define NIG_MASK_XGXS0_LINK_STATUS \
58 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
59#define NIG_MASK_SERDES0_LINK_STATUS \
60 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
61
62#define MDIO_AN_CL73_OR_37_COMPLETE \
63 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
64 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
65
66#define XGXS_RESET_BITS \
67 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
68 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
71 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
72
73#define SERDES_RESET_BITS \
74 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
75 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
77 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
78
79#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
80#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Eilon Greenstein3196a882008-08-13 15:58:49 -070081#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
82#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070083 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070084#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070085 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070086#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070087
88#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
89 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
90#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
91 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
92#define GP_STATUS_SPEED_MASK \
93 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
94#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
95#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
96#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
97#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
98#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
99#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
100#define GP_STATUS_10G_HIG \
101 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
102#define GP_STATUS_10G_CX4 \
103 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
104#define GP_STATUS_12G_HIG \
105 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
106#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
107#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
108#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
109#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
110#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
111#define GP_STATUS_10G_KX4 \
112 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
113
114#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
115#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
116#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
117#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
118#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
119#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
120#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
121#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
122#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
123#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
124#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
125#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
126#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
127#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
128#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
129#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
130#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
131#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
132#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
133#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
134#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
135#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
136#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
137
138#define PHY_XGXS_FLAG 0x1
139#define PHY_SGMII_FLAG 0x2
140#define PHY_SERDES_FLAG 0x4
141
142/**********************************************************/
143/* INTERFACE */
144/**********************************************************/
145#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
146 bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
147 DEFAULT_PHY_DEV_ADDR, \
148 (_bank + (_addr & 0xf)), \
149 _val)
150
151#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
152 bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
153 DEFAULT_PHY_DEV_ADDR, \
154 (_bank + (_addr & 0xf)), \
155 _val)
156
157static void bnx2x_set_phy_mdio(struct link_params *params)
158{
159 struct bnx2x *bp = params->bp;
160 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
161 params->port*0x18, 0);
162 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
163 DEFAULT_PHY_DEV_ADDR);
164}
165
166static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
167{
168 u32 val = REG_RD(bp, reg);
169
170 val |= bits;
171 REG_WR(bp, reg, val);
172 return val;
173}
174
175static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
176{
177 u32 val = REG_RD(bp, reg);
178
179 val &= ~bits;
180 REG_WR(bp, reg, val);
181 return val;
182}
183
184static void bnx2x_emac_init(struct link_params *params,
185 struct link_vars *vars)
186{
187 /* reset and unreset the emac core */
188 struct bnx2x *bp = params->bp;
189 u8 port = params->port;
190 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
191 u32 val;
192 u16 timeout;
193
194 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
195 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
196 udelay(5);
197 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
198 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
199
200 /* init emac - use read-modify-write */
201 /* self clear reset */
202 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700203 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700204
205 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700206 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700207 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
208 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
209 if (!timeout) {
210 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
211 return;
212 }
213 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700214 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700215
216 /* Set mac address */
217 val = ((params->mac_addr[0] << 8) |
218 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700219 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700220
221 val = ((params->mac_addr[2] << 24) |
222 (params->mac_addr[3] << 16) |
223 (params->mac_addr[4] << 8) |
224 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700225 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700226}
227
228static u8 bnx2x_emac_enable(struct link_params *params,
229 struct link_vars *vars, u8 lb)
230{
231 struct bnx2x *bp = params->bp;
232 u8 port = params->port;
233 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
234 u32 val;
235
236 DP(NETIF_MSG_LINK, "enabling EMAC\n");
237
238 /* enable emac and not bmac */
239 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
240
241 /* for paladium */
242 if (CHIP_REV_IS_EMUL(bp)) {
243 /* Use lane 1 (of lanes 0-3) */
244 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
245 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
246 port*4, 1);
247 }
248 /* for fpga */
249 else
250
251 if (CHIP_REV_IS_FPGA(bp)) {
252 /* Use lane 1 (of lanes 0-3) */
253 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
254
255 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
256 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
257 0);
258 } else
259 /* ASIC */
260 if (vars->phy_flags & PHY_XGXS_FLAG) {
261 u32 ser_lane = ((params->lane_config &
262 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
263 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
264
265 DP(NETIF_MSG_LINK, "XGXS\n");
266 /* select the master lanes (out of 0-3) */
267 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
268 port*4, ser_lane);
269 /* select XGXS */
270 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
271 port*4, 1);
272
273 } else { /* SerDes */
274 DP(NETIF_MSG_LINK, "SerDes\n");
275 /* select SerDes */
276 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
277 port*4, 0);
278 }
279
280 /* enable emac */
281 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
282
283 if (CHIP_REV_IS_SLOW(bp)) {
284 /* config GMII mode */
285 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700286 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700287 (val | EMAC_MODE_PORT_GMII));
288 } else { /* ASIC */
289 /* pause enable/disable */
290 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
291 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800292 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700293 bnx2x_bits_en(bp, emac_base +
294 EMAC_REG_EMAC_RX_MODE,
295 EMAC_RX_MODE_FLOW_EN);
296
297 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700298 (EMAC_TX_MODE_EXT_PAUSE_EN |
299 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800300 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700301 bnx2x_bits_en(bp, emac_base +
302 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700303 (EMAC_TX_MODE_EXT_PAUSE_EN |
304 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700305 }
306
307 /* KEEP_VLAN_TAG, promiscuous */
308 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
309 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700310 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700311
312 /* Set Loopback */
313 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
314 if (lb)
315 val |= 0x810;
316 else
317 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700318 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700319
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000320 /* enable emac */
321 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
322
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700323 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700324 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700325 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
326 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
327
328 /* strip CRC */
329 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
330
331 /* disable the NIG in/out to the bmac */
332 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
333 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
334 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
335
336 /* enable the NIG in/out to the emac */
337 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
338 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800339 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700340 val = 1;
341
342 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
343 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
344
345 if (CHIP_REV_IS_EMUL(bp)) {
346 /* take the BigMac out of reset */
347 REG_WR(bp,
348 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
349 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
350
351 /* enable access for bmac registers */
352 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
353 }
354
355 vars->mac_type = MAC_TYPE_EMAC;
356 return 0;
357}
358
359
360
361static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
362 u8 is_lb)
363{
364 struct bnx2x *bp = params->bp;
365 u8 port = params->port;
366 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
367 NIG_REG_INGRESS_BMAC0_MEM;
368 u32 wb_data[2];
369 u32 val;
370
371 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
372 /* reset and unreset the BigMac */
373 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
374 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
375 msleep(1);
376
377 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
378 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
379
380 /* enable access for bmac registers */
381 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
382
383 /* XGXS control */
384 wb_data[0] = 0x3c;
385 wb_data[1] = 0;
386 REG_WR_DMAE(bp, bmac_addr +
387 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
388 wb_data, 2);
389
390 /* tx MAC SA */
391 wb_data[0] = ((params->mac_addr[2] << 24) |
392 (params->mac_addr[3] << 16) |
393 (params->mac_addr[4] << 8) |
394 params->mac_addr[5]);
395 wb_data[1] = ((params->mac_addr[0] << 8) |
396 params->mac_addr[1]);
397 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
398 wb_data, 2);
399
400 /* tx control */
401 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800402 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700403 val |= 0x800000;
404 wb_data[0] = val;
405 wb_data[1] = 0;
406 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
407 wb_data, 2);
408
409 /* mac control */
410 val = 0x3;
411 if (is_lb) {
412 val |= 0x4;
413 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
414 }
415 wb_data[0] = val;
416 wb_data[1] = 0;
417 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
418 wb_data, 2);
419
420
421 /* set rx mtu */
422 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
423 wb_data[1] = 0;
424 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
425 wb_data, 2);
426
427 /* rx control set to don't strip crc */
428 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800429 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700430 val |= 0x20;
431 wb_data[0] = val;
432 wb_data[1] = 0;
433 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
434 wb_data, 2);
435
436 /* set tx mtu */
437 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
438 wb_data[1] = 0;
439 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
440 wb_data, 2);
441
442 /* set cnt max size */
443 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
444 wb_data[1] = 0;
445 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
446 wb_data, 2);
447
448 /* configure safc */
449 wb_data[0] = 0x1000200;
450 wb_data[1] = 0;
451 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
452 wb_data, 2);
453 /* fix for emulation */
454 if (CHIP_REV_IS_EMUL(bp)) {
455 wb_data[0] = 0xf000;
456 wb_data[1] = 0;
457 REG_WR_DMAE(bp,
458 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
459 wb_data, 2);
460 }
461
462 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
463 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
464 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
465 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800466 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700467 val = 1;
468 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
469 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
470 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
471 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
472 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
473 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
474
475 vars->mac_type = MAC_TYPE_BMAC;
476 return 0;
477}
478
479static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
480{
481 struct bnx2x *bp = params->bp;
482 u32 val;
483
484 if (phy_flags & PHY_XGXS_FLAG) {
485 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
486 val = XGXS_RESET_BITS;
487
488 } else { /* SerDes */
489 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
490 val = SERDES_RESET_BITS;
491 }
492
493 val = val << (params->port*16);
494
495 /* reset and unreset the SerDes/XGXS */
496 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
497 val);
498 udelay(500);
499 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
500 val);
501 bnx2x_set_phy_mdio(params);
502}
503
504void bnx2x_link_status_update(struct link_params *params,
505 struct link_vars *vars)
506{
507 struct bnx2x *bp = params->bp;
508 u8 link_10g;
509 u8 port = params->port;
510
511 if (params->switch_cfg == SWITCH_CFG_1G)
512 vars->phy_flags = PHY_SERDES_FLAG;
513 else
514 vars->phy_flags = PHY_XGXS_FLAG;
515 vars->link_status = REG_RD(bp, params->shmem_base +
516 offsetof(struct shmem_region,
517 port_mb[port].link_status));
518
519 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
520
521 if (vars->link_up) {
522 DP(NETIF_MSG_LINK, "phy link up\n");
523
524 vars->phy_link_up = 1;
525 vars->duplex = DUPLEX_FULL;
526 switch (vars->link_status &
527 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
528 case LINK_10THD:
529 vars->duplex = DUPLEX_HALF;
530 /* fall thru */
531 case LINK_10TFD:
532 vars->line_speed = SPEED_10;
533 break;
534
535 case LINK_100TXHD:
536 vars->duplex = DUPLEX_HALF;
537 /* fall thru */
538 case LINK_100T4:
539 case LINK_100TXFD:
540 vars->line_speed = SPEED_100;
541 break;
542
543 case LINK_1000THD:
544 vars->duplex = DUPLEX_HALF;
545 /* fall thru */
546 case LINK_1000TFD:
547 vars->line_speed = SPEED_1000;
548 break;
549
550 case LINK_2500THD:
551 vars->duplex = DUPLEX_HALF;
552 /* fall thru */
553 case LINK_2500TFD:
554 vars->line_speed = SPEED_2500;
555 break;
556
557 case LINK_10GTFD:
558 vars->line_speed = SPEED_10000;
559 break;
560
561 case LINK_12GTFD:
562 vars->line_speed = SPEED_12000;
563 break;
564
565 case LINK_12_5GTFD:
566 vars->line_speed = SPEED_12500;
567 break;
568
569 case LINK_13GTFD:
570 vars->line_speed = SPEED_13000;
571 break;
572
573 case LINK_15GTFD:
574 vars->line_speed = SPEED_15000;
575 break;
576
577 case LINK_16GTFD:
578 vars->line_speed = SPEED_16000;
579 break;
580
581 default:
582 break;
583 }
584
585 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800586 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700587 else
David S. Millerc0700f92008-12-16 23:53:20 -0800588 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700589
590 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800591 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700592 else
David S. Millerc0700f92008-12-16 23:53:20 -0800593 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700594
595 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700596 if (vars->line_speed &&
597 ((vars->line_speed == SPEED_10) ||
598 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700599 vars->phy_flags |= PHY_SGMII_FLAG;
600 } else {
601 vars->phy_flags &= ~PHY_SGMII_FLAG;
602 }
603 }
604
605 /* anything 10 and over uses the bmac */
606 link_10g = ((vars->line_speed == SPEED_10000) ||
607 (vars->line_speed == SPEED_12000) ||
608 (vars->line_speed == SPEED_12500) ||
609 (vars->line_speed == SPEED_13000) ||
610 (vars->line_speed == SPEED_15000) ||
611 (vars->line_speed == SPEED_16000));
612 if (link_10g)
613 vars->mac_type = MAC_TYPE_BMAC;
614 else
615 vars->mac_type = MAC_TYPE_EMAC;
616
617 } else { /* link down */
618 DP(NETIF_MSG_LINK, "phy link down\n");
619
620 vars->phy_link_up = 0;
621
622 vars->line_speed = 0;
623 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -0800624 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700625
626 /* indicate no mac active */
627 vars->mac_type = MAC_TYPE_NONE;
628 }
629
630 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
631 vars->link_status, vars->phy_link_up);
632 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
633 vars->line_speed, vars->duplex, vars->flow_ctrl);
634}
635
636static void bnx2x_update_mng(struct link_params *params, u32 link_status)
637{
638 struct bnx2x *bp = params->bp;
639 REG_WR(bp, params->shmem_base +
640 offsetof(struct shmem_region,
641 port_mb[params->port].link_status),
642 link_status);
643}
644
645static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
646{
647 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
648 NIG_REG_INGRESS_BMAC0_MEM;
649 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700650 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700651
652 /* Only if the bmac is out of reset */
653 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
654 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
655 nig_bmac_enable) {
656
657 /* Clear Rx Enable bit in BMAC_CONTROL register */
658 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
659 wb_data, 2);
660 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
661 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
662 wb_data, 2);
663
664 msleep(1);
665 }
666}
667
668static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
669 u32 line_speed)
670{
671 struct bnx2x *bp = params->bp;
672 u8 port = params->port;
673 u32 init_crd, crd;
674 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700675
676 /* disable port */
677 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
678
679 /* wait for init credit */
680 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
681 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
682 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
683
684 while ((init_crd != crd) && count) {
685 msleep(5);
686
687 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
688 count--;
689 }
690 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
691 if (init_crd != crd) {
692 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
693 init_crd, crd);
694 return -EINVAL;
695 }
696
David S. Millerc0700f92008-12-16 23:53:20 -0800697 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700698 line_speed == SPEED_10 ||
699 line_speed == SPEED_100 ||
700 line_speed == SPEED_1000 ||
701 line_speed == SPEED_2500) {
702 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700703 /* update threshold */
704 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
705 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700706 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700707
708 } else {
709 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
710 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700711 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700712 /* update threshold */
713 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
714 /* update init credit */
715 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700716 case SPEED_10000:
717 init_crd = thresh + 553 - 22;
718 break;
719
720 case SPEED_12000:
721 init_crd = thresh + 664 - 22;
722 break;
723
724 case SPEED_13000:
725 init_crd = thresh + 742 - 22;
726 break;
727
728 case SPEED_16000:
729 init_crd = thresh + 778 - 22;
730 break;
731 default:
732 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
733 line_speed);
734 return -EINVAL;
735 break;
736 }
737 }
738 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
739 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
740 line_speed, init_crd);
741
742 /* probe the credit changes */
743 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
744 msleep(5);
745 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
746
747 /* enable port */
748 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
749 return 0;
750}
751
752static u32 bnx2x_get_emac_base(u32 ext_phy_type, u8 port)
753{
754 u32 emac_base;
755 switch (ext_phy_type) {
756 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
757 emac_base = GRCBASE_EMAC0;
758 break;
759 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700760 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700761 break;
762 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700763 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700764 break;
765 }
766 return emac_base;
767
768}
769
770u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
771 u8 phy_addr, u8 devad, u16 reg, u16 val)
772{
773 u32 tmp, saved_mode;
774 u8 i, rc = 0;
775 u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
776
777 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
778 * (a value of 49==0x31) and make sure that the AUTO poll is off
779 */
780 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
781 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
782 EMAC_MDIO_MODE_CLOCK_CNT);
783 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
784 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
785 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
786 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
787 udelay(40);
788
789 /* address */
790
791 tmp = ((phy_addr << 21) | (devad << 16) | reg |
792 EMAC_MDIO_COMM_COMMAND_ADDRESS |
793 EMAC_MDIO_COMM_START_BUSY);
794 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
795
796 for (i = 0; i < 50; i++) {
797 udelay(10);
798
799 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
800 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
801 udelay(5);
802 break;
803 }
804 }
805 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
806 DP(NETIF_MSG_LINK, "write phy register failed\n");
807 rc = -EFAULT;
808 } else {
809 /* data */
810 tmp = ((phy_addr << 21) | (devad << 16) | val |
811 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
812 EMAC_MDIO_COMM_START_BUSY);
813 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
814
815 for (i = 0; i < 50; i++) {
816 udelay(10);
817
818 tmp = REG_RD(bp, mdio_ctrl +
819 EMAC_REG_EMAC_MDIO_COMM);
820 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
821 udelay(5);
822 break;
823 }
824 }
825 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
826 DP(NETIF_MSG_LINK, "write phy register failed\n");
827 rc = -EFAULT;
828 }
829 }
830
831 /* Restore the saved mode */
832 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
833
834 return rc;
835}
836
837u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
838 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
839{
840 u32 val, saved_mode;
841 u16 i;
842 u8 rc = 0;
843
844 u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
845 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
846 * (a value of 49==0x31) and make sure that the AUTO poll is off
847 */
848 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
849 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
850 EMAC_MDIO_MODE_CLOCK_CNT));
851 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
852 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
853 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
854 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
855 udelay(40);
856
857 /* address */
858 val = ((phy_addr << 21) | (devad << 16) | reg |
859 EMAC_MDIO_COMM_COMMAND_ADDRESS |
860 EMAC_MDIO_COMM_START_BUSY);
861 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
862
863 for (i = 0; i < 50; i++) {
864 udelay(10);
865
866 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
867 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
868 udelay(5);
869 break;
870 }
871 }
872 if (val & EMAC_MDIO_COMM_START_BUSY) {
873 DP(NETIF_MSG_LINK, "read phy register failed\n");
874
875 *ret_val = 0;
876 rc = -EFAULT;
877
878 } else {
879 /* data */
880 val = ((phy_addr << 21) | (devad << 16) |
881 EMAC_MDIO_COMM_COMMAND_READ_45 |
882 EMAC_MDIO_COMM_START_BUSY);
883 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
884
885 for (i = 0; i < 50; i++) {
886 udelay(10);
887
888 val = REG_RD(bp, mdio_ctrl +
889 EMAC_REG_EMAC_MDIO_COMM);
890 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
891 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
892 break;
893 }
894 }
895 if (val & EMAC_MDIO_COMM_START_BUSY) {
896 DP(NETIF_MSG_LINK, "read phy register failed\n");
897
898 *ret_val = 0;
899 rc = -EFAULT;
900 }
901 }
902
903 /* Restore the saved mode */
904 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
905
906 return rc;
907}
908
909static void bnx2x_set_aer_mmd(struct link_params *params,
910 struct link_vars *vars)
911{
912 struct bnx2x *bp = params->bp;
913 u32 ser_lane;
914 u16 offset;
915
916 ser_lane = ((params->lane_config &
917 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
918 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
919
920 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
921 (params->phy_addr + ser_lane) : 0;
922
923 CL45_WR_OVER_CL22(bp, params->port,
924 params->phy_addr,
925 MDIO_REG_BANK_AER_BLOCK,
926 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
927}
928
929static void bnx2x_set_master_ln(struct link_params *params)
930{
931 struct bnx2x *bp = params->bp;
932 u16 new_master_ln, ser_lane;
933 ser_lane = ((params->lane_config &
934 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
935 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
936
937 /* set the master_ln for AN */
938 CL45_RD_OVER_CL22(bp, params->port,
939 params->phy_addr,
940 MDIO_REG_BANK_XGXS_BLOCK2,
941 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
942 &new_master_ln);
943
944 CL45_WR_OVER_CL22(bp, params->port,
945 params->phy_addr,
946 MDIO_REG_BANK_XGXS_BLOCK2 ,
947 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
948 (new_master_ln | ser_lane));
949}
950
951static u8 bnx2x_reset_unicore(struct link_params *params)
952{
953 struct bnx2x *bp = params->bp;
954 u16 mii_control;
955 u16 i;
956
957 CL45_RD_OVER_CL22(bp, params->port,
958 params->phy_addr,
959 MDIO_REG_BANK_COMBO_IEEE0,
960 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
961
962 /* reset the unicore */
963 CL45_WR_OVER_CL22(bp, params->port,
964 params->phy_addr,
965 MDIO_REG_BANK_COMBO_IEEE0,
966 MDIO_COMBO_IEEE0_MII_CONTROL,
967 (mii_control |
968 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
969
970 /* wait for the reset to self clear */
971 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
972 udelay(5);
973
974 /* the reset erased the previous bank value */
975 CL45_RD_OVER_CL22(bp, params->port,
976 params->phy_addr,
977 MDIO_REG_BANK_COMBO_IEEE0,
978 MDIO_COMBO_IEEE0_MII_CONTROL,
979 &mii_control);
980
981 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
982 udelay(5);
983 return 0;
984 }
985 }
986
987 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
988 return -EINVAL;
989
990}
991
992static void bnx2x_set_swap_lanes(struct link_params *params)
993{
994 struct bnx2x *bp = params->bp;
995 /* Each two bits represents a lane number:
996 No swap is 0123 => 0x1b no need to enable the swap */
997 u16 ser_lane, rx_lane_swap, tx_lane_swap;
998
999 ser_lane = ((params->lane_config &
1000 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1001 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1002 rx_lane_swap = ((params->lane_config &
1003 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1004 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1005 tx_lane_swap = ((params->lane_config &
1006 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1007 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1008
1009 if (rx_lane_swap != 0x1b) {
1010 CL45_WR_OVER_CL22(bp, params->port,
1011 params->phy_addr,
1012 MDIO_REG_BANK_XGXS_BLOCK2,
1013 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1014 (rx_lane_swap |
1015 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1016 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1017 } else {
1018 CL45_WR_OVER_CL22(bp, params->port,
1019 params->phy_addr,
1020 MDIO_REG_BANK_XGXS_BLOCK2,
1021 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1022 }
1023
1024 if (tx_lane_swap != 0x1b) {
1025 CL45_WR_OVER_CL22(bp, params->port,
1026 params->phy_addr,
1027 MDIO_REG_BANK_XGXS_BLOCK2,
1028 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1029 (tx_lane_swap |
1030 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1031 } else {
1032 CL45_WR_OVER_CL22(bp, params->port,
1033 params->phy_addr,
1034 MDIO_REG_BANK_XGXS_BLOCK2,
1035 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1036 }
1037}
1038
1039static void bnx2x_set_parallel_detection(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07001040 u8 phy_flags)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001041{
1042 struct bnx2x *bp = params->bp;
1043 u16 control2;
1044
1045 CL45_RD_OVER_CL22(bp, params->port,
1046 params->phy_addr,
1047 MDIO_REG_BANK_SERDES_DIGITAL,
1048 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1049 &control2);
1050
1051
1052 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1053
1054
1055 CL45_WR_OVER_CL22(bp, params->port,
1056 params->phy_addr,
1057 MDIO_REG_BANK_SERDES_DIGITAL,
1058 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1059 control2);
1060
1061 if (phy_flags & PHY_XGXS_FLAG) {
1062 DP(NETIF_MSG_LINK, "XGXS\n");
1063
1064 CL45_WR_OVER_CL22(bp, params->port,
1065 params->phy_addr,
1066 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1067 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1068 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1069
1070 CL45_RD_OVER_CL22(bp, params->port,
1071 params->phy_addr,
1072 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1073 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1074 &control2);
1075
1076
1077 control2 |=
1078 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1079
1080 CL45_WR_OVER_CL22(bp, params->port,
1081 params->phy_addr,
1082 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1083 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1084 control2);
1085
1086 /* Disable parallel detection of HiG */
1087 CL45_WR_OVER_CL22(bp, params->port,
1088 params->phy_addr,
1089 MDIO_REG_BANK_XGXS_BLOCK2,
1090 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1091 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1092 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1093 }
1094}
1095
1096static void bnx2x_set_autoneg(struct link_params *params,
1097 struct link_vars *vars)
1098{
1099 struct bnx2x *bp = params->bp;
1100 u16 reg_val;
1101
1102 /* CL37 Autoneg */
1103
1104 CL45_RD_OVER_CL22(bp, params->port,
1105 params->phy_addr,
1106 MDIO_REG_BANK_COMBO_IEEE0,
1107 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1108
1109 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001110 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001111 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1112 else /* CL37 Autoneg Disabled */
1113 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1114 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1115
1116 CL45_WR_OVER_CL22(bp, params->port,
1117 params->phy_addr,
1118 MDIO_REG_BANK_COMBO_IEEE0,
1119 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1120
1121 /* Enable/Disable Autodetection */
1122
1123 CL45_RD_OVER_CL22(bp, params->port,
1124 params->phy_addr,
1125 MDIO_REG_BANK_SERDES_DIGITAL,
1126 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
1127 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001128 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001129 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1130 else
1131 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1132
1133 CL45_WR_OVER_CL22(bp, params->port,
1134 params->phy_addr,
1135 MDIO_REG_BANK_SERDES_DIGITAL,
1136 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1137
1138 /* Enable TetonII and BAM autoneg */
1139 CL45_RD_OVER_CL22(bp, params->port,
1140 params->phy_addr,
1141 MDIO_REG_BANK_BAM_NEXT_PAGE,
1142 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1143 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001144 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001145 /* Enable BAM aneg Mode and TetonII aneg Mode */
1146 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1147 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1148 } else {
1149 /* TetonII and BAM Autoneg Disabled */
1150 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1151 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1152 }
1153 CL45_WR_OVER_CL22(bp, params->port,
1154 params->phy_addr,
1155 MDIO_REG_BANK_BAM_NEXT_PAGE,
1156 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1157 reg_val);
1158
1159 /* Enable Clause 73 Aneg */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001160 if ((vars->line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001161 (SUPPORT_CL73)) {
1162 /* Enable BAM Station Manager */
1163
1164 CL45_WR_OVER_CL22(bp, params->port,
1165 params->phy_addr,
1166 MDIO_REG_BANK_CL73_USERB0,
1167 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1168 (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1169 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1170 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN));
1171
1172 /* Merge CL73 and CL37 aneg resolution */
1173 CL45_RD_OVER_CL22(bp, params->port,
1174 params->phy_addr,
1175 MDIO_REG_BANK_CL73_USERB0,
1176 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1177 &reg_val);
1178
1179 CL45_WR_OVER_CL22(bp, params->port,
1180 params->phy_addr,
1181 MDIO_REG_BANK_CL73_USERB0,
1182 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1183 (reg_val |
1184 MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR));
1185
1186 /* Set the CL73 AN speed */
1187
1188 CL45_RD_OVER_CL22(bp, params->port,
1189 params->phy_addr,
1190 MDIO_REG_BANK_CL73_IEEEB1,
1191 MDIO_CL73_IEEEB1_AN_ADV2, &reg_val);
1192 /* In the SerDes we support only the 1G.
1193 In the XGXS we support the 10G KX4
1194 but we currently do not support the KR */
1195 if (vars->phy_flags & PHY_XGXS_FLAG) {
1196 DP(NETIF_MSG_LINK, "XGXS\n");
1197 /* 10G KX4 */
1198 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1199 } else {
1200 DP(NETIF_MSG_LINK, "SerDes\n");
1201 /* 1000M KX */
1202 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
1203 }
1204 CL45_WR_OVER_CL22(bp, params->port,
1205 params->phy_addr,
1206 MDIO_REG_BANK_CL73_IEEEB1,
1207 MDIO_CL73_IEEEB1_AN_ADV2, reg_val);
1208
1209 /* CL73 Autoneg Enabled */
1210 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1211 } else {
1212 /* CL73 Autoneg Disabled */
1213 reg_val = 0;
1214 }
1215 CL45_WR_OVER_CL22(bp, params->port,
1216 params->phy_addr,
1217 MDIO_REG_BANK_CL73_IEEEB0,
1218 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1219}
1220
1221/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001222static void bnx2x_program_serdes(struct link_params *params,
1223 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001224{
1225 struct bnx2x *bp = params->bp;
1226 u16 reg_val;
1227
1228 /* program duplex, disable autoneg */
1229
1230 CL45_RD_OVER_CL22(bp, params->port,
1231 params->phy_addr,
1232 MDIO_REG_BANK_COMBO_IEEE0,
1233 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1234 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
1235 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN);
1236 if (params->req_duplex == DUPLEX_FULL)
1237 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1238 CL45_WR_OVER_CL22(bp, params->port,
1239 params->phy_addr,
1240 MDIO_REG_BANK_COMBO_IEEE0,
1241 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1242
1243 /* program speed
1244 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001245 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001246 params->phy_addr,
1247 MDIO_REG_BANK_SERDES_DIGITAL,
1248 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001249 /* clearing the speed value before setting the right speed */
1250 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1251
1252 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1253 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1254
1255 if (!((vars->line_speed == SPEED_1000) ||
1256 (vars->line_speed == SPEED_100) ||
1257 (vars->line_speed == SPEED_10))) {
1258
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001259 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1260 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001261 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001262 reg_val |=
1263 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001264 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001265 reg_val |=
1266 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001267 }
1268
1269 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001270 params->phy_addr,
1271 MDIO_REG_BANK_SERDES_DIGITAL,
1272 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001273
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001274}
1275
1276static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1277{
1278 struct bnx2x *bp = params->bp;
1279 u16 val = 0;
1280
1281 /* configure the 48 bits for BAM AN */
1282
1283 /* set extended capabilities */
1284 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1285 val |= MDIO_OVER_1G_UP1_2_5G;
1286 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1287 val |= MDIO_OVER_1G_UP1_10G;
1288 CL45_WR_OVER_CL22(bp, params->port,
1289 params->phy_addr,
1290 MDIO_REG_BANK_OVER_1G,
1291 MDIO_OVER_1G_UP1, val);
1292
1293 CL45_WR_OVER_CL22(bp, params->port,
1294 params->phy_addr,
1295 MDIO_REG_BANK_OVER_1G,
1296 MDIO_OVER_1G_UP3, 0);
1297}
1298
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001299static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001300{
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001301 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001302 /* resolve pause mode and advertisement
1303 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1304
1305 switch (params->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001306 case BNX2X_FLOW_CTRL_AUTO:
1307 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001308 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001309 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1310 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001311 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001312 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1313 }
1314 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001315 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001316 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001317 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1318 break;
1319
David S. Millerc0700f92008-12-16 23:53:20 -08001320 case BNX2X_FLOW_CTRL_RX:
1321 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001322 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001323 break;
1324
David S. Millerc0700f92008-12-16 23:53:20 -08001325 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001326 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001327 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001328 break;
1329 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001330}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001331
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001332static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
1333 u32 ieee_fc)
1334{
1335 struct bnx2x *bp = params->bp;
1336 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001337
1338 CL45_WR_OVER_CL22(bp, params->port,
1339 params->phy_addr,
1340 MDIO_REG_BANK_COMBO_IEEE0,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001341 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001342}
1343
1344static void bnx2x_restart_autoneg(struct link_params *params)
1345{
1346 struct bnx2x *bp = params->bp;
1347 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
1348 if (SUPPORT_CL73) {
1349 /* enable and restart clause 73 aneg */
1350 u16 an_ctrl;
1351
1352 CL45_RD_OVER_CL22(bp, params->port,
1353 params->phy_addr,
1354 MDIO_REG_BANK_CL73_IEEEB0,
1355 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1356 &an_ctrl);
1357 CL45_WR_OVER_CL22(bp, params->port,
1358 params->phy_addr,
1359 MDIO_REG_BANK_CL73_IEEEB0,
1360 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1361 (an_ctrl |
1362 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1363 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1364
1365 } else {
1366 /* Enable and restart BAM/CL37 aneg */
1367 u16 mii_control;
1368
1369 CL45_RD_OVER_CL22(bp, params->port,
1370 params->phy_addr,
1371 MDIO_REG_BANK_COMBO_IEEE0,
1372 MDIO_COMBO_IEEE0_MII_CONTROL,
1373 &mii_control);
1374 DP(NETIF_MSG_LINK,
1375 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1376 mii_control);
1377 CL45_WR_OVER_CL22(bp, params->port,
1378 params->phy_addr,
1379 MDIO_REG_BANK_COMBO_IEEE0,
1380 MDIO_COMBO_IEEE0_MII_CONTROL,
1381 (mii_control |
1382 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1383 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1384 }
1385}
1386
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001387static void bnx2x_initialize_sgmii_process(struct link_params *params,
1388 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001389{
1390 struct bnx2x *bp = params->bp;
1391 u16 control1;
1392
1393 /* in SGMII mode, the unicore is always slave */
1394
1395 CL45_RD_OVER_CL22(bp, params->port,
1396 params->phy_addr,
1397 MDIO_REG_BANK_SERDES_DIGITAL,
1398 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1399 &control1);
1400 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1401 /* set sgmii mode (and not fiber) */
1402 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1403 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1404 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1405 CL45_WR_OVER_CL22(bp, params->port,
1406 params->phy_addr,
1407 MDIO_REG_BANK_SERDES_DIGITAL,
1408 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1409 control1);
1410
1411 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001412 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001413 /* set speed, disable autoneg */
1414 u16 mii_control;
1415
1416 CL45_RD_OVER_CL22(bp, params->port,
1417 params->phy_addr,
1418 MDIO_REG_BANK_COMBO_IEEE0,
1419 MDIO_COMBO_IEEE0_MII_CONTROL,
1420 &mii_control);
1421 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1422 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1423 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1424
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001425 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001426 case SPEED_100:
1427 mii_control |=
1428 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1429 break;
1430 case SPEED_1000:
1431 mii_control |=
1432 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1433 break;
1434 case SPEED_10:
1435 /* there is nothing to set for 10M */
1436 break;
1437 default:
1438 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001439 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1440 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001441 break;
1442 }
1443
1444 /* setting the full duplex */
1445 if (params->req_duplex == DUPLEX_FULL)
1446 mii_control |=
1447 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1448 CL45_WR_OVER_CL22(bp, params->port,
1449 params->phy_addr,
1450 MDIO_REG_BANK_COMBO_IEEE0,
1451 MDIO_COMBO_IEEE0_MII_CONTROL,
1452 mii_control);
1453
1454 } else { /* AN mode */
1455 /* enable and restart AN */
1456 bnx2x_restart_autoneg(params);
1457 }
1458}
1459
1460
1461/*
1462 * link management
1463 */
1464
1465static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001466{ /* LD LP */
1467 switch (pause_result) { /* ASYM P ASYM P */
1468 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001469 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001470 break;
1471
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001472 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001473 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001474 break;
1475
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001476 case 0x5: /* 0 1 0 1 */
1477 case 0x7: /* 0 1 1 1 */
1478 case 0xd: /* 1 1 0 1 */
1479 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001480 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001481 break;
1482
1483 default:
1484 break;
1485 }
1486}
1487
1488static u8 bnx2x_ext_phy_resove_fc(struct link_params *params,
1489 struct link_vars *vars)
1490{
1491 struct bnx2x *bp = params->bp;
1492 u8 ext_phy_addr;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001493 u16 ld_pause; /* local */
1494 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001495 u16 an_complete; /* AN complete */
1496 u16 pause_result;
1497 u8 ret = 0;
1498 u32 ext_phy_type;
1499 u8 port = params->port;
1500 ext_phy_addr = ((params->ext_phy_config &
1501 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1502 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1503
1504 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1505 /* read twice */
1506
1507 bnx2x_cl45_read(bp, port,
1508 ext_phy_type,
1509 ext_phy_addr,
1510 MDIO_AN_DEVAD,
1511 MDIO_AN_REG_STATUS, &an_complete);
1512 bnx2x_cl45_read(bp, port,
1513 ext_phy_type,
1514 ext_phy_addr,
1515 MDIO_AN_DEVAD,
1516 MDIO_AN_REG_STATUS, &an_complete);
1517
1518 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1519 ret = 1;
1520 bnx2x_cl45_read(bp, port,
1521 ext_phy_type,
1522 ext_phy_addr,
1523 MDIO_AN_DEVAD,
1524 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1525 bnx2x_cl45_read(bp, port,
1526 ext_phy_type,
1527 ext_phy_addr,
1528 MDIO_AN_DEVAD,
1529 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1530 pause_result = (ld_pause &
1531 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1532 pause_result |= (lp_pause &
1533 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1534 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
1535 pause_result);
1536 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001537 if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001538 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1539 bnx2x_cl45_read(bp, port,
1540 ext_phy_type,
1541 ext_phy_addr,
1542 MDIO_AN_DEVAD,
1543 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1544
1545 bnx2x_cl45_read(bp, port,
1546 ext_phy_type,
1547 ext_phy_addr,
1548 MDIO_AN_DEVAD,
1549 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1550 pause_result = (ld_pause &
1551 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1552 pause_result |= (lp_pause &
1553 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1554
1555 bnx2x_pause_resolve(vars, pause_result);
1556 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
1557 pause_result);
1558 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001559 }
1560 return ret;
1561}
1562
1563
1564static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1565 struct link_vars *vars,
1566 u32 gp_status)
1567{
1568 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001569 u16 ld_pause; /* local driver */
1570 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001571 u16 pause_result;
1572
David S. Millerc0700f92008-12-16 23:53:20 -08001573 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001574
1575 /* resolve from gp_status in case of AN complete and not sgmii */
David S. Millerc0700f92008-12-16 23:53:20 -08001576 if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001577 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1578 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1579 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1580 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
1581 CL45_RD_OVER_CL22(bp, params->port,
1582 params->phy_addr,
1583 MDIO_REG_BANK_COMBO_IEEE0,
1584 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1585 &ld_pause);
1586 CL45_RD_OVER_CL22(bp, params->port,
1587 params->phy_addr,
1588 MDIO_REG_BANK_COMBO_IEEE0,
1589 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1590 &lp_pause);
1591 pause_result = (ld_pause &
1592 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
1593 pause_result |= (lp_pause &
1594 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
1595 DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
1596 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001597 } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001598 (bnx2x_ext_phy_resove_fc(params, vars))) {
1599 return;
1600 } else {
David S. Millerc0700f92008-12-16 23:53:20 -08001601 if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001602 vars->flow_ctrl = params->req_fc_auto_adv;
1603 else
1604 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001605 }
1606 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1607}
1608
1609
1610static u8 bnx2x_link_settings_status(struct link_params *params,
1611 struct link_vars *vars,
1612 u32 gp_status)
1613{
1614 struct bnx2x *bp = params->bp;
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001615 u16 new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001616 u8 rc = 0;
1617 vars->link_status = 0;
1618
1619 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1620 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1621 gp_status);
1622
1623 vars->phy_link_up = 1;
1624 vars->link_status |= LINK_STATUS_LINK_UP;
1625
1626 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1627 vars->duplex = DUPLEX_FULL;
1628 else
1629 vars->duplex = DUPLEX_HALF;
1630
1631 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1632
1633 switch (gp_status & GP_STATUS_SPEED_MASK) {
1634 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001635 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001636 if (vars->duplex == DUPLEX_FULL)
1637 vars->link_status |= LINK_10TFD;
1638 else
1639 vars->link_status |= LINK_10THD;
1640 break;
1641
1642 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001643 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001644 if (vars->duplex == DUPLEX_FULL)
1645 vars->link_status |= LINK_100TXFD;
1646 else
1647 vars->link_status |= LINK_100TXHD;
1648 break;
1649
1650 case GP_STATUS_1G:
1651 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001652 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001653 if (vars->duplex == DUPLEX_FULL)
1654 vars->link_status |= LINK_1000TFD;
1655 else
1656 vars->link_status |= LINK_1000THD;
1657 break;
1658
1659 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001660 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001661 if (vars->duplex == DUPLEX_FULL)
1662 vars->link_status |= LINK_2500TFD;
1663 else
1664 vars->link_status |= LINK_2500THD;
1665 break;
1666
1667 case GP_STATUS_5G:
1668 case GP_STATUS_6G:
1669 DP(NETIF_MSG_LINK,
1670 "link speed unsupported gp_status 0x%x\n",
1671 gp_status);
1672 return -EINVAL;
1673 break;
1674 case GP_STATUS_10G_KX4:
1675 case GP_STATUS_10G_HIG:
1676 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001677 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001678 vars->link_status |= LINK_10GTFD;
1679 break;
1680
1681 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001682 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001683 vars->link_status |= LINK_12GTFD;
1684 break;
1685
1686 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001687 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001688 vars->link_status |= LINK_12_5GTFD;
1689 break;
1690
1691 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001692 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001693 vars->link_status |= LINK_13GTFD;
1694 break;
1695
1696 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001697 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001698 vars->link_status |= LINK_15GTFD;
1699 break;
1700
1701 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001702 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001703 vars->link_status |= LINK_16GTFD;
1704 break;
1705
1706 default:
1707 DP(NETIF_MSG_LINK,
1708 "link speed unsupported gp_status 0x%x\n",
1709 gp_status);
1710 return -EINVAL;
1711 break;
1712 }
1713
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001714 /* Upon link speed change set the NIG into drain mode.
1715 Comes to deals with possible FIFO glitch due to clk change
1716 when speed is decreased without link down indicator */
1717 if (new_line_speed != vars->line_speed) {
1718 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
1719 + params->port*4, 0);
1720 msleep(1);
1721 }
1722 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001723 vars->link_status |= LINK_STATUS_SERDES_LINK;
1724
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001725 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1726 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1727 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1728 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1729 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001730 vars->autoneg = AUTO_NEG_ENABLED;
1731
1732 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1733 vars->autoneg |= AUTO_NEG_COMPLETE;
1734 vars->link_status |=
1735 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1736 }
1737
1738 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1739 vars->link_status |=
1740 LINK_STATUS_PARALLEL_DETECTION_USED;
1741
1742 }
David S. Millerc0700f92008-12-16 23:53:20 -08001743 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001744 vars->link_status |=
1745 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001746
David S. Millerc0700f92008-12-16 23:53:20 -08001747 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001748 vars->link_status |=
1749 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001750
1751 } else { /* link_down */
1752 DP(NETIF_MSG_LINK, "phy link down\n");
1753
1754 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001755
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001756 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001757 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001758 vars->autoneg = AUTO_NEG_DISABLED;
1759 vars->mac_type = MAC_TYPE_NONE;
1760 }
1761
1762 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n",
1763 gp_status, vars->phy_link_up, vars->line_speed);
1764 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1765 " autoneg 0x%x\n",
1766 vars->duplex,
1767 vars->flow_ctrl, vars->autoneg);
1768 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1769
1770 return rc;
1771}
1772
1773static void bnx2x_set_sgmii_tx_driver(struct link_params *params)
1774{
1775 struct bnx2x *bp = params->bp;
1776 u16 lp_up2;
1777 u16 tx_driver;
1778
1779 /* read precomp */
1780
1781 CL45_RD_OVER_CL22(bp, params->port,
1782 params->phy_addr,
1783 MDIO_REG_BANK_OVER_1G,
1784 MDIO_OVER_1G_LP_UP2, &lp_up2);
1785
1786 CL45_RD_OVER_CL22(bp, params->port,
1787 params->phy_addr,
1788 MDIO_REG_BANK_TX0,
1789 MDIO_TX0_TX_DRIVER, &tx_driver);
1790
1791 /* bits [10:7] at lp_up2, positioned at [15:12] */
1792 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1793 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1794 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1795
1796 if ((lp_up2 != 0) &&
1797 (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) {
1798 /* replace tx_driver bits [15:12] */
1799 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1800 tx_driver |= lp_up2;
1801 CL45_WR_OVER_CL22(bp, params->port,
1802 params->phy_addr,
1803 MDIO_REG_BANK_TX0,
1804 MDIO_TX0_TX_DRIVER, tx_driver);
1805 }
1806}
1807
1808static u8 bnx2x_emac_program(struct link_params *params,
1809 u32 line_speed, u32 duplex)
1810{
1811 struct bnx2x *bp = params->bp;
1812 u8 port = params->port;
1813 u16 mode = 0;
1814
1815 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1816 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1817 EMAC_REG_EMAC_MODE,
1818 (EMAC_MODE_25G_MODE |
1819 EMAC_MODE_PORT_MII_10M |
1820 EMAC_MODE_HALF_DUPLEX));
1821 switch (line_speed) {
1822 case SPEED_10:
1823 mode |= EMAC_MODE_PORT_MII_10M;
1824 break;
1825
1826 case SPEED_100:
1827 mode |= EMAC_MODE_PORT_MII;
1828 break;
1829
1830 case SPEED_1000:
1831 mode |= EMAC_MODE_PORT_GMII;
1832 break;
1833
1834 case SPEED_2500:
1835 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
1836 break;
1837
1838 default:
1839 /* 10G not valid for EMAC */
1840 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
1841 return -EINVAL;
1842 }
1843
1844 if (duplex == DUPLEX_HALF)
1845 mode |= EMAC_MODE_HALF_DUPLEX;
1846 bnx2x_bits_en(bp,
1847 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
1848 mode);
1849
1850 bnx2x_set_led(bp, params->port, LED_MODE_OPER,
1851 line_speed, params->hw_led_mode, params->chip_id);
1852 return 0;
1853}
1854
1855/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001856/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001857/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001858static void bnx2x_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001859{
1860 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001861 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001862 msleep(1);
1863 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001864 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001865}
1866
1867static void bnx2x_ext_phy_reset(struct link_params *params,
1868 struct link_vars *vars)
1869{
1870 struct bnx2x *bp = params->bp;
1871 u32 ext_phy_type;
1872 u8 ext_phy_addr = ((params->ext_phy_config &
1873 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1874 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1875 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
1876 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1877 /* The PHY reset is controled by GPIO 1
1878 * Give it 1ms of reset pulse
1879 */
1880 if (vars->phy_flags & PHY_XGXS_FLAG) {
1881
1882 switch (ext_phy_type) {
1883 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
1884 DP(NETIF_MSG_LINK, "XGXS Direct\n");
1885 break;
1886
1887 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
1888 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
1889 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
1890
1891 /* Restore normal power mode*/
1892 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001893 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1894 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001895
1896 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001897 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001898
1899 bnx2x_cl45_write(bp, params->port,
1900 ext_phy_type,
1901 ext_phy_addr,
1902 MDIO_PMA_DEVAD,
1903 MDIO_PMA_REG_CTRL, 0xa040);
1904 break;
1905 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
1906 /* Unset Low Power Mode and SW reset */
1907 /* Restore normal power mode*/
1908 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001909 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1910 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001911
1912 DP(NETIF_MSG_LINK, "XGXS 8072\n");
1913 bnx2x_cl45_write(bp, params->port,
1914 ext_phy_type,
1915 ext_phy_addr,
1916 MDIO_PMA_DEVAD,
1917 MDIO_PMA_REG_CTRL,
1918 1<<15);
1919 break;
1920 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
1921 {
1922 u16 emac_base;
1923 emac_base = (params->port) ? GRCBASE_EMAC0 :
1924 GRCBASE_EMAC1;
1925
1926 /* Restore normal power mode*/
1927 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001928 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1929 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001930
1931 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001932 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1933 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001934
1935 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001936 }
1937 break;
1938
1939 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
1940 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
1941
1942 /* Restore normal power mode*/
1943 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001944 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1945 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001946
1947 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001948 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001949
1950 break;
1951
1952 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
1953 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
1954 break;
1955
1956 default:
1957 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
1958 params->ext_phy_config);
1959 break;
1960 }
1961
1962 } else { /* SerDes */
1963 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
1964 switch (ext_phy_type) {
1965 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
1966 DP(NETIF_MSG_LINK, "SerDes Direct\n");
1967 break;
1968
1969 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
1970 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001971 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001972 break;
1973
1974 default:
1975 DP(NETIF_MSG_LINK,
1976 "BAD SerDes ext_phy_config 0x%x\n",
1977 params->ext_phy_config);
1978 break;
1979 }
1980 }
1981}
1982
1983static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
1984{
1985 struct bnx2x *bp = params->bp;
1986 u8 port = params->port;
1987 u8 ext_phy_addr = ((params->ext_phy_config &
1988 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1989 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1990 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1991 u16 fw_ver1, fw_ver2;
1992
1993 /* Need to wait 200ms after reset */
1994 msleep(200);
1995 /* Boot port from external ROM
1996 * Set ser_boot_ctl bit in the MISC_CTRL1 register
1997 */
1998 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
1999 MDIO_PMA_DEVAD,
2000 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2001
2002 /* Reset internal microprocessor */
2003 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2004 MDIO_PMA_DEVAD,
2005 MDIO_PMA_REG_GEN_CTRL,
2006 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2007 /* set micro reset = 0 */
2008 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2009 MDIO_PMA_DEVAD,
2010 MDIO_PMA_REG_GEN_CTRL,
2011 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2012 /* Reset internal microprocessor */
2013 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2014 MDIO_PMA_DEVAD,
2015 MDIO_PMA_REG_GEN_CTRL,
2016 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2017 /* wait for 100ms for code download via SPI port */
2018 msleep(100);
2019
2020 /* Clear ser_boot_ctl bit */
2021 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2022 MDIO_PMA_DEVAD,
2023 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2024 /* Wait 100ms */
2025 msleep(100);
2026
2027 /* Print the PHY FW version */
2028 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2029 MDIO_PMA_DEVAD,
2030 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2031 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2032 MDIO_PMA_DEVAD,
2033 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2034 DP(NETIF_MSG_LINK, "8072 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
2035}
2036
2037static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2038{
2039 /* This is only required for 8073A1, version 102 only */
2040
2041 struct bnx2x *bp = params->bp;
2042 u8 ext_phy_addr = ((params->ext_phy_config &
2043 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2044 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2045 u16 val;
2046
2047 /* Read 8073 HW revision*/
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 0xc801, &val);
2053
2054 if (val != 1) {
2055 /* No need to workaround in 8073 A1 */
2056 return 0;
2057 }
2058
2059 bnx2x_cl45_read(bp, params->port,
2060 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2061 ext_phy_addr,
2062 MDIO_PMA_DEVAD,
2063 MDIO_PMA_REG_ROM_VER2, &val);
2064
2065 /* SNR should be applied only for version 0x102 */
2066 if (val != 0x102)
2067 return 0;
2068
2069 return 1;
2070}
2071
2072static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2073{
2074 struct bnx2x *bp = params->bp;
2075 u8 ext_phy_addr = ((params->ext_phy_config &
2076 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2077 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2078 u16 val, cnt, cnt1 ;
2079
2080 bnx2x_cl45_read(bp, params->port,
2081 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2082 ext_phy_addr,
2083 MDIO_PMA_DEVAD,
2084 0xc801, &val);
2085
2086 if (val > 0) {
2087 /* No need to workaround in 8073 A1 */
2088 return 0;
2089 }
2090 /* XAUI workaround in 8073 A0: */
2091
2092 /* After loading the boot ROM and restarting Autoneg,
2093 poll Dev1, Reg $C820: */
2094
2095 for (cnt = 0; cnt < 1000; cnt++) {
2096 bnx2x_cl45_read(bp, params->port,
2097 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2098 ext_phy_addr,
2099 MDIO_PMA_DEVAD,
2100 0xc820, &val);
2101 /* If bit [14] = 0 or bit [13] = 0, continue on with
2102 system initialization (XAUI work-around not required,
2103 as these bits indicate 2.5G or 1G link up). */
2104 if (!(val & (1<<14)) || !(val & (1<<13))) {
2105 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2106 return 0;
2107 } else if (!(val & (1<<15))) {
2108 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2109 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2110 it's MSB (bit 15) goes to 1 (indicating that the
2111 XAUI workaround has completed),
2112 then continue on with system initialization.*/
2113 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2114 bnx2x_cl45_read(bp, params->port,
2115 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2116 ext_phy_addr,
2117 MDIO_PMA_DEVAD,
2118 0xc841, &val);
2119 if (val & (1<<15)) {
2120 DP(NETIF_MSG_LINK,
2121 "XAUI workaround has completed\n");
2122 return 0;
2123 }
2124 msleep(3);
2125 }
2126 break;
2127 }
2128 msleep(3);
2129 }
2130 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2131 return -EINVAL;
2132
2133}
2134
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002135static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
2136 u8 ext_phy_addr)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002137{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002138 u16 fw_ver1, fw_ver2;
2139 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002140 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002141 bnx2x_cl45_write(bp, port,
2142 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2143 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002144 MDIO_PMA_DEVAD,
2145 MDIO_PMA_REG_GEN_CTRL,
2146 0x0001);
2147
2148 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002149 bnx2x_cl45_write(bp, port,
2150 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2151 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002152 MDIO_PMA_DEVAD,
2153 MDIO_PMA_REG_GEN_CTRL,
2154 0x008c);
2155
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002156 bnx2x_cl45_write(bp, port,
2157 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2158 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002159 MDIO_PMA_DEVAD,
2160 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2161
2162 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002163 bnx2x_cl45_write(bp, port,
2164 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2165 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002166 MDIO_PMA_DEVAD,
2167 MDIO_PMA_REG_GEN_CTRL,
2168 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2169
2170 /* Release srst 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_GEN_CTRL,
2176 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2177
2178 /* wait for 100ms for code download via SPI port */
2179 msleep(100);
2180
2181 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002182 bnx2x_cl45_write(bp, port,
2183 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2184 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002185 MDIO_PMA_DEVAD,
2186 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2187
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002188 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2189 ext_phy_addr,
2190 MDIO_PMA_DEVAD,
2191 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2192 bnx2x_cl45_read(bp, port,
2193 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2194 ext_phy_addr,
2195 MDIO_PMA_DEVAD,
2196 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002197 DP(NETIF_MSG_LINK, "8073 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
2198
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002199}
2200
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002201static void bnx2x_bcm807x_force_10G(struct link_params *params)
2202{
2203 struct bnx2x *bp = params->bp;
2204 u8 port = params->port;
2205 u8 ext_phy_addr = ((params->ext_phy_config &
2206 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2207 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2208 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2209
2210 /* Force KR or KX */
2211 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2212 MDIO_PMA_DEVAD,
2213 MDIO_PMA_REG_CTRL,
2214 0x2040);
2215 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2216 MDIO_PMA_DEVAD,
2217 MDIO_PMA_REG_10G_CTRL2,
2218 0x000b);
2219 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2220 MDIO_PMA_DEVAD,
2221 MDIO_PMA_REG_BCM_CTRL,
2222 0x0000);
2223 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2224 MDIO_AN_DEVAD,
2225 MDIO_AN_REG_CTRL,
2226 0x0000);
2227}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002228static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
2229{
2230 struct bnx2x *bp = params->bp;
2231 u8 port = params->port;
2232 u16 val;
2233 u8 ext_phy_addr = ((params->ext_phy_config &
2234 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2235 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2236 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2237
2238 bnx2x_cl45_read(bp, params->port,
2239 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2240 ext_phy_addr,
2241 MDIO_PMA_DEVAD,
2242 0xc801, &val);
2243
2244 if (val == 0) {
2245 /* Mustn't set low power mode in 8073 A0 */
2246 return;
2247 }
2248
2249 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
2250 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2251 MDIO_XS_DEVAD,
2252 MDIO_XS_PLL_SEQUENCER, &val);
2253 val &= ~(1<<13);
2254 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2255 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2256
2257 /* PLL controls */
2258 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2259 MDIO_XS_DEVAD, 0x805E, 0x1077);
2260 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2261 MDIO_XS_DEVAD, 0x805D, 0x0000);
2262 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2263 MDIO_XS_DEVAD, 0x805C, 0x030B);
2264 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2265 MDIO_XS_DEVAD, 0x805B, 0x1240);
2266 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2267 MDIO_XS_DEVAD, 0x805A, 0x2490);
2268
2269 /* Tx Controls */
2270 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2271 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2272 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2273 MDIO_XS_DEVAD, 0x80A6, 0x9041);
2274 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2275 MDIO_XS_DEVAD, 0x80A5, 0x4640);
2276
2277 /* Rx Controls */
2278 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2279 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2280 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2281 MDIO_XS_DEVAD, 0x80FD, 0x9249);
2282 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2283 MDIO_XS_DEVAD, 0x80FC, 0x2015);
2284
2285 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
2286 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2287 MDIO_XS_DEVAD,
2288 MDIO_XS_PLL_SEQUENCER, &val);
2289 val |= (1<<13);
2290 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2291 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2292}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002293
2294static void bnx2x_8073_set_pause_cl37(struct link_params *params,
2295 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002296{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002297
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002298 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002299 u16 cl37_val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002300 u8 ext_phy_addr = ((params->ext_phy_config &
2301 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2302 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2303 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2304
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002305 bnx2x_cl45_read(bp, params->port,
2306 ext_phy_type,
2307 ext_phy_addr,
2308 MDIO_AN_DEVAD,
2309 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
2310
2311 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2312 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2313
2314 if ((vars->ieee_fc &
2315 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
2316 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
2317 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
2318 }
2319 if ((vars->ieee_fc &
2320 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2321 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2322 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2323 }
2324 if ((vars->ieee_fc &
2325 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2326 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2327 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2328 }
2329 DP(NETIF_MSG_LINK,
2330 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
2331
2332 bnx2x_cl45_write(bp, params->port,
2333 ext_phy_type,
2334 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002335 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002336 MDIO_AN_REG_CL37_FC_LD, cl37_val);
2337 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002338}
2339
2340static void bnx2x_ext_phy_set_pause(struct link_params *params,
2341 struct link_vars *vars)
2342{
2343 struct bnx2x *bp = params->bp;
2344 u16 val;
2345 u8 ext_phy_addr = ((params->ext_phy_config &
2346 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2347 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2348 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2349
2350 /* read modify write pause advertizing */
2351 bnx2x_cl45_read(bp, params->port,
2352 ext_phy_type,
2353 ext_phy_addr,
2354 MDIO_AN_DEVAD,
2355 MDIO_AN_REG_ADV_PAUSE, &val);
2356
2357 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002358
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002359 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2360
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002361 if ((vars->ieee_fc &
2362 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002363 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2364 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2365 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002366 if ((vars->ieee_fc &
2367 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002368 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2369 val |=
2370 MDIO_AN_REG_ADV_PAUSE_PAUSE;
2371 }
2372 DP(NETIF_MSG_LINK,
2373 "Ext phy AN advertize 0x%x\n", val);
2374 bnx2x_cl45_write(bp, params->port,
2375 ext_phy_type,
2376 ext_phy_addr,
2377 MDIO_AN_DEVAD,
2378 MDIO_AN_REG_ADV_PAUSE, val);
2379}
2380
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002381
2382static void bnx2x_init_internal_phy(struct link_params *params,
2383 struct link_vars *vars)
2384{
2385 struct bnx2x *bp = params->bp;
2386 u8 port = params->port;
2387 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2388 u16 bank, rx_eq;
2389
2390 rx_eq = ((params->serdes_config &
2391 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >>
2392 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT);
2393
2394 DP(NETIF_MSG_LINK, "setting rx eq to 0x%x\n", rx_eq);
2395 for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL;
2396 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0)) {
2397 CL45_WR_OVER_CL22(bp, port,
2398 params->phy_addr,
2399 bank ,
2400 MDIO_RX0_RX_EQ_BOOST,
2401 ((rx_eq &
2402 MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) |
2403 MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL));
2404 }
2405
2406 /* forced speed requested? */
2407 if (vars->line_speed != SPEED_AUTO_NEG) {
2408 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2409
2410 /* disable autoneg */
2411 bnx2x_set_autoneg(params, vars);
2412
2413 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002414 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002415
2416 } else { /* AN_mode */
2417 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2418
2419 /* AN enabled */
2420 bnx2x_set_brcm_cl37_advertisment(params);
2421
2422 /* program duplex & pause advertisement (for aneg) */
2423 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002424 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002425
2426 /* enable autoneg */
2427 bnx2x_set_autoneg(params, vars);
2428
2429 /* enable and restart AN */
2430 bnx2x_restart_autoneg(params);
2431 }
2432
2433 } else { /* SGMII mode */
2434 DP(NETIF_MSG_LINK, "SGMII\n");
2435
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002436 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002437 }
2438}
2439
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002440static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
2441{
2442 struct bnx2x *bp = params->bp;
2443 u32 ext_phy_type;
2444 u8 ext_phy_addr;
2445 u16 cnt;
2446 u16 ctrl = 0;
2447 u16 val = 0;
2448 u8 rc = 0;
2449 if (vars->phy_flags & PHY_XGXS_FLAG) {
2450 ext_phy_addr = ((params->ext_phy_config &
2451 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2452 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2453
2454 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2455 /* Make sure that the soft reset is off (expect for the 8072:
2456 * due to the lock, it will be done inside the specific
2457 * handling)
2458 */
2459 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
2460 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
2461 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
2462 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
2463 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
2464 /* Wait for soft reset to get cleared upto 1 sec */
2465 for (cnt = 0; cnt < 1000; cnt++) {
2466 bnx2x_cl45_read(bp, params->port,
2467 ext_phy_type,
2468 ext_phy_addr,
2469 MDIO_PMA_DEVAD,
2470 MDIO_PMA_REG_CTRL, &ctrl);
2471 if (!(ctrl & (1<<15)))
2472 break;
2473 msleep(1);
2474 }
2475 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
2476 ctrl, cnt);
2477 }
2478
2479 switch (ext_phy_type) {
2480 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002481 break;
2482
2483 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2484 DP(NETIF_MSG_LINK, "XGXS 8705\n");
2485
2486 bnx2x_cl45_write(bp, params->port,
2487 ext_phy_type,
2488 ext_phy_addr,
2489 MDIO_PMA_DEVAD,
2490 MDIO_PMA_REG_MISC_CTRL,
2491 0x8288);
2492 bnx2x_cl45_write(bp, params->port,
2493 ext_phy_type,
2494 ext_phy_addr,
2495 MDIO_PMA_DEVAD,
2496 MDIO_PMA_REG_PHY_IDENTIFIER,
2497 0x7fbf);
2498 bnx2x_cl45_write(bp, params->port,
2499 ext_phy_type,
2500 ext_phy_addr,
2501 MDIO_PMA_DEVAD,
2502 MDIO_PMA_REG_CMU_PLL_BYPASS,
2503 0x0100);
2504 bnx2x_cl45_write(bp, params->port,
2505 ext_phy_type,
2506 ext_phy_addr,
2507 MDIO_WIS_DEVAD,
2508 MDIO_WIS_REG_LASI_CNTL, 0x1);
2509 break;
2510
2511 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2512 DP(NETIF_MSG_LINK, "XGXS 8706\n");
2513
2514 msleep(10);
2515 /* Force speed */
2516 /* First enable LASI */
2517 bnx2x_cl45_write(bp, params->port,
2518 ext_phy_type,
2519 ext_phy_addr,
2520 MDIO_PMA_DEVAD,
2521 MDIO_PMA_REG_RX_ALARM_CTRL,
2522 0x0400);
2523 bnx2x_cl45_write(bp, params->port,
2524 ext_phy_type,
2525 ext_phy_addr,
2526 MDIO_PMA_DEVAD,
2527 MDIO_PMA_REG_LASI_CTRL, 0x0004);
2528
2529 if (params->req_line_speed == SPEED_10000) {
2530 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
2531
2532 bnx2x_cl45_write(bp, params->port,
2533 ext_phy_type,
2534 ext_phy_addr,
2535 MDIO_PMA_DEVAD,
2536 MDIO_PMA_REG_DIGITAL_CTRL,
2537 0x400);
2538 } else {
2539 /* Force 1Gbps using autoneg with 1G
2540 advertisment */
2541
2542 /* Allow CL37 through CL73 */
2543 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
2544 bnx2x_cl45_write(bp, params->port,
2545 ext_phy_type,
2546 ext_phy_addr,
2547 MDIO_AN_DEVAD,
2548 MDIO_AN_REG_CL37_CL73,
2549 0x040c);
2550
2551 /* Enable Full-Duplex advertisment on CL37 */
2552 bnx2x_cl45_write(bp, params->port,
2553 ext_phy_type,
2554 ext_phy_addr,
2555 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002556 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002557 0x0020);
2558 /* Enable CL37 AN */
2559 bnx2x_cl45_write(bp, params->port,
2560 ext_phy_type,
2561 ext_phy_addr,
2562 MDIO_AN_DEVAD,
2563 MDIO_AN_REG_CL37_AN,
2564 0x1000);
2565 /* 1G support */
2566 bnx2x_cl45_write(bp, params->port,
2567 ext_phy_type,
2568 ext_phy_addr,
2569 MDIO_AN_DEVAD,
2570 MDIO_AN_REG_ADV, (1<<5));
2571
2572 /* Enable clause 73 AN */
2573 bnx2x_cl45_write(bp, params->port,
2574 ext_phy_type,
2575 ext_phy_addr,
2576 MDIO_AN_DEVAD,
2577 MDIO_AN_REG_CTRL,
2578 0x1200);
2579
2580 }
2581
2582 break;
2583
2584 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
2585 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
2586 {
2587 u16 tmp1;
2588 u16 rx_alarm_ctrl_val;
2589 u16 lasi_ctrl_val;
2590 if (ext_phy_type ==
2591 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
2592 rx_alarm_ctrl_val = 0x400;
2593 lasi_ctrl_val = 0x0004;
2594 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002595 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002596 lasi_ctrl_val = 0x0004;
2597 }
2598
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002599 /* enable LASI */
2600 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002601 ext_phy_type,
2602 ext_phy_addr,
2603 MDIO_PMA_DEVAD,
2604 MDIO_PMA_REG_RX_ALARM_CTRL,
2605 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002606
2607 bnx2x_cl45_write(bp, params->port,
2608 ext_phy_type,
2609 ext_phy_addr,
2610 MDIO_PMA_DEVAD,
2611 MDIO_PMA_REG_LASI_CTRL,
2612 lasi_ctrl_val);
2613
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002614 bnx2x_8073_set_pause_cl37(params, vars);
2615
2616 if (ext_phy_type ==
2617 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){
2618 bnx2x_bcm8072_external_rom_boot(params);
2619 } else {
2620
2621 /* In case of 8073 with long xaui lines,
2622 don't set the 8073 xaui low power*/
2623 bnx2x_bcm8073_set_xaui_low_power_mode(params);
2624 }
2625
2626 bnx2x_cl45_read(bp, params->port,
2627 ext_phy_type,
2628 ext_phy_addr,
2629 MDIO_PMA_DEVAD,
2630 0xca13,
2631 &tmp1);
2632
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002633 bnx2x_cl45_read(bp, params->port,
2634 ext_phy_type,
2635 ext_phy_addr,
2636 MDIO_PMA_DEVAD,
2637 MDIO_PMA_REG_RX_ALARM, &tmp1);
2638
2639 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
2640 "0x%x\n", tmp1);
2641
2642 /* If this is forced speed, set to KR or KX
2643 * (all other are not supported)
2644 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002645 if (params->loopback_mode == LOOPBACK_EXT) {
2646 bnx2x_bcm807x_force_10G(params);
2647 DP(NETIF_MSG_LINK,
2648 "Forced speed 10G on 807X\n");
2649 break;
2650 } else {
2651 bnx2x_cl45_write(bp, params->port,
2652 ext_phy_type, ext_phy_addr,
2653 MDIO_PMA_DEVAD,
2654 MDIO_PMA_REG_BCM_CTRL,
2655 0x0002);
2656 }
2657 if (params->req_line_speed != SPEED_AUTO_NEG) {
2658 if (params->req_line_speed == SPEED_10000) {
2659 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002660 } else if (params->req_line_speed ==
2661 SPEED_2500) {
2662 val = (1<<5);
2663 /* Note that 2.5G works only
2664 when used with 1G advertisment */
2665 } else
2666 val = (1<<5);
2667 } else {
2668
2669 val = 0;
2670 if (params->speed_cap_mask &
2671 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
2672 val |= (1<<7);
2673
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002674 /* Note that 2.5G works only when
2675 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002676 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002677 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
2678 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002679 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002680 DP(NETIF_MSG_LINK,
2681 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002682 }
2683
2684 bnx2x_cl45_write(bp, params->port,
2685 ext_phy_type,
2686 ext_phy_addr,
2687 MDIO_AN_DEVAD,
2688 MDIO_AN_REG_ADV, val);
2689
2690 if (ext_phy_type ==
2691 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002692
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002693 bnx2x_cl45_read(bp, params->port,
2694 ext_phy_type,
2695 ext_phy_addr,
2696 MDIO_AN_DEVAD,
2697 0x8329, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002698
2699 if (((params->speed_cap_mask &
2700 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
2701 (params->req_line_speed ==
2702 SPEED_AUTO_NEG)) ||
2703 (params->req_line_speed ==
2704 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002705 u16 phy_ver;
2706 /* Allow 2.5G for A1 and above */
2707 bnx2x_cl45_read(bp, params->port,
2708 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2709 ext_phy_addr,
2710 MDIO_PMA_DEVAD,
2711 0xc801, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002712 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002713 if (phy_ver > 0)
2714 tmp1 |= 1;
2715 else
2716 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002717 } else {
2718 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002719 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002720 }
2721
2722 bnx2x_cl45_write(bp, params->port,
2723 ext_phy_type,
2724 ext_phy_addr,
2725 MDIO_AN_DEVAD,
2726 0x8329, tmp1);
2727 }
2728
2729 /* Add support for CL37 (passive mode) II */
2730
2731 bnx2x_cl45_read(bp, params->port,
2732 ext_phy_type,
2733 ext_phy_addr,
2734 MDIO_AN_DEVAD,
2735 MDIO_AN_REG_CL37_FC_LD,
2736 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002737
2738 bnx2x_cl45_write(bp, params->port,
2739 ext_phy_type,
2740 ext_phy_addr,
2741 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002742 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
2743 ((params->req_duplex == DUPLEX_FULL) ?
2744 0x20 : 0x40)));
2745
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002746 /* Add support for CL37 (passive mode) III */
2747 bnx2x_cl45_write(bp, params->port,
2748 ext_phy_type,
2749 ext_phy_addr,
2750 MDIO_AN_DEVAD,
2751 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002752
2753 if (ext_phy_type ==
2754 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002755 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002756 BW and FEE main tap. Rest commands are executed
2757 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002758 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002759 if (bnx2x_8073_is_snr_needed(params))
2760 bnx2x_cl45_write(bp, params->port,
2761 ext_phy_type,
2762 ext_phy_addr,
2763 MDIO_PMA_DEVAD,
2764 MDIO_PMA_REG_EDC_FFE_MAIN,
2765 0xFB0C);
2766
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002767 /* Enable FEC (Forware Error Correction)
2768 Request in the AN */
2769 bnx2x_cl45_read(bp, params->port,
2770 ext_phy_type,
2771 ext_phy_addr,
2772 MDIO_AN_DEVAD,
2773 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002774
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002775 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002776
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002777 bnx2x_cl45_write(bp, params->port,
2778 ext_phy_type,
2779 ext_phy_addr,
2780 MDIO_AN_DEVAD,
2781 MDIO_AN_REG_ADV2, tmp1);
2782
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002783 }
2784
2785 bnx2x_ext_phy_set_pause(params, vars);
2786
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002787 /* Restart autoneg */
2788 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002789 bnx2x_cl45_write(bp, params->port,
2790 ext_phy_type,
2791 ext_phy_addr,
2792 MDIO_AN_DEVAD,
2793 MDIO_AN_REG_CTRL, 0x1200);
2794 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
2795 "Advertise 1G=%x, 10G=%x\n",
2796 ((val & (1<<5)) > 0),
2797 ((val & (1<<7)) > 0));
2798 break;
2799 }
2800 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
2801 DP(NETIF_MSG_LINK,
2802 "Setting the SFX7101 LASI indication\n");
2803
2804 bnx2x_cl45_write(bp, params->port,
2805 ext_phy_type,
2806 ext_phy_addr,
2807 MDIO_PMA_DEVAD,
2808 MDIO_PMA_REG_LASI_CTRL, 0x1);
2809 DP(NETIF_MSG_LINK,
2810 "Setting the SFX7101 LED to blink on traffic\n");
2811 bnx2x_cl45_write(bp, params->port,
2812 ext_phy_type,
2813 ext_phy_addr,
2814 MDIO_PMA_DEVAD,
2815 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
2816
2817 bnx2x_ext_phy_set_pause(params, vars);
2818 /* Restart autoneg */
2819 bnx2x_cl45_read(bp, params->port,
2820 ext_phy_type,
2821 ext_phy_addr,
2822 MDIO_AN_DEVAD,
2823 MDIO_AN_REG_CTRL, &val);
2824 val |= 0x200;
2825 bnx2x_cl45_write(bp, params->port,
2826 ext_phy_type,
2827 ext_phy_addr,
2828 MDIO_AN_DEVAD,
2829 MDIO_AN_REG_CTRL, val);
2830 break;
2831 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
2832 DP(NETIF_MSG_LINK,
2833 "XGXS PHY Failure detected 0x%x\n",
2834 params->ext_phy_config);
2835 rc = -EINVAL;
2836 break;
2837 default:
2838 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
2839 params->ext_phy_config);
2840 rc = -EINVAL;
2841 break;
2842 }
2843
2844 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002845
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002846 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
2847 switch (ext_phy_type) {
2848 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
2849 DP(NETIF_MSG_LINK, "SerDes Direct\n");
2850 break;
2851
2852 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
2853 DP(NETIF_MSG_LINK, "SerDes 5482\n");
2854 break;
2855
2856 default:
2857 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
2858 params->ext_phy_config);
2859 break;
2860 }
2861 }
2862 return rc;
2863}
2864
2865
2866static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002867 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002868{
2869 struct bnx2x *bp = params->bp;
2870 u32 ext_phy_type;
2871 u8 ext_phy_addr;
2872 u16 val1 = 0, val2;
2873 u16 rx_sd, pcs_status;
2874 u8 ext_phy_link_up = 0;
2875 u8 port = params->port;
2876 if (vars->phy_flags & PHY_XGXS_FLAG) {
2877 ext_phy_addr = ((params->ext_phy_config &
2878 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2879 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2880
2881 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2882 switch (ext_phy_type) {
2883 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
2884 DP(NETIF_MSG_LINK, "XGXS Direct\n");
2885 ext_phy_link_up = 1;
2886 break;
2887
2888 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2889 DP(NETIF_MSG_LINK, "XGXS 8705\n");
2890 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2891 ext_phy_addr,
2892 MDIO_WIS_DEVAD,
2893 MDIO_WIS_REG_LASI_STATUS, &val1);
2894 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
2895
2896 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2897 ext_phy_addr,
2898 MDIO_WIS_DEVAD,
2899 MDIO_WIS_REG_LASI_STATUS, &val1);
2900 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
2901
2902 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2903 ext_phy_addr,
2904 MDIO_PMA_DEVAD,
2905 MDIO_PMA_REG_RX_SD, &rx_sd);
2906 DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
2907 ext_phy_link_up = (rx_sd & 0x1);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002908 if (ext_phy_link_up)
2909 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002910 break;
2911
2912 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2913 DP(NETIF_MSG_LINK, "XGXS 8706\n");
2914 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2915 ext_phy_addr,
2916 MDIO_PMA_DEVAD,
2917 MDIO_PMA_REG_LASI_STATUS, &val1);
2918 DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
2919
2920 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2921 ext_phy_addr,
2922 MDIO_PMA_DEVAD,
2923 MDIO_PMA_REG_LASI_STATUS, &val1);
2924 DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
2925
2926 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2927 ext_phy_addr,
2928 MDIO_PMA_DEVAD,
2929 MDIO_PMA_REG_RX_SD, &rx_sd);
2930 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2931 ext_phy_addr,
2932 MDIO_PCS_DEVAD,
2933 MDIO_PCS_REG_STATUS, &pcs_status);
2934
2935 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2936 ext_phy_addr,
2937 MDIO_AN_DEVAD,
2938 MDIO_AN_REG_LINK_STATUS, &val2);
2939 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2940 ext_phy_addr,
2941 MDIO_AN_DEVAD,
2942 MDIO_AN_REG_LINK_STATUS, &val2);
2943
2944 DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x"
2945 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
2946 rx_sd, pcs_status, val2);
2947 /* link is up if both bit 0 of pmd_rx_sd and
2948 * bit 0 of pcs_status are set, or if the autoneg bit
2949 1 is set
2950 */
2951 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
2952 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002953 if (ext_phy_link_up) {
2954 if (val2 & (1<<1))
2955 vars->line_speed = SPEED_1000;
2956 else
2957 vars->line_speed = SPEED_10000;
2958 }
2959
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002960 /* clear LASI indication*/
2961 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2962 ext_phy_addr,
2963 MDIO_PMA_DEVAD,
2964 MDIO_PMA_REG_RX_ALARM, &val2);
2965 break;
2966
2967 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
2968 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
2969 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002970 u16 link_status = 0;
2971 u16 an1000_status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002972 if (ext_phy_type ==
2973 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
2974 bnx2x_cl45_read(bp, params->port,
2975 ext_phy_type,
2976 ext_phy_addr,
2977 MDIO_PCS_DEVAD,
2978 MDIO_PCS_REG_LASI_STATUS, &val1);
2979 bnx2x_cl45_read(bp, params->port,
2980 ext_phy_type,
2981 ext_phy_addr,
2982 MDIO_PCS_DEVAD,
2983 MDIO_PCS_REG_LASI_STATUS, &val2);
2984 DP(NETIF_MSG_LINK,
2985 "870x LASI status 0x%x->0x%x\n",
2986 val1, val2);
2987
2988 } else {
2989 /* In 8073, port1 is directed through emac0 and
2990 * port0 is directed through emac1
2991 */
2992 bnx2x_cl45_read(bp, params->port,
2993 ext_phy_type,
2994 ext_phy_addr,
2995 MDIO_PMA_DEVAD,
2996 MDIO_PMA_REG_LASI_STATUS, &val1);
2997
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002998 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002999 "8703 LASI status 0x%x\n",
3000 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003001 }
3002
3003 /* clear the interrupt LASI status register */
3004 bnx2x_cl45_read(bp, params->port,
3005 ext_phy_type,
3006 ext_phy_addr,
3007 MDIO_PCS_DEVAD,
3008 MDIO_PCS_REG_STATUS, &val2);
3009 bnx2x_cl45_read(bp, params->port,
3010 ext_phy_type,
3011 ext_phy_addr,
3012 MDIO_PCS_DEVAD,
3013 MDIO_PCS_REG_STATUS, &val1);
3014 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
3015 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003016 /* Clear MSG-OUT */
3017 bnx2x_cl45_read(bp, params->port,
3018 ext_phy_type,
3019 ext_phy_addr,
3020 MDIO_PMA_DEVAD,
3021 0xca13,
3022 &val1);
3023
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003024 /* Check the LASI */
3025 bnx2x_cl45_read(bp, params->port,
3026 ext_phy_type,
3027 ext_phy_addr,
3028 MDIO_PMA_DEVAD,
3029 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003030
3031 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3032
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003033 /* Check the link status */
3034 bnx2x_cl45_read(bp, params->port,
3035 ext_phy_type,
3036 ext_phy_addr,
3037 MDIO_PCS_DEVAD,
3038 MDIO_PCS_REG_STATUS, &val2);
3039 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3040
3041 bnx2x_cl45_read(bp, params->port,
3042 ext_phy_type,
3043 ext_phy_addr,
3044 MDIO_PMA_DEVAD,
3045 MDIO_PMA_REG_STATUS, &val2);
3046 bnx2x_cl45_read(bp, params->port,
3047 ext_phy_type,
3048 ext_phy_addr,
3049 MDIO_PMA_DEVAD,
3050 MDIO_PMA_REG_STATUS, &val1);
3051 ext_phy_link_up = ((val1 & 4) == 4);
3052 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3053 if (ext_phy_type ==
3054 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003055
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003056 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003057 ((params->req_line_speed !=
3058 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003059 if (bnx2x_bcm8073_xaui_wa(params)
3060 != 0) {
3061 ext_phy_link_up = 0;
3062 break;
3063 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003064 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003065 bnx2x_cl45_read(bp, params->port,
3066 ext_phy_type,
3067 ext_phy_addr,
3068 MDIO_AN_DEVAD,
3069 0x8304,
3070 &an1000_status);
3071 bnx2x_cl45_read(bp, params->port,
3072 ext_phy_type,
3073 ext_phy_addr,
3074 MDIO_AN_DEVAD,
3075 0x8304,
3076 &an1000_status);
3077
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003078 /* Check the link status on 1.1.2 */
3079 bnx2x_cl45_read(bp, params->port,
3080 ext_phy_type,
3081 ext_phy_addr,
3082 MDIO_PMA_DEVAD,
3083 MDIO_PMA_REG_STATUS, &val2);
3084 bnx2x_cl45_read(bp, params->port,
3085 ext_phy_type,
3086 ext_phy_addr,
3087 MDIO_PMA_DEVAD,
3088 MDIO_PMA_REG_STATUS, &val1);
3089 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3090 "an_link_status=0x%x\n",
3091 val2, val1, an1000_status);
3092
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003093 ext_phy_link_up = (((val1 & 4) == 4) ||
3094 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003095 if (ext_phy_link_up &&
3096 bnx2x_8073_is_snr_needed(params)) {
3097 /* The SNR will improve about 2dbby
3098 changing the BW and FEE main tap.*/
3099
3100 /* The 1st write to change FFE main
3101 tap is set before restart AN */
3102 /* Change PLL Bandwidth in EDC
3103 register */
3104 bnx2x_cl45_write(bp, port, ext_phy_type,
3105 ext_phy_addr,
3106 MDIO_PMA_DEVAD,
3107 MDIO_PMA_REG_PLL_BANDWIDTH,
3108 0x26BC);
3109
3110 /* Change CDR Bandwidth in EDC
3111 register */
3112 bnx2x_cl45_write(bp, port, ext_phy_type,
3113 ext_phy_addr,
3114 MDIO_PMA_DEVAD,
3115 MDIO_PMA_REG_CDR_BANDWIDTH,
3116 0x0333);
3117
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003118
3119 }
3120 bnx2x_cl45_read(bp, params->port,
3121 ext_phy_type,
3122 ext_phy_addr,
3123 MDIO_PMA_DEVAD,
3124 0xc820,
3125 &link_status);
3126
3127 /* Bits 0..2 --> speed detected,
3128 bits 13..15--> link is down */
3129 if ((link_status & (1<<2)) &&
3130 (!(link_status & (1<<15)))) {
3131 ext_phy_link_up = 1;
3132 vars->line_speed = SPEED_10000;
3133 DP(NETIF_MSG_LINK,
3134 "port %x: External link"
3135 " up in 10G\n", params->port);
3136 } else if ((link_status & (1<<1)) &&
3137 (!(link_status & (1<<14)))) {
3138 ext_phy_link_up = 1;
3139 vars->line_speed = SPEED_2500;
3140 DP(NETIF_MSG_LINK,
3141 "port %x: External link"
3142 " up in 2.5G\n", params->port);
3143 } else if ((link_status & (1<<0)) &&
3144 (!(link_status & (1<<13)))) {
3145 ext_phy_link_up = 1;
3146 vars->line_speed = SPEED_1000;
3147 DP(NETIF_MSG_LINK,
3148 "port %x: External link"
3149 " up in 1G\n", params->port);
3150 } else {
3151 ext_phy_link_up = 0;
3152 DP(NETIF_MSG_LINK,
3153 "port %x: External link"
3154 " is down\n", params->port);
3155 }
3156 } else {
3157 /* See if 1G link is up for the 8072 */
3158 bnx2x_cl45_read(bp, params->port,
3159 ext_phy_type,
3160 ext_phy_addr,
3161 MDIO_AN_DEVAD,
3162 0x8304,
3163 &an1000_status);
3164 bnx2x_cl45_read(bp, params->port,
3165 ext_phy_type,
3166 ext_phy_addr,
3167 MDIO_AN_DEVAD,
3168 0x8304,
3169 &an1000_status);
3170 if (an1000_status & (1<<1)) {
3171 ext_phy_link_up = 1;
3172 vars->line_speed = SPEED_1000;
3173 DP(NETIF_MSG_LINK,
3174 "port %x: External link"
3175 " up in 1G\n", params->port);
3176 } else if (ext_phy_link_up) {
3177 ext_phy_link_up = 1;
3178 vars->line_speed = SPEED_10000;
3179 DP(NETIF_MSG_LINK,
3180 "port %x: External link"
3181 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003182 }
3183 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003184
3185
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003186 break;
3187 }
3188 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3189 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3190 ext_phy_addr,
3191 MDIO_PMA_DEVAD,
3192 MDIO_PMA_REG_LASI_STATUS, &val2);
3193 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3194 ext_phy_addr,
3195 MDIO_PMA_DEVAD,
3196 MDIO_PMA_REG_LASI_STATUS, &val1);
3197 DP(NETIF_MSG_LINK,
3198 "10G-base-T LASI status 0x%x->0x%x\n",
3199 val2, val1);
3200 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3201 ext_phy_addr,
3202 MDIO_PMA_DEVAD,
3203 MDIO_PMA_REG_STATUS, &val2);
3204 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3205 ext_phy_addr,
3206 MDIO_PMA_DEVAD,
3207 MDIO_PMA_REG_STATUS, &val1);
3208 DP(NETIF_MSG_LINK,
3209 "10G-base-T PMA status 0x%x->0x%x\n",
3210 val2, val1);
3211 ext_phy_link_up = ((val1 & 4) == 4);
3212 /* if link is up
3213 * print the AN outcome of the SFX7101 PHY
3214 */
3215 if (ext_phy_link_up) {
3216 bnx2x_cl45_read(bp, params->port,
3217 ext_phy_type,
3218 ext_phy_addr,
3219 MDIO_AN_DEVAD,
3220 MDIO_AN_REG_MASTER_STATUS,
3221 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003222 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003223 DP(NETIF_MSG_LINK,
3224 "SFX7101 AN status 0x%x->Master=%x\n",
3225 val2,
3226 (val2 & (1<<14)));
3227 }
3228 break;
3229
3230 default:
3231 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3232 params->ext_phy_config);
3233 ext_phy_link_up = 0;
3234 break;
3235 }
3236
3237 } else { /* SerDes */
3238 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3239 switch (ext_phy_type) {
3240 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3241 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3242 ext_phy_link_up = 1;
3243 break;
3244
3245 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3246 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3247 ext_phy_link_up = 1;
3248 break;
3249
3250 default:
3251 DP(NETIF_MSG_LINK,
3252 "BAD SerDes ext_phy_config 0x%x\n",
3253 params->ext_phy_config);
3254 ext_phy_link_up = 0;
3255 break;
3256 }
3257 }
3258
3259 return ext_phy_link_up;
3260}
3261
3262static void bnx2x_link_int_enable(struct link_params *params)
3263{
3264 u8 port = params->port;
3265 u32 ext_phy_type;
3266 u32 mask;
3267 struct bnx2x *bp = params->bp;
3268 /* setting the status to report on link up
3269 for either XGXS or SerDes */
3270
3271 if (params->switch_cfg == SWITCH_CFG_10G) {
3272 mask = (NIG_MASK_XGXS0_LINK10G |
3273 NIG_MASK_XGXS0_LINK_STATUS);
3274 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
3275 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3276 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3277 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3278 (ext_phy_type !=
3279 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
3280 mask |= NIG_MASK_MI_INT;
3281 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3282 }
3283
3284 } else { /* SerDes */
3285 mask = NIG_MASK_SERDES0_LINK_STATUS;
3286 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
3287 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3288 if ((ext_phy_type !=
3289 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
3290 (ext_phy_type !=
3291 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
3292 mask |= NIG_MASK_MI_INT;
3293 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3294 }
3295 }
3296 bnx2x_bits_en(bp,
3297 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
3298 mask);
3299 DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port,
3300 (params->switch_cfg == SWITCH_CFG_10G),
3301 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
3302
3303 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
3304 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3305 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
3306 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
3307 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
3308 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
3309 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
3310}
3311
3312
3313/*
3314 * link management
3315 */
3316static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07003317 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003318{
3319 struct bnx2x *bp = params->bp;
3320 u8 port = params->port;
3321
3322 /* first reset all status
3323 * we assume only one line will be change at a time */
3324 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3325 (NIG_STATUS_XGXS0_LINK10G |
3326 NIG_STATUS_XGXS0_LINK_STATUS |
3327 NIG_STATUS_SERDES0_LINK_STATUS));
3328 if (vars->phy_link_up) {
3329 if (is_10g) {
3330 /* Disable the 10G link interrupt
3331 * by writing 1 to the status register
3332 */
3333 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
3334 bnx2x_bits_en(bp,
3335 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3336 NIG_STATUS_XGXS0_LINK10G);
3337
3338 } else if (params->switch_cfg == SWITCH_CFG_10G) {
3339 /* Disable the link interrupt
3340 * by writing 1 to the relevant lane
3341 * in the status register
3342 */
3343 u32 ser_lane = ((params->lane_config &
3344 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
3345 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
3346
3347 DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
3348 bnx2x_bits_en(bp,
3349 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3350 ((1 << ser_lane) <<
3351 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
3352
3353 } else { /* SerDes */
3354 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
3355 /* Disable the link interrupt
3356 * by writing 1 to the status register
3357 */
3358 bnx2x_bits_en(bp,
3359 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3360 NIG_STATUS_SERDES0_LINK_STATUS);
3361 }
3362
3363 } else { /* link_down */
3364 }
3365}
3366
3367static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
3368{
3369 u8 *str_ptr = str;
3370 u32 mask = 0xf0000000;
3371 u8 shift = 8*4;
3372 u8 digit;
3373 if (len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02003374 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003375 *str_ptr = '\0';
3376 return -EINVAL;
3377 }
3378 while (shift > 0) {
3379
3380 shift -= 4;
3381 digit = ((num & mask) >> shift);
3382 if (digit < 0xa)
3383 *str_ptr = digit + '0';
3384 else
3385 *str_ptr = digit - 0xa + 'a';
3386 str_ptr++;
3387 mask = mask >> 4;
3388 if (shift == 4*4) {
3389 *str_ptr = ':';
3390 str_ptr++;
3391 }
3392 }
3393 *str_ptr = '\0';
3394 return 0;
3395}
3396
3397
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003398static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr,
3399 u32 ext_phy_type)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003400{
3401 u32 cnt = 0;
3402 u16 ctrl = 0;
3403 /* Enable EMAC0 in to enable MDIO */
3404 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
3405 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
3406 msleep(5);
3407
3408 /* take ext phy out of reset */
3409 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003410 MISC_REGISTERS_GPIO_2,
3411 MISC_REGISTERS_GPIO_HIGH,
3412 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003413
3414 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003415 MISC_REGISTERS_GPIO_1,
3416 MISC_REGISTERS_GPIO_HIGH,
3417 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003418
3419 /* wait for 5ms */
3420 msleep(5);
3421
3422 for (cnt = 0; cnt < 1000; cnt++) {
3423 msleep(1);
3424 bnx2x_cl45_read(bp, port,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003425 ext_phy_type,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003426 ext_phy_addr,
3427 MDIO_PMA_DEVAD,
3428 MDIO_PMA_REG_CTRL,
3429 &ctrl);
3430 if (!(ctrl & (1<<15))) {
3431 DP(NETIF_MSG_LINK, "Reset completed\n\n");
3432 break;
3433 }
3434 }
3435}
3436
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003437static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003438{
3439 /* put sf to reset */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003440 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003441 MISC_REGISTERS_GPIO_1,
3442 MISC_REGISTERS_GPIO_LOW,
3443 port);
3444 bnx2x_set_gpio(bp,
3445 MISC_REGISTERS_GPIO_2,
3446 MISC_REGISTERS_GPIO_LOW,
3447 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003448}
3449
3450u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
3451 u8 *version, u16 len)
3452{
3453 struct bnx2x *bp = params->bp;
3454 u32 ext_phy_type = 0;
3455 u16 val = 0;
3456 u8 ext_phy_addr = 0 ;
3457 u8 status = 0 ;
3458 u32 ver_num;
3459
3460 if (version == NULL || params == NULL)
3461 return -EINVAL;
3462
3463 /* reset the returned value to zero */
3464 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3465 ext_phy_addr = ((params->ext_phy_config &
3466 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3467 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3468
3469 switch (ext_phy_type) {
3470 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3471
3472 if (len < 5)
3473 return -EINVAL;
3474
3475 /* Take ext phy out of reset */
3476 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003477 bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
3478 ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003479
3480 /* wait for 1ms */
3481 msleep(1);
3482
3483 bnx2x_cl45_read(bp, params->port,
3484 ext_phy_type,
3485 ext_phy_addr,
3486 MDIO_PMA_DEVAD,
3487 MDIO_PMA_REG_7101_VER1, &val);
3488 version[2] = (val & 0xFF);
3489 version[3] = ((val & 0xFF00)>>8);
3490
3491 bnx2x_cl45_read(bp, params->port,
3492 ext_phy_type,
3493 ext_phy_addr,
3494 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2,
3495 &val);
3496 version[0] = (val & 0xFF);
3497 version[1] = ((val & 0xFF00)>>8);
3498 version[4] = '\0';
3499
3500 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003501 bnx2x_turn_off_sf(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003502 break;
3503 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3504 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3505 {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003506 /* Take ext phy out of reset */
3507 if (!driver_loaded)
3508 bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
3509 ext_phy_type);
3510
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003511 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3512 ext_phy_addr,
3513 MDIO_PMA_DEVAD,
3514 MDIO_PMA_REG_ROM_VER1, &val);
3515 ver_num = val<<16;
3516 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3517 ext_phy_addr,
3518 MDIO_PMA_DEVAD,
3519 MDIO_PMA_REG_ROM_VER2, &val);
3520 ver_num |= val;
3521 status = bnx2x_format_ver(ver_num, version, len);
3522 break;
3523 }
3524 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3525 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
3526
3527 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3528 ext_phy_addr,
3529 MDIO_PMA_DEVAD,
3530 MDIO_PMA_REG_ROM_VER1, &val);
3531 ver_num = val<<16;
3532 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3533 ext_phy_addr,
3534 MDIO_PMA_DEVAD,
3535 MDIO_PMA_REG_ROM_VER2, &val);
3536 ver_num |= val;
3537 status = bnx2x_format_ver(ver_num, version, len);
3538 break;
3539
3540 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3541 break;
3542
3543 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
3544 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
3545 " type is FAILURE!\n");
3546 status = -EINVAL;
3547 break;
3548
3549 default:
3550 break;
3551 }
3552 return status;
3553}
3554
3555static void bnx2x_set_xgxs_loopback(struct link_params *params,
3556 struct link_vars *vars,
3557 u8 is_10g)
3558{
3559 u8 port = params->port;
3560 struct bnx2x *bp = params->bp;
3561
3562 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07003563 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003564
3565 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
3566
3567 /* change the uni_phy_addr in the nig */
3568 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
3569 port*0x18));
3570
3571 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
3572
3573 bnx2x_cl45_write(bp, port, 0,
3574 params->phy_addr,
3575 5,
3576 (MDIO_REG_BANK_AER_BLOCK +
3577 (MDIO_AER_BLOCK_AER_REG & 0xf)),
3578 0x2800);
3579
3580 bnx2x_cl45_write(bp, port, 0,
3581 params->phy_addr,
3582 5,
3583 (MDIO_REG_BANK_CL73_IEEEB0 +
3584 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
3585 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00003586 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003587 /* set aer mmd back */
3588 bnx2x_set_aer_mmd(params, vars);
3589
3590 /* and md_devad */
3591 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
3592 md_devad);
3593
3594 } else {
3595 u16 mii_control;
3596
3597 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
3598
3599 CL45_RD_OVER_CL22(bp, port,
3600 params->phy_addr,
3601 MDIO_REG_BANK_COMBO_IEEE0,
3602 MDIO_COMBO_IEEE0_MII_CONTROL,
3603 &mii_control);
3604
3605 CL45_WR_OVER_CL22(bp, port,
3606 params->phy_addr,
3607 MDIO_REG_BANK_COMBO_IEEE0,
3608 MDIO_COMBO_IEEE0_MII_CONTROL,
3609 (mii_control |
3610 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
3611 }
3612}
3613
3614
3615static void bnx2x_ext_phy_loopback(struct link_params *params)
3616{
3617 struct bnx2x *bp = params->bp;
3618 u8 ext_phy_addr;
3619 u32 ext_phy_type;
3620
3621 if (params->switch_cfg == SWITCH_CFG_10G) {
3622 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3623 /* CL37 Autoneg Enabled */
3624 ext_phy_addr = ((params->ext_phy_config &
3625 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3626 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3627 switch (ext_phy_type) {
3628 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3629 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
3630 DP(NETIF_MSG_LINK,
3631 "ext_phy_loopback: We should not get here\n");
3632 break;
3633 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3634 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
3635 break;
3636 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
3637 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
3638 break;
3639 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3640 /* SFX7101_XGXS_TEST1 */
3641 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3642 ext_phy_addr,
3643 MDIO_XS_DEVAD,
3644 MDIO_XS_SFX7101_XGXS_TEST1,
3645 0x100);
3646 DP(NETIF_MSG_LINK,
3647 "ext_phy_loopback: set ext phy loopback\n");
3648 break;
3649 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3650
3651 break;
3652 } /* switch external PHY type */
3653 } else {
3654 /* serdes */
3655 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3656 ext_phy_addr = (params->ext_phy_config &
3657 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
3658 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
3659 }
3660}
3661
3662
3663/*
3664 *------------------------------------------------------------------------
3665 * bnx2x_override_led_value -
3666 *
3667 * Override the led value of the requsted led
3668 *
3669 *------------------------------------------------------------------------
3670 */
3671u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
3672 u32 led_idx, u32 value)
3673{
3674 u32 reg_val;
3675
3676 /* If port 0 then use EMAC0, else use EMAC1*/
3677 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
3678
3679 DP(NETIF_MSG_LINK,
3680 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
3681 port, led_idx, value);
3682
3683 switch (led_idx) {
3684 case 0: /* 10MB led */
3685 /* Read the current value of the LED register in
3686 the EMAC block */
3687 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3688 /* Set the OVERRIDE bit to 1 */
3689 reg_val |= EMAC_LED_OVERRIDE;
3690 /* If value is 1, set the 10M_OVERRIDE bit,
3691 otherwise reset it.*/
3692 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
3693 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
3694 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3695 break;
3696 case 1: /*100MB led */
3697 /*Read the current value of the LED register in
3698 the EMAC block */
3699 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3700 /* Set the OVERRIDE bit to 1 */
3701 reg_val |= EMAC_LED_OVERRIDE;
3702 /* If value is 1, set the 100M_OVERRIDE bit,
3703 otherwise reset it.*/
3704 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
3705 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
3706 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3707 break;
3708 case 2: /* 1000MB led */
3709 /* Read the current value of the LED register in the
3710 EMAC block */
3711 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3712 /* Set the OVERRIDE bit to 1 */
3713 reg_val |= EMAC_LED_OVERRIDE;
3714 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
3715 reset it. */
3716 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
3717 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
3718 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3719 break;
3720 case 3: /* 2500MB led */
3721 /* Read the current value of the LED register in the
3722 EMAC block*/
3723 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3724 /* Set the OVERRIDE bit to 1 */
3725 reg_val |= EMAC_LED_OVERRIDE;
3726 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
3727 reset it.*/
3728 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
3729 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
3730 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3731 break;
3732 case 4: /*10G led */
3733 if (port == 0) {
3734 REG_WR(bp, NIG_REG_LED_10G_P0,
3735 value);
3736 } else {
3737 REG_WR(bp, NIG_REG_LED_10G_P1,
3738 value);
3739 }
3740 break;
3741 case 5: /* TRAFFIC led */
3742 /* Find if the traffic control is via BMAC or EMAC */
3743 if (port == 0)
3744 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
3745 else
3746 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
3747
3748 /* Override the traffic led in the EMAC:*/
3749 if (reg_val == 1) {
3750 /* Read the current value of the LED register in
3751 the EMAC block */
3752 reg_val = REG_RD(bp, emac_base +
3753 EMAC_REG_EMAC_LED);
3754 /* Set the TRAFFIC_OVERRIDE bit to 1 */
3755 reg_val |= EMAC_LED_OVERRIDE;
3756 /* If value is 1, set the TRAFFIC bit, otherwise
3757 reset it.*/
3758 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
3759 (reg_val & ~EMAC_LED_TRAFFIC);
3760 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3761 } else { /* Override the traffic led in the BMAC: */
3762 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
3763 + port*4, 1);
3764 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
3765 value);
3766 }
3767 break;
3768 default:
3769 DP(NETIF_MSG_LINK,
3770 "bnx2x_override_led_value() unknown led index %d "
3771 "(should be 0-5)\n", led_idx);
3772 return -EINVAL;
3773 }
3774
3775 return 0;
3776}
3777
3778
3779u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
3780 u16 hw_led_mode, u32 chip_id)
3781{
3782 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003783 u32 tmp;
3784 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003785 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
3786 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
3787 speed, hw_led_mode);
3788 switch (mode) {
3789 case LED_MODE_OFF:
3790 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
3791 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
3792 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003793
3794 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003795 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003796 break;
3797
3798 case LED_MODE_OPER:
3799 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
3800 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
3801 port*4, 0);
3802 /* Set blinking rate to ~15.9Hz */
3803 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
3804 LED_BLINK_RATE_VAL);
3805 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
3806 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003807 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003808 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003809 (tmp & (~EMAC_LED_OVERRIDE)));
3810
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003811 if (!CHIP_IS_E1H(bp) &&
3812 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003813 (speed == SPEED_1000) ||
3814 (speed == SPEED_100) ||
3815 (speed == SPEED_10))) {
3816 /* On Everest 1 Ax chip versions for speeds less than
3817 10G LED scheme is different */
3818 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
3819 + port*4, 1);
3820 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
3821 port*4, 0);
3822 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
3823 port*4, 1);
3824 }
3825 break;
3826
3827 default:
3828 rc = -EINVAL;
3829 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
3830 mode);
3831 break;
3832 }
3833 return rc;
3834
3835}
3836
3837u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
3838{
3839 struct bnx2x *bp = params->bp;
3840 u16 gp_status = 0;
3841
3842 CL45_RD_OVER_CL22(bp, params->port,
3843 params->phy_addr,
3844 MDIO_REG_BANK_GP_STATUS,
3845 MDIO_GP_STATUS_TOP_AN_STATUS1,
3846 &gp_status);
3847 /* link is up only if both local phy and external phy are up */
3848 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
3849 bnx2x_ext_phy_is_link_up(params, vars))
3850 return 0;
3851
3852 return -ESRCH;
3853}
3854
3855static u8 bnx2x_link_initialize(struct link_params *params,
3856 struct link_vars *vars)
3857{
3858 struct bnx2x *bp = params->bp;
3859 u8 port = params->port;
3860 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003861 u8 non_ext_phy;
3862 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003863 /* Activate the external PHY */
3864 bnx2x_ext_phy_reset(params, vars);
3865
3866 bnx2x_set_aer_mmd(params, vars);
3867
3868 if (vars->phy_flags & PHY_XGXS_FLAG)
3869 bnx2x_set_master_ln(params);
3870
3871 rc = bnx2x_reset_unicore(params);
3872 /* reset the SerDes and wait for reset bit return low */
3873 if (rc != 0)
3874 return rc;
3875
3876 bnx2x_set_aer_mmd(params, vars);
3877
3878 /* setting the masterLn_def again after the reset */
3879 if (vars->phy_flags & PHY_XGXS_FLAG) {
3880 bnx2x_set_master_ln(params);
3881 bnx2x_set_swap_lanes(params);
3882 }
3883
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003884 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00003885 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003886 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00003887 (params->req_line_speed == SPEED_10))) ||
3888 (!params->req_line_speed &&
3889 (params->speed_cap_mask >=
3890 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
3891 (params->speed_cap_mask <
3892 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
3893 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003894 vars->phy_flags |= PHY_SGMII_FLAG;
3895 } else {
3896 vars->phy_flags &= ~PHY_SGMII_FLAG;
3897 }
3898 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003899 /* In case of external phy existance, the line speed would be the
3900 line speed linked up by the external phy. In case it is direct only,
3901 then the line_speed during initialization will be equal to the
3902 req_line_speed*/
3903 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003904
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003905 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003906
3907 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003908 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
3909 (params->loopback_mode == LOOPBACK_XGXS_10) ||
3910 (params->loopback_mode == LOOPBACK_EXT_PHY));
3911
3912 if (non_ext_phy ||
3913 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705)) {
3914 if (params->req_line_speed == SPEED_AUTO_NEG)
3915 bnx2x_set_parallel_detection(params, vars->phy_flags);
3916 bnx2x_init_internal_phy(params, vars);
3917 }
3918
3919 if (!non_ext_phy)
3920 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003921
3922 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003923 (NIG_STATUS_XGXS0_LINK10G |
3924 NIG_STATUS_XGXS0_LINK_STATUS |
3925 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003926
3927 return rc;
3928
3929}
3930
3931
3932u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
3933{
3934 struct bnx2x *bp = params->bp;
3935
3936 u32 val;
Eilon Greenstein3196a882008-08-13 15:58:49 -07003937 DP(NETIF_MSG_LINK, "Phy Initialization started \n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003938 DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
3939 params->req_line_speed, params->req_flow_ctrl);
3940 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003941 vars->phy_link_up = 0;
3942 vars->link_up = 0;
3943 vars->line_speed = 0;
3944 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08003945 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003946 vars->mac_type = MAC_TYPE_NONE;
3947
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003948 if (params->switch_cfg == SWITCH_CFG_1G)
3949 vars->phy_flags = PHY_SERDES_FLAG;
3950 else
3951 vars->phy_flags = PHY_XGXS_FLAG;
3952
Eilon Greenstein3196a882008-08-13 15:58:49 -07003953
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003954 /* disable attentions */
3955 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
3956 (NIG_MASK_XGXS0_LINK_STATUS |
3957 NIG_MASK_XGXS0_LINK10G |
3958 NIG_MASK_SERDES0_LINK_STATUS |
3959 NIG_MASK_MI_INT));
3960
3961 bnx2x_emac_init(params, vars);
3962
3963 if (CHIP_REV_IS_FPGA(bp)) {
3964 vars->link_up = 1;
3965 vars->line_speed = SPEED_10000;
3966 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08003967 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003968 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003969 /* enable on E1.5 FPGA */
3970 if (CHIP_IS_E1H(bp)) {
3971 vars->flow_ctrl |=
David S. Millerc0700f92008-12-16 23:53:20 -08003972 (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003973 vars->link_status |=
3974 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
3975 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
3976 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003977
3978 bnx2x_emac_enable(params, vars, 0);
3979 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
3980 /* disable drain */
3981 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3982 + params->port*4, 0);
3983
3984 /* update shared memory */
3985 bnx2x_update_mng(params, vars->link_status);
3986
3987 return 0;
3988
3989 } else
3990 if (CHIP_REV_IS_EMUL(bp)) {
3991
3992 vars->link_up = 1;
3993 vars->line_speed = SPEED_10000;
3994 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08003995 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003996 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
3997
3998 bnx2x_bmac_enable(params, vars, 0);
3999
4000 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4001 /* Disable drain */
4002 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4003 + params->port*4, 0);
4004
4005 /* update shared memory */
4006 bnx2x_update_mng(params, vars->link_status);
4007
4008 return 0;
4009
4010 } else
4011 if (params->loopback_mode == LOOPBACK_BMAC) {
4012 vars->link_up = 1;
4013 vars->line_speed = SPEED_10000;
4014 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004015 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004016 vars->mac_type = MAC_TYPE_BMAC;
4017
4018 vars->phy_flags = PHY_XGXS_FLAG;
4019
4020 bnx2x_phy_deassert(params, vars->phy_flags);
4021 /* set bmac loopback */
4022 bnx2x_bmac_enable(params, vars, 1);
4023
4024 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4025 params->port*4, 0);
4026 } else if (params->loopback_mode == LOOPBACK_EMAC) {
4027 vars->link_up = 1;
4028 vars->line_speed = SPEED_1000;
4029 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004030 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004031 vars->mac_type = MAC_TYPE_EMAC;
4032
4033 vars->phy_flags = PHY_XGXS_FLAG;
4034
4035 bnx2x_phy_deassert(params, vars->phy_flags);
4036 /* set bmac loopback */
4037 bnx2x_emac_enable(params, vars, 1);
4038 bnx2x_emac_program(params, vars->line_speed,
4039 vars->duplex);
4040 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4041 params->port*4, 0);
4042 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
4043 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
4044 vars->link_up = 1;
4045 vars->line_speed = SPEED_10000;
4046 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004047 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004048
4049 vars->phy_flags = PHY_XGXS_FLAG;
4050
4051 val = REG_RD(bp,
4052 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4053 params->port*0x18);
4054 params->phy_addr = (u8)val;
4055
4056 bnx2x_phy_deassert(params, vars->phy_flags);
4057 bnx2x_link_initialize(params, vars);
4058
4059 vars->mac_type = MAC_TYPE_BMAC;
4060
4061 bnx2x_bmac_enable(params, vars, 0);
4062
4063 if (params->loopback_mode == LOOPBACK_XGXS_10) {
4064 /* set 10G XGXS loopback */
4065 bnx2x_set_xgxs_loopback(params, vars, 1);
4066 } else {
4067 /* set external phy loopback */
4068 bnx2x_ext_phy_loopback(params);
4069 }
4070 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4071 params->port*4, 0);
4072 } else
4073 /* No loopback */
4074 {
4075
4076 bnx2x_phy_deassert(params, vars->phy_flags);
4077 switch (params->switch_cfg) {
4078 case SWITCH_CFG_1G:
4079 vars->phy_flags |= PHY_SERDES_FLAG;
4080 if ((params->ext_phy_config &
4081 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
4082 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
4083 vars->phy_flags |=
4084 PHY_SGMII_FLAG;
4085 }
4086
4087 val = REG_RD(bp,
4088 NIG_REG_SERDES0_CTRL_PHY_ADDR+
4089 params->port*0x10);
4090
4091 params->phy_addr = (u8)val;
4092
4093 break;
4094 case SWITCH_CFG_10G:
4095 vars->phy_flags |= PHY_XGXS_FLAG;
4096 val = REG_RD(bp,
4097 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4098 params->port*0x18);
4099 params->phy_addr = (u8)val;
4100
4101 break;
4102 default:
4103 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
4104 return -EINVAL;
4105 break;
4106 }
4107
4108 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004109 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004110 bnx2x_link_int_enable(params);
4111 }
4112 return 0;
4113}
4114
4115u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars)
4116{
4117
4118 struct bnx2x *bp = params->bp;
4119 u32 ext_phy_config = params->ext_phy_config;
4120 u16 hw_led_mode = params->hw_led_mode;
4121 u32 chip_id = params->chip_id;
4122 u8 port = params->port;
4123 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4124 /* disable attentions */
4125
4126 vars->link_status = 0;
4127 bnx2x_update_mng(params, vars->link_status);
4128 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4129 (NIG_MASK_XGXS0_LINK_STATUS |
4130 NIG_MASK_XGXS0_LINK10G |
4131 NIG_MASK_SERDES0_LINK_STATUS |
4132 NIG_MASK_MI_INT));
4133
4134 /* activate nig drain */
4135 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4136
4137 /* disable nig egress interface */
4138 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4139 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4140
4141 /* Stop BigMac rx */
4142 bnx2x_bmac_rx_disable(bp, port);
4143
4144 /* disable emac */
4145 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4146
4147 msleep(10);
4148 /* The PHY reset is controled by GPIO 1
4149 * Hold it as vars low
4150 */
4151 /* clear link led */
4152 bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
4153 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
4154 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
4155 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
4156 /* HW reset */
4157
4158 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004159 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4160 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004161
4162 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004163 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4164 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004165
4166 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004167 } else if (ext_phy_type ==
4168 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
4169 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004170 "low power mode\n",
4171 port);
4172 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004173 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4174 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004175 }
4176 }
4177 /* reset the SerDes/XGXS */
4178 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
4179 (0x1ff << (port*16)));
4180
4181 /* reset BigMac */
4182 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
4183 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4184
4185 /* disable nig ingress interface */
4186 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
4187 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
4188 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4189 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4190 vars->link_up = 0;
4191 return 0;
4192}
4193
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004194static u8 bnx2x_update_link_down(struct link_params *params,
4195 struct link_vars *vars)
4196{
4197 struct bnx2x *bp = params->bp;
4198 u8 port = params->port;
4199 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
4200 bnx2x_set_led(bp, port, LED_MODE_OFF,
4201 0, params->hw_led_mode,
4202 params->chip_id);
4203
4204 /* indicate no mac active */
4205 vars->mac_type = MAC_TYPE_NONE;
4206
4207 /* update shared memory */
4208 vars->link_status = 0;
4209 vars->line_speed = 0;
4210 bnx2x_update_mng(params, vars->link_status);
4211
4212 /* activate nig drain */
4213 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4214
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004215 /* disable emac */
4216 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4217
4218 msleep(10);
4219
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004220 /* reset BigMac */
4221 bnx2x_bmac_rx_disable(bp, params->port);
4222 REG_WR(bp, GRCBASE_MISC +
4223 MISC_REGISTERS_RESET_REG_2_CLEAR,
4224 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4225 return 0;
4226}
4227
4228static u8 bnx2x_update_link_up(struct link_params *params,
4229 struct link_vars *vars,
4230 u8 link_10g, u32 gp_status)
4231{
4232 struct bnx2x *bp = params->bp;
4233 u8 port = params->port;
4234 u8 rc = 0;
4235 vars->link_status |= LINK_STATUS_LINK_UP;
4236 if (link_10g) {
4237 bnx2x_bmac_enable(params, vars, 0);
4238 bnx2x_set_led(bp, port, LED_MODE_OPER,
4239 SPEED_10000, params->hw_led_mode,
4240 params->chip_id);
4241
4242 } else {
4243 bnx2x_emac_enable(params, vars, 0);
4244 rc = bnx2x_emac_program(params, vars->line_speed,
4245 vars->duplex);
4246
4247 /* AN complete? */
4248 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
4249 if (!(vars->phy_flags &
4250 PHY_SGMII_FLAG))
4251 bnx2x_set_sgmii_tx_driver(params);
4252 }
4253 }
4254
4255 /* PBF - link up */
4256 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
4257 vars->line_speed);
4258
4259 /* disable drain */
4260 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
4261
4262 /* update shared memory */
4263 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004264 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004265 return rc;
4266}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004267/* This function should called upon link interrupt */
4268/* In case vars->link_up, driver needs to
4269 1. Update the pbf
4270 2. Disable drain
4271 3. Update the shared memory
4272 4. Indicate link up
4273 5. Set LEDs
4274 Otherwise,
4275 1. Update shared memory
4276 2. Reset BigMac
4277 3. Report link down
4278 4. Unset LEDs
4279*/
4280u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
4281{
4282 struct bnx2x *bp = params->bp;
4283 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004284 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004285 u8 link_10g;
4286 u8 ext_phy_link_up, rc = 0;
4287 u32 ext_phy_type;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004288
4289 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
4290 port,
4291 (vars->phy_flags & PHY_XGXS_FLAG),
4292 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
4293
4294 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
4295 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4296 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4297 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
4298
4299 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4300 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4301 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4302
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004303 /* disable emac */
4304 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4305
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004306 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004307
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004308 /* Check external link change only for non-direct */
4309 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
4310
4311 /* Read gp_status */
4312 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
4313 MDIO_REG_BANK_GP_STATUS,
4314 MDIO_GP_STATUS_TOP_AN_STATUS1,
4315 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004316
4317 rc = bnx2x_link_settings_status(params, vars, gp_status);
4318 if (rc != 0)
4319 return rc;
4320
4321 /* anything 10 and over uses the bmac */
4322 link_10g = ((vars->line_speed == SPEED_10000) ||
4323 (vars->line_speed == SPEED_12000) ||
4324 (vars->line_speed == SPEED_12500) ||
4325 (vars->line_speed == SPEED_13000) ||
4326 (vars->line_speed == SPEED_15000) ||
4327 (vars->line_speed == SPEED_16000));
4328
4329 bnx2x_link_int_ack(params, vars, link_10g);
4330
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004331 /* In case external phy link is up, and internal link is down
4332 ( not initialized yet probably after link initialization, it needs
4333 to be initialized.
4334 Note that after link down-up as result of cable plug,
4335 the xgxs link would probably become up again without the need to
4336 initialize it*/
4337
4338 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
4339 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
4340 (ext_phy_link_up && !vars->phy_link_up))
4341 bnx2x_init_internal_phy(params, vars);
4342
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004343 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004344 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004345
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004346 if (vars->link_up)
4347 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
4348 else
4349 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004350
4351 return rc;
4352}
4353
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004354static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
4355{
4356 u8 ext_phy_addr[PORT_MAX];
4357 u16 val;
4358 s8 port;
4359
4360 /* PART1 - Reset both phys */
4361 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4362 /* Extract the ext phy address for the port */
4363 u32 ext_phy_config = REG_RD(bp, shmem_base +
4364 offsetof(struct shmem_region,
4365 dev_info.port_hw_config[port].external_phy_config));
4366
4367 /* disable attentions */
4368 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4369 (NIG_MASK_XGXS0_LINK_STATUS |
4370 NIG_MASK_XGXS0_LINK10G |
4371 NIG_MASK_SERDES0_LINK_STATUS |
4372 NIG_MASK_MI_INT));
4373
4374 ext_phy_addr[port] =
4375 ((ext_phy_config &
4376 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4377 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4378
4379 /* Need to take the phy out of low power mode in order
4380 to write to access its registers */
4381 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4382 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
4383
4384 /* Reset the phy */
4385 bnx2x_cl45_write(bp, port,
4386 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4387 ext_phy_addr[port],
4388 MDIO_PMA_DEVAD,
4389 MDIO_PMA_REG_CTRL,
4390 1<<15);
4391 }
4392
4393 /* Add delay of 150ms after reset */
4394 msleep(150);
4395
4396 /* PART2 - Download firmware to both phys */
4397 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4398 u16 fw_ver1;
4399
4400 bnx2x_bcm8073_external_rom_boot(bp, port,
4401 ext_phy_addr[port]);
4402
4403 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4404 ext_phy_addr[port],
4405 MDIO_PMA_DEVAD,
4406 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00004407 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004408 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00004409 "bnx2x_8073_common_init_phy port %x:"
4410 "Download failed. fw version = 0x%x\n",
4411 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004412 return -EINVAL;
4413 }
4414
4415 /* Only set bit 10 = 1 (Tx power down) */
4416 bnx2x_cl45_read(bp, port,
4417 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4418 ext_phy_addr[port],
4419 MDIO_PMA_DEVAD,
4420 MDIO_PMA_REG_TX_POWER_DOWN, &val);
4421
4422 /* Phase1 of TX_POWER_DOWN reset */
4423 bnx2x_cl45_write(bp, port,
4424 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4425 ext_phy_addr[port],
4426 MDIO_PMA_DEVAD,
4427 MDIO_PMA_REG_TX_POWER_DOWN,
4428 (val | 1<<10));
4429 }
4430
4431 /* Toggle Transmitter: Power down and then up with 600ms
4432 delay between */
4433 msleep(600);
4434
4435 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
4436 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4437 /* Phase2 of POWER_DOWN_RESET*/
4438 /* Release bit 10 (Release Tx power down) */
4439 bnx2x_cl45_read(bp, port,
4440 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4441 ext_phy_addr[port],
4442 MDIO_PMA_DEVAD,
4443 MDIO_PMA_REG_TX_POWER_DOWN, &val);
4444
4445 bnx2x_cl45_write(bp, port,
4446 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4447 ext_phy_addr[port],
4448 MDIO_PMA_DEVAD,
4449 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
4450 msleep(15);
4451
4452 /* Read modify write the SPI-ROM version select register */
4453 bnx2x_cl45_read(bp, port,
4454 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4455 ext_phy_addr[port],
4456 MDIO_PMA_DEVAD,
4457 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
4458 bnx2x_cl45_write(bp, port,
4459 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4460 ext_phy_addr[port],
4461 MDIO_PMA_DEVAD,
4462 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
4463
4464 /* set GPIO2 back to LOW */
4465 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4466 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
4467 }
4468 return 0;
4469
4470}
4471
4472u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
4473{
4474 u8 rc = 0;
4475 u32 ext_phy_type;
4476
4477 DP(NETIF_MSG_LINK, "bnx2x_common_init_phy\n");
4478
4479 /* Read the ext_phy_type for arbitrary port(0) */
4480 ext_phy_type = XGXS_EXT_PHY_TYPE(
4481 REG_RD(bp, shmem_base +
4482 offsetof(struct shmem_region,
4483 dev_info.port_hw_config[0].external_phy_config)));
4484
4485 switch (ext_phy_type) {
4486 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4487 {
4488 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
4489 break;
4490 }
4491 default:
4492 DP(NETIF_MSG_LINK,
4493 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
4494 ext_phy_type);
4495 break;
4496 }
4497
4498 return rc;
4499}
4500
4501
4502
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004503static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
4504{
4505 u16 val, cnt;
4506
4507 bnx2x_cl45_read(bp, port,
4508 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4509 phy_addr,
4510 MDIO_PMA_DEVAD,
4511 MDIO_PMA_REG_7101_RESET, &val);
4512
4513 for (cnt = 0; cnt < 10; cnt++) {
4514 msleep(50);
4515 /* Writes a self-clearing reset */
4516 bnx2x_cl45_write(bp, port,
4517 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4518 phy_addr,
4519 MDIO_PMA_DEVAD,
4520 MDIO_PMA_REG_7101_RESET,
4521 (val | (1<<15)));
4522 /* Wait for clear */
4523 bnx2x_cl45_read(bp, port,
4524 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4525 phy_addr,
4526 MDIO_PMA_DEVAD,
4527 MDIO_PMA_REG_7101_RESET, &val);
4528
4529 if ((val & (1<<15)) == 0)
4530 break;
4531 }
4532}
4533#define RESERVED_SIZE 256
4534/* max application is 160K bytes - data at end of RAM */
Eilon Greenstein6378c022008-08-13 15:59:25 -07004535#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004536
4537/* Header is 14 bytes */
4538#define HEADER_SIZE 14
4539#define DATA_OFFSET HEADER_SIZE
4540
4541#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \
4542 bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \
4543 ext_phy_addr, \
4544 MDIO_PCS_DEVAD, \
4545 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1)
4546
4547/* Programs an image to DSP's flash via the SPI port*/
4548static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port,
4549 u8 ext_phy_addr,
4550 char data[], u32 size)
4551{
4552 const u16 num_trans = size/4; /* 4 bytes can be sent at a time */
4553 /* Doesn't include last trans!*/
4554 const u16 last_trans_size = size%4; /* Num bytes on last trans */
4555 u16 trans_cnt, byte_cnt;
4556 u32 data_index;
4557 u16 tmp;
4558 u16 code_started = 0;
4559 u16 image_revision1, image_revision2;
4560 u16 cnt;
4561
4562 DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size);
4563 /* Going to flash*/
4564 if ((size-HEADER_SIZE) > MAX_APP_SIZE) {
4565 /* This very often will be the case, because the image is built
4566 with 160Kbytes size whereas the total image size must actually
4567 be 160Kbytes-RESERVED_SIZE */
4568 DP(NETIF_MSG_LINK, "Warning, file size was %d bytes "
4569 "truncated to %d bytes\n", size, MAX_APP_SIZE);
4570 size = MAX_APP_SIZE+HEADER_SIZE;
4571 }
4572 DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004573 DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004574 /* Put the DSP in download mode by setting FLASH_CFG[2] to 1
4575 and issuing a reset.*/
4576
4577 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004578 MISC_REGISTERS_GPIO_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004579
4580 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
4581
4582 /* wait 0.5 sec */
4583 for (cnt = 0; cnt < 100; cnt++)
4584 msleep(5);
4585
4586 /* Make sure we can access the DSP
4587 And it's in the correct mode (waiting for download) */
4588
4589 bnx2x_cl45_read(bp, port,
4590 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4591 ext_phy_addr,
4592 MDIO_PCS_DEVAD,
4593 MDIO_PCS_REG_7101_DSP_ACCESS, &tmp);
4594
4595 if (tmp != 0x000A) {
4596 DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. "
4597 "Expected 0x000A, read 0x%04X\n", tmp);
4598 DP(NETIF_MSG_LINK, "Download failed\n");
4599 return -EINVAL;
4600 }
4601
4602 /* Mux the SPI interface away from the internal processor */
4603 bnx2x_cl45_write(bp, port,
4604 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4605 ext_phy_addr,
4606 MDIO_PCS_DEVAD,
4607 MDIO_PCS_REG_7101_SPI_MUX, 1);
4608
4609 /* Reset the SPI port */
4610 bnx2x_cl45_write(bp, port,
4611 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4612 ext_phy_addr,
4613 MDIO_PCS_DEVAD,
4614 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
4615 bnx2x_cl45_write(bp, port,
4616 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4617 ext_phy_addr,
4618 MDIO_PCS_DEVAD,
4619 MDIO_PCS_REG_7101_SPI_CTRL_ADDR,
4620 (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT));
4621 bnx2x_cl45_write(bp, port,
4622 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4623 ext_phy_addr,
4624 MDIO_PCS_DEVAD,
4625 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
4626
4627 /* Erase the flash */
4628 bnx2x_cl45_write(bp, port,
4629 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4630 ext_phy_addr,
4631 MDIO_PCS_DEVAD,
4632 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4633 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4634
4635 bnx2x_cl45_write(bp, port,
4636 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4637 ext_phy_addr,
4638 MDIO_PCS_DEVAD,
4639 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4640 1);
4641
4642 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4643 bnx2x_cl45_write(bp, port,
4644 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4645 ext_phy_addr,
4646 MDIO_PCS_DEVAD,
4647 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4648 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD);
4649
4650 bnx2x_cl45_write(bp, port,
4651 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4652 ext_phy_addr,
4653 MDIO_PCS_DEVAD,
4654 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4655 1);
4656 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4657
4658 /* Wait 10 seconds, the maximum time for the erase to complete */
4659 DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n");
4660 for (cnt = 0; cnt < 1000; cnt++)
4661 msleep(10);
4662
4663 DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n");
4664 data_index = 0;
4665 for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) {
4666 bnx2x_cl45_write(bp, port,
4667 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4668 ext_phy_addr,
4669 MDIO_PCS_DEVAD,
4670 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4671 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4672
4673 bnx2x_cl45_write(bp, port,
4674 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4675 ext_phy_addr,
4676 MDIO_PCS_DEVAD,
4677 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4678 1);
4679 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4680
4681 bnx2x_cl45_write(bp, port,
4682 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4683 ext_phy_addr,
4684 MDIO_PCS_DEVAD,
4685 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4686 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
4687
4688 /* Bits 23-16 of address */
4689 bnx2x_cl45_write(bp, port,
4690 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4691 ext_phy_addr,
4692 MDIO_PCS_DEVAD,
4693 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4694 (data_index>>16));
4695 /* Bits 15-8 of address */
4696 bnx2x_cl45_write(bp, port,
4697 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4698 ext_phy_addr,
4699 MDIO_PCS_DEVAD,
4700 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4701 (data_index>>8));
4702
4703 /* Bits 7-0 of address */
4704 bnx2x_cl45_write(bp, port,
4705 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4706 ext_phy_addr,
4707 MDIO_PCS_DEVAD,
4708 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4709 ((u16)data_index));
4710
4711 byte_cnt = 0;
4712 while (byte_cnt < 4 && data_index < size) {
4713 bnx2x_cl45_write(bp, port,
4714 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4715 ext_phy_addr,
4716 MDIO_PCS_DEVAD,
4717 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4718 data[data_index++]);
4719 byte_cnt++;
4720 }
4721
4722 bnx2x_cl45_write(bp, port,
4723 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4724 ext_phy_addr,
4725 MDIO_PCS_DEVAD,
4726 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4727 byte_cnt+4);
4728
4729 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4730 msleep(5); /* Wait 5 ms minimum between transs */
4731
4732 /* Let the user know something's going on.*/
4733 /* a pacifier ever 4K */
4734 if ((data_index % 1023) == 0)
4735 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
4736 }
4737
4738 DP(NETIF_MSG_LINK, "\n");
4739 /* Transfer the last block if there is data remaining */
4740 if (last_trans_size) {
4741 bnx2x_cl45_write(bp, port,
4742 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4743 ext_phy_addr,
4744 MDIO_PCS_DEVAD,
4745 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4746 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4747
4748 bnx2x_cl45_write(bp, port,
4749 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4750 ext_phy_addr,
4751 MDIO_PCS_DEVAD,
4752 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4753 1);
4754
4755 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4756
4757 bnx2x_cl45_write(bp, port,
4758 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4759 ext_phy_addr,
4760 MDIO_PCS_DEVAD,
4761 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4762 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
4763
4764 /* Bits 23-16 of address */
4765 bnx2x_cl45_write(bp, port,
4766 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4767 ext_phy_addr,
4768 MDIO_PCS_DEVAD,
4769 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4770 (data_index>>16));
4771 /* Bits 15-8 of address */
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_FIFO_ADDR,
4777 (data_index>>8));
4778
4779 /* Bits 7-0 of address */
4780 bnx2x_cl45_write(bp, port,
4781 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4782 ext_phy_addr,
4783 MDIO_PCS_DEVAD,
4784 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4785 ((u16)data_index));
4786
4787 byte_cnt = 0;
4788 while (byte_cnt < last_trans_size && data_index < size) {
4789 /* Bits 7-0 of address */
4790 bnx2x_cl45_write(bp, port,
4791 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4792 ext_phy_addr,
4793 MDIO_PCS_DEVAD,
4794 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4795 data[data_index++]);
4796 byte_cnt++;
4797 }
4798
4799 bnx2x_cl45_write(bp, port,
4800 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4801 ext_phy_addr,
4802 MDIO_PCS_DEVAD,
4803 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4804 byte_cnt+4);
4805
4806 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4807 }
4808
4809 /* DSP Remove Download Mode */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004810 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4811 MISC_REGISTERS_GPIO_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004812
4813 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
4814
4815 /* wait 0.5 sec to allow it to run */
4816 for (cnt = 0; cnt < 100; cnt++)
4817 msleep(5);
4818
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004819 bnx2x_hw_reset(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004820
4821 for (cnt = 0; cnt < 100; cnt++)
4822 msleep(5);
4823
4824 /* Check that the code is started. In case the download
4825 checksum failed, the code won't be started. */
4826 bnx2x_cl45_read(bp, port,
4827 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4828 ext_phy_addr,
4829 MDIO_PCS_DEVAD,
4830 MDIO_PCS_REG_7101_DSP_ACCESS,
4831 &tmp);
4832
4833 code_started = (tmp & (1<<4));
4834 if (!code_started) {
4835 DP(NETIF_MSG_LINK, "Download failed. Please check file.\n");
4836 return -EINVAL;
4837 }
4838
4839 /* Verify that the file revision is now equal to the image
4840 revision within the DSP */
4841 bnx2x_cl45_read(bp, port,
4842 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4843 ext_phy_addr,
4844 MDIO_PMA_DEVAD,
4845 MDIO_PMA_REG_7101_VER1,
4846 &image_revision1);
4847
4848 bnx2x_cl45_read(bp, port,
4849 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4850 ext_phy_addr,
4851 MDIO_PMA_DEVAD,
4852 MDIO_PMA_REG_7101_VER2,
4853 &image_revision2);
4854
Eilon Greenstein3196a882008-08-13 15:58:49 -07004855 if (data[0x14e] != (image_revision2&0xFF) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004856 data[0x14f] != ((image_revision2&0xFF00)>>8) ||
4857 data[0x150] != (image_revision1&0xFF) ||
4858 data[0x151] != ((image_revision1&0xFF00)>>8)) {
4859 DP(NETIF_MSG_LINK, "Download failed.\n");
4860 return -EINVAL;
4861 }
4862 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
4863 return 0;
4864}
4865
4866u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
4867 u8 driver_loaded, char data[], u32 size)
4868{
4869 u8 rc = 0;
4870 u32 ext_phy_type;
4871 u8 ext_phy_addr;
4872 ext_phy_addr = ((ext_phy_config &
4873 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4874 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4875
4876 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4877
4878 switch (ext_phy_type) {
4879 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4880 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4881 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4882 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
4883 DP(NETIF_MSG_LINK,
4884 "Flash download not supported for this ext phy\n");
4885 rc = -EINVAL;
4886 break;
4887 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4888 /* Take ext phy out of reset */
4889 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004890 bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004891 rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
4892 data, size);
4893 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004894 bnx2x_turn_off_sf(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004895 break;
4896 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4897 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4898 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
4899 default:
4900 DP(NETIF_MSG_LINK, "Invalid ext phy type\n");
4901 rc = -EINVAL;
4902 break;
4903 }
4904 return rc;
4905}
4906