blob: b61a7a24ecc5aacded8435e6f81fa3801c4a29c1 [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/********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070032#define ETH_HLEN 14
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070033#define ETH_OVREHEAD (ETH_HLEN + 8)/* 8 for CRC + VLAN*/
34#define ETH_MIN_PACKET_SIZE 60
35#define ETH_MAX_PACKET_SIZE 1500
36#define ETH_MAX_JUMBO_PACKET_SIZE 9600
37#define MDIO_ACCESS_TIMEOUT 1000
38#define BMAC_CONTROL_RX_ENABLE 2
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070039
40/***********************************************************/
Eilon Greenstein3196a882008-08-13 15:58:49 -070041/* Shortcut definitions */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070042/***********************************************************/
43
44#define NIG_STATUS_XGXS0_LINK10G \
45 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
46#define NIG_STATUS_XGXS0_LINK_STATUS \
47 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
48#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
49 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
50#define NIG_STATUS_SERDES0_LINK_STATUS \
51 NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
52#define NIG_MASK_MI_INT \
53 NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
54#define NIG_MASK_XGXS0_LINK10G \
55 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
56#define NIG_MASK_XGXS0_LINK_STATUS \
57 NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
58#define NIG_MASK_SERDES0_LINK_STATUS \
59 NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
60
61#define MDIO_AN_CL73_OR_37_COMPLETE \
62 (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
63 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
64
65#define XGXS_RESET_BITS \
66 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \
67 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \
68 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \
69 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
70 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
71
72#define SERDES_RESET_BITS \
73 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
74 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \
75 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \
76 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
77
78#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37
79#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73
Eilon Greenstein3196a882008-08-13 15:58:49 -070080#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM
81#define AUTONEG_PARALLEL \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070082 SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
Eilon Greenstein3196a882008-08-13 15:58:49 -070083#define AUTONEG_SGMII_FIBER_AUTODET \
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070084 SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
Eilon Greenstein3196a882008-08-13 15:58:49 -070085#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
Yaniv Rosnerea4e0402008-06-23 20:27:26 -070086
87#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
88 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
89#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
90 MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
91#define GP_STATUS_SPEED_MASK \
92 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
93#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
94#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
95#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
96#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
97#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
98#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
99#define GP_STATUS_10G_HIG \
100 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
101#define GP_STATUS_10G_CX4 \
102 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
103#define GP_STATUS_12G_HIG \
104 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
105#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
106#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
107#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
108#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
109#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
110#define GP_STATUS_10G_KX4 \
111 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
112
113#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD
114#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD
115#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
116#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4
117#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
118#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD
119#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
120#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
121#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD
122#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
123#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
124#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
125#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
126#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
127#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
128#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
129#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
130#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
131#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
132#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
133#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
134#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
135#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
136
137#define PHY_XGXS_FLAG 0x1
138#define PHY_SGMII_FLAG 0x2
139#define PHY_SERDES_FLAG 0x4
140
Eilon Greenstein589abe32009-02-12 08:36:55 +0000141/* */
142#define SFP_EEPROM_CON_TYPE_ADDR 0x2
143 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
144 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
145
146#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
147 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
148 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
149#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
150#define SFP_EEPROM_VENDOR_NAME_SIZE 16
151#define SFP_EEPROM_OPTIONS_ADDR 0x40
152 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
153#define SFP_EEPROM_OPTIONS_SIZE 2
154
155#define SFP_MODULE_TYPE_UNKNOWN 0x0
156#define SFP_MODULE_TYPE_LC 0x1
157#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE 0x2
158#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE 0x3
159
160#define SFP_LIMITING_MODE_VALUE 0x0044
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700161/**********************************************************/
162/* INTERFACE */
163/**********************************************************/
164#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
165 bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
166 DEFAULT_PHY_DEV_ADDR, \
167 (_bank + (_addr & 0xf)), \
168 _val)
169
170#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
171 bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
172 DEFAULT_PHY_DEV_ADDR, \
173 (_bank + (_addr & 0xf)), \
174 _val)
175
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000176static void bnx2x_set_serdes_access(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700177{
178 struct bnx2x *bp = params->bp;
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000179 u32 emac_base = (params->port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
180 /* Set Clause 22 */
181 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 1);
182 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
183 udelay(500);
184 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
185 udelay(500);
186 /* Set Clause 45 */
187 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 0);
188}
189static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags)
190{
191 struct bnx2x *bp = params->bp;
192 if (phy_flags & PHY_XGXS_FLAG) {
193 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
194 params->port*0x18, 0);
195 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
196 DEFAULT_PHY_DEV_ADDR);
197 } else {
198 bnx2x_set_serdes_access(params);
199
200 REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
201 params->port*0x10,
202 DEFAULT_PHY_DEV_ADDR);
203 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700204}
205
206static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
207{
208 u32 val = REG_RD(bp, reg);
209
210 val |= bits;
211 REG_WR(bp, reg, val);
212 return val;
213}
214
215static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
216{
217 u32 val = REG_RD(bp, reg);
218
219 val &= ~bits;
220 REG_WR(bp, reg, val);
221 return val;
222}
223
224static void bnx2x_emac_init(struct link_params *params,
225 struct link_vars *vars)
226{
227 /* reset and unreset the emac core */
228 struct bnx2x *bp = params->bp;
229 u8 port = params->port;
230 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
231 u32 val;
232 u16 timeout;
233
234 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
235 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
236 udelay(5);
237 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
238 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
239
240 /* init emac - use read-modify-write */
241 /* self clear reset */
242 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700243 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700244
245 timeout = 200;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700246 do {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700247 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
248 DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
249 if (!timeout) {
250 DP(NETIF_MSG_LINK, "EMAC timeout!\n");
251 return;
252 }
253 timeout--;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700254 } while (val & EMAC_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700255
256 /* Set mac address */
257 val = ((params->mac_addr[0] << 8) |
258 params->mac_addr[1]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700259 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700260
261 val = ((params->mac_addr[2] << 24) |
262 (params->mac_addr[3] << 16) |
263 (params->mac_addr[4] << 8) |
264 params->mac_addr[5]);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700265 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700266}
267
268static u8 bnx2x_emac_enable(struct link_params *params,
269 struct link_vars *vars, u8 lb)
270{
271 struct bnx2x *bp = params->bp;
272 u8 port = params->port;
273 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
274 u32 val;
275
276 DP(NETIF_MSG_LINK, "enabling EMAC\n");
277
278 /* enable emac and not bmac */
279 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
280
281 /* for paladium */
282 if (CHIP_REV_IS_EMUL(bp)) {
283 /* Use lane 1 (of lanes 0-3) */
284 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
285 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
286 port*4, 1);
287 }
288 /* for fpga */
289 else
290
291 if (CHIP_REV_IS_FPGA(bp)) {
292 /* Use lane 1 (of lanes 0-3) */
293 DP(NETIF_MSG_LINK, "bnx2x_emac_enable: Setting FPGA\n");
294
295 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
296 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4,
297 0);
298 } else
299 /* ASIC */
300 if (vars->phy_flags & PHY_XGXS_FLAG) {
301 u32 ser_lane = ((params->lane_config &
302 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
303 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
304
305 DP(NETIF_MSG_LINK, "XGXS\n");
306 /* select the master lanes (out of 0-3) */
307 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 +
308 port*4, ser_lane);
309 /* select XGXS */
310 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
311 port*4, 1);
312
313 } else { /* SerDes */
314 DP(NETIF_MSG_LINK, "SerDes\n");
315 /* select SerDes */
316 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL +
317 port*4, 0);
318 }
319
Eilon Greenstein811a2f22009-02-12 08:37:04 +0000320 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
321 EMAC_RX_MODE_RESET);
322 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
323 EMAC_TX_MODE_RESET);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700324
325 if (CHIP_REV_IS_SLOW(bp)) {
326 /* config GMII mode */
327 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
Eilon Greenstein3196a882008-08-13 15:58:49 -0700328 EMAC_WR(bp, EMAC_REG_EMAC_MODE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700329 (val | EMAC_MODE_PORT_GMII));
330 } else { /* ASIC */
331 /* pause enable/disable */
332 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
333 EMAC_RX_MODE_FLOW_EN);
David S. Millerc0700f92008-12-16 23:53:20 -0800334 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700335 bnx2x_bits_en(bp, emac_base +
336 EMAC_REG_EMAC_RX_MODE,
337 EMAC_RX_MODE_FLOW_EN);
338
339 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700340 (EMAC_TX_MODE_EXT_PAUSE_EN |
341 EMAC_TX_MODE_FLOW_EN));
David S. Millerc0700f92008-12-16 23:53:20 -0800342 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700343 bnx2x_bits_en(bp, emac_base +
344 EMAC_REG_EMAC_TX_MODE,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700345 (EMAC_TX_MODE_EXT_PAUSE_EN |
346 EMAC_TX_MODE_FLOW_EN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700347 }
348
349 /* KEEP_VLAN_TAG, promiscuous */
350 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
351 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700352 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700353
354 /* Set Loopback */
355 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
356 if (lb)
357 val |= 0x810;
358 else
359 val &= ~0x810;
Eilon Greenstein3196a882008-08-13 15:58:49 -0700360 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700361
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +0000362 /* enable emac */
363 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);
364
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700365 /* enable emac for jumbo packets */
Eilon Greenstein3196a882008-08-13 15:58:49 -0700366 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700367 (EMAC_RX_MTU_SIZE_JUMBO_ENA |
368 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)));
369
370 /* strip CRC */
371 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
372
373 /* disable the NIG in/out to the bmac */
374 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
375 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
376 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
377
378 /* enable the NIG in/out to the emac */
379 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
380 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800381 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700382 val = 1;
383
384 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
385 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
386
387 if (CHIP_REV_IS_EMUL(bp)) {
388 /* take the BigMac out of reset */
389 REG_WR(bp,
390 GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
391 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
392
393 /* enable access for bmac registers */
394 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
395 }
396
397 vars->mac_type = MAC_TYPE_EMAC;
398 return 0;
399}
400
401
402
403static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
404 u8 is_lb)
405{
406 struct bnx2x *bp = params->bp;
407 u8 port = params->port;
408 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
409 NIG_REG_INGRESS_BMAC0_MEM;
410 u32 wb_data[2];
411 u32 val;
412
413 DP(NETIF_MSG_LINK, "Enabling BigMAC\n");
414 /* reset and unreset the BigMac */
415 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
416 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
417 msleep(1);
418
419 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
420 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
421
422 /* enable access for bmac registers */
423 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
424
425 /* XGXS control */
426 wb_data[0] = 0x3c;
427 wb_data[1] = 0;
428 REG_WR_DMAE(bp, bmac_addr +
429 BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
430 wb_data, 2);
431
432 /* tx MAC SA */
433 wb_data[0] = ((params->mac_addr[2] << 24) |
434 (params->mac_addr[3] << 16) |
435 (params->mac_addr[4] << 8) |
436 params->mac_addr[5]);
437 wb_data[1] = ((params->mac_addr[0] << 8) |
438 params->mac_addr[1]);
439 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
440 wb_data, 2);
441
442 /* tx control */
443 val = 0xc0;
David S. Millerc0700f92008-12-16 23:53:20 -0800444 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700445 val |= 0x800000;
446 wb_data[0] = val;
447 wb_data[1] = 0;
448 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL,
449 wb_data, 2);
450
451 /* mac control */
452 val = 0x3;
453 if (is_lb) {
454 val |= 0x4;
455 DP(NETIF_MSG_LINK, "enable bmac loopback\n");
456 }
457 wb_data[0] = val;
458 wb_data[1] = 0;
459 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
460 wb_data, 2);
461
462
463 /* set rx mtu */
464 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
465 wb_data[1] = 0;
466 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE,
467 wb_data, 2);
468
469 /* rx control set to don't strip crc */
470 val = 0x14;
David S. Millerc0700f92008-12-16 23:53:20 -0800471 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700472 val |= 0x20;
473 wb_data[0] = val;
474 wb_data[1] = 0;
475 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL,
476 wb_data, 2);
477
478 /* set tx mtu */
479 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
480 wb_data[1] = 0;
481 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE,
482 wb_data, 2);
483
484 /* set cnt max size */
485 wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
486 wb_data[1] = 0;
487 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
488 wb_data, 2);
489
490 /* configure safc */
491 wb_data[0] = 0x1000200;
492 wb_data[1] = 0;
493 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
494 wb_data, 2);
495 /* fix for emulation */
496 if (CHIP_REV_IS_EMUL(bp)) {
497 wb_data[0] = 0xf000;
498 wb_data[1] = 0;
499 REG_WR_DMAE(bp,
500 bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
501 wb_data, 2);
502 }
503
504 REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
505 REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
506 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
507 val = 0;
David S. Millerc0700f92008-12-16 23:53:20 -0800508 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700509 val = 1;
510 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
511 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
512 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0);
513 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
514 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1);
515 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
516
517 vars->mac_type = MAC_TYPE_BMAC;
518 return 0;
519}
520
521static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
522{
523 struct bnx2x *bp = params->bp;
524 u32 val;
525
526 if (phy_flags & PHY_XGXS_FLAG) {
527 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
528 val = XGXS_RESET_BITS;
529
530 } else { /* SerDes */
531 DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
532 val = SERDES_RESET_BITS;
533 }
534
535 val = val << (params->port*16);
536
537 /* reset and unreset the SerDes/XGXS */
538 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
539 val);
540 udelay(500);
541 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
542 val);
Eilon Greensteinc1b73992009-02-12 08:37:07 +0000543 bnx2x_set_phy_mdio(params, phy_flags);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700544}
545
546void bnx2x_link_status_update(struct link_params *params,
547 struct link_vars *vars)
548{
549 struct bnx2x *bp = params->bp;
550 u8 link_10g;
551 u8 port = params->port;
552
553 if (params->switch_cfg == SWITCH_CFG_1G)
554 vars->phy_flags = PHY_SERDES_FLAG;
555 else
556 vars->phy_flags = PHY_XGXS_FLAG;
557 vars->link_status = REG_RD(bp, params->shmem_base +
558 offsetof(struct shmem_region,
559 port_mb[port].link_status));
560
561 vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
562
563 if (vars->link_up) {
564 DP(NETIF_MSG_LINK, "phy link up\n");
565
566 vars->phy_link_up = 1;
567 vars->duplex = DUPLEX_FULL;
568 switch (vars->link_status &
569 LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
570 case LINK_10THD:
571 vars->duplex = DUPLEX_HALF;
572 /* fall thru */
573 case LINK_10TFD:
574 vars->line_speed = SPEED_10;
575 break;
576
577 case LINK_100TXHD:
578 vars->duplex = DUPLEX_HALF;
579 /* fall thru */
580 case LINK_100T4:
581 case LINK_100TXFD:
582 vars->line_speed = SPEED_100;
583 break;
584
585 case LINK_1000THD:
586 vars->duplex = DUPLEX_HALF;
587 /* fall thru */
588 case LINK_1000TFD:
589 vars->line_speed = SPEED_1000;
590 break;
591
592 case LINK_2500THD:
593 vars->duplex = DUPLEX_HALF;
594 /* fall thru */
595 case LINK_2500TFD:
596 vars->line_speed = SPEED_2500;
597 break;
598
599 case LINK_10GTFD:
600 vars->line_speed = SPEED_10000;
601 break;
602
603 case LINK_12GTFD:
604 vars->line_speed = SPEED_12000;
605 break;
606
607 case LINK_12_5GTFD:
608 vars->line_speed = SPEED_12500;
609 break;
610
611 case LINK_13GTFD:
612 vars->line_speed = SPEED_13000;
613 break;
614
615 case LINK_15GTFD:
616 vars->line_speed = SPEED_15000;
617 break;
618
619 case LINK_16GTFD:
620 vars->line_speed = SPEED_16000;
621 break;
622
623 default:
624 break;
625 }
626
627 if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800628 vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700629 else
David S. Millerc0700f92008-12-16 23:53:20 -0800630 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700631
632 if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
David S. Millerc0700f92008-12-16 23:53:20 -0800633 vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700634 else
David S. Millerc0700f92008-12-16 23:53:20 -0800635 vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700636
637 if (vars->phy_flags & PHY_XGXS_FLAG) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700638 if (vars->line_speed &&
639 ((vars->line_speed == SPEED_10) ||
640 (vars->line_speed == SPEED_100))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700641 vars->phy_flags |= PHY_SGMII_FLAG;
642 } else {
643 vars->phy_flags &= ~PHY_SGMII_FLAG;
644 }
645 }
646
647 /* anything 10 and over uses the bmac */
648 link_10g = ((vars->line_speed == SPEED_10000) ||
649 (vars->line_speed == SPEED_12000) ||
650 (vars->line_speed == SPEED_12500) ||
651 (vars->line_speed == SPEED_13000) ||
652 (vars->line_speed == SPEED_15000) ||
653 (vars->line_speed == SPEED_16000));
654 if (link_10g)
655 vars->mac_type = MAC_TYPE_BMAC;
656 else
657 vars->mac_type = MAC_TYPE_EMAC;
658
659 } else { /* link down */
660 DP(NETIF_MSG_LINK, "phy link down\n");
661
662 vars->phy_link_up = 0;
663
664 vars->line_speed = 0;
665 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -0800666 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700667
668 /* indicate no mac active */
669 vars->mac_type = MAC_TYPE_NONE;
670 }
671
672 DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n",
673 vars->link_status, vars->phy_link_up);
674 DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n",
675 vars->line_speed, vars->duplex, vars->flow_ctrl);
676}
677
678static void bnx2x_update_mng(struct link_params *params, u32 link_status)
679{
680 struct bnx2x *bp = params->bp;
681 REG_WR(bp, params->shmem_base +
682 offsetof(struct shmem_region,
683 port_mb[params->port].link_status),
684 link_status);
685}
686
687static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
688{
689 u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
690 NIG_REG_INGRESS_BMAC0_MEM;
691 u32 wb_data[2];
Eilon Greenstein3196a882008-08-13 15:58:49 -0700692 u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700693
694 /* Only if the bmac is out of reset */
695 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
696 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) &&
697 nig_bmac_enable) {
698
699 /* Clear Rx Enable bit in BMAC_CONTROL register */
700 REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
701 wb_data, 2);
702 wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
703 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
704 wb_data, 2);
705
706 msleep(1);
707 }
708}
709
710static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
711 u32 line_speed)
712{
713 struct bnx2x *bp = params->bp;
714 u8 port = params->port;
715 u32 init_crd, crd;
716 u32 count = 1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700717
718 /* disable port */
719 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
720
721 /* wait for init credit */
722 init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
723 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
724 DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd);
725
726 while ((init_crd != crd) && count) {
727 msleep(5);
728
729 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
730 count--;
731 }
732 crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
733 if (init_crd != crd) {
734 DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n",
735 init_crd, crd);
736 return -EINVAL;
737 }
738
David S. Millerc0700f92008-12-16 23:53:20 -0800739 if (flow_ctrl & BNX2X_FLOW_CTRL_RX ||
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700740 line_speed == SPEED_10 ||
741 line_speed == SPEED_100 ||
742 line_speed == SPEED_1000 ||
743 line_speed == SPEED_2500) {
744 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700745 /* update threshold */
746 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
747 /* update init credit */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700748 init_crd = 778; /* (800-18-4) */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700749
750 } else {
751 u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
752 ETH_OVREHEAD)/16;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -0700753 REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700754 /* update threshold */
755 REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
756 /* update init credit */
757 switch (line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700758 case SPEED_10000:
759 init_crd = thresh + 553 - 22;
760 break;
761
762 case SPEED_12000:
763 init_crd = thresh + 664 - 22;
764 break;
765
766 case SPEED_13000:
767 init_crd = thresh + 742 - 22;
768 break;
769
770 case SPEED_16000:
771 init_crd = thresh + 778 - 22;
772 break;
773 default:
774 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
775 line_speed);
776 return -EINVAL;
777 break;
778 }
779 }
780 REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
781 DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
782 line_speed, init_crd);
783
784 /* probe the credit changes */
785 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
786 msleep(5);
787 REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
788
789 /* enable port */
790 REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
791 return 0;
792}
793
Eilon Greenstein589abe32009-02-12 08:36:55 +0000794static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700795{
796 u32 emac_base;
797 switch (ext_phy_type) {
798 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
Eilon Greenstein589abe32009-02-12 08:36:55 +0000799 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
800 /* All MDC/MDIO is directed through single EMAC */
801 if (REG_RD(bp, NIG_REG_PORT_SWAP))
802 emac_base = GRCBASE_EMAC0;
803 else
804 emac_base = GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700805 break;
806 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700807 emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700808 break;
809 default:
Eilon Greenstein6378c022008-08-13 15:59:25 -0700810 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700811 break;
812 }
813 return emac_base;
814
815}
816
817u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
818 u8 phy_addr, u8 devad, u16 reg, u16 val)
819{
820 u32 tmp, saved_mode;
821 u8 i, rc = 0;
Eilon Greenstein589abe32009-02-12 08:36:55 +0000822 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700823
824 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
825 * (a value of 49==0x31) and make sure that the AUTO poll is off
826 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000827
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700828 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
829 tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
830 EMAC_MDIO_MODE_CLOCK_CNT);
831 tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
832 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
833 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
834 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
835 udelay(40);
836
837 /* address */
838
839 tmp = ((phy_addr << 21) | (devad << 16) | reg |
840 EMAC_MDIO_COMM_COMMAND_ADDRESS |
841 EMAC_MDIO_COMM_START_BUSY);
842 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
843
844 for (i = 0; i < 50; i++) {
845 udelay(10);
846
847 tmp = REG_RD(bp, mdio_ctrl + 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 } else {
857 /* data */
858 tmp = ((phy_addr << 21) | (devad << 16) | val |
859 EMAC_MDIO_COMM_COMMAND_WRITE_45 |
860 EMAC_MDIO_COMM_START_BUSY);
861 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
862
863 for (i = 0; i < 50; i++) {
864 udelay(10);
865
866 tmp = REG_RD(bp, mdio_ctrl +
867 EMAC_REG_EMAC_MDIO_COMM);
868 if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
869 udelay(5);
870 break;
871 }
872 }
873 if (tmp & EMAC_MDIO_COMM_START_BUSY) {
874 DP(NETIF_MSG_LINK, "write phy register failed\n");
875 rc = -EFAULT;
876 }
877 }
878
879 /* Restore the saved mode */
880 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
881
882 return rc;
883}
884
885u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
886 u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
887{
888 u32 val, saved_mode;
889 u16 i;
890 u8 rc = 0;
891
Eilon Greenstein589abe32009-02-12 08:36:55 +0000892 u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700893 /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
894 * (a value of 49==0x31) and make sure that the AUTO poll is off
895 */
Eilon Greenstein589abe32009-02-12 08:36:55 +0000896
Yaniv Rosnerea4e0402008-06-23 20:27:26 -0700897 saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
898 val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
899 EMAC_MDIO_MODE_CLOCK_CNT));
900 val |= (EMAC_MDIO_MODE_CLAUSE_45 |
901 (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
902 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
903 REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
904 udelay(40);
905
906 /* address */
907 val = ((phy_addr << 21) | (devad << 16) | reg |
908 EMAC_MDIO_COMM_COMMAND_ADDRESS |
909 EMAC_MDIO_COMM_START_BUSY);
910 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
911
912 for (i = 0; i < 50; i++) {
913 udelay(10);
914
915 val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
916 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
917 udelay(5);
918 break;
919 }
920 }
921 if (val & EMAC_MDIO_COMM_START_BUSY) {
922 DP(NETIF_MSG_LINK, "read phy register failed\n");
923
924 *ret_val = 0;
925 rc = -EFAULT;
926
927 } else {
928 /* data */
929 val = ((phy_addr << 21) | (devad << 16) |
930 EMAC_MDIO_COMM_COMMAND_READ_45 |
931 EMAC_MDIO_COMM_START_BUSY);
932 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
933
934 for (i = 0; i < 50; i++) {
935 udelay(10);
936
937 val = REG_RD(bp, mdio_ctrl +
938 EMAC_REG_EMAC_MDIO_COMM);
939 if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
940 *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
941 break;
942 }
943 }
944 if (val & EMAC_MDIO_COMM_START_BUSY) {
945 DP(NETIF_MSG_LINK, "read phy register failed\n");
946
947 *ret_val = 0;
948 rc = -EFAULT;
949 }
950 }
951
952 /* Restore the saved mode */
953 REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
954
955 return rc;
956}
957
958static void bnx2x_set_aer_mmd(struct link_params *params,
959 struct link_vars *vars)
960{
961 struct bnx2x *bp = params->bp;
962 u32 ser_lane;
963 u16 offset;
964
965 ser_lane = ((params->lane_config &
966 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
967 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
968
969 offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
970 (params->phy_addr + ser_lane) : 0;
971
972 CL45_WR_OVER_CL22(bp, params->port,
973 params->phy_addr,
974 MDIO_REG_BANK_AER_BLOCK,
975 MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
976}
977
978static void bnx2x_set_master_ln(struct link_params *params)
979{
980 struct bnx2x *bp = params->bp;
981 u16 new_master_ln, ser_lane;
982 ser_lane = ((params->lane_config &
983 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
984 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
985
986 /* set the master_ln for AN */
987 CL45_RD_OVER_CL22(bp, params->port,
988 params->phy_addr,
989 MDIO_REG_BANK_XGXS_BLOCK2,
990 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
991 &new_master_ln);
992
993 CL45_WR_OVER_CL22(bp, params->port,
994 params->phy_addr,
995 MDIO_REG_BANK_XGXS_BLOCK2 ,
996 MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
997 (new_master_ln | ser_lane));
998}
999
1000static u8 bnx2x_reset_unicore(struct link_params *params)
1001{
1002 struct bnx2x *bp = params->bp;
1003 u16 mii_control;
1004 u16 i;
1005
1006 CL45_RD_OVER_CL22(bp, params->port,
1007 params->phy_addr,
1008 MDIO_REG_BANK_COMBO_IEEE0,
1009 MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
1010
1011 /* reset the unicore */
1012 CL45_WR_OVER_CL22(bp, params->port,
1013 params->phy_addr,
1014 MDIO_REG_BANK_COMBO_IEEE0,
1015 MDIO_COMBO_IEEE0_MII_CONTROL,
1016 (mii_control |
1017 MDIO_COMBO_IEEO_MII_CONTROL_RESET));
1018
Eilon Greensteinc1b73992009-02-12 08:37:07 +00001019 bnx2x_set_serdes_access(params);
1020
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001021 /* wait for the reset to self clear */
1022 for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
1023 udelay(5);
1024
1025 /* the reset erased the previous bank value */
1026 CL45_RD_OVER_CL22(bp, params->port,
1027 params->phy_addr,
1028 MDIO_REG_BANK_COMBO_IEEE0,
1029 MDIO_COMBO_IEEE0_MII_CONTROL,
1030 &mii_control);
1031
1032 if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
1033 udelay(5);
1034 return 0;
1035 }
1036 }
1037
1038 DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
1039 return -EINVAL;
1040
1041}
1042
1043static void bnx2x_set_swap_lanes(struct link_params *params)
1044{
1045 struct bnx2x *bp = params->bp;
1046 /* Each two bits represents a lane number:
1047 No swap is 0123 => 0x1b no need to enable the swap */
1048 u16 ser_lane, rx_lane_swap, tx_lane_swap;
1049
1050 ser_lane = ((params->lane_config &
1051 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
1052 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
1053 rx_lane_swap = ((params->lane_config &
1054 PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
1055 PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
1056 tx_lane_swap = ((params->lane_config &
1057 PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
1058 PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
1059
1060 if (rx_lane_swap != 0x1b) {
1061 CL45_WR_OVER_CL22(bp, params->port,
1062 params->phy_addr,
1063 MDIO_REG_BANK_XGXS_BLOCK2,
1064 MDIO_XGXS_BLOCK2_RX_LN_SWAP,
1065 (rx_lane_swap |
1066 MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
1067 MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
1068 } else {
1069 CL45_WR_OVER_CL22(bp, params->port,
1070 params->phy_addr,
1071 MDIO_REG_BANK_XGXS_BLOCK2,
1072 MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
1073 }
1074
1075 if (tx_lane_swap != 0x1b) {
1076 CL45_WR_OVER_CL22(bp, params->port,
1077 params->phy_addr,
1078 MDIO_REG_BANK_XGXS_BLOCK2,
1079 MDIO_XGXS_BLOCK2_TX_LN_SWAP,
1080 (tx_lane_swap |
1081 MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
1082 } else {
1083 CL45_WR_OVER_CL22(bp, params->port,
1084 params->phy_addr,
1085 MDIO_REG_BANK_XGXS_BLOCK2,
1086 MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
1087 }
1088}
1089
1090static void bnx2x_set_parallel_detection(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07001091 u8 phy_flags)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001092{
1093 struct bnx2x *bp = params->bp;
1094 u16 control2;
1095
1096 CL45_RD_OVER_CL22(bp, params->port,
1097 params->phy_addr,
1098 MDIO_REG_BANK_SERDES_DIGITAL,
1099 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1100 &control2);
1101
1102
1103 control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
1104
1105
1106 CL45_WR_OVER_CL22(bp, params->port,
1107 params->phy_addr,
1108 MDIO_REG_BANK_SERDES_DIGITAL,
1109 MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
1110 control2);
1111
1112 if (phy_flags & PHY_XGXS_FLAG) {
1113 DP(NETIF_MSG_LINK, "XGXS\n");
1114
1115 CL45_WR_OVER_CL22(bp, params->port,
1116 params->phy_addr,
1117 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1118 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
1119 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
1120
1121 CL45_RD_OVER_CL22(bp, params->port,
1122 params->phy_addr,
1123 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1124 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1125 &control2);
1126
1127
1128 control2 |=
1129 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
1130
1131 CL45_WR_OVER_CL22(bp, params->port,
1132 params->phy_addr,
1133 MDIO_REG_BANK_10G_PARALLEL_DETECT,
1134 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
1135 control2);
1136
1137 /* Disable parallel detection of HiG */
1138 CL45_WR_OVER_CL22(bp, params->port,
1139 params->phy_addr,
1140 MDIO_REG_BANK_XGXS_BLOCK2,
1141 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
1142 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
1143 MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
1144 }
1145}
1146
1147static void bnx2x_set_autoneg(struct link_params *params,
1148 struct link_vars *vars)
1149{
1150 struct bnx2x *bp = params->bp;
1151 u16 reg_val;
1152
1153 /* CL37 Autoneg */
1154
1155 CL45_RD_OVER_CL22(bp, params->port,
1156 params->phy_addr,
1157 MDIO_REG_BANK_COMBO_IEEE0,
1158 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1159
1160 /* CL37 Autoneg Enabled */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001161 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001162 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
1163 else /* CL37 Autoneg Disabled */
1164 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1165 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
1166
1167 CL45_WR_OVER_CL22(bp, params->port,
1168 params->phy_addr,
1169 MDIO_REG_BANK_COMBO_IEEE0,
1170 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1171
1172 /* Enable/Disable Autodetection */
1173
1174 CL45_RD_OVER_CL22(bp, params->port,
1175 params->phy_addr,
1176 MDIO_REG_BANK_SERDES_DIGITAL,
1177 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
1178 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001179 if (vars->line_speed == SPEED_AUTO_NEG)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001180 reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1181 else
1182 reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
1183
1184 CL45_WR_OVER_CL22(bp, params->port,
1185 params->phy_addr,
1186 MDIO_REG_BANK_SERDES_DIGITAL,
1187 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
1188
1189 /* Enable TetonII and BAM autoneg */
1190 CL45_RD_OVER_CL22(bp, params->port,
1191 params->phy_addr,
1192 MDIO_REG_BANK_BAM_NEXT_PAGE,
1193 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1194 &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001195 if (vars->line_speed == SPEED_AUTO_NEG) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001196 /* Enable BAM aneg Mode and TetonII aneg Mode */
1197 reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1198 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1199 } else {
1200 /* TetonII and BAM Autoneg Disabled */
1201 reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
1202 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
1203 }
1204 CL45_WR_OVER_CL22(bp, params->port,
1205 params->phy_addr,
1206 MDIO_REG_BANK_BAM_NEXT_PAGE,
1207 MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
1208 reg_val);
1209
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001210 /* CL73 Autoneg Disabled */
1211 reg_val = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001212
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001213 CL45_WR_OVER_CL22(bp, params->port,
1214 params->phy_addr,
1215 MDIO_REG_BANK_CL73_IEEEB0,
1216 MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
1217}
1218
1219/* program SerDes, forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001220static void bnx2x_program_serdes(struct link_params *params,
1221 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001222{
1223 struct bnx2x *bp = params->bp;
1224 u16 reg_val;
1225
1226 /* program duplex, disable autoneg */
1227
1228 CL45_RD_OVER_CL22(bp, params->port,
1229 params->phy_addr,
1230 MDIO_REG_BANK_COMBO_IEEE0,
1231 MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
1232 reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
1233 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN);
1234 if (params->req_duplex == DUPLEX_FULL)
1235 reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1236 CL45_WR_OVER_CL22(bp, params->port,
1237 params->phy_addr,
1238 MDIO_REG_BANK_COMBO_IEEE0,
1239 MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
1240
1241 /* program speed
1242 - needed only if the speed is greater than 1G (2.5G or 10G) */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001243 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001244 params->phy_addr,
1245 MDIO_REG_BANK_SERDES_DIGITAL,
1246 MDIO_SERDES_DIGITAL_MISC1, &reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001247 /* clearing the speed value before setting the right speed */
1248 DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
1249
1250 reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
1251 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
1252
1253 if (!((vars->line_speed == SPEED_1000) ||
1254 (vars->line_speed == SPEED_100) ||
1255 (vars->line_speed == SPEED_10))) {
1256
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001257 reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
1258 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001259 if (vars->line_speed == SPEED_10000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001260 reg_val |=
1261 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001262 if (vars->line_speed == SPEED_13000)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001263 reg_val |=
1264 MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001265 }
1266
1267 CL45_WR_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001268 params->phy_addr,
1269 MDIO_REG_BANK_SERDES_DIGITAL,
1270 MDIO_SERDES_DIGITAL_MISC1, reg_val);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001271
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001272}
1273
1274static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
1275{
1276 struct bnx2x *bp = params->bp;
1277 u16 val = 0;
1278
1279 /* configure the 48 bits for BAM AN */
1280
1281 /* set extended capabilities */
1282 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
1283 val |= MDIO_OVER_1G_UP1_2_5G;
1284 if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
1285 val |= MDIO_OVER_1G_UP1_10G;
1286 CL45_WR_OVER_CL22(bp, params->port,
1287 params->phy_addr,
1288 MDIO_REG_BANK_OVER_1G,
1289 MDIO_OVER_1G_UP1, val);
1290
1291 CL45_WR_OVER_CL22(bp, params->port,
1292 params->phy_addr,
1293 MDIO_REG_BANK_OVER_1G,
1294 MDIO_OVER_1G_UP3, 0);
1295}
1296
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001297static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001298{
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001299 *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001300 /* resolve pause mode and advertisement
1301 * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
1302
1303 switch (params->req_flow_ctrl) {
David S. Millerc0700f92008-12-16 23:53:20 -08001304 case BNX2X_FLOW_CTRL_AUTO:
1305 if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001306 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001307 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
1308 } else {
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001309 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001310 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1311 }
1312 break;
David S. Millerc0700f92008-12-16 23:53:20 -08001313 case BNX2X_FLOW_CTRL_TX:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001314 *ieee_fc |=
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001315 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
1316 break;
1317
David S. Millerc0700f92008-12-16 23:53:20 -08001318 case BNX2X_FLOW_CTRL_RX:
1319 case BNX2X_FLOW_CTRL_BOTH:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001320 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001321 break;
1322
David S. Millerc0700f92008-12-16 23:53:20 -08001323 case BNX2X_FLOW_CTRL_NONE:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001324 default:
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001325 *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001326 break;
1327 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001328}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001329
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001330static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
1331 u32 ieee_fc)
1332{
1333 struct bnx2x *bp = params->bp;
1334 /* for AN, we are always publishing full duplex */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001335
1336 CL45_WR_OVER_CL22(bp, params->port,
1337 params->phy_addr,
1338 MDIO_REG_BANK_COMBO_IEEE0,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001339 MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001340}
1341
1342static void bnx2x_restart_autoneg(struct link_params *params)
1343{
1344 struct bnx2x *bp = params->bp;
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001345 u16 mii_control;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001346 DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n");
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001347 /* Enable and restart BAM/CL37 aneg */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001348
Eilon Greenstein3a36f2e2009-02-12 08:37:09 +00001349 CL45_RD_OVER_CL22(bp, params->port,
1350 params->phy_addr,
1351 MDIO_REG_BANK_COMBO_IEEE0,
1352 MDIO_COMBO_IEEE0_MII_CONTROL,
1353 &mii_control);
1354 DP(NETIF_MSG_LINK,
1355 "bnx2x_restart_autoneg mii_control before = 0x%x\n",
1356 mii_control);
1357 CL45_WR_OVER_CL22(bp, params->port,
1358 params->phy_addr,
1359 MDIO_REG_BANK_COMBO_IEEE0,
1360 MDIO_COMBO_IEEE0_MII_CONTROL,
1361 (mii_control |
1362 MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1363 MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001364}
1365
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001366static void bnx2x_initialize_sgmii_process(struct link_params *params,
1367 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001368{
1369 struct bnx2x *bp = params->bp;
1370 u16 control1;
1371
1372 /* in SGMII mode, the unicore is always slave */
1373
1374 CL45_RD_OVER_CL22(bp, params->port,
1375 params->phy_addr,
1376 MDIO_REG_BANK_SERDES_DIGITAL,
1377 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1378 &control1);
1379 control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
1380 /* set sgmii mode (and not fiber) */
1381 control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
1382 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
1383 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
1384 CL45_WR_OVER_CL22(bp, params->port,
1385 params->phy_addr,
1386 MDIO_REG_BANK_SERDES_DIGITAL,
1387 MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
1388 control1);
1389
1390 /* if forced speed */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001391 if (!(vars->line_speed == SPEED_AUTO_NEG)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001392 /* set speed, disable autoneg */
1393 u16 mii_control;
1394
1395 CL45_RD_OVER_CL22(bp, params->port,
1396 params->phy_addr,
1397 MDIO_REG_BANK_COMBO_IEEE0,
1398 MDIO_COMBO_IEEE0_MII_CONTROL,
1399 &mii_control);
1400 mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
1401 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
1402 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
1403
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001404 switch (vars->line_speed) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001405 case SPEED_100:
1406 mii_control |=
1407 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
1408 break;
1409 case SPEED_1000:
1410 mii_control |=
1411 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
1412 break;
1413 case SPEED_10:
1414 /* there is nothing to set for 10M */
1415 break;
1416 default:
1417 /* invalid speed for SGMII */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001418 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
1419 vars->line_speed);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001420 break;
1421 }
1422
1423 /* setting the full duplex */
1424 if (params->req_duplex == DUPLEX_FULL)
1425 mii_control |=
1426 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
1427 CL45_WR_OVER_CL22(bp, params->port,
1428 params->phy_addr,
1429 MDIO_REG_BANK_COMBO_IEEE0,
1430 MDIO_COMBO_IEEE0_MII_CONTROL,
1431 mii_control);
1432
1433 } else { /* AN mode */
1434 /* enable and restart AN */
1435 bnx2x_restart_autoneg(params);
1436 }
1437}
1438
1439
1440/*
1441 * link management
1442 */
1443
1444static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001445{ /* LD LP */
1446 switch (pause_result) { /* ASYM P ASYM P */
1447 case 0xb: /* 1 0 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001448 vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001449 break;
1450
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001451 case 0xe: /* 1 1 1 0 */
David S. Millerc0700f92008-12-16 23:53:20 -08001452 vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001453 break;
1454
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001455 case 0x5: /* 0 1 0 1 */
1456 case 0x7: /* 0 1 1 1 */
1457 case 0xd: /* 1 1 0 1 */
1458 case 0xf: /* 1 1 1 1 */
David S. Millerc0700f92008-12-16 23:53:20 -08001459 vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001460 break;
1461
1462 default:
1463 break;
1464 }
1465}
1466
1467static u8 bnx2x_ext_phy_resove_fc(struct link_params *params,
1468 struct link_vars *vars)
1469{
1470 struct bnx2x *bp = params->bp;
1471 u8 ext_phy_addr;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001472 u16 ld_pause; /* local */
1473 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001474 u16 an_complete; /* AN complete */
1475 u16 pause_result;
1476 u8 ret = 0;
1477 u32 ext_phy_type;
1478 u8 port = params->port;
1479 ext_phy_addr = ((params->ext_phy_config &
1480 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1481 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1482
1483 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1484 /* read twice */
1485
1486 bnx2x_cl45_read(bp, port,
1487 ext_phy_type,
1488 ext_phy_addr,
1489 MDIO_AN_DEVAD,
1490 MDIO_AN_REG_STATUS, &an_complete);
1491 bnx2x_cl45_read(bp, port,
1492 ext_phy_type,
1493 ext_phy_addr,
1494 MDIO_AN_DEVAD,
1495 MDIO_AN_REG_STATUS, &an_complete);
1496
1497 if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
1498 ret = 1;
1499 bnx2x_cl45_read(bp, port,
1500 ext_phy_type,
1501 ext_phy_addr,
1502 MDIO_AN_DEVAD,
1503 MDIO_AN_REG_ADV_PAUSE, &ld_pause);
1504 bnx2x_cl45_read(bp, port,
1505 ext_phy_type,
1506 ext_phy_addr,
1507 MDIO_AN_DEVAD,
1508 MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
1509 pause_result = (ld_pause &
1510 MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
1511 pause_result |= (lp_pause &
1512 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
1513 DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
1514 pause_result);
1515 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001516 if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001517 ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
1518 bnx2x_cl45_read(bp, port,
1519 ext_phy_type,
1520 ext_phy_addr,
1521 MDIO_AN_DEVAD,
1522 MDIO_AN_REG_CL37_FC_LD, &ld_pause);
1523
1524 bnx2x_cl45_read(bp, port,
1525 ext_phy_type,
1526 ext_phy_addr,
1527 MDIO_AN_DEVAD,
1528 MDIO_AN_REG_CL37_FC_LP, &lp_pause);
1529 pause_result = (ld_pause &
1530 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
1531 pause_result |= (lp_pause &
1532 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
1533
1534 bnx2x_pause_resolve(vars, pause_result);
1535 DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
1536 pause_result);
1537 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001538 }
1539 return ret;
1540}
1541
1542
1543static void bnx2x_flow_ctrl_resolve(struct link_params *params,
1544 struct link_vars *vars,
1545 u32 gp_status)
1546{
1547 struct bnx2x *bp = params->bp;
Eilon Greenstein3196a882008-08-13 15:58:49 -07001548 u16 ld_pause; /* local driver */
1549 u16 lp_pause; /* link partner */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001550 u16 pause_result;
1551
David S. Millerc0700f92008-12-16 23:53:20 -08001552 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001553
1554 /* resolve from gp_status in case of AN complete and not sgmii */
David S. Millerc0700f92008-12-16 23:53:20 -08001555 if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001556 (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
1557 (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
1558 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1559 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
1560 CL45_RD_OVER_CL22(bp, params->port,
1561 params->phy_addr,
1562 MDIO_REG_BANK_COMBO_IEEE0,
1563 MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
1564 &ld_pause);
1565 CL45_RD_OVER_CL22(bp, params->port,
1566 params->phy_addr,
1567 MDIO_REG_BANK_COMBO_IEEE0,
1568 MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
1569 &lp_pause);
1570 pause_result = (ld_pause &
1571 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
1572 pause_result |= (lp_pause &
1573 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
1574 DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
1575 bnx2x_pause_resolve(vars, pause_result);
David S. Millerc0700f92008-12-16 23:53:20 -08001576 } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001577 (bnx2x_ext_phy_resove_fc(params, vars))) {
1578 return;
1579 } else {
David S. Millerc0700f92008-12-16 23:53:20 -08001580 if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001581 vars->flow_ctrl = params->req_fc_auto_adv;
1582 else
1583 vars->flow_ctrl = params->req_flow_ctrl;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001584 }
1585 DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
1586}
1587
1588
1589static u8 bnx2x_link_settings_status(struct link_params *params,
1590 struct link_vars *vars,
1591 u32 gp_status)
1592{
1593 struct bnx2x *bp = params->bp;
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001594 u16 new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001595 u8 rc = 0;
1596 vars->link_status = 0;
1597
1598 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
1599 DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
1600 gp_status);
1601
1602 vars->phy_link_up = 1;
1603 vars->link_status |= LINK_STATUS_LINK_UP;
1604
1605 if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
1606 vars->duplex = DUPLEX_FULL;
1607 else
1608 vars->duplex = DUPLEX_HALF;
1609
1610 bnx2x_flow_ctrl_resolve(params, vars, gp_status);
1611
1612 switch (gp_status & GP_STATUS_SPEED_MASK) {
1613 case GP_STATUS_10M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001614 new_line_speed = SPEED_10;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001615 if (vars->duplex == DUPLEX_FULL)
1616 vars->link_status |= LINK_10TFD;
1617 else
1618 vars->link_status |= LINK_10THD;
1619 break;
1620
1621 case GP_STATUS_100M:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001622 new_line_speed = SPEED_100;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001623 if (vars->duplex == DUPLEX_FULL)
1624 vars->link_status |= LINK_100TXFD;
1625 else
1626 vars->link_status |= LINK_100TXHD;
1627 break;
1628
1629 case GP_STATUS_1G:
1630 case GP_STATUS_1G_KX:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001631 new_line_speed = SPEED_1000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001632 if (vars->duplex == DUPLEX_FULL)
1633 vars->link_status |= LINK_1000TFD;
1634 else
1635 vars->link_status |= LINK_1000THD;
1636 break;
1637
1638 case GP_STATUS_2_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001639 new_line_speed = SPEED_2500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001640 if (vars->duplex == DUPLEX_FULL)
1641 vars->link_status |= LINK_2500TFD;
1642 else
1643 vars->link_status |= LINK_2500THD;
1644 break;
1645
1646 case GP_STATUS_5G:
1647 case GP_STATUS_6G:
1648 DP(NETIF_MSG_LINK,
1649 "link speed unsupported gp_status 0x%x\n",
1650 gp_status);
1651 return -EINVAL;
1652 break;
1653 case GP_STATUS_10G_KX4:
1654 case GP_STATUS_10G_HIG:
1655 case GP_STATUS_10G_CX4:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001656 new_line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001657 vars->link_status |= LINK_10GTFD;
1658 break;
1659
1660 case GP_STATUS_12G_HIG:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001661 new_line_speed = SPEED_12000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001662 vars->link_status |= LINK_12GTFD;
1663 break;
1664
1665 case GP_STATUS_12_5G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001666 new_line_speed = SPEED_12500;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001667 vars->link_status |= LINK_12_5GTFD;
1668 break;
1669
1670 case GP_STATUS_13G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001671 new_line_speed = SPEED_13000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001672 vars->link_status |= LINK_13GTFD;
1673 break;
1674
1675 case GP_STATUS_15G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001676 new_line_speed = SPEED_15000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001677 vars->link_status |= LINK_15GTFD;
1678 break;
1679
1680 case GP_STATUS_16G:
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001681 new_line_speed = SPEED_16000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001682 vars->link_status |= LINK_16GTFD;
1683 break;
1684
1685 default:
1686 DP(NETIF_MSG_LINK,
1687 "link speed unsupported gp_status 0x%x\n",
1688 gp_status);
1689 return -EINVAL;
1690 break;
1691 }
1692
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00001693 /* Upon link speed change set the NIG into drain mode.
1694 Comes to deals with possible FIFO glitch due to clk change
1695 when speed is decreased without link down indicator */
1696 if (new_line_speed != vars->line_speed) {
1697 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
1698 + params->port*4, 0);
1699 msleep(1);
1700 }
1701 vars->line_speed = new_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001702 vars->link_status |= LINK_STATUS_SERDES_LINK;
1703
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001704 if ((params->req_line_speed == SPEED_AUTO_NEG) &&
1705 ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1706 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
1707 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein589abe32009-02-12 08:36:55 +00001708 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
1709 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
Eilon Greenstein28577182009-02-12 08:37:00 +00001710 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
1711 (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
1712 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001713 vars->autoneg = AUTO_NEG_ENABLED;
1714
1715 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
1716 vars->autoneg |= AUTO_NEG_COMPLETE;
1717 vars->link_status |=
1718 LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
1719 }
1720
1721 vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
1722 vars->link_status |=
1723 LINK_STATUS_PARALLEL_DETECTION_USED;
1724
1725 }
David S. Millerc0700f92008-12-16 23:53:20 -08001726 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001727 vars->link_status |=
1728 LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001729
David S. Millerc0700f92008-12-16 23:53:20 -08001730 if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07001731 vars->link_status |=
1732 LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001733
1734 } else { /* link_down */
1735 DP(NETIF_MSG_LINK, "phy link down\n");
1736
1737 vars->phy_link_up = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07001738
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001739 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08001740 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001741 vars->autoneg = AUTO_NEG_DISABLED;
1742 vars->mac_type = MAC_TYPE_NONE;
1743 }
1744
1745 DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n",
1746 gp_status, vars->phy_link_up, vars->line_speed);
1747 DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x"
1748 " autoneg 0x%x\n",
1749 vars->duplex,
1750 vars->flow_ctrl, vars->autoneg);
1751 DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
1752
1753 return rc;
1754}
1755
Eilon Greensteined8680a2009-02-12 08:37:12 +00001756static void bnx2x_set_gmii_tx_driver(struct link_params *params)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001757{
1758 struct bnx2x *bp = params->bp;
1759 u16 lp_up2;
1760 u16 tx_driver;
1761
1762 /* read precomp */
1763
1764 CL45_RD_OVER_CL22(bp, params->port,
1765 params->phy_addr,
1766 MDIO_REG_BANK_OVER_1G,
1767 MDIO_OVER_1G_LP_UP2, &lp_up2);
1768
1769 CL45_RD_OVER_CL22(bp, params->port,
1770 params->phy_addr,
1771 MDIO_REG_BANK_TX0,
1772 MDIO_TX0_TX_DRIVER, &tx_driver);
1773
1774 /* bits [10:7] at lp_up2, positioned at [15:12] */
1775 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1776 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1777 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1778
1779 if ((lp_up2 != 0) &&
1780 (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) {
1781 /* replace tx_driver bits [15:12] */
1782 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1783 tx_driver |= lp_up2;
1784 CL45_WR_OVER_CL22(bp, params->port,
1785 params->phy_addr,
1786 MDIO_REG_BANK_TX0,
1787 MDIO_TX0_TX_DRIVER, tx_driver);
1788 }
1789}
1790
1791static u8 bnx2x_emac_program(struct link_params *params,
1792 u32 line_speed, u32 duplex)
1793{
1794 struct bnx2x *bp = params->bp;
1795 u8 port = params->port;
1796 u16 mode = 0;
1797
1798 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1799 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1800 EMAC_REG_EMAC_MODE,
1801 (EMAC_MODE_25G_MODE |
1802 EMAC_MODE_PORT_MII_10M |
1803 EMAC_MODE_HALF_DUPLEX));
1804 switch (line_speed) {
1805 case SPEED_10:
1806 mode |= EMAC_MODE_PORT_MII_10M;
1807 break;
1808
1809 case SPEED_100:
1810 mode |= EMAC_MODE_PORT_MII;
1811 break;
1812
1813 case SPEED_1000:
1814 mode |= EMAC_MODE_PORT_GMII;
1815 break;
1816
1817 case SPEED_2500:
1818 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
1819 break;
1820
1821 default:
1822 /* 10G not valid for EMAC */
1823 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
1824 return -EINVAL;
1825 }
1826
1827 if (duplex == DUPLEX_HALF)
1828 mode |= EMAC_MODE_HALF_DUPLEX;
1829 bnx2x_bits_en(bp,
1830 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
1831 mode);
1832
1833 bnx2x_set_led(bp, params->port, LED_MODE_OPER,
1834 line_speed, params->hw_led_mode, params->chip_id);
1835 return 0;
1836}
1837
1838/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001839/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001840/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001841static void bnx2x_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001842{
1843 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001844 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001845 msleep(1);
1846 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001847 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001848}
1849
1850static void bnx2x_ext_phy_reset(struct link_params *params,
1851 struct link_vars *vars)
1852{
1853 struct bnx2x *bp = params->bp;
1854 u32 ext_phy_type;
1855 u8 ext_phy_addr = ((params->ext_phy_config &
1856 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1857 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1858 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
1859 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1860 /* The PHY reset is controled by GPIO 1
1861 * Give it 1ms of reset pulse
1862 */
1863 if (vars->phy_flags & PHY_XGXS_FLAG) {
1864
1865 switch (ext_phy_type) {
1866 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
1867 DP(NETIF_MSG_LINK, "XGXS Direct\n");
1868 break;
1869
1870 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
1871 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
1872 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
1873
1874 /* Restore normal power mode*/
1875 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001876 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1877 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001878
1879 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001880 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001881
1882 bnx2x_cl45_write(bp, params->port,
1883 ext_phy_type,
1884 ext_phy_addr,
1885 MDIO_PMA_DEVAD,
1886 MDIO_PMA_REG_CTRL, 0xa040);
1887 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00001888 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
1889
1890 /* Restore normal power mode*/
1891 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
1892 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1893 params->port);
1894
1895 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
1896 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1897 params->port);
1898
1899 bnx2x_cl45_write(bp, params->port,
1900 ext_phy_type,
1901 ext_phy_addr,
1902 MDIO_PMA_DEVAD,
1903 MDIO_PMA_REG_CTRL,
1904 1<<15);
1905
1906 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001907 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
1908 /* Unset Low Power Mode and SW reset */
1909 /* Restore normal power mode*/
1910 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001911 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1912 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001913
1914 DP(NETIF_MSG_LINK, "XGXS 8072\n");
1915 bnx2x_cl45_write(bp, params->port,
1916 ext_phy_type,
1917 ext_phy_addr,
1918 MDIO_PMA_DEVAD,
1919 MDIO_PMA_REG_CTRL,
1920 1<<15);
1921 break;
1922 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
1923 {
1924 u16 emac_base;
1925 emac_base = (params->port) ? GRCBASE_EMAC0 :
1926 GRCBASE_EMAC1;
1927
1928 /* Restore normal power mode*/
1929 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001930 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1931 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001932
1933 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001934 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1935 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001936
1937 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001938 }
1939 break;
1940
1941 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
1942 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
1943
1944 /* Restore normal power mode*/
1945 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001946 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1947 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001948
1949 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001950 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001951
1952 break;
1953
Eilon Greenstein28577182009-02-12 08:37:00 +00001954 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
1955
1956 /* Restore normal power mode*/
1957 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
1958 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1959 params->port);
1960
1961 /* HW reset */
1962 bnx2x_hw_reset(bp, params->port);
1963
1964 bnx2x_cl45_write(bp, params->port,
1965 ext_phy_type,
1966 ext_phy_addr,
1967 MDIO_PMA_DEVAD,
1968 MDIO_PMA_REG_CTRL,
1969 1<<15);
1970 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001971 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
1972 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
1973 break;
1974
1975 default:
1976 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
1977 params->ext_phy_config);
1978 break;
1979 }
1980
1981 } else { /* SerDes */
1982 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
1983 switch (ext_phy_type) {
1984 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
1985 DP(NETIF_MSG_LINK, "SerDes Direct\n");
1986 break;
1987
1988 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
1989 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001990 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001991 break;
1992
1993 default:
1994 DP(NETIF_MSG_LINK,
1995 "BAD SerDes ext_phy_config 0x%x\n",
1996 params->ext_phy_config);
1997 break;
1998 }
1999 }
2000}
2001
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002002
2003static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
2004 u32 shmem_base, u32 spirom_ver)
2005{
2006 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x\n",
2007 (u16)(spirom_ver>>16), (u16)spirom_ver);
2008 REG_WR(bp, shmem_base +
2009 offsetof(struct shmem_region,
2010 port_mb[port].ext_phy_fw_version),
2011 spirom_ver);
2012}
2013
2014static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
2015 u32 ext_phy_type, u8 ext_phy_addr,
2016 u32 shmem_base)
2017{
2018 u16 fw_ver1, fw_ver2;
2019 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2020 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2021 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2022 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2023 bnx2x_save_spirom_version(bp, port, shmem_base,
2024 (u32)(fw_ver1<<16 | fw_ver2));
2025}
2026
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002027static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
2028{
2029 struct bnx2x *bp = params->bp;
2030 u8 port = params->port;
2031 u8 ext_phy_addr = ((params->ext_phy_config &
2032 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2033 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2034 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002035
2036 /* Need to wait 200ms after reset */
2037 msleep(200);
2038 /* Boot port from external ROM
2039 * Set ser_boot_ctl bit in the MISC_CTRL1 register
2040 */
2041 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2042 MDIO_PMA_DEVAD,
2043 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2044
2045 /* Reset internal microprocessor */
2046 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2047 MDIO_PMA_DEVAD,
2048 MDIO_PMA_REG_GEN_CTRL,
2049 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2050 /* set micro reset = 0 */
2051 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2052 MDIO_PMA_DEVAD,
2053 MDIO_PMA_REG_GEN_CTRL,
2054 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2055 /* Reset internal microprocessor */
2056 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2057 MDIO_PMA_DEVAD,
2058 MDIO_PMA_REG_GEN_CTRL,
2059 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2060 /* wait for 100ms for code download via SPI port */
2061 msleep(100);
2062
2063 /* Clear ser_boot_ctl bit */
2064 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2065 MDIO_PMA_DEVAD,
2066 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2067 /* Wait 100ms */
2068 msleep(100);
2069
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002070 bnx2x_save_bcm_spirom_ver(bp, port,
2071 ext_phy_type,
2072 ext_phy_addr,
2073 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002074}
2075
2076static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2077{
2078 /* This is only required for 8073A1, version 102 only */
2079
2080 struct bnx2x *bp = params->bp;
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 u16 val;
2085
2086 /* Read 8073 HW revision*/
2087 bnx2x_cl45_read(bp, params->port,
2088 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2089 ext_phy_addr,
2090 MDIO_PMA_DEVAD,
2091 0xc801, &val);
2092
2093 if (val != 1) {
2094 /* No need to workaround in 8073 A1 */
2095 return 0;
2096 }
2097
2098 bnx2x_cl45_read(bp, params->port,
2099 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2100 ext_phy_addr,
2101 MDIO_PMA_DEVAD,
2102 MDIO_PMA_REG_ROM_VER2, &val);
2103
2104 /* SNR should be applied only for version 0x102 */
2105 if (val != 0x102)
2106 return 0;
2107
2108 return 1;
2109}
2110
2111static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2112{
2113 struct bnx2x *bp = params->bp;
2114 u8 ext_phy_addr = ((params->ext_phy_config &
2115 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2116 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2117 u16 val, cnt, cnt1 ;
2118
2119 bnx2x_cl45_read(bp, params->port,
2120 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2121 ext_phy_addr,
2122 MDIO_PMA_DEVAD,
2123 0xc801, &val);
2124
2125 if (val > 0) {
2126 /* No need to workaround in 8073 A1 */
2127 return 0;
2128 }
2129 /* XAUI workaround in 8073 A0: */
2130
2131 /* After loading the boot ROM and restarting Autoneg,
2132 poll Dev1, Reg $C820: */
2133
2134 for (cnt = 0; cnt < 1000; cnt++) {
2135 bnx2x_cl45_read(bp, params->port,
2136 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2137 ext_phy_addr,
2138 MDIO_PMA_DEVAD,
2139 0xc820, &val);
2140 /* If bit [14] = 0 or bit [13] = 0, continue on with
2141 system initialization (XAUI work-around not required,
2142 as these bits indicate 2.5G or 1G link up). */
2143 if (!(val & (1<<14)) || !(val & (1<<13))) {
2144 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2145 return 0;
2146 } else if (!(val & (1<<15))) {
2147 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2148 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2149 it's MSB (bit 15) goes to 1 (indicating that the
2150 XAUI workaround has completed),
2151 then continue on with system initialization.*/
2152 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2153 bnx2x_cl45_read(bp, params->port,
2154 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2155 ext_phy_addr,
2156 MDIO_PMA_DEVAD,
2157 0xc841, &val);
2158 if (val & (1<<15)) {
2159 DP(NETIF_MSG_LINK,
2160 "XAUI workaround has completed\n");
2161 return 0;
2162 }
2163 msleep(3);
2164 }
2165 break;
2166 }
2167 msleep(3);
2168 }
2169 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2170 return -EINVAL;
2171
2172}
2173
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002174static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002175 u8 ext_phy_addr, u32 shmem_base)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002176{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002177 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002178 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002179 bnx2x_cl45_write(bp, port,
2180 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2181 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002182 MDIO_PMA_DEVAD,
2183 MDIO_PMA_REG_GEN_CTRL,
2184 0x0001);
2185
2186 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002187 bnx2x_cl45_write(bp, port,
2188 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2189 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002190 MDIO_PMA_DEVAD,
2191 MDIO_PMA_REG_GEN_CTRL,
2192 0x008c);
2193
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002194 bnx2x_cl45_write(bp, port,
2195 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2196 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002197 MDIO_PMA_DEVAD,
2198 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2199
2200 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002201 bnx2x_cl45_write(bp, port,
2202 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2203 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002204 MDIO_PMA_DEVAD,
2205 MDIO_PMA_REG_GEN_CTRL,
2206 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2207
2208 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002209 bnx2x_cl45_write(bp, port,
2210 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2211 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002212 MDIO_PMA_DEVAD,
2213 MDIO_PMA_REG_GEN_CTRL,
2214 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2215
2216 /* wait for 100ms for code download via SPI port */
2217 msleep(100);
2218
2219 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002220 bnx2x_cl45_write(bp, port,
2221 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2222 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002223 MDIO_PMA_DEVAD,
2224 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2225
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002226 bnx2x_save_bcm_spirom_ver(bp, port,
2227 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2228 ext_phy_addr,
2229 shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002230}
2231
Eilon Greenstein589abe32009-02-12 08:36:55 +00002232static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
2233{
2234 struct bnx2x *bp = params->bp;
2235 u8 port = params->port;
2236 u8 ext_phy_addr = ((params->ext_phy_config &
2237 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2238 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2239 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2240
2241 /* Need to wait 100ms after reset */
2242 msleep(100);
2243
2244 /* Set serial boot control for external load */
2245 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2246 MDIO_PMA_DEVAD,
2247 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2248
2249 /* Micro controller re-boot */
2250 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2251 MDIO_PMA_DEVAD,
2252 MDIO_PMA_REG_GEN_CTRL,
2253 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2254
2255 /* Set soft reset */
2256 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2257 MDIO_PMA_DEVAD,
2258 MDIO_PMA_REG_GEN_CTRL,
2259 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2260
2261 /* Clear soft reset.
2262 Will automatically reset micro-controller re-boot */
2263 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2264 MDIO_PMA_DEVAD,
2265 MDIO_PMA_REG_GEN_CTRL,
2266 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2267
2268 /* wait for 100ms for microcode load */
2269 msleep(100);
2270
2271 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
2272 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2273 MDIO_PMA_DEVAD,
2274 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2275
2276 msleep(200);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002277 bnx2x_save_bcm_spirom_ver(bp, port,
2278 ext_phy_type,
2279 ext_phy_addr,
2280 params->shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002281}
2282
2283static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
2284 u8 ext_phy_addr, u8 tx_en)
2285{
2286 u16 val;
2287 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2288 tx_en, port);
2289 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
2290 bnx2x_cl45_read(bp, port,
2291 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2292 ext_phy_addr,
2293 MDIO_PMA_DEVAD,
2294 MDIO_PMA_REG_PHY_IDENTIFIER,
2295 &val);
2296
2297 if (tx_en)
2298 val &= ~(1<<15);
2299 else
2300 val |= (1<<15);
2301
2302 bnx2x_cl45_write(bp, port,
2303 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2304 ext_phy_addr,
2305 MDIO_PMA_DEVAD,
2306 MDIO_PMA_REG_PHY_IDENTIFIER,
2307 val);
2308}
2309
2310
2311static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
2312 u8 byte_cnt, u8 *o_buf) {
2313 struct bnx2x *bp = params->bp;
2314 u16 val, i;
2315 u8 port = params->port;
2316 u8 ext_phy_addr = ((params->ext_phy_config &
2317 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2318 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2319 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2320 if (byte_cnt > 16) {
2321 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2322 " is limited to 0xf\n");
2323 return -EINVAL;
2324 }
2325 /* Set the read command byte count */
2326 bnx2x_cl45_write(bp, port,
2327 ext_phy_type,
2328 ext_phy_addr,
2329 MDIO_PMA_DEVAD,
2330 MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
2331 (byte_cnt | 0xa000));
2332
2333 /* Set the read command address */
2334 bnx2x_cl45_write(bp, port,
2335 ext_phy_type,
2336 ext_phy_addr,
2337 MDIO_PMA_DEVAD,
2338 MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
2339 addr);
2340
2341 /* Activate read command */
2342 bnx2x_cl45_write(bp, port,
2343 ext_phy_type,
2344 ext_phy_addr,
2345 MDIO_PMA_DEVAD,
2346 MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
2347 0x2c0f);
2348
2349 /* Wait up to 500us for command complete status */
2350 for (i = 0; i < 100; i++) {
2351 bnx2x_cl45_read(bp, port,
2352 ext_phy_type,
2353 ext_phy_addr,
2354 MDIO_PMA_DEVAD,
2355 MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
2356 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
2357 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
2358 break;
2359 udelay(5);
2360 }
2361
2362 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
2363 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
2364 DP(NETIF_MSG_LINK,
2365 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2366 (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
2367 return -EINVAL;
2368 }
2369
2370 /* Read the buffer */
2371 for (i = 0; i < byte_cnt; i++) {
2372 bnx2x_cl45_read(bp, port,
2373 ext_phy_type,
2374 ext_phy_addr,
2375 MDIO_PMA_DEVAD,
2376 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2377 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2378 }
2379
2380 for (i = 0; i < 100; i++) {
2381 bnx2x_cl45_read(bp, port,
2382 ext_phy_type,
2383 ext_phy_addr,
2384 MDIO_PMA_DEVAD,
2385 MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
2386 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
2387 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
2388 return 0;;
2389 msleep(1);
2390 }
2391 return -EINVAL;
2392}
2393
2394
2395static u8 bnx2x_get_sfp_module_type(struct link_params *params,
2396 u8 *module_type)
2397{
2398 struct bnx2x *bp = params->bp;
2399 u8 val;
2400 *module_type = SFP_MODULE_TYPE_UNKNOWN;
2401
2402 /* First check for copper cable */
2403 if (bnx2x_read_sfp_module_eeprom(params,
2404 SFP_EEPROM_CON_TYPE_ADDR,
2405 1,
2406 &val) != 0) {
2407 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
2408 return -EINVAL;
2409 }
2410
2411 switch (val) {
2412 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2413 {
2414 u8 copper_module_type;
2415 /* Check if its active cable( includes SFP+ module)
2416 of passive cable*/
2417 if (bnx2x_read_sfp_module_eeprom(params,
2418 SFP_EEPROM_FC_TX_TECH_ADDR,
2419 1,
2420 &copper_module_type) !=
2421 0) {
2422 DP(NETIF_MSG_LINK,
2423 "Failed to read copper-cable-type"
2424 " from SFP+ EEPROM\n");
2425 return -EINVAL;
2426 }
2427
2428 if (copper_module_type &
2429 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2430 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
2431 *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
2432 } else if (copper_module_type &
2433 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2434 DP(NETIF_MSG_LINK, "Passive Copper"
2435 " cable detected\n");
2436 *module_type =
2437 SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
2438 } else {
2439 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2440 "type 0x%x !!!\n", copper_module_type);
2441 return -EINVAL;
2442 }
2443 break;
2444 }
2445 case SFP_EEPROM_CON_TYPE_VAL_LC:
2446 DP(NETIF_MSG_LINK, "Optic module detected\n");
2447 *module_type = SFP_MODULE_TYPE_LC;
2448 break;
2449
2450 default:
2451 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2452 val);
2453 return -EINVAL;
2454 }
2455 return 0;
2456}
2457
2458
2459/* This function read the relevant field from the module ( SFP+ ),
2460 and verify it is compliant with this board */
2461static u8 bnx2x_verify_sfp_module(struct link_params *params,
2462 u8 module_type)
2463{
2464 struct bnx2x *bp = params->bp;
2465 u8 *str_p, *tmp_buf;
2466 u16 i;
2467
2468#define COMPLIANCE_STR_CNT 6
2469 u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
2470 "FINISAR CORP. ", "Amphenol"};
2471 u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
2472 /* Passive Copper cables are allowed to participate,
2473 since the module is hardwired to the copper cable */
2474
2475 if (!(params->feature_config_flags &
2476 FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
2477 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2478 return 0;
2479 }
2480
2481 if (module_type != SFP_MODULE_TYPE_LC) {
2482 DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
2483 return 0;
2484 }
2485
2486 /* In case of non copper cable or Active copper cable,
2487 verify that the SFP+ module is compliant with this board*/
2488 if (bnx2x_read_sfp_module_eeprom(params,
2489 SFP_EEPROM_VENDOR_NAME_ADDR,
2490 SFP_EEPROM_VENDOR_NAME_SIZE,
2491 buf) != 0) {
2492 DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
2493 " module EEPROM\n");
2494 return -EINVAL;
2495 }
2496 for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
2497 str_p = compliance_str[i];
2498 tmp_buf = buf;
2499 while (*str_p) {
2500 if ((u8)(*tmp_buf) != (u8)(*str_p))
2501 break;
2502 str_p++;
2503 tmp_buf++;
2504 }
2505
2506 if (!(*str_p)) {
2507 DP(NETIF_MSG_LINK, "SFP+ Module verified, "
2508 "index=%x\n", i);
2509 return 0;
2510 }
2511 }
2512 DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
2513 return -EINVAL;
2514}
2515
2516
2517static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
2518 u8 module_type)
2519{
2520 struct bnx2x *bp = params->bp;
2521 u8 port = params->port;
2522 u8 options[SFP_EEPROM_OPTIONS_SIZE];
2523 u8 limiting_mode;
2524 u8 ext_phy_addr = ((params->ext_phy_config &
2525 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2526 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2527
2528 if (bnx2x_read_sfp_module_eeprom(params,
2529 SFP_EEPROM_OPTIONS_ADDR,
2530 SFP_EEPROM_OPTIONS_SIZE,
2531 options) != 0) {
2532 DP(NETIF_MSG_LINK, "Failed to read Option field from"
2533 " module EEPROM\n");
2534 return -EINVAL;
2535 }
2536 limiting_mode = !(options[0] &
2537 SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
2538 if (limiting_mode &&
2539 (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
2540 DP(NETIF_MSG_LINK,
2541 "Module options = 0x%x.Setting LIMITING MODE\n",
2542 options[0]);
2543 bnx2x_cl45_write(bp, port,
2544 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2545 ext_phy_addr,
2546 MDIO_PMA_DEVAD,
2547 MDIO_PMA_REG_ROM_VER2,
2548 SFP_LIMITING_MODE_VALUE);
2549 } else { /* LRM mode ( default )*/
2550 u16 cur_limiting_mode;
2551 DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
2552 options[0]);
2553
2554 bnx2x_cl45_read(bp, port,
2555 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2556 ext_phy_addr,
2557 MDIO_PMA_DEVAD,
2558 MDIO_PMA_REG_ROM_VER2,
2559 &cur_limiting_mode);
2560
2561 /* Changing to LRM mode takes quite few seconds.
2562 So do it only if current mode is limiting
2563 ( default is LRM )*/
2564 if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
2565 return 0;
2566
2567 bnx2x_cl45_write(bp, port,
2568 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2569 ext_phy_addr,
2570 MDIO_PMA_DEVAD,
2571 MDIO_PMA_REG_LRM_MODE,
2572 0);
2573 bnx2x_cl45_write(bp, port,
2574 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2575 ext_phy_addr,
2576 MDIO_PMA_DEVAD,
2577 MDIO_PMA_REG_ROM_VER2,
2578 0x128);
2579 bnx2x_cl45_write(bp, port,
2580 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2581 ext_phy_addr,
2582 MDIO_PMA_DEVAD,
2583 MDIO_PMA_REG_MISC_CTRL0,
2584 0x4008);
2585 bnx2x_cl45_write(bp, port,
2586 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2587 ext_phy_addr,
2588 MDIO_PMA_DEVAD,
2589 MDIO_PMA_REG_LRM_MODE,
2590 0xaaaa);
2591 }
2592 return 0;
2593}
2594
2595static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
2596{
2597 u8 val;
2598 struct bnx2x *bp = params->bp;
2599 u16 timeout;
2600 /* Initialization time after hot-plug may take up to 300ms for some
2601 phys type ( e.g. JDSU ) */
2602 for (timeout = 0; timeout < 60; timeout++) {
2603 if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
2604 == 0) {
2605 DP(NETIF_MSG_LINK, "SFP+ module initialization "
2606 "took %d ms\n", timeout * 5);
2607 return 0;
2608 }
2609 msleep(5);
2610 }
2611 return -EINVAL;
2612}
2613
2614static u8 bnx2x_sfp_module_detection(struct link_params *params)
2615{
2616 struct bnx2x *bp = params->bp;
2617 u8 module_type;
2618 u8 ext_phy_addr = ((params->ext_phy_config &
2619 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2620 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2621 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2622
2623 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
2624 DP(NETIF_MSG_LINK, "Module detection is not required "
2625 "for this phy\n");
2626 return 0;
2627 }
2628
2629 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
2630 params->port);
2631
2632 if (bnx2x_get_sfp_module_type(params,
2633 &module_type) != 0) {
2634 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
2635 if (!(params->feature_config_flags &
2636 FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
2637 /* In case module detection is disabled, it trys to
2638 link up. The issue that can happen here is LRM /
2639 LIMITING mode which set according to the module-type*/
2640 DP(NETIF_MSG_LINK, "Unable to read module-type."
2641 "Probably due to Bit Stretching."
2642 " Proceeding...\n");
2643 } else {
2644 return -EINVAL;
2645 }
2646 } else if (bnx2x_verify_sfp_module(params, module_type) !=
2647 0) {
2648 /* check SFP+ module compatibility */
2649 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
2650 /* Turn on fault module-detected led */
2651 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2652 MISC_REGISTERS_GPIO_HIGH,
2653 params->port);
2654 return -EINVAL;
2655 }
2656
2657 /* Turn off fault module-detected led */
2658 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2659 MISC_REGISTERS_GPIO_LOW,
2660 params->port);
2661
2662 /* Check and set limiting mode / LRM mode */
2663 if (bnx2x_bcm8726_set_limiting_mode(params, module_type)
2664 != 0) {
2665 DP(NETIF_MSG_LINK, "Setting limiting mode failed!!\n");
2666 return -EINVAL;
2667 }
2668
2669 /* Enable transmit for this module */
2670 bnx2x_bcm8726_set_transmitter(bp, params->port,
2671 ext_phy_addr, 1);
2672 return 0;
2673}
2674
2675void bnx2x_handle_module_detect_int(struct link_params *params)
2676{
2677 struct bnx2x *bp = params->bp;
2678 u32 gpio_val;
2679 u8 port = params->port;
2680 /* Set valid module led off */
2681 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2682 MISC_REGISTERS_GPIO_HIGH,
2683 params->port);
2684
2685 /* Get current gpio val refelecting module plugged in / out*/
2686 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
2687
2688 /* Call the handling function in case module is detected */
2689 if (gpio_val == 0) {
2690
2691 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
2692 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
2693 port);
2694
2695 if (bnx2x_wait_for_sfp_module_initialized(params)
2696 == 0)
2697 bnx2x_sfp_module_detection(params);
2698 else
2699 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
2700 } else {
2701 u8 ext_phy_addr = ((params->ext_phy_config &
2702 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2703 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2704 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
2705 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
2706 port);
2707 /* Module was plugged out. */
2708 /* Disable transmit for this module */
2709 bnx2x_bcm8726_set_transmitter(bp, params->port,
2710 ext_phy_addr, 0);
2711 }
2712}
2713
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002714static void bnx2x_bcm807x_force_10G(struct link_params *params)
2715{
2716 struct bnx2x *bp = params->bp;
2717 u8 port = params->port;
2718 u8 ext_phy_addr = ((params->ext_phy_config &
2719 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2720 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2721 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2722
2723 /* Force KR or KX */
2724 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2725 MDIO_PMA_DEVAD,
2726 MDIO_PMA_REG_CTRL,
2727 0x2040);
2728 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2729 MDIO_PMA_DEVAD,
2730 MDIO_PMA_REG_10G_CTRL2,
2731 0x000b);
2732 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2733 MDIO_PMA_DEVAD,
2734 MDIO_PMA_REG_BCM_CTRL,
2735 0x0000);
2736 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2737 MDIO_AN_DEVAD,
2738 MDIO_AN_REG_CTRL,
2739 0x0000);
2740}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002741static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
2742{
2743 struct bnx2x *bp = params->bp;
2744 u8 port = params->port;
2745 u16 val;
2746 u8 ext_phy_addr = ((params->ext_phy_config &
2747 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2748 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2749 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2750
2751 bnx2x_cl45_read(bp, params->port,
2752 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2753 ext_phy_addr,
2754 MDIO_PMA_DEVAD,
2755 0xc801, &val);
2756
2757 if (val == 0) {
2758 /* Mustn't set low power mode in 8073 A0 */
2759 return;
2760 }
2761
2762 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
2763 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2764 MDIO_XS_DEVAD,
2765 MDIO_XS_PLL_SEQUENCER, &val);
2766 val &= ~(1<<13);
2767 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2768 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2769
2770 /* PLL controls */
2771 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2772 MDIO_XS_DEVAD, 0x805E, 0x1077);
2773 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2774 MDIO_XS_DEVAD, 0x805D, 0x0000);
2775 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2776 MDIO_XS_DEVAD, 0x805C, 0x030B);
2777 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2778 MDIO_XS_DEVAD, 0x805B, 0x1240);
2779 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2780 MDIO_XS_DEVAD, 0x805A, 0x2490);
2781
2782 /* Tx Controls */
2783 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2784 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2785 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2786 MDIO_XS_DEVAD, 0x80A6, 0x9041);
2787 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2788 MDIO_XS_DEVAD, 0x80A5, 0x4640);
2789
2790 /* Rx Controls */
2791 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2792 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2793 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2794 MDIO_XS_DEVAD, 0x80FD, 0x9249);
2795 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2796 MDIO_XS_DEVAD, 0x80FC, 0x2015);
2797
2798 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
2799 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2800 MDIO_XS_DEVAD,
2801 MDIO_XS_PLL_SEQUENCER, &val);
2802 val |= (1<<13);
2803 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2804 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2805}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002806
2807static void bnx2x_8073_set_pause_cl37(struct link_params *params,
2808 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002809{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002810
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002811 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002812 u16 cl37_val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002813 u8 ext_phy_addr = ((params->ext_phy_config &
2814 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2815 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2816 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2817
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002818 bnx2x_cl45_read(bp, params->port,
2819 ext_phy_type,
2820 ext_phy_addr,
2821 MDIO_AN_DEVAD,
2822 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
2823
2824 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2825 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2826
2827 if ((vars->ieee_fc &
2828 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
2829 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
2830 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
2831 }
2832 if ((vars->ieee_fc &
2833 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2834 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2835 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2836 }
2837 if ((vars->ieee_fc &
2838 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2839 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2840 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2841 }
2842 DP(NETIF_MSG_LINK,
2843 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
2844
2845 bnx2x_cl45_write(bp, params->port,
2846 ext_phy_type,
2847 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002848 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002849 MDIO_AN_REG_CL37_FC_LD, cl37_val);
2850 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002851}
2852
2853static void bnx2x_ext_phy_set_pause(struct link_params *params,
2854 struct link_vars *vars)
2855{
2856 struct bnx2x *bp = params->bp;
2857 u16 val;
2858 u8 ext_phy_addr = ((params->ext_phy_config &
2859 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2860 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2861 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2862
2863 /* read modify write pause advertizing */
2864 bnx2x_cl45_read(bp, params->port,
2865 ext_phy_type,
2866 ext_phy_addr,
2867 MDIO_AN_DEVAD,
2868 MDIO_AN_REG_ADV_PAUSE, &val);
2869
2870 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002871
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002872 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2873
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002874 if ((vars->ieee_fc &
2875 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002876 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2877 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2878 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002879 if ((vars->ieee_fc &
2880 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002881 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2882 val |=
2883 MDIO_AN_REG_ADV_PAUSE_PAUSE;
2884 }
2885 DP(NETIF_MSG_LINK,
2886 "Ext phy AN advertize 0x%x\n", val);
2887 bnx2x_cl45_write(bp, params->port,
2888 ext_phy_type,
2889 ext_phy_addr,
2890 MDIO_AN_DEVAD,
2891 MDIO_AN_REG_ADV_PAUSE, val);
2892}
2893
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002894
2895static void bnx2x_init_internal_phy(struct link_params *params,
2896 struct link_vars *vars)
2897{
2898 struct bnx2x *bp = params->bp;
2899 u8 port = params->port;
2900 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
2901 u16 bank, rx_eq;
2902
2903 rx_eq = ((params->serdes_config &
2904 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >>
2905 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT);
2906
2907 DP(NETIF_MSG_LINK, "setting rx eq to 0x%x\n", rx_eq);
2908 for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL;
2909 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0)) {
2910 CL45_WR_OVER_CL22(bp, port,
2911 params->phy_addr,
2912 bank ,
2913 MDIO_RX0_RX_EQ_BOOST,
2914 ((rx_eq &
2915 MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) |
2916 MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL));
2917 }
2918
2919 /* forced speed requested? */
2920 if (vars->line_speed != SPEED_AUTO_NEG) {
2921 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2922
2923 /* disable autoneg */
2924 bnx2x_set_autoneg(params, vars);
2925
2926 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002927 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002928
2929 } else { /* AN_mode */
2930 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2931
2932 /* AN enabled */
2933 bnx2x_set_brcm_cl37_advertisment(params);
2934
2935 /* program duplex & pause advertisement (for aneg) */
2936 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002937 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002938
2939 /* enable autoneg */
2940 bnx2x_set_autoneg(params, vars);
2941
2942 /* enable and restart AN */
2943 bnx2x_restart_autoneg(params);
2944 }
2945
2946 } else { /* SGMII mode */
2947 DP(NETIF_MSG_LINK, "SGMII\n");
2948
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002949 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002950 }
2951}
2952
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002953static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
2954{
2955 struct bnx2x *bp = params->bp;
2956 u32 ext_phy_type;
2957 u8 ext_phy_addr;
2958 u16 cnt;
2959 u16 ctrl = 0;
2960 u16 val = 0;
2961 u8 rc = 0;
2962 if (vars->phy_flags & PHY_XGXS_FLAG) {
2963 ext_phy_addr = ((params->ext_phy_config &
2964 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2965 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2966
2967 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2968 /* Make sure that the soft reset is off (expect for the 8072:
2969 * due to the lock, it will be done inside the specific
2970 * handling)
2971 */
2972 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
2973 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
2974 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
2975 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
2976 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
2977 /* Wait for soft reset to get cleared upto 1 sec */
2978 for (cnt = 0; cnt < 1000; cnt++) {
2979 bnx2x_cl45_read(bp, params->port,
2980 ext_phy_type,
2981 ext_phy_addr,
2982 MDIO_PMA_DEVAD,
2983 MDIO_PMA_REG_CTRL, &ctrl);
2984 if (!(ctrl & (1<<15)))
2985 break;
2986 msleep(1);
2987 }
2988 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
2989 ctrl, cnt);
2990 }
2991
2992 switch (ext_phy_type) {
2993 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002994 break;
2995
2996 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
2997 DP(NETIF_MSG_LINK, "XGXS 8705\n");
2998
2999 bnx2x_cl45_write(bp, params->port,
3000 ext_phy_type,
3001 ext_phy_addr,
3002 MDIO_PMA_DEVAD,
3003 MDIO_PMA_REG_MISC_CTRL,
3004 0x8288);
3005 bnx2x_cl45_write(bp, params->port,
3006 ext_phy_type,
3007 ext_phy_addr,
3008 MDIO_PMA_DEVAD,
3009 MDIO_PMA_REG_PHY_IDENTIFIER,
3010 0x7fbf);
3011 bnx2x_cl45_write(bp, params->port,
3012 ext_phy_type,
3013 ext_phy_addr,
3014 MDIO_PMA_DEVAD,
3015 MDIO_PMA_REG_CMU_PLL_BYPASS,
3016 0x0100);
3017 bnx2x_cl45_write(bp, params->port,
3018 ext_phy_type,
3019 ext_phy_addr,
3020 MDIO_WIS_DEVAD,
3021 MDIO_WIS_REG_LASI_CNTL, 0x1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003022
3023 bnx2x_save_bcm_spirom_ver(bp, params->port,
3024 ext_phy_type,
3025 ext_phy_addr,
3026 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003027 break;
3028
3029 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003030 /* Wait until fw is loaded */
3031 for (cnt = 0; cnt < 100; cnt++) {
3032 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3033 ext_phy_addr, MDIO_PMA_DEVAD,
3034 MDIO_PMA_REG_ROM_VER1, &val);
3035 if (val)
3036 break;
3037 msleep(10);
3038 }
3039 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized "
3040 "after %d ms\n", cnt);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003041 /* Force speed */
3042 /* First enable LASI */
3043 bnx2x_cl45_write(bp, params->port,
3044 ext_phy_type,
3045 ext_phy_addr,
3046 MDIO_PMA_DEVAD,
3047 MDIO_PMA_REG_RX_ALARM_CTRL,
3048 0x0400);
3049 bnx2x_cl45_write(bp, params->port,
3050 ext_phy_type,
3051 ext_phy_addr,
3052 MDIO_PMA_DEVAD,
3053 MDIO_PMA_REG_LASI_CTRL, 0x0004);
3054
3055 if (params->req_line_speed == SPEED_10000) {
3056 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
3057
3058 bnx2x_cl45_write(bp, params->port,
3059 ext_phy_type,
3060 ext_phy_addr,
3061 MDIO_PMA_DEVAD,
3062 MDIO_PMA_REG_DIGITAL_CTRL,
3063 0x400);
3064 } else {
3065 /* Force 1Gbps using autoneg with 1G
3066 advertisment */
3067
3068 /* Allow CL37 through CL73 */
3069 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3070 bnx2x_cl45_write(bp, params->port,
3071 ext_phy_type,
3072 ext_phy_addr,
3073 MDIO_AN_DEVAD,
3074 MDIO_AN_REG_CL37_CL73,
3075 0x040c);
3076
3077 /* Enable Full-Duplex advertisment on CL37 */
3078 bnx2x_cl45_write(bp, params->port,
3079 ext_phy_type,
3080 ext_phy_addr,
3081 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003082 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003083 0x0020);
3084 /* Enable CL37 AN */
3085 bnx2x_cl45_write(bp, params->port,
3086 ext_phy_type,
3087 ext_phy_addr,
3088 MDIO_AN_DEVAD,
3089 MDIO_AN_REG_CL37_AN,
3090 0x1000);
3091 /* 1G support */
3092 bnx2x_cl45_write(bp, params->port,
3093 ext_phy_type,
3094 ext_phy_addr,
3095 MDIO_AN_DEVAD,
3096 MDIO_AN_REG_ADV, (1<<5));
3097
3098 /* Enable clause 73 AN */
3099 bnx2x_cl45_write(bp, params->port,
3100 ext_phy_type,
3101 ext_phy_addr,
3102 MDIO_AN_DEVAD,
3103 MDIO_AN_REG_CTRL,
3104 0x1200);
3105
3106 }
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003107 bnx2x_save_bcm_spirom_ver(bp, params->port,
3108 ext_phy_type,
3109 ext_phy_addr,
3110 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003111 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003112 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3113 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3114 bnx2x_bcm8726_external_rom_boot(params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003115
Eilon Greenstein589abe32009-02-12 08:36:55 +00003116 /* Need to call module detected on initialization since
3117 the module detection triggered by actual module
3118 insertion might occur before driver is loaded, and when
3119 driver is loaded, it reset all registers, including the
3120 transmitter */
3121 bnx2x_sfp_module_detection(params);
3122 if (params->req_line_speed == SPEED_1000) {
3123 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3124 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3125 ext_phy_addr, MDIO_PMA_DEVAD,
3126 MDIO_PMA_REG_CTRL, 0x40);
3127 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3128 ext_phy_addr, MDIO_PMA_DEVAD,
3129 MDIO_PMA_REG_10G_CTRL2, 0xD);
3130 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3131 ext_phy_addr, MDIO_PMA_DEVAD,
3132 MDIO_PMA_REG_LASI_CTRL, 0x5);
3133 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3134 ext_phy_addr, MDIO_PMA_DEVAD,
3135 MDIO_PMA_REG_RX_ALARM_CTRL,
3136 0x400);
3137 } else if ((params->req_line_speed ==
3138 SPEED_AUTO_NEG) &&
3139 ((params->speed_cap_mask &
3140 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
3141 DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
3142 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3143 ext_phy_addr, MDIO_AN_DEVAD,
3144 MDIO_AN_REG_ADV, 0x20);
3145 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3146 ext_phy_addr, MDIO_AN_DEVAD,
3147 MDIO_AN_REG_CL37_CL73, 0x040c);
3148 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3149 ext_phy_addr, MDIO_AN_DEVAD,
3150 MDIO_AN_REG_CL37_FC_LD, 0x0020);
3151 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3152 ext_phy_addr, MDIO_AN_DEVAD,
3153 MDIO_AN_REG_CL37_AN, 0x1000);
3154 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3155 ext_phy_addr, MDIO_AN_DEVAD,
3156 MDIO_AN_REG_CTRL, 0x1200);
3157
3158 /* Enable RX-ALARM control to receive
3159 interrupt for 1G speed change */
3160 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3161 ext_phy_addr, MDIO_PMA_DEVAD,
3162 MDIO_PMA_REG_LASI_CTRL, 0x4);
3163 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3164 ext_phy_addr, MDIO_PMA_DEVAD,
3165 MDIO_PMA_REG_RX_ALARM_CTRL,
3166 0x400);
3167
3168 } else { /* Default 10G. Set only LASI control */
3169 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3170 ext_phy_addr, MDIO_PMA_DEVAD,
3171 MDIO_PMA_REG_LASI_CTRL, 1);
3172 }
3173 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003174 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3175 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3176 {
3177 u16 tmp1;
3178 u16 rx_alarm_ctrl_val;
3179 u16 lasi_ctrl_val;
3180 if (ext_phy_type ==
3181 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3182 rx_alarm_ctrl_val = 0x400;
3183 lasi_ctrl_val = 0x0004;
3184 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003185 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003186 lasi_ctrl_val = 0x0004;
3187 }
3188
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003189 /* enable LASI */
3190 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003191 ext_phy_type,
3192 ext_phy_addr,
3193 MDIO_PMA_DEVAD,
3194 MDIO_PMA_REG_RX_ALARM_CTRL,
3195 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003196
3197 bnx2x_cl45_write(bp, params->port,
3198 ext_phy_type,
3199 ext_phy_addr,
3200 MDIO_PMA_DEVAD,
3201 MDIO_PMA_REG_LASI_CTRL,
3202 lasi_ctrl_val);
3203
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003204 bnx2x_8073_set_pause_cl37(params, vars);
3205
3206 if (ext_phy_type ==
3207 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){
3208 bnx2x_bcm8072_external_rom_boot(params);
3209 } else {
3210
3211 /* In case of 8073 with long xaui lines,
3212 don't set the 8073 xaui low power*/
3213 bnx2x_bcm8073_set_xaui_low_power_mode(params);
3214 }
3215
3216 bnx2x_cl45_read(bp, params->port,
3217 ext_phy_type,
3218 ext_phy_addr,
3219 MDIO_PMA_DEVAD,
3220 0xca13,
3221 &tmp1);
3222
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003223 bnx2x_cl45_read(bp, params->port,
3224 ext_phy_type,
3225 ext_phy_addr,
3226 MDIO_PMA_DEVAD,
3227 MDIO_PMA_REG_RX_ALARM, &tmp1);
3228
3229 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
3230 "0x%x\n", tmp1);
3231
3232 /* If this is forced speed, set to KR or KX
3233 * (all other are not supported)
3234 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003235 if (params->loopback_mode == LOOPBACK_EXT) {
3236 bnx2x_bcm807x_force_10G(params);
3237 DP(NETIF_MSG_LINK,
3238 "Forced speed 10G on 807X\n");
3239 break;
3240 } else {
3241 bnx2x_cl45_write(bp, params->port,
3242 ext_phy_type, ext_phy_addr,
3243 MDIO_PMA_DEVAD,
3244 MDIO_PMA_REG_BCM_CTRL,
3245 0x0002);
3246 }
3247 if (params->req_line_speed != SPEED_AUTO_NEG) {
3248 if (params->req_line_speed == SPEED_10000) {
3249 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003250 } else if (params->req_line_speed ==
3251 SPEED_2500) {
3252 val = (1<<5);
3253 /* Note that 2.5G works only
3254 when used with 1G advertisment */
3255 } else
3256 val = (1<<5);
3257 } else {
3258
3259 val = 0;
3260 if (params->speed_cap_mask &
3261 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3262 val |= (1<<7);
3263
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003264 /* Note that 2.5G works only when
3265 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003266 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003267 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3268 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003269 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003270 DP(NETIF_MSG_LINK,
3271 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003272 }
3273
3274 bnx2x_cl45_write(bp, params->port,
3275 ext_phy_type,
3276 ext_phy_addr,
3277 MDIO_AN_DEVAD,
3278 MDIO_AN_REG_ADV, val);
3279
3280 if (ext_phy_type ==
3281 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003282
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003283 bnx2x_cl45_read(bp, params->port,
3284 ext_phy_type,
3285 ext_phy_addr,
3286 MDIO_AN_DEVAD,
3287 0x8329, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003288
3289 if (((params->speed_cap_mask &
3290 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3291 (params->req_line_speed ==
3292 SPEED_AUTO_NEG)) ||
3293 (params->req_line_speed ==
3294 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003295 u16 phy_ver;
3296 /* Allow 2.5G for A1 and above */
3297 bnx2x_cl45_read(bp, params->port,
3298 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
3299 ext_phy_addr,
3300 MDIO_PMA_DEVAD,
3301 0xc801, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003302 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003303 if (phy_ver > 0)
3304 tmp1 |= 1;
3305 else
3306 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003307 } else {
3308 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003309 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003310 }
3311
3312 bnx2x_cl45_write(bp, params->port,
3313 ext_phy_type,
3314 ext_phy_addr,
3315 MDIO_AN_DEVAD,
3316 0x8329, tmp1);
3317 }
3318
3319 /* Add support for CL37 (passive mode) II */
3320
3321 bnx2x_cl45_read(bp, params->port,
3322 ext_phy_type,
3323 ext_phy_addr,
3324 MDIO_AN_DEVAD,
3325 MDIO_AN_REG_CL37_FC_LD,
3326 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003327
3328 bnx2x_cl45_write(bp, params->port,
3329 ext_phy_type,
3330 ext_phy_addr,
3331 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003332 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
3333 ((params->req_duplex == DUPLEX_FULL) ?
3334 0x20 : 0x40)));
3335
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003336 /* Add support for CL37 (passive mode) III */
3337 bnx2x_cl45_write(bp, params->port,
3338 ext_phy_type,
3339 ext_phy_addr,
3340 MDIO_AN_DEVAD,
3341 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003342
3343 if (ext_phy_type ==
3344 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003345 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003346 BW and FEE main tap. Rest commands are executed
3347 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003348 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003349 if (bnx2x_8073_is_snr_needed(params))
3350 bnx2x_cl45_write(bp, params->port,
3351 ext_phy_type,
3352 ext_phy_addr,
3353 MDIO_PMA_DEVAD,
3354 MDIO_PMA_REG_EDC_FFE_MAIN,
3355 0xFB0C);
3356
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003357 /* Enable FEC (Forware Error Correction)
3358 Request in the AN */
3359 bnx2x_cl45_read(bp, params->port,
3360 ext_phy_type,
3361 ext_phy_addr,
3362 MDIO_AN_DEVAD,
3363 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003364
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003365 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003366
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003367 bnx2x_cl45_write(bp, params->port,
3368 ext_phy_type,
3369 ext_phy_addr,
3370 MDIO_AN_DEVAD,
3371 MDIO_AN_REG_ADV2, tmp1);
3372
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003373 }
3374
3375 bnx2x_ext_phy_set_pause(params, vars);
3376
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003377 /* Restart autoneg */
3378 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003379 bnx2x_cl45_write(bp, params->port,
3380 ext_phy_type,
3381 ext_phy_addr,
3382 MDIO_AN_DEVAD,
3383 MDIO_AN_REG_CTRL, 0x1200);
3384 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
3385 "Advertise 1G=%x, 10G=%x\n",
3386 ((val & (1<<5)) > 0),
3387 ((val & (1<<7)) > 0));
3388 break;
3389 }
3390 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003391 {
3392 u16 fw_ver1, fw_ver2;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003393 DP(NETIF_MSG_LINK,
3394 "Setting the SFX7101 LASI indication\n");
3395
3396 bnx2x_cl45_write(bp, params->port,
3397 ext_phy_type,
3398 ext_phy_addr,
3399 MDIO_PMA_DEVAD,
3400 MDIO_PMA_REG_LASI_CTRL, 0x1);
3401 DP(NETIF_MSG_LINK,
3402 "Setting the SFX7101 LED to blink on traffic\n");
3403 bnx2x_cl45_write(bp, params->port,
3404 ext_phy_type,
3405 ext_phy_addr,
3406 MDIO_PMA_DEVAD,
3407 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
3408
3409 bnx2x_ext_phy_set_pause(params, vars);
3410 /* Restart autoneg */
3411 bnx2x_cl45_read(bp, params->port,
3412 ext_phy_type,
3413 ext_phy_addr,
3414 MDIO_AN_DEVAD,
3415 MDIO_AN_REG_CTRL, &val);
3416 val |= 0x200;
3417 bnx2x_cl45_write(bp, params->port,
3418 ext_phy_type,
3419 ext_phy_addr,
3420 MDIO_AN_DEVAD,
3421 MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003422
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003423 /* Save spirom version */
3424 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3425 ext_phy_addr, MDIO_PMA_DEVAD,
3426 MDIO_PMA_REG_7101_VER1, &fw_ver1);
3427
3428 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3429 ext_phy_addr, MDIO_PMA_DEVAD,
3430 MDIO_PMA_REG_7101_VER2, &fw_ver2);
3431
3432 bnx2x_save_spirom_version(params->bp, params->port,
3433 params->shmem_base,
3434 (u32)(fw_ver1<<16 | fw_ver2));
3435
Eilon Greenstein28577182009-02-12 08:37:00 +00003436 break;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003437 }
Eilon Greenstein28577182009-02-12 08:37:00 +00003438 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
3439 DP(NETIF_MSG_LINK,
3440 "Setting the BCM8481 LASI control\n");
3441
3442 bnx2x_cl45_write(bp, params->port,
3443 ext_phy_type,
3444 ext_phy_addr,
3445 MDIO_PMA_DEVAD,
3446 MDIO_PMA_REG_LASI_CTRL, 0x1);
3447
3448 /* Restart autoneg */
3449 bnx2x_cl45_read(bp, params->port,
3450 ext_phy_type,
3451 ext_phy_addr,
3452 MDIO_AN_DEVAD,
3453 MDIO_AN_REG_CTRL, &val);
3454 val |= 0x200;
3455 bnx2x_cl45_write(bp, params->port,
3456 ext_phy_type,
3457 ext_phy_addr,
3458 MDIO_AN_DEVAD,
3459 MDIO_AN_REG_CTRL, val);
3460
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003461 bnx2x_save_bcm_spirom_ver(bp, params->port,
3462 ext_phy_type,
3463 ext_phy_addr,
3464 params->shmem_base);
3465
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003466 break;
3467 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
3468 DP(NETIF_MSG_LINK,
3469 "XGXS PHY Failure detected 0x%x\n",
3470 params->ext_phy_config);
3471 rc = -EINVAL;
3472 break;
3473 default:
3474 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3475 params->ext_phy_config);
3476 rc = -EINVAL;
3477 break;
3478 }
3479
3480 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003481
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003482 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3483 switch (ext_phy_type) {
3484 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3485 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3486 break;
3487
3488 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3489 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3490 break;
3491
3492 default:
3493 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
3494 params->ext_phy_config);
3495 break;
3496 }
3497 }
3498 return rc;
3499}
3500
3501
3502static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003503 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003504{
3505 struct bnx2x *bp = params->bp;
3506 u32 ext_phy_type;
3507 u8 ext_phy_addr;
3508 u16 val1 = 0, val2;
3509 u16 rx_sd, pcs_status;
3510 u8 ext_phy_link_up = 0;
3511 u8 port = params->port;
3512 if (vars->phy_flags & PHY_XGXS_FLAG) {
3513 ext_phy_addr = ((params->ext_phy_config &
3514 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3515 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3516
3517 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3518 switch (ext_phy_type) {
3519 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3520 DP(NETIF_MSG_LINK, "XGXS Direct\n");
3521 ext_phy_link_up = 1;
3522 break;
3523
3524 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3525 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3526 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3527 ext_phy_addr,
3528 MDIO_WIS_DEVAD,
3529 MDIO_WIS_REG_LASI_STATUS, &val1);
3530 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3531
3532 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3533 ext_phy_addr,
3534 MDIO_WIS_DEVAD,
3535 MDIO_WIS_REG_LASI_STATUS, &val1);
3536 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3537
3538 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3539 ext_phy_addr,
3540 MDIO_PMA_DEVAD,
3541 MDIO_PMA_REG_RX_SD, &rx_sd);
3542 DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
3543 ext_phy_link_up = (rx_sd & 0x1);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003544 if (ext_phy_link_up)
3545 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003546 break;
3547
3548 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00003549 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3550 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
3551 /* Clear RX Alarm*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003552 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3553 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00003554 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
3555 &val2);
3556 /* clear LASI indication*/
3557 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3558 ext_phy_addr,
3559 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
3560 &val1);
3561 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3562 ext_phy_addr,
3563 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
3564 &val2);
3565 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
3566 "0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003567
3568 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3569 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00003570 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
3571 &rx_sd);
3572 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3573 ext_phy_addr,
3574 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
3575 &pcs_status);
3576 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3577 ext_phy_addr,
3578 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
3579 &val2);
3580 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3581 ext_phy_addr,
3582 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
3583 &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003584
Eilon Greenstein589abe32009-02-12 08:36:55 +00003585 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003586 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
3587 rx_sd, pcs_status, val2);
3588 /* link is up if both bit 0 of pmd_rx_sd and
3589 * bit 0 of pcs_status are set, or if the autoneg bit
3590 1 is set
3591 */
3592 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
3593 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003594 if (ext_phy_link_up) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003595 if (ext_phy_type ==
3596 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
3597 /* If transmitter is disabled,
3598 ignore false link up indication */
3599 bnx2x_cl45_read(bp, params->port,
3600 ext_phy_type,
3601 ext_phy_addr,
3602 MDIO_PMA_DEVAD,
3603 MDIO_PMA_REG_PHY_IDENTIFIER,
3604 &val1);
3605 if (val1 & (1<<15)) {
3606 DP(NETIF_MSG_LINK, "Tx is "
3607 "disabled\n");
3608 ext_phy_link_up = 0;
3609 break;
3610 }
3611 }
3612
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003613 if (val2 & (1<<1))
3614 vars->line_speed = SPEED_1000;
3615 else
3616 vars->line_speed = SPEED_10000;
3617 }
3618
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003619 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003620 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3621 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3622 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003623 u16 link_status = 0;
3624 u16 an1000_status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003625 if (ext_phy_type ==
3626 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3627 bnx2x_cl45_read(bp, params->port,
3628 ext_phy_type,
3629 ext_phy_addr,
3630 MDIO_PCS_DEVAD,
3631 MDIO_PCS_REG_LASI_STATUS, &val1);
3632 bnx2x_cl45_read(bp, params->port,
3633 ext_phy_type,
3634 ext_phy_addr,
3635 MDIO_PCS_DEVAD,
3636 MDIO_PCS_REG_LASI_STATUS, &val2);
3637 DP(NETIF_MSG_LINK,
3638 "870x LASI status 0x%x->0x%x\n",
3639 val1, val2);
3640
3641 } else {
3642 /* In 8073, port1 is directed through emac0 and
3643 * port0 is directed through emac1
3644 */
3645 bnx2x_cl45_read(bp, params->port,
3646 ext_phy_type,
3647 ext_phy_addr,
3648 MDIO_PMA_DEVAD,
3649 MDIO_PMA_REG_LASI_STATUS, &val1);
3650
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003651 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003652 "8703 LASI status 0x%x\n",
3653 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003654 }
3655
3656 /* clear the interrupt LASI status register */
3657 bnx2x_cl45_read(bp, params->port,
3658 ext_phy_type,
3659 ext_phy_addr,
3660 MDIO_PCS_DEVAD,
3661 MDIO_PCS_REG_STATUS, &val2);
3662 bnx2x_cl45_read(bp, params->port,
3663 ext_phy_type,
3664 ext_phy_addr,
3665 MDIO_PCS_DEVAD,
3666 MDIO_PCS_REG_STATUS, &val1);
3667 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
3668 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003669 /* Clear MSG-OUT */
3670 bnx2x_cl45_read(bp, params->port,
3671 ext_phy_type,
3672 ext_phy_addr,
3673 MDIO_PMA_DEVAD,
3674 0xca13,
3675 &val1);
3676
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003677 /* Check the LASI */
3678 bnx2x_cl45_read(bp, params->port,
3679 ext_phy_type,
3680 ext_phy_addr,
3681 MDIO_PMA_DEVAD,
3682 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003683
3684 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3685
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003686 /* Check the link status */
3687 bnx2x_cl45_read(bp, params->port,
3688 ext_phy_type,
3689 ext_phy_addr,
3690 MDIO_PCS_DEVAD,
3691 MDIO_PCS_REG_STATUS, &val2);
3692 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3693
3694 bnx2x_cl45_read(bp, params->port,
3695 ext_phy_type,
3696 ext_phy_addr,
3697 MDIO_PMA_DEVAD,
3698 MDIO_PMA_REG_STATUS, &val2);
3699 bnx2x_cl45_read(bp, params->port,
3700 ext_phy_type,
3701 ext_phy_addr,
3702 MDIO_PMA_DEVAD,
3703 MDIO_PMA_REG_STATUS, &val1);
3704 ext_phy_link_up = ((val1 & 4) == 4);
3705 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3706 if (ext_phy_type ==
3707 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003708
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003709 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003710 ((params->req_line_speed !=
3711 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003712 if (bnx2x_bcm8073_xaui_wa(params)
3713 != 0) {
3714 ext_phy_link_up = 0;
3715 break;
3716 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003717 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003718 bnx2x_cl45_read(bp, params->port,
3719 ext_phy_type,
3720 ext_phy_addr,
3721 MDIO_AN_DEVAD,
3722 0x8304,
3723 &an1000_status);
3724 bnx2x_cl45_read(bp, params->port,
3725 ext_phy_type,
3726 ext_phy_addr,
3727 MDIO_AN_DEVAD,
3728 0x8304,
3729 &an1000_status);
3730
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003731 /* Check the link status on 1.1.2 */
3732 bnx2x_cl45_read(bp, params->port,
3733 ext_phy_type,
3734 ext_phy_addr,
3735 MDIO_PMA_DEVAD,
3736 MDIO_PMA_REG_STATUS, &val2);
3737 bnx2x_cl45_read(bp, params->port,
3738 ext_phy_type,
3739 ext_phy_addr,
3740 MDIO_PMA_DEVAD,
3741 MDIO_PMA_REG_STATUS, &val1);
3742 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3743 "an_link_status=0x%x\n",
3744 val2, val1, an1000_status);
3745
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003746 ext_phy_link_up = (((val1 & 4) == 4) ||
3747 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003748 if (ext_phy_link_up &&
3749 bnx2x_8073_is_snr_needed(params)) {
3750 /* The SNR will improve about 2dbby
3751 changing the BW and FEE main tap.*/
3752
3753 /* The 1st write to change FFE main
3754 tap is set before restart AN */
3755 /* Change PLL Bandwidth in EDC
3756 register */
3757 bnx2x_cl45_write(bp, port, ext_phy_type,
3758 ext_phy_addr,
3759 MDIO_PMA_DEVAD,
3760 MDIO_PMA_REG_PLL_BANDWIDTH,
3761 0x26BC);
3762
3763 /* Change CDR Bandwidth in EDC
3764 register */
3765 bnx2x_cl45_write(bp, port, ext_phy_type,
3766 ext_phy_addr,
3767 MDIO_PMA_DEVAD,
3768 MDIO_PMA_REG_CDR_BANDWIDTH,
3769 0x0333);
3770
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003771
3772 }
3773 bnx2x_cl45_read(bp, params->port,
3774 ext_phy_type,
3775 ext_phy_addr,
3776 MDIO_PMA_DEVAD,
3777 0xc820,
3778 &link_status);
3779
3780 /* Bits 0..2 --> speed detected,
3781 bits 13..15--> link is down */
3782 if ((link_status & (1<<2)) &&
3783 (!(link_status & (1<<15)))) {
3784 ext_phy_link_up = 1;
3785 vars->line_speed = SPEED_10000;
3786 DP(NETIF_MSG_LINK,
3787 "port %x: External link"
3788 " up in 10G\n", params->port);
3789 } else if ((link_status & (1<<1)) &&
3790 (!(link_status & (1<<14)))) {
3791 ext_phy_link_up = 1;
3792 vars->line_speed = SPEED_2500;
3793 DP(NETIF_MSG_LINK,
3794 "port %x: External link"
3795 " up in 2.5G\n", params->port);
3796 } else if ((link_status & (1<<0)) &&
3797 (!(link_status & (1<<13)))) {
3798 ext_phy_link_up = 1;
3799 vars->line_speed = SPEED_1000;
3800 DP(NETIF_MSG_LINK,
3801 "port %x: External link"
3802 " up in 1G\n", params->port);
3803 } else {
3804 ext_phy_link_up = 0;
3805 DP(NETIF_MSG_LINK,
3806 "port %x: External link"
3807 " is down\n", params->port);
3808 }
3809 } else {
3810 /* See if 1G link is up for the 8072 */
3811 bnx2x_cl45_read(bp, params->port,
3812 ext_phy_type,
3813 ext_phy_addr,
3814 MDIO_AN_DEVAD,
3815 0x8304,
3816 &an1000_status);
3817 bnx2x_cl45_read(bp, params->port,
3818 ext_phy_type,
3819 ext_phy_addr,
3820 MDIO_AN_DEVAD,
3821 0x8304,
3822 &an1000_status);
3823 if (an1000_status & (1<<1)) {
3824 ext_phy_link_up = 1;
3825 vars->line_speed = SPEED_1000;
3826 DP(NETIF_MSG_LINK,
3827 "port %x: External link"
3828 " up in 1G\n", params->port);
3829 } else if (ext_phy_link_up) {
3830 ext_phy_link_up = 1;
3831 vars->line_speed = SPEED_10000;
3832 DP(NETIF_MSG_LINK,
3833 "port %x: External link"
3834 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003835 }
3836 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003837
3838
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003839 break;
3840 }
3841 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3842 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3843 ext_phy_addr,
3844 MDIO_PMA_DEVAD,
3845 MDIO_PMA_REG_LASI_STATUS, &val2);
3846 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3847 ext_phy_addr,
3848 MDIO_PMA_DEVAD,
3849 MDIO_PMA_REG_LASI_STATUS, &val1);
3850 DP(NETIF_MSG_LINK,
3851 "10G-base-T LASI status 0x%x->0x%x\n",
3852 val2, val1);
3853 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3854 ext_phy_addr,
3855 MDIO_PMA_DEVAD,
3856 MDIO_PMA_REG_STATUS, &val2);
3857 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3858 ext_phy_addr,
3859 MDIO_PMA_DEVAD,
3860 MDIO_PMA_REG_STATUS, &val1);
3861 DP(NETIF_MSG_LINK,
3862 "10G-base-T PMA status 0x%x->0x%x\n",
3863 val2, val1);
3864 ext_phy_link_up = ((val1 & 4) == 4);
3865 /* if link is up
3866 * print the AN outcome of the SFX7101 PHY
3867 */
3868 if (ext_phy_link_up) {
3869 bnx2x_cl45_read(bp, params->port,
3870 ext_phy_type,
3871 ext_phy_addr,
3872 MDIO_AN_DEVAD,
3873 MDIO_AN_REG_MASTER_STATUS,
3874 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003875 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003876 DP(NETIF_MSG_LINK,
3877 "SFX7101 AN status 0x%x->Master=%x\n",
3878 val2,
3879 (val2 & (1<<14)));
3880 }
3881 break;
Eilon Greenstein28577182009-02-12 08:37:00 +00003882 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
3883 /* Clear LASI interrupt */
3884 bnx2x_cl45_read(bp, params->port,
3885 ext_phy_type,
3886 ext_phy_addr,
3887 MDIO_PMA_DEVAD,
3888 MDIO_PMA_REG_LASI_STATUS, &val1);
3889 DP(NETIF_MSG_LINK, "8481 LASI status reg = 0x%x\n",
3890 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003891
Eilon Greenstein28577182009-02-12 08:37:00 +00003892 /* Check 10G-BaseT link status */
3893 /* Check Global PMD signal ok */
3894 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3895 ext_phy_addr,
3896 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
3897 &rx_sd);
3898 /* Check PCS block lock */
3899 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3900 ext_phy_addr,
3901 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
3902 &pcs_status);
3903 DP(NETIF_MSG_LINK, "8481 1.a = 0x%x, 1.20 = 0x%x\n",
3904 rx_sd, pcs_status);
3905 if (rx_sd & pcs_status & 0x1) {
3906 vars->line_speed = SPEED_10000;
3907 ext_phy_link_up = 1;
3908 } else {
3909
3910 /* Check 1000-BaseT link status */
3911 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3912 ext_phy_addr,
3913 MDIO_AN_DEVAD, 0xFFE1,
3914 &val1);
3915
3916 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3917 ext_phy_addr,
3918 MDIO_AN_DEVAD, 0xFFE1,
3919 &val2);
3920 DP(NETIF_MSG_LINK, "8481 7.FFE1 ="
3921 "0x%x-->0x%x\n", val1, val2);
3922 if (val2 & (1<<2)) {
3923 vars->line_speed = SPEED_1000;
3924 ext_phy_link_up = 1;
3925 }
3926 }
3927
3928 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003929 default:
3930 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3931 params->ext_phy_config);
3932 ext_phy_link_up = 0;
3933 break;
3934 }
3935
3936 } else { /* SerDes */
3937 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3938 switch (ext_phy_type) {
3939 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3940 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3941 ext_phy_link_up = 1;
3942 break;
3943
3944 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3945 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3946 ext_phy_link_up = 1;
3947 break;
3948
3949 default:
3950 DP(NETIF_MSG_LINK,
3951 "BAD SerDes ext_phy_config 0x%x\n",
3952 params->ext_phy_config);
3953 ext_phy_link_up = 0;
3954 break;
3955 }
3956 }
3957
3958 return ext_phy_link_up;
3959}
3960
3961static void bnx2x_link_int_enable(struct link_params *params)
3962{
3963 u8 port = params->port;
3964 u32 ext_phy_type;
3965 u32 mask;
3966 struct bnx2x *bp = params->bp;
3967 /* setting the status to report on link up
3968 for either XGXS or SerDes */
3969
3970 if (params->switch_cfg == SWITCH_CFG_10G) {
3971 mask = (NIG_MASK_XGXS0_LINK10G |
3972 NIG_MASK_XGXS0_LINK_STATUS);
3973 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
3974 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3975 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
3976 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
3977 (ext_phy_type !=
3978 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
3979 mask |= NIG_MASK_MI_INT;
3980 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3981 }
3982
3983 } else { /* SerDes */
3984 mask = NIG_MASK_SERDES0_LINK_STATUS;
3985 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
3986 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3987 if ((ext_phy_type !=
3988 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
3989 (ext_phy_type !=
3990 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
3991 mask |= NIG_MASK_MI_INT;
3992 DP(NETIF_MSG_LINK, "enabled external phy int\n");
3993 }
3994 }
3995 bnx2x_bits_en(bp,
3996 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
3997 mask);
3998 DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port,
3999 (params->switch_cfg == SWITCH_CFG_10G),
4000 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
4001
4002 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
4003 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4004 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4005 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
4006 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4007 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4008 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4009}
4010
4011
4012/*
4013 * link management
4014 */
4015static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07004016 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004017{
4018 struct bnx2x *bp = params->bp;
4019 u8 port = params->port;
4020
4021 /* first reset all status
4022 * we assume only one line will be change at a time */
4023 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4024 (NIG_STATUS_XGXS0_LINK10G |
4025 NIG_STATUS_XGXS0_LINK_STATUS |
4026 NIG_STATUS_SERDES0_LINK_STATUS));
4027 if (vars->phy_link_up) {
4028 if (is_10g) {
4029 /* Disable the 10G link interrupt
4030 * by writing 1 to the status register
4031 */
4032 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
4033 bnx2x_bits_en(bp,
4034 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4035 NIG_STATUS_XGXS0_LINK10G);
4036
4037 } else if (params->switch_cfg == SWITCH_CFG_10G) {
4038 /* Disable the link interrupt
4039 * by writing 1 to the relevant lane
4040 * in the status register
4041 */
4042 u32 ser_lane = ((params->lane_config &
4043 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
4044 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
4045
4046 DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
4047 bnx2x_bits_en(bp,
4048 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4049 ((1 << ser_lane) <<
4050 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
4051
4052 } else { /* SerDes */
4053 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
4054 /* Disable the link interrupt
4055 * by writing 1 to the status register
4056 */
4057 bnx2x_bits_en(bp,
4058 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4059 NIG_STATUS_SERDES0_LINK_STATUS);
4060 }
4061
4062 } else { /* link_down */
4063 }
4064}
4065
4066static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
4067{
4068 u8 *str_ptr = str;
4069 u32 mask = 0xf0000000;
4070 u8 shift = 8*4;
4071 u8 digit;
4072 if (len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02004073 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004074 *str_ptr = '\0';
4075 return -EINVAL;
4076 }
4077 while (shift > 0) {
4078
4079 shift -= 4;
4080 digit = ((num & mask) >> shift);
4081 if (digit < 0xa)
4082 *str_ptr = digit + '0';
4083 else
4084 *str_ptr = digit - 0xa + 'a';
4085 str_ptr++;
4086 mask = mask >> 4;
4087 if (shift == 4*4) {
4088 *str_ptr = ':';
4089 str_ptr++;
4090 }
4091 }
4092 *str_ptr = '\0';
4093 return 0;
4094}
4095
4096
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004097static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr,
4098 u32 ext_phy_type)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004099{
4100 u32 cnt = 0;
4101 u16 ctrl = 0;
4102 /* Enable EMAC0 in to enable MDIO */
4103 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
4104 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
4105 msleep(5);
4106
4107 /* take ext phy out of reset */
4108 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004109 MISC_REGISTERS_GPIO_2,
4110 MISC_REGISTERS_GPIO_HIGH,
4111 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004112
4113 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004114 MISC_REGISTERS_GPIO_1,
4115 MISC_REGISTERS_GPIO_HIGH,
4116 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004117
4118 /* wait for 5ms */
4119 msleep(5);
4120
4121 for (cnt = 0; cnt < 1000; cnt++) {
4122 msleep(1);
4123 bnx2x_cl45_read(bp, port,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004124 ext_phy_type,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004125 ext_phy_addr,
4126 MDIO_PMA_DEVAD,
4127 MDIO_PMA_REG_CTRL,
4128 &ctrl);
4129 if (!(ctrl & (1<<15))) {
4130 DP(NETIF_MSG_LINK, "Reset completed\n\n");
4131 break;
4132 }
4133 }
4134}
4135
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004136static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004137{
4138 /* put sf to reset */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004139 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004140 MISC_REGISTERS_GPIO_1,
4141 MISC_REGISTERS_GPIO_LOW,
4142 port);
4143 bnx2x_set_gpio(bp,
4144 MISC_REGISTERS_GPIO_2,
4145 MISC_REGISTERS_GPIO_LOW,
4146 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004147}
4148
4149u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
4150 u8 *version, u16 len)
4151{
4152 struct bnx2x *bp = params->bp;
4153 u32 ext_phy_type = 0;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004154 u32 spirom_ver = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004155 u8 status = 0 ;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004156
4157 if (version == NULL || params == NULL)
4158 return -EINVAL;
4159
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004160 spirom_ver = REG_RD(bp, params->shmem_base +
4161 offsetof(struct shmem_region,
4162 port_mb[params->port].ext_phy_fw_version));
4163
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004164 /* reset the returned value to zero */
4165 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004166 switch (ext_phy_type) {
4167 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4168
4169 if (len < 5)
4170 return -EINVAL;
4171
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004172 version[0] = (spirom_ver & 0xFF);
4173 version[1] = (spirom_ver & 0xFF00) >> 8;
4174 version[2] = (spirom_ver & 0xFF0000) >> 16;
4175 version[3] = (spirom_ver & 0xFF000000) >> 24;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004176 version[4] = '\0';
4177
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004178 break;
4179 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4180 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004181 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4182 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00004183 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004184 status = bnx2x_format_ver(spirom_ver, version, len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004185 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004186 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4187 break;
4188
4189 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4190 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
4191 " type is FAILURE!\n");
4192 status = -EINVAL;
4193 break;
4194
4195 default:
4196 break;
4197 }
4198 return status;
4199}
4200
4201static void bnx2x_set_xgxs_loopback(struct link_params *params,
4202 struct link_vars *vars,
4203 u8 is_10g)
4204{
4205 u8 port = params->port;
4206 struct bnx2x *bp = params->bp;
4207
4208 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07004209 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004210
4211 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
4212
4213 /* change the uni_phy_addr in the nig */
4214 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
4215 port*0x18));
4216
4217 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
4218
4219 bnx2x_cl45_write(bp, port, 0,
4220 params->phy_addr,
4221 5,
4222 (MDIO_REG_BANK_AER_BLOCK +
4223 (MDIO_AER_BLOCK_AER_REG & 0xf)),
4224 0x2800);
4225
4226 bnx2x_cl45_write(bp, port, 0,
4227 params->phy_addr,
4228 5,
4229 (MDIO_REG_BANK_CL73_IEEEB0 +
4230 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
4231 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00004232 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004233 /* set aer mmd back */
4234 bnx2x_set_aer_mmd(params, vars);
4235
4236 /* and md_devad */
4237 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
4238 md_devad);
4239
4240 } else {
4241 u16 mii_control;
4242
4243 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
4244
4245 CL45_RD_OVER_CL22(bp, port,
4246 params->phy_addr,
4247 MDIO_REG_BANK_COMBO_IEEE0,
4248 MDIO_COMBO_IEEE0_MII_CONTROL,
4249 &mii_control);
4250
4251 CL45_WR_OVER_CL22(bp, port,
4252 params->phy_addr,
4253 MDIO_REG_BANK_COMBO_IEEE0,
4254 MDIO_COMBO_IEEE0_MII_CONTROL,
4255 (mii_control |
4256 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
4257 }
4258}
4259
4260
4261static void bnx2x_ext_phy_loopback(struct link_params *params)
4262{
4263 struct bnx2x *bp = params->bp;
4264 u8 ext_phy_addr;
4265 u32 ext_phy_type;
4266
4267 if (params->switch_cfg == SWITCH_CFG_10G) {
4268 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4269 /* CL37 Autoneg Enabled */
4270 ext_phy_addr = ((params->ext_phy_config &
4271 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4272 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4273 switch (ext_phy_type) {
4274 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4275 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
4276 DP(NETIF_MSG_LINK,
4277 "ext_phy_loopback: We should not get here\n");
4278 break;
4279 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4280 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
4281 break;
4282 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
4283 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
4284 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00004285 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4286 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4287 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4288 ext_phy_addr,
4289 MDIO_PMA_DEVAD,
4290 MDIO_PMA_REG_CTRL,
4291 0x0001);
4292 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004293 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4294 /* SFX7101_XGXS_TEST1 */
4295 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4296 ext_phy_addr,
4297 MDIO_XS_DEVAD,
4298 MDIO_XS_SFX7101_XGXS_TEST1,
4299 0x100);
4300 DP(NETIF_MSG_LINK,
4301 "ext_phy_loopback: set ext phy loopback\n");
4302 break;
4303 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4304
4305 break;
4306 } /* switch external PHY type */
4307 } else {
4308 /* serdes */
4309 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4310 ext_phy_addr = (params->ext_phy_config &
4311 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
4312 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
4313 }
4314}
4315
4316
4317/*
4318 *------------------------------------------------------------------------
4319 * bnx2x_override_led_value -
4320 *
4321 * Override the led value of the requsted led
4322 *
4323 *------------------------------------------------------------------------
4324 */
4325u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
4326 u32 led_idx, u32 value)
4327{
4328 u32 reg_val;
4329
4330 /* If port 0 then use EMAC0, else use EMAC1*/
4331 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
4332
4333 DP(NETIF_MSG_LINK,
4334 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
4335 port, led_idx, value);
4336
4337 switch (led_idx) {
4338 case 0: /* 10MB led */
4339 /* Read the current value of the LED register in
4340 the EMAC block */
4341 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4342 /* Set the OVERRIDE bit to 1 */
4343 reg_val |= EMAC_LED_OVERRIDE;
4344 /* If value is 1, set the 10M_OVERRIDE bit,
4345 otherwise reset it.*/
4346 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
4347 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
4348 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4349 break;
4350 case 1: /*100MB led */
4351 /*Read the current value of the LED register in
4352 the EMAC block */
4353 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4354 /* Set the OVERRIDE bit to 1 */
4355 reg_val |= EMAC_LED_OVERRIDE;
4356 /* If value is 1, set the 100M_OVERRIDE bit,
4357 otherwise reset it.*/
4358 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
4359 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
4360 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4361 break;
4362 case 2: /* 1000MB led */
4363 /* Read the current value of the LED register in the
4364 EMAC block */
4365 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4366 /* Set the OVERRIDE bit to 1 */
4367 reg_val |= EMAC_LED_OVERRIDE;
4368 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
4369 reset it. */
4370 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
4371 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
4372 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4373 break;
4374 case 3: /* 2500MB led */
4375 /* Read the current value of the LED register in the
4376 EMAC block*/
4377 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4378 /* Set the OVERRIDE bit to 1 */
4379 reg_val |= EMAC_LED_OVERRIDE;
4380 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
4381 reset it.*/
4382 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
4383 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
4384 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4385 break;
4386 case 4: /*10G led */
4387 if (port == 0) {
4388 REG_WR(bp, NIG_REG_LED_10G_P0,
4389 value);
4390 } else {
4391 REG_WR(bp, NIG_REG_LED_10G_P1,
4392 value);
4393 }
4394 break;
4395 case 5: /* TRAFFIC led */
4396 /* Find if the traffic control is via BMAC or EMAC */
4397 if (port == 0)
4398 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
4399 else
4400 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
4401
4402 /* Override the traffic led in the EMAC:*/
4403 if (reg_val == 1) {
4404 /* Read the current value of the LED register in
4405 the EMAC block */
4406 reg_val = REG_RD(bp, emac_base +
4407 EMAC_REG_EMAC_LED);
4408 /* Set the TRAFFIC_OVERRIDE bit to 1 */
4409 reg_val |= EMAC_LED_OVERRIDE;
4410 /* If value is 1, set the TRAFFIC bit, otherwise
4411 reset it.*/
4412 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
4413 (reg_val & ~EMAC_LED_TRAFFIC);
4414 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4415 } else { /* Override the traffic led in the BMAC: */
4416 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4417 + port*4, 1);
4418 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
4419 value);
4420 }
4421 break;
4422 default:
4423 DP(NETIF_MSG_LINK,
4424 "bnx2x_override_led_value() unknown led index %d "
4425 "(should be 0-5)\n", led_idx);
4426 return -EINVAL;
4427 }
4428
4429 return 0;
4430}
4431
4432
4433u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
4434 u16 hw_led_mode, u32 chip_id)
4435{
4436 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004437 u32 tmp;
4438 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004439 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
4440 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
4441 speed, hw_led_mode);
4442 switch (mode) {
4443 case LED_MODE_OFF:
4444 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
4445 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4446 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004447
4448 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004449 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004450 break;
4451
4452 case LED_MODE_OPER:
4453 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
4454 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
4455 port*4, 0);
4456 /* Set blinking rate to ~15.9Hz */
4457 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
4458 LED_BLINK_RATE_VAL);
4459 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
4460 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004461 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004462 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004463 (tmp & (~EMAC_LED_OVERRIDE)));
4464
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004465 if (!CHIP_IS_E1H(bp) &&
4466 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004467 (speed == SPEED_1000) ||
4468 (speed == SPEED_100) ||
4469 (speed == SPEED_10))) {
4470 /* On Everest 1 Ax chip versions for speeds less than
4471 10G LED scheme is different */
4472 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4473 + port*4, 1);
4474 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
4475 port*4, 0);
4476 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
4477 port*4, 1);
4478 }
4479 break;
4480
4481 default:
4482 rc = -EINVAL;
4483 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
4484 mode);
4485 break;
4486 }
4487 return rc;
4488
4489}
4490
4491u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
4492{
4493 struct bnx2x *bp = params->bp;
4494 u16 gp_status = 0;
4495
4496 CL45_RD_OVER_CL22(bp, params->port,
4497 params->phy_addr,
4498 MDIO_REG_BANK_GP_STATUS,
4499 MDIO_GP_STATUS_TOP_AN_STATUS1,
4500 &gp_status);
4501 /* link is up only if both local phy and external phy are up */
4502 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
4503 bnx2x_ext_phy_is_link_up(params, vars))
4504 return 0;
4505
4506 return -ESRCH;
4507}
4508
4509static u8 bnx2x_link_initialize(struct link_params *params,
4510 struct link_vars *vars)
4511{
4512 struct bnx2x *bp = params->bp;
4513 u8 port = params->port;
4514 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004515 u8 non_ext_phy;
4516 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004517 /* Activate the external PHY */
4518 bnx2x_ext_phy_reset(params, vars);
4519
4520 bnx2x_set_aer_mmd(params, vars);
4521
4522 if (vars->phy_flags & PHY_XGXS_FLAG)
4523 bnx2x_set_master_ln(params);
4524
4525 rc = bnx2x_reset_unicore(params);
4526 /* reset the SerDes and wait for reset bit return low */
4527 if (rc != 0)
4528 return rc;
4529
4530 bnx2x_set_aer_mmd(params, vars);
4531
4532 /* setting the masterLn_def again after the reset */
4533 if (vars->phy_flags & PHY_XGXS_FLAG) {
4534 bnx2x_set_master_ln(params);
4535 bnx2x_set_swap_lanes(params);
4536 }
4537
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004538 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00004539 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004540 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00004541 (params->req_line_speed == SPEED_10))) ||
4542 (!params->req_line_speed &&
4543 (params->speed_cap_mask >=
4544 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
4545 (params->speed_cap_mask <
4546 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
4547 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004548 vars->phy_flags |= PHY_SGMII_FLAG;
4549 } else {
4550 vars->phy_flags &= ~PHY_SGMII_FLAG;
4551 }
4552 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004553 /* In case of external phy existance, the line speed would be the
4554 line speed linked up by the external phy. In case it is direct only,
4555 then the line_speed during initialization will be equal to the
4556 req_line_speed*/
4557 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004558
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004559 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004560
4561 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004562 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
4563 (params->loopback_mode == LOOPBACK_XGXS_10) ||
4564 (params->loopback_mode == LOOPBACK_EXT_PHY));
4565
4566 if (non_ext_phy ||
Eilon Greenstein589abe32009-02-12 08:36:55 +00004567 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Eilon Greenstein28577182009-02-12 08:37:00 +00004568 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
4569 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004570 if (params->req_line_speed == SPEED_AUTO_NEG)
4571 bnx2x_set_parallel_detection(params, vars->phy_flags);
4572 bnx2x_init_internal_phy(params, vars);
4573 }
4574
4575 if (!non_ext_phy)
4576 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004577
4578 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004579 (NIG_STATUS_XGXS0_LINK10G |
4580 NIG_STATUS_XGXS0_LINK_STATUS |
4581 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004582
4583 return rc;
4584
4585}
4586
4587
4588u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
4589{
4590 struct bnx2x *bp = params->bp;
4591
4592 u32 val;
Eilon Greenstein3196a882008-08-13 15:58:49 -07004593 DP(NETIF_MSG_LINK, "Phy Initialization started \n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004594 DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
4595 params->req_line_speed, params->req_flow_ctrl);
4596 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004597 vars->phy_link_up = 0;
4598 vars->link_up = 0;
4599 vars->line_speed = 0;
4600 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004601 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004602 vars->mac_type = MAC_TYPE_NONE;
4603
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004604 if (params->switch_cfg == SWITCH_CFG_1G)
4605 vars->phy_flags = PHY_SERDES_FLAG;
4606 else
4607 vars->phy_flags = PHY_XGXS_FLAG;
4608
Eilon Greenstein3196a882008-08-13 15:58:49 -07004609
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004610 /* disable attentions */
4611 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
4612 (NIG_MASK_XGXS0_LINK_STATUS |
4613 NIG_MASK_XGXS0_LINK10G |
4614 NIG_MASK_SERDES0_LINK_STATUS |
4615 NIG_MASK_MI_INT));
4616
4617 bnx2x_emac_init(params, vars);
4618
4619 if (CHIP_REV_IS_FPGA(bp)) {
4620 vars->link_up = 1;
4621 vars->line_speed = SPEED_10000;
4622 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004623 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004624 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004625 /* enable on E1.5 FPGA */
4626 if (CHIP_IS_E1H(bp)) {
4627 vars->flow_ctrl |=
David S. Millerc0700f92008-12-16 23:53:20 -08004628 (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004629 vars->link_status |=
4630 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
4631 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
4632 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004633
4634 bnx2x_emac_enable(params, vars, 0);
4635 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4636 /* disable drain */
4637 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4638 + params->port*4, 0);
4639
4640 /* update shared memory */
4641 bnx2x_update_mng(params, vars->link_status);
4642
4643 return 0;
4644
4645 } else
4646 if (CHIP_REV_IS_EMUL(bp)) {
4647
4648 vars->link_up = 1;
4649 vars->line_speed = SPEED_10000;
4650 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004651 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004652 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
4653
4654 bnx2x_bmac_enable(params, vars, 0);
4655
4656 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4657 /* Disable drain */
4658 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4659 + params->port*4, 0);
4660
4661 /* update shared memory */
4662 bnx2x_update_mng(params, vars->link_status);
4663
4664 return 0;
4665
4666 } else
4667 if (params->loopback_mode == LOOPBACK_BMAC) {
4668 vars->link_up = 1;
4669 vars->line_speed = SPEED_10000;
4670 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004671 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004672 vars->mac_type = MAC_TYPE_BMAC;
4673
4674 vars->phy_flags = PHY_XGXS_FLAG;
4675
4676 bnx2x_phy_deassert(params, vars->phy_flags);
4677 /* set bmac loopback */
4678 bnx2x_bmac_enable(params, vars, 1);
4679
4680 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4681 params->port*4, 0);
4682 } else if (params->loopback_mode == LOOPBACK_EMAC) {
4683 vars->link_up = 1;
4684 vars->line_speed = SPEED_1000;
4685 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004686 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004687 vars->mac_type = MAC_TYPE_EMAC;
4688
4689 vars->phy_flags = PHY_XGXS_FLAG;
4690
4691 bnx2x_phy_deassert(params, vars->phy_flags);
4692 /* set bmac loopback */
4693 bnx2x_emac_enable(params, vars, 1);
4694 bnx2x_emac_program(params, vars->line_speed,
4695 vars->duplex);
4696 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4697 params->port*4, 0);
4698 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
4699 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
4700 vars->link_up = 1;
4701 vars->line_speed = SPEED_10000;
4702 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004703 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004704
4705 vars->phy_flags = PHY_XGXS_FLAG;
4706
4707 val = REG_RD(bp,
4708 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4709 params->port*0x18);
4710 params->phy_addr = (u8)val;
4711
4712 bnx2x_phy_deassert(params, vars->phy_flags);
4713 bnx2x_link_initialize(params, vars);
4714
4715 vars->mac_type = MAC_TYPE_BMAC;
4716
4717 bnx2x_bmac_enable(params, vars, 0);
4718
4719 if (params->loopback_mode == LOOPBACK_XGXS_10) {
4720 /* set 10G XGXS loopback */
4721 bnx2x_set_xgxs_loopback(params, vars, 1);
4722 } else {
4723 /* set external phy loopback */
4724 bnx2x_ext_phy_loopback(params);
4725 }
4726 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4727 params->port*4, 0);
4728 } else
4729 /* No loopback */
4730 {
4731
4732 bnx2x_phy_deassert(params, vars->phy_flags);
4733 switch (params->switch_cfg) {
4734 case SWITCH_CFG_1G:
4735 vars->phy_flags |= PHY_SERDES_FLAG;
4736 if ((params->ext_phy_config &
4737 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
4738 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
4739 vars->phy_flags |=
4740 PHY_SGMII_FLAG;
4741 }
4742
4743 val = REG_RD(bp,
4744 NIG_REG_SERDES0_CTRL_PHY_ADDR+
4745 params->port*0x10);
4746
4747 params->phy_addr = (u8)val;
4748
4749 break;
4750 case SWITCH_CFG_10G:
4751 vars->phy_flags |= PHY_XGXS_FLAG;
4752 val = REG_RD(bp,
4753 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4754 params->port*0x18);
4755 params->phy_addr = (u8)val;
4756
4757 break;
4758 default:
4759 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
4760 return -EINVAL;
4761 break;
4762 }
4763
4764 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004765 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004766 bnx2x_link_int_enable(params);
4767 }
4768 return 0;
4769}
4770
Eilon Greenstein589abe32009-02-12 08:36:55 +00004771static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
4772{
4773 DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
4774
4775 /* Set serial boot control for external load */
4776 bnx2x_cl45_write(bp, port,
4777 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
4778 MDIO_PMA_DEVAD,
4779 MDIO_PMA_REG_GEN_CTRL, 0x0001);
4780
4781 /* Disable Transmitter */
4782 bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
4783
4784}
4785
4786u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
4787 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004788{
4789
4790 struct bnx2x *bp = params->bp;
4791 u32 ext_phy_config = params->ext_phy_config;
4792 u16 hw_led_mode = params->hw_led_mode;
4793 u32 chip_id = params->chip_id;
4794 u8 port = params->port;
4795 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4796 /* disable attentions */
4797
4798 vars->link_status = 0;
4799 bnx2x_update_mng(params, vars->link_status);
4800 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4801 (NIG_MASK_XGXS0_LINK_STATUS |
4802 NIG_MASK_XGXS0_LINK10G |
4803 NIG_MASK_SERDES0_LINK_STATUS |
4804 NIG_MASK_MI_INT));
4805
4806 /* activate nig drain */
4807 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4808
4809 /* disable nig egress interface */
4810 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4811 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4812
4813 /* Stop BigMac rx */
4814 bnx2x_bmac_rx_disable(bp, port);
4815
4816 /* disable emac */
4817 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4818
4819 msleep(10);
4820 /* The PHY reset is controled by GPIO 1
4821 * Hold it as vars low
4822 */
4823 /* clear link led */
4824 bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
Eilon Greenstein589abe32009-02-12 08:36:55 +00004825 if (reset_ext_phy) {
4826 switch (ext_phy_type) {
4827 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4828 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4829 break;
4830 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4831 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
4832 "low power mode\n",
4833 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004834 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004835 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4836 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00004837 break;
4838 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4839 {
4840 u8 ext_phy_addr = ((params->ext_phy_config &
4841 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4842 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4843 /* Set soft reset */
4844 bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
4845 break;
4846 }
4847 default:
4848 /* HW reset */
4849 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4850 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4851 port);
4852 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4853 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4854 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004855 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004856 }
4857 }
4858 /* reset the SerDes/XGXS */
4859 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
4860 (0x1ff << (port*16)));
4861
4862 /* reset BigMac */
4863 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
4864 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4865
4866 /* disable nig ingress interface */
4867 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
4868 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
4869 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4870 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4871 vars->link_up = 0;
4872 return 0;
4873}
4874
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004875static u8 bnx2x_update_link_down(struct link_params *params,
4876 struct link_vars *vars)
4877{
4878 struct bnx2x *bp = params->bp;
4879 u8 port = params->port;
4880 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
4881 bnx2x_set_led(bp, port, LED_MODE_OFF,
4882 0, params->hw_led_mode,
4883 params->chip_id);
4884
4885 /* indicate no mac active */
4886 vars->mac_type = MAC_TYPE_NONE;
4887
4888 /* update shared memory */
4889 vars->link_status = 0;
4890 vars->line_speed = 0;
4891 bnx2x_update_mng(params, vars->link_status);
4892
4893 /* activate nig drain */
4894 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4895
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004896 /* disable emac */
4897 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4898
4899 msleep(10);
4900
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004901 /* reset BigMac */
4902 bnx2x_bmac_rx_disable(bp, params->port);
4903 REG_WR(bp, GRCBASE_MISC +
4904 MISC_REGISTERS_RESET_REG_2_CLEAR,
4905 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4906 return 0;
4907}
4908
4909static u8 bnx2x_update_link_up(struct link_params *params,
4910 struct link_vars *vars,
4911 u8 link_10g, u32 gp_status)
4912{
4913 struct bnx2x *bp = params->bp;
4914 u8 port = params->port;
4915 u8 rc = 0;
4916 vars->link_status |= LINK_STATUS_LINK_UP;
4917 if (link_10g) {
4918 bnx2x_bmac_enable(params, vars, 0);
4919 bnx2x_set_led(bp, port, LED_MODE_OPER,
4920 SPEED_10000, params->hw_led_mode,
4921 params->chip_id);
4922
4923 } else {
4924 bnx2x_emac_enable(params, vars, 0);
4925 rc = bnx2x_emac_program(params, vars->line_speed,
4926 vars->duplex);
4927
4928 /* AN complete? */
4929 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
4930 if (!(vars->phy_flags &
4931 PHY_SGMII_FLAG))
Eilon Greensteined8680a2009-02-12 08:37:12 +00004932 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004933 }
4934 }
4935
4936 /* PBF - link up */
4937 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
4938 vars->line_speed);
4939
4940 /* disable drain */
4941 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
4942
4943 /* update shared memory */
4944 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004945 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004946 return rc;
4947}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004948/* This function should called upon link interrupt */
4949/* In case vars->link_up, driver needs to
4950 1. Update the pbf
4951 2. Disable drain
4952 3. Update the shared memory
4953 4. Indicate link up
4954 5. Set LEDs
4955 Otherwise,
4956 1. Update shared memory
4957 2. Reset BigMac
4958 3. Report link down
4959 4. Unset LEDs
4960*/
4961u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
4962{
4963 struct bnx2x *bp = params->bp;
4964 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004965 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004966 u8 link_10g;
4967 u8 ext_phy_link_up, rc = 0;
4968 u32 ext_phy_type;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004969
4970 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
4971 port,
4972 (vars->phy_flags & PHY_XGXS_FLAG),
4973 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
4974
4975 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
4976 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4977 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4978 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
4979
4980 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4981 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4982 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4983
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004984 /* disable emac */
4985 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4986
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004987 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004988
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004989 /* Check external link change only for non-direct */
4990 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
4991
4992 /* Read gp_status */
4993 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
4994 MDIO_REG_BANK_GP_STATUS,
4995 MDIO_GP_STATUS_TOP_AN_STATUS1,
4996 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004997
4998 rc = bnx2x_link_settings_status(params, vars, gp_status);
4999 if (rc != 0)
5000 return rc;
5001
5002 /* anything 10 and over uses the bmac */
5003 link_10g = ((vars->line_speed == SPEED_10000) ||
5004 (vars->line_speed == SPEED_12000) ||
5005 (vars->line_speed == SPEED_12500) ||
5006 (vars->line_speed == SPEED_13000) ||
5007 (vars->line_speed == SPEED_15000) ||
5008 (vars->line_speed == SPEED_16000));
5009
5010 bnx2x_link_int_ack(params, vars, link_10g);
5011
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005012 /* In case external phy link is up, and internal link is down
5013 ( not initialized yet probably after link initialization, it needs
5014 to be initialized.
5015 Note that after link down-up as result of cable plug,
5016 the xgxs link would probably become up again without the need to
5017 initialize it*/
5018
5019 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
5020 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
Eilon Greenstein589abe32009-02-12 08:36:55 +00005021 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005022 (ext_phy_link_up && !vars->phy_link_up))
5023 bnx2x_init_internal_phy(params, vars);
5024
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005025 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005026 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005027
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005028 if (vars->link_up)
5029 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
5030 else
5031 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005032
5033 return rc;
5034}
5035
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005036static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5037{
5038 u8 ext_phy_addr[PORT_MAX];
5039 u16 val;
5040 s8 port;
5041
5042 /* PART1 - Reset both phys */
5043 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5044 /* Extract the ext phy address for the port */
5045 u32 ext_phy_config = REG_RD(bp, shmem_base +
5046 offsetof(struct shmem_region,
5047 dev_info.port_hw_config[port].external_phy_config));
5048
5049 /* disable attentions */
5050 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5051 (NIG_MASK_XGXS0_LINK_STATUS |
5052 NIG_MASK_XGXS0_LINK10G |
5053 NIG_MASK_SERDES0_LINK_STATUS |
5054 NIG_MASK_MI_INT));
5055
5056 ext_phy_addr[port] =
5057 ((ext_phy_config &
5058 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5059 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5060
5061 /* Need to take the phy out of low power mode in order
5062 to write to access its registers */
5063 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5064 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
5065
5066 /* Reset the phy */
5067 bnx2x_cl45_write(bp, port,
5068 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5069 ext_phy_addr[port],
5070 MDIO_PMA_DEVAD,
5071 MDIO_PMA_REG_CTRL,
5072 1<<15);
5073 }
5074
5075 /* Add delay of 150ms after reset */
5076 msleep(150);
5077
5078 /* PART2 - Download firmware to both phys */
5079 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5080 u16 fw_ver1;
5081
5082 bnx2x_bcm8073_external_rom_boot(bp, port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005083 ext_phy_addr[port], shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005084
5085 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5086 ext_phy_addr[port],
5087 MDIO_PMA_DEVAD,
5088 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00005089 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005090 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00005091 "bnx2x_8073_common_init_phy port %x:"
5092 "Download failed. fw version = 0x%x\n",
5093 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005094 return -EINVAL;
5095 }
5096
5097 /* Only set bit 10 = 1 (Tx power down) */
5098 bnx2x_cl45_read(bp, port,
5099 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5100 ext_phy_addr[port],
5101 MDIO_PMA_DEVAD,
5102 MDIO_PMA_REG_TX_POWER_DOWN, &val);
5103
5104 /* Phase1 of TX_POWER_DOWN reset */
5105 bnx2x_cl45_write(bp, port,
5106 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5107 ext_phy_addr[port],
5108 MDIO_PMA_DEVAD,
5109 MDIO_PMA_REG_TX_POWER_DOWN,
5110 (val | 1<<10));
5111 }
5112
5113 /* Toggle Transmitter: Power down and then up with 600ms
5114 delay between */
5115 msleep(600);
5116
5117 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
5118 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5119 /* Phase2 of POWER_DOWN_RESET*/
5120 /* Release bit 10 (Release Tx power down) */
5121 bnx2x_cl45_read(bp, port,
5122 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5123 ext_phy_addr[port],
5124 MDIO_PMA_DEVAD,
5125 MDIO_PMA_REG_TX_POWER_DOWN, &val);
5126
5127 bnx2x_cl45_write(bp, port,
5128 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5129 ext_phy_addr[port],
5130 MDIO_PMA_DEVAD,
5131 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
5132 msleep(15);
5133
5134 /* Read modify write the SPI-ROM version select register */
5135 bnx2x_cl45_read(bp, port,
5136 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5137 ext_phy_addr[port],
5138 MDIO_PMA_DEVAD,
5139 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
5140 bnx2x_cl45_write(bp, port,
5141 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5142 ext_phy_addr[port],
5143 MDIO_PMA_DEVAD,
5144 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
5145
5146 /* set GPIO2 back to LOW */
5147 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5148 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
5149 }
5150 return 0;
5151
5152}
5153
Eilon Greenstein589abe32009-02-12 08:36:55 +00005154
5155static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5156{
5157 u8 ext_phy_addr;
5158 u32 val;
5159 s8 port;
5160 /* Use port1 because of the static port-swap */
5161 /* Enable the module detection interrupt */
5162 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
5163 val |= ((1<<MISC_REGISTERS_GPIO_3)|
5164 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
5165 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
5166
5167 bnx2x_hw_reset(bp, 1);
5168 msleep(5);
5169 for (port = 0; port < PORT_MAX; port++) {
5170 /* Extract the ext phy address for the port */
5171 u32 ext_phy_config = REG_RD(bp, shmem_base +
5172 offsetof(struct shmem_region,
5173 dev_info.port_hw_config[port].external_phy_config));
5174
5175 ext_phy_addr =
5176 ((ext_phy_config &
5177 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5178 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5179 DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
5180 ext_phy_addr);
5181
5182 bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
5183
5184 /* Set fault module detected LED on */
5185 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5186 MISC_REGISTERS_GPIO_HIGH,
5187 port);
5188 }
5189
5190 return 0;
5191}
5192
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005193u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5194{
5195 u8 rc = 0;
5196 u32 ext_phy_type;
5197
5198 DP(NETIF_MSG_LINK, "bnx2x_common_init_phy\n");
5199
5200 /* Read the ext_phy_type for arbitrary port(0) */
5201 ext_phy_type = XGXS_EXT_PHY_TYPE(
5202 REG_RD(bp, shmem_base +
5203 offsetof(struct shmem_region,
5204 dev_info.port_hw_config[0].external_phy_config)));
5205
5206 switch (ext_phy_type) {
5207 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
5208 {
5209 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
5210 break;
5211 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00005212 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5213 /* GPIO1 affects both ports, so there's need to pull
5214 it for single port alone */
5215 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
5216
5217 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005218 default:
5219 DP(NETIF_MSG_LINK,
5220 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
5221 ext_phy_type);
5222 break;
5223 }
5224
5225 return rc;
5226}
5227
5228
5229
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005230static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
5231{
5232 u16 val, cnt;
5233
5234 bnx2x_cl45_read(bp, port,
5235 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5236 phy_addr,
5237 MDIO_PMA_DEVAD,
5238 MDIO_PMA_REG_7101_RESET, &val);
5239
5240 for (cnt = 0; cnt < 10; cnt++) {
5241 msleep(50);
5242 /* Writes a self-clearing reset */
5243 bnx2x_cl45_write(bp, port,
5244 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5245 phy_addr,
5246 MDIO_PMA_DEVAD,
5247 MDIO_PMA_REG_7101_RESET,
5248 (val | (1<<15)));
5249 /* Wait for clear */
5250 bnx2x_cl45_read(bp, port,
5251 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5252 phy_addr,
5253 MDIO_PMA_DEVAD,
5254 MDIO_PMA_REG_7101_RESET, &val);
5255
5256 if ((val & (1<<15)) == 0)
5257 break;
5258 }
5259}
5260#define RESERVED_SIZE 256
5261/* max application is 160K bytes - data at end of RAM */
Eilon Greenstein6378c022008-08-13 15:59:25 -07005262#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005263
5264/* Header is 14 bytes */
5265#define HEADER_SIZE 14
5266#define DATA_OFFSET HEADER_SIZE
5267
5268#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \
5269 bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \
5270 ext_phy_addr, \
5271 MDIO_PCS_DEVAD, \
5272 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1)
5273
5274/* Programs an image to DSP's flash via the SPI port*/
5275static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port,
5276 u8 ext_phy_addr,
5277 char data[], u32 size)
5278{
5279 const u16 num_trans = size/4; /* 4 bytes can be sent at a time */
5280 /* Doesn't include last trans!*/
5281 const u16 last_trans_size = size%4; /* Num bytes on last trans */
5282 u16 trans_cnt, byte_cnt;
5283 u32 data_index;
5284 u16 tmp;
5285 u16 code_started = 0;
5286 u16 image_revision1, image_revision2;
5287 u16 cnt;
5288
5289 DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size);
5290 /* Going to flash*/
5291 if ((size-HEADER_SIZE) > MAX_APP_SIZE) {
5292 /* This very often will be the case, because the image is built
5293 with 160Kbytes size whereas the total image size must actually
5294 be 160Kbytes-RESERVED_SIZE */
5295 DP(NETIF_MSG_LINK, "Warning, file size was %d bytes "
5296 "truncated to %d bytes\n", size, MAX_APP_SIZE);
5297 size = MAX_APP_SIZE+HEADER_SIZE;
5298 }
5299 DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005300 DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005301 /* Put the DSP in download mode by setting FLASH_CFG[2] to 1
5302 and issuing a reset.*/
5303
5304 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005305 MISC_REGISTERS_GPIO_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005306
5307 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
5308
5309 /* wait 0.5 sec */
5310 for (cnt = 0; cnt < 100; cnt++)
5311 msleep(5);
5312
5313 /* Make sure we can access the DSP
5314 And it's in the correct mode (waiting for download) */
5315
5316 bnx2x_cl45_read(bp, port,
5317 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5318 ext_phy_addr,
5319 MDIO_PCS_DEVAD,
5320 MDIO_PCS_REG_7101_DSP_ACCESS, &tmp);
5321
5322 if (tmp != 0x000A) {
5323 DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. "
5324 "Expected 0x000A, read 0x%04X\n", tmp);
5325 DP(NETIF_MSG_LINK, "Download failed\n");
5326 return -EINVAL;
5327 }
5328
5329 /* Mux the SPI interface away from the internal processor */
5330 bnx2x_cl45_write(bp, port,
5331 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5332 ext_phy_addr,
5333 MDIO_PCS_DEVAD,
5334 MDIO_PCS_REG_7101_SPI_MUX, 1);
5335
5336 /* Reset the SPI port */
5337 bnx2x_cl45_write(bp, port,
5338 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5339 ext_phy_addr,
5340 MDIO_PCS_DEVAD,
5341 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
5342 bnx2x_cl45_write(bp, port,
5343 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5344 ext_phy_addr,
5345 MDIO_PCS_DEVAD,
5346 MDIO_PCS_REG_7101_SPI_CTRL_ADDR,
5347 (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT));
5348 bnx2x_cl45_write(bp, port,
5349 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5350 ext_phy_addr,
5351 MDIO_PCS_DEVAD,
5352 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
5353
5354 /* Erase the flash */
5355 bnx2x_cl45_write(bp, port,
5356 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5357 ext_phy_addr,
5358 MDIO_PCS_DEVAD,
5359 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5360 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5361
5362 bnx2x_cl45_write(bp, port,
5363 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5364 ext_phy_addr,
5365 MDIO_PCS_DEVAD,
5366 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5367 1);
5368
5369 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5370 bnx2x_cl45_write(bp, port,
5371 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5372 ext_phy_addr,
5373 MDIO_PCS_DEVAD,
5374 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5375 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD);
5376
5377 bnx2x_cl45_write(bp, port,
5378 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5379 ext_phy_addr,
5380 MDIO_PCS_DEVAD,
5381 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5382 1);
5383 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5384
5385 /* Wait 10 seconds, the maximum time for the erase to complete */
5386 DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n");
5387 for (cnt = 0; cnt < 1000; cnt++)
5388 msleep(10);
5389
5390 DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n");
5391 data_index = 0;
5392 for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) {
5393 bnx2x_cl45_write(bp, port,
5394 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5395 ext_phy_addr,
5396 MDIO_PCS_DEVAD,
5397 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5398 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5399
5400 bnx2x_cl45_write(bp, port,
5401 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5402 ext_phy_addr,
5403 MDIO_PCS_DEVAD,
5404 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5405 1);
5406 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5407
5408 bnx2x_cl45_write(bp, port,
5409 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5410 ext_phy_addr,
5411 MDIO_PCS_DEVAD,
5412 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5413 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
5414
5415 /* Bits 23-16 of address */
5416 bnx2x_cl45_write(bp, port,
5417 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5418 ext_phy_addr,
5419 MDIO_PCS_DEVAD,
5420 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5421 (data_index>>16));
5422 /* Bits 15-8 of address */
5423 bnx2x_cl45_write(bp, port,
5424 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5425 ext_phy_addr,
5426 MDIO_PCS_DEVAD,
5427 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5428 (data_index>>8));
5429
5430 /* Bits 7-0 of address */
5431 bnx2x_cl45_write(bp, port,
5432 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5433 ext_phy_addr,
5434 MDIO_PCS_DEVAD,
5435 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5436 ((u16)data_index));
5437
5438 byte_cnt = 0;
5439 while (byte_cnt < 4 && data_index < size) {
5440 bnx2x_cl45_write(bp, port,
5441 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5442 ext_phy_addr,
5443 MDIO_PCS_DEVAD,
5444 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5445 data[data_index++]);
5446 byte_cnt++;
5447 }
5448
5449 bnx2x_cl45_write(bp, port,
5450 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5451 ext_phy_addr,
5452 MDIO_PCS_DEVAD,
5453 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5454 byte_cnt+4);
5455
5456 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5457 msleep(5); /* Wait 5 ms minimum between transs */
5458
5459 /* Let the user know something's going on.*/
5460 /* a pacifier ever 4K */
5461 if ((data_index % 1023) == 0)
5462 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
5463 }
5464
5465 DP(NETIF_MSG_LINK, "\n");
5466 /* Transfer the last block if there is data remaining */
5467 if (last_trans_size) {
5468 bnx2x_cl45_write(bp, port,
5469 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5470 ext_phy_addr,
5471 MDIO_PCS_DEVAD,
5472 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5473 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5474
5475 bnx2x_cl45_write(bp, port,
5476 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5477 ext_phy_addr,
5478 MDIO_PCS_DEVAD,
5479 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5480 1);
5481
5482 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5483
5484 bnx2x_cl45_write(bp, port,
5485 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5486 ext_phy_addr,
5487 MDIO_PCS_DEVAD,
5488 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5489 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
5490
5491 /* Bits 23-16 of address */
5492 bnx2x_cl45_write(bp, port,
5493 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5494 ext_phy_addr,
5495 MDIO_PCS_DEVAD,
5496 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5497 (data_index>>16));
5498 /* Bits 15-8 of address */
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_FIFO_ADDR,
5504 (data_index>>8));
5505
5506 /* Bits 7-0 of address */
5507 bnx2x_cl45_write(bp, port,
5508 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5509 ext_phy_addr,
5510 MDIO_PCS_DEVAD,
5511 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5512 ((u16)data_index));
5513
5514 byte_cnt = 0;
5515 while (byte_cnt < last_trans_size && data_index < size) {
5516 /* Bits 7-0 of address */
5517 bnx2x_cl45_write(bp, port,
5518 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5519 ext_phy_addr,
5520 MDIO_PCS_DEVAD,
5521 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5522 data[data_index++]);
5523 byte_cnt++;
5524 }
5525
5526 bnx2x_cl45_write(bp, port,
5527 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5528 ext_phy_addr,
5529 MDIO_PCS_DEVAD,
5530 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5531 byte_cnt+4);
5532
5533 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5534 }
5535
5536 /* DSP Remove Download Mode */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005537 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5538 MISC_REGISTERS_GPIO_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005539
5540 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
5541
5542 /* wait 0.5 sec to allow it to run */
5543 for (cnt = 0; cnt < 100; cnt++)
5544 msleep(5);
5545
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005546 bnx2x_hw_reset(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005547
5548 for (cnt = 0; cnt < 100; cnt++)
5549 msleep(5);
5550
5551 /* Check that the code is started. In case the download
5552 checksum failed, the code won't be started. */
5553 bnx2x_cl45_read(bp, port,
5554 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5555 ext_phy_addr,
5556 MDIO_PCS_DEVAD,
5557 MDIO_PCS_REG_7101_DSP_ACCESS,
5558 &tmp);
5559
5560 code_started = (tmp & (1<<4));
5561 if (!code_started) {
5562 DP(NETIF_MSG_LINK, "Download failed. Please check file.\n");
5563 return -EINVAL;
5564 }
5565
5566 /* Verify that the file revision is now equal to the image
5567 revision within the DSP */
5568 bnx2x_cl45_read(bp, port,
5569 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5570 ext_phy_addr,
5571 MDIO_PMA_DEVAD,
5572 MDIO_PMA_REG_7101_VER1,
5573 &image_revision1);
5574
5575 bnx2x_cl45_read(bp, port,
5576 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5577 ext_phy_addr,
5578 MDIO_PMA_DEVAD,
5579 MDIO_PMA_REG_7101_VER2,
5580 &image_revision2);
5581
Eilon Greenstein3196a882008-08-13 15:58:49 -07005582 if (data[0x14e] != (image_revision2&0xFF) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005583 data[0x14f] != ((image_revision2&0xFF00)>>8) ||
5584 data[0x150] != (image_revision1&0xFF) ||
5585 data[0x151] != ((image_revision1&0xFF00)>>8)) {
5586 DP(NETIF_MSG_LINK, "Download failed.\n");
5587 return -EINVAL;
5588 }
5589 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
5590 return 0;
5591}
5592
5593u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
5594 u8 driver_loaded, char data[], u32 size)
5595{
5596 u8 rc = 0;
5597 u32 ext_phy_type;
5598 u8 ext_phy_addr;
5599 ext_phy_addr = ((ext_phy_config &
5600 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5601 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5602
5603 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
5604
5605 switch (ext_phy_type) {
5606 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5607 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
5608 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5609 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
5610 DP(NETIF_MSG_LINK,
5611 "Flash download not supported for this ext phy\n");
5612 rc = -EINVAL;
5613 break;
5614 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5615 /* Take ext phy out of reset */
5616 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005617 bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005618 rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
5619 data, size);
5620 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005621 bnx2x_turn_off_sf(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005622 break;
5623 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
5624 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
5625 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
5626 default:
5627 DP(NETIF_MSG_LINK, "Invalid ext phy type\n");
5628 rc = -EINVAL;
5629 break;
5630 }
5631 return rc;
5632}
5633