blob: 4ce7fe9c5251143745985b70cb449df9f394edfd [file] [log] [blame]
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001/* Copyright 2008 Broadcom Corporation
2 *
3 * Unless you and Broadcom execute a separate written software license
4 * agreement governing use of this software, this software is licensed to you
5 * under the terms of the GNU General Public License version 2, available
6 * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
7 *
8 * Notwithstanding the above, under no circumstances may you combine this
9 * software in any way with any other Broadcom software provided under a
10 * license other than the GPL, without Broadcom's express prior written
11 * consent.
12 *
13 * Written by Yaniv Rosner
14 *
15 */
16
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/pci.h>
20#include <linux/netdevice.h>
21#include <linux/delay.h>
22#include <linux/ethtool.h>
23#include <linux/mutex.h>
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);
292 if (vars->flow_ctrl & FLOW_CTRL_RX)
293 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));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700300 if (vars->flow_ctrl & FLOW_CTRL_TX)
301 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
320 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700321 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700322 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
323 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
324
325 /* strip CRC */
326 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
327
328 /* disable the NIG in/out to the bmac */
329 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
330 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
331 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
332
333 /* enable the NIG in/out to the emac */
334 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
335 val = 0;
336 if (vars->flow_ctrl & FLOW_CTRL_TX)
337 val = 1;
338
339 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
340 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
341
342 if (CHIP_REV_IS_EMUL(bp)) {
343 /* take the BigMac out of reset */
344 REG_WR(bp,
345 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
346 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
347
348 /* enable access for bmac registers */
349 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
350 }
351
352 vars->mac_type = MAC_TYPE_EMAC;
353 return 0;
354}
355
356
357
358static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
359 u8 is_lb)
360{
361 struct bnx2x *bp = params->bp;
362 u8 port = params->port;
363 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
364 NIG_REG_INGRESS_BMAC0_MEM;
365 u32 wb_data[2];
366 u32 val;
367
368 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
369 /* reset and unreset the BigMac */
370 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
371 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
372 msleep(1);
373
374 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
375 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
376
377 /* enable access for bmac registers */
378 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
379
380 /* XGXS control */
381 wb_data[0] = 0x3c;
382 wb_data[1] = 0;
383 REG_WR_DMAE(bp, bmac_addr +
384 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
385 wb_data, 2);
386
387 /* tx MAC SA */
388 wb_data[0] = ((params->mac_addr[2] << 24) |
389 (params->mac_addr[3] << 16) |
390 (params->mac_addr[4] << 8) |
391 params->mac_addr[5]);
392 wb_data[1] = ((params->mac_addr[0] << 8) |
393 params->mac_addr[1]);
394 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
395 wb_data, 2);
396
397 /* tx control */
398 val = 0xc0;
399 if (vars->flow_ctrl & FLOW_CTRL_TX)
400 val |= 0x800000;
401 wb_data[0] = val;
402 wb_data[1] = 0;
403 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
404 wb_data, 2);
405
406 /* mac control */
407 val = 0x3;
408 if (is_lb) {
409 val |= 0x4;
410 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
411 }
412 wb_data[0] = val;
413 wb_data[1] = 0;
414 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
415 wb_data, 2);
416
417
418 /* set rx mtu */
419 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
420 wb_data[1] = 0;
421 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
422 wb_data, 2);
423
424 /* rx control set to don't strip crc */
425 val = 0x14;
426 if (vars->flow_ctrl & FLOW_CTRL_RX)
427 val |= 0x20;
428 wb_data[0] = val;
429 wb_data[1] = 0;
430 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
431 wb_data, 2);
432
433 /* set tx mtu */
434 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
435 wb_data[1] = 0;
436 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
437 wb_data, 2);
438
439 /* set cnt max size */
440 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
441 wb_data[1] = 0;
442 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
443 wb_data, 2);
444
445 /* configure safc */
446 wb_data[0] = 0x1000200;
447 wb_data[1] = 0;
448 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
449 wb_data, 2);
450 /* fix for emulation */
451 if (CHIP_REV_IS_EMUL(bp)) {
452 wb_data[0] = 0xf000;
453 wb_data[1] = 0;
454 REG_WR_DMAE(bp,
455 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
456 wb_data, 2);
457 }
458
459 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
460 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
461 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
462 val = 0;
463 if (vars->flow_ctrl & FLOW_CTRL_TX)
464 val = 1;
465 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
466 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
467 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
468 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
469 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
470 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
471
472 vars->mac_type = MAC_TYPE_BMAC;
473 return 0;
474}
475
476static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
477{
478 struct bnx2x *bp = params->bp;
479 u32 val;
480
481 if (phy_flags & PHY_XGXS_FLAG) {
482 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
483 val = XGXS_RESET_BITS;
484
485 } else { /* SerDes */
486 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
487 val = SERDES_RESET_BITS;
488 }
489
490 val = val << (params->port*16);
491
492 /* reset and unreset the SerDes/XGXS */
493 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
494 val);
495 udelay(500);
496 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
497 val);
498 bnx2x_set_phy_mdio(params);
499}
500
501void bnx2x_link_status_update(struct link_params *params,
502 struct link_vars *vars)
503{
504 struct bnx2x *bp = params->bp;
505 u8 link_10g;
506 u8 port = params->port;
507
508 if (params->switch_cfg == SWITCH_CFG_1G)
509 vars->phy_flags = PHY_SERDES_FLAG;
510 else
511 vars->phy_flags = PHY_XGXS_FLAG;
512 vars->link_status = REG_RD(bp, params->shmem_base +
513 offsetof(struct shmem_region,
514 port_mb[port].link_status));
515
516 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
517
518 if (vars->link_up) {
519 DP(NETIF_MSG_LINK, "phy link up\n");
520
521 vars->phy_link_up = 1;
522 vars->duplex = DUPLEX_FULL;
523 switch (vars->link_status &
524 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
525 case LINK_10THD:
526 vars->duplex = DUPLEX_HALF;
527 /* fall thru */
528 case LINK_10TFD:
529 vars->line_speed = SPEED_10;
530 break;
531
532 case LINK_100TXHD:
533 vars->duplex = DUPLEX_HALF;
534 /* fall thru */
535 case LINK_100T4:
536 case LINK_100TXFD:
537 vars->line_speed = SPEED_100;
538 break;
539
540 case LINK_1000THD:
541 vars->duplex = DUPLEX_HALF;
542 /* fall thru */
543 case LINK_1000TFD:
544 vars->line_speed = SPEED_1000;
545 break;
546
547 case LINK_2500THD:
548 vars->duplex = DUPLEX_HALF;
549 /* fall thru */
550 case LINK_2500TFD:
551 vars->line_speed = SPEED_2500;
552 break;
553
554 case LINK_10GTFD:
555 vars->line_speed = SPEED_10000;
556 break;
557
558 case LINK_12GTFD:
559 vars->line_speed = SPEED_12000;
560 break;
561
562 case LINK_12_5GTFD:
563 vars->line_speed = SPEED_12500;
564 break;
565
566 case LINK_13GTFD:
567 vars->line_speed = SPEED_13000;
568 break;
569
570 case LINK_15GTFD:
571 vars->line_speed = SPEED_15000;
572 break;
573
574 case LINK_16GTFD:
575 vars->line_speed = SPEED_16000;
576 break;
577
578 default:
579 break;
580 }
581
582 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
583 vars->flow_ctrl |= FLOW_CTRL_TX;
584 else
585 vars->flow_ctrl &= ~FLOW_CTRL_TX;
586
587 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
588 vars->flow_ctrl |= FLOW_CTRL_RX;
589 else
590 vars->flow_ctrl &= ~FLOW_CTRL_RX;
591
592 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700593 if (vars->line_speed &&
594 ((vars->line_speed == SPEED_10) ||
595 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700596 vars->phy_flags |= PHY_SGMII_FLAG;
597 } else {
598 vars->phy_flags &= ~PHY_SGMII_FLAG;
599 }
600 }
601
602 /* anything 10 and over uses the bmac */
603 link_10g = ((vars->line_speed == SPEED_10000) ||
604 (vars->line_speed == SPEED_12000) ||
605 (vars->line_speed == SPEED_12500) ||
606 (vars->line_speed == SPEED_13000) ||
607 (vars->line_speed == SPEED_15000) ||
608 (vars->line_speed == SPEED_16000));
609 if (link_10g)
610 vars->mac_type = MAC_TYPE_BMAC;
611 else
612 vars->mac_type = MAC_TYPE_EMAC;
613
614 } else { /* link down */
615 DP(NETIF_MSG_LINK, "phy link down\n");
616
617 vars->phy_link_up = 0;
618
619 vars->line_speed = 0;
620 vars->duplex = DUPLEX_FULL;
621 vars->flow_ctrl = FLOW_CTRL_NONE;
622
623 /* indicate no mac active */
624 vars->mac_type = MAC_TYPE_NONE;
625 }
626
627 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
628 vars->link_status, vars->phy_link_up);
629 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
630 vars->line_speed, vars->duplex, vars->flow_ctrl);
631}
632
633static void bnx2x_update_mng(struct link_params *params, u32 link_status)
634{
635 struct bnx2x *bp = params->bp;
636 REG_WR(bp, params->shmem_base +
637 offsetof(struct shmem_region,
638 port_mb[params->port].link_status),
639 link_status);
640}
641
642static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
643{
644 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
645 NIG_REG_INGRESS_BMAC0_MEM;
646 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700647 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700648
649 /* Only if the bmac is out of reset */
650 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
651 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
652 nig_bmac_enable) {
653
654 /* Clear Rx Enable bit in BMAC_CONTROL register */
655 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
656 wb_data, 2);
657 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
658 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
659 wb_data, 2);
660
661 msleep(1);
662 }
663}
664
665static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
666 u32 line_speed)
667{
668 struct bnx2x *bp = params->bp;
669 u8 port = params->port;
670 u32 init_crd, crd;
671 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700672
673 /* disable port */
674 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
675
676 /* wait for init credit */
677 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
678 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
679 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
680
681 while ((init_crd != crd) && count) {
682 msleep(5);
683
684 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
685 count--;
686 }
687 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
688 if (init_crd != crd) {
689 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
690 init_crd, crd);
691 return -EINVAL;
692 }
693
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700694 if (flow_ctrl & FLOW_CTRL_RX ||
695 line_speed == SPEED_10 ||
696 line_speed == SPEED_100 ||
697 line_speed == SPEED_1000 ||
698 line_speed == SPEED_2500) {
699 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700700 /* update threshold */
701 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
702 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700703 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700704
705 } else {
706 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
707 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700708 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700709 /* update threshold */
710 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
711 /* update init credit */
712 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700713 case SPEED_10000:
714 init_crd = thresh + 553 - 22;
715 break;
716
717 case SPEED_12000:
718 init_crd = thresh + 664 - 22;
719 break;
720
721 case SPEED_13000:
722 init_crd = thresh + 742 - 22;
723 break;
724
725 case SPEED_16000:
726 init_crd = thresh + 778 - 22;
727 break;
728 default:
729 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
730 line_speed);
731 return -EINVAL;
732 break;
733 }
734 }
735 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
736 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
737 line_speed, init_crd);
738
739 /* probe the credit changes */
740 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
741 msleep(5);
742 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
743
744 /* enable port */
745 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
746 return 0;
747}
748
749static u32 bnx2x_get_emac_base(u32 ext_phy_type, u8 port)
750{
751 u32 emac_base;
752 switch (ext_phy_type) {
753 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
754 emac_base = GRCBASE_EMAC0;
755 break;
756 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700757 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700758 break;
759 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700760 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700761 break;
762 }
763 return emac_base;
764
765}
766
767u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
768 u8 phy_addr, u8 devad, u16 reg, u16 val)
769{
770 u32 tmp, saved_mode;
771 u8 i, rc = 0;
772 u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
773
774 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
775 * (a value of 49==0x31) and make sure that the AUTO poll is off
776 */
777 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
778 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
779 EMAC_MDIO_MODE_CLOCK_CNT);
780 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
781 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
782 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
783 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
784 udelay(40);
785
786 /* address */
787
788 tmp = ((phy_addr << 21) | (devad << 16) | reg |
789 EMAC_MDIO_COMM_COMMAND_ADDRESS |
790 EMAC_MDIO_COMM_START_BUSY);
791 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
792
793 for (i = 0; i < 50; i++) {
794 udelay(10);
795
796 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
797 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
798 udelay(5);
799 break;
800 }
801 }
802 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
803 DP(NETIF_MSG_LINK, "write phy register failed\n");
804 rc = -EFAULT;
805 } else {
806 /* data */
807 tmp = ((phy_addr << 21) | (devad << 16) | val |
808 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
809 EMAC_MDIO_COMM_START_BUSY);
810 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
811
812 for (i = 0; i < 50; i++) {
813 udelay(10);
814
815 tmp = REG_RD(bp, mdio_ctrl +
816 EMAC_REG_EMAC_MDIO_COMM);
817 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
818 udelay(5);
819 break;
820 }
821 }
822 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
823 DP(NETIF_MSG_LINK, "write phy register failed\n");
824 rc = -EFAULT;
825 }
826 }
827
828 /* Restore the saved mode */
829 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
830
831 return rc;
832}
833
834u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
835 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
836{
837 u32 val, saved_mode;
838 u16 i;
839 u8 rc = 0;
840
841 u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port);
842 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
843 * (a value of 49==0x31) and make sure that the AUTO poll is off
844 */
845 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
846 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
847 EMAC_MDIO_MODE_CLOCK_CNT));
848 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
849 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
850 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
851 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
852 udelay(40);
853
854 /* address */
855 val = ((phy_addr << 21) | (devad << 16) | reg |
856 EMAC_MDIO_COMM_COMMAND_ADDRESS |
857 EMAC_MDIO_COMM_START_BUSY);
858 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
859
860 for (i = 0; i < 50; i++) {
861 udelay(10);
862
863 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
864 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
865 udelay(5);
866 break;
867 }
868 }
869 if (val & EMAC_MDIO_COMM_START_BUSY) {
870 DP(NETIF_MSG_LINK, "read phy register failed\n");
871
872 *ret_val = 0;
873 rc = -EFAULT;
874
875 } else {
876 /* data */
877 val = ((phy_addr << 21) | (devad << 16) |
878 EMAC_MDIO_COMM_COMMAND_READ_45 |
879 EMAC_MDIO_COMM_START_BUSY);
880 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
881
882 for (i = 0; i < 50; i++) {
883 udelay(10);
884
885 val = REG_RD(bp, mdio_ctrl +
886 EMAC_REG_EMAC_MDIO_COMM);
887 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
888 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
889 break;
890 }
891 }
892 if (val & EMAC_MDIO_COMM_START_BUSY) {
893 DP(NETIF_MSG_LINK, "read phy register failed\n");
894
895 *ret_val = 0;
896 rc = -EFAULT;
897 }
898 }
899
900 /* Restore the saved mode */
901 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
902
903 return rc;
904}
905
906static void bnx2x_set_aer_mmd(struct link_params *params,
907 struct link_vars *vars)
908{
909 struct bnx2x *bp = params->bp;
910 u32 ser_lane;
911 u16 offset;
912
913 ser_lane = ((params->lane_config &
914 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
915 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
916
917 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
918 (params->phy_addr + ser_lane) : 0;
919
920 CL45_WR_OVER_CL22(bp, params->port,
921 params->phy_addr,
922 MDIO_REG_BANK_AER_BLOCK,
923 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
924}
925
926static void bnx2x_set_master_ln(struct link_params *params)
927{
928 struct bnx2x *bp = params->bp;
929 u16 new_master_ln, ser_lane;
930 ser_lane = ((params->lane_config &
931 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
932 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
933
934 /* set the master_ln for AN */
935 CL45_RD_OVER_CL22(bp, params->port,
936 params->phy_addr,
937 MDIO_REG_BANK_XGXS_BLOCK2,
938 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
939 &new_master_ln);
940
941 CL45_WR_OVER_CL22(bp, params->port,
942 params->phy_addr,
943 MDIO_REG_BANK_XGXS_BLOCK2 ,
944 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
945 (new_master_ln | ser_lane));
946}
947
948static u8 bnx2x_reset_unicore(struct link_params *params)
949{
950 struct bnx2x *bp = params->bp;
951 u16 mii_control;
952 u16 i;
953
954 CL45_RD_OVER_CL22(bp, params->port,
955 params->phy_addr,
956 MDIO_REG_BANK_COMBO_IEEE0,
957 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
958
959 /* reset the unicore */
960 CL45_WR_OVER_CL22(bp, params->port,
961 params->phy_addr,
962 MDIO_REG_BANK_COMBO_IEEE0,
963 MDIO_COMBO_IEEE0_MII_CONTROL,
964 (mii_control |
965 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
966
967 /* wait for the reset to self clear */
968 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
969 udelay(5);
970
971 /* the reset erased the previous bank value */
972 CL45_RD_OVER_CL22(bp, params->port,
973 params->phy_addr,
974 MDIO_REG_BANK_COMBO_IEEE0,
975 MDIO_COMBO_IEEE0_MII_CONTROL,
976 &mii_control);
977
978 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
979 udelay(5);
980 return 0;
981 }
982 }
983
984 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
985 return -EINVAL;
986
987}
988
989static void bnx2x_set_swap_lanes(struct link_params *params)
990{
991 struct bnx2x *bp = params->bp;
992 /* Each two bits represents a lane number:
993 No swap is 0123 => 0x1b no need to enable the swap */
994 u16 ser_lane, rx_lane_swap, tx_lane_swap;
995
996 ser_lane = ((params->lane_config &
997 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
998 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
999 rx_lane_swap = ((params->lane_config &
1000 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1001 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1002 tx_lane_swap = ((params->lane_config &
1003 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1004 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1005
1006 if (rx_lane_swap != 0x1b) {
1007 CL45_WR_OVER_CL22(bp, params->port,
1008 params->phy_addr,
1009 MDIO_REG_BANK_XGXS_BLOCK2,
1010 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1011 (rx_lane_swap |
1012 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1013 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1014 } else {
1015 CL45_WR_OVER_CL22(bp, params->port,
1016 params->phy_addr,
1017 MDIO_REG_BANK_XGXS_BLOCK2,
1018 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1019 }
1020
1021 if (tx_lane_swap != 0x1b) {
1022 CL45_WR_OVER_CL22(bp, params->port,
1023 params->phy_addr,
1024 MDIO_REG_BANK_XGXS_BLOCK2,
1025 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1026 (tx_lane_swap |
1027 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1028 } else {
1029 CL45_WR_OVER_CL22(bp, params->port,
1030 params->phy_addr,
1031 MDIO_REG_BANK_XGXS_BLOCK2,
1032 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1033 }
1034}
1035
1036static void bnx2x_set_parallel_detection(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07001037 u8 phy_flags)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001038{
1039 struct bnx2x *bp = params->bp;
1040 u16 control2;
1041
1042 CL45_RD_OVER_CL22(bp, params->port,
1043 params->phy_addr,
1044 MDIO_REG_BANK_SERDES_DIGITAL,
1045 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1046 &control2);
1047
1048
1049 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1050
1051
1052 CL45_WR_OVER_CL22(bp, params->port,
1053 params->phy_addr,
1054 MDIO_REG_BANK_SERDES_DIGITAL,
1055 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1056 control2);
1057
1058 if (phy_flags & PHY_XGXS_FLAG) {
1059 DP(NETIF_MSG_LINK, "XGXS\n");
1060
1061 CL45_WR_OVER_CL22(bp, params->port,
1062 params->phy_addr,
1063 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1064 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1065 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1066
1067 CL45_RD_OVER_CL22(bp, params->port,
1068 params->phy_addr,
1069 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1070 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1071 &control2);
1072
1073
1074 control2 |=
1075 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1076
1077 CL45_WR_OVER_CL22(bp, params->port,
1078 params->phy_addr,
1079 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1080 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1081 control2);
1082
1083 /* Disable parallel detection of HiG */
1084 CL45_WR_OVER_CL22(bp, params->port,
1085 params->phy_addr,
1086 MDIO_REG_BANK_XGXS_BLOCK2,
1087 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1088 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1089 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1090 }
1091}
1092
1093static void bnx2x_set_autoneg(struct link_params *params,
1094 struct link_vars *vars)
1095{
1096 struct bnx2x *bp = params->bp;
1097 u16 reg_val;
1098
1099 /* CL37 Autoneg */
1100
1101 CL45_RD_OVER_CL22(bp, params->port,
1102 params->phy_addr,
1103 MDIO_REG_BANK_COMBO_IEEE0,
1104 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1105
1106 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001107 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001108 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1109 else /* CL37 Autoneg Disabled */
1110 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1111 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1112
1113 CL45_WR_OVER_CL22(bp, params->port,
1114 params->phy_addr,
1115 MDIO_REG_BANK_COMBO_IEEE0,
1116 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1117
1118 /* Enable/Disable Autodetection */
1119
1120 CL45_RD_OVER_CL22(bp, params->port,
1121 params->phy_addr,
1122 MDIO_REG_BANK_SERDES_DIGITAL,
1123 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
1124 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001125 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001126 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1127 else
1128 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1129
1130 CL45_WR_OVER_CL22(bp, params->port,
1131 params->phy_addr,
1132 MDIO_REG_BANK_SERDES_DIGITAL,
1133 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1134
1135 /* Enable TetonII and BAM autoneg */
1136 CL45_RD_OVER_CL22(bp, params->port,
1137 params->phy_addr,
1138 MDIO_REG_BANK_BAM_NEXT_PAGE,
1139 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1140 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001141 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001142 /* Enable BAM aneg Mode and TetonII aneg Mode */
1143 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1144 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1145 } else {
1146 /* TetonII and BAM Autoneg Disabled */
1147 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1148 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1149 }
1150 CL45_WR_OVER_CL22(bp, params->port,
1151 params->phy_addr,
1152 MDIO_REG_BANK_BAM_NEXT_PAGE,
1153 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1154 reg_val);
1155
1156 /* Enable Clause 73 Aneg */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001157 if ((vars->line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001158 (SUPPORT_CL73)) {
1159 /* Enable BAM Station Manager */
1160
1161 CL45_WR_OVER_CL22(bp, params->port,
1162 params->phy_addr,
1163 MDIO_REG_BANK_CL73_USERB0,
1164 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1165 (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1166 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1167 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN));
1168
1169 /* Merge CL73 and CL37 aneg resolution */
1170 CL45_RD_OVER_CL22(bp, params->port,
1171 params->phy_addr,
1172 MDIO_REG_BANK_CL73_USERB0,
1173 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1174 &reg_val);
1175
1176 CL45_WR_OVER_CL22(bp, params->port,
1177 params->phy_addr,
1178 MDIO_REG_BANK_CL73_USERB0,
1179 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1180 (reg_val |
1181 MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR));
1182
1183 /* Set the CL73 AN speed */
1184
1185 CL45_RD_OVER_CL22(bp, params->port,
1186 params->phy_addr,
1187 MDIO_REG_BANK_CL73_IEEEB1,
1188 MDIO_CL73_IEEEB1_AN_ADV2, &reg_val);
1189 /* In the SerDes we support only the 1G.
1190 In the XGXS we support the 10G KX4
1191 but we currently do not support the KR */
1192 if (vars->phy_flags & PHY_XGXS_FLAG) {
1193 DP(NETIF_MSG_LINK, "XGXS\n");
1194 /* 10G KX4 */
1195 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1196 } else {
1197 DP(NETIF_MSG_LINK, "SerDes\n");
1198 /* 1000M KX */
1199 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
1200 }
1201 CL45_WR_OVER_CL22(bp, params->port,
1202 params->phy_addr,
1203 MDIO_REG_BANK_CL73_IEEEB1,
1204 MDIO_CL73_IEEEB1_AN_ADV2, reg_val);
1205
1206 /* CL73 Autoneg Enabled */
1207 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1208 } else {
1209 /* CL73 Autoneg Disabled */
1210 reg_val = 0;
1211 }
1212 CL45_WR_OVER_CL22(bp, params->port,
1213 params->phy_addr,
1214 MDIO_REG_BANK_CL73_IEEEB0,
1215 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1216}
1217
1218/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001219static void bnx2x_program_serdes(struct link_params *params,
1220 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001221{
1222 struct bnx2x *bp = params->bp;
1223 u16 reg_val;
1224
1225 /* program duplex, disable autoneg */
1226
1227 CL45_RD_OVER_CL22(bp, params->port,
1228 params->phy_addr,
1229 MDIO_REG_BANK_COMBO_IEEE0,
1230 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1231 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
1232 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN);
1233 if (params->req_duplex == DUPLEX_FULL)
1234 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1235 CL45_WR_OVER_CL22(bp, params->port,
1236 params->phy_addr,
1237 MDIO_REG_BANK_COMBO_IEEE0,
1238 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1239
1240 /* program speed
1241 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001242 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001243 params->phy_addr,
1244 MDIO_REG_BANK_SERDES_DIGITAL,
1245 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001246 /* clearing the speed value before setting the right speed */
1247 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1248
1249 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1250 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1251
1252 if (!((vars->line_speed == SPEED_1000) ||
1253 (vars->line_speed == SPEED_100) ||
1254 (vars->line_speed == SPEED_10))) {
1255
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001256 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1257 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001258 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001259 reg_val |=
1260 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001261 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001262 reg_val |=
1263 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001264 }
1265
1266 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001267 params->phy_addr,
1268 MDIO_REG_BANK_SERDES_DIGITAL,
1269 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001270
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001271}
1272
1273static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1274{
1275 struct bnx2x *bp = params->bp;
1276 u16 val = 0;
1277
1278 /* configure the 48 bits for BAM AN */
1279
1280 /* set extended capabilities */
1281 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1282 val |= MDIO_OVER_1G_UP1_2_5G;
1283 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1284 val |= MDIO_OVER_1G_UP1_10G;
1285 CL45_WR_OVER_CL22(bp, params->port,
1286 params->phy_addr,
1287 MDIO_REG_BANK_OVER_1G,
1288 MDIO_OVER_1G_UP1, val);
1289
1290 CL45_WR_OVER_CL22(bp, params->port,
1291 params->phy_addr,
1292 MDIO_REG_BANK_OVER_1G,
1293 MDIO_OVER_1G_UP3, 0);
1294}
1295
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001296static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001297{
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001298 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001299 /* resolve pause mode and advertisement
1300 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1301
1302 switch (params->req_flow_ctrl) {
1303 case FLOW_CTRL_AUTO:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001304 if (params->req_fc_auto_adv == FLOW_CTRL_BOTH) {
1305 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001306 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1307 } else {
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_ASYMMETRIC;
1310 }
1311 break;
1312 case FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001313 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001314 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1315 break;
1316
1317 case FLOW_CTRL_RX:
1318 case FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001319 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001320 break;
1321
1322 case FLOW_CTRL_NONE:
1323 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001324 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001325 break;
1326 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001327}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001328
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001329static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
1330 u32 ieee_fc)
1331{
1332 struct bnx2x *bp = params->bp;
1333 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001334
1335 CL45_WR_OVER_CL22(bp, params->port,
1336 params->phy_addr,
1337 MDIO_REG_BANK_COMBO_IEEE0,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001338 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001339}
1340
1341static void bnx2x_restart_autoneg(struct link_params *params)
1342{
1343 struct bnx2x *bp = params->bp;
1344 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
1345 if (SUPPORT_CL73) {
1346 /* enable and restart clause 73 aneg */
1347 u16 an_ctrl;
1348
1349 CL45_RD_OVER_CL22(bp, params->port,
1350 params->phy_addr,
1351 MDIO_REG_BANK_CL73_IEEEB0,
1352 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1353 &an_ctrl);
1354 CL45_WR_OVER_CL22(bp, params->port,
1355 params->phy_addr,
1356 MDIO_REG_BANK_CL73_IEEEB0,
1357 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1358 (an_ctrl |
1359 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1360 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1361
1362 } else {
1363 /* Enable and restart BAM/CL37 aneg */
1364 u16 mii_control;
1365
1366 CL45_RD_OVER_CL22(bp, params->port,
1367 params->phy_addr,
1368 MDIO_REG_BANK_COMBO_IEEE0,
1369 MDIO_COMBO_IEEE0_MII_CONTROL,
1370 &mii_control);
1371 DP(NETIF_MSG_LINK,
1372 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1373 mii_control);
1374 CL45_WR_OVER_CL22(bp, params->port,
1375 params->phy_addr,
1376 MDIO_REG_BANK_COMBO_IEEE0,
1377 MDIO_COMBO_IEEE0_MII_CONTROL,
1378 (mii_control |
1379 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1380 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1381 }
1382}
1383
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001384static void bnx2x_initialize_sgmii_process(struct link_params *params,
1385 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001386{
1387 struct bnx2x *bp = params->bp;
1388 u16 control1;
1389
1390 /* in SGMII mode, the unicore is always slave */
1391
1392 CL45_RD_OVER_CL22(bp, params->port,
1393 params->phy_addr,
1394 MDIO_REG_BANK_SERDES_DIGITAL,
1395 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1396 &control1);
1397 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1398 /* set sgmii mode (and not fiber) */
1399 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1400 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1401 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1402 CL45_WR_OVER_CL22(bp, params->port,
1403 params->phy_addr,
1404 MDIO_REG_BANK_SERDES_DIGITAL,
1405 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1406 control1);
1407
1408 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001409 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001410 /* set speed, disable autoneg */
1411 u16 mii_control;
1412
1413 CL45_RD_OVER_CL22(bp, params->port,
1414 params->phy_addr,
1415 MDIO_REG_BANK_COMBO_IEEE0,
1416 MDIO_COMBO_IEEE0_MII_CONTROL,
1417 &mii_control);
1418 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1419 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1420 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1421
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001422 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001423 case SPEED_100:
1424 mii_control |=
1425 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1426 break;
1427 case SPEED_1000:
1428 mii_control |=
1429 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1430 break;
1431 case SPEED_10:
1432 /* there is nothing to set for 10M */
1433 break;
1434 default:
1435 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001436 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1437 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001438 break;
1439 }
1440
1441 /* setting the full duplex */
1442 if (params->req_duplex == DUPLEX_FULL)
1443 mii_control |=
1444 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1445 CL45_WR_OVER_CL22(bp, params->port,
1446 params->phy_addr,
1447 MDIO_REG_BANK_COMBO_IEEE0,
1448 MDIO_COMBO_IEEE0_MII_CONTROL,
1449 mii_control);
1450
1451 } else { /* AN mode */
1452 /* enable and restart AN */
1453 bnx2x_restart_autoneg(params);
1454 }
1455}
1456
1457
1458/*
1459 * link management
1460 */
1461
1462static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001463{ /* LD LP */
1464 switch (pause_result) { /* ASYM P ASYM P */
1465 case 0xb: /* 1 0 1 1 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001466 vars->flow_ctrl = FLOW_CTRL_TX;
1467 break;
1468
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001469 case 0xe: /* 1 1 1 0 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001470 vars->flow_ctrl = FLOW_CTRL_RX;
1471 break;
1472
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001473 case 0x5: /* 0 1 0 1 */
1474 case 0x7: /* 0 1 1 1 */
1475 case 0xd: /* 1 1 0 1 */
1476 case 0xf: /* 1 1 1 1 */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001477 vars->flow_ctrl = FLOW_CTRL_BOTH;
1478 break;
1479
1480 default:
1481 break;
1482 }
1483}
1484
1485static u8 bnx2x_ext_phy_resove_fc(struct link_params *params,
1486 struct link_vars *vars)
1487{
1488 struct bnx2x *bp = params->bp;
1489 u8 ext_phy_addr;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001490 u16 ld_pause; /* local */
1491 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001492 u16 an_complete; /* AN complete */
1493 u16 pause_result;
1494 u8 ret = 0;
1495 u32 ext_phy_type;
1496 u8 port = params->port;
1497 ext_phy_addr = ((params->ext_phy_config &
1498 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1499 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1500
1501 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1502 /* read twice */
1503
1504 bnx2x_cl45_read(bp, port,
1505 ext_phy_type,
1506 ext_phy_addr,
1507 MDIO_AN_DEVAD,
1508 MDIO_AN_REG_STATUS, &an_complete);
1509 bnx2x_cl45_read(bp, port,
1510 ext_phy_type,
1511 ext_phy_addr,
1512 MDIO_AN_DEVAD,
1513 MDIO_AN_REG_STATUS, &an_complete);
1514
1515 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1516 ret = 1;
1517 bnx2x_cl45_read(bp, port,
1518 ext_phy_type,
1519 ext_phy_addr,
1520 MDIO_AN_DEVAD,
1521 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1522 bnx2x_cl45_read(bp, port,
1523 ext_phy_type,
1524 ext_phy_addr,
1525 MDIO_AN_DEVAD,
1526 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1527 pause_result = (ld_pause &
1528 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1529 pause_result |= (lp_pause &
1530 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1531 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
1532 pause_result);
1533 bnx2x_pause_resolve(vars, pause_result);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001534 if (vars->flow_ctrl == FLOW_CTRL_NONE &&
1535 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1536 bnx2x_cl45_read(bp, port,
1537 ext_phy_type,
1538 ext_phy_addr,
1539 MDIO_AN_DEVAD,
1540 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1541
1542 bnx2x_cl45_read(bp, port,
1543 ext_phy_type,
1544 ext_phy_addr,
1545 MDIO_AN_DEVAD,
1546 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1547 pause_result = (ld_pause &
1548 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1549 pause_result |= (lp_pause &
1550 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1551
1552 bnx2x_pause_resolve(vars, pause_result);
1553 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
1554 pause_result);
1555 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001556 }
1557 return ret;
1558}
1559
1560
1561static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1562 struct link_vars *vars,
1563 u32 gp_status)
1564{
1565 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001566 u16 ld_pause; /* local driver */
1567 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001568 u16 pause_result;
1569
1570 vars->flow_ctrl = FLOW_CTRL_NONE;
1571
1572 /* resolve from gp_status in case of AN complete and not sgmii */
1573 if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) &&
1574 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1575 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1576 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1577 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
1578 CL45_RD_OVER_CL22(bp, params->port,
1579 params->phy_addr,
1580 MDIO_REG_BANK_COMBO_IEEE0,
1581 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1582 &ld_pause);
1583 CL45_RD_OVER_CL22(bp, params->port,
1584 params->phy_addr,
1585 MDIO_REG_BANK_COMBO_IEEE0,
1586 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1587 &lp_pause);
1588 pause_result = (ld_pause &
1589 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
1590 pause_result |= (lp_pause &
1591 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
1592 DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
1593 bnx2x_pause_resolve(vars, pause_result);
1594 } else if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) &&
1595 (bnx2x_ext_phy_resove_fc(params, vars))) {
1596 return;
1597 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001598 if (params->req_flow_ctrl == FLOW_CTRL_AUTO)
1599 vars->flow_ctrl = params->req_fc_auto_adv;
1600 else
1601 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001602 }
1603 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1604}
1605
1606
1607static u8 bnx2x_link_settings_status(struct link_params *params,
1608 struct link_vars *vars,
1609 u32 gp_status)
1610{
1611 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001612
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001613 u8 rc = 0;
1614 vars->link_status = 0;
1615
1616 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1617 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1618 gp_status);
1619
1620 vars->phy_link_up = 1;
1621 vars->link_status |= LINK_STATUS_LINK_UP;
1622
1623 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1624 vars->duplex = DUPLEX_FULL;
1625 else
1626 vars->duplex = DUPLEX_HALF;
1627
1628 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1629
1630 switch (gp_status & GP_STATUS_SPEED_MASK) {
1631 case GP_STATUS_10M:
1632 vars->line_speed = SPEED_10;
1633 if (vars->duplex == DUPLEX_FULL)
1634 vars->link_status |= LINK_10TFD;
1635 else
1636 vars->link_status |= LINK_10THD;
1637 break;
1638
1639 case GP_STATUS_100M:
1640 vars->line_speed = SPEED_100;
1641 if (vars->duplex == DUPLEX_FULL)
1642 vars->link_status |= LINK_100TXFD;
1643 else
1644 vars->link_status |= LINK_100TXHD;
1645 break;
1646
1647 case GP_STATUS_1G:
1648 case GP_STATUS_1G_KX:
1649 vars->line_speed = SPEED_1000;
1650 if (vars->duplex == DUPLEX_FULL)
1651 vars->link_status |= LINK_1000TFD;
1652 else
1653 vars->link_status |= LINK_1000THD;
1654 break;
1655
1656 case GP_STATUS_2_5G:
1657 vars->line_speed = SPEED_2500;
1658 if (vars->duplex == DUPLEX_FULL)
1659 vars->link_status |= LINK_2500TFD;
1660 else
1661 vars->link_status |= LINK_2500THD;
1662 break;
1663
1664 case GP_STATUS_5G:
1665 case GP_STATUS_6G:
1666 DP(NETIF_MSG_LINK,
1667 "link speed unsupported gp_status 0x%x\n",
1668 gp_status);
1669 return -EINVAL;
1670 break;
1671 case GP_STATUS_10G_KX4:
1672 case GP_STATUS_10G_HIG:
1673 case GP_STATUS_10G_CX4:
1674 vars->line_speed = SPEED_10000;
1675 vars->link_status |= LINK_10GTFD;
1676 break;
1677
1678 case GP_STATUS_12G_HIG:
1679 vars->line_speed = SPEED_12000;
1680 vars->link_status |= LINK_12GTFD;
1681 break;
1682
1683 case GP_STATUS_12_5G:
1684 vars->line_speed = SPEED_12500;
1685 vars->link_status |= LINK_12_5GTFD;
1686 break;
1687
1688 case GP_STATUS_13G:
1689 vars->line_speed = SPEED_13000;
1690 vars->link_status |= LINK_13GTFD;
1691 break;
1692
1693 case GP_STATUS_15G:
1694 vars->line_speed = SPEED_15000;
1695 vars->link_status |= LINK_15GTFD;
1696 break;
1697
1698 case GP_STATUS_16G:
1699 vars->line_speed = SPEED_16000;
1700 vars->link_status |= LINK_16GTFD;
1701 break;
1702
1703 default:
1704 DP(NETIF_MSG_LINK,
1705 "link speed unsupported gp_status 0x%x\n",
1706 gp_status);
1707 return -EINVAL;
1708 break;
1709 }
1710
1711 vars->link_status |= LINK_STATUS_SERDES_LINK;
1712
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001713 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1714 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1715 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1716 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1717 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001718 vars->autoneg = AUTO_NEG_ENABLED;
1719
1720 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1721 vars->autoneg |= AUTO_NEG_COMPLETE;
1722 vars->link_status |=
1723 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1724 }
1725
1726 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1727 vars->link_status |=
1728 LINK_STATUS_PARALLEL_DETECTION_USED;
1729
1730 }
1731 if (vars->flow_ctrl & FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001732 vars->link_status |=
1733 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001734
1735 if (vars->flow_ctrl & FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001736 vars->link_status |=
1737 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001738
1739 } else { /* link_down */
1740 DP(NETIF_MSG_LINK, "phy link down\n");
1741
1742 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001743
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001744 vars->duplex = DUPLEX_FULL;
1745 vars->flow_ctrl = FLOW_CTRL_NONE;
1746 vars->autoneg = AUTO_NEG_DISABLED;
1747 vars->mac_type = MAC_TYPE_NONE;
1748 }
1749
1750 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n",
1751 gp_status, vars->phy_link_up, vars->line_speed);
1752 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1753 " autoneg 0x%x\n",
1754 vars->duplex,
1755 vars->flow_ctrl, vars->autoneg);
1756 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1757
1758 return rc;
1759}
1760
1761static void bnx2x_set_sgmii_tx_driver(struct link_params *params)
1762{
1763 struct bnx2x *bp = params->bp;
1764 u16 lp_up2;
1765 u16 tx_driver;
1766
1767 /* read precomp */
1768
1769 CL45_RD_OVER_CL22(bp, params->port,
1770 params->phy_addr,
1771 MDIO_REG_BANK_OVER_1G,
1772 MDIO_OVER_1G_LP_UP2, &lp_up2);
1773
1774 CL45_RD_OVER_CL22(bp, params->port,
1775 params->phy_addr,
1776 MDIO_REG_BANK_TX0,
1777 MDIO_TX0_TX_DRIVER, &tx_driver);
1778
1779 /* bits [10:7] at lp_up2, positioned at [15:12] */
1780 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1781 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1782 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1783
1784 if ((lp_up2 != 0) &&
1785 (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) {
1786 /* replace tx_driver bits [15:12] */
1787 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1788 tx_driver |= lp_up2;
1789 CL45_WR_OVER_CL22(bp, params->port,
1790 params->phy_addr,
1791 MDIO_REG_BANK_TX0,
1792 MDIO_TX0_TX_DRIVER, tx_driver);
1793 }
1794}
1795
1796static u8 bnx2x_emac_program(struct link_params *params,
1797 u32 line_speed, u32 duplex)
1798{
1799 struct bnx2x *bp = params->bp;
1800 u8 port = params->port;
1801 u16 mode = 0;
1802
1803 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1804 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1805 EMAC_REG_EMAC_MODE,
1806 (EMAC_MODE_25G_MODE |
1807 EMAC_MODE_PORT_MII_10M |
1808 EMAC_MODE_HALF_DUPLEX));
1809 switch (line_speed) {
1810 case SPEED_10:
1811 mode |= EMAC_MODE_PORT_MII_10M;
1812 break;
1813
1814 case SPEED_100:
1815 mode |= EMAC_MODE_PORT_MII;
1816 break;
1817
1818 case SPEED_1000:
1819 mode |= EMAC_MODE_PORT_GMII;
1820 break;
1821
1822 case SPEED_2500:
1823 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
1824 break;
1825
1826 default:
1827 /* 10G not valid for EMAC */
1828 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
1829 return -EINVAL;
1830 }
1831
1832 if (duplex == DUPLEX_HALF)
1833 mode |= EMAC_MODE_HALF_DUPLEX;
1834 bnx2x_bits_en(bp,
1835 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
1836 mode);
1837
1838 bnx2x_set_led(bp, params->port, LED_MODE_OPER,
1839 line_speed, params->hw_led_mode, params->chip_id);
1840 return 0;
1841}
1842
1843/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001844/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001845/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001846static void bnx2x_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001847{
1848 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001849 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001850 msleep(1);
1851 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001852 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001853}
1854
1855static void bnx2x_ext_phy_reset(struct link_params *params,
1856 struct link_vars *vars)
1857{
1858 struct bnx2x *bp = params->bp;
1859 u32 ext_phy_type;
1860 u8 ext_phy_addr = ((params->ext_phy_config &
1861 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1862 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1863 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
1864 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1865 /* The PHY reset is controled by GPIO 1
1866 * Give it 1ms of reset pulse
1867 */
1868 if (vars->phy_flags & PHY_XGXS_FLAG) {
1869
1870 switch (ext_phy_type) {
1871 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
1872 DP(NETIF_MSG_LINK, "XGXS Direct\n");
1873 break;
1874
1875 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
1876 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
1877 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
1878
1879 /* Restore normal power mode*/
1880 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001881 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1882 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001883
1884 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001885 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001886
1887 bnx2x_cl45_write(bp, params->port,
1888 ext_phy_type,
1889 ext_phy_addr,
1890 MDIO_PMA_DEVAD,
1891 MDIO_PMA_REG_CTRL, 0xa040);
1892 break;
1893 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
1894 /* Unset Low Power Mode and SW reset */
1895 /* Restore normal power mode*/
1896 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001897 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1898 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001899
1900 DP(NETIF_MSG_LINK, "XGXS 8072\n");
1901 bnx2x_cl45_write(bp, params->port,
1902 ext_phy_type,
1903 ext_phy_addr,
1904 MDIO_PMA_DEVAD,
1905 MDIO_PMA_REG_CTRL,
1906 1<<15);
1907 break;
1908 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
1909 {
1910 u16 emac_base;
1911 emac_base = (params->port) ? GRCBASE_EMAC0 :
1912 GRCBASE_EMAC1;
1913
1914 /* Restore normal power mode*/
1915 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001916 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1917 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001918
1919 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001920 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1921 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001922
1923 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001924 }
1925 break;
1926
1927 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
1928 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
1929
1930 /* Restore normal power mode*/
1931 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
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 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001936 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001937
1938 break;
1939
1940 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
1941 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
1942 break;
1943
1944 default:
1945 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
1946 params->ext_phy_config);
1947 break;
1948 }
1949
1950 } else { /* SerDes */
1951 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
1952 switch (ext_phy_type) {
1953 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
1954 DP(NETIF_MSG_LINK, "SerDes Direct\n");
1955 break;
1956
1957 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
1958 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001959 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001960 break;
1961
1962 default:
1963 DP(NETIF_MSG_LINK,
1964 "BAD SerDes ext_phy_config 0x%x\n",
1965 params->ext_phy_config);
1966 break;
1967 }
1968 }
1969}
1970
1971static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
1972{
1973 struct bnx2x *bp = params->bp;
1974 u8 port = params->port;
1975 u8 ext_phy_addr = ((params->ext_phy_config &
1976 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1977 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1978 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1979 u16 fw_ver1, fw_ver2;
1980
1981 /* Need to wait 200ms after reset */
1982 msleep(200);
1983 /* Boot port from external ROM
1984 * Set ser_boot_ctl bit in the MISC_CTRL1 register
1985 */
1986 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
1987 MDIO_PMA_DEVAD,
1988 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
1989
1990 /* Reset internal microprocessor */
1991 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
1992 MDIO_PMA_DEVAD,
1993 MDIO_PMA_REG_GEN_CTRL,
1994 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
1995 /* set micro reset = 0 */
1996 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
1997 MDIO_PMA_DEVAD,
1998 MDIO_PMA_REG_GEN_CTRL,
1999 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2000 /* Reset internal microprocessor */
2001 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2002 MDIO_PMA_DEVAD,
2003 MDIO_PMA_REG_GEN_CTRL,
2004 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2005 /* wait for 100ms for code download via SPI port */
2006 msleep(100);
2007
2008 /* Clear ser_boot_ctl bit */
2009 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2010 MDIO_PMA_DEVAD,
2011 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2012 /* Wait 100ms */
2013 msleep(100);
2014
2015 /* Print the PHY FW version */
2016 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2017 MDIO_PMA_DEVAD,
2018 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2019 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2020 MDIO_PMA_DEVAD,
2021 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2022 DP(NETIF_MSG_LINK, "8072 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
2023}
2024
2025static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2026{
2027 /* This is only required for 8073A1, version 102 only */
2028
2029 struct bnx2x *bp = params->bp;
2030 u8 ext_phy_addr = ((params->ext_phy_config &
2031 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2032 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2033 u16 val;
2034
2035 /* Read 8073 HW revision*/
2036 bnx2x_cl45_read(bp, params->port,
2037 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2038 ext_phy_addr,
2039 MDIO_PMA_DEVAD,
2040 0xc801, &val);
2041
2042 if (val != 1) {
2043 /* No need to workaround in 8073 A1 */
2044 return 0;
2045 }
2046
2047 bnx2x_cl45_read(bp, params->port,
2048 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2049 ext_phy_addr,
2050 MDIO_PMA_DEVAD,
2051 MDIO_PMA_REG_ROM_VER2, &val);
2052
2053 /* SNR should be applied only for version 0x102 */
2054 if (val != 0x102)
2055 return 0;
2056
2057 return 1;
2058}
2059
2060static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2061{
2062 struct bnx2x *bp = params->bp;
2063 u8 ext_phy_addr = ((params->ext_phy_config &
2064 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2065 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2066 u16 val, cnt, cnt1 ;
2067
2068 bnx2x_cl45_read(bp, params->port,
2069 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2070 ext_phy_addr,
2071 MDIO_PMA_DEVAD,
2072 0xc801, &val);
2073
2074 if (val > 0) {
2075 /* No need to workaround in 8073 A1 */
2076 return 0;
2077 }
2078 /* XAUI workaround in 8073 A0: */
2079
2080 /* After loading the boot ROM and restarting Autoneg,
2081 poll Dev1, Reg $C820: */
2082
2083 for (cnt = 0; cnt < 1000; cnt++) {
2084 bnx2x_cl45_read(bp, params->port,
2085 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2086 ext_phy_addr,
2087 MDIO_PMA_DEVAD,
2088 0xc820, &val);
2089 /* If bit [14] = 0 or bit [13] = 0, continue on with
2090 system initialization (XAUI work-around not required,
2091 as these bits indicate 2.5G or 1G link up). */
2092 if (!(val & (1<<14)) || !(val & (1<<13))) {
2093 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2094 return 0;
2095 } else if (!(val & (1<<15))) {
2096 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2097 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2098 it's MSB (bit 15) goes to 1 (indicating that the
2099 XAUI workaround has completed),
2100 then continue on with system initialization.*/
2101 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2102 bnx2x_cl45_read(bp, params->port,
2103 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2104 ext_phy_addr,
2105 MDIO_PMA_DEVAD,
2106 0xc841, &val);
2107 if (val & (1<<15)) {
2108 DP(NETIF_MSG_LINK,
2109 "XAUI workaround has completed\n");
2110 return 0;
2111 }
2112 msleep(3);
2113 }
2114 break;
2115 }
2116 msleep(3);
2117 }
2118 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2119 return -EINVAL;
2120
2121}
2122
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002123static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
2124 u8 ext_phy_addr)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002125{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002126 u16 fw_ver1, fw_ver2;
2127 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002128 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002129 bnx2x_cl45_write(bp, port,
2130 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2131 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002132 MDIO_PMA_DEVAD,
2133 MDIO_PMA_REG_GEN_CTRL,
2134 0x0001);
2135
2136 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002137 bnx2x_cl45_write(bp, port,
2138 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2139 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002140 MDIO_PMA_DEVAD,
2141 MDIO_PMA_REG_GEN_CTRL,
2142 0x008c);
2143
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002144 bnx2x_cl45_write(bp, port,
2145 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2146 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002147 MDIO_PMA_DEVAD,
2148 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2149
2150 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002151 bnx2x_cl45_write(bp, port,
2152 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2153 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002154 MDIO_PMA_DEVAD,
2155 MDIO_PMA_REG_GEN_CTRL,
2156 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2157
2158 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002159 bnx2x_cl45_write(bp, port,
2160 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2161 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002162 MDIO_PMA_DEVAD,
2163 MDIO_PMA_REG_GEN_CTRL,
2164 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2165
2166 /* wait for 100ms for code download via SPI port */
2167 msleep(100);
2168
2169 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002170 bnx2x_cl45_write(bp, port,
2171 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2172 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002173 MDIO_PMA_DEVAD,
2174 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2175
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002176 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2177 ext_phy_addr,
2178 MDIO_PMA_DEVAD,
2179 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2180 bnx2x_cl45_read(bp, port,
2181 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2182 ext_phy_addr,
2183 MDIO_PMA_DEVAD,
2184 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002185 DP(NETIF_MSG_LINK, "8073 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
2186
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002187}
2188
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002189static void bnx2x_bcm807x_force_10G(struct link_params *params)
2190{
2191 struct bnx2x *bp = params->bp;
2192 u8 port = params->port;
2193 u8 ext_phy_addr = ((params->ext_phy_config &
2194 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2195 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2196 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2197
2198 /* Force KR or KX */
2199 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2200 MDIO_PMA_DEVAD,
2201 MDIO_PMA_REG_CTRL,
2202 0x2040);
2203 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2204 MDIO_PMA_DEVAD,
2205 MDIO_PMA_REG_10G_CTRL2,
2206 0x000b);
2207 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2208 MDIO_PMA_DEVAD,
2209 MDIO_PMA_REG_BCM_CTRL,
2210 0x0000);
2211 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2212 MDIO_AN_DEVAD,
2213 MDIO_AN_REG_CTRL,
2214 0x0000);
2215}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002216static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
2217{
2218 struct bnx2x *bp = params->bp;
2219 u8 port = params->port;
2220 u16 val;
2221 u8 ext_phy_addr = ((params->ext_phy_config &
2222 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2223 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2224 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2225
2226 bnx2x_cl45_read(bp, params->port,
2227 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2228 ext_phy_addr,
2229 MDIO_PMA_DEVAD,
2230 0xc801, &val);
2231
2232 if (val == 0) {
2233 /* Mustn't set low power mode in 8073 A0 */
2234 return;
2235 }
2236
2237 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
2238 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2239 MDIO_XS_DEVAD,
2240 MDIO_XS_PLL_SEQUENCER, &val);
2241 val &= ~(1<<13);
2242 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2243 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2244
2245 /* PLL controls */
2246 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2247 MDIO_XS_DEVAD, 0x805E, 0x1077);
2248 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2249 MDIO_XS_DEVAD, 0x805D, 0x0000);
2250 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2251 MDIO_XS_DEVAD, 0x805C, 0x030B);
2252 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2253 MDIO_XS_DEVAD, 0x805B, 0x1240);
2254 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2255 MDIO_XS_DEVAD, 0x805A, 0x2490);
2256
2257 /* Tx Controls */
2258 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2259 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2260 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2261 MDIO_XS_DEVAD, 0x80A6, 0x9041);
2262 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2263 MDIO_XS_DEVAD, 0x80A5, 0x4640);
2264
2265 /* Rx Controls */
2266 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2267 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2268 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2269 MDIO_XS_DEVAD, 0x80FD, 0x9249);
2270 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2271 MDIO_XS_DEVAD, 0x80FC, 0x2015);
2272
2273 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
2274 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2275 MDIO_XS_DEVAD,
2276 MDIO_XS_PLL_SEQUENCER, &val);
2277 val |= (1<<13);
2278 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2279 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2280}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002281
2282static void bnx2x_8073_set_pause_cl37(struct link_params *params,
2283 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002284{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002285
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002286 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002287 u16 cl37_val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002288 u8 ext_phy_addr = ((params->ext_phy_config &
2289 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2290 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2291 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2292
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002293 bnx2x_cl45_read(bp, params->port,
2294 ext_phy_type,
2295 ext_phy_addr,
2296 MDIO_AN_DEVAD,
2297 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
2298
2299 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2300 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2301
2302 if ((vars->ieee_fc &
2303 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
2304 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
2305 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
2306 }
2307 if ((vars->ieee_fc &
2308 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2309 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2310 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2311 }
2312 if ((vars->ieee_fc &
2313 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2314 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2315 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2316 }
2317 DP(NETIF_MSG_LINK,
2318 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
2319
2320 bnx2x_cl45_write(bp, params->port,
2321 ext_phy_type,
2322 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002323 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002324 MDIO_AN_REG_CL37_FC_LD, cl37_val);
2325 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002326}
2327
2328static void bnx2x_ext_phy_set_pause(struct link_params *params,
2329 struct link_vars *vars)
2330{
2331 struct bnx2x *bp = params->bp;
2332 u16 val;
2333 u8 ext_phy_addr = ((params->ext_phy_config &
2334 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2335 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2336 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2337
2338 /* read modify write pause advertizing */
2339 bnx2x_cl45_read(bp, params->port,
2340 ext_phy_type,
2341 ext_phy_addr,
2342 MDIO_AN_DEVAD,
2343 MDIO_AN_REG_ADV_PAUSE, &val);
2344
2345 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002346
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002347 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2348
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002349 if ((vars->ieee_fc &
2350 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002351 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2352 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2353 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002354 if ((vars->ieee_fc &
2355 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002356 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2357 val |=
2358 MDIO_AN_REG_ADV_PAUSE_PAUSE;
2359 }
2360 DP(NETIF_MSG_LINK,
2361 "Ext phy AN advertize 0x%x\n", val);
2362 bnx2x_cl45_write(bp, params->port,
2363 ext_phy_type,
2364 ext_phy_addr,
2365 MDIO_AN_DEVAD,
2366 MDIO_AN_REG_ADV_PAUSE, val);
2367}
2368
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002369
2370static void bnx2x_init_internal_phy(struct link_params *params,
2371 struct link_vars *vars)
2372{
2373 struct bnx2x *bp = params->bp;
2374 u8 port = params->port;
2375 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2376 u16 bank, rx_eq;
2377
2378 rx_eq = ((params->serdes_config &
2379 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >>
2380 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT);
2381
2382 DP(NETIF_MSG_LINK, "setting rx eq to 0x%x\n", rx_eq);
2383 for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL;
2384 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0)) {
2385 CL45_WR_OVER_CL22(bp, port,
2386 params->phy_addr,
2387 bank ,
2388 MDIO_RX0_RX_EQ_BOOST,
2389 ((rx_eq &
2390 MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) |
2391 MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL));
2392 }
2393
2394 /* forced speed requested? */
2395 if (vars->line_speed != SPEED_AUTO_NEG) {
2396 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2397
2398 /* disable autoneg */
2399 bnx2x_set_autoneg(params, vars);
2400
2401 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002402 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002403
2404 } else { /* AN_mode */
2405 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2406
2407 /* AN enabled */
2408 bnx2x_set_brcm_cl37_advertisment(params);
2409
2410 /* program duplex & pause advertisement (for aneg) */
2411 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002412 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002413
2414 /* enable autoneg */
2415 bnx2x_set_autoneg(params, vars);
2416
2417 /* enable and restart AN */
2418 bnx2x_restart_autoneg(params);
2419 }
2420
2421 } else { /* SGMII mode */
2422 DP(NETIF_MSG_LINK, "SGMII\n");
2423
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002424 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002425 }
2426}
2427
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002428static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
2429{
2430 struct bnx2x *bp = params->bp;
2431 u32 ext_phy_type;
2432 u8 ext_phy_addr;
2433 u16 cnt;
2434 u16 ctrl = 0;
2435 u16 val = 0;
2436 u8 rc = 0;
2437 if (vars->phy_flags & PHY_XGXS_FLAG) {
2438 ext_phy_addr = ((params->ext_phy_config &
2439 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2440 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2441
2442 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2443 /* Make sure that the soft reset is off (expect for the 8072:
2444 * due to the lock, it will be done inside the specific
2445 * handling)
2446 */
2447 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
2448 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
2449 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
2450 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
2451 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
2452 /* Wait for soft reset to get cleared upto 1 sec */
2453 for (cnt = 0; cnt < 1000; cnt++) {
2454 bnx2x_cl45_read(bp, params->port,
2455 ext_phy_type,
2456 ext_phy_addr,
2457 MDIO_PMA_DEVAD,
2458 MDIO_PMA_REG_CTRL, &ctrl);
2459 if (!(ctrl & (1<<15)))
2460 break;
2461 msleep(1);
2462 }
2463 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
2464 ctrl, cnt);
2465 }
2466
2467 switch (ext_phy_type) {
2468 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002469 break;
2470
2471 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2472 DP(NETIF_MSG_LINK, "XGXS 8705\n");
2473
2474 bnx2x_cl45_write(bp, params->port,
2475 ext_phy_type,
2476 ext_phy_addr,
2477 MDIO_PMA_DEVAD,
2478 MDIO_PMA_REG_MISC_CTRL,
2479 0x8288);
2480 bnx2x_cl45_write(bp, params->port,
2481 ext_phy_type,
2482 ext_phy_addr,
2483 MDIO_PMA_DEVAD,
2484 MDIO_PMA_REG_PHY_IDENTIFIER,
2485 0x7fbf);
2486 bnx2x_cl45_write(bp, params->port,
2487 ext_phy_type,
2488 ext_phy_addr,
2489 MDIO_PMA_DEVAD,
2490 MDIO_PMA_REG_CMU_PLL_BYPASS,
2491 0x0100);
2492 bnx2x_cl45_write(bp, params->port,
2493 ext_phy_type,
2494 ext_phy_addr,
2495 MDIO_WIS_DEVAD,
2496 MDIO_WIS_REG_LASI_CNTL, 0x1);
2497 break;
2498
2499 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2500 DP(NETIF_MSG_LINK, "XGXS 8706\n");
2501
2502 msleep(10);
2503 /* Force speed */
2504 /* First enable LASI */
2505 bnx2x_cl45_write(bp, params->port,
2506 ext_phy_type,
2507 ext_phy_addr,
2508 MDIO_PMA_DEVAD,
2509 MDIO_PMA_REG_RX_ALARM_CTRL,
2510 0x0400);
2511 bnx2x_cl45_write(bp, params->port,
2512 ext_phy_type,
2513 ext_phy_addr,
2514 MDIO_PMA_DEVAD,
2515 MDIO_PMA_REG_LASI_CTRL, 0x0004);
2516
2517 if (params->req_line_speed == SPEED_10000) {
2518 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
2519
2520 bnx2x_cl45_write(bp, params->port,
2521 ext_phy_type,
2522 ext_phy_addr,
2523 MDIO_PMA_DEVAD,
2524 MDIO_PMA_REG_DIGITAL_CTRL,
2525 0x400);
2526 } else {
2527 /* Force 1Gbps using autoneg with 1G
2528 advertisment */
2529
2530 /* Allow CL37 through CL73 */
2531 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
2532 bnx2x_cl45_write(bp, params->port,
2533 ext_phy_type,
2534 ext_phy_addr,
2535 MDIO_AN_DEVAD,
2536 MDIO_AN_REG_CL37_CL73,
2537 0x040c);
2538
2539 /* Enable Full-Duplex advertisment on CL37 */
2540 bnx2x_cl45_write(bp, params->port,
2541 ext_phy_type,
2542 ext_phy_addr,
2543 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002544 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002545 0x0020);
2546 /* Enable CL37 AN */
2547 bnx2x_cl45_write(bp, params->port,
2548 ext_phy_type,
2549 ext_phy_addr,
2550 MDIO_AN_DEVAD,
2551 MDIO_AN_REG_CL37_AN,
2552 0x1000);
2553 /* 1G support */
2554 bnx2x_cl45_write(bp, params->port,
2555 ext_phy_type,
2556 ext_phy_addr,
2557 MDIO_AN_DEVAD,
2558 MDIO_AN_REG_ADV, (1<<5));
2559
2560 /* Enable clause 73 AN */
2561 bnx2x_cl45_write(bp, params->port,
2562 ext_phy_type,
2563 ext_phy_addr,
2564 MDIO_AN_DEVAD,
2565 MDIO_AN_REG_CTRL,
2566 0x1200);
2567
2568 }
2569
2570 break;
2571
2572 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
2573 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
2574 {
2575 u16 tmp1;
2576 u16 rx_alarm_ctrl_val;
2577 u16 lasi_ctrl_val;
2578 if (ext_phy_type ==
2579 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
2580 rx_alarm_ctrl_val = 0x400;
2581 lasi_ctrl_val = 0x0004;
2582 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002583 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002584 lasi_ctrl_val = 0x0004;
2585 }
2586
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002587 /* enable LASI */
2588 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002589 ext_phy_type,
2590 ext_phy_addr,
2591 MDIO_PMA_DEVAD,
2592 MDIO_PMA_REG_RX_ALARM_CTRL,
2593 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002594
2595 bnx2x_cl45_write(bp, params->port,
2596 ext_phy_type,
2597 ext_phy_addr,
2598 MDIO_PMA_DEVAD,
2599 MDIO_PMA_REG_LASI_CTRL,
2600 lasi_ctrl_val);
2601
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002602 bnx2x_8073_set_pause_cl37(params, vars);
2603
2604 if (ext_phy_type ==
2605 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){
2606 bnx2x_bcm8072_external_rom_boot(params);
2607 } else {
2608
2609 /* In case of 8073 with long xaui lines,
2610 don't set the 8073 xaui low power*/
2611 bnx2x_bcm8073_set_xaui_low_power_mode(params);
2612 }
2613
2614 bnx2x_cl45_read(bp, params->port,
2615 ext_phy_type,
2616 ext_phy_addr,
2617 MDIO_PMA_DEVAD,
2618 0xca13,
2619 &tmp1);
2620
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002621 bnx2x_cl45_read(bp, params->port,
2622 ext_phy_type,
2623 ext_phy_addr,
2624 MDIO_PMA_DEVAD,
2625 MDIO_PMA_REG_RX_ALARM, &tmp1);
2626
2627 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
2628 "0x%x\n", tmp1);
2629
2630 /* If this is forced speed, set to KR or KX
2631 * (all other are not supported)
2632 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002633 if (params->loopback_mode == LOOPBACK_EXT) {
2634 bnx2x_bcm807x_force_10G(params);
2635 DP(NETIF_MSG_LINK,
2636 "Forced speed 10G on 807X\n");
2637 break;
2638 } else {
2639 bnx2x_cl45_write(bp, params->port,
2640 ext_phy_type, ext_phy_addr,
2641 MDIO_PMA_DEVAD,
2642 MDIO_PMA_REG_BCM_CTRL,
2643 0x0002);
2644 }
2645 if (params->req_line_speed != SPEED_AUTO_NEG) {
2646 if (params->req_line_speed == SPEED_10000) {
2647 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002648 } else if (params->req_line_speed ==
2649 SPEED_2500) {
2650 val = (1<<5);
2651 /* Note that 2.5G works only
2652 when used with 1G advertisment */
2653 } else
2654 val = (1<<5);
2655 } else {
2656
2657 val = 0;
2658 if (params->speed_cap_mask &
2659 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
2660 val |= (1<<7);
2661
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002662 /* Note that 2.5G works only when
2663 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002664 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002665 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
2666 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002667 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002668 DP(NETIF_MSG_LINK,
2669 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002670 }
2671
2672 bnx2x_cl45_write(bp, params->port,
2673 ext_phy_type,
2674 ext_phy_addr,
2675 MDIO_AN_DEVAD,
2676 MDIO_AN_REG_ADV, val);
2677
2678 if (ext_phy_type ==
2679 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002680
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002681 bnx2x_cl45_read(bp, params->port,
2682 ext_phy_type,
2683 ext_phy_addr,
2684 MDIO_AN_DEVAD,
2685 0x8329, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002686
2687 if (((params->speed_cap_mask &
2688 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
2689 (params->req_line_speed ==
2690 SPEED_AUTO_NEG)) ||
2691 (params->req_line_speed ==
2692 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002693 u16 phy_ver;
2694 /* Allow 2.5G for A1 and above */
2695 bnx2x_cl45_read(bp, params->port,
2696 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2697 ext_phy_addr,
2698 MDIO_PMA_DEVAD,
2699 0xc801, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002700 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002701 if (phy_ver > 0)
2702 tmp1 |= 1;
2703 else
2704 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002705 } else {
2706 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002707 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002708 }
2709
2710 bnx2x_cl45_write(bp, params->port,
2711 ext_phy_type,
2712 ext_phy_addr,
2713 MDIO_AN_DEVAD,
2714 0x8329, tmp1);
2715 }
2716
2717 /* Add support for CL37 (passive mode) II */
2718
2719 bnx2x_cl45_read(bp, params->port,
2720 ext_phy_type,
2721 ext_phy_addr,
2722 MDIO_AN_DEVAD,
2723 MDIO_AN_REG_CL37_FC_LD,
2724 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002725
2726 bnx2x_cl45_write(bp, params->port,
2727 ext_phy_type,
2728 ext_phy_addr,
2729 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002730 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
2731 ((params->req_duplex == DUPLEX_FULL) ?
2732 0x20 : 0x40)));
2733
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002734 /* Add support for CL37 (passive mode) III */
2735 bnx2x_cl45_write(bp, params->port,
2736 ext_phy_type,
2737 ext_phy_addr,
2738 MDIO_AN_DEVAD,
2739 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002740
2741 if (ext_phy_type ==
2742 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002743 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002744 BW and FEE main tap. Rest commands are executed
2745 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002746 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002747 if (bnx2x_8073_is_snr_needed(params))
2748 bnx2x_cl45_write(bp, params->port,
2749 ext_phy_type,
2750 ext_phy_addr,
2751 MDIO_PMA_DEVAD,
2752 MDIO_PMA_REG_EDC_FFE_MAIN,
2753 0xFB0C);
2754
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002755 /* Enable FEC (Forware Error Correction)
2756 Request in the AN */
2757 bnx2x_cl45_read(bp, params->port,
2758 ext_phy_type,
2759 ext_phy_addr,
2760 MDIO_AN_DEVAD,
2761 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002762
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002763 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002764
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002765 bnx2x_cl45_write(bp, params->port,
2766 ext_phy_type,
2767 ext_phy_addr,
2768 MDIO_AN_DEVAD,
2769 MDIO_AN_REG_ADV2, tmp1);
2770
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002771 }
2772
2773 bnx2x_ext_phy_set_pause(params, vars);
2774
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002775 /* Restart autoneg */
2776 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002777 bnx2x_cl45_write(bp, params->port,
2778 ext_phy_type,
2779 ext_phy_addr,
2780 MDIO_AN_DEVAD,
2781 MDIO_AN_REG_CTRL, 0x1200);
2782 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
2783 "Advertise 1G=%x, 10G=%x\n",
2784 ((val & (1<<5)) > 0),
2785 ((val & (1<<7)) > 0));
2786 break;
2787 }
2788 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
2789 DP(NETIF_MSG_LINK,
2790 "Setting the SFX7101 LASI indication\n");
2791
2792 bnx2x_cl45_write(bp, params->port,
2793 ext_phy_type,
2794 ext_phy_addr,
2795 MDIO_PMA_DEVAD,
2796 MDIO_PMA_REG_LASI_CTRL, 0x1);
2797 DP(NETIF_MSG_LINK,
2798 "Setting the SFX7101 LED to blink on traffic\n");
2799 bnx2x_cl45_write(bp, params->port,
2800 ext_phy_type,
2801 ext_phy_addr,
2802 MDIO_PMA_DEVAD,
2803 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
2804
2805 bnx2x_ext_phy_set_pause(params, vars);
2806 /* Restart autoneg */
2807 bnx2x_cl45_read(bp, params->port,
2808 ext_phy_type,
2809 ext_phy_addr,
2810 MDIO_AN_DEVAD,
2811 MDIO_AN_REG_CTRL, &val);
2812 val |= 0x200;
2813 bnx2x_cl45_write(bp, params->port,
2814 ext_phy_type,
2815 ext_phy_addr,
2816 MDIO_AN_DEVAD,
2817 MDIO_AN_REG_CTRL, val);
2818 break;
2819 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
2820 DP(NETIF_MSG_LINK,
2821 "XGXS PHY Failure detected 0x%x\n",
2822 params->ext_phy_config);
2823 rc = -EINVAL;
2824 break;
2825 default:
2826 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
2827 params->ext_phy_config);
2828 rc = -EINVAL;
2829 break;
2830 }
2831
2832 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002833
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002834 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
2835 switch (ext_phy_type) {
2836 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
2837 DP(NETIF_MSG_LINK, "SerDes Direct\n");
2838 break;
2839
2840 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
2841 DP(NETIF_MSG_LINK, "SerDes 5482\n");
2842 break;
2843
2844 default:
2845 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
2846 params->ext_phy_config);
2847 break;
2848 }
2849 }
2850 return rc;
2851}
2852
2853
2854static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002855 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002856{
2857 struct bnx2x *bp = params->bp;
2858 u32 ext_phy_type;
2859 u8 ext_phy_addr;
2860 u16 val1 = 0, val2;
2861 u16 rx_sd, pcs_status;
2862 u8 ext_phy_link_up = 0;
2863 u8 port = params->port;
2864 if (vars->phy_flags & PHY_XGXS_FLAG) {
2865 ext_phy_addr = ((params->ext_phy_config &
2866 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2867 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2868
2869 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2870 switch (ext_phy_type) {
2871 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
2872 DP(NETIF_MSG_LINK, "XGXS Direct\n");
2873 ext_phy_link_up = 1;
2874 break;
2875
2876 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2877 DP(NETIF_MSG_LINK, "XGXS 8705\n");
2878 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2879 ext_phy_addr,
2880 MDIO_WIS_DEVAD,
2881 MDIO_WIS_REG_LASI_STATUS, &val1);
2882 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
2883
2884 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2885 ext_phy_addr,
2886 MDIO_WIS_DEVAD,
2887 MDIO_WIS_REG_LASI_STATUS, &val1);
2888 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
2889
2890 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2891 ext_phy_addr,
2892 MDIO_PMA_DEVAD,
2893 MDIO_PMA_REG_RX_SD, &rx_sd);
2894 DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
2895 ext_phy_link_up = (rx_sd & 0x1);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002896 if (ext_phy_link_up)
2897 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002898 break;
2899
2900 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
2901 DP(NETIF_MSG_LINK, "XGXS 8706\n");
2902 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2903 ext_phy_addr,
2904 MDIO_PMA_DEVAD,
2905 MDIO_PMA_REG_LASI_STATUS, &val1);
2906 DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
2907
2908 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2909 ext_phy_addr,
2910 MDIO_PMA_DEVAD,
2911 MDIO_PMA_REG_LASI_STATUS, &val1);
2912 DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
2913
2914 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2915 ext_phy_addr,
2916 MDIO_PMA_DEVAD,
2917 MDIO_PMA_REG_RX_SD, &rx_sd);
2918 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2919 ext_phy_addr,
2920 MDIO_PCS_DEVAD,
2921 MDIO_PCS_REG_STATUS, &pcs_status);
2922
2923 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2924 ext_phy_addr,
2925 MDIO_AN_DEVAD,
2926 MDIO_AN_REG_LINK_STATUS, &val2);
2927 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2928 ext_phy_addr,
2929 MDIO_AN_DEVAD,
2930 MDIO_AN_REG_LINK_STATUS, &val2);
2931
2932 DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x"
2933 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
2934 rx_sd, pcs_status, val2);
2935 /* link is up if both bit 0 of pmd_rx_sd and
2936 * bit 0 of pcs_status are set, or if the autoneg bit
2937 1 is set
2938 */
2939 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
2940 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002941 if (ext_phy_link_up) {
2942 if (val2 & (1<<1))
2943 vars->line_speed = SPEED_1000;
2944 else
2945 vars->line_speed = SPEED_10000;
2946 }
2947
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002948 /* clear LASI indication*/
2949 bnx2x_cl45_read(bp, params->port, ext_phy_type,
2950 ext_phy_addr,
2951 MDIO_PMA_DEVAD,
2952 MDIO_PMA_REG_RX_ALARM, &val2);
2953 break;
2954
2955 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
2956 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
2957 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002958 u16 link_status = 0;
2959 u16 an1000_status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002960 if (ext_phy_type ==
2961 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
2962 bnx2x_cl45_read(bp, params->port,
2963 ext_phy_type,
2964 ext_phy_addr,
2965 MDIO_PCS_DEVAD,
2966 MDIO_PCS_REG_LASI_STATUS, &val1);
2967 bnx2x_cl45_read(bp, params->port,
2968 ext_phy_type,
2969 ext_phy_addr,
2970 MDIO_PCS_DEVAD,
2971 MDIO_PCS_REG_LASI_STATUS, &val2);
2972 DP(NETIF_MSG_LINK,
2973 "870x LASI status 0x%x->0x%x\n",
2974 val1, val2);
2975
2976 } else {
2977 /* In 8073, port1 is directed through emac0 and
2978 * port0 is directed through emac1
2979 */
2980 bnx2x_cl45_read(bp, params->port,
2981 ext_phy_type,
2982 ext_phy_addr,
2983 MDIO_PMA_DEVAD,
2984 MDIO_PMA_REG_LASI_STATUS, &val1);
2985
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002986 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002987 "8703 LASI status 0x%x\n",
2988 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002989 }
2990
2991 /* clear the interrupt LASI status register */
2992 bnx2x_cl45_read(bp, params->port,
2993 ext_phy_type,
2994 ext_phy_addr,
2995 MDIO_PCS_DEVAD,
2996 MDIO_PCS_REG_STATUS, &val2);
2997 bnx2x_cl45_read(bp, params->port,
2998 ext_phy_type,
2999 ext_phy_addr,
3000 MDIO_PCS_DEVAD,
3001 MDIO_PCS_REG_STATUS, &val1);
3002 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
3003 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003004 /* Clear MSG-OUT */
3005 bnx2x_cl45_read(bp, params->port,
3006 ext_phy_type,
3007 ext_phy_addr,
3008 MDIO_PMA_DEVAD,
3009 0xca13,
3010 &val1);
3011
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003012 /* Check the LASI */
3013 bnx2x_cl45_read(bp, params->port,
3014 ext_phy_type,
3015 ext_phy_addr,
3016 MDIO_PMA_DEVAD,
3017 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003018
3019 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3020
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003021 /* Check the link status */
3022 bnx2x_cl45_read(bp, params->port,
3023 ext_phy_type,
3024 ext_phy_addr,
3025 MDIO_PCS_DEVAD,
3026 MDIO_PCS_REG_STATUS, &val2);
3027 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3028
3029 bnx2x_cl45_read(bp, params->port,
3030 ext_phy_type,
3031 ext_phy_addr,
3032 MDIO_PMA_DEVAD,
3033 MDIO_PMA_REG_STATUS, &val2);
3034 bnx2x_cl45_read(bp, params->port,
3035 ext_phy_type,
3036 ext_phy_addr,
3037 MDIO_PMA_DEVAD,
3038 MDIO_PMA_REG_STATUS, &val1);
3039 ext_phy_link_up = ((val1 & 4) == 4);
3040 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3041 if (ext_phy_type ==
3042 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003043
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003044 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003045 ((params->req_line_speed !=
3046 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003047 if (bnx2x_bcm8073_xaui_wa(params)
3048 != 0) {
3049 ext_phy_link_up = 0;
3050 break;
3051 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003052 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003053 bnx2x_cl45_read(bp, params->port,
3054 ext_phy_type,
3055 ext_phy_addr,
3056 MDIO_AN_DEVAD,
3057 0x8304,
3058 &an1000_status);
3059 bnx2x_cl45_read(bp, params->port,
3060 ext_phy_type,
3061 ext_phy_addr,
3062 MDIO_AN_DEVAD,
3063 0x8304,
3064 &an1000_status);
3065
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003066 /* Check the link status on 1.1.2 */
3067 bnx2x_cl45_read(bp, params->port,
3068 ext_phy_type,
3069 ext_phy_addr,
3070 MDIO_PMA_DEVAD,
3071 MDIO_PMA_REG_STATUS, &val2);
3072 bnx2x_cl45_read(bp, params->port,
3073 ext_phy_type,
3074 ext_phy_addr,
3075 MDIO_PMA_DEVAD,
3076 MDIO_PMA_REG_STATUS, &val1);
3077 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3078 "an_link_status=0x%x\n",
3079 val2, val1, an1000_status);
3080
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003081 ext_phy_link_up = (((val1 & 4) == 4) ||
3082 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003083 if (ext_phy_link_up &&
3084 bnx2x_8073_is_snr_needed(params)) {
3085 /* The SNR will improve about 2dbby
3086 changing the BW and FEE main tap.*/
3087
3088 /* The 1st write to change FFE main
3089 tap is set before restart AN */
3090 /* Change PLL Bandwidth in EDC
3091 register */
3092 bnx2x_cl45_write(bp, port, ext_phy_type,
3093 ext_phy_addr,
3094 MDIO_PMA_DEVAD,
3095 MDIO_PMA_REG_PLL_BANDWIDTH,
3096 0x26BC);
3097
3098 /* Change CDR Bandwidth in EDC
3099 register */
3100 bnx2x_cl45_write(bp, port, ext_phy_type,
3101 ext_phy_addr,
3102 MDIO_PMA_DEVAD,
3103 MDIO_PMA_REG_CDR_BANDWIDTH,
3104 0x0333);
3105
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003106
3107 }
3108 bnx2x_cl45_read(bp, params->port,
3109 ext_phy_type,
3110 ext_phy_addr,
3111 MDIO_PMA_DEVAD,
3112 0xc820,
3113 &link_status);
3114
3115 /* Bits 0..2 --> speed detected,
3116 bits 13..15--> link is down */
3117 if ((link_status & (1<<2)) &&
3118 (!(link_status & (1<<15)))) {
3119 ext_phy_link_up = 1;
3120 vars->line_speed = SPEED_10000;
3121 DP(NETIF_MSG_LINK,
3122 "port %x: External link"
3123 " up in 10G\n", params->port);
3124 } else if ((link_status & (1<<1)) &&
3125 (!(link_status & (1<<14)))) {
3126 ext_phy_link_up = 1;
3127 vars->line_speed = SPEED_2500;
3128 DP(NETIF_MSG_LINK,
3129 "port %x: External link"
3130 " up in 2.5G\n", params->port);
3131 } else if ((link_status & (1<<0)) &&
3132 (!(link_status & (1<<13)))) {
3133 ext_phy_link_up = 1;
3134 vars->line_speed = SPEED_1000;
3135 DP(NETIF_MSG_LINK,
3136 "port %x: External link"
3137 " up in 1G\n", params->port);
3138 } else {
3139 ext_phy_link_up = 0;
3140 DP(NETIF_MSG_LINK,
3141 "port %x: External link"
3142 " is down\n", params->port);
3143 }
3144 } else {
3145 /* See if 1G link is up for the 8072 */
3146 bnx2x_cl45_read(bp, params->port,
3147 ext_phy_type,
3148 ext_phy_addr,
3149 MDIO_AN_DEVAD,
3150 0x8304,
3151 &an1000_status);
3152 bnx2x_cl45_read(bp, params->port,
3153 ext_phy_type,
3154 ext_phy_addr,
3155 MDIO_AN_DEVAD,
3156 0x8304,
3157 &an1000_status);
3158 if (an1000_status & (1<<1)) {
3159 ext_phy_link_up = 1;
3160 vars->line_speed = SPEED_1000;
3161 DP(NETIF_MSG_LINK,
3162 "port %x: External link"
3163 " up in 1G\n", params->port);
3164 } else if (ext_phy_link_up) {
3165 ext_phy_link_up = 1;
3166 vars->line_speed = SPEED_10000;
3167 DP(NETIF_MSG_LINK,
3168 "port %x: External link"
3169 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003170 }
3171 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003172
3173
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003174 break;
3175 }
3176 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3177 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3178 ext_phy_addr,
3179 MDIO_PMA_DEVAD,
3180 MDIO_PMA_REG_LASI_STATUS, &val2);
3181 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3182 ext_phy_addr,
3183 MDIO_PMA_DEVAD,
3184 MDIO_PMA_REG_LASI_STATUS, &val1);
3185 DP(NETIF_MSG_LINK,
3186 "10G-base-T LASI status 0x%x->0x%x\n",
3187 val2, val1);
3188 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3189 ext_phy_addr,
3190 MDIO_PMA_DEVAD,
3191 MDIO_PMA_REG_STATUS, &val2);
3192 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3193 ext_phy_addr,
3194 MDIO_PMA_DEVAD,
3195 MDIO_PMA_REG_STATUS, &val1);
3196 DP(NETIF_MSG_LINK,
3197 "10G-base-T PMA status 0x%x->0x%x\n",
3198 val2, val1);
3199 ext_phy_link_up = ((val1 & 4) == 4);
3200 /* if link is up
3201 * print the AN outcome of the SFX7101 PHY
3202 */
3203 if (ext_phy_link_up) {
3204 bnx2x_cl45_read(bp, params->port,
3205 ext_phy_type,
3206 ext_phy_addr,
3207 MDIO_AN_DEVAD,
3208 MDIO_AN_REG_MASTER_STATUS,
3209 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003210 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003211 DP(NETIF_MSG_LINK,
3212 "SFX7101 AN status 0x%x->Master=%x\n",
3213 val2,
3214 (val2 & (1<<14)));
3215 }
3216 break;
3217
3218 default:
3219 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3220 params->ext_phy_config);
3221 ext_phy_link_up = 0;
3222 break;
3223 }
3224
3225 } else { /* SerDes */
3226 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3227 switch (ext_phy_type) {
3228 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3229 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3230 ext_phy_link_up = 1;
3231 break;
3232
3233 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3234 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3235 ext_phy_link_up = 1;
3236 break;
3237
3238 default:
3239 DP(NETIF_MSG_LINK,
3240 "BAD SerDes ext_phy_config 0x%x\n",
3241 params->ext_phy_config);
3242 ext_phy_link_up = 0;
3243 break;
3244 }
3245 }
3246
3247 return ext_phy_link_up;
3248}
3249
3250static void bnx2x_link_int_enable(struct link_params *params)
3251{
3252 u8 port = params->port;
3253 u32 ext_phy_type;
3254 u32 mask;
3255 struct bnx2x *bp = params->bp;
3256 /* setting the status to report on link up
3257 for either XGXS or SerDes */
3258
3259 if (params->switch_cfg == SWITCH_CFG_10G) {
3260 mask = (NIG_MASK_XGXS0_LINK10G |
3261 NIG_MASK_XGXS0_LINK_STATUS);
3262 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
3263 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3264 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3265 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3266 (ext_phy_type !=
3267 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
3268 mask |= NIG_MASK_MI_INT;
3269 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3270 }
3271
3272 } else { /* SerDes */
3273 mask = NIG_MASK_SERDES0_LINK_STATUS;
3274 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
3275 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3276 if ((ext_phy_type !=
3277 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
3278 (ext_phy_type !=
3279 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
3280 mask |= NIG_MASK_MI_INT;
3281 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3282 }
3283 }
3284 bnx2x_bits_en(bp,
3285 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
3286 mask);
3287 DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port,
3288 (params->switch_cfg == SWITCH_CFG_10G),
3289 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
3290
3291 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
3292 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
3293 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
3294 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
3295 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
3296 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
3297 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
3298}
3299
3300
3301/*
3302 * link management
3303 */
3304static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07003305 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003306{
3307 struct bnx2x *bp = params->bp;
3308 u8 port = params->port;
3309
3310 /* first reset all status
3311 * we assume only one line will be change at a time */
3312 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3313 (NIG_STATUS_XGXS0_LINK10G |
3314 NIG_STATUS_XGXS0_LINK_STATUS |
3315 NIG_STATUS_SERDES0_LINK_STATUS));
3316 if (vars->phy_link_up) {
3317 if (is_10g) {
3318 /* Disable the 10G link interrupt
3319 * by writing 1 to the status register
3320 */
3321 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
3322 bnx2x_bits_en(bp,
3323 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3324 NIG_STATUS_XGXS0_LINK10G);
3325
3326 } else if (params->switch_cfg == SWITCH_CFG_10G) {
3327 /* Disable the link interrupt
3328 * by writing 1 to the relevant lane
3329 * in the status register
3330 */
3331 u32 ser_lane = ((params->lane_config &
3332 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
3333 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
3334
3335 DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
3336 bnx2x_bits_en(bp,
3337 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3338 ((1 << ser_lane) <<
3339 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
3340
3341 } else { /* SerDes */
3342 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
3343 /* Disable the link interrupt
3344 * by writing 1 to the status register
3345 */
3346 bnx2x_bits_en(bp,
3347 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
3348 NIG_STATUS_SERDES0_LINK_STATUS);
3349 }
3350
3351 } else { /* link_down */
3352 }
3353}
3354
3355static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
3356{
3357 u8 *str_ptr = str;
3358 u32 mask = 0xf0000000;
3359 u8 shift = 8*4;
3360 u8 digit;
3361 if (len < 10) {
3362 /* Need more then 10chars for this format */
3363 *str_ptr = '\0';
3364 return -EINVAL;
3365 }
3366 while (shift > 0) {
3367
3368 shift -= 4;
3369 digit = ((num & mask) >> shift);
3370 if (digit < 0xa)
3371 *str_ptr = digit + '0';
3372 else
3373 *str_ptr = digit - 0xa + 'a';
3374 str_ptr++;
3375 mask = mask >> 4;
3376 if (shift == 4*4) {
3377 *str_ptr = ':';
3378 str_ptr++;
3379 }
3380 }
3381 *str_ptr = '\0';
3382 return 0;
3383}
3384
3385
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003386static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr,
3387 u32 ext_phy_type)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003388{
3389 u32 cnt = 0;
3390 u16 ctrl = 0;
3391 /* Enable EMAC0 in to enable MDIO */
3392 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
3393 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
3394 msleep(5);
3395
3396 /* take ext phy out of reset */
3397 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003398 MISC_REGISTERS_GPIO_2,
3399 MISC_REGISTERS_GPIO_HIGH,
3400 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003401
3402 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003403 MISC_REGISTERS_GPIO_1,
3404 MISC_REGISTERS_GPIO_HIGH,
3405 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003406
3407 /* wait for 5ms */
3408 msleep(5);
3409
3410 for (cnt = 0; cnt < 1000; cnt++) {
3411 msleep(1);
3412 bnx2x_cl45_read(bp, port,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003413 ext_phy_type,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003414 ext_phy_addr,
3415 MDIO_PMA_DEVAD,
3416 MDIO_PMA_REG_CTRL,
3417 &ctrl);
3418 if (!(ctrl & (1<<15))) {
3419 DP(NETIF_MSG_LINK, "Reset completed\n\n");
3420 break;
3421 }
3422 }
3423}
3424
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003425static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003426{
3427 /* put sf to reset */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003428 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003429 MISC_REGISTERS_GPIO_1,
3430 MISC_REGISTERS_GPIO_LOW,
3431 port);
3432 bnx2x_set_gpio(bp,
3433 MISC_REGISTERS_GPIO_2,
3434 MISC_REGISTERS_GPIO_LOW,
3435 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003436}
3437
3438u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
3439 u8 *version, u16 len)
3440{
3441 struct bnx2x *bp = params->bp;
3442 u32 ext_phy_type = 0;
3443 u16 val = 0;
3444 u8 ext_phy_addr = 0 ;
3445 u8 status = 0 ;
3446 u32 ver_num;
3447
3448 if (version == NULL || params == NULL)
3449 return -EINVAL;
3450
3451 /* reset the returned value to zero */
3452 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3453 ext_phy_addr = ((params->ext_phy_config &
3454 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3455 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3456
3457 switch (ext_phy_type) {
3458 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3459
3460 if (len < 5)
3461 return -EINVAL;
3462
3463 /* Take ext phy out of reset */
3464 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003465 bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
3466 ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003467
3468 /* wait for 1ms */
3469 msleep(1);
3470
3471 bnx2x_cl45_read(bp, params->port,
3472 ext_phy_type,
3473 ext_phy_addr,
3474 MDIO_PMA_DEVAD,
3475 MDIO_PMA_REG_7101_VER1, &val);
3476 version[2] = (val & 0xFF);
3477 version[3] = ((val & 0xFF00)>>8);
3478
3479 bnx2x_cl45_read(bp, params->port,
3480 ext_phy_type,
3481 ext_phy_addr,
3482 MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2,
3483 &val);
3484 version[0] = (val & 0xFF);
3485 version[1] = ((val & 0xFF00)>>8);
3486 version[4] = '\0';
3487
3488 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07003489 bnx2x_turn_off_sf(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003490 break;
3491 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3492 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3493 {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003494 /* Take ext phy out of reset */
3495 if (!driver_loaded)
3496 bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
3497 ext_phy_type);
3498
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003499 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3500 ext_phy_addr,
3501 MDIO_PMA_DEVAD,
3502 MDIO_PMA_REG_ROM_VER1, &val);
3503 ver_num = val<<16;
3504 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3505 ext_phy_addr,
3506 MDIO_PMA_DEVAD,
3507 MDIO_PMA_REG_ROM_VER2, &val);
3508 ver_num |= val;
3509 status = bnx2x_format_ver(ver_num, version, len);
3510 break;
3511 }
3512 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3513 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
3514
3515 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3516 ext_phy_addr,
3517 MDIO_PMA_DEVAD,
3518 MDIO_PMA_REG_ROM_VER1, &val);
3519 ver_num = val<<16;
3520 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3521 ext_phy_addr,
3522 MDIO_PMA_DEVAD,
3523 MDIO_PMA_REG_ROM_VER2, &val);
3524 ver_num |= val;
3525 status = bnx2x_format_ver(ver_num, version, len);
3526 break;
3527
3528 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3529 break;
3530
3531 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
3532 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
3533 " type is FAILURE!\n");
3534 status = -EINVAL;
3535 break;
3536
3537 default:
3538 break;
3539 }
3540 return status;
3541}
3542
3543static void bnx2x_set_xgxs_loopback(struct link_params *params,
3544 struct link_vars *vars,
3545 u8 is_10g)
3546{
3547 u8 port = params->port;
3548 struct bnx2x *bp = params->bp;
3549
3550 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07003551 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003552
3553 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
3554
3555 /* change the uni_phy_addr in the nig */
3556 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
3557 port*0x18));
3558
3559 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
3560
3561 bnx2x_cl45_write(bp, port, 0,
3562 params->phy_addr,
3563 5,
3564 (MDIO_REG_BANK_AER_BLOCK +
3565 (MDIO_AER_BLOCK_AER_REG & 0xf)),
3566 0x2800);
3567
3568 bnx2x_cl45_write(bp, port, 0,
3569 params->phy_addr,
3570 5,
3571 (MDIO_REG_BANK_CL73_IEEEB0 +
3572 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
3573 0x6041);
3574
3575 /* set aer mmd back */
3576 bnx2x_set_aer_mmd(params, vars);
3577
3578 /* and md_devad */
3579 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
3580 md_devad);
3581
3582 } else {
3583 u16 mii_control;
3584
3585 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
3586
3587 CL45_RD_OVER_CL22(bp, port,
3588 params->phy_addr,
3589 MDIO_REG_BANK_COMBO_IEEE0,
3590 MDIO_COMBO_IEEE0_MII_CONTROL,
3591 &mii_control);
3592
3593 CL45_WR_OVER_CL22(bp, port,
3594 params->phy_addr,
3595 MDIO_REG_BANK_COMBO_IEEE0,
3596 MDIO_COMBO_IEEE0_MII_CONTROL,
3597 (mii_control |
3598 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
3599 }
3600}
3601
3602
3603static void bnx2x_ext_phy_loopback(struct link_params *params)
3604{
3605 struct bnx2x *bp = params->bp;
3606 u8 ext_phy_addr;
3607 u32 ext_phy_type;
3608
3609 if (params->switch_cfg == SWITCH_CFG_10G) {
3610 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3611 /* CL37 Autoneg Enabled */
3612 ext_phy_addr = ((params->ext_phy_config &
3613 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3614 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3615 switch (ext_phy_type) {
3616 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3617 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
3618 DP(NETIF_MSG_LINK,
3619 "ext_phy_loopback: We should not get here\n");
3620 break;
3621 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3622 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
3623 break;
3624 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
3625 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
3626 break;
3627 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3628 /* SFX7101_XGXS_TEST1 */
3629 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3630 ext_phy_addr,
3631 MDIO_XS_DEVAD,
3632 MDIO_XS_SFX7101_XGXS_TEST1,
3633 0x100);
3634 DP(NETIF_MSG_LINK,
3635 "ext_phy_loopback: set ext phy loopback\n");
3636 break;
3637 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3638
3639 break;
3640 } /* switch external PHY type */
3641 } else {
3642 /* serdes */
3643 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3644 ext_phy_addr = (params->ext_phy_config &
3645 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
3646 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
3647 }
3648}
3649
3650
3651/*
3652 *------------------------------------------------------------------------
3653 * bnx2x_override_led_value -
3654 *
3655 * Override the led value of the requsted led
3656 *
3657 *------------------------------------------------------------------------
3658 */
3659u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
3660 u32 led_idx, u32 value)
3661{
3662 u32 reg_val;
3663
3664 /* If port 0 then use EMAC0, else use EMAC1*/
3665 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
3666
3667 DP(NETIF_MSG_LINK,
3668 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
3669 port, led_idx, value);
3670
3671 switch (led_idx) {
3672 case 0: /* 10MB led */
3673 /* Read the current value of the LED register in
3674 the EMAC block */
3675 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
3676 /* Set the OVERRIDE bit to 1 */
3677 reg_val |= EMAC_LED_OVERRIDE;
3678 /* If value is 1, set the 10M_OVERRIDE bit,
3679 otherwise reset it.*/
3680 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
3681 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
3682 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3683 break;
3684 case 1: /*100MB 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 100M_OVERRIDE bit,
3691 otherwise reset it.*/
3692 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
3693 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
3694 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3695 break;
3696 case 2: /* 1000MB led */
3697 /* Read the current value of the LED register in the
3698 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 1000M_OVERRIDE bit, otherwise
3703 reset it. */
3704 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
3705 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
3706 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3707 break;
3708 case 3: /* 2500MB 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 2500M_OVERRIDE bit, otherwise
3715 reset it.*/
3716 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
3717 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
3718 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3719 break;
3720 case 4: /*10G led */
3721 if (port == 0) {
3722 REG_WR(bp, NIG_REG_LED_10G_P0,
3723 value);
3724 } else {
3725 REG_WR(bp, NIG_REG_LED_10G_P1,
3726 value);
3727 }
3728 break;
3729 case 5: /* TRAFFIC led */
3730 /* Find if the traffic control is via BMAC or EMAC */
3731 if (port == 0)
3732 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
3733 else
3734 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
3735
3736 /* Override the traffic led in the EMAC:*/
3737 if (reg_val == 1) {
3738 /* Read the current value of the LED register in
3739 the EMAC block */
3740 reg_val = REG_RD(bp, emac_base +
3741 EMAC_REG_EMAC_LED);
3742 /* Set the TRAFFIC_OVERRIDE bit to 1 */
3743 reg_val |= EMAC_LED_OVERRIDE;
3744 /* If value is 1, set the TRAFFIC bit, otherwise
3745 reset it.*/
3746 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
3747 (reg_val & ~EMAC_LED_TRAFFIC);
3748 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
3749 } else { /* Override the traffic led in the BMAC: */
3750 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
3751 + port*4, 1);
3752 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
3753 value);
3754 }
3755 break;
3756 default:
3757 DP(NETIF_MSG_LINK,
3758 "bnx2x_override_led_value() unknown led index %d "
3759 "(should be 0-5)\n", led_idx);
3760 return -EINVAL;
3761 }
3762
3763 return 0;
3764}
3765
3766
3767u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
3768 u16 hw_led_mode, u32 chip_id)
3769{
3770 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003771 u32 tmp;
3772 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003773 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
3774 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
3775 speed, hw_led_mode);
3776 switch (mode) {
3777 case LED_MODE_OFF:
3778 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
3779 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
3780 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003781
3782 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003783 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003784 break;
3785
3786 case LED_MODE_OPER:
3787 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
3788 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
3789 port*4, 0);
3790 /* Set blinking rate to ~15.9Hz */
3791 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
3792 LED_BLINK_RATE_VAL);
3793 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
3794 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003795 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07003796 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07003797 (tmp & (~EMAC_LED_OVERRIDE)));
3798
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003799 if (!CHIP_IS_E1H(bp) &&
3800 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003801 (speed == SPEED_1000) ||
3802 (speed == SPEED_100) ||
3803 (speed == SPEED_10))) {
3804 /* On Everest 1 Ax chip versions for speeds less than
3805 10G LED scheme is different */
3806 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
3807 + port*4, 1);
3808 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
3809 port*4, 0);
3810 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
3811 port*4, 1);
3812 }
3813 break;
3814
3815 default:
3816 rc = -EINVAL;
3817 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
3818 mode);
3819 break;
3820 }
3821 return rc;
3822
3823}
3824
3825u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
3826{
3827 struct bnx2x *bp = params->bp;
3828 u16 gp_status = 0;
3829
3830 CL45_RD_OVER_CL22(bp, params->port,
3831 params->phy_addr,
3832 MDIO_REG_BANK_GP_STATUS,
3833 MDIO_GP_STATUS_TOP_AN_STATUS1,
3834 &gp_status);
3835 /* link is up only if both local phy and external phy are up */
3836 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
3837 bnx2x_ext_phy_is_link_up(params, vars))
3838 return 0;
3839
3840 return -ESRCH;
3841}
3842
3843static u8 bnx2x_link_initialize(struct link_params *params,
3844 struct link_vars *vars)
3845{
3846 struct bnx2x *bp = params->bp;
3847 u8 port = params->port;
3848 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003849 u8 non_ext_phy;
3850 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003851 /* Activate the external PHY */
3852 bnx2x_ext_phy_reset(params, vars);
3853
3854 bnx2x_set_aer_mmd(params, vars);
3855
3856 if (vars->phy_flags & PHY_XGXS_FLAG)
3857 bnx2x_set_master_ln(params);
3858
3859 rc = bnx2x_reset_unicore(params);
3860 /* reset the SerDes and wait for reset bit return low */
3861 if (rc != 0)
3862 return rc;
3863
3864 bnx2x_set_aer_mmd(params, vars);
3865
3866 /* setting the masterLn_def again after the reset */
3867 if (vars->phy_flags & PHY_XGXS_FLAG) {
3868 bnx2x_set_master_ln(params);
3869 bnx2x_set_swap_lanes(params);
3870 }
3871
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003872 if (vars->phy_flags & PHY_XGXS_FLAG) {
3873 if (params->req_line_speed &&
3874 ((params->req_line_speed == SPEED_100) ||
3875 (params->req_line_speed == SPEED_10))) {
3876 vars->phy_flags |= PHY_SGMII_FLAG;
3877 } else {
3878 vars->phy_flags &= ~PHY_SGMII_FLAG;
3879 }
3880 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003881 /* In case of external phy existance, the line speed would be the
3882 line speed linked up by the external phy. In case it is direct only,
3883 then the line_speed during initialization will be equal to the
3884 req_line_speed*/
3885 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003886
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003887 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003888
3889 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003890 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
3891 (params->loopback_mode == LOOPBACK_XGXS_10) ||
3892 (params->loopback_mode == LOOPBACK_EXT_PHY));
3893
3894 if (non_ext_phy ||
3895 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705)) {
3896 if (params->req_line_speed == SPEED_AUTO_NEG)
3897 bnx2x_set_parallel_detection(params, vars->phy_flags);
3898 bnx2x_init_internal_phy(params, vars);
3899 }
3900
3901 if (!non_ext_phy)
3902 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003903
3904 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003905 (NIG_STATUS_XGXS0_LINK10G |
3906 NIG_STATUS_XGXS0_LINK_STATUS |
3907 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003908
3909 return rc;
3910
3911}
3912
3913
3914u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
3915{
3916 struct bnx2x *bp = params->bp;
3917
3918 u32 val;
Eilon Greenstein3196a882008-08-13 15:58:49 -07003919 DP(NETIF_MSG_LINK, "Phy Initialization started \n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003920 DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
3921 params->req_line_speed, params->req_flow_ctrl);
3922 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003923 vars->phy_link_up = 0;
3924 vars->link_up = 0;
3925 vars->line_speed = 0;
3926 vars->duplex = DUPLEX_FULL;
3927 vars->flow_ctrl = FLOW_CTRL_NONE;
3928 vars->mac_type = MAC_TYPE_NONE;
3929
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003930 if (params->switch_cfg == SWITCH_CFG_1G)
3931 vars->phy_flags = PHY_SERDES_FLAG;
3932 else
3933 vars->phy_flags = PHY_XGXS_FLAG;
3934
Eilon Greenstein3196a882008-08-13 15:58:49 -07003935
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003936 /* disable attentions */
3937 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
3938 (NIG_MASK_XGXS0_LINK_STATUS |
3939 NIG_MASK_XGXS0_LINK10G |
3940 NIG_MASK_SERDES0_LINK_STATUS |
3941 NIG_MASK_MI_INT));
3942
3943 bnx2x_emac_init(params, vars);
3944
3945 if (CHIP_REV_IS_FPGA(bp)) {
3946 vars->link_up = 1;
3947 vars->line_speed = SPEED_10000;
3948 vars->duplex = DUPLEX_FULL;
3949 vars->flow_ctrl = FLOW_CTRL_NONE;
3950 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07003951 /* enable on E1.5 FPGA */
3952 if (CHIP_IS_E1H(bp)) {
3953 vars->flow_ctrl |=
3954 (FLOW_CTRL_TX | FLOW_CTRL_RX);
3955 vars->link_status |=
3956 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
3957 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
3958 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003959
3960 bnx2x_emac_enable(params, vars, 0);
3961 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
3962 /* disable drain */
3963 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3964 + params->port*4, 0);
3965
3966 /* update shared memory */
3967 bnx2x_update_mng(params, vars->link_status);
3968
3969 return 0;
3970
3971 } else
3972 if (CHIP_REV_IS_EMUL(bp)) {
3973
3974 vars->link_up = 1;
3975 vars->line_speed = SPEED_10000;
3976 vars->duplex = DUPLEX_FULL;
3977 vars->flow_ctrl = FLOW_CTRL_NONE;
3978 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
3979
3980 bnx2x_bmac_enable(params, vars, 0);
3981
3982 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
3983 /* Disable drain */
3984 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
3985 + params->port*4, 0);
3986
3987 /* update shared memory */
3988 bnx2x_update_mng(params, vars->link_status);
3989
3990 return 0;
3991
3992 } else
3993 if (params->loopback_mode == LOOPBACK_BMAC) {
3994 vars->link_up = 1;
3995 vars->line_speed = SPEED_10000;
3996 vars->duplex = DUPLEX_FULL;
3997 vars->flow_ctrl = FLOW_CTRL_NONE;
3998 vars->mac_type = MAC_TYPE_BMAC;
3999
4000 vars->phy_flags = PHY_XGXS_FLAG;
4001
4002 bnx2x_phy_deassert(params, vars->phy_flags);
4003 /* set bmac loopback */
4004 bnx2x_bmac_enable(params, vars, 1);
4005
4006 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4007 params->port*4, 0);
4008 } else if (params->loopback_mode == LOOPBACK_EMAC) {
4009 vars->link_up = 1;
4010 vars->line_speed = SPEED_1000;
4011 vars->duplex = DUPLEX_FULL;
4012 vars->flow_ctrl = FLOW_CTRL_NONE;
4013 vars->mac_type = MAC_TYPE_EMAC;
4014
4015 vars->phy_flags = PHY_XGXS_FLAG;
4016
4017 bnx2x_phy_deassert(params, vars->phy_flags);
4018 /* set bmac loopback */
4019 bnx2x_emac_enable(params, vars, 1);
4020 bnx2x_emac_program(params, vars->line_speed,
4021 vars->duplex);
4022 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4023 params->port*4, 0);
4024 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
4025 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
4026 vars->link_up = 1;
4027 vars->line_speed = SPEED_10000;
4028 vars->duplex = DUPLEX_FULL;
4029 vars->flow_ctrl = FLOW_CTRL_NONE;
4030
4031 vars->phy_flags = PHY_XGXS_FLAG;
4032
4033 val = REG_RD(bp,
4034 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4035 params->port*0x18);
4036 params->phy_addr = (u8)val;
4037
4038 bnx2x_phy_deassert(params, vars->phy_flags);
4039 bnx2x_link_initialize(params, vars);
4040
4041 vars->mac_type = MAC_TYPE_BMAC;
4042
4043 bnx2x_bmac_enable(params, vars, 0);
4044
4045 if (params->loopback_mode == LOOPBACK_XGXS_10) {
4046 /* set 10G XGXS loopback */
4047 bnx2x_set_xgxs_loopback(params, vars, 1);
4048 } else {
4049 /* set external phy loopback */
4050 bnx2x_ext_phy_loopback(params);
4051 }
4052 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4053 params->port*4, 0);
4054 } else
4055 /* No loopback */
4056 {
4057
4058 bnx2x_phy_deassert(params, vars->phy_flags);
4059 switch (params->switch_cfg) {
4060 case SWITCH_CFG_1G:
4061 vars->phy_flags |= PHY_SERDES_FLAG;
4062 if ((params->ext_phy_config &
4063 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
4064 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
4065 vars->phy_flags |=
4066 PHY_SGMII_FLAG;
4067 }
4068
4069 val = REG_RD(bp,
4070 NIG_REG_SERDES0_CTRL_PHY_ADDR+
4071 params->port*0x10);
4072
4073 params->phy_addr = (u8)val;
4074
4075 break;
4076 case SWITCH_CFG_10G:
4077 vars->phy_flags |= PHY_XGXS_FLAG;
4078 val = REG_RD(bp,
4079 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4080 params->port*0x18);
4081 params->phy_addr = (u8)val;
4082
4083 break;
4084 default:
4085 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
4086 return -EINVAL;
4087 break;
4088 }
4089
4090 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004091 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004092 bnx2x_link_int_enable(params);
4093 }
4094 return 0;
4095}
4096
4097u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars)
4098{
4099
4100 struct bnx2x *bp = params->bp;
4101 u32 ext_phy_config = params->ext_phy_config;
4102 u16 hw_led_mode = params->hw_led_mode;
4103 u32 chip_id = params->chip_id;
4104 u8 port = params->port;
4105 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4106 /* disable attentions */
4107
4108 vars->link_status = 0;
4109 bnx2x_update_mng(params, vars->link_status);
4110 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4111 (NIG_MASK_XGXS0_LINK_STATUS |
4112 NIG_MASK_XGXS0_LINK10G |
4113 NIG_MASK_SERDES0_LINK_STATUS |
4114 NIG_MASK_MI_INT));
4115
4116 /* activate nig drain */
4117 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4118
4119 /* disable nig egress interface */
4120 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4121 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4122
4123 /* Stop BigMac rx */
4124 bnx2x_bmac_rx_disable(bp, port);
4125
4126 /* disable emac */
4127 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4128
4129 msleep(10);
4130 /* The PHY reset is controled by GPIO 1
4131 * Hold it as vars low
4132 */
4133 /* clear link led */
4134 bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
4135 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
4136 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
4137 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
4138 /* HW reset */
4139
4140 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004141 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4142 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004143
4144 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004145 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4146 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004147
4148 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004149 } else if (ext_phy_type ==
4150 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
4151 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004152 "low power mode\n",
4153 port);
4154 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004155 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4156 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004157 }
4158 }
4159 /* reset the SerDes/XGXS */
4160 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
4161 (0x1ff << (port*16)));
4162
4163 /* reset BigMac */
4164 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
4165 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4166
4167 /* disable nig ingress interface */
4168 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
4169 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
4170 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4171 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4172 vars->link_up = 0;
4173 return 0;
4174}
4175
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004176static u8 bnx2x_update_link_down(struct link_params *params,
4177 struct link_vars *vars)
4178{
4179 struct bnx2x *bp = params->bp;
4180 u8 port = params->port;
4181 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
4182 bnx2x_set_led(bp, port, LED_MODE_OFF,
4183 0, params->hw_led_mode,
4184 params->chip_id);
4185
4186 /* indicate no mac active */
4187 vars->mac_type = MAC_TYPE_NONE;
4188
4189 /* update shared memory */
4190 vars->link_status = 0;
4191 vars->line_speed = 0;
4192 bnx2x_update_mng(params, vars->link_status);
4193
4194 /* activate nig drain */
4195 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4196
4197 /* reset BigMac */
4198 bnx2x_bmac_rx_disable(bp, params->port);
4199 REG_WR(bp, GRCBASE_MISC +
4200 MISC_REGISTERS_RESET_REG_2_CLEAR,
4201 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4202 return 0;
4203}
4204
4205static u8 bnx2x_update_link_up(struct link_params *params,
4206 struct link_vars *vars,
4207 u8 link_10g, u32 gp_status)
4208{
4209 struct bnx2x *bp = params->bp;
4210 u8 port = params->port;
4211 u8 rc = 0;
4212 vars->link_status |= LINK_STATUS_LINK_UP;
4213 if (link_10g) {
4214 bnx2x_bmac_enable(params, vars, 0);
4215 bnx2x_set_led(bp, port, LED_MODE_OPER,
4216 SPEED_10000, params->hw_led_mode,
4217 params->chip_id);
4218
4219 } else {
4220 bnx2x_emac_enable(params, vars, 0);
4221 rc = bnx2x_emac_program(params, vars->line_speed,
4222 vars->duplex);
4223
4224 /* AN complete? */
4225 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
4226 if (!(vars->phy_flags &
4227 PHY_SGMII_FLAG))
4228 bnx2x_set_sgmii_tx_driver(params);
4229 }
4230 }
4231
4232 /* PBF - link up */
4233 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
4234 vars->line_speed);
4235
4236 /* disable drain */
4237 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
4238
4239 /* update shared memory */
4240 bnx2x_update_mng(params, vars->link_status);
4241 return rc;
4242}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004243/* This function should called upon link interrupt */
4244/* In case vars->link_up, driver needs to
4245 1. Update the pbf
4246 2. Disable drain
4247 3. Update the shared memory
4248 4. Indicate link up
4249 5. Set LEDs
4250 Otherwise,
4251 1. Update shared memory
4252 2. Reset BigMac
4253 3. Report link down
4254 4. Unset LEDs
4255*/
4256u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
4257{
4258 struct bnx2x *bp = params->bp;
4259 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004260 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004261 u8 link_10g;
4262 u8 ext_phy_link_up, rc = 0;
4263 u32 ext_phy_type;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004264
4265 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
4266 port,
4267 (vars->phy_flags & PHY_XGXS_FLAG),
4268 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
4269
4270 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
4271 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4272 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4273 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
4274
4275 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4276 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4277 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4278
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004279 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004280
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004281 /* Check external link change only for non-direct */
4282 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
4283
4284 /* Read gp_status */
4285 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
4286 MDIO_REG_BANK_GP_STATUS,
4287 MDIO_GP_STATUS_TOP_AN_STATUS1,
4288 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004289
4290 rc = bnx2x_link_settings_status(params, vars, gp_status);
4291 if (rc != 0)
4292 return rc;
4293
4294 /* anything 10 and over uses the bmac */
4295 link_10g = ((vars->line_speed == SPEED_10000) ||
4296 (vars->line_speed == SPEED_12000) ||
4297 (vars->line_speed == SPEED_12500) ||
4298 (vars->line_speed == SPEED_13000) ||
4299 (vars->line_speed == SPEED_15000) ||
4300 (vars->line_speed == SPEED_16000));
4301
4302 bnx2x_link_int_ack(params, vars, link_10g);
4303
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004304 /* In case external phy link is up, and internal link is down
4305 ( not initialized yet probably after link initialization, it needs
4306 to be initialized.
4307 Note that after link down-up as result of cable plug,
4308 the xgxs link would probably become up again without the need to
4309 initialize it*/
4310
4311 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
4312 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
4313 (ext_phy_link_up && !vars->phy_link_up))
4314 bnx2x_init_internal_phy(params, vars);
4315
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004316 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004317 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004318
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004319 if (vars->link_up)
4320 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
4321 else
4322 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004323
4324 return rc;
4325}
4326
Yaniv Rosner6bbca912008-08-13 15:57:28 -07004327static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
4328{
4329 u8 ext_phy_addr[PORT_MAX];
4330 u16 val;
4331 s8 port;
4332
4333 /* PART1 - Reset both phys */
4334 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4335 /* Extract the ext phy address for the port */
4336 u32 ext_phy_config = REG_RD(bp, shmem_base +
4337 offsetof(struct shmem_region,
4338 dev_info.port_hw_config[port].external_phy_config));
4339
4340 /* disable attentions */
4341 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4342 (NIG_MASK_XGXS0_LINK_STATUS |
4343 NIG_MASK_XGXS0_LINK10G |
4344 NIG_MASK_SERDES0_LINK_STATUS |
4345 NIG_MASK_MI_INT));
4346
4347 ext_phy_addr[port] =
4348 ((ext_phy_config &
4349 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4350 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4351
4352 /* Need to take the phy out of low power mode in order
4353 to write to access its registers */
4354 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4355 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
4356
4357 /* Reset the phy */
4358 bnx2x_cl45_write(bp, port,
4359 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4360 ext_phy_addr[port],
4361 MDIO_PMA_DEVAD,
4362 MDIO_PMA_REG_CTRL,
4363 1<<15);
4364 }
4365
4366 /* Add delay of 150ms after reset */
4367 msleep(150);
4368
4369 /* PART2 - Download firmware to both phys */
4370 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4371 u16 fw_ver1;
4372
4373 bnx2x_bcm8073_external_rom_boot(bp, port,
4374 ext_phy_addr[port]);
4375
4376 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4377 ext_phy_addr[port],
4378 MDIO_PMA_DEVAD,
4379 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
4380 if (fw_ver1 == 0) {
4381 DP(NETIF_MSG_LINK,
4382 "bnx2x_8073_common_init_phy port %x "
4383 "fw Download failed\n", port);
4384 return -EINVAL;
4385 }
4386
4387 /* Only set bit 10 = 1 (Tx power down) */
4388 bnx2x_cl45_read(bp, port,
4389 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4390 ext_phy_addr[port],
4391 MDIO_PMA_DEVAD,
4392 MDIO_PMA_REG_TX_POWER_DOWN, &val);
4393
4394 /* Phase1 of TX_POWER_DOWN reset */
4395 bnx2x_cl45_write(bp, port,
4396 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4397 ext_phy_addr[port],
4398 MDIO_PMA_DEVAD,
4399 MDIO_PMA_REG_TX_POWER_DOWN,
4400 (val | 1<<10));
4401 }
4402
4403 /* Toggle Transmitter: Power down and then up with 600ms
4404 delay between */
4405 msleep(600);
4406
4407 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
4408 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
4409 /* Phase2 of POWER_DOWN_RESET*/
4410 /* Release bit 10 (Release Tx power down) */
4411 bnx2x_cl45_read(bp, port,
4412 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4413 ext_phy_addr[port],
4414 MDIO_PMA_DEVAD,
4415 MDIO_PMA_REG_TX_POWER_DOWN, &val);
4416
4417 bnx2x_cl45_write(bp, port,
4418 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4419 ext_phy_addr[port],
4420 MDIO_PMA_DEVAD,
4421 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
4422 msleep(15);
4423
4424 /* Read modify write the SPI-ROM version select register */
4425 bnx2x_cl45_read(bp, port,
4426 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4427 ext_phy_addr[port],
4428 MDIO_PMA_DEVAD,
4429 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
4430 bnx2x_cl45_write(bp, port,
4431 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
4432 ext_phy_addr[port],
4433 MDIO_PMA_DEVAD,
4434 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
4435
4436 /* set GPIO2 back to LOW */
4437 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4438 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
4439 }
4440 return 0;
4441
4442}
4443
4444u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
4445{
4446 u8 rc = 0;
4447 u32 ext_phy_type;
4448
4449 DP(NETIF_MSG_LINK, "bnx2x_common_init_phy\n");
4450
4451 /* Read the ext_phy_type for arbitrary port(0) */
4452 ext_phy_type = XGXS_EXT_PHY_TYPE(
4453 REG_RD(bp, shmem_base +
4454 offsetof(struct shmem_region,
4455 dev_info.port_hw_config[0].external_phy_config)));
4456
4457 switch (ext_phy_type) {
4458 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4459 {
4460 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
4461 break;
4462 }
4463 default:
4464 DP(NETIF_MSG_LINK,
4465 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
4466 ext_phy_type);
4467 break;
4468 }
4469
4470 return rc;
4471}
4472
4473
4474
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004475static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
4476{
4477 u16 val, cnt;
4478
4479 bnx2x_cl45_read(bp, port,
4480 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4481 phy_addr,
4482 MDIO_PMA_DEVAD,
4483 MDIO_PMA_REG_7101_RESET, &val);
4484
4485 for (cnt = 0; cnt < 10; cnt++) {
4486 msleep(50);
4487 /* Writes a self-clearing reset */
4488 bnx2x_cl45_write(bp, port,
4489 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4490 phy_addr,
4491 MDIO_PMA_DEVAD,
4492 MDIO_PMA_REG_7101_RESET,
4493 (val | (1<<15)));
4494 /* Wait for clear */
4495 bnx2x_cl45_read(bp, port,
4496 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4497 phy_addr,
4498 MDIO_PMA_DEVAD,
4499 MDIO_PMA_REG_7101_RESET, &val);
4500
4501 if ((val & (1<<15)) == 0)
4502 break;
4503 }
4504}
4505#define RESERVED_SIZE 256
4506/* max application is 160K bytes - data at end of RAM */
Eilon Greenstein6378c022008-08-13 15:59:25 -07004507#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004508
4509/* Header is 14 bytes */
4510#define HEADER_SIZE 14
4511#define DATA_OFFSET HEADER_SIZE
4512
4513#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \
4514 bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \
4515 ext_phy_addr, \
4516 MDIO_PCS_DEVAD, \
4517 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1)
4518
4519/* Programs an image to DSP's flash via the SPI port*/
4520static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port,
4521 u8 ext_phy_addr,
4522 char data[], u32 size)
4523{
4524 const u16 num_trans = size/4; /* 4 bytes can be sent at a time */
4525 /* Doesn't include last trans!*/
4526 const u16 last_trans_size = size%4; /* Num bytes on last trans */
4527 u16 trans_cnt, byte_cnt;
4528 u32 data_index;
4529 u16 tmp;
4530 u16 code_started = 0;
4531 u16 image_revision1, image_revision2;
4532 u16 cnt;
4533
4534 DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size);
4535 /* Going to flash*/
4536 if ((size-HEADER_SIZE) > MAX_APP_SIZE) {
4537 /* This very often will be the case, because the image is built
4538 with 160Kbytes size whereas the total image size must actually
4539 be 160Kbytes-RESERVED_SIZE */
4540 DP(NETIF_MSG_LINK, "Warning, file size was %d bytes "
4541 "truncated to %d bytes\n", size, MAX_APP_SIZE);
4542 size = MAX_APP_SIZE+HEADER_SIZE;
4543 }
4544 DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004545 DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004546 /* Put the DSP in download mode by setting FLASH_CFG[2] to 1
4547 and issuing a reset.*/
4548
4549 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004550 MISC_REGISTERS_GPIO_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004551
4552 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
4553
4554 /* wait 0.5 sec */
4555 for (cnt = 0; cnt < 100; cnt++)
4556 msleep(5);
4557
4558 /* Make sure we can access the DSP
4559 And it's in the correct mode (waiting for download) */
4560
4561 bnx2x_cl45_read(bp, port,
4562 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4563 ext_phy_addr,
4564 MDIO_PCS_DEVAD,
4565 MDIO_PCS_REG_7101_DSP_ACCESS, &tmp);
4566
4567 if (tmp != 0x000A) {
4568 DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. "
4569 "Expected 0x000A, read 0x%04X\n", tmp);
4570 DP(NETIF_MSG_LINK, "Download failed\n");
4571 return -EINVAL;
4572 }
4573
4574 /* Mux the SPI interface away from the internal processor */
4575 bnx2x_cl45_write(bp, port,
4576 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4577 ext_phy_addr,
4578 MDIO_PCS_DEVAD,
4579 MDIO_PCS_REG_7101_SPI_MUX, 1);
4580
4581 /* Reset the SPI port */
4582 bnx2x_cl45_write(bp, port,
4583 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4584 ext_phy_addr,
4585 MDIO_PCS_DEVAD,
4586 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
4587 bnx2x_cl45_write(bp, port,
4588 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4589 ext_phy_addr,
4590 MDIO_PCS_DEVAD,
4591 MDIO_PCS_REG_7101_SPI_CTRL_ADDR,
4592 (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT));
4593 bnx2x_cl45_write(bp, port,
4594 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4595 ext_phy_addr,
4596 MDIO_PCS_DEVAD,
4597 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
4598
4599 /* Erase the flash */
4600 bnx2x_cl45_write(bp, port,
4601 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4602 ext_phy_addr,
4603 MDIO_PCS_DEVAD,
4604 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4605 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4606
4607 bnx2x_cl45_write(bp, port,
4608 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4609 ext_phy_addr,
4610 MDIO_PCS_DEVAD,
4611 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4612 1);
4613
4614 SPI_START_TRANSFER(bp, port, ext_phy_addr);
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_FIFO_ADDR,
4620 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD);
4621
4622 bnx2x_cl45_write(bp, port,
4623 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4624 ext_phy_addr,
4625 MDIO_PCS_DEVAD,
4626 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4627 1);
4628 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4629
4630 /* Wait 10 seconds, the maximum time for the erase to complete */
4631 DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n");
4632 for (cnt = 0; cnt < 1000; cnt++)
4633 msleep(10);
4634
4635 DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n");
4636 data_index = 0;
4637 for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) {
4638 bnx2x_cl45_write(bp, port,
4639 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4640 ext_phy_addr,
4641 MDIO_PCS_DEVAD,
4642 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4643 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4644
4645 bnx2x_cl45_write(bp, port,
4646 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4647 ext_phy_addr,
4648 MDIO_PCS_DEVAD,
4649 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4650 1);
4651 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4652
4653 bnx2x_cl45_write(bp, port,
4654 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4655 ext_phy_addr,
4656 MDIO_PCS_DEVAD,
4657 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4658 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
4659
4660 /* Bits 23-16 of address */
4661 bnx2x_cl45_write(bp, port,
4662 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4663 ext_phy_addr,
4664 MDIO_PCS_DEVAD,
4665 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4666 (data_index>>16));
4667 /* Bits 15-8 of address */
4668 bnx2x_cl45_write(bp, port,
4669 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4670 ext_phy_addr,
4671 MDIO_PCS_DEVAD,
4672 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4673 (data_index>>8));
4674
4675 /* Bits 7-0 of address */
4676 bnx2x_cl45_write(bp, port,
4677 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4678 ext_phy_addr,
4679 MDIO_PCS_DEVAD,
4680 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4681 ((u16)data_index));
4682
4683 byte_cnt = 0;
4684 while (byte_cnt < 4 && data_index < size) {
4685 bnx2x_cl45_write(bp, port,
4686 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4687 ext_phy_addr,
4688 MDIO_PCS_DEVAD,
4689 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4690 data[data_index++]);
4691 byte_cnt++;
4692 }
4693
4694 bnx2x_cl45_write(bp, port,
4695 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4696 ext_phy_addr,
4697 MDIO_PCS_DEVAD,
4698 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4699 byte_cnt+4);
4700
4701 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4702 msleep(5); /* Wait 5 ms minimum between transs */
4703
4704 /* Let the user know something's going on.*/
4705 /* a pacifier ever 4K */
4706 if ((data_index % 1023) == 0)
4707 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
4708 }
4709
4710 DP(NETIF_MSG_LINK, "\n");
4711 /* Transfer the last block if there is data remaining */
4712 if (last_trans_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 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
4719
4720 bnx2x_cl45_write(bp, port,
4721 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4722 ext_phy_addr,
4723 MDIO_PCS_DEVAD,
4724 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4725 1);
4726
4727 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4728
4729 bnx2x_cl45_write(bp, port,
4730 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4731 ext_phy_addr,
4732 MDIO_PCS_DEVAD,
4733 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4734 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
4735
4736 /* Bits 23-16 of address */
4737 bnx2x_cl45_write(bp, port,
4738 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4739 ext_phy_addr,
4740 MDIO_PCS_DEVAD,
4741 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4742 (data_index>>16));
4743 /* Bits 15-8 of address */
4744 bnx2x_cl45_write(bp, port,
4745 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4746 ext_phy_addr,
4747 MDIO_PCS_DEVAD,
4748 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4749 (data_index>>8));
4750
4751 /* Bits 7-0 of address */
4752 bnx2x_cl45_write(bp, port,
4753 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4754 ext_phy_addr,
4755 MDIO_PCS_DEVAD,
4756 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4757 ((u16)data_index));
4758
4759 byte_cnt = 0;
4760 while (byte_cnt < last_trans_size && data_index < size) {
4761 /* Bits 7-0 of address */
4762 bnx2x_cl45_write(bp, port,
4763 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4764 ext_phy_addr,
4765 MDIO_PCS_DEVAD,
4766 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
4767 data[data_index++]);
4768 byte_cnt++;
4769 }
4770
4771 bnx2x_cl45_write(bp, port,
4772 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4773 ext_phy_addr,
4774 MDIO_PCS_DEVAD,
4775 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
4776 byte_cnt+4);
4777
4778 SPI_START_TRANSFER(bp, port, ext_phy_addr);
4779 }
4780
4781 /* DSP Remove Download Mode */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004782 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
4783 MISC_REGISTERS_GPIO_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004784
4785 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
4786
4787 /* wait 0.5 sec to allow it to run */
4788 for (cnt = 0; cnt < 100; cnt++)
4789 msleep(5);
4790
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004791 bnx2x_hw_reset(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004792
4793 for (cnt = 0; cnt < 100; cnt++)
4794 msleep(5);
4795
4796 /* Check that the code is started. In case the download
4797 checksum failed, the code won't be started. */
4798 bnx2x_cl45_read(bp, port,
4799 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4800 ext_phy_addr,
4801 MDIO_PCS_DEVAD,
4802 MDIO_PCS_REG_7101_DSP_ACCESS,
4803 &tmp);
4804
4805 code_started = (tmp & (1<<4));
4806 if (!code_started) {
4807 DP(NETIF_MSG_LINK, "Download failed. Please check file.\n");
4808 return -EINVAL;
4809 }
4810
4811 /* Verify that the file revision is now equal to the image
4812 revision within the DSP */
4813 bnx2x_cl45_read(bp, port,
4814 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4815 ext_phy_addr,
4816 MDIO_PMA_DEVAD,
4817 MDIO_PMA_REG_7101_VER1,
4818 &image_revision1);
4819
4820 bnx2x_cl45_read(bp, port,
4821 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
4822 ext_phy_addr,
4823 MDIO_PMA_DEVAD,
4824 MDIO_PMA_REG_7101_VER2,
4825 &image_revision2);
4826
Eilon Greenstein3196a882008-08-13 15:58:49 -07004827 if (data[0x14e] != (image_revision2&0xFF) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004828 data[0x14f] != ((image_revision2&0xFF00)>>8) ||
4829 data[0x150] != (image_revision1&0xFF) ||
4830 data[0x151] != ((image_revision1&0xFF00)>>8)) {
4831 DP(NETIF_MSG_LINK, "Download failed.\n");
4832 return -EINVAL;
4833 }
4834 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
4835 return 0;
4836}
4837
4838u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
4839 u8 driver_loaded, char data[], u32 size)
4840{
4841 u8 rc = 0;
4842 u32 ext_phy_type;
4843 u8 ext_phy_addr;
4844 ext_phy_addr = ((ext_phy_config &
4845 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4846 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4847
4848 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4849
4850 switch (ext_phy_type) {
4851 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4852 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4853 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4854 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
4855 DP(NETIF_MSG_LINK,
4856 "Flash download not supported for this ext phy\n");
4857 rc = -EINVAL;
4858 break;
4859 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4860 /* Take ext phy out of reset */
4861 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004862 bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004863 rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
4864 data, size);
4865 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004866 bnx2x_turn_off_sf(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004867 break;
4868 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4869 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4870 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
4871 default:
4872 DP(NETIF_MSG_LINK, "Invalid ext phy type\n");
4873 rc = -EINVAL;
4874 break;
4875 }
4876 return rc;
4877}
4878