blob: f4c699ecfb4190729648f1eb089feceff339417d [file] [log] [blame]
Eilon Greensteind05c26c2009-01-17 23:26:13 -08001/* Copyright 2008-2009 Broadcom Corporation
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002 *
3 * Unless you and Broadcom execute a separate written software license
4 * agreement governing use of this software, this software is licensed to you
5 * under the terms of the GNU General Public License version 2, available
6 * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
7 *
8 * Notwithstanding the above, under no circumstances may you combine this
9 * software in any way with any other Broadcom software provided under a
10 * license other than the GPL, without Broadcom's express prior written
11 * consent.
12 *
13 * Written by Yaniv Rosner
14 *
15 */
16
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/pci.h>
20#include <linux/netdevice.h>
21#include <linux/delay.h>
22#include <linux/ethtool.h>
23#include <linux/mutex.h>
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070024
25#include "bnx2x_reg.h"
26#include "bnx2x_fw_defs.h"
27#include "bnx2x_hsi.h"
28#include "bnx2x_link.h"
29#include "bnx2x.h"
30
31/********************************************************/
32#define SUPPORT_CL73 0 /* Currently no */
Eilon Greenstein3196a882008-08-13 15:58:49 -070033#define ETH_HLEN 14
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070034#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
35#define ETH_MIN_PACKET_SIZE 60
36#define ETH_MAX_PACKET_SIZE 1500
37#define ETH_MAX_JUMBO_PACKET_SIZE 9600
38#define MDIO_ACCESS_TIMEOUT 1000
39#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070040
41/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070042/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070043/***********************************************************/
44
45#define NIG_STATUS_XGXS0_LINK10G \
46 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
47#define NIG_STATUS_XGXS0_LINK_STATUS \
48 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
49#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
50 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
51#define NIG_STATUS_SERDES0_LINK_STATUS \
52 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
53#define NIG_MASK_MI_INT \
54 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
55#define NIG_MASK_XGXS0_LINK10G \
56 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
57#define NIG_MASK_XGXS0_LINK_STATUS \
58 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
59#define NIG_MASK_SERDES0_LINK_STATUS \
60 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
61
62#define MDIO_AN_CL73_OR_37_COMPLETE \
63 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
64 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
65
66#define XGXS_RESET_BITS \
67 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
68 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
71 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
72
73#define SERDES_RESET_BITS \
74 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
75 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
77 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
78
79#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
80#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Eilon Greenstein3196a882008-08-13 15:58:49 -070081#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
82#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070083 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070084#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070085 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070086#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070087
88#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
89 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
90#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
91 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
92#define GP_STATUS_SPEED_MASK \
93 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
94#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
95#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
96#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
97#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
98#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
99#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
100#define GP_STATUS_10G_HIG \
101 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
102#define GP_STATUS_10G_CX4 \
103 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
104#define GP_STATUS_12G_HIG \
105 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
106#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
107#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
108#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
109#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
110#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
111#define GP_STATUS_10G_KX4 \
112 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
113
114#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
115#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
116#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
117#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
118#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
119#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
120#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
121#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
122#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
123#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
124#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
125#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
126#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
127#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
128#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
129#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
130#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
131#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
132#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
133#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
134#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
135#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
136#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
137
138#define PHY_XGXS_FLAG 0x1
139#define PHY_SGMII_FLAG 0x2
140#define PHY_SERDES_FLAG 0x4
141
Eilon Greenstein589abe32009-02-12 08:36:55 +0000142/* */
143#define SFP_EEPROM_CON_TYPE_ADDR 0x2
144 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
145 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
146
147#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
148 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
149 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
150#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
151#define SFP_EEPROM_VENDOR_NAME_SIZE 16
152#define SFP_EEPROM_OPTIONS_ADDR 0x40
153 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
154#define SFP_EEPROM_OPTIONS_SIZE 2
155
156#define SFP_MODULE_TYPE_UNKNOWN 0x0
157#define SFP_MODULE_TYPE_LC 0x1
158#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE 0x2
159#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE 0x3
160
161#define SFP_LIMITING_MODE_VALUE 0x0044
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700162/**********************************************************/
163/* INTERFACE */
164/**********************************************************/
165#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
166 bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
167 DEFAULT_PHY_DEV_ADDR, \
168 (_bank + (_addr & 0xf)), \
169 _val)
170
171#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
172 bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
173 DEFAULT_PHY_DEV_ADDR, \
174 (_bank + (_addr & 0xf)), \
175 _val)
176
177static void bnx2x_set_phy_mdio(struct link_params *params)
178{
179 struct bnx2x *bp = params->bp;
180 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
181 params->port*0x18, 0);
182 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
183 DEFAULT_PHY_DEV_ADDR);
184}
185
186static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
187{
188 u32 val = REG_RD(bp, reg);
189
190 val |= bits;
191 REG_WR(bp, reg, val);
192 return val;
193}
194
195static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
196{
197 u32 val = REG_RD(bp, reg);
198
199 val &= ~bits;
200 REG_WR(bp, reg, val);
201 return val;
202}
203
204static void bnx2x_emac_init(struct link_params *params,
205 struct link_vars *vars)
206{
207 /* reset and unreset the emac core */
208 struct bnx2x *bp = params->bp;
209 u8 port = params->port;
210 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
211 u32 val;
212 u16 timeout;
213
214 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
215 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
216 udelay(5);
217 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
218 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
219
220 /* init emac - use read-modify-write */
221 /* self clear reset */
222 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700223 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700224
225 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700226 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700227 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
228 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
229 if (!timeout) {
230 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
231 return;
232 }
233 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700234 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700235
236 /* Set mac address */
237 val = ((params->mac_addr[0] << 8) |
238 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700239 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700240
241 val = ((params->mac_addr[2] << 24) |
242 (params->mac_addr[3] << 16) |
243 (params->mac_addr[4] << 8) |
244 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700245 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700246}
247
248static u8 bnx2x_emac_enable(struct link_params *params,
249 struct link_vars *vars, u8 lb)
250{
251 struct bnx2x *bp = params->bp;
252 u8 port = params->port;
253 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
254 u32 val;
255
256 DP(NETIF_MSG_LINK, "enabling EMAC\n");
257
258 /* enable emac and not bmac */
259 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
260
261 /* for paladium */
262 if (CHIP_REV_IS_EMUL(bp)) {
263 /* Use lane 1 (of lanes 0-3) */
264 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
265 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
266 port*4, 1);
267 }
268 /* for fpga */
269 else
270
271 if (CHIP_REV_IS_FPGA(bp)) {
272 /* Use lane 1 (of lanes 0-3) */
273 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
274
275 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
276 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
277 0);
278 } else
279 /* ASIC */
280 if (vars->phy_flags & PHY_XGXS_FLAG) {
281 u32 ser_lane = ((params->lane_config &
282 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
283 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
284
285 DP(NETIF_MSG_LINK, "XGXS\n");
286 /* select the master lanes (out of 0-3) */
287 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
288 port*4, ser_lane);
289 /* select XGXS */
290 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
291 port*4, 1);
292
293 } else { /* SerDes */
294 DP(NETIF_MSG_LINK, "SerDes\n");
295 /* select SerDes */
296 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
297 port*4, 0);
298 }
299
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000300 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
301 EMAC_RX_MODE_RESET);
302 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
303 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700304
305 if (CHIP_REV_IS_SLOW(bp)) {
306 /* config GMII mode */
307 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700308 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700309 (val | EMAC_MODE_PORT_GMII));
310 } else { /* ASIC */
311 /* pause enable/disable */
312 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
313 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800314 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700315 bnx2x_bits_en(bp, emac_base +
316 EMAC_REG_EMAC_RX_MODE,
317 EMAC_RX_MODE_FLOW_EN);
318
319 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700320 (EMAC_TX_MODE_EXT_PAUSE_EN |
321 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800322 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700323 bnx2x_bits_en(bp, emac_base +
324 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700325 (EMAC_TX_MODE_EXT_PAUSE_EN |
326 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700327 }
328
329 /* KEEP_VLAN_TAG, promiscuous */
330 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
331 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700332 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700333
334 /* Set Loopback */
335 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
336 if (lb)
337 val |= 0x810;
338 else
339 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700340 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700341
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000342 /* enable emac */
343 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
344
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700345 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700346 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700347 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
348 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
349
350 /* strip CRC */
351 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
352
353 /* disable the NIG in/out to the bmac */
354 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
355 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
356 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
357
358 /* enable the NIG in/out to the emac */
359 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
360 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800361 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700362 val = 1;
363
364 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
365 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
366
367 if (CHIP_REV_IS_EMUL(bp)) {
368 /* take the BigMac out of reset */
369 REG_WR(bp,
370 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
371 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
372
373 /* enable access for bmac registers */
374 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
375 }
376
377 vars->mac_type = MAC_TYPE_EMAC;
378 return 0;
379}
380
381
382
383static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
384 u8 is_lb)
385{
386 struct bnx2x *bp = params->bp;
387 u8 port = params->port;
388 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
389 NIG_REG_INGRESS_BMAC0_MEM;
390 u32 wb_data[2];
391 u32 val;
392
393 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
394 /* reset and unreset the BigMac */
395 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
396 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
397 msleep(1);
398
399 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
400 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
401
402 /* enable access for bmac registers */
403 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
404
405 /* XGXS control */
406 wb_data[0] = 0x3c;
407 wb_data[1] = 0;
408 REG_WR_DMAE(bp, bmac_addr +
409 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
410 wb_data, 2);
411
412 /* tx MAC SA */
413 wb_data[0] = ((params->mac_addr[2] << 24) |
414 (params->mac_addr[3] << 16) |
415 (params->mac_addr[4] << 8) |
416 params->mac_addr[5]);
417 wb_data[1] = ((params->mac_addr[0] << 8) |
418 params->mac_addr[1]);
419 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
420 wb_data, 2);
421
422 /* tx control */
423 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800424 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700425 val |= 0x800000;
426 wb_data[0] = val;
427 wb_data[1] = 0;
428 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
429 wb_data, 2);
430
431 /* mac control */
432 val = 0x3;
433 if (is_lb) {
434 val |= 0x4;
435 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
436 }
437 wb_data[0] = val;
438 wb_data[1] = 0;
439 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
440 wb_data, 2);
441
442
443 /* set rx mtu */
444 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
445 wb_data[1] = 0;
446 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
447 wb_data, 2);
448
449 /* rx control set to don't strip crc */
450 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800451 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700452 val |= 0x20;
453 wb_data[0] = val;
454 wb_data[1] = 0;
455 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
456 wb_data, 2);
457
458 /* set tx mtu */
459 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
460 wb_data[1] = 0;
461 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
462 wb_data, 2);
463
464 /* set cnt max size */
465 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
466 wb_data[1] = 0;
467 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
468 wb_data, 2);
469
470 /* configure safc */
471 wb_data[0] = 0x1000200;
472 wb_data[1] = 0;
473 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
474 wb_data, 2);
475 /* fix for emulation */
476 if (CHIP_REV_IS_EMUL(bp)) {
477 wb_data[0] = 0xf000;
478 wb_data[1] = 0;
479 REG_WR_DMAE(bp,
480 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
481 wb_data, 2);
482 }
483
484 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
485 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
486 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
487 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800488 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700489 val = 1;
490 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
491 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
492 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
493 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
494 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
495 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
496
497 vars->mac_type = MAC_TYPE_BMAC;
498 return 0;
499}
500
501static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
502{
503 struct bnx2x *bp = params->bp;
504 u32 val;
505
506 if (phy_flags & PHY_XGXS_FLAG) {
507 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
508 val = XGXS_RESET_BITS;
509
510 } else { /* SerDes */
511 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
512 val = SERDES_RESET_BITS;
513 }
514
515 val = val << (params->port*16);
516
517 /* reset and unreset the SerDes/XGXS */
518 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
519 val);
520 udelay(500);
521 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
522 val);
523 bnx2x_set_phy_mdio(params);
524}
525
526void bnx2x_link_status_update(struct link_params *params,
527 struct link_vars *vars)
528{
529 struct bnx2x *bp = params->bp;
530 u8 link_10g;
531 u8 port = params->port;
532
533 if (params->switch_cfg == SWITCH_CFG_1G)
534 vars->phy_flags = PHY_SERDES_FLAG;
535 else
536 vars->phy_flags = PHY_XGXS_FLAG;
537 vars->link_status = REG_RD(bp, params->shmem_base +
538 offsetof(struct shmem_region,
539 port_mb[port].link_status));
540
541 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
542
543 if (vars->link_up) {
544 DP(NETIF_MSG_LINK, "phy link up\n");
545
546 vars->phy_link_up = 1;
547 vars->duplex = DUPLEX_FULL;
548 switch (vars->link_status &
549 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
550 case LINK_10THD:
551 vars->duplex = DUPLEX_HALF;
552 /* fall thru */
553 case LINK_10TFD:
554 vars->line_speed = SPEED_10;
555 break;
556
557 case LINK_100TXHD:
558 vars->duplex = DUPLEX_HALF;
559 /* fall thru */
560 case LINK_100T4:
561 case LINK_100TXFD:
562 vars->line_speed = SPEED_100;
563 break;
564
565 case LINK_1000THD:
566 vars->duplex = DUPLEX_HALF;
567 /* fall thru */
568 case LINK_1000TFD:
569 vars->line_speed = SPEED_1000;
570 break;
571
572 case LINK_2500THD:
573 vars->duplex = DUPLEX_HALF;
574 /* fall thru */
575 case LINK_2500TFD:
576 vars->line_speed = SPEED_2500;
577 break;
578
579 case LINK_10GTFD:
580 vars->line_speed = SPEED_10000;
581 break;
582
583 case LINK_12GTFD:
584 vars->line_speed = SPEED_12000;
585 break;
586
587 case LINK_12_5GTFD:
588 vars->line_speed = SPEED_12500;
589 break;
590
591 case LINK_13GTFD:
592 vars->line_speed = SPEED_13000;
593 break;
594
595 case LINK_15GTFD:
596 vars->line_speed = SPEED_15000;
597 break;
598
599 case LINK_16GTFD:
600 vars->line_speed = SPEED_16000;
601 break;
602
603 default:
604 break;
605 }
606
607 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800608 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700609 else
David S. Millerc0700f92008-12-16 23:53:20 -0800610 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700611
612 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800613 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700614 else
David S. Millerc0700f92008-12-16 23:53:20 -0800615 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700616
617 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700618 if (vars->line_speed &&
619 ((vars->line_speed == SPEED_10) ||
620 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700621 vars->phy_flags |= PHY_SGMII_FLAG;
622 } else {
623 vars->phy_flags &= ~PHY_SGMII_FLAG;
624 }
625 }
626
627 /* anything 10 and over uses the bmac */
628 link_10g = ((vars->line_speed == SPEED_10000) ||
629 (vars->line_speed == SPEED_12000) ||
630 (vars->line_speed == SPEED_12500) ||
631 (vars->line_speed == SPEED_13000) ||
632 (vars->line_speed == SPEED_15000) ||
633 (vars->line_speed == SPEED_16000));
634 if (link_10g)
635 vars->mac_type = MAC_TYPE_BMAC;
636 else
637 vars->mac_type = MAC_TYPE_EMAC;
638
639 } else { /* link down */
640 DP(NETIF_MSG_LINK, "phy link down\n");
641
642 vars->phy_link_up = 0;
643
644 vars->line_speed = 0;
645 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -0800646 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700647
648 /* indicate no mac active */
649 vars->mac_type = MAC_TYPE_NONE;
650 }
651
652 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
653 vars->link_status, vars->phy_link_up);
654 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
655 vars->line_speed, vars->duplex, vars->flow_ctrl);
656}
657
658static void bnx2x_update_mng(struct link_params *params, u32 link_status)
659{
660 struct bnx2x *bp = params->bp;
661 REG_WR(bp, params->shmem_base +
662 offsetof(struct shmem_region,
663 port_mb[params->port].link_status),
664 link_status);
665}
666
667static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
668{
669 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
670 NIG_REG_INGRESS_BMAC0_MEM;
671 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700672 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700673
674 /* Only if the bmac is out of reset */
675 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
676 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
677 nig_bmac_enable) {
678
679 /* Clear Rx Enable bit in BMAC_CONTROL register */
680 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
681 wb_data, 2);
682 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
683 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
684 wb_data, 2);
685
686 msleep(1);
687 }
688}
689
690static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
691 u32 line_speed)
692{
693 struct bnx2x *bp = params->bp;
694 u8 port = params->port;
695 u32 init_crd, crd;
696 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700697
698 /* disable port */
699 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
700
701 /* wait for init credit */
702 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
703 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
704 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
705
706 while ((init_crd != crd) && count) {
707 msleep(5);
708
709 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
710 count--;
711 }
712 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
713 if (init_crd != crd) {
714 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
715 init_crd, crd);
716 return -EINVAL;
717 }
718
David S. Millerc0700f92008-12-16 23:53:20 -0800719 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700720 line_speed == SPEED_10 ||
721 line_speed == SPEED_100 ||
722 line_speed == SPEED_1000 ||
723 line_speed == SPEED_2500) {
724 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700725 /* update threshold */
726 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
727 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700728 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700729
730 } else {
731 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
732 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700733 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700734 /* update threshold */
735 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
736 /* update init credit */
737 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700738 case SPEED_10000:
739 init_crd = thresh + 553 - 22;
740 break;
741
742 case SPEED_12000:
743 init_crd = thresh + 664 - 22;
744 break;
745
746 case SPEED_13000:
747 init_crd = thresh + 742 - 22;
748 break;
749
750 case SPEED_16000:
751 init_crd = thresh + 778 - 22;
752 break;
753 default:
754 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
755 line_speed);
756 return -EINVAL;
757 break;
758 }
759 }
760 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
761 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
762 line_speed, init_crd);
763
764 /* probe the credit changes */
765 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
766 msleep(5);
767 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
768
769 /* enable port */
770 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
771 return 0;
772}
773
Eilon Greenstein589abe32009-02-12 08:36:55 +0000774static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700775{
776 u32 emac_base;
777 switch (ext_phy_type) {
778 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000779 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
780 /* All MDC/MDIO is directed through single EMAC */
781 if (REG_RD(bp, NIG_REG_PORT_SWAP))
782 emac_base = GRCBASE_EMAC0;
783 else
784 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700785 break;
786 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700787 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700788 break;
789 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700790 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700791 break;
792 }
793 return emac_base;
794
795}
796
797u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
798 u8 phy_addr, u8 devad, u16 reg, u16 val)
799{
800 u32 tmp, saved_mode;
801 u8 i, rc = 0;
Eilon Greenstein589abe32009-02-12 08:36:55 +0000802 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700803
804 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
805 * (a value of 49==0x31) and make sure that the AUTO poll is off
806 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000807
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700808 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
809 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
810 EMAC_MDIO_MODE_CLOCK_CNT);
811 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
812 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
813 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
814 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
815 udelay(40);
816
817 /* address */
818
819 tmp = ((phy_addr << 21) | (devad << 16) | reg |
820 EMAC_MDIO_COMM_COMMAND_ADDRESS |
821 EMAC_MDIO_COMM_START_BUSY);
822 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
823
824 for (i = 0; i < 50; i++) {
825 udelay(10);
826
827 tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
828 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
829 udelay(5);
830 break;
831 }
832 }
833 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
834 DP(NETIF_MSG_LINK, "write phy register failed\n");
835 rc = -EFAULT;
836 } else {
837 /* data */
838 tmp = ((phy_addr << 21) | (devad << 16) | val |
839 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
840 EMAC_MDIO_COMM_START_BUSY);
841 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
842
843 for (i = 0; i < 50; i++) {
844 udelay(10);
845
846 tmp = REG_RD(bp, mdio_ctrl +
847 EMAC_REG_EMAC_MDIO_COMM);
848 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
849 udelay(5);
850 break;
851 }
852 }
853 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
854 DP(NETIF_MSG_LINK, "write phy register failed\n");
855 rc = -EFAULT;
856 }
857 }
858
859 /* Restore the saved mode */
860 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
861
862 return rc;
863}
864
865u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
866 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
867{
868 u32 val, saved_mode;
869 u16 i;
870 u8 rc = 0;
871
Eilon Greenstein589abe32009-02-12 08:36:55 +0000872 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700873 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
874 * (a value of 49==0x31) and make sure that the AUTO poll is off
875 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000876
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700877 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
878 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
879 EMAC_MDIO_MODE_CLOCK_CNT));
880 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
881 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
882 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
883 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
884 udelay(40);
885
886 /* address */
887 val = ((phy_addr << 21) | (devad << 16) | reg |
888 EMAC_MDIO_COMM_COMMAND_ADDRESS |
889 EMAC_MDIO_COMM_START_BUSY);
890 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
891
892 for (i = 0; i < 50; i++) {
893 udelay(10);
894
895 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
896 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
897 udelay(5);
898 break;
899 }
900 }
901 if (val & EMAC_MDIO_COMM_START_BUSY) {
902 DP(NETIF_MSG_LINK, "read phy register failed\n");
903
904 *ret_val = 0;
905 rc = -EFAULT;
906
907 } else {
908 /* data */
909 val = ((phy_addr << 21) | (devad << 16) |
910 EMAC_MDIO_COMM_COMMAND_READ_45 |
911 EMAC_MDIO_COMM_START_BUSY);
912 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
913
914 for (i = 0; i < 50; i++) {
915 udelay(10);
916
917 val = REG_RD(bp, mdio_ctrl +
918 EMAC_REG_EMAC_MDIO_COMM);
919 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
920 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
921 break;
922 }
923 }
924 if (val & EMAC_MDIO_COMM_START_BUSY) {
925 DP(NETIF_MSG_LINK, "read phy register failed\n");
926
927 *ret_val = 0;
928 rc = -EFAULT;
929 }
930 }
931
932 /* Restore the saved mode */
933 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
934
935 return rc;
936}
937
938static void bnx2x_set_aer_mmd(struct link_params *params,
939 struct link_vars *vars)
940{
941 struct bnx2x *bp = params->bp;
942 u32 ser_lane;
943 u16 offset;
944
945 ser_lane = ((params->lane_config &
946 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
947 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
948
949 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
950 (params->phy_addr + ser_lane) : 0;
951
952 CL45_WR_OVER_CL22(bp, params->port,
953 params->phy_addr,
954 MDIO_REG_BANK_AER_BLOCK,
955 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
956}
957
958static void bnx2x_set_master_ln(struct link_params *params)
959{
960 struct bnx2x *bp = params->bp;
961 u16 new_master_ln, ser_lane;
962 ser_lane = ((params->lane_config &
963 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
964 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
965
966 /* set the master_ln for AN */
967 CL45_RD_OVER_CL22(bp, params->port,
968 params->phy_addr,
969 MDIO_REG_BANK_XGXS_BLOCK2,
970 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
971 &new_master_ln);
972
973 CL45_WR_OVER_CL22(bp, params->port,
974 params->phy_addr,
975 MDIO_REG_BANK_XGXS_BLOCK2 ,
976 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
977 (new_master_ln | ser_lane));
978}
979
980static u8 bnx2x_reset_unicore(struct link_params *params)
981{
982 struct bnx2x *bp = params->bp;
983 u16 mii_control;
984 u16 i;
985
986 CL45_RD_OVER_CL22(bp, params->port,
987 params->phy_addr,
988 MDIO_REG_BANK_COMBO_IEEE0,
989 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
990
991 /* reset the unicore */
992 CL45_WR_OVER_CL22(bp, params->port,
993 params->phy_addr,
994 MDIO_REG_BANK_COMBO_IEEE0,
995 MDIO_COMBO_IEEE0_MII_CONTROL,
996 (mii_control |
997 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
998
999 /* wait for the reset to self clear */
1000 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1001 udelay(5);
1002
1003 /* the reset erased the previous bank value */
1004 CL45_RD_OVER_CL22(bp, params->port,
1005 params->phy_addr,
1006 MDIO_REG_BANK_COMBO_IEEE0,
1007 MDIO_COMBO_IEEE0_MII_CONTROL,
1008 &mii_control);
1009
1010 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1011 udelay(5);
1012 return 0;
1013 }
1014 }
1015
1016 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1017 return -EINVAL;
1018
1019}
1020
1021static void bnx2x_set_swap_lanes(struct link_params *params)
1022{
1023 struct bnx2x *bp = params->bp;
1024 /* Each two bits represents a lane number:
1025 No swap is 0123 => 0x1b no need to enable the swap */
1026 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1027
1028 ser_lane = ((params->lane_config &
1029 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1030 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1031 rx_lane_swap = ((params->lane_config &
1032 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1033 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1034 tx_lane_swap = ((params->lane_config &
1035 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1036 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1037
1038 if (rx_lane_swap != 0x1b) {
1039 CL45_WR_OVER_CL22(bp, params->port,
1040 params->phy_addr,
1041 MDIO_REG_BANK_XGXS_BLOCK2,
1042 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1043 (rx_lane_swap |
1044 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1045 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1046 } else {
1047 CL45_WR_OVER_CL22(bp, params->port,
1048 params->phy_addr,
1049 MDIO_REG_BANK_XGXS_BLOCK2,
1050 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1051 }
1052
1053 if (tx_lane_swap != 0x1b) {
1054 CL45_WR_OVER_CL22(bp, params->port,
1055 params->phy_addr,
1056 MDIO_REG_BANK_XGXS_BLOCK2,
1057 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1058 (tx_lane_swap |
1059 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1060 } else {
1061 CL45_WR_OVER_CL22(bp, params->port,
1062 params->phy_addr,
1063 MDIO_REG_BANK_XGXS_BLOCK2,
1064 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1065 }
1066}
1067
1068static void bnx2x_set_parallel_detection(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07001069 u8 phy_flags)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001070{
1071 struct bnx2x *bp = params->bp;
1072 u16 control2;
1073
1074 CL45_RD_OVER_CL22(bp, params->port,
1075 params->phy_addr,
1076 MDIO_REG_BANK_SERDES_DIGITAL,
1077 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1078 &control2);
1079
1080
1081 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1082
1083
1084 CL45_WR_OVER_CL22(bp, params->port,
1085 params->phy_addr,
1086 MDIO_REG_BANK_SERDES_DIGITAL,
1087 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1088 control2);
1089
1090 if (phy_flags & PHY_XGXS_FLAG) {
1091 DP(NETIF_MSG_LINK, "XGXS\n");
1092
1093 CL45_WR_OVER_CL22(bp, params->port,
1094 params->phy_addr,
1095 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1096 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1097 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1098
1099 CL45_RD_OVER_CL22(bp, params->port,
1100 params->phy_addr,
1101 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1102 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1103 &control2);
1104
1105
1106 control2 |=
1107 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1108
1109 CL45_WR_OVER_CL22(bp, params->port,
1110 params->phy_addr,
1111 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1112 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1113 control2);
1114
1115 /* Disable parallel detection of HiG */
1116 CL45_WR_OVER_CL22(bp, params->port,
1117 params->phy_addr,
1118 MDIO_REG_BANK_XGXS_BLOCK2,
1119 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1120 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1121 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1122 }
1123}
1124
1125static void bnx2x_set_autoneg(struct link_params *params,
1126 struct link_vars *vars)
1127{
1128 struct bnx2x *bp = params->bp;
1129 u16 reg_val;
1130
1131 /* CL37 Autoneg */
1132
1133 CL45_RD_OVER_CL22(bp, params->port,
1134 params->phy_addr,
1135 MDIO_REG_BANK_COMBO_IEEE0,
1136 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1137
1138 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001139 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001140 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1141 else /* CL37 Autoneg Disabled */
1142 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1143 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1144
1145 CL45_WR_OVER_CL22(bp, params->port,
1146 params->phy_addr,
1147 MDIO_REG_BANK_COMBO_IEEE0,
1148 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1149
1150 /* Enable/Disable Autodetection */
1151
1152 CL45_RD_OVER_CL22(bp, params->port,
1153 params->phy_addr,
1154 MDIO_REG_BANK_SERDES_DIGITAL,
1155 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
1156 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001157 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001158 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1159 else
1160 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1161
1162 CL45_WR_OVER_CL22(bp, params->port,
1163 params->phy_addr,
1164 MDIO_REG_BANK_SERDES_DIGITAL,
1165 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1166
1167 /* Enable TetonII and BAM autoneg */
1168 CL45_RD_OVER_CL22(bp, params->port,
1169 params->phy_addr,
1170 MDIO_REG_BANK_BAM_NEXT_PAGE,
1171 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1172 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001173 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001174 /* Enable BAM aneg Mode and TetonII aneg Mode */
1175 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1176 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1177 } else {
1178 /* TetonII and BAM Autoneg Disabled */
1179 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1180 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1181 }
1182 CL45_WR_OVER_CL22(bp, params->port,
1183 params->phy_addr,
1184 MDIO_REG_BANK_BAM_NEXT_PAGE,
1185 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1186 reg_val);
1187
1188 /* Enable Clause 73 Aneg */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001189 if ((vars->line_speed == SPEED_AUTO_NEG) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001190 (SUPPORT_CL73)) {
1191 /* Enable BAM Station Manager */
1192
1193 CL45_WR_OVER_CL22(bp, params->port,
1194 params->phy_addr,
1195 MDIO_REG_BANK_CL73_USERB0,
1196 MDIO_CL73_USERB0_CL73_BAM_CTRL1,
1197 (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
1198 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
1199 MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN));
1200
1201 /* Merge CL73 and CL37 aneg resolution */
1202 CL45_RD_OVER_CL22(bp, params->port,
1203 params->phy_addr,
1204 MDIO_REG_BANK_CL73_USERB0,
1205 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1206 &reg_val);
1207
1208 CL45_WR_OVER_CL22(bp, params->port,
1209 params->phy_addr,
1210 MDIO_REG_BANK_CL73_USERB0,
1211 MDIO_CL73_USERB0_CL73_BAM_CTRL3,
1212 (reg_val |
1213 MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR));
1214
1215 /* Set the CL73 AN speed */
1216
1217 CL45_RD_OVER_CL22(bp, params->port,
1218 params->phy_addr,
1219 MDIO_REG_BANK_CL73_IEEEB1,
1220 MDIO_CL73_IEEEB1_AN_ADV2, &reg_val);
1221 /* In the SerDes we support only the 1G.
1222 In the XGXS we support the 10G KX4
1223 but we currently do not support the KR */
1224 if (vars->phy_flags & PHY_XGXS_FLAG) {
1225 DP(NETIF_MSG_LINK, "XGXS\n");
1226 /* 10G KX4 */
1227 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
1228 } else {
1229 DP(NETIF_MSG_LINK, "SerDes\n");
1230 /* 1000M KX */
1231 reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
1232 }
1233 CL45_WR_OVER_CL22(bp, params->port,
1234 params->phy_addr,
1235 MDIO_REG_BANK_CL73_IEEEB1,
1236 MDIO_CL73_IEEEB1_AN_ADV2, reg_val);
1237
1238 /* CL73 Autoneg Enabled */
1239 reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
1240 } else {
1241 /* CL73 Autoneg Disabled */
1242 reg_val = 0;
1243 }
1244 CL45_WR_OVER_CL22(bp, params->port,
1245 params->phy_addr,
1246 MDIO_REG_BANK_CL73_IEEEB0,
1247 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1248}
1249
1250/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001251static void bnx2x_program_serdes(struct link_params *params,
1252 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001253{
1254 struct bnx2x *bp = params->bp;
1255 u16 reg_val;
1256
1257 /* program duplex, disable autoneg */
1258
1259 CL45_RD_OVER_CL22(bp, params->port,
1260 params->phy_addr,
1261 MDIO_REG_BANK_COMBO_IEEE0,
1262 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1263 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
1264 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN);
1265 if (params->req_duplex == DUPLEX_FULL)
1266 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1267 CL45_WR_OVER_CL22(bp, params->port,
1268 params->phy_addr,
1269 MDIO_REG_BANK_COMBO_IEEE0,
1270 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1271
1272 /* program speed
1273 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001274 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001275 params->phy_addr,
1276 MDIO_REG_BANK_SERDES_DIGITAL,
1277 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001278 /* clearing the speed value before setting the right speed */
1279 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1280
1281 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1282 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1283
1284 if (!((vars->line_speed == SPEED_1000) ||
1285 (vars->line_speed == SPEED_100) ||
1286 (vars->line_speed == SPEED_10))) {
1287
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001288 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1289 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001290 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001291 reg_val |=
1292 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001293 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001294 reg_val |=
1295 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001296 }
1297
1298 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001299 params->phy_addr,
1300 MDIO_REG_BANK_SERDES_DIGITAL,
1301 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001302
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001303}
1304
1305static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1306{
1307 struct bnx2x *bp = params->bp;
1308 u16 val = 0;
1309
1310 /* configure the 48 bits for BAM AN */
1311
1312 /* set extended capabilities */
1313 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1314 val |= MDIO_OVER_1G_UP1_2_5G;
1315 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1316 val |= MDIO_OVER_1G_UP1_10G;
1317 CL45_WR_OVER_CL22(bp, params->port,
1318 params->phy_addr,
1319 MDIO_REG_BANK_OVER_1G,
1320 MDIO_OVER_1G_UP1, val);
1321
1322 CL45_WR_OVER_CL22(bp, params->port,
1323 params->phy_addr,
1324 MDIO_REG_BANK_OVER_1G,
1325 MDIO_OVER_1G_UP3, 0);
1326}
1327
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001328static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001329{
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001330 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001331 /* resolve pause mode and advertisement
1332 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1333
1334 switch (params->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001335 case BNX2X_FLOW_CTRL_AUTO:
1336 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001337 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001338 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1339 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001340 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001341 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1342 }
1343 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001344 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001345 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001346 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1347 break;
1348
David S. Millerc0700f92008-12-16 23:53:20 -08001349 case BNX2X_FLOW_CTRL_RX:
1350 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001351 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001352 break;
1353
David S. Millerc0700f92008-12-16 23:53:20 -08001354 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001355 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001356 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001357 break;
1358 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001359}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001360
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001361static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
1362 u32 ieee_fc)
1363{
1364 struct bnx2x *bp = params->bp;
1365 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001366
1367 CL45_WR_OVER_CL22(bp, params->port,
1368 params->phy_addr,
1369 MDIO_REG_BANK_COMBO_IEEE0,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001370 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001371}
1372
1373static void bnx2x_restart_autoneg(struct link_params *params)
1374{
1375 struct bnx2x *bp = params->bp;
1376 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
1377 if (SUPPORT_CL73) {
1378 /* enable and restart clause 73 aneg */
1379 u16 an_ctrl;
1380
1381 CL45_RD_OVER_CL22(bp, params->port,
1382 params->phy_addr,
1383 MDIO_REG_BANK_CL73_IEEEB0,
1384 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1385 &an_ctrl);
1386 CL45_WR_OVER_CL22(bp, params->port,
1387 params->phy_addr,
1388 MDIO_REG_BANK_CL73_IEEEB0,
1389 MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
1390 (an_ctrl |
1391 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
1392 MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
1393
1394 } else {
1395 /* Enable and restart BAM/CL37 aneg */
1396 u16 mii_control;
1397
1398 CL45_RD_OVER_CL22(bp, params->port,
1399 params->phy_addr,
1400 MDIO_REG_BANK_COMBO_IEEE0,
1401 MDIO_COMBO_IEEE0_MII_CONTROL,
1402 &mii_control);
1403 DP(NETIF_MSG_LINK,
1404 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1405 mii_control);
1406 CL45_WR_OVER_CL22(bp, params->port,
1407 params->phy_addr,
1408 MDIO_REG_BANK_COMBO_IEEE0,
1409 MDIO_COMBO_IEEE0_MII_CONTROL,
1410 (mii_control |
1411 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1412 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
1413 }
1414}
1415
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001416static void bnx2x_initialize_sgmii_process(struct link_params *params,
1417 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001418{
1419 struct bnx2x *bp = params->bp;
1420 u16 control1;
1421
1422 /* in SGMII mode, the unicore is always slave */
1423
1424 CL45_RD_OVER_CL22(bp, params->port,
1425 params->phy_addr,
1426 MDIO_REG_BANK_SERDES_DIGITAL,
1427 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1428 &control1);
1429 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1430 /* set sgmii mode (and not fiber) */
1431 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1432 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1433 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1434 CL45_WR_OVER_CL22(bp, params->port,
1435 params->phy_addr,
1436 MDIO_REG_BANK_SERDES_DIGITAL,
1437 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1438 control1);
1439
1440 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001441 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001442 /* set speed, disable autoneg */
1443 u16 mii_control;
1444
1445 CL45_RD_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 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1451 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1452 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1453
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001454 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001455 case SPEED_100:
1456 mii_control |=
1457 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1458 break;
1459 case SPEED_1000:
1460 mii_control |=
1461 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1462 break;
1463 case SPEED_10:
1464 /* there is nothing to set for 10M */
1465 break;
1466 default:
1467 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001468 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1469 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001470 break;
1471 }
1472
1473 /* setting the full duplex */
1474 if (params->req_duplex == DUPLEX_FULL)
1475 mii_control |=
1476 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1477 CL45_WR_OVER_CL22(bp, params->port,
1478 params->phy_addr,
1479 MDIO_REG_BANK_COMBO_IEEE0,
1480 MDIO_COMBO_IEEE0_MII_CONTROL,
1481 mii_control);
1482
1483 } else { /* AN mode */
1484 /* enable and restart AN */
1485 bnx2x_restart_autoneg(params);
1486 }
1487}
1488
1489
1490/*
1491 * link management
1492 */
1493
1494static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001495{ /* LD LP */
1496 switch (pause_result) { /* ASYM P ASYM P */
1497 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001498 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001499 break;
1500
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001501 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001502 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001503 break;
1504
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001505 case 0x5: /* 0 1 0 1 */
1506 case 0x7: /* 0 1 1 1 */
1507 case 0xd: /* 1 1 0 1 */
1508 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001509 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001510 break;
1511
1512 default:
1513 break;
1514 }
1515}
1516
1517static u8 bnx2x_ext_phy_resove_fc(struct link_params *params,
1518 struct link_vars *vars)
1519{
1520 struct bnx2x *bp = params->bp;
1521 u8 ext_phy_addr;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001522 u16 ld_pause; /* local */
1523 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001524 u16 an_complete; /* AN complete */
1525 u16 pause_result;
1526 u8 ret = 0;
1527 u32 ext_phy_type;
1528 u8 port = params->port;
1529 ext_phy_addr = ((params->ext_phy_config &
1530 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1531 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1532
1533 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1534 /* read twice */
1535
1536 bnx2x_cl45_read(bp, port,
1537 ext_phy_type,
1538 ext_phy_addr,
1539 MDIO_AN_DEVAD,
1540 MDIO_AN_REG_STATUS, &an_complete);
1541 bnx2x_cl45_read(bp, port,
1542 ext_phy_type,
1543 ext_phy_addr,
1544 MDIO_AN_DEVAD,
1545 MDIO_AN_REG_STATUS, &an_complete);
1546
1547 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1548 ret = 1;
1549 bnx2x_cl45_read(bp, port,
1550 ext_phy_type,
1551 ext_phy_addr,
1552 MDIO_AN_DEVAD,
1553 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1554 bnx2x_cl45_read(bp, port,
1555 ext_phy_type,
1556 ext_phy_addr,
1557 MDIO_AN_DEVAD,
1558 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1559 pause_result = (ld_pause &
1560 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1561 pause_result |= (lp_pause &
1562 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1563 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
1564 pause_result);
1565 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001566 if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001567 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1568 bnx2x_cl45_read(bp, port,
1569 ext_phy_type,
1570 ext_phy_addr,
1571 MDIO_AN_DEVAD,
1572 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1573
1574 bnx2x_cl45_read(bp, port,
1575 ext_phy_type,
1576 ext_phy_addr,
1577 MDIO_AN_DEVAD,
1578 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1579 pause_result = (ld_pause &
1580 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1581 pause_result |= (lp_pause &
1582 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1583
1584 bnx2x_pause_resolve(vars, pause_result);
1585 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
1586 pause_result);
1587 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001588 }
1589 return ret;
1590}
1591
1592
1593static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1594 struct link_vars *vars,
1595 u32 gp_status)
1596{
1597 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001598 u16 ld_pause; /* local driver */
1599 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001600 u16 pause_result;
1601
David S. Millerc0700f92008-12-16 23:53:20 -08001602 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001603
1604 /* resolve from gp_status in case of AN complete and not sgmii */
David S. Millerc0700f92008-12-16 23:53:20 -08001605 if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001606 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1607 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1608 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1609 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
1610 CL45_RD_OVER_CL22(bp, params->port,
1611 params->phy_addr,
1612 MDIO_REG_BANK_COMBO_IEEE0,
1613 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1614 &ld_pause);
1615 CL45_RD_OVER_CL22(bp, params->port,
1616 params->phy_addr,
1617 MDIO_REG_BANK_COMBO_IEEE0,
1618 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1619 &lp_pause);
1620 pause_result = (ld_pause &
1621 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
1622 pause_result |= (lp_pause &
1623 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
1624 DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
1625 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001626 } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001627 (bnx2x_ext_phy_resove_fc(params, vars))) {
1628 return;
1629 } else {
David S. Millerc0700f92008-12-16 23:53:20 -08001630 if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001631 vars->flow_ctrl = params->req_fc_auto_adv;
1632 else
1633 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001634 }
1635 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1636}
1637
1638
1639static u8 bnx2x_link_settings_status(struct link_params *params,
1640 struct link_vars *vars,
1641 u32 gp_status)
1642{
1643 struct bnx2x *bp = params->bp;
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001644 u16 new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001645 u8 rc = 0;
1646 vars->link_status = 0;
1647
1648 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1649 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1650 gp_status);
1651
1652 vars->phy_link_up = 1;
1653 vars->link_status |= LINK_STATUS_LINK_UP;
1654
1655 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1656 vars->duplex = DUPLEX_FULL;
1657 else
1658 vars->duplex = DUPLEX_HALF;
1659
1660 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1661
1662 switch (gp_status & GP_STATUS_SPEED_MASK) {
1663 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001664 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001665 if (vars->duplex == DUPLEX_FULL)
1666 vars->link_status |= LINK_10TFD;
1667 else
1668 vars->link_status |= LINK_10THD;
1669 break;
1670
1671 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001672 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001673 if (vars->duplex == DUPLEX_FULL)
1674 vars->link_status |= LINK_100TXFD;
1675 else
1676 vars->link_status |= LINK_100TXHD;
1677 break;
1678
1679 case GP_STATUS_1G:
1680 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001681 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001682 if (vars->duplex == DUPLEX_FULL)
1683 vars->link_status |= LINK_1000TFD;
1684 else
1685 vars->link_status |= LINK_1000THD;
1686 break;
1687
1688 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001689 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001690 if (vars->duplex == DUPLEX_FULL)
1691 vars->link_status |= LINK_2500TFD;
1692 else
1693 vars->link_status |= LINK_2500THD;
1694 break;
1695
1696 case GP_STATUS_5G:
1697 case GP_STATUS_6G:
1698 DP(NETIF_MSG_LINK,
1699 "link speed unsupported gp_status 0x%x\n",
1700 gp_status);
1701 return -EINVAL;
1702 break;
1703 case GP_STATUS_10G_KX4:
1704 case GP_STATUS_10G_HIG:
1705 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001706 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001707 vars->link_status |= LINK_10GTFD;
1708 break;
1709
1710 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001711 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001712 vars->link_status |= LINK_12GTFD;
1713 break;
1714
1715 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001716 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001717 vars->link_status |= LINK_12_5GTFD;
1718 break;
1719
1720 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001721 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001722 vars->link_status |= LINK_13GTFD;
1723 break;
1724
1725 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001726 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001727 vars->link_status |= LINK_15GTFD;
1728 break;
1729
1730 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001731 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001732 vars->link_status |= LINK_16GTFD;
1733 break;
1734
1735 default:
1736 DP(NETIF_MSG_LINK,
1737 "link speed unsupported gp_status 0x%x\n",
1738 gp_status);
1739 return -EINVAL;
1740 break;
1741 }
1742
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001743 /* Upon link speed change set the NIG into drain mode.
1744 Comes to deals with possible FIFO glitch due to clk change
1745 when speed is decreased without link down indicator */
1746 if (new_line_speed != vars->line_speed) {
1747 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
1748 + params->port*4, 0);
1749 msleep(1);
1750 }
1751 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001752 vars->link_status |= LINK_STATUS_SERDES_LINK;
1753
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001754 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1755 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1756 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1757 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein589abe32009-02-12 08:36:55 +00001758 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
1759 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein28577182009-02-12 08:37:00 +00001760 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
1761 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1762 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001763 vars->autoneg = AUTO_NEG_ENABLED;
1764
1765 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1766 vars->autoneg |= AUTO_NEG_COMPLETE;
1767 vars->link_status |=
1768 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1769 }
1770
1771 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1772 vars->link_status |=
1773 LINK_STATUS_PARALLEL_DETECTION_USED;
1774
1775 }
David S. Millerc0700f92008-12-16 23:53:20 -08001776 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001777 vars->link_status |=
1778 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001779
David S. Millerc0700f92008-12-16 23:53:20 -08001780 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001781 vars->link_status |=
1782 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001783
1784 } else { /* link_down */
1785 DP(NETIF_MSG_LINK, "phy link down\n");
1786
1787 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001788
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001789 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001790 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001791 vars->autoneg = AUTO_NEG_DISABLED;
1792 vars->mac_type = MAC_TYPE_NONE;
1793 }
1794
1795 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n",
1796 gp_status, vars->phy_link_up, vars->line_speed);
1797 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1798 " autoneg 0x%x\n",
1799 vars->duplex,
1800 vars->flow_ctrl, vars->autoneg);
1801 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1802
1803 return rc;
1804}
1805
1806static void bnx2x_set_sgmii_tx_driver(struct link_params *params)
1807{
1808 struct bnx2x *bp = params->bp;
1809 u16 lp_up2;
1810 u16 tx_driver;
1811
1812 /* read precomp */
1813
1814 CL45_RD_OVER_CL22(bp, params->port,
1815 params->phy_addr,
1816 MDIO_REG_BANK_OVER_1G,
1817 MDIO_OVER_1G_LP_UP2, &lp_up2);
1818
1819 CL45_RD_OVER_CL22(bp, params->port,
1820 params->phy_addr,
1821 MDIO_REG_BANK_TX0,
1822 MDIO_TX0_TX_DRIVER, &tx_driver);
1823
1824 /* bits [10:7] at lp_up2, positioned at [15:12] */
1825 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1826 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1827 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1828
1829 if ((lp_up2 != 0) &&
1830 (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) {
1831 /* replace tx_driver bits [15:12] */
1832 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1833 tx_driver |= lp_up2;
1834 CL45_WR_OVER_CL22(bp, params->port,
1835 params->phy_addr,
1836 MDIO_REG_BANK_TX0,
1837 MDIO_TX0_TX_DRIVER, tx_driver);
1838 }
1839}
1840
1841static u8 bnx2x_emac_program(struct link_params *params,
1842 u32 line_speed, u32 duplex)
1843{
1844 struct bnx2x *bp = params->bp;
1845 u8 port = params->port;
1846 u16 mode = 0;
1847
1848 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1849 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1850 EMAC_REG_EMAC_MODE,
1851 (EMAC_MODE_25G_MODE |
1852 EMAC_MODE_PORT_MII_10M |
1853 EMAC_MODE_HALF_DUPLEX));
1854 switch (line_speed) {
1855 case SPEED_10:
1856 mode |= EMAC_MODE_PORT_MII_10M;
1857 break;
1858
1859 case SPEED_100:
1860 mode |= EMAC_MODE_PORT_MII;
1861 break;
1862
1863 case SPEED_1000:
1864 mode |= EMAC_MODE_PORT_GMII;
1865 break;
1866
1867 case SPEED_2500:
1868 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
1869 break;
1870
1871 default:
1872 /* 10G not valid for EMAC */
1873 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
1874 return -EINVAL;
1875 }
1876
1877 if (duplex == DUPLEX_HALF)
1878 mode |= EMAC_MODE_HALF_DUPLEX;
1879 bnx2x_bits_en(bp,
1880 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
1881 mode);
1882
1883 bnx2x_set_led(bp, params->port, LED_MODE_OPER,
1884 line_speed, params->hw_led_mode, params->chip_id);
1885 return 0;
1886}
1887
1888/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001889/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001890/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001891static void bnx2x_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001892{
1893 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001894 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001895 msleep(1);
1896 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001897 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001898}
1899
1900static void bnx2x_ext_phy_reset(struct link_params *params,
1901 struct link_vars *vars)
1902{
1903 struct bnx2x *bp = params->bp;
1904 u32 ext_phy_type;
1905 u8 ext_phy_addr = ((params->ext_phy_config &
1906 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1907 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1908 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
1909 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1910 /* The PHY reset is controled by GPIO 1
1911 * Give it 1ms of reset pulse
1912 */
1913 if (vars->phy_flags & PHY_XGXS_FLAG) {
1914
1915 switch (ext_phy_type) {
1916 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
1917 DP(NETIF_MSG_LINK, "XGXS Direct\n");
1918 break;
1919
1920 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
1921 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
1922 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
1923
1924 /* Restore normal power mode*/
1925 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001926 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1927 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001928
1929 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001930 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001931
1932 bnx2x_cl45_write(bp, params->port,
1933 ext_phy_type,
1934 ext_phy_addr,
1935 MDIO_PMA_DEVAD,
1936 MDIO_PMA_REG_CTRL, 0xa040);
1937 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00001938 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
1939
1940 /* Restore normal power mode*/
1941 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
1942 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1943 params->port);
1944
1945 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
1946 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1947 params->port);
1948
1949 bnx2x_cl45_write(bp, params->port,
1950 ext_phy_type,
1951 ext_phy_addr,
1952 MDIO_PMA_DEVAD,
1953 MDIO_PMA_REG_CTRL,
1954 1<<15);
1955
1956 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001957 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
1958 /* Unset Low Power Mode and SW reset */
1959 /* Restore normal power mode*/
1960 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001961 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1962 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001963
1964 DP(NETIF_MSG_LINK, "XGXS 8072\n");
1965 bnx2x_cl45_write(bp, params->port,
1966 ext_phy_type,
1967 ext_phy_addr,
1968 MDIO_PMA_DEVAD,
1969 MDIO_PMA_REG_CTRL,
1970 1<<15);
1971 break;
1972 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
1973 {
1974 u16 emac_base;
1975 emac_base = (params->port) ? GRCBASE_EMAC0 :
1976 GRCBASE_EMAC1;
1977
1978 /* Restore normal power mode*/
1979 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001980 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1981 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001982
1983 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001984 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1985 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001986
1987 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001988 }
1989 break;
1990
1991 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
1992 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
1993
1994 /* Restore normal power mode*/
1995 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001996 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1997 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001998
1999 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002000 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002001
2002 break;
2003
Eilon Greenstein28577182009-02-12 08:37:00 +00002004 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
2005
2006 /* Restore normal power mode*/
2007 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
2008 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
2009 params->port);
2010
2011 /* HW reset */
2012 bnx2x_hw_reset(bp, params->port);
2013
2014 bnx2x_cl45_write(bp, params->port,
2015 ext_phy_type,
2016 ext_phy_addr,
2017 MDIO_PMA_DEVAD,
2018 MDIO_PMA_REG_CTRL,
2019 1<<15);
2020 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002021 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
2022 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
2023 break;
2024
2025 default:
2026 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
2027 params->ext_phy_config);
2028 break;
2029 }
2030
2031 } else { /* SerDes */
2032 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
2033 switch (ext_phy_type) {
2034 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
2035 DP(NETIF_MSG_LINK, "SerDes Direct\n");
2036 break;
2037
2038 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
2039 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greenstein17de50b2008-08-13 15:56:59 -07002040 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002041 break;
2042
2043 default:
2044 DP(NETIF_MSG_LINK,
2045 "BAD SerDes ext_phy_config 0x%x\n",
2046 params->ext_phy_config);
2047 break;
2048 }
2049 }
2050}
2051
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002052
2053static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
2054 u32 shmem_base, u32 spirom_ver)
2055{
2056 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x\n",
2057 (u16)(spirom_ver>>16), (u16)spirom_ver);
2058 REG_WR(bp, shmem_base +
2059 offsetof(struct shmem_region,
2060 port_mb[port].ext_phy_fw_version),
2061 spirom_ver);
2062}
2063
2064static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
2065 u32 ext_phy_type, u8 ext_phy_addr,
2066 u32 shmem_base)
2067{
2068 u16 fw_ver1, fw_ver2;
2069 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2070 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2071 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2072 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2073 bnx2x_save_spirom_version(bp, port, shmem_base,
2074 (u32)(fw_ver1<<16 | fw_ver2));
2075}
2076
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002077static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
2078{
2079 struct bnx2x *bp = params->bp;
2080 u8 port = params->port;
2081 u8 ext_phy_addr = ((params->ext_phy_config &
2082 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2083 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2084 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002085
2086 /* Need to wait 200ms after reset */
2087 msleep(200);
2088 /* Boot port from external ROM
2089 * Set ser_boot_ctl bit in the MISC_CTRL1 register
2090 */
2091 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2092 MDIO_PMA_DEVAD,
2093 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2094
2095 /* Reset internal microprocessor */
2096 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2097 MDIO_PMA_DEVAD,
2098 MDIO_PMA_REG_GEN_CTRL,
2099 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2100 /* set micro reset = 0 */
2101 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2102 MDIO_PMA_DEVAD,
2103 MDIO_PMA_REG_GEN_CTRL,
2104 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2105 /* Reset internal microprocessor */
2106 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2107 MDIO_PMA_DEVAD,
2108 MDIO_PMA_REG_GEN_CTRL,
2109 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2110 /* wait for 100ms for code download via SPI port */
2111 msleep(100);
2112
2113 /* Clear ser_boot_ctl bit */
2114 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2115 MDIO_PMA_DEVAD,
2116 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2117 /* Wait 100ms */
2118 msleep(100);
2119
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002120 bnx2x_save_bcm_spirom_ver(bp, port,
2121 ext_phy_type,
2122 ext_phy_addr,
2123 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002124}
2125
2126static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2127{
2128 /* This is only required for 8073A1, version 102 only */
2129
2130 struct bnx2x *bp = params->bp;
2131 u8 ext_phy_addr = ((params->ext_phy_config &
2132 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2133 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2134 u16 val;
2135
2136 /* Read 8073 HW revision*/
2137 bnx2x_cl45_read(bp, params->port,
2138 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2139 ext_phy_addr,
2140 MDIO_PMA_DEVAD,
2141 0xc801, &val);
2142
2143 if (val != 1) {
2144 /* No need to workaround in 8073 A1 */
2145 return 0;
2146 }
2147
2148 bnx2x_cl45_read(bp, params->port,
2149 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2150 ext_phy_addr,
2151 MDIO_PMA_DEVAD,
2152 MDIO_PMA_REG_ROM_VER2, &val);
2153
2154 /* SNR should be applied only for version 0x102 */
2155 if (val != 0x102)
2156 return 0;
2157
2158 return 1;
2159}
2160
2161static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2162{
2163 struct bnx2x *bp = params->bp;
2164 u8 ext_phy_addr = ((params->ext_phy_config &
2165 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2166 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2167 u16 val, cnt, cnt1 ;
2168
2169 bnx2x_cl45_read(bp, params->port,
2170 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2171 ext_phy_addr,
2172 MDIO_PMA_DEVAD,
2173 0xc801, &val);
2174
2175 if (val > 0) {
2176 /* No need to workaround in 8073 A1 */
2177 return 0;
2178 }
2179 /* XAUI workaround in 8073 A0: */
2180
2181 /* After loading the boot ROM and restarting Autoneg,
2182 poll Dev1, Reg $C820: */
2183
2184 for (cnt = 0; cnt < 1000; cnt++) {
2185 bnx2x_cl45_read(bp, params->port,
2186 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2187 ext_phy_addr,
2188 MDIO_PMA_DEVAD,
2189 0xc820, &val);
2190 /* If bit [14] = 0 or bit [13] = 0, continue on with
2191 system initialization (XAUI work-around not required,
2192 as these bits indicate 2.5G or 1G link up). */
2193 if (!(val & (1<<14)) || !(val & (1<<13))) {
2194 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2195 return 0;
2196 } else if (!(val & (1<<15))) {
2197 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2198 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2199 it's MSB (bit 15) goes to 1 (indicating that the
2200 XAUI workaround has completed),
2201 then continue on with system initialization.*/
2202 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2203 bnx2x_cl45_read(bp, params->port,
2204 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2205 ext_phy_addr,
2206 MDIO_PMA_DEVAD,
2207 0xc841, &val);
2208 if (val & (1<<15)) {
2209 DP(NETIF_MSG_LINK,
2210 "XAUI workaround has completed\n");
2211 return 0;
2212 }
2213 msleep(3);
2214 }
2215 break;
2216 }
2217 msleep(3);
2218 }
2219 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2220 return -EINVAL;
2221
2222}
2223
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002224static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002225 u8 ext_phy_addr, u32 shmem_base)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002226{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002227 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002228 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002229 bnx2x_cl45_write(bp, port,
2230 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2231 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002232 MDIO_PMA_DEVAD,
2233 MDIO_PMA_REG_GEN_CTRL,
2234 0x0001);
2235
2236 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002237 bnx2x_cl45_write(bp, port,
2238 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2239 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002240 MDIO_PMA_DEVAD,
2241 MDIO_PMA_REG_GEN_CTRL,
2242 0x008c);
2243
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002244 bnx2x_cl45_write(bp, port,
2245 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2246 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002247 MDIO_PMA_DEVAD,
2248 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2249
2250 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002251 bnx2x_cl45_write(bp, port,
2252 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2253 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002254 MDIO_PMA_DEVAD,
2255 MDIO_PMA_REG_GEN_CTRL,
2256 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2257
2258 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002259 bnx2x_cl45_write(bp, port,
2260 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2261 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002262 MDIO_PMA_DEVAD,
2263 MDIO_PMA_REG_GEN_CTRL,
2264 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2265
2266 /* wait for 100ms for code download via SPI port */
2267 msleep(100);
2268
2269 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002270 bnx2x_cl45_write(bp, port,
2271 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2272 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002273 MDIO_PMA_DEVAD,
2274 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2275
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002276 bnx2x_save_bcm_spirom_ver(bp, port,
2277 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2278 ext_phy_addr,
2279 shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002280}
2281
Eilon Greenstein589abe32009-02-12 08:36:55 +00002282static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
2283{
2284 struct bnx2x *bp = params->bp;
2285 u8 port = params->port;
2286 u8 ext_phy_addr = ((params->ext_phy_config &
2287 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2288 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2289 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2290
2291 /* Need to wait 100ms after reset */
2292 msleep(100);
2293
2294 /* Set serial boot control for external load */
2295 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2296 MDIO_PMA_DEVAD,
2297 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2298
2299 /* Micro controller re-boot */
2300 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2301 MDIO_PMA_DEVAD,
2302 MDIO_PMA_REG_GEN_CTRL,
2303 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2304
2305 /* Set soft reset */
2306 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2307 MDIO_PMA_DEVAD,
2308 MDIO_PMA_REG_GEN_CTRL,
2309 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2310
2311 /* Clear soft reset.
2312 Will automatically reset micro-controller re-boot */
2313 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2314 MDIO_PMA_DEVAD,
2315 MDIO_PMA_REG_GEN_CTRL,
2316 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2317
2318 /* wait for 100ms for microcode load */
2319 msleep(100);
2320
2321 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
2322 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2323 MDIO_PMA_DEVAD,
2324 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2325
2326 msleep(200);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002327 bnx2x_save_bcm_spirom_ver(bp, port,
2328 ext_phy_type,
2329 ext_phy_addr,
2330 params->shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002331}
2332
2333static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
2334 u8 ext_phy_addr, u8 tx_en)
2335{
2336 u16 val;
2337 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2338 tx_en, port);
2339 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
2340 bnx2x_cl45_read(bp, port,
2341 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2342 ext_phy_addr,
2343 MDIO_PMA_DEVAD,
2344 MDIO_PMA_REG_PHY_IDENTIFIER,
2345 &val);
2346
2347 if (tx_en)
2348 val &= ~(1<<15);
2349 else
2350 val |= (1<<15);
2351
2352 bnx2x_cl45_write(bp, port,
2353 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2354 ext_phy_addr,
2355 MDIO_PMA_DEVAD,
2356 MDIO_PMA_REG_PHY_IDENTIFIER,
2357 val);
2358}
2359
2360
2361static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
2362 u8 byte_cnt, u8 *o_buf) {
2363 struct bnx2x *bp = params->bp;
2364 u16 val, i;
2365 u8 port = params->port;
2366 u8 ext_phy_addr = ((params->ext_phy_config &
2367 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2368 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2369 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2370 if (byte_cnt > 16) {
2371 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2372 " is limited to 0xf\n");
2373 return -EINVAL;
2374 }
2375 /* Set the read command byte count */
2376 bnx2x_cl45_write(bp, port,
2377 ext_phy_type,
2378 ext_phy_addr,
2379 MDIO_PMA_DEVAD,
2380 MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
2381 (byte_cnt | 0xa000));
2382
2383 /* Set the read command address */
2384 bnx2x_cl45_write(bp, port,
2385 ext_phy_type,
2386 ext_phy_addr,
2387 MDIO_PMA_DEVAD,
2388 MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
2389 addr);
2390
2391 /* Activate read command */
2392 bnx2x_cl45_write(bp, port,
2393 ext_phy_type,
2394 ext_phy_addr,
2395 MDIO_PMA_DEVAD,
2396 MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
2397 0x2c0f);
2398
2399 /* Wait up to 500us for command complete status */
2400 for (i = 0; i < 100; i++) {
2401 bnx2x_cl45_read(bp, port,
2402 ext_phy_type,
2403 ext_phy_addr,
2404 MDIO_PMA_DEVAD,
2405 MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
2406 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
2407 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
2408 break;
2409 udelay(5);
2410 }
2411
2412 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
2413 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
2414 DP(NETIF_MSG_LINK,
2415 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2416 (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
2417 return -EINVAL;
2418 }
2419
2420 /* Read the buffer */
2421 for (i = 0; i < byte_cnt; i++) {
2422 bnx2x_cl45_read(bp, port,
2423 ext_phy_type,
2424 ext_phy_addr,
2425 MDIO_PMA_DEVAD,
2426 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2427 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2428 }
2429
2430 for (i = 0; i < 100; i++) {
2431 bnx2x_cl45_read(bp, port,
2432 ext_phy_type,
2433 ext_phy_addr,
2434 MDIO_PMA_DEVAD,
2435 MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
2436 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
2437 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
2438 return 0;;
2439 msleep(1);
2440 }
2441 return -EINVAL;
2442}
2443
2444
2445static u8 bnx2x_get_sfp_module_type(struct link_params *params,
2446 u8 *module_type)
2447{
2448 struct bnx2x *bp = params->bp;
2449 u8 val;
2450 *module_type = SFP_MODULE_TYPE_UNKNOWN;
2451
2452 /* First check for copper cable */
2453 if (bnx2x_read_sfp_module_eeprom(params,
2454 SFP_EEPROM_CON_TYPE_ADDR,
2455 1,
2456 &val) != 0) {
2457 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
2458 return -EINVAL;
2459 }
2460
2461 switch (val) {
2462 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2463 {
2464 u8 copper_module_type;
2465 /* Check if its active cable( includes SFP+ module)
2466 of passive cable*/
2467 if (bnx2x_read_sfp_module_eeprom(params,
2468 SFP_EEPROM_FC_TX_TECH_ADDR,
2469 1,
2470 &copper_module_type) !=
2471 0) {
2472 DP(NETIF_MSG_LINK,
2473 "Failed to read copper-cable-type"
2474 " from SFP+ EEPROM\n");
2475 return -EINVAL;
2476 }
2477
2478 if (copper_module_type &
2479 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2480 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
2481 *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
2482 } else if (copper_module_type &
2483 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2484 DP(NETIF_MSG_LINK, "Passive Copper"
2485 " cable detected\n");
2486 *module_type =
2487 SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
2488 } else {
2489 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2490 "type 0x%x !!!\n", copper_module_type);
2491 return -EINVAL;
2492 }
2493 break;
2494 }
2495 case SFP_EEPROM_CON_TYPE_VAL_LC:
2496 DP(NETIF_MSG_LINK, "Optic module detected\n");
2497 *module_type = SFP_MODULE_TYPE_LC;
2498 break;
2499
2500 default:
2501 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2502 val);
2503 return -EINVAL;
2504 }
2505 return 0;
2506}
2507
2508
2509/* This function read the relevant field from the module ( SFP+ ),
2510 and verify it is compliant with this board */
2511static u8 bnx2x_verify_sfp_module(struct link_params *params,
2512 u8 module_type)
2513{
2514 struct bnx2x *bp = params->bp;
2515 u8 *str_p, *tmp_buf;
2516 u16 i;
2517
2518#define COMPLIANCE_STR_CNT 6
2519 u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
2520 "FINISAR CORP. ", "Amphenol"};
2521 u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
2522 /* Passive Copper cables are allowed to participate,
2523 since the module is hardwired to the copper cable */
2524
2525 if (!(params->feature_config_flags &
2526 FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
2527 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2528 return 0;
2529 }
2530
2531 if (module_type != SFP_MODULE_TYPE_LC) {
2532 DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
2533 return 0;
2534 }
2535
2536 /* In case of non copper cable or Active copper cable,
2537 verify that the SFP+ module is compliant with this board*/
2538 if (bnx2x_read_sfp_module_eeprom(params,
2539 SFP_EEPROM_VENDOR_NAME_ADDR,
2540 SFP_EEPROM_VENDOR_NAME_SIZE,
2541 buf) != 0) {
2542 DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
2543 " module EEPROM\n");
2544 return -EINVAL;
2545 }
2546 for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
2547 str_p = compliance_str[i];
2548 tmp_buf = buf;
2549 while (*str_p) {
2550 if ((u8)(*tmp_buf) != (u8)(*str_p))
2551 break;
2552 str_p++;
2553 tmp_buf++;
2554 }
2555
2556 if (!(*str_p)) {
2557 DP(NETIF_MSG_LINK, "SFP+ Module verified, "
2558 "index=%x\n", i);
2559 return 0;
2560 }
2561 }
2562 DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
2563 return -EINVAL;
2564}
2565
2566
2567static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
2568 u8 module_type)
2569{
2570 struct bnx2x *bp = params->bp;
2571 u8 port = params->port;
2572 u8 options[SFP_EEPROM_OPTIONS_SIZE];
2573 u8 limiting_mode;
2574 u8 ext_phy_addr = ((params->ext_phy_config &
2575 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2576 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2577
2578 if (bnx2x_read_sfp_module_eeprom(params,
2579 SFP_EEPROM_OPTIONS_ADDR,
2580 SFP_EEPROM_OPTIONS_SIZE,
2581 options) != 0) {
2582 DP(NETIF_MSG_LINK, "Failed to read Option field from"
2583 " module EEPROM\n");
2584 return -EINVAL;
2585 }
2586 limiting_mode = !(options[0] &
2587 SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
2588 if (limiting_mode &&
2589 (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
2590 DP(NETIF_MSG_LINK,
2591 "Module options = 0x%x.Setting LIMITING MODE\n",
2592 options[0]);
2593 bnx2x_cl45_write(bp, port,
2594 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2595 ext_phy_addr,
2596 MDIO_PMA_DEVAD,
2597 MDIO_PMA_REG_ROM_VER2,
2598 SFP_LIMITING_MODE_VALUE);
2599 } else { /* LRM mode ( default )*/
2600 u16 cur_limiting_mode;
2601 DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
2602 options[0]);
2603
2604 bnx2x_cl45_read(bp, port,
2605 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2606 ext_phy_addr,
2607 MDIO_PMA_DEVAD,
2608 MDIO_PMA_REG_ROM_VER2,
2609 &cur_limiting_mode);
2610
2611 /* Changing to LRM mode takes quite few seconds.
2612 So do it only if current mode is limiting
2613 ( default is LRM )*/
2614 if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
2615 return 0;
2616
2617 bnx2x_cl45_write(bp, port,
2618 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2619 ext_phy_addr,
2620 MDIO_PMA_DEVAD,
2621 MDIO_PMA_REG_LRM_MODE,
2622 0);
2623 bnx2x_cl45_write(bp, port,
2624 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2625 ext_phy_addr,
2626 MDIO_PMA_DEVAD,
2627 MDIO_PMA_REG_ROM_VER2,
2628 0x128);
2629 bnx2x_cl45_write(bp, port,
2630 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2631 ext_phy_addr,
2632 MDIO_PMA_DEVAD,
2633 MDIO_PMA_REG_MISC_CTRL0,
2634 0x4008);
2635 bnx2x_cl45_write(bp, port,
2636 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2637 ext_phy_addr,
2638 MDIO_PMA_DEVAD,
2639 MDIO_PMA_REG_LRM_MODE,
2640 0xaaaa);
2641 }
2642 return 0;
2643}
2644
2645static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
2646{
2647 u8 val;
2648 struct bnx2x *bp = params->bp;
2649 u16 timeout;
2650 /* Initialization time after hot-plug may take up to 300ms for some
2651 phys type ( e.g. JDSU ) */
2652 for (timeout = 0; timeout < 60; timeout++) {
2653 if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
2654 == 0) {
2655 DP(NETIF_MSG_LINK, "SFP+ module initialization "
2656 "took %d ms\n", timeout * 5);
2657 return 0;
2658 }
2659 msleep(5);
2660 }
2661 return -EINVAL;
2662}
2663
2664static u8 bnx2x_sfp_module_detection(struct link_params *params)
2665{
2666 struct bnx2x *bp = params->bp;
2667 u8 module_type;
2668 u8 ext_phy_addr = ((params->ext_phy_config &
2669 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2670 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2671 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2672
2673 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
2674 DP(NETIF_MSG_LINK, "Module detection is not required "
2675 "for this phy\n");
2676 return 0;
2677 }
2678
2679 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
2680 params->port);
2681
2682 if (bnx2x_get_sfp_module_type(params,
2683 &module_type) != 0) {
2684 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
2685 if (!(params->feature_config_flags &
2686 FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
2687 /* In case module detection is disabled, it trys to
2688 link up. The issue that can happen here is LRM /
2689 LIMITING mode which set according to the module-type*/
2690 DP(NETIF_MSG_LINK, "Unable to read module-type."
2691 "Probably due to Bit Stretching."
2692 " Proceeding...\n");
2693 } else {
2694 return -EINVAL;
2695 }
2696 } else if (bnx2x_verify_sfp_module(params, module_type) !=
2697 0) {
2698 /* check SFP+ module compatibility */
2699 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
2700 /* Turn on fault module-detected led */
2701 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2702 MISC_REGISTERS_GPIO_HIGH,
2703 params->port);
2704 return -EINVAL;
2705 }
2706
2707 /* Turn off fault module-detected led */
2708 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2709 MISC_REGISTERS_GPIO_LOW,
2710 params->port);
2711
2712 /* Check and set limiting mode / LRM mode */
2713 if (bnx2x_bcm8726_set_limiting_mode(params, module_type)
2714 != 0) {
2715 DP(NETIF_MSG_LINK, "Setting limiting mode failed!!\n");
2716 return -EINVAL;
2717 }
2718
2719 /* Enable transmit for this module */
2720 bnx2x_bcm8726_set_transmitter(bp, params->port,
2721 ext_phy_addr, 1);
2722 return 0;
2723}
2724
2725void bnx2x_handle_module_detect_int(struct link_params *params)
2726{
2727 struct bnx2x *bp = params->bp;
2728 u32 gpio_val;
2729 u8 port = params->port;
2730 /* Set valid module led off */
2731 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2732 MISC_REGISTERS_GPIO_HIGH,
2733 params->port);
2734
2735 /* Get current gpio val refelecting module plugged in / out*/
2736 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
2737
2738 /* Call the handling function in case module is detected */
2739 if (gpio_val == 0) {
2740
2741 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
2742 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
2743 port);
2744
2745 if (bnx2x_wait_for_sfp_module_initialized(params)
2746 == 0)
2747 bnx2x_sfp_module_detection(params);
2748 else
2749 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
2750 } else {
2751 u8 ext_phy_addr = ((params->ext_phy_config &
2752 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2753 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2754 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
2755 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
2756 port);
2757 /* Module was plugged out. */
2758 /* Disable transmit for this module */
2759 bnx2x_bcm8726_set_transmitter(bp, params->port,
2760 ext_phy_addr, 0);
2761 }
2762}
2763
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002764static void bnx2x_bcm807x_force_10G(struct link_params *params)
2765{
2766 struct bnx2x *bp = params->bp;
2767 u8 port = params->port;
2768 u8 ext_phy_addr = ((params->ext_phy_config &
2769 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2770 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2771 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2772
2773 /* Force KR or KX */
2774 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2775 MDIO_PMA_DEVAD,
2776 MDIO_PMA_REG_CTRL,
2777 0x2040);
2778 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2779 MDIO_PMA_DEVAD,
2780 MDIO_PMA_REG_10G_CTRL2,
2781 0x000b);
2782 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2783 MDIO_PMA_DEVAD,
2784 MDIO_PMA_REG_BCM_CTRL,
2785 0x0000);
2786 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2787 MDIO_AN_DEVAD,
2788 MDIO_AN_REG_CTRL,
2789 0x0000);
2790}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002791static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
2792{
2793 struct bnx2x *bp = params->bp;
2794 u8 port = params->port;
2795 u16 val;
2796 u8 ext_phy_addr = ((params->ext_phy_config &
2797 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2798 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2799 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2800
2801 bnx2x_cl45_read(bp, params->port,
2802 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2803 ext_phy_addr,
2804 MDIO_PMA_DEVAD,
2805 0xc801, &val);
2806
2807 if (val == 0) {
2808 /* Mustn't set low power mode in 8073 A0 */
2809 return;
2810 }
2811
2812 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
2813 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2814 MDIO_XS_DEVAD,
2815 MDIO_XS_PLL_SEQUENCER, &val);
2816 val &= ~(1<<13);
2817 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2818 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2819
2820 /* PLL controls */
2821 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2822 MDIO_XS_DEVAD, 0x805E, 0x1077);
2823 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2824 MDIO_XS_DEVAD, 0x805D, 0x0000);
2825 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2826 MDIO_XS_DEVAD, 0x805C, 0x030B);
2827 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2828 MDIO_XS_DEVAD, 0x805B, 0x1240);
2829 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2830 MDIO_XS_DEVAD, 0x805A, 0x2490);
2831
2832 /* Tx Controls */
2833 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2834 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2835 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2836 MDIO_XS_DEVAD, 0x80A6, 0x9041);
2837 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2838 MDIO_XS_DEVAD, 0x80A5, 0x4640);
2839
2840 /* Rx Controls */
2841 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2842 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2843 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2844 MDIO_XS_DEVAD, 0x80FD, 0x9249);
2845 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2846 MDIO_XS_DEVAD, 0x80FC, 0x2015);
2847
2848 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
2849 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2850 MDIO_XS_DEVAD,
2851 MDIO_XS_PLL_SEQUENCER, &val);
2852 val |= (1<<13);
2853 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2854 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2855}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002856
2857static void bnx2x_8073_set_pause_cl37(struct link_params *params,
2858 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002859{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002860
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002861 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002862 u16 cl37_val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002863 u8 ext_phy_addr = ((params->ext_phy_config &
2864 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2865 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2866 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2867
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002868 bnx2x_cl45_read(bp, params->port,
2869 ext_phy_type,
2870 ext_phy_addr,
2871 MDIO_AN_DEVAD,
2872 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
2873
2874 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2875 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2876
2877 if ((vars->ieee_fc &
2878 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
2879 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
2880 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
2881 }
2882 if ((vars->ieee_fc &
2883 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2884 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2885 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2886 }
2887 if ((vars->ieee_fc &
2888 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2889 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2890 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2891 }
2892 DP(NETIF_MSG_LINK,
2893 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
2894
2895 bnx2x_cl45_write(bp, params->port,
2896 ext_phy_type,
2897 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002898 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002899 MDIO_AN_REG_CL37_FC_LD, cl37_val);
2900 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002901}
2902
2903static void bnx2x_ext_phy_set_pause(struct link_params *params,
2904 struct link_vars *vars)
2905{
2906 struct bnx2x *bp = params->bp;
2907 u16 val;
2908 u8 ext_phy_addr = ((params->ext_phy_config &
2909 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2910 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2911 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2912
2913 /* read modify write pause advertizing */
2914 bnx2x_cl45_read(bp, params->port,
2915 ext_phy_type,
2916 ext_phy_addr,
2917 MDIO_AN_DEVAD,
2918 MDIO_AN_REG_ADV_PAUSE, &val);
2919
2920 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002921
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002922 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2923
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002924 if ((vars->ieee_fc &
2925 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002926 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2927 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2928 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002929 if ((vars->ieee_fc &
2930 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002931 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2932 val |=
2933 MDIO_AN_REG_ADV_PAUSE_PAUSE;
2934 }
2935 DP(NETIF_MSG_LINK,
2936 "Ext phy AN advertize 0x%x\n", val);
2937 bnx2x_cl45_write(bp, params->port,
2938 ext_phy_type,
2939 ext_phy_addr,
2940 MDIO_AN_DEVAD,
2941 MDIO_AN_REG_ADV_PAUSE, val);
2942}
2943
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002944
2945static void bnx2x_init_internal_phy(struct link_params *params,
2946 struct link_vars *vars)
2947{
2948 struct bnx2x *bp = params->bp;
2949 u8 port = params->port;
2950 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2951 u16 bank, rx_eq;
2952
2953 rx_eq = ((params->serdes_config &
2954 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >>
2955 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT);
2956
2957 DP(NETIF_MSG_LINK, "setting rx eq to 0x%x\n", rx_eq);
2958 for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL;
2959 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0)) {
2960 CL45_WR_OVER_CL22(bp, port,
2961 params->phy_addr,
2962 bank ,
2963 MDIO_RX0_RX_EQ_BOOST,
2964 ((rx_eq &
2965 MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) |
2966 MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL));
2967 }
2968
2969 /* forced speed requested? */
2970 if (vars->line_speed != SPEED_AUTO_NEG) {
2971 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2972
2973 /* disable autoneg */
2974 bnx2x_set_autoneg(params, vars);
2975
2976 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002977 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002978
2979 } else { /* AN_mode */
2980 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2981
2982 /* AN enabled */
2983 bnx2x_set_brcm_cl37_advertisment(params);
2984
2985 /* program duplex & pause advertisement (for aneg) */
2986 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002987 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002988
2989 /* enable autoneg */
2990 bnx2x_set_autoneg(params, vars);
2991
2992 /* enable and restart AN */
2993 bnx2x_restart_autoneg(params);
2994 }
2995
2996 } else { /* SGMII mode */
2997 DP(NETIF_MSG_LINK, "SGMII\n");
2998
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002999 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003000 }
3001}
3002
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003003static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
3004{
3005 struct bnx2x *bp = params->bp;
3006 u32 ext_phy_type;
3007 u8 ext_phy_addr;
3008 u16 cnt;
3009 u16 ctrl = 0;
3010 u16 val = 0;
3011 u8 rc = 0;
3012 if (vars->phy_flags & PHY_XGXS_FLAG) {
3013 ext_phy_addr = ((params->ext_phy_config &
3014 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3015 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3016
3017 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3018 /* Make sure that the soft reset is off (expect for the 8072:
3019 * due to the lock, it will be done inside the specific
3020 * handling)
3021 */
3022 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3023 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3024 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
3025 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
3026 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
3027 /* Wait for soft reset to get cleared upto 1 sec */
3028 for (cnt = 0; cnt < 1000; cnt++) {
3029 bnx2x_cl45_read(bp, params->port,
3030 ext_phy_type,
3031 ext_phy_addr,
3032 MDIO_PMA_DEVAD,
3033 MDIO_PMA_REG_CTRL, &ctrl);
3034 if (!(ctrl & (1<<15)))
3035 break;
3036 msleep(1);
3037 }
3038 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
3039 ctrl, cnt);
3040 }
3041
3042 switch (ext_phy_type) {
3043 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003044 break;
3045
3046 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3047 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3048
3049 bnx2x_cl45_write(bp, params->port,
3050 ext_phy_type,
3051 ext_phy_addr,
3052 MDIO_PMA_DEVAD,
3053 MDIO_PMA_REG_MISC_CTRL,
3054 0x8288);
3055 bnx2x_cl45_write(bp, params->port,
3056 ext_phy_type,
3057 ext_phy_addr,
3058 MDIO_PMA_DEVAD,
3059 MDIO_PMA_REG_PHY_IDENTIFIER,
3060 0x7fbf);
3061 bnx2x_cl45_write(bp, params->port,
3062 ext_phy_type,
3063 ext_phy_addr,
3064 MDIO_PMA_DEVAD,
3065 MDIO_PMA_REG_CMU_PLL_BYPASS,
3066 0x0100);
3067 bnx2x_cl45_write(bp, params->port,
3068 ext_phy_type,
3069 ext_phy_addr,
3070 MDIO_WIS_DEVAD,
3071 MDIO_WIS_REG_LASI_CNTL, 0x1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003072
3073 bnx2x_save_bcm_spirom_ver(bp, params->port,
3074 ext_phy_type,
3075 ext_phy_addr,
3076 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003077 break;
3078
3079 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003080 /* Wait until fw is loaded */
3081 for (cnt = 0; cnt < 100; cnt++) {
3082 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3083 ext_phy_addr, MDIO_PMA_DEVAD,
3084 MDIO_PMA_REG_ROM_VER1, &val);
3085 if (val)
3086 break;
3087 msleep(10);
3088 }
3089 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized "
3090 "after %d ms\n", cnt);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003091 /* Force speed */
3092 /* First enable LASI */
3093 bnx2x_cl45_write(bp, params->port,
3094 ext_phy_type,
3095 ext_phy_addr,
3096 MDIO_PMA_DEVAD,
3097 MDIO_PMA_REG_RX_ALARM_CTRL,
3098 0x0400);
3099 bnx2x_cl45_write(bp, params->port,
3100 ext_phy_type,
3101 ext_phy_addr,
3102 MDIO_PMA_DEVAD,
3103 MDIO_PMA_REG_LASI_CTRL, 0x0004);
3104
3105 if (params->req_line_speed == SPEED_10000) {
3106 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
3107
3108 bnx2x_cl45_write(bp, params->port,
3109 ext_phy_type,
3110 ext_phy_addr,
3111 MDIO_PMA_DEVAD,
3112 MDIO_PMA_REG_DIGITAL_CTRL,
3113 0x400);
3114 } else {
3115 /* Force 1Gbps using autoneg with 1G
3116 advertisment */
3117
3118 /* Allow CL37 through CL73 */
3119 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3120 bnx2x_cl45_write(bp, params->port,
3121 ext_phy_type,
3122 ext_phy_addr,
3123 MDIO_AN_DEVAD,
3124 MDIO_AN_REG_CL37_CL73,
3125 0x040c);
3126
3127 /* Enable Full-Duplex advertisment on CL37 */
3128 bnx2x_cl45_write(bp, params->port,
3129 ext_phy_type,
3130 ext_phy_addr,
3131 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003132 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003133 0x0020);
3134 /* Enable CL37 AN */
3135 bnx2x_cl45_write(bp, params->port,
3136 ext_phy_type,
3137 ext_phy_addr,
3138 MDIO_AN_DEVAD,
3139 MDIO_AN_REG_CL37_AN,
3140 0x1000);
3141 /* 1G support */
3142 bnx2x_cl45_write(bp, params->port,
3143 ext_phy_type,
3144 ext_phy_addr,
3145 MDIO_AN_DEVAD,
3146 MDIO_AN_REG_ADV, (1<<5));
3147
3148 /* Enable clause 73 AN */
3149 bnx2x_cl45_write(bp, params->port,
3150 ext_phy_type,
3151 ext_phy_addr,
3152 MDIO_AN_DEVAD,
3153 MDIO_AN_REG_CTRL,
3154 0x1200);
3155
3156 }
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003157 bnx2x_save_bcm_spirom_ver(bp, params->port,
3158 ext_phy_type,
3159 ext_phy_addr,
3160 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003161 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003162 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3163 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3164 bnx2x_bcm8726_external_rom_boot(params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003165
Eilon Greenstein589abe32009-02-12 08:36:55 +00003166 /* Need to call module detected on initialization since
3167 the module detection triggered by actual module
3168 insertion might occur before driver is loaded, and when
3169 driver is loaded, it reset all registers, including the
3170 transmitter */
3171 bnx2x_sfp_module_detection(params);
3172 if (params->req_line_speed == SPEED_1000) {
3173 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3174 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3175 ext_phy_addr, MDIO_PMA_DEVAD,
3176 MDIO_PMA_REG_CTRL, 0x40);
3177 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3178 ext_phy_addr, MDIO_PMA_DEVAD,
3179 MDIO_PMA_REG_10G_CTRL2, 0xD);
3180 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3181 ext_phy_addr, MDIO_PMA_DEVAD,
3182 MDIO_PMA_REG_LASI_CTRL, 0x5);
3183 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3184 ext_phy_addr, MDIO_PMA_DEVAD,
3185 MDIO_PMA_REG_RX_ALARM_CTRL,
3186 0x400);
3187 } else if ((params->req_line_speed ==
3188 SPEED_AUTO_NEG) &&
3189 ((params->speed_cap_mask &
3190 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
3191 DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
3192 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3193 ext_phy_addr, MDIO_AN_DEVAD,
3194 MDIO_AN_REG_ADV, 0x20);
3195 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3196 ext_phy_addr, MDIO_AN_DEVAD,
3197 MDIO_AN_REG_CL37_CL73, 0x040c);
3198 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3199 ext_phy_addr, MDIO_AN_DEVAD,
3200 MDIO_AN_REG_CL37_FC_LD, 0x0020);
3201 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3202 ext_phy_addr, MDIO_AN_DEVAD,
3203 MDIO_AN_REG_CL37_AN, 0x1000);
3204 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3205 ext_phy_addr, MDIO_AN_DEVAD,
3206 MDIO_AN_REG_CTRL, 0x1200);
3207
3208 /* Enable RX-ALARM control to receive
3209 interrupt for 1G speed change */
3210 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3211 ext_phy_addr, MDIO_PMA_DEVAD,
3212 MDIO_PMA_REG_LASI_CTRL, 0x4);
3213 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3214 ext_phy_addr, MDIO_PMA_DEVAD,
3215 MDIO_PMA_REG_RX_ALARM_CTRL,
3216 0x400);
3217
3218 } else { /* Default 10G. Set only LASI control */
3219 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3220 ext_phy_addr, MDIO_PMA_DEVAD,
3221 MDIO_PMA_REG_LASI_CTRL, 1);
3222 }
3223 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003224 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3225 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3226 {
3227 u16 tmp1;
3228 u16 rx_alarm_ctrl_val;
3229 u16 lasi_ctrl_val;
3230 if (ext_phy_type ==
3231 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3232 rx_alarm_ctrl_val = 0x400;
3233 lasi_ctrl_val = 0x0004;
3234 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003235 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003236 lasi_ctrl_val = 0x0004;
3237 }
3238
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003239 /* enable LASI */
3240 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003241 ext_phy_type,
3242 ext_phy_addr,
3243 MDIO_PMA_DEVAD,
3244 MDIO_PMA_REG_RX_ALARM_CTRL,
3245 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003246
3247 bnx2x_cl45_write(bp, params->port,
3248 ext_phy_type,
3249 ext_phy_addr,
3250 MDIO_PMA_DEVAD,
3251 MDIO_PMA_REG_LASI_CTRL,
3252 lasi_ctrl_val);
3253
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003254 bnx2x_8073_set_pause_cl37(params, vars);
3255
3256 if (ext_phy_type ==
3257 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){
3258 bnx2x_bcm8072_external_rom_boot(params);
3259 } else {
3260
3261 /* In case of 8073 with long xaui lines,
3262 don't set the 8073 xaui low power*/
3263 bnx2x_bcm8073_set_xaui_low_power_mode(params);
3264 }
3265
3266 bnx2x_cl45_read(bp, params->port,
3267 ext_phy_type,
3268 ext_phy_addr,
3269 MDIO_PMA_DEVAD,
3270 0xca13,
3271 &tmp1);
3272
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003273 bnx2x_cl45_read(bp, params->port,
3274 ext_phy_type,
3275 ext_phy_addr,
3276 MDIO_PMA_DEVAD,
3277 MDIO_PMA_REG_RX_ALARM, &tmp1);
3278
3279 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
3280 "0x%x\n", tmp1);
3281
3282 /* If this is forced speed, set to KR or KX
3283 * (all other are not supported)
3284 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003285 if (params->loopback_mode == LOOPBACK_EXT) {
3286 bnx2x_bcm807x_force_10G(params);
3287 DP(NETIF_MSG_LINK,
3288 "Forced speed 10G on 807X\n");
3289 break;
3290 } else {
3291 bnx2x_cl45_write(bp, params->port,
3292 ext_phy_type, ext_phy_addr,
3293 MDIO_PMA_DEVAD,
3294 MDIO_PMA_REG_BCM_CTRL,
3295 0x0002);
3296 }
3297 if (params->req_line_speed != SPEED_AUTO_NEG) {
3298 if (params->req_line_speed == SPEED_10000) {
3299 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003300 } else if (params->req_line_speed ==
3301 SPEED_2500) {
3302 val = (1<<5);
3303 /* Note that 2.5G works only
3304 when used with 1G advertisment */
3305 } else
3306 val = (1<<5);
3307 } else {
3308
3309 val = 0;
3310 if (params->speed_cap_mask &
3311 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3312 val |= (1<<7);
3313
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003314 /* Note that 2.5G works only when
3315 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003316 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003317 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3318 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003319 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003320 DP(NETIF_MSG_LINK,
3321 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003322 }
3323
3324 bnx2x_cl45_write(bp, params->port,
3325 ext_phy_type,
3326 ext_phy_addr,
3327 MDIO_AN_DEVAD,
3328 MDIO_AN_REG_ADV, val);
3329
3330 if (ext_phy_type ==
3331 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003332
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003333 bnx2x_cl45_read(bp, params->port,
3334 ext_phy_type,
3335 ext_phy_addr,
3336 MDIO_AN_DEVAD,
3337 0x8329, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003338
3339 if (((params->speed_cap_mask &
3340 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3341 (params->req_line_speed ==
3342 SPEED_AUTO_NEG)) ||
3343 (params->req_line_speed ==
3344 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003345 u16 phy_ver;
3346 /* Allow 2.5G for A1 and above */
3347 bnx2x_cl45_read(bp, params->port,
3348 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
3349 ext_phy_addr,
3350 MDIO_PMA_DEVAD,
3351 0xc801, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003352 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003353 if (phy_ver > 0)
3354 tmp1 |= 1;
3355 else
3356 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003357 } else {
3358 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003359 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003360 }
3361
3362 bnx2x_cl45_write(bp, params->port,
3363 ext_phy_type,
3364 ext_phy_addr,
3365 MDIO_AN_DEVAD,
3366 0x8329, tmp1);
3367 }
3368
3369 /* Add support for CL37 (passive mode) II */
3370
3371 bnx2x_cl45_read(bp, params->port,
3372 ext_phy_type,
3373 ext_phy_addr,
3374 MDIO_AN_DEVAD,
3375 MDIO_AN_REG_CL37_FC_LD,
3376 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003377
3378 bnx2x_cl45_write(bp, params->port,
3379 ext_phy_type,
3380 ext_phy_addr,
3381 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003382 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
3383 ((params->req_duplex == DUPLEX_FULL) ?
3384 0x20 : 0x40)));
3385
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003386 /* Add support for CL37 (passive mode) III */
3387 bnx2x_cl45_write(bp, params->port,
3388 ext_phy_type,
3389 ext_phy_addr,
3390 MDIO_AN_DEVAD,
3391 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003392
3393 if (ext_phy_type ==
3394 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003395 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003396 BW and FEE main tap. Rest commands are executed
3397 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003398 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003399 if (bnx2x_8073_is_snr_needed(params))
3400 bnx2x_cl45_write(bp, params->port,
3401 ext_phy_type,
3402 ext_phy_addr,
3403 MDIO_PMA_DEVAD,
3404 MDIO_PMA_REG_EDC_FFE_MAIN,
3405 0xFB0C);
3406
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003407 /* Enable FEC (Forware Error Correction)
3408 Request in the AN */
3409 bnx2x_cl45_read(bp, params->port,
3410 ext_phy_type,
3411 ext_phy_addr,
3412 MDIO_AN_DEVAD,
3413 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003414
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003415 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003416
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003417 bnx2x_cl45_write(bp, params->port,
3418 ext_phy_type,
3419 ext_phy_addr,
3420 MDIO_AN_DEVAD,
3421 MDIO_AN_REG_ADV2, tmp1);
3422
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003423 }
3424
3425 bnx2x_ext_phy_set_pause(params, vars);
3426
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003427 /* Restart autoneg */
3428 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003429 bnx2x_cl45_write(bp, params->port,
3430 ext_phy_type,
3431 ext_phy_addr,
3432 MDIO_AN_DEVAD,
3433 MDIO_AN_REG_CTRL, 0x1200);
3434 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
3435 "Advertise 1G=%x, 10G=%x\n",
3436 ((val & (1<<5)) > 0),
3437 ((val & (1<<7)) > 0));
3438 break;
3439 }
3440 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003441 {
3442 u16 fw_ver1, fw_ver2;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003443 DP(NETIF_MSG_LINK,
3444 "Setting the SFX7101 LASI indication\n");
3445
3446 bnx2x_cl45_write(bp, params->port,
3447 ext_phy_type,
3448 ext_phy_addr,
3449 MDIO_PMA_DEVAD,
3450 MDIO_PMA_REG_LASI_CTRL, 0x1);
3451 DP(NETIF_MSG_LINK,
3452 "Setting the SFX7101 LED to blink on traffic\n");
3453 bnx2x_cl45_write(bp, params->port,
3454 ext_phy_type,
3455 ext_phy_addr,
3456 MDIO_PMA_DEVAD,
3457 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
3458
3459 bnx2x_ext_phy_set_pause(params, vars);
3460 /* Restart autoneg */
3461 bnx2x_cl45_read(bp, params->port,
3462 ext_phy_type,
3463 ext_phy_addr,
3464 MDIO_AN_DEVAD,
3465 MDIO_AN_REG_CTRL, &val);
3466 val |= 0x200;
3467 bnx2x_cl45_write(bp, params->port,
3468 ext_phy_type,
3469 ext_phy_addr,
3470 MDIO_AN_DEVAD,
3471 MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003472
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003473 /* Save spirom version */
3474 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3475 ext_phy_addr, MDIO_PMA_DEVAD,
3476 MDIO_PMA_REG_7101_VER1, &fw_ver1);
3477
3478 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3479 ext_phy_addr, MDIO_PMA_DEVAD,
3480 MDIO_PMA_REG_7101_VER2, &fw_ver2);
3481
3482 bnx2x_save_spirom_version(params->bp, params->port,
3483 params->shmem_base,
3484 (u32)(fw_ver1<<16 | fw_ver2));
3485
Eilon Greenstein28577182009-02-12 08:37:00 +00003486 break;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003487 }
Eilon Greenstein28577182009-02-12 08:37:00 +00003488 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
3489 DP(NETIF_MSG_LINK,
3490 "Setting the BCM8481 LASI control\n");
3491
3492 bnx2x_cl45_write(bp, params->port,
3493 ext_phy_type,
3494 ext_phy_addr,
3495 MDIO_PMA_DEVAD,
3496 MDIO_PMA_REG_LASI_CTRL, 0x1);
3497
3498 /* Restart autoneg */
3499 bnx2x_cl45_read(bp, params->port,
3500 ext_phy_type,
3501 ext_phy_addr,
3502 MDIO_AN_DEVAD,
3503 MDIO_AN_REG_CTRL, &val);
3504 val |= 0x200;
3505 bnx2x_cl45_write(bp, params->port,
3506 ext_phy_type,
3507 ext_phy_addr,
3508 MDIO_AN_DEVAD,
3509 MDIO_AN_REG_CTRL, val);
3510
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003511 bnx2x_save_bcm_spirom_ver(bp, params->port,
3512 ext_phy_type,
3513 ext_phy_addr,
3514 params->shmem_base);
3515
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003516 break;
3517 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
3518 DP(NETIF_MSG_LINK,
3519 "XGXS PHY Failure detected 0x%x\n",
3520 params->ext_phy_config);
3521 rc = -EINVAL;
3522 break;
3523 default:
3524 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3525 params->ext_phy_config);
3526 rc = -EINVAL;
3527 break;
3528 }
3529
3530 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003531
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003532 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3533 switch (ext_phy_type) {
3534 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3535 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3536 break;
3537
3538 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3539 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3540 break;
3541
3542 default:
3543 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
3544 params->ext_phy_config);
3545 break;
3546 }
3547 }
3548 return rc;
3549}
3550
3551
3552static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003553 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003554{
3555 struct bnx2x *bp = params->bp;
3556 u32 ext_phy_type;
3557 u8 ext_phy_addr;
3558 u16 val1 = 0, val2;
3559 u16 rx_sd, pcs_status;
3560 u8 ext_phy_link_up = 0;
3561 u8 port = params->port;
3562 if (vars->phy_flags & PHY_XGXS_FLAG) {
3563 ext_phy_addr = ((params->ext_phy_config &
3564 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3565 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3566
3567 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3568 switch (ext_phy_type) {
3569 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3570 DP(NETIF_MSG_LINK, "XGXS Direct\n");
3571 ext_phy_link_up = 1;
3572 break;
3573
3574 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3575 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3576 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3577 ext_phy_addr,
3578 MDIO_WIS_DEVAD,
3579 MDIO_WIS_REG_LASI_STATUS, &val1);
3580 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3581
3582 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3583 ext_phy_addr,
3584 MDIO_WIS_DEVAD,
3585 MDIO_WIS_REG_LASI_STATUS, &val1);
3586 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3587
3588 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3589 ext_phy_addr,
3590 MDIO_PMA_DEVAD,
3591 MDIO_PMA_REG_RX_SD, &rx_sd);
3592 DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
3593 ext_phy_link_up = (rx_sd & 0x1);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003594 if (ext_phy_link_up)
3595 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003596 break;
3597
3598 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00003599 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3600 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
3601 /* Clear RX Alarm*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003602 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3603 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00003604 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
3605 &val2);
3606 /* clear LASI indication*/
3607 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3608 ext_phy_addr,
3609 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
3610 &val1);
3611 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3612 ext_phy_addr,
3613 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
3614 &val2);
3615 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
3616 "0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003617
3618 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3619 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00003620 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
3621 &rx_sd);
3622 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3623 ext_phy_addr,
3624 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
3625 &pcs_status);
3626 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3627 ext_phy_addr,
3628 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
3629 &val2);
3630 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3631 ext_phy_addr,
3632 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
3633 &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003634
Eilon Greenstein589abe32009-02-12 08:36:55 +00003635 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003636 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
3637 rx_sd, pcs_status, val2);
3638 /* link is up if both bit 0 of pmd_rx_sd and
3639 * bit 0 of pcs_status are set, or if the autoneg bit
3640 1 is set
3641 */
3642 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
3643 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003644 if (ext_phy_link_up) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003645 if (ext_phy_type ==
3646 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
3647 /* If transmitter is disabled,
3648 ignore false link up indication */
3649 bnx2x_cl45_read(bp, params->port,
3650 ext_phy_type,
3651 ext_phy_addr,
3652 MDIO_PMA_DEVAD,
3653 MDIO_PMA_REG_PHY_IDENTIFIER,
3654 &val1);
3655 if (val1 & (1<<15)) {
3656 DP(NETIF_MSG_LINK, "Tx is "
3657 "disabled\n");
3658 ext_phy_link_up = 0;
3659 break;
3660 }
3661 }
3662
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003663 if (val2 & (1<<1))
3664 vars->line_speed = SPEED_1000;
3665 else
3666 vars->line_speed = SPEED_10000;
3667 }
3668
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003669 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003670 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3671 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3672 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003673 u16 link_status = 0;
3674 u16 an1000_status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003675 if (ext_phy_type ==
3676 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3677 bnx2x_cl45_read(bp, params->port,
3678 ext_phy_type,
3679 ext_phy_addr,
3680 MDIO_PCS_DEVAD,
3681 MDIO_PCS_REG_LASI_STATUS, &val1);
3682 bnx2x_cl45_read(bp, params->port,
3683 ext_phy_type,
3684 ext_phy_addr,
3685 MDIO_PCS_DEVAD,
3686 MDIO_PCS_REG_LASI_STATUS, &val2);
3687 DP(NETIF_MSG_LINK,
3688 "870x LASI status 0x%x->0x%x\n",
3689 val1, val2);
3690
3691 } else {
3692 /* In 8073, port1 is directed through emac0 and
3693 * port0 is directed through emac1
3694 */
3695 bnx2x_cl45_read(bp, params->port,
3696 ext_phy_type,
3697 ext_phy_addr,
3698 MDIO_PMA_DEVAD,
3699 MDIO_PMA_REG_LASI_STATUS, &val1);
3700
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003701 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003702 "8703 LASI status 0x%x\n",
3703 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003704 }
3705
3706 /* clear the interrupt LASI status register */
3707 bnx2x_cl45_read(bp, params->port,
3708 ext_phy_type,
3709 ext_phy_addr,
3710 MDIO_PCS_DEVAD,
3711 MDIO_PCS_REG_STATUS, &val2);
3712 bnx2x_cl45_read(bp, params->port,
3713 ext_phy_type,
3714 ext_phy_addr,
3715 MDIO_PCS_DEVAD,
3716 MDIO_PCS_REG_STATUS, &val1);
3717 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
3718 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003719 /* Clear MSG-OUT */
3720 bnx2x_cl45_read(bp, params->port,
3721 ext_phy_type,
3722 ext_phy_addr,
3723 MDIO_PMA_DEVAD,
3724 0xca13,
3725 &val1);
3726
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003727 /* Check the LASI */
3728 bnx2x_cl45_read(bp, params->port,
3729 ext_phy_type,
3730 ext_phy_addr,
3731 MDIO_PMA_DEVAD,
3732 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003733
3734 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3735
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003736 /* Check the link status */
3737 bnx2x_cl45_read(bp, params->port,
3738 ext_phy_type,
3739 ext_phy_addr,
3740 MDIO_PCS_DEVAD,
3741 MDIO_PCS_REG_STATUS, &val2);
3742 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3743
3744 bnx2x_cl45_read(bp, params->port,
3745 ext_phy_type,
3746 ext_phy_addr,
3747 MDIO_PMA_DEVAD,
3748 MDIO_PMA_REG_STATUS, &val2);
3749 bnx2x_cl45_read(bp, params->port,
3750 ext_phy_type,
3751 ext_phy_addr,
3752 MDIO_PMA_DEVAD,
3753 MDIO_PMA_REG_STATUS, &val1);
3754 ext_phy_link_up = ((val1 & 4) == 4);
3755 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3756 if (ext_phy_type ==
3757 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003758
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003759 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003760 ((params->req_line_speed !=
3761 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003762 if (bnx2x_bcm8073_xaui_wa(params)
3763 != 0) {
3764 ext_phy_link_up = 0;
3765 break;
3766 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003767 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003768 bnx2x_cl45_read(bp, params->port,
3769 ext_phy_type,
3770 ext_phy_addr,
3771 MDIO_AN_DEVAD,
3772 0x8304,
3773 &an1000_status);
3774 bnx2x_cl45_read(bp, params->port,
3775 ext_phy_type,
3776 ext_phy_addr,
3777 MDIO_AN_DEVAD,
3778 0x8304,
3779 &an1000_status);
3780
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003781 /* Check the link status on 1.1.2 */
3782 bnx2x_cl45_read(bp, params->port,
3783 ext_phy_type,
3784 ext_phy_addr,
3785 MDIO_PMA_DEVAD,
3786 MDIO_PMA_REG_STATUS, &val2);
3787 bnx2x_cl45_read(bp, params->port,
3788 ext_phy_type,
3789 ext_phy_addr,
3790 MDIO_PMA_DEVAD,
3791 MDIO_PMA_REG_STATUS, &val1);
3792 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3793 "an_link_status=0x%x\n",
3794 val2, val1, an1000_status);
3795
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003796 ext_phy_link_up = (((val1 & 4) == 4) ||
3797 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003798 if (ext_phy_link_up &&
3799 bnx2x_8073_is_snr_needed(params)) {
3800 /* The SNR will improve about 2dbby
3801 changing the BW and FEE main tap.*/
3802
3803 /* The 1st write to change FFE main
3804 tap is set before restart AN */
3805 /* Change PLL Bandwidth in EDC
3806 register */
3807 bnx2x_cl45_write(bp, port, ext_phy_type,
3808 ext_phy_addr,
3809 MDIO_PMA_DEVAD,
3810 MDIO_PMA_REG_PLL_BANDWIDTH,
3811 0x26BC);
3812
3813 /* Change CDR Bandwidth in EDC
3814 register */
3815 bnx2x_cl45_write(bp, port, ext_phy_type,
3816 ext_phy_addr,
3817 MDIO_PMA_DEVAD,
3818 MDIO_PMA_REG_CDR_BANDWIDTH,
3819 0x0333);
3820
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003821
3822 }
3823 bnx2x_cl45_read(bp, params->port,
3824 ext_phy_type,
3825 ext_phy_addr,
3826 MDIO_PMA_DEVAD,
3827 0xc820,
3828 &link_status);
3829
3830 /* Bits 0..2 --> speed detected,
3831 bits 13..15--> link is down */
3832 if ((link_status & (1<<2)) &&
3833 (!(link_status & (1<<15)))) {
3834 ext_phy_link_up = 1;
3835 vars->line_speed = SPEED_10000;
3836 DP(NETIF_MSG_LINK,
3837 "port %x: External link"
3838 " up in 10G\n", params->port);
3839 } else if ((link_status & (1<<1)) &&
3840 (!(link_status & (1<<14)))) {
3841 ext_phy_link_up = 1;
3842 vars->line_speed = SPEED_2500;
3843 DP(NETIF_MSG_LINK,
3844 "port %x: External link"
3845 " up in 2.5G\n", params->port);
3846 } else if ((link_status & (1<<0)) &&
3847 (!(link_status & (1<<13)))) {
3848 ext_phy_link_up = 1;
3849 vars->line_speed = SPEED_1000;
3850 DP(NETIF_MSG_LINK,
3851 "port %x: External link"
3852 " up in 1G\n", params->port);
3853 } else {
3854 ext_phy_link_up = 0;
3855 DP(NETIF_MSG_LINK,
3856 "port %x: External link"
3857 " is down\n", params->port);
3858 }
3859 } else {
3860 /* See if 1G link is up for the 8072 */
3861 bnx2x_cl45_read(bp, params->port,
3862 ext_phy_type,
3863 ext_phy_addr,
3864 MDIO_AN_DEVAD,
3865 0x8304,
3866 &an1000_status);
3867 bnx2x_cl45_read(bp, params->port,
3868 ext_phy_type,
3869 ext_phy_addr,
3870 MDIO_AN_DEVAD,
3871 0x8304,
3872 &an1000_status);
3873 if (an1000_status & (1<<1)) {
3874 ext_phy_link_up = 1;
3875 vars->line_speed = SPEED_1000;
3876 DP(NETIF_MSG_LINK,
3877 "port %x: External link"
3878 " up in 1G\n", params->port);
3879 } else if (ext_phy_link_up) {
3880 ext_phy_link_up = 1;
3881 vars->line_speed = SPEED_10000;
3882 DP(NETIF_MSG_LINK,
3883 "port %x: External link"
3884 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003885 }
3886 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003887
3888
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003889 break;
3890 }
3891 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3892 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3893 ext_phy_addr,
3894 MDIO_PMA_DEVAD,
3895 MDIO_PMA_REG_LASI_STATUS, &val2);
3896 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3897 ext_phy_addr,
3898 MDIO_PMA_DEVAD,
3899 MDIO_PMA_REG_LASI_STATUS, &val1);
3900 DP(NETIF_MSG_LINK,
3901 "10G-base-T LASI status 0x%x->0x%x\n",
3902 val2, val1);
3903 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3904 ext_phy_addr,
3905 MDIO_PMA_DEVAD,
3906 MDIO_PMA_REG_STATUS, &val2);
3907 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3908 ext_phy_addr,
3909 MDIO_PMA_DEVAD,
3910 MDIO_PMA_REG_STATUS, &val1);
3911 DP(NETIF_MSG_LINK,
3912 "10G-base-T PMA status 0x%x->0x%x\n",
3913 val2, val1);
3914 ext_phy_link_up = ((val1 & 4) == 4);
3915 /* if link is up
3916 * print the AN outcome of the SFX7101 PHY
3917 */
3918 if (ext_phy_link_up) {
3919 bnx2x_cl45_read(bp, params->port,
3920 ext_phy_type,
3921 ext_phy_addr,
3922 MDIO_AN_DEVAD,
3923 MDIO_AN_REG_MASTER_STATUS,
3924 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003925 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003926 DP(NETIF_MSG_LINK,
3927 "SFX7101 AN status 0x%x->Master=%x\n",
3928 val2,
3929 (val2 & (1<<14)));
3930 }
3931 break;
Eilon Greenstein28577182009-02-12 08:37:00 +00003932 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
3933 /* Clear LASI interrupt */
3934 bnx2x_cl45_read(bp, params->port,
3935 ext_phy_type,
3936 ext_phy_addr,
3937 MDIO_PMA_DEVAD,
3938 MDIO_PMA_REG_LASI_STATUS, &val1);
3939 DP(NETIF_MSG_LINK, "8481 LASI status reg = 0x%x\n",
3940 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003941
Eilon Greenstein28577182009-02-12 08:37:00 +00003942 /* Check 10G-BaseT link status */
3943 /* Check Global PMD signal ok */
3944 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3945 ext_phy_addr,
3946 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
3947 &rx_sd);
3948 /* Check PCS block lock */
3949 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3950 ext_phy_addr,
3951 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
3952 &pcs_status);
3953 DP(NETIF_MSG_LINK, "8481 1.a = 0x%x, 1.20 = 0x%x\n",
3954 rx_sd, pcs_status);
3955 if (rx_sd & pcs_status & 0x1) {
3956 vars->line_speed = SPEED_10000;
3957 ext_phy_link_up = 1;
3958 } else {
3959
3960 /* Check 1000-BaseT link status */
3961 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3962 ext_phy_addr,
3963 MDIO_AN_DEVAD, 0xFFE1,
3964 &val1);
3965
3966 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3967 ext_phy_addr,
3968 MDIO_AN_DEVAD, 0xFFE1,
3969 &val2);
3970 DP(NETIF_MSG_LINK, "8481 7.FFE1 ="
3971 "0x%x-->0x%x\n", val1, val2);
3972 if (val2 & (1<<2)) {
3973 vars->line_speed = SPEED_1000;
3974 ext_phy_link_up = 1;
3975 }
3976 }
3977
3978 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003979 default:
3980 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3981 params->ext_phy_config);
3982 ext_phy_link_up = 0;
3983 break;
3984 }
3985
3986 } else { /* SerDes */
3987 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3988 switch (ext_phy_type) {
3989 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3990 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3991 ext_phy_link_up = 1;
3992 break;
3993
3994 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3995 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3996 ext_phy_link_up = 1;
3997 break;
3998
3999 default:
4000 DP(NETIF_MSG_LINK,
4001 "BAD SerDes ext_phy_config 0x%x\n",
4002 params->ext_phy_config);
4003 ext_phy_link_up = 0;
4004 break;
4005 }
4006 }
4007
4008 return ext_phy_link_up;
4009}
4010
4011static void bnx2x_link_int_enable(struct link_params *params)
4012{
4013 u8 port = params->port;
4014 u32 ext_phy_type;
4015 u32 mask;
4016 struct bnx2x *bp = params->bp;
4017 /* setting the status to report on link up
4018 for either XGXS or SerDes */
4019
4020 if (params->switch_cfg == SWITCH_CFG_10G) {
4021 mask = (NIG_MASK_XGXS0_LINK10G |
4022 NIG_MASK_XGXS0_LINK_STATUS);
4023 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
4024 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4025 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
4026 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
4027 (ext_phy_type !=
4028 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
4029 mask |= NIG_MASK_MI_INT;
4030 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4031 }
4032
4033 } else { /* SerDes */
4034 mask = NIG_MASK_SERDES0_LINK_STATUS;
4035 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
4036 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4037 if ((ext_phy_type !=
4038 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
4039 (ext_phy_type !=
4040 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
4041 mask |= NIG_MASK_MI_INT;
4042 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4043 }
4044 }
4045 bnx2x_bits_en(bp,
4046 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4047 mask);
4048 DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port,
4049 (params->switch_cfg == SWITCH_CFG_10G),
4050 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
4051
4052 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
4053 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4054 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4055 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
4056 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4057 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4058 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4059}
4060
4061
4062/*
4063 * link management
4064 */
4065static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07004066 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004067{
4068 struct bnx2x *bp = params->bp;
4069 u8 port = params->port;
4070
4071 /* first reset all status
4072 * we assume only one line will be change at a time */
4073 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4074 (NIG_STATUS_XGXS0_LINK10G |
4075 NIG_STATUS_XGXS0_LINK_STATUS |
4076 NIG_STATUS_SERDES0_LINK_STATUS));
4077 if (vars->phy_link_up) {
4078 if (is_10g) {
4079 /* Disable the 10G link interrupt
4080 * by writing 1 to the status register
4081 */
4082 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
4083 bnx2x_bits_en(bp,
4084 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4085 NIG_STATUS_XGXS0_LINK10G);
4086
4087 } else if (params->switch_cfg == SWITCH_CFG_10G) {
4088 /* Disable the link interrupt
4089 * by writing 1 to the relevant lane
4090 * in the status register
4091 */
4092 u32 ser_lane = ((params->lane_config &
4093 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
4094 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
4095
4096 DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
4097 bnx2x_bits_en(bp,
4098 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4099 ((1 << ser_lane) <<
4100 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
4101
4102 } else { /* SerDes */
4103 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
4104 /* Disable the link interrupt
4105 * by writing 1 to the status register
4106 */
4107 bnx2x_bits_en(bp,
4108 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4109 NIG_STATUS_SERDES0_LINK_STATUS);
4110 }
4111
4112 } else { /* link_down */
4113 }
4114}
4115
4116static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
4117{
4118 u8 *str_ptr = str;
4119 u32 mask = 0xf0000000;
4120 u8 shift = 8*4;
4121 u8 digit;
4122 if (len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02004123 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004124 *str_ptr = '\0';
4125 return -EINVAL;
4126 }
4127 while (shift > 0) {
4128
4129 shift -= 4;
4130 digit = ((num & mask) >> shift);
4131 if (digit < 0xa)
4132 *str_ptr = digit + '0';
4133 else
4134 *str_ptr = digit - 0xa + 'a';
4135 str_ptr++;
4136 mask = mask >> 4;
4137 if (shift == 4*4) {
4138 *str_ptr = ':';
4139 str_ptr++;
4140 }
4141 }
4142 *str_ptr = '\0';
4143 return 0;
4144}
4145
4146
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004147static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr,
4148 u32 ext_phy_type)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004149{
4150 u32 cnt = 0;
4151 u16 ctrl = 0;
4152 /* Enable EMAC0 in to enable MDIO */
4153 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
4154 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
4155 msleep(5);
4156
4157 /* take ext phy out of reset */
4158 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004159 MISC_REGISTERS_GPIO_2,
4160 MISC_REGISTERS_GPIO_HIGH,
4161 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004162
4163 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004164 MISC_REGISTERS_GPIO_1,
4165 MISC_REGISTERS_GPIO_HIGH,
4166 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004167
4168 /* wait for 5ms */
4169 msleep(5);
4170
4171 for (cnt = 0; cnt < 1000; cnt++) {
4172 msleep(1);
4173 bnx2x_cl45_read(bp, port,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004174 ext_phy_type,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004175 ext_phy_addr,
4176 MDIO_PMA_DEVAD,
4177 MDIO_PMA_REG_CTRL,
4178 &ctrl);
4179 if (!(ctrl & (1<<15))) {
4180 DP(NETIF_MSG_LINK, "Reset completed\n\n");
4181 break;
4182 }
4183 }
4184}
4185
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004186static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004187{
4188 /* put sf to reset */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004189 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004190 MISC_REGISTERS_GPIO_1,
4191 MISC_REGISTERS_GPIO_LOW,
4192 port);
4193 bnx2x_set_gpio(bp,
4194 MISC_REGISTERS_GPIO_2,
4195 MISC_REGISTERS_GPIO_LOW,
4196 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004197}
4198
4199u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
4200 u8 *version, u16 len)
4201{
4202 struct bnx2x *bp = params->bp;
4203 u32 ext_phy_type = 0;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004204 u32 spirom_ver = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004205 u8 status = 0 ;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004206
4207 if (version == NULL || params == NULL)
4208 return -EINVAL;
4209
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004210 spirom_ver = REG_RD(bp, params->shmem_base +
4211 offsetof(struct shmem_region,
4212 port_mb[params->port].ext_phy_fw_version));
4213
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004214 /* reset the returned value to zero */
4215 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004216 switch (ext_phy_type) {
4217 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4218
4219 if (len < 5)
4220 return -EINVAL;
4221
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004222 version[0] = (spirom_ver & 0xFF);
4223 version[1] = (spirom_ver & 0xFF00) >> 8;
4224 version[2] = (spirom_ver & 0xFF0000) >> 16;
4225 version[3] = (spirom_ver & 0xFF000000) >> 24;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004226 version[4] = '\0';
4227
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004228 break;
4229 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4230 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004231 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4232 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00004233 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004234 status = bnx2x_format_ver(spirom_ver, version, len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004235 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004236 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4237 break;
4238
4239 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4240 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
4241 " type is FAILURE!\n");
4242 status = -EINVAL;
4243 break;
4244
4245 default:
4246 break;
4247 }
4248 return status;
4249}
4250
4251static void bnx2x_set_xgxs_loopback(struct link_params *params,
4252 struct link_vars *vars,
4253 u8 is_10g)
4254{
4255 u8 port = params->port;
4256 struct bnx2x *bp = params->bp;
4257
4258 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07004259 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004260
4261 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
4262
4263 /* change the uni_phy_addr in the nig */
4264 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
4265 port*0x18));
4266
4267 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
4268
4269 bnx2x_cl45_write(bp, port, 0,
4270 params->phy_addr,
4271 5,
4272 (MDIO_REG_BANK_AER_BLOCK +
4273 (MDIO_AER_BLOCK_AER_REG & 0xf)),
4274 0x2800);
4275
4276 bnx2x_cl45_write(bp, port, 0,
4277 params->phy_addr,
4278 5,
4279 (MDIO_REG_BANK_CL73_IEEEB0 +
4280 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
4281 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00004282 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004283 /* set aer mmd back */
4284 bnx2x_set_aer_mmd(params, vars);
4285
4286 /* and md_devad */
4287 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
4288 md_devad);
4289
4290 } else {
4291 u16 mii_control;
4292
4293 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
4294
4295 CL45_RD_OVER_CL22(bp, port,
4296 params->phy_addr,
4297 MDIO_REG_BANK_COMBO_IEEE0,
4298 MDIO_COMBO_IEEE0_MII_CONTROL,
4299 &mii_control);
4300
4301 CL45_WR_OVER_CL22(bp, port,
4302 params->phy_addr,
4303 MDIO_REG_BANK_COMBO_IEEE0,
4304 MDIO_COMBO_IEEE0_MII_CONTROL,
4305 (mii_control |
4306 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
4307 }
4308}
4309
4310
4311static void bnx2x_ext_phy_loopback(struct link_params *params)
4312{
4313 struct bnx2x *bp = params->bp;
4314 u8 ext_phy_addr;
4315 u32 ext_phy_type;
4316
4317 if (params->switch_cfg == SWITCH_CFG_10G) {
4318 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4319 /* CL37 Autoneg Enabled */
4320 ext_phy_addr = ((params->ext_phy_config &
4321 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4322 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4323 switch (ext_phy_type) {
4324 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4325 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
4326 DP(NETIF_MSG_LINK,
4327 "ext_phy_loopback: We should not get here\n");
4328 break;
4329 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4330 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
4331 break;
4332 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
4333 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
4334 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00004335 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4336 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4337 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4338 ext_phy_addr,
4339 MDIO_PMA_DEVAD,
4340 MDIO_PMA_REG_CTRL,
4341 0x0001);
4342 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004343 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4344 /* SFX7101_XGXS_TEST1 */
4345 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4346 ext_phy_addr,
4347 MDIO_XS_DEVAD,
4348 MDIO_XS_SFX7101_XGXS_TEST1,
4349 0x100);
4350 DP(NETIF_MSG_LINK,
4351 "ext_phy_loopback: set ext phy loopback\n");
4352 break;
4353 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4354
4355 break;
4356 } /* switch external PHY type */
4357 } else {
4358 /* serdes */
4359 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4360 ext_phy_addr = (params->ext_phy_config &
4361 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
4362 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
4363 }
4364}
4365
4366
4367/*
4368 *------------------------------------------------------------------------
4369 * bnx2x_override_led_value -
4370 *
4371 * Override the led value of the requsted led
4372 *
4373 *------------------------------------------------------------------------
4374 */
4375u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
4376 u32 led_idx, u32 value)
4377{
4378 u32 reg_val;
4379
4380 /* If port 0 then use EMAC0, else use EMAC1*/
4381 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
4382
4383 DP(NETIF_MSG_LINK,
4384 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
4385 port, led_idx, value);
4386
4387 switch (led_idx) {
4388 case 0: /* 10MB led */
4389 /* Read the current value of the LED register in
4390 the EMAC block */
4391 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4392 /* Set the OVERRIDE bit to 1 */
4393 reg_val |= EMAC_LED_OVERRIDE;
4394 /* If value is 1, set the 10M_OVERRIDE bit,
4395 otherwise reset it.*/
4396 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
4397 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
4398 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4399 break;
4400 case 1: /*100MB led */
4401 /*Read the current value of the LED register in
4402 the EMAC block */
4403 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4404 /* Set the OVERRIDE bit to 1 */
4405 reg_val |= EMAC_LED_OVERRIDE;
4406 /* If value is 1, set the 100M_OVERRIDE bit,
4407 otherwise reset it.*/
4408 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
4409 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
4410 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4411 break;
4412 case 2: /* 1000MB led */
4413 /* Read the current value of the LED register in the
4414 EMAC block */
4415 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4416 /* Set the OVERRIDE bit to 1 */
4417 reg_val |= EMAC_LED_OVERRIDE;
4418 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
4419 reset it. */
4420 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
4421 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
4422 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4423 break;
4424 case 3: /* 2500MB led */
4425 /* Read the current value of the LED register in the
4426 EMAC block*/
4427 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4428 /* Set the OVERRIDE bit to 1 */
4429 reg_val |= EMAC_LED_OVERRIDE;
4430 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
4431 reset it.*/
4432 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
4433 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
4434 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4435 break;
4436 case 4: /*10G led */
4437 if (port == 0) {
4438 REG_WR(bp, NIG_REG_LED_10G_P0,
4439 value);
4440 } else {
4441 REG_WR(bp, NIG_REG_LED_10G_P1,
4442 value);
4443 }
4444 break;
4445 case 5: /* TRAFFIC led */
4446 /* Find if the traffic control is via BMAC or EMAC */
4447 if (port == 0)
4448 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
4449 else
4450 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
4451
4452 /* Override the traffic led in the EMAC:*/
4453 if (reg_val == 1) {
4454 /* Read the current value of the LED register in
4455 the EMAC block */
4456 reg_val = REG_RD(bp, emac_base +
4457 EMAC_REG_EMAC_LED);
4458 /* Set the TRAFFIC_OVERRIDE bit to 1 */
4459 reg_val |= EMAC_LED_OVERRIDE;
4460 /* If value is 1, set the TRAFFIC bit, otherwise
4461 reset it.*/
4462 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
4463 (reg_val & ~EMAC_LED_TRAFFIC);
4464 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4465 } else { /* Override the traffic led in the BMAC: */
4466 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4467 + port*4, 1);
4468 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
4469 value);
4470 }
4471 break;
4472 default:
4473 DP(NETIF_MSG_LINK,
4474 "bnx2x_override_led_value() unknown led index %d "
4475 "(should be 0-5)\n", led_idx);
4476 return -EINVAL;
4477 }
4478
4479 return 0;
4480}
4481
4482
4483u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
4484 u16 hw_led_mode, u32 chip_id)
4485{
4486 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004487 u32 tmp;
4488 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004489 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
4490 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
4491 speed, hw_led_mode);
4492 switch (mode) {
4493 case LED_MODE_OFF:
4494 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
4495 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4496 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004497
4498 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004499 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004500 break;
4501
4502 case LED_MODE_OPER:
4503 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
4504 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
4505 port*4, 0);
4506 /* Set blinking rate to ~15.9Hz */
4507 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
4508 LED_BLINK_RATE_VAL);
4509 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
4510 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004511 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004512 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004513 (tmp & (~EMAC_LED_OVERRIDE)));
4514
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004515 if (!CHIP_IS_E1H(bp) &&
4516 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004517 (speed == SPEED_1000) ||
4518 (speed == SPEED_100) ||
4519 (speed == SPEED_10))) {
4520 /* On Everest 1 Ax chip versions for speeds less than
4521 10G LED scheme is different */
4522 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4523 + port*4, 1);
4524 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
4525 port*4, 0);
4526 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
4527 port*4, 1);
4528 }
4529 break;
4530
4531 default:
4532 rc = -EINVAL;
4533 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
4534 mode);
4535 break;
4536 }
4537 return rc;
4538
4539}
4540
4541u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
4542{
4543 struct bnx2x *bp = params->bp;
4544 u16 gp_status = 0;
4545
4546 CL45_RD_OVER_CL22(bp, params->port,
4547 params->phy_addr,
4548 MDIO_REG_BANK_GP_STATUS,
4549 MDIO_GP_STATUS_TOP_AN_STATUS1,
4550 &gp_status);
4551 /* link is up only if both local phy and external phy are up */
4552 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
4553 bnx2x_ext_phy_is_link_up(params, vars))
4554 return 0;
4555
4556 return -ESRCH;
4557}
4558
4559static u8 bnx2x_link_initialize(struct link_params *params,
4560 struct link_vars *vars)
4561{
4562 struct bnx2x *bp = params->bp;
4563 u8 port = params->port;
4564 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004565 u8 non_ext_phy;
4566 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004567 /* Activate the external PHY */
4568 bnx2x_ext_phy_reset(params, vars);
4569
4570 bnx2x_set_aer_mmd(params, vars);
4571
4572 if (vars->phy_flags & PHY_XGXS_FLAG)
4573 bnx2x_set_master_ln(params);
4574
4575 rc = bnx2x_reset_unicore(params);
4576 /* reset the SerDes and wait for reset bit return low */
4577 if (rc != 0)
4578 return rc;
4579
4580 bnx2x_set_aer_mmd(params, vars);
4581
4582 /* setting the masterLn_def again after the reset */
4583 if (vars->phy_flags & PHY_XGXS_FLAG) {
4584 bnx2x_set_master_ln(params);
4585 bnx2x_set_swap_lanes(params);
4586 }
4587
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004588 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00004589 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004590 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00004591 (params->req_line_speed == SPEED_10))) ||
4592 (!params->req_line_speed &&
4593 (params->speed_cap_mask >=
4594 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
4595 (params->speed_cap_mask <
4596 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
4597 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004598 vars->phy_flags |= PHY_SGMII_FLAG;
4599 } else {
4600 vars->phy_flags &= ~PHY_SGMII_FLAG;
4601 }
4602 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004603 /* In case of external phy existance, the line speed would be the
4604 line speed linked up by the external phy. In case it is direct only,
4605 then the line_speed during initialization will be equal to the
4606 req_line_speed*/
4607 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004608
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004609 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004610
4611 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004612 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
4613 (params->loopback_mode == LOOPBACK_XGXS_10) ||
4614 (params->loopback_mode == LOOPBACK_EXT_PHY));
4615
4616 if (non_ext_phy ||
Eilon Greenstein589abe32009-02-12 08:36:55 +00004617 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Eilon Greenstein28577182009-02-12 08:37:00 +00004618 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
4619 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004620 if (params->req_line_speed == SPEED_AUTO_NEG)
4621 bnx2x_set_parallel_detection(params, vars->phy_flags);
4622 bnx2x_init_internal_phy(params, vars);
4623 }
4624
4625 if (!non_ext_phy)
4626 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004627
4628 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004629 (NIG_STATUS_XGXS0_LINK10G |
4630 NIG_STATUS_XGXS0_LINK_STATUS |
4631 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004632
4633 return rc;
4634
4635}
4636
4637
4638u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
4639{
4640 struct bnx2x *bp = params->bp;
4641
4642 u32 val;
Eilon Greenstein3196a882008-08-13 15:58:49 -07004643 DP(NETIF_MSG_LINK, "Phy Initialization started \n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004644 DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
4645 params->req_line_speed, params->req_flow_ctrl);
4646 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004647 vars->phy_link_up = 0;
4648 vars->link_up = 0;
4649 vars->line_speed = 0;
4650 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004651 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004652 vars->mac_type = MAC_TYPE_NONE;
4653
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004654 if (params->switch_cfg == SWITCH_CFG_1G)
4655 vars->phy_flags = PHY_SERDES_FLAG;
4656 else
4657 vars->phy_flags = PHY_XGXS_FLAG;
4658
Eilon Greenstein3196a882008-08-13 15:58:49 -07004659
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004660 /* disable attentions */
4661 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
4662 (NIG_MASK_XGXS0_LINK_STATUS |
4663 NIG_MASK_XGXS0_LINK10G |
4664 NIG_MASK_SERDES0_LINK_STATUS |
4665 NIG_MASK_MI_INT));
4666
4667 bnx2x_emac_init(params, vars);
4668
4669 if (CHIP_REV_IS_FPGA(bp)) {
4670 vars->link_up = 1;
4671 vars->line_speed = SPEED_10000;
4672 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004673 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004674 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004675 /* enable on E1.5 FPGA */
4676 if (CHIP_IS_E1H(bp)) {
4677 vars->flow_ctrl |=
David S. Millerc0700f92008-12-16 23:53:20 -08004678 (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004679 vars->link_status |=
4680 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
4681 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
4682 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004683
4684 bnx2x_emac_enable(params, vars, 0);
4685 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4686 /* disable drain */
4687 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4688 + params->port*4, 0);
4689
4690 /* update shared memory */
4691 bnx2x_update_mng(params, vars->link_status);
4692
4693 return 0;
4694
4695 } else
4696 if (CHIP_REV_IS_EMUL(bp)) {
4697
4698 vars->link_up = 1;
4699 vars->line_speed = SPEED_10000;
4700 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004701 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004702 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
4703
4704 bnx2x_bmac_enable(params, vars, 0);
4705
4706 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4707 /* Disable drain */
4708 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4709 + params->port*4, 0);
4710
4711 /* update shared memory */
4712 bnx2x_update_mng(params, vars->link_status);
4713
4714 return 0;
4715
4716 } else
4717 if (params->loopback_mode == LOOPBACK_BMAC) {
4718 vars->link_up = 1;
4719 vars->line_speed = SPEED_10000;
4720 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004721 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004722 vars->mac_type = MAC_TYPE_BMAC;
4723
4724 vars->phy_flags = PHY_XGXS_FLAG;
4725
4726 bnx2x_phy_deassert(params, vars->phy_flags);
4727 /* set bmac loopback */
4728 bnx2x_bmac_enable(params, vars, 1);
4729
4730 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4731 params->port*4, 0);
4732 } else if (params->loopback_mode == LOOPBACK_EMAC) {
4733 vars->link_up = 1;
4734 vars->line_speed = SPEED_1000;
4735 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004736 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004737 vars->mac_type = MAC_TYPE_EMAC;
4738
4739 vars->phy_flags = PHY_XGXS_FLAG;
4740
4741 bnx2x_phy_deassert(params, vars->phy_flags);
4742 /* set bmac loopback */
4743 bnx2x_emac_enable(params, vars, 1);
4744 bnx2x_emac_program(params, vars->line_speed,
4745 vars->duplex);
4746 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4747 params->port*4, 0);
4748 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
4749 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
4750 vars->link_up = 1;
4751 vars->line_speed = SPEED_10000;
4752 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004753 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004754
4755 vars->phy_flags = PHY_XGXS_FLAG;
4756
4757 val = REG_RD(bp,
4758 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4759 params->port*0x18);
4760 params->phy_addr = (u8)val;
4761
4762 bnx2x_phy_deassert(params, vars->phy_flags);
4763 bnx2x_link_initialize(params, vars);
4764
4765 vars->mac_type = MAC_TYPE_BMAC;
4766
4767 bnx2x_bmac_enable(params, vars, 0);
4768
4769 if (params->loopback_mode == LOOPBACK_XGXS_10) {
4770 /* set 10G XGXS loopback */
4771 bnx2x_set_xgxs_loopback(params, vars, 1);
4772 } else {
4773 /* set external phy loopback */
4774 bnx2x_ext_phy_loopback(params);
4775 }
4776 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4777 params->port*4, 0);
4778 } else
4779 /* No loopback */
4780 {
4781
4782 bnx2x_phy_deassert(params, vars->phy_flags);
4783 switch (params->switch_cfg) {
4784 case SWITCH_CFG_1G:
4785 vars->phy_flags |= PHY_SERDES_FLAG;
4786 if ((params->ext_phy_config &
4787 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
4788 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
4789 vars->phy_flags |=
4790 PHY_SGMII_FLAG;
4791 }
4792
4793 val = REG_RD(bp,
4794 NIG_REG_SERDES0_CTRL_PHY_ADDR+
4795 params->port*0x10);
4796
4797 params->phy_addr = (u8)val;
4798
4799 break;
4800 case SWITCH_CFG_10G:
4801 vars->phy_flags |= PHY_XGXS_FLAG;
4802 val = REG_RD(bp,
4803 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4804 params->port*0x18);
4805 params->phy_addr = (u8)val;
4806
4807 break;
4808 default:
4809 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
4810 return -EINVAL;
4811 break;
4812 }
4813
4814 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004815 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004816 bnx2x_link_int_enable(params);
4817 }
4818 return 0;
4819}
4820
Eilon Greenstein589abe32009-02-12 08:36:55 +00004821static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
4822{
4823 DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
4824
4825 /* Set serial boot control for external load */
4826 bnx2x_cl45_write(bp, port,
4827 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
4828 MDIO_PMA_DEVAD,
4829 MDIO_PMA_REG_GEN_CTRL, 0x0001);
4830
4831 /* Disable Transmitter */
4832 bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
4833
4834}
4835
4836u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
4837 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004838{
4839
4840 struct bnx2x *bp = params->bp;
4841 u32 ext_phy_config = params->ext_phy_config;
4842 u16 hw_led_mode = params->hw_led_mode;
4843 u32 chip_id = params->chip_id;
4844 u8 port = params->port;
4845 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4846 /* disable attentions */
4847
4848 vars->link_status = 0;
4849 bnx2x_update_mng(params, vars->link_status);
4850 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4851 (NIG_MASK_XGXS0_LINK_STATUS |
4852 NIG_MASK_XGXS0_LINK10G |
4853 NIG_MASK_SERDES0_LINK_STATUS |
4854 NIG_MASK_MI_INT));
4855
4856 /* activate nig drain */
4857 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4858
4859 /* disable nig egress interface */
4860 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4861 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4862
4863 /* Stop BigMac rx */
4864 bnx2x_bmac_rx_disable(bp, port);
4865
4866 /* disable emac */
4867 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4868
4869 msleep(10);
4870 /* The PHY reset is controled by GPIO 1
4871 * Hold it as vars low
4872 */
4873 /* clear link led */
4874 bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
Eilon Greenstein589abe32009-02-12 08:36:55 +00004875 if (reset_ext_phy) {
4876 switch (ext_phy_type) {
4877 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4878 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4879 break;
4880 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4881 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
4882 "low power mode\n",
4883 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004884 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004885 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4886 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00004887 break;
4888 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4889 {
4890 u8 ext_phy_addr = ((params->ext_phy_config &
4891 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4892 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4893 /* Set soft reset */
4894 bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
4895 break;
4896 }
4897 default:
4898 /* HW reset */
4899 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4900 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4901 port);
4902 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4903 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4904 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004905 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004906 }
4907 }
4908 /* reset the SerDes/XGXS */
4909 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
4910 (0x1ff << (port*16)));
4911
4912 /* reset BigMac */
4913 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
4914 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4915
4916 /* disable nig ingress interface */
4917 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
4918 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
4919 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4920 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4921 vars->link_up = 0;
4922 return 0;
4923}
4924
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004925static u8 bnx2x_update_link_down(struct link_params *params,
4926 struct link_vars *vars)
4927{
4928 struct bnx2x *bp = params->bp;
4929 u8 port = params->port;
4930 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
4931 bnx2x_set_led(bp, port, LED_MODE_OFF,
4932 0, params->hw_led_mode,
4933 params->chip_id);
4934
4935 /* indicate no mac active */
4936 vars->mac_type = MAC_TYPE_NONE;
4937
4938 /* update shared memory */
4939 vars->link_status = 0;
4940 vars->line_speed = 0;
4941 bnx2x_update_mng(params, vars->link_status);
4942
4943 /* activate nig drain */
4944 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4945
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004946 /* disable emac */
4947 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4948
4949 msleep(10);
4950
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004951 /* reset BigMac */
4952 bnx2x_bmac_rx_disable(bp, params->port);
4953 REG_WR(bp, GRCBASE_MISC +
4954 MISC_REGISTERS_RESET_REG_2_CLEAR,
4955 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4956 return 0;
4957}
4958
4959static u8 bnx2x_update_link_up(struct link_params *params,
4960 struct link_vars *vars,
4961 u8 link_10g, u32 gp_status)
4962{
4963 struct bnx2x *bp = params->bp;
4964 u8 port = params->port;
4965 u8 rc = 0;
4966 vars->link_status |= LINK_STATUS_LINK_UP;
4967 if (link_10g) {
4968 bnx2x_bmac_enable(params, vars, 0);
4969 bnx2x_set_led(bp, port, LED_MODE_OPER,
4970 SPEED_10000, params->hw_led_mode,
4971 params->chip_id);
4972
4973 } else {
4974 bnx2x_emac_enable(params, vars, 0);
4975 rc = bnx2x_emac_program(params, vars->line_speed,
4976 vars->duplex);
4977
4978 /* AN complete? */
4979 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
4980 if (!(vars->phy_flags &
4981 PHY_SGMII_FLAG))
4982 bnx2x_set_sgmii_tx_driver(params);
4983 }
4984 }
4985
4986 /* PBF - link up */
4987 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
4988 vars->line_speed);
4989
4990 /* disable drain */
4991 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
4992
4993 /* update shared memory */
4994 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004995 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004996 return rc;
4997}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004998/* This function should called upon link interrupt */
4999/* In case vars->link_up, driver needs to
5000 1. Update the pbf
5001 2. Disable drain
5002 3. Update the shared memory
5003 4. Indicate link up
5004 5. Set LEDs
5005 Otherwise,
5006 1. Update shared memory
5007 2. Reset BigMac
5008 3. Report link down
5009 4. Unset LEDs
5010*/
5011u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
5012{
5013 struct bnx2x *bp = params->bp;
5014 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005015 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005016 u8 link_10g;
5017 u8 ext_phy_link_up, rc = 0;
5018 u32 ext_phy_type;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005019
5020 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
5021 port,
5022 (vars->phy_flags & PHY_XGXS_FLAG),
5023 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
5024
5025 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
5026 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5027 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
5028 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
5029
5030 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5031 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5032 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5033
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005034 /* disable emac */
5035 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5036
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005037 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005038
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005039 /* Check external link change only for non-direct */
5040 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
5041
5042 /* Read gp_status */
5043 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
5044 MDIO_REG_BANK_GP_STATUS,
5045 MDIO_GP_STATUS_TOP_AN_STATUS1,
5046 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005047
5048 rc = bnx2x_link_settings_status(params, vars, gp_status);
5049 if (rc != 0)
5050 return rc;
5051
5052 /* anything 10 and over uses the bmac */
5053 link_10g = ((vars->line_speed == SPEED_10000) ||
5054 (vars->line_speed == SPEED_12000) ||
5055 (vars->line_speed == SPEED_12500) ||
5056 (vars->line_speed == SPEED_13000) ||
5057 (vars->line_speed == SPEED_15000) ||
5058 (vars->line_speed == SPEED_16000));
5059
5060 bnx2x_link_int_ack(params, vars, link_10g);
5061
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005062 /* In case external phy link is up, and internal link is down
5063 ( not initialized yet probably after link initialization, it needs
5064 to be initialized.
5065 Note that after link down-up as result of cable plug,
5066 the xgxs link would probably become up again without the need to
5067 initialize it*/
5068
5069 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
5070 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
Eilon Greenstein589abe32009-02-12 08:36:55 +00005071 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005072 (ext_phy_link_up && !vars->phy_link_up))
5073 bnx2x_init_internal_phy(params, vars);
5074
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005075 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005076 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005077
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005078 if (vars->link_up)
5079 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
5080 else
5081 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005082
5083 return rc;
5084}
5085
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005086static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5087{
5088 u8 ext_phy_addr[PORT_MAX];
5089 u16 val;
5090 s8 port;
5091
5092 /* PART1 - Reset both phys */
5093 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5094 /* Extract the ext phy address for the port */
5095 u32 ext_phy_config = REG_RD(bp, shmem_base +
5096 offsetof(struct shmem_region,
5097 dev_info.port_hw_config[port].external_phy_config));
5098
5099 /* disable attentions */
5100 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5101 (NIG_MASK_XGXS0_LINK_STATUS |
5102 NIG_MASK_XGXS0_LINK10G |
5103 NIG_MASK_SERDES0_LINK_STATUS |
5104 NIG_MASK_MI_INT));
5105
5106 ext_phy_addr[port] =
5107 ((ext_phy_config &
5108 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5109 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5110
5111 /* Need to take the phy out of low power mode in order
5112 to write to access its registers */
5113 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5114 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
5115
5116 /* Reset the phy */
5117 bnx2x_cl45_write(bp, port,
5118 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5119 ext_phy_addr[port],
5120 MDIO_PMA_DEVAD,
5121 MDIO_PMA_REG_CTRL,
5122 1<<15);
5123 }
5124
5125 /* Add delay of 150ms after reset */
5126 msleep(150);
5127
5128 /* PART2 - Download firmware to both phys */
5129 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5130 u16 fw_ver1;
5131
5132 bnx2x_bcm8073_external_rom_boot(bp, port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005133 ext_phy_addr[port], shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005134
5135 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5136 ext_phy_addr[port],
5137 MDIO_PMA_DEVAD,
5138 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00005139 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005140 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00005141 "bnx2x_8073_common_init_phy port %x:"
5142 "Download failed. fw version = 0x%x\n",
5143 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005144 return -EINVAL;
5145 }
5146
5147 /* Only set bit 10 = 1 (Tx power down) */
5148 bnx2x_cl45_read(bp, port,
5149 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5150 ext_phy_addr[port],
5151 MDIO_PMA_DEVAD,
5152 MDIO_PMA_REG_TX_POWER_DOWN, &val);
5153
5154 /* Phase1 of TX_POWER_DOWN reset */
5155 bnx2x_cl45_write(bp, port,
5156 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5157 ext_phy_addr[port],
5158 MDIO_PMA_DEVAD,
5159 MDIO_PMA_REG_TX_POWER_DOWN,
5160 (val | 1<<10));
5161 }
5162
5163 /* Toggle Transmitter: Power down and then up with 600ms
5164 delay between */
5165 msleep(600);
5166
5167 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
5168 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5169 /* Phase2 of POWER_DOWN_RESET*/
5170 /* Release bit 10 (Release Tx power down) */
5171 bnx2x_cl45_read(bp, port,
5172 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5173 ext_phy_addr[port],
5174 MDIO_PMA_DEVAD,
5175 MDIO_PMA_REG_TX_POWER_DOWN, &val);
5176
5177 bnx2x_cl45_write(bp, port,
5178 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5179 ext_phy_addr[port],
5180 MDIO_PMA_DEVAD,
5181 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
5182 msleep(15);
5183
5184 /* Read modify write the SPI-ROM version select register */
5185 bnx2x_cl45_read(bp, port,
5186 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5187 ext_phy_addr[port],
5188 MDIO_PMA_DEVAD,
5189 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
5190 bnx2x_cl45_write(bp, port,
5191 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5192 ext_phy_addr[port],
5193 MDIO_PMA_DEVAD,
5194 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
5195
5196 /* set GPIO2 back to LOW */
5197 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5198 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
5199 }
5200 return 0;
5201
5202}
5203
Eilon Greenstein589abe32009-02-12 08:36:55 +00005204
5205static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5206{
5207 u8 ext_phy_addr;
5208 u32 val;
5209 s8 port;
5210 /* Use port1 because of the static port-swap */
5211 /* Enable the module detection interrupt */
5212 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
5213 val |= ((1<<MISC_REGISTERS_GPIO_3)|
5214 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
5215 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
5216
5217 bnx2x_hw_reset(bp, 1);
5218 msleep(5);
5219 for (port = 0; port < PORT_MAX; port++) {
5220 /* Extract the ext phy address for the port */
5221 u32 ext_phy_config = REG_RD(bp, shmem_base +
5222 offsetof(struct shmem_region,
5223 dev_info.port_hw_config[port].external_phy_config));
5224
5225 ext_phy_addr =
5226 ((ext_phy_config &
5227 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5228 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5229 DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
5230 ext_phy_addr);
5231
5232 bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
5233
5234 /* Set fault module detected LED on */
5235 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5236 MISC_REGISTERS_GPIO_HIGH,
5237 port);
5238 }
5239
5240 return 0;
5241}
5242
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005243u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5244{
5245 u8 rc = 0;
5246 u32 ext_phy_type;
5247
5248 DP(NETIF_MSG_LINK, "bnx2x_common_init_phy\n");
5249
5250 /* Read the ext_phy_type for arbitrary port(0) */
5251 ext_phy_type = XGXS_EXT_PHY_TYPE(
5252 REG_RD(bp, shmem_base +
5253 offsetof(struct shmem_region,
5254 dev_info.port_hw_config[0].external_phy_config)));
5255
5256 switch (ext_phy_type) {
5257 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
5258 {
5259 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
5260 break;
5261 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00005262 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5263 /* GPIO1 affects both ports, so there's need to pull
5264 it for single port alone */
5265 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
5266
5267 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005268 default:
5269 DP(NETIF_MSG_LINK,
5270 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
5271 ext_phy_type);
5272 break;
5273 }
5274
5275 return rc;
5276}
5277
5278
5279
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005280static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
5281{
5282 u16 val, cnt;
5283
5284 bnx2x_cl45_read(bp, port,
5285 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5286 phy_addr,
5287 MDIO_PMA_DEVAD,
5288 MDIO_PMA_REG_7101_RESET, &val);
5289
5290 for (cnt = 0; cnt < 10; cnt++) {
5291 msleep(50);
5292 /* Writes a self-clearing reset */
5293 bnx2x_cl45_write(bp, port,
5294 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5295 phy_addr,
5296 MDIO_PMA_DEVAD,
5297 MDIO_PMA_REG_7101_RESET,
5298 (val | (1<<15)));
5299 /* Wait for clear */
5300 bnx2x_cl45_read(bp, port,
5301 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5302 phy_addr,
5303 MDIO_PMA_DEVAD,
5304 MDIO_PMA_REG_7101_RESET, &val);
5305
5306 if ((val & (1<<15)) == 0)
5307 break;
5308 }
5309}
5310#define RESERVED_SIZE 256
5311/* max application is 160K bytes - data at end of RAM */
Eilon Greenstein6378c022008-08-13 15:59:25 -07005312#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005313
5314/* Header is 14 bytes */
5315#define HEADER_SIZE 14
5316#define DATA_OFFSET HEADER_SIZE
5317
5318#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \
5319 bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \
5320 ext_phy_addr, \
5321 MDIO_PCS_DEVAD, \
5322 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1)
5323
5324/* Programs an image to DSP's flash via the SPI port*/
5325static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port,
5326 u8 ext_phy_addr,
5327 char data[], u32 size)
5328{
5329 const u16 num_trans = size/4; /* 4 bytes can be sent at a time */
5330 /* Doesn't include last trans!*/
5331 const u16 last_trans_size = size%4; /* Num bytes on last trans */
5332 u16 trans_cnt, byte_cnt;
5333 u32 data_index;
5334 u16 tmp;
5335 u16 code_started = 0;
5336 u16 image_revision1, image_revision2;
5337 u16 cnt;
5338
5339 DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size);
5340 /* Going to flash*/
5341 if ((size-HEADER_SIZE) > MAX_APP_SIZE) {
5342 /* This very often will be the case, because the image is built
5343 with 160Kbytes size whereas the total image size must actually
5344 be 160Kbytes-RESERVED_SIZE */
5345 DP(NETIF_MSG_LINK, "Warning, file size was %d bytes "
5346 "truncated to %d bytes\n", size, MAX_APP_SIZE);
5347 size = MAX_APP_SIZE+HEADER_SIZE;
5348 }
5349 DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005350 DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005351 /* Put the DSP in download mode by setting FLASH_CFG[2] to 1
5352 and issuing a reset.*/
5353
5354 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005355 MISC_REGISTERS_GPIO_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005356
5357 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
5358
5359 /* wait 0.5 sec */
5360 for (cnt = 0; cnt < 100; cnt++)
5361 msleep(5);
5362
5363 /* Make sure we can access the DSP
5364 And it's in the correct mode (waiting for download) */
5365
5366 bnx2x_cl45_read(bp, port,
5367 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5368 ext_phy_addr,
5369 MDIO_PCS_DEVAD,
5370 MDIO_PCS_REG_7101_DSP_ACCESS, &tmp);
5371
5372 if (tmp != 0x000A) {
5373 DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. "
5374 "Expected 0x000A, read 0x%04X\n", tmp);
5375 DP(NETIF_MSG_LINK, "Download failed\n");
5376 return -EINVAL;
5377 }
5378
5379 /* Mux the SPI interface away from the internal processor */
5380 bnx2x_cl45_write(bp, port,
5381 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5382 ext_phy_addr,
5383 MDIO_PCS_DEVAD,
5384 MDIO_PCS_REG_7101_SPI_MUX, 1);
5385
5386 /* Reset the SPI port */
5387 bnx2x_cl45_write(bp, port,
5388 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5389 ext_phy_addr,
5390 MDIO_PCS_DEVAD,
5391 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
5392 bnx2x_cl45_write(bp, port,
5393 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5394 ext_phy_addr,
5395 MDIO_PCS_DEVAD,
5396 MDIO_PCS_REG_7101_SPI_CTRL_ADDR,
5397 (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT));
5398 bnx2x_cl45_write(bp, port,
5399 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5400 ext_phy_addr,
5401 MDIO_PCS_DEVAD,
5402 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
5403
5404 /* Erase the flash */
5405 bnx2x_cl45_write(bp, port,
5406 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5407 ext_phy_addr,
5408 MDIO_PCS_DEVAD,
5409 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5410 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5411
5412 bnx2x_cl45_write(bp, port,
5413 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5414 ext_phy_addr,
5415 MDIO_PCS_DEVAD,
5416 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5417 1);
5418
5419 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5420 bnx2x_cl45_write(bp, port,
5421 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5422 ext_phy_addr,
5423 MDIO_PCS_DEVAD,
5424 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5425 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD);
5426
5427 bnx2x_cl45_write(bp, port,
5428 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5429 ext_phy_addr,
5430 MDIO_PCS_DEVAD,
5431 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5432 1);
5433 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5434
5435 /* Wait 10 seconds, the maximum time for the erase to complete */
5436 DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n");
5437 for (cnt = 0; cnt < 1000; cnt++)
5438 msleep(10);
5439
5440 DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n");
5441 data_index = 0;
5442 for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) {
5443 bnx2x_cl45_write(bp, port,
5444 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5445 ext_phy_addr,
5446 MDIO_PCS_DEVAD,
5447 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5448 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5449
5450 bnx2x_cl45_write(bp, port,
5451 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5452 ext_phy_addr,
5453 MDIO_PCS_DEVAD,
5454 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5455 1);
5456 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5457
5458 bnx2x_cl45_write(bp, port,
5459 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5460 ext_phy_addr,
5461 MDIO_PCS_DEVAD,
5462 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5463 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
5464
5465 /* Bits 23-16 of address */
5466 bnx2x_cl45_write(bp, port,
5467 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5468 ext_phy_addr,
5469 MDIO_PCS_DEVAD,
5470 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5471 (data_index>>16));
5472 /* Bits 15-8 of address */
5473 bnx2x_cl45_write(bp, port,
5474 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5475 ext_phy_addr,
5476 MDIO_PCS_DEVAD,
5477 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5478 (data_index>>8));
5479
5480 /* Bits 7-0 of address */
5481 bnx2x_cl45_write(bp, port,
5482 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5483 ext_phy_addr,
5484 MDIO_PCS_DEVAD,
5485 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5486 ((u16)data_index));
5487
5488 byte_cnt = 0;
5489 while (byte_cnt < 4 && data_index < size) {
5490 bnx2x_cl45_write(bp, port,
5491 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5492 ext_phy_addr,
5493 MDIO_PCS_DEVAD,
5494 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5495 data[data_index++]);
5496 byte_cnt++;
5497 }
5498
5499 bnx2x_cl45_write(bp, port,
5500 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5501 ext_phy_addr,
5502 MDIO_PCS_DEVAD,
5503 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5504 byte_cnt+4);
5505
5506 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5507 msleep(5); /* Wait 5 ms minimum between transs */
5508
5509 /* Let the user know something's going on.*/
5510 /* a pacifier ever 4K */
5511 if ((data_index % 1023) == 0)
5512 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
5513 }
5514
5515 DP(NETIF_MSG_LINK, "\n");
5516 /* Transfer the last block if there is data remaining */
5517 if (last_trans_size) {
5518 bnx2x_cl45_write(bp, port,
5519 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5520 ext_phy_addr,
5521 MDIO_PCS_DEVAD,
5522 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5523 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5524
5525 bnx2x_cl45_write(bp, port,
5526 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5527 ext_phy_addr,
5528 MDIO_PCS_DEVAD,
5529 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5530 1);
5531
5532 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5533
5534 bnx2x_cl45_write(bp, port,
5535 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5536 ext_phy_addr,
5537 MDIO_PCS_DEVAD,
5538 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5539 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
5540
5541 /* Bits 23-16 of address */
5542 bnx2x_cl45_write(bp, port,
5543 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5544 ext_phy_addr,
5545 MDIO_PCS_DEVAD,
5546 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5547 (data_index>>16));
5548 /* Bits 15-8 of address */
5549 bnx2x_cl45_write(bp, port,
5550 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5551 ext_phy_addr,
5552 MDIO_PCS_DEVAD,
5553 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5554 (data_index>>8));
5555
5556 /* Bits 7-0 of address */
5557 bnx2x_cl45_write(bp, port,
5558 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5559 ext_phy_addr,
5560 MDIO_PCS_DEVAD,
5561 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5562 ((u16)data_index));
5563
5564 byte_cnt = 0;
5565 while (byte_cnt < last_trans_size && data_index < size) {
5566 /* Bits 7-0 of address */
5567 bnx2x_cl45_write(bp, port,
5568 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5569 ext_phy_addr,
5570 MDIO_PCS_DEVAD,
5571 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5572 data[data_index++]);
5573 byte_cnt++;
5574 }
5575
5576 bnx2x_cl45_write(bp, port,
5577 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5578 ext_phy_addr,
5579 MDIO_PCS_DEVAD,
5580 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5581 byte_cnt+4);
5582
5583 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5584 }
5585
5586 /* DSP Remove Download Mode */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005587 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5588 MISC_REGISTERS_GPIO_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005589
5590 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
5591
5592 /* wait 0.5 sec to allow it to run */
5593 for (cnt = 0; cnt < 100; cnt++)
5594 msleep(5);
5595
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005596 bnx2x_hw_reset(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005597
5598 for (cnt = 0; cnt < 100; cnt++)
5599 msleep(5);
5600
5601 /* Check that the code is started. In case the download
5602 checksum failed, the code won't be started. */
5603 bnx2x_cl45_read(bp, port,
5604 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5605 ext_phy_addr,
5606 MDIO_PCS_DEVAD,
5607 MDIO_PCS_REG_7101_DSP_ACCESS,
5608 &tmp);
5609
5610 code_started = (tmp & (1<<4));
5611 if (!code_started) {
5612 DP(NETIF_MSG_LINK, "Download failed. Please check file.\n");
5613 return -EINVAL;
5614 }
5615
5616 /* Verify that the file revision is now equal to the image
5617 revision within the DSP */
5618 bnx2x_cl45_read(bp, port,
5619 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5620 ext_phy_addr,
5621 MDIO_PMA_DEVAD,
5622 MDIO_PMA_REG_7101_VER1,
5623 &image_revision1);
5624
5625 bnx2x_cl45_read(bp, port,
5626 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5627 ext_phy_addr,
5628 MDIO_PMA_DEVAD,
5629 MDIO_PMA_REG_7101_VER2,
5630 &image_revision2);
5631
Eilon Greenstein3196a882008-08-13 15:58:49 -07005632 if (data[0x14e] != (image_revision2&0xFF) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005633 data[0x14f] != ((image_revision2&0xFF00)>>8) ||
5634 data[0x150] != (image_revision1&0xFF) ||
5635 data[0x151] != ((image_revision1&0xFF00)>>8)) {
5636 DP(NETIF_MSG_LINK, "Download failed.\n");
5637 return -EINVAL;
5638 }
5639 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
5640 return 0;
5641}
5642
5643u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
5644 u8 driver_loaded, char data[], u32 size)
5645{
5646 u8 rc = 0;
5647 u32 ext_phy_type;
5648 u8 ext_phy_addr;
5649 ext_phy_addr = ((ext_phy_config &
5650 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5651 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5652
5653 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
5654
5655 switch (ext_phy_type) {
5656 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5657 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
5658 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5659 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
5660 DP(NETIF_MSG_LINK,
5661 "Flash download not supported for this ext phy\n");
5662 rc = -EINVAL;
5663 break;
5664 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5665 /* Take ext phy out of reset */
5666 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005667 bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005668 rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
5669 data, size);
5670 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005671 bnx2x_turn_off_sf(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005672 break;
5673 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
5674 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
5675 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
5676 default:
5677 DP(NETIF_MSG_LINK, "Invalid ext phy type\n");
5678 rc = -EINVAL;
5679 break;
5680 }
5681 return rc;
5682}
5683