blob: 39db995c6985a3e0ccd129beb4b7c0aa4ac0eecc [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;
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001761 u16 bank;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001762
1763 /* read precomp */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001764 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
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001769 /* bits [10:7] at lp_up2, positioned at [15:12] */
1770 lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
1771 MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
1772 MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
1773
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001774 if (lp_up2 == 0)
1775 return;
1776
1777 for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
1778 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
1779 CL45_RD_OVER_CL22(bp, params->port,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001780 params->phy_addr,
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00001781 bank,
1782 MDIO_TX0_TX_DRIVER, &tx_driver);
1783
1784 /* replace tx_driver bits [15:12] */
1785 if (lp_up2 !=
1786 (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
1787 tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
1788 tx_driver |= lp_up2;
1789 CL45_WR_OVER_CL22(bp, params->port,
1790 params->phy_addr,
1791 bank,
1792 MDIO_TX0_TX_DRIVER, tx_driver);
1793 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001794 }
1795}
1796
1797static u8 bnx2x_emac_program(struct link_params *params,
1798 u32 line_speed, u32 duplex)
1799{
1800 struct bnx2x *bp = params->bp;
1801 u8 port = params->port;
1802 u16 mode = 0;
1803
1804 DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
1805 bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 +
1806 EMAC_REG_EMAC_MODE,
1807 (EMAC_MODE_25G_MODE |
1808 EMAC_MODE_PORT_MII_10M |
1809 EMAC_MODE_HALF_DUPLEX));
1810 switch (line_speed) {
1811 case SPEED_10:
1812 mode |= EMAC_MODE_PORT_MII_10M;
1813 break;
1814
1815 case SPEED_100:
1816 mode |= EMAC_MODE_PORT_MII;
1817 break;
1818
1819 case SPEED_1000:
1820 mode |= EMAC_MODE_PORT_GMII;
1821 break;
1822
1823 case SPEED_2500:
1824 mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
1825 break;
1826
1827 default:
1828 /* 10G not valid for EMAC */
1829 DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
1830 return -EINVAL;
1831 }
1832
1833 if (duplex == DUPLEX_HALF)
1834 mode |= EMAC_MODE_HALF_DUPLEX;
1835 bnx2x_bits_en(bp,
1836 GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
1837 mode);
1838
1839 bnx2x_set_led(bp, params->port, LED_MODE_OPER,
1840 line_speed, params->hw_led_mode, params->chip_id);
1841 return 0;
1842}
1843
1844/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001845/* External Phy section */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001846/*****************************************************************************/
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001847static void bnx2x_hw_reset(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001848{
1849 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001850 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001851 msleep(1);
1852 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001853 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001854}
1855
1856static void bnx2x_ext_phy_reset(struct link_params *params,
1857 struct link_vars *vars)
1858{
1859 struct bnx2x *bp = params->bp;
1860 u32 ext_phy_type;
1861 u8 ext_phy_addr = ((params->ext_phy_config &
1862 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
1863 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
1864 DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
1865 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
1866 /* The PHY reset is controled by GPIO 1
1867 * Give it 1ms of reset pulse
1868 */
1869 if (vars->phy_flags & PHY_XGXS_FLAG) {
1870
1871 switch (ext_phy_type) {
1872 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
1873 DP(NETIF_MSG_LINK, "XGXS Direct\n");
1874 break;
1875
1876 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
1877 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
1878 DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
1879
1880 /* Restore normal power mode*/
1881 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001882 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1883 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001884
1885 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001886 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001887
1888 bnx2x_cl45_write(bp, params->port,
1889 ext_phy_type,
1890 ext_phy_addr,
1891 MDIO_PMA_DEVAD,
1892 MDIO_PMA_REG_CTRL, 0xa040);
1893 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00001894 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
1895
1896 /* Restore normal power mode*/
1897 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
1898 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1899 params->port);
1900
1901 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
1902 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1903 params->port);
1904
1905 bnx2x_cl45_write(bp, params->port,
1906 ext_phy_type,
1907 ext_phy_addr,
1908 MDIO_PMA_DEVAD,
1909 MDIO_PMA_REG_CTRL,
1910 1<<15);
1911
1912 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001913 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
1914 /* Unset Low Power Mode and SW reset */
1915 /* Restore normal power mode*/
1916 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001917 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1918 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001919
1920 DP(NETIF_MSG_LINK, "XGXS 8072\n");
1921 bnx2x_cl45_write(bp, params->port,
1922 ext_phy_type,
1923 ext_phy_addr,
1924 MDIO_PMA_DEVAD,
1925 MDIO_PMA_REG_CTRL,
1926 1<<15);
1927 break;
1928 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
1929 {
1930 u16 emac_base;
1931 emac_base = (params->port) ? GRCBASE_EMAC0 :
1932 GRCBASE_EMAC1;
1933
1934 /* Restore normal power mode*/
1935 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001936 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1937 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001938
1939 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001940 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1941 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001942
1943 DP(NETIF_MSG_LINK, "XGXS 8073\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001944 }
1945 break;
1946
1947 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
1948 DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
1949
1950 /* Restore normal power mode*/
1951 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001952 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1953 params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001954
1955 /* HW reset */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001956 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001957
1958 break;
1959
Eilon Greenstein28577182009-02-12 08:37:00 +00001960 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
1961
1962 /* Restore normal power mode*/
1963 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
1964 MISC_REGISTERS_GPIO_OUTPUT_HIGH,
1965 params->port);
1966
1967 /* HW reset */
1968 bnx2x_hw_reset(bp, params->port);
1969
1970 bnx2x_cl45_write(bp, params->port,
1971 ext_phy_type,
1972 ext_phy_addr,
1973 MDIO_PMA_DEVAD,
1974 MDIO_PMA_REG_CTRL,
1975 1<<15);
1976 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001977 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
1978 DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
1979 break;
1980
1981 default:
1982 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
1983 params->ext_phy_config);
1984 break;
1985 }
1986
1987 } else { /* SerDes */
1988 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
1989 switch (ext_phy_type) {
1990 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
1991 DP(NETIF_MSG_LINK, "SerDes Direct\n");
1992 break;
1993
1994 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
1995 DP(NETIF_MSG_LINK, "SerDes 5482\n");
Eilon Greenstein17de50b2008-08-13 15:56:59 -07001996 bnx2x_hw_reset(bp, params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07001997 break;
1998
1999 default:
2000 DP(NETIF_MSG_LINK,
2001 "BAD SerDes ext_phy_config 0x%x\n",
2002 params->ext_phy_config);
2003 break;
2004 }
2005 }
2006}
2007
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002008
2009static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
2010 u32 shmem_base, u32 spirom_ver)
2011{
2012 DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x\n",
2013 (u16)(spirom_ver>>16), (u16)spirom_ver);
2014 REG_WR(bp, shmem_base +
2015 offsetof(struct shmem_region,
2016 port_mb[port].ext_phy_fw_version),
2017 spirom_ver);
2018}
2019
2020static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
2021 u32 ext_phy_type, u8 ext_phy_addr,
2022 u32 shmem_base)
2023{
2024 u16 fw_ver1, fw_ver2;
2025 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2026 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
2027 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
2028 MDIO_PMA_REG_ROM_VER2, &fw_ver2);
2029 bnx2x_save_spirom_version(bp, port, shmem_base,
2030 (u32)(fw_ver1<<16 | fw_ver2));
2031}
2032
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002033static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
2034{
2035 struct bnx2x *bp = params->bp;
2036 u8 port = params->port;
2037 u8 ext_phy_addr = ((params->ext_phy_config &
2038 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2039 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2040 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002041
2042 /* Need to wait 200ms after reset */
2043 msleep(200);
2044 /* Boot port from external ROM
2045 * Set ser_boot_ctl bit in the MISC_CTRL1 register
2046 */
2047 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2048 MDIO_PMA_DEVAD,
2049 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2050
2051 /* Reset internal microprocessor */
2052 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2053 MDIO_PMA_DEVAD,
2054 MDIO_PMA_REG_GEN_CTRL,
2055 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2056 /* set micro reset = 0 */
2057 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2058 MDIO_PMA_DEVAD,
2059 MDIO_PMA_REG_GEN_CTRL,
2060 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2061 /* Reset internal microprocessor */
2062 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2063 MDIO_PMA_DEVAD,
2064 MDIO_PMA_REG_GEN_CTRL,
2065 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2066 /* wait for 100ms for code download via SPI port */
2067 msleep(100);
2068
2069 /* Clear ser_boot_ctl bit */
2070 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2071 MDIO_PMA_DEVAD,
2072 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2073 /* Wait 100ms */
2074 msleep(100);
2075
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002076 bnx2x_save_bcm_spirom_ver(bp, port,
2077 ext_phy_type,
2078 ext_phy_addr,
2079 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002080}
2081
2082static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
2083{
2084 /* This is only required for 8073A1, version 102 only */
2085
2086 struct bnx2x *bp = params->bp;
2087 u8 ext_phy_addr = ((params->ext_phy_config &
2088 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2089 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2090 u16 val;
2091
2092 /* Read 8073 HW revision*/
2093 bnx2x_cl45_read(bp, params->port,
2094 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2095 ext_phy_addr,
2096 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002097 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002098
2099 if (val != 1) {
2100 /* No need to workaround in 8073 A1 */
2101 return 0;
2102 }
2103
2104 bnx2x_cl45_read(bp, params->port,
2105 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2106 ext_phy_addr,
2107 MDIO_PMA_DEVAD,
2108 MDIO_PMA_REG_ROM_VER2, &val);
2109
2110 /* SNR should be applied only for version 0x102 */
2111 if (val != 0x102)
2112 return 0;
2113
2114 return 1;
2115}
2116
2117static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
2118{
2119 struct bnx2x *bp = params->bp;
2120 u8 ext_phy_addr = ((params->ext_phy_config &
2121 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2122 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2123 u16 val, cnt, cnt1 ;
2124
2125 bnx2x_cl45_read(bp, params->port,
2126 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2127 ext_phy_addr,
2128 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002129 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002130
2131 if (val > 0) {
2132 /* No need to workaround in 8073 A1 */
2133 return 0;
2134 }
2135 /* XAUI workaround in 8073 A0: */
2136
2137 /* After loading the boot ROM and restarting Autoneg,
2138 poll Dev1, Reg $C820: */
2139
2140 for (cnt = 0; cnt < 1000; cnt++) {
2141 bnx2x_cl45_read(bp, params->port,
2142 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2143 ext_phy_addr,
2144 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002145 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
2146 &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002147 /* If bit [14] = 0 or bit [13] = 0, continue on with
2148 system initialization (XAUI work-around not required,
2149 as these bits indicate 2.5G or 1G link up). */
2150 if (!(val & (1<<14)) || !(val & (1<<13))) {
2151 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2152 return 0;
2153 } else if (!(val & (1<<15))) {
2154 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2155 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2156 it's MSB (bit 15) goes to 1 (indicating that the
2157 XAUI workaround has completed),
2158 then continue on with system initialization.*/
2159 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2160 bnx2x_cl45_read(bp, params->port,
2161 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2162 ext_phy_addr,
2163 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002164 MDIO_PMA_REG_8073_XAUI_WA, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002165 if (val & (1<<15)) {
2166 DP(NETIF_MSG_LINK,
2167 "XAUI workaround has completed\n");
2168 return 0;
2169 }
2170 msleep(3);
2171 }
2172 break;
2173 }
2174 msleep(3);
2175 }
2176 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2177 return -EINVAL;
2178
2179}
2180
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002181static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002182 u8 ext_phy_addr, u32 shmem_base)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002183{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002184 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002185 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002186 bnx2x_cl45_write(bp, port,
2187 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2188 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002189 MDIO_PMA_DEVAD,
2190 MDIO_PMA_REG_GEN_CTRL,
2191 0x0001);
2192
2193 /* ucode reboot and rst */
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_GEN_CTRL,
2199 0x008c);
2200
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_MISC_CTRL1, 0x0001);
2206
2207 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002208 bnx2x_cl45_write(bp, port,
2209 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2210 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002211 MDIO_PMA_DEVAD,
2212 MDIO_PMA_REG_GEN_CTRL,
2213 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2214
2215 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002216 bnx2x_cl45_write(bp, port,
2217 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2218 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002219 MDIO_PMA_DEVAD,
2220 MDIO_PMA_REG_GEN_CTRL,
2221 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2222
2223 /* wait for 100ms for code download via SPI port */
2224 msleep(100);
2225
2226 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002227 bnx2x_cl45_write(bp, port,
2228 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2229 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002230 MDIO_PMA_DEVAD,
2231 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2232
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002233 bnx2x_save_bcm_spirom_ver(bp, port,
2234 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2235 ext_phy_addr,
2236 shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002237}
2238
Eilon Greenstein589abe32009-02-12 08:36:55 +00002239static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
2240{
2241 struct bnx2x *bp = params->bp;
2242 u8 port = params->port;
2243 u8 ext_phy_addr = ((params->ext_phy_config &
2244 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2245 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2246 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2247
2248 /* Need to wait 100ms after reset */
2249 msleep(100);
2250
2251 /* Set serial boot control for external load */
2252 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2253 MDIO_PMA_DEVAD,
2254 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2255
2256 /* Micro controller re-boot */
2257 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2258 MDIO_PMA_DEVAD,
2259 MDIO_PMA_REG_GEN_CTRL,
2260 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2261
2262 /* Set soft reset */
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_MICRO_RESET);
2267
2268 /* Clear soft reset.
2269 Will automatically reset micro-controller re-boot */
2270 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2271 MDIO_PMA_DEVAD,
2272 MDIO_PMA_REG_GEN_CTRL,
2273 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2274
2275 /* wait for 100ms for microcode load */
2276 msleep(100);
2277
2278 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
2279 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2280 MDIO_PMA_DEVAD,
2281 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2282
2283 msleep(200);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002284 bnx2x_save_bcm_spirom_ver(bp, port,
2285 ext_phy_type,
2286 ext_phy_addr,
2287 params->shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002288}
2289
2290static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
2291 u8 ext_phy_addr, u8 tx_en)
2292{
2293 u16 val;
2294 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2295 tx_en, port);
2296 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
2297 bnx2x_cl45_read(bp, port,
2298 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2299 ext_phy_addr,
2300 MDIO_PMA_DEVAD,
2301 MDIO_PMA_REG_PHY_IDENTIFIER,
2302 &val);
2303
2304 if (tx_en)
2305 val &= ~(1<<15);
2306 else
2307 val |= (1<<15);
2308
2309 bnx2x_cl45_write(bp, port,
2310 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2311 ext_phy_addr,
2312 MDIO_PMA_DEVAD,
2313 MDIO_PMA_REG_PHY_IDENTIFIER,
2314 val);
2315}
2316
2317
2318static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
2319 u8 byte_cnt, u8 *o_buf) {
2320 struct bnx2x *bp = params->bp;
2321 u16 val, i;
2322 u8 port = params->port;
2323 u8 ext_phy_addr = ((params->ext_phy_config &
2324 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2325 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2326 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2327 if (byte_cnt > 16) {
2328 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2329 " is limited to 0xf\n");
2330 return -EINVAL;
2331 }
2332 /* Set the read command byte count */
2333 bnx2x_cl45_write(bp, port,
2334 ext_phy_type,
2335 ext_phy_addr,
2336 MDIO_PMA_DEVAD,
2337 MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
2338 (byte_cnt | 0xa000));
2339
2340 /* Set the read command address */
2341 bnx2x_cl45_write(bp, port,
2342 ext_phy_type,
2343 ext_phy_addr,
2344 MDIO_PMA_DEVAD,
2345 MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
2346 addr);
2347
2348 /* Activate read command */
2349 bnx2x_cl45_write(bp, port,
2350 ext_phy_type,
2351 ext_phy_addr,
2352 MDIO_PMA_DEVAD,
2353 MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
2354 0x2c0f);
2355
2356 /* Wait up to 500us for command complete status */
2357 for (i = 0; i < 100; i++) {
2358 bnx2x_cl45_read(bp, port,
2359 ext_phy_type,
2360 ext_phy_addr,
2361 MDIO_PMA_DEVAD,
2362 MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
2363 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
2364 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
2365 break;
2366 udelay(5);
2367 }
2368
2369 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
2370 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
2371 DP(NETIF_MSG_LINK,
2372 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2373 (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
2374 return -EINVAL;
2375 }
2376
2377 /* Read the buffer */
2378 for (i = 0; i < byte_cnt; i++) {
2379 bnx2x_cl45_read(bp, port,
2380 ext_phy_type,
2381 ext_phy_addr,
2382 MDIO_PMA_DEVAD,
2383 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2384 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2385 }
2386
2387 for (i = 0; i < 100; i++) {
2388 bnx2x_cl45_read(bp, port,
2389 ext_phy_type,
2390 ext_phy_addr,
2391 MDIO_PMA_DEVAD,
2392 MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
2393 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
2394 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
2395 return 0;;
2396 msleep(1);
2397 }
2398 return -EINVAL;
2399}
2400
2401
2402static u8 bnx2x_get_sfp_module_type(struct link_params *params,
2403 u8 *module_type)
2404{
2405 struct bnx2x *bp = params->bp;
2406 u8 val;
2407 *module_type = SFP_MODULE_TYPE_UNKNOWN;
2408
2409 /* First check for copper cable */
2410 if (bnx2x_read_sfp_module_eeprom(params,
2411 SFP_EEPROM_CON_TYPE_ADDR,
2412 1,
2413 &val) != 0) {
2414 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
2415 return -EINVAL;
2416 }
2417
2418 switch (val) {
2419 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2420 {
2421 u8 copper_module_type;
2422 /* Check if its active cable( includes SFP+ module)
2423 of passive cable*/
2424 if (bnx2x_read_sfp_module_eeprom(params,
2425 SFP_EEPROM_FC_TX_TECH_ADDR,
2426 1,
2427 &copper_module_type) !=
2428 0) {
2429 DP(NETIF_MSG_LINK,
2430 "Failed to read copper-cable-type"
2431 " from SFP+ EEPROM\n");
2432 return -EINVAL;
2433 }
2434
2435 if (copper_module_type &
2436 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2437 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
2438 *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
2439 } else if (copper_module_type &
2440 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2441 DP(NETIF_MSG_LINK, "Passive Copper"
2442 " cable detected\n");
2443 *module_type =
2444 SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
2445 } else {
2446 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2447 "type 0x%x !!!\n", copper_module_type);
2448 return -EINVAL;
2449 }
2450 break;
2451 }
2452 case SFP_EEPROM_CON_TYPE_VAL_LC:
2453 DP(NETIF_MSG_LINK, "Optic module detected\n");
2454 *module_type = SFP_MODULE_TYPE_LC;
2455 break;
2456
2457 default:
2458 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2459 val);
2460 return -EINVAL;
2461 }
2462 return 0;
2463}
2464
2465
2466/* This function read the relevant field from the module ( SFP+ ),
2467 and verify it is compliant with this board */
2468static u8 bnx2x_verify_sfp_module(struct link_params *params,
2469 u8 module_type)
2470{
2471 struct bnx2x *bp = params->bp;
2472 u8 *str_p, *tmp_buf;
2473 u16 i;
2474
2475#define COMPLIANCE_STR_CNT 6
2476 u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
2477 "FINISAR CORP. ", "Amphenol"};
2478 u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
2479 /* Passive Copper cables are allowed to participate,
2480 since the module is hardwired to the copper cable */
2481
2482 if (!(params->feature_config_flags &
2483 FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
2484 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2485 return 0;
2486 }
2487
2488 if (module_type != SFP_MODULE_TYPE_LC) {
2489 DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
2490 return 0;
2491 }
2492
2493 /* In case of non copper cable or Active copper cable,
2494 verify that the SFP+ module is compliant with this board*/
2495 if (bnx2x_read_sfp_module_eeprom(params,
2496 SFP_EEPROM_VENDOR_NAME_ADDR,
2497 SFP_EEPROM_VENDOR_NAME_SIZE,
2498 buf) != 0) {
2499 DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
2500 " module EEPROM\n");
2501 return -EINVAL;
2502 }
2503 for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
2504 str_p = compliance_str[i];
2505 tmp_buf = buf;
2506 while (*str_p) {
2507 if ((u8)(*tmp_buf) != (u8)(*str_p))
2508 break;
2509 str_p++;
2510 tmp_buf++;
2511 }
2512
2513 if (!(*str_p)) {
2514 DP(NETIF_MSG_LINK, "SFP+ Module verified, "
2515 "index=%x\n", i);
2516 return 0;
2517 }
2518 }
2519 DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
2520 return -EINVAL;
2521}
2522
2523
2524static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
2525 u8 module_type)
2526{
2527 struct bnx2x *bp = params->bp;
2528 u8 port = params->port;
2529 u8 options[SFP_EEPROM_OPTIONS_SIZE];
2530 u8 limiting_mode;
2531 u8 ext_phy_addr = ((params->ext_phy_config &
2532 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2533 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2534
2535 if (bnx2x_read_sfp_module_eeprom(params,
2536 SFP_EEPROM_OPTIONS_ADDR,
2537 SFP_EEPROM_OPTIONS_SIZE,
2538 options) != 0) {
2539 DP(NETIF_MSG_LINK, "Failed to read Option field from"
2540 " module EEPROM\n");
2541 return -EINVAL;
2542 }
2543 limiting_mode = !(options[0] &
2544 SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
2545 if (limiting_mode &&
2546 (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
2547 DP(NETIF_MSG_LINK,
2548 "Module options = 0x%x.Setting LIMITING MODE\n",
2549 options[0]);
2550 bnx2x_cl45_write(bp, port,
2551 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2552 ext_phy_addr,
2553 MDIO_PMA_DEVAD,
2554 MDIO_PMA_REG_ROM_VER2,
2555 SFP_LIMITING_MODE_VALUE);
2556 } else { /* LRM mode ( default )*/
2557 u16 cur_limiting_mode;
2558 DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
2559 options[0]);
2560
2561 bnx2x_cl45_read(bp, port,
2562 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2563 ext_phy_addr,
2564 MDIO_PMA_DEVAD,
2565 MDIO_PMA_REG_ROM_VER2,
2566 &cur_limiting_mode);
2567
2568 /* Changing to LRM mode takes quite few seconds.
2569 So do it only if current mode is limiting
2570 ( default is LRM )*/
2571 if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
2572 return 0;
2573
2574 bnx2x_cl45_write(bp, port,
2575 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2576 ext_phy_addr,
2577 MDIO_PMA_DEVAD,
2578 MDIO_PMA_REG_LRM_MODE,
2579 0);
2580 bnx2x_cl45_write(bp, port,
2581 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2582 ext_phy_addr,
2583 MDIO_PMA_DEVAD,
2584 MDIO_PMA_REG_ROM_VER2,
2585 0x128);
2586 bnx2x_cl45_write(bp, port,
2587 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2588 ext_phy_addr,
2589 MDIO_PMA_DEVAD,
2590 MDIO_PMA_REG_MISC_CTRL0,
2591 0x4008);
2592 bnx2x_cl45_write(bp, port,
2593 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2594 ext_phy_addr,
2595 MDIO_PMA_DEVAD,
2596 MDIO_PMA_REG_LRM_MODE,
2597 0xaaaa);
2598 }
2599 return 0;
2600}
2601
2602static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
2603{
2604 u8 val;
2605 struct bnx2x *bp = params->bp;
2606 u16 timeout;
2607 /* Initialization time after hot-plug may take up to 300ms for some
2608 phys type ( e.g. JDSU ) */
2609 for (timeout = 0; timeout < 60; timeout++) {
2610 if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
2611 == 0) {
2612 DP(NETIF_MSG_LINK, "SFP+ module initialization "
2613 "took %d ms\n", timeout * 5);
2614 return 0;
2615 }
2616 msleep(5);
2617 }
2618 return -EINVAL;
2619}
2620
2621static u8 bnx2x_sfp_module_detection(struct link_params *params)
2622{
2623 struct bnx2x *bp = params->bp;
2624 u8 module_type;
2625 u8 ext_phy_addr = ((params->ext_phy_config &
2626 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2627 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2628 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2629
2630 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
2631 DP(NETIF_MSG_LINK, "Module detection is not required "
2632 "for this phy\n");
2633 return 0;
2634 }
2635
2636 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
2637 params->port);
2638
2639 if (bnx2x_get_sfp_module_type(params,
2640 &module_type) != 0) {
2641 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
2642 if (!(params->feature_config_flags &
2643 FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
2644 /* In case module detection is disabled, it trys to
2645 link up. The issue that can happen here is LRM /
2646 LIMITING mode which set according to the module-type*/
2647 DP(NETIF_MSG_LINK, "Unable to read module-type."
2648 "Probably due to Bit Stretching."
2649 " Proceeding...\n");
2650 } else {
2651 return -EINVAL;
2652 }
2653 } else if (bnx2x_verify_sfp_module(params, module_type) !=
2654 0) {
2655 /* check SFP+ module compatibility */
2656 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
2657 /* Turn on fault module-detected led */
2658 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2659 MISC_REGISTERS_GPIO_HIGH,
2660 params->port);
2661 return -EINVAL;
2662 }
2663
2664 /* Turn off fault module-detected led */
2665 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2666 MISC_REGISTERS_GPIO_LOW,
2667 params->port);
2668
2669 /* Check and set limiting mode / LRM mode */
2670 if (bnx2x_bcm8726_set_limiting_mode(params, module_type)
2671 != 0) {
2672 DP(NETIF_MSG_LINK, "Setting limiting mode failed!!\n");
2673 return -EINVAL;
2674 }
2675
2676 /* Enable transmit for this module */
2677 bnx2x_bcm8726_set_transmitter(bp, params->port,
2678 ext_phy_addr, 1);
2679 return 0;
2680}
2681
2682void bnx2x_handle_module_detect_int(struct link_params *params)
2683{
2684 struct bnx2x *bp = params->bp;
2685 u32 gpio_val;
2686 u8 port = params->port;
2687 /* Set valid module led off */
2688 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2689 MISC_REGISTERS_GPIO_HIGH,
2690 params->port);
2691
2692 /* Get current gpio val refelecting module plugged in / out*/
2693 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
2694
2695 /* Call the handling function in case module is detected */
2696 if (gpio_val == 0) {
2697
2698 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
2699 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
2700 port);
2701
2702 if (bnx2x_wait_for_sfp_module_initialized(params)
2703 == 0)
2704 bnx2x_sfp_module_detection(params);
2705 else
2706 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
2707 } else {
2708 u8 ext_phy_addr = ((params->ext_phy_config &
2709 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2710 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2711 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
2712 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
2713 port);
2714 /* Module was plugged out. */
2715 /* Disable transmit for this module */
2716 bnx2x_bcm8726_set_transmitter(bp, params->port,
2717 ext_phy_addr, 0);
2718 }
2719}
2720
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002721static void bnx2x_bcm807x_force_10G(struct link_params *params)
2722{
2723 struct bnx2x *bp = params->bp;
2724 u8 port = params->port;
2725 u8 ext_phy_addr = ((params->ext_phy_config &
2726 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2727 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2728 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2729
2730 /* Force KR or KX */
2731 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2732 MDIO_PMA_DEVAD,
2733 MDIO_PMA_REG_CTRL,
2734 0x2040);
2735 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2736 MDIO_PMA_DEVAD,
2737 MDIO_PMA_REG_10G_CTRL2,
2738 0x000b);
2739 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2740 MDIO_PMA_DEVAD,
2741 MDIO_PMA_REG_BCM_CTRL,
2742 0x0000);
2743 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2744 MDIO_AN_DEVAD,
2745 MDIO_AN_REG_CTRL,
2746 0x0000);
2747}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002748static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
2749{
2750 struct bnx2x *bp = params->bp;
2751 u8 port = params->port;
2752 u16 val;
2753 u8 ext_phy_addr = ((params->ext_phy_config &
2754 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2755 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2756 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2757
2758 bnx2x_cl45_read(bp, params->port,
2759 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2760 ext_phy_addr,
2761 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00002762 MDIO_PMA_REG_8073_CHIP_REV, &val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002763
2764 if (val == 0) {
2765 /* Mustn't set low power mode in 8073 A0 */
2766 return;
2767 }
2768
2769 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
2770 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2771 MDIO_XS_DEVAD,
2772 MDIO_XS_PLL_SEQUENCER, &val);
2773 val &= ~(1<<13);
2774 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2775 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2776
2777 /* PLL controls */
2778 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2779 MDIO_XS_DEVAD, 0x805E, 0x1077);
2780 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2781 MDIO_XS_DEVAD, 0x805D, 0x0000);
2782 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2783 MDIO_XS_DEVAD, 0x805C, 0x030B);
2784 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2785 MDIO_XS_DEVAD, 0x805B, 0x1240);
2786 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2787 MDIO_XS_DEVAD, 0x805A, 0x2490);
2788
2789 /* Tx Controls */
2790 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2791 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2792 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2793 MDIO_XS_DEVAD, 0x80A6, 0x9041);
2794 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2795 MDIO_XS_DEVAD, 0x80A5, 0x4640);
2796
2797 /* Rx Controls */
2798 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2799 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2800 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2801 MDIO_XS_DEVAD, 0x80FD, 0x9249);
2802 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2803 MDIO_XS_DEVAD, 0x80FC, 0x2015);
2804
2805 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
2806 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2807 MDIO_XS_DEVAD,
2808 MDIO_XS_PLL_SEQUENCER, &val);
2809 val |= (1<<13);
2810 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2811 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2812}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002813
2814static void bnx2x_8073_set_pause_cl37(struct link_params *params,
2815 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002816{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002817
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002818 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002819 u16 cl37_val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002820 u8 ext_phy_addr = ((params->ext_phy_config &
2821 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2822 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2823 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2824
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002825 bnx2x_cl45_read(bp, params->port,
2826 ext_phy_type,
2827 ext_phy_addr,
2828 MDIO_AN_DEVAD,
2829 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
2830
2831 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2832 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2833
2834 if ((vars->ieee_fc &
2835 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
2836 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
2837 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
2838 }
2839 if ((vars->ieee_fc &
2840 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2841 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2842 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2843 }
2844 if ((vars->ieee_fc &
2845 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2846 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2847 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2848 }
2849 DP(NETIF_MSG_LINK,
2850 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
2851
2852 bnx2x_cl45_write(bp, params->port,
2853 ext_phy_type,
2854 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002855 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002856 MDIO_AN_REG_CL37_FC_LD, cl37_val);
2857 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002858}
2859
2860static void bnx2x_ext_phy_set_pause(struct link_params *params,
2861 struct link_vars *vars)
2862{
2863 struct bnx2x *bp = params->bp;
2864 u16 val;
2865 u8 ext_phy_addr = ((params->ext_phy_config &
2866 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2867 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2868 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2869
2870 /* read modify write pause advertizing */
2871 bnx2x_cl45_read(bp, params->port,
2872 ext_phy_type,
2873 ext_phy_addr,
2874 MDIO_AN_DEVAD,
2875 MDIO_AN_REG_ADV_PAUSE, &val);
2876
2877 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002878
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002879 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2880
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002881 if ((vars->ieee_fc &
2882 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002883 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2884 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2885 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002886 if ((vars->ieee_fc &
2887 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002888 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2889 val |=
2890 MDIO_AN_REG_ADV_PAUSE_PAUSE;
2891 }
2892 DP(NETIF_MSG_LINK,
2893 "Ext phy AN advertize 0x%x\n", val);
2894 bnx2x_cl45_write(bp, params->port,
2895 ext_phy_type,
2896 ext_phy_addr,
2897 MDIO_AN_DEVAD,
2898 MDIO_AN_REG_ADV_PAUSE, val);
2899}
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002900static void bnx2x_set_preemphasis(struct link_params *params)
2901{
2902 u16 bank, i = 0;
2903 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002904
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002905 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
2906 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
2907 CL45_WR_OVER_CL22(bp, params->port,
2908 params->phy_addr,
2909 bank,
2910 MDIO_RX0_RX_EQ_BOOST,
2911 params->xgxs_config_rx[i]);
2912 }
2913
2914 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
2915 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
2916 CL45_WR_OVER_CL22(bp, params->port,
2917 params->phy_addr,
2918 bank,
2919 MDIO_TX0_TX_DRIVER,
2920 params->xgxs_config_tx[i]);
2921 }
2922}
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002923
2924static void bnx2x_init_internal_phy(struct link_params *params,
2925 struct link_vars *vars)
2926{
2927 struct bnx2x *bp = params->bp;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002928 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002929 if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
2930 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
2931 (params->feature_config_flags &
2932 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
2933 bnx2x_set_preemphasis(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002934
2935 /* forced speed requested? */
2936 if (vars->line_speed != SPEED_AUTO_NEG) {
2937 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2938
2939 /* disable autoneg */
2940 bnx2x_set_autoneg(params, vars);
2941
2942 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002943 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002944
2945 } else { /* AN_mode */
2946 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2947
2948 /* AN enabled */
2949 bnx2x_set_brcm_cl37_advertisment(params);
2950
2951 /* program duplex & pause advertisement (for aneg) */
2952 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002953 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002954
2955 /* enable autoneg */
2956 bnx2x_set_autoneg(params, vars);
2957
2958 /* enable and restart AN */
2959 bnx2x_restart_autoneg(params);
2960 }
2961
2962 } else { /* SGMII mode */
2963 DP(NETIF_MSG_LINK, "SGMII\n");
2964
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002965 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002966 }
2967}
2968
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002969static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
2970{
2971 struct bnx2x *bp = params->bp;
2972 u32 ext_phy_type;
2973 u8 ext_phy_addr;
2974 u16 cnt;
2975 u16 ctrl = 0;
2976 u16 val = 0;
2977 u8 rc = 0;
2978 if (vars->phy_flags & PHY_XGXS_FLAG) {
2979 ext_phy_addr = ((params->ext_phy_config &
2980 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2981 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2982
2983 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2984 /* Make sure that the soft reset is off (expect for the 8072:
2985 * due to the lock, it will be done inside the specific
2986 * handling)
2987 */
2988 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
2989 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
2990 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
2991 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
2992 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
2993 /* Wait for soft reset to get cleared upto 1 sec */
2994 for (cnt = 0; cnt < 1000; cnt++) {
2995 bnx2x_cl45_read(bp, params->port,
2996 ext_phy_type,
2997 ext_phy_addr,
2998 MDIO_PMA_DEVAD,
2999 MDIO_PMA_REG_CTRL, &ctrl);
3000 if (!(ctrl & (1<<15)))
3001 break;
3002 msleep(1);
3003 }
3004 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
3005 ctrl, cnt);
3006 }
3007
3008 switch (ext_phy_type) {
3009 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003010 break;
3011
3012 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3013 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3014
3015 bnx2x_cl45_write(bp, params->port,
3016 ext_phy_type,
3017 ext_phy_addr,
3018 MDIO_PMA_DEVAD,
3019 MDIO_PMA_REG_MISC_CTRL,
3020 0x8288);
3021 bnx2x_cl45_write(bp, params->port,
3022 ext_phy_type,
3023 ext_phy_addr,
3024 MDIO_PMA_DEVAD,
3025 MDIO_PMA_REG_PHY_IDENTIFIER,
3026 0x7fbf);
3027 bnx2x_cl45_write(bp, params->port,
3028 ext_phy_type,
3029 ext_phy_addr,
3030 MDIO_PMA_DEVAD,
3031 MDIO_PMA_REG_CMU_PLL_BYPASS,
3032 0x0100);
3033 bnx2x_cl45_write(bp, params->port,
3034 ext_phy_type,
3035 ext_phy_addr,
3036 MDIO_WIS_DEVAD,
3037 MDIO_WIS_REG_LASI_CNTL, 0x1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003038
3039 bnx2x_save_bcm_spirom_ver(bp, params->port,
3040 ext_phy_type,
3041 ext_phy_addr,
3042 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003043 break;
3044
3045 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003046 /* Wait until fw is loaded */
3047 for (cnt = 0; cnt < 100; cnt++) {
3048 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3049 ext_phy_addr, MDIO_PMA_DEVAD,
3050 MDIO_PMA_REG_ROM_VER1, &val);
3051 if (val)
3052 break;
3053 msleep(10);
3054 }
3055 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized "
3056 "after %d ms\n", cnt);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003057 if ((params->feature_config_flags &
3058 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3059 u8 i;
3060 u16 reg;
3061 for (i = 0; i < 4; i++) {
3062 reg = MDIO_XS_8706_REG_BANK_RX0 +
3063 i*(MDIO_XS_8706_REG_BANK_RX1 -
3064 MDIO_XS_8706_REG_BANK_RX0);
3065 bnx2x_cl45_read(bp, params->port,
3066 ext_phy_type,
3067 ext_phy_addr,
3068 MDIO_XS_DEVAD,
3069 reg, &val);
3070 /* Clear first 3 bits of the control */
3071 val &= ~0x7;
3072 /* Set control bits according to
3073 configuation */
3074 val |= (params->xgxs_config_rx[i] &
3075 0x7);
3076 DP(NETIF_MSG_LINK, "Setting RX"
3077 "Equalizer to BCM8706 reg 0x%x"
3078 " <-- val 0x%x\n", reg, val);
3079 bnx2x_cl45_write(bp, params->port,
3080 ext_phy_type,
3081 ext_phy_addr,
3082 MDIO_XS_DEVAD,
3083 reg, val);
3084 }
3085 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003086 /* Force speed */
3087 /* First enable LASI */
3088 bnx2x_cl45_write(bp, params->port,
3089 ext_phy_type,
3090 ext_phy_addr,
3091 MDIO_PMA_DEVAD,
3092 MDIO_PMA_REG_RX_ALARM_CTRL,
3093 0x0400);
3094 bnx2x_cl45_write(bp, params->port,
3095 ext_phy_type,
3096 ext_phy_addr,
3097 MDIO_PMA_DEVAD,
3098 MDIO_PMA_REG_LASI_CTRL, 0x0004);
3099
3100 if (params->req_line_speed == SPEED_10000) {
3101 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
3102
3103 bnx2x_cl45_write(bp, params->port,
3104 ext_phy_type,
3105 ext_phy_addr,
3106 MDIO_PMA_DEVAD,
3107 MDIO_PMA_REG_DIGITAL_CTRL,
3108 0x400);
3109 } else {
3110 /* Force 1Gbps using autoneg with 1G
3111 advertisment */
3112
3113 /* Allow CL37 through CL73 */
3114 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3115 bnx2x_cl45_write(bp, params->port,
3116 ext_phy_type,
3117 ext_phy_addr,
3118 MDIO_AN_DEVAD,
3119 MDIO_AN_REG_CL37_CL73,
3120 0x040c);
3121
3122 /* Enable Full-Duplex advertisment on CL37 */
3123 bnx2x_cl45_write(bp, params->port,
3124 ext_phy_type,
3125 ext_phy_addr,
3126 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003127 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003128 0x0020);
3129 /* Enable CL37 AN */
3130 bnx2x_cl45_write(bp, params->port,
3131 ext_phy_type,
3132 ext_phy_addr,
3133 MDIO_AN_DEVAD,
3134 MDIO_AN_REG_CL37_AN,
3135 0x1000);
3136 /* 1G support */
3137 bnx2x_cl45_write(bp, params->port,
3138 ext_phy_type,
3139 ext_phy_addr,
3140 MDIO_AN_DEVAD,
3141 MDIO_AN_REG_ADV, (1<<5));
3142
3143 /* Enable clause 73 AN */
3144 bnx2x_cl45_write(bp, params->port,
3145 ext_phy_type,
3146 ext_phy_addr,
3147 MDIO_AN_DEVAD,
3148 MDIO_AN_REG_CTRL,
3149 0x1200);
3150
3151 }
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003152 bnx2x_save_bcm_spirom_ver(bp, params->port,
3153 ext_phy_type,
3154 ext_phy_addr,
3155 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003156 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003157 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3158 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3159 bnx2x_bcm8726_external_rom_boot(params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003160
Eilon Greenstein589abe32009-02-12 08:36:55 +00003161 /* Need to call module detected on initialization since
3162 the module detection triggered by actual module
3163 insertion might occur before driver is loaded, and when
3164 driver is loaded, it reset all registers, including the
3165 transmitter */
3166 bnx2x_sfp_module_detection(params);
3167 if (params->req_line_speed == SPEED_1000) {
3168 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3169 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3170 ext_phy_addr, MDIO_PMA_DEVAD,
3171 MDIO_PMA_REG_CTRL, 0x40);
3172 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3173 ext_phy_addr, MDIO_PMA_DEVAD,
3174 MDIO_PMA_REG_10G_CTRL2, 0xD);
3175 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3176 ext_phy_addr, MDIO_PMA_DEVAD,
3177 MDIO_PMA_REG_LASI_CTRL, 0x5);
3178 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3179 ext_phy_addr, MDIO_PMA_DEVAD,
3180 MDIO_PMA_REG_RX_ALARM_CTRL,
3181 0x400);
3182 } else if ((params->req_line_speed ==
3183 SPEED_AUTO_NEG) &&
3184 ((params->speed_cap_mask &
3185 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
3186 DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
3187 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3188 ext_phy_addr, MDIO_AN_DEVAD,
3189 MDIO_AN_REG_ADV, 0x20);
3190 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3191 ext_phy_addr, MDIO_AN_DEVAD,
3192 MDIO_AN_REG_CL37_CL73, 0x040c);
3193 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3194 ext_phy_addr, MDIO_AN_DEVAD,
3195 MDIO_AN_REG_CL37_FC_LD, 0x0020);
3196 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3197 ext_phy_addr, MDIO_AN_DEVAD,
3198 MDIO_AN_REG_CL37_AN, 0x1000);
3199 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3200 ext_phy_addr, MDIO_AN_DEVAD,
3201 MDIO_AN_REG_CTRL, 0x1200);
3202
3203 /* Enable RX-ALARM control to receive
3204 interrupt for 1G speed change */
3205 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3206 ext_phy_addr, MDIO_PMA_DEVAD,
3207 MDIO_PMA_REG_LASI_CTRL, 0x4);
3208 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3209 ext_phy_addr, MDIO_PMA_DEVAD,
3210 MDIO_PMA_REG_RX_ALARM_CTRL,
3211 0x400);
3212
3213 } else { /* Default 10G. Set only LASI control */
3214 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3215 ext_phy_addr, MDIO_PMA_DEVAD,
3216 MDIO_PMA_REG_LASI_CTRL, 1);
3217 }
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003218
3219 /* Set TX PreEmphasis if needed */
3220 if ((params->feature_config_flags &
3221 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3222 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
3223 "TX_CTRL2 0x%x\n",
3224 params->xgxs_config_tx[0],
3225 params->xgxs_config_tx[1]);
3226 bnx2x_cl45_write(bp, params->port,
3227 ext_phy_type,
3228 ext_phy_addr,
3229 MDIO_PMA_DEVAD,
3230 MDIO_PMA_REG_8726_TX_CTRL1,
3231 params->xgxs_config_tx[0]);
3232
3233 bnx2x_cl45_write(bp, params->port,
3234 ext_phy_type,
3235 ext_phy_addr,
3236 MDIO_PMA_DEVAD,
3237 MDIO_PMA_REG_8726_TX_CTRL2,
3238 params->xgxs_config_tx[1]);
3239 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00003240 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003241 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3242 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3243 {
3244 u16 tmp1;
3245 u16 rx_alarm_ctrl_val;
3246 u16 lasi_ctrl_val;
3247 if (ext_phy_type ==
3248 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3249 rx_alarm_ctrl_val = 0x400;
3250 lasi_ctrl_val = 0x0004;
3251 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003252 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003253 lasi_ctrl_val = 0x0004;
3254 }
3255
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003256 /* enable LASI */
3257 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003258 ext_phy_type,
3259 ext_phy_addr,
3260 MDIO_PMA_DEVAD,
3261 MDIO_PMA_REG_RX_ALARM_CTRL,
3262 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003263
3264 bnx2x_cl45_write(bp, params->port,
3265 ext_phy_type,
3266 ext_phy_addr,
3267 MDIO_PMA_DEVAD,
3268 MDIO_PMA_REG_LASI_CTRL,
3269 lasi_ctrl_val);
3270
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003271 bnx2x_8073_set_pause_cl37(params, vars);
3272
3273 if (ext_phy_type ==
3274 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){
3275 bnx2x_bcm8072_external_rom_boot(params);
3276 } else {
3277
3278 /* In case of 8073 with long xaui lines,
3279 don't set the 8073 xaui low power*/
3280 bnx2x_bcm8073_set_xaui_low_power_mode(params);
3281 }
3282
3283 bnx2x_cl45_read(bp, params->port,
3284 ext_phy_type,
3285 ext_phy_addr,
3286 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003287 MDIO_PMA_REG_M8051_MSGOUT_REG,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003288 &tmp1);
3289
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003290 bnx2x_cl45_read(bp, params->port,
3291 ext_phy_type,
3292 ext_phy_addr,
3293 MDIO_PMA_DEVAD,
3294 MDIO_PMA_REG_RX_ALARM, &tmp1);
3295
3296 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
3297 "0x%x\n", tmp1);
3298
3299 /* If this is forced speed, set to KR or KX
3300 * (all other are not supported)
3301 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003302 if (params->loopback_mode == LOOPBACK_EXT) {
3303 bnx2x_bcm807x_force_10G(params);
3304 DP(NETIF_MSG_LINK,
3305 "Forced speed 10G on 807X\n");
3306 break;
3307 } else {
3308 bnx2x_cl45_write(bp, params->port,
3309 ext_phy_type, ext_phy_addr,
3310 MDIO_PMA_DEVAD,
3311 MDIO_PMA_REG_BCM_CTRL,
3312 0x0002);
3313 }
3314 if (params->req_line_speed != SPEED_AUTO_NEG) {
3315 if (params->req_line_speed == SPEED_10000) {
3316 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003317 } else if (params->req_line_speed ==
3318 SPEED_2500) {
3319 val = (1<<5);
3320 /* Note that 2.5G works only
3321 when used with 1G advertisment */
3322 } else
3323 val = (1<<5);
3324 } else {
3325
3326 val = 0;
3327 if (params->speed_cap_mask &
3328 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3329 val |= (1<<7);
3330
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003331 /* Note that 2.5G works only when
3332 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003333 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003334 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3335 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003336 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003337 DP(NETIF_MSG_LINK,
3338 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003339 }
3340
3341 bnx2x_cl45_write(bp, params->port,
3342 ext_phy_type,
3343 ext_phy_addr,
3344 MDIO_AN_DEVAD,
3345 MDIO_AN_REG_ADV, val);
3346
3347 if (ext_phy_type ==
3348 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003349
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003350 bnx2x_cl45_read(bp, params->port,
3351 ext_phy_type,
3352 ext_phy_addr,
3353 MDIO_AN_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003354 MDIO_AN_REG_8073_2_5G, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003355
3356 if (((params->speed_cap_mask &
3357 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3358 (params->req_line_speed ==
3359 SPEED_AUTO_NEG)) ||
3360 (params->req_line_speed ==
3361 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003362 u16 phy_ver;
3363 /* Allow 2.5G for A1 and above */
3364 bnx2x_cl45_read(bp, params->port,
3365 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
3366 ext_phy_addr,
3367 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003368 MDIO_PMA_REG_8073_CHIP_REV, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003369 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003370 if (phy_ver > 0)
3371 tmp1 |= 1;
3372 else
3373 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003374 } else {
3375 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003376 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003377 }
3378
3379 bnx2x_cl45_write(bp, params->port,
3380 ext_phy_type,
3381 ext_phy_addr,
3382 MDIO_AN_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003383 MDIO_AN_REG_8073_2_5G, tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003384 }
3385
3386 /* Add support for CL37 (passive mode) II */
3387
3388 bnx2x_cl45_read(bp, params->port,
3389 ext_phy_type,
3390 ext_phy_addr,
3391 MDIO_AN_DEVAD,
3392 MDIO_AN_REG_CL37_FC_LD,
3393 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003394
3395 bnx2x_cl45_write(bp, params->port,
3396 ext_phy_type,
3397 ext_phy_addr,
3398 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003399 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
3400 ((params->req_duplex == DUPLEX_FULL) ?
3401 0x20 : 0x40)));
3402
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003403 /* Add support for CL37 (passive mode) III */
3404 bnx2x_cl45_write(bp, params->port,
3405 ext_phy_type,
3406 ext_phy_addr,
3407 MDIO_AN_DEVAD,
3408 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003409
3410 if (ext_phy_type ==
3411 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003412 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003413 BW and FEE main tap. Rest commands are executed
3414 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003415 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003416 if (bnx2x_8073_is_snr_needed(params))
3417 bnx2x_cl45_write(bp, params->port,
3418 ext_phy_type,
3419 ext_phy_addr,
3420 MDIO_PMA_DEVAD,
3421 MDIO_PMA_REG_EDC_FFE_MAIN,
3422 0xFB0C);
3423
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003424 /* Enable FEC (Forware Error Correction)
3425 Request in the AN */
3426 bnx2x_cl45_read(bp, params->port,
3427 ext_phy_type,
3428 ext_phy_addr,
3429 MDIO_AN_DEVAD,
3430 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003431
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003432 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003433
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003434 bnx2x_cl45_write(bp, params->port,
3435 ext_phy_type,
3436 ext_phy_addr,
3437 MDIO_AN_DEVAD,
3438 MDIO_AN_REG_ADV2, tmp1);
3439
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003440 }
3441
3442 bnx2x_ext_phy_set_pause(params, vars);
3443
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003444 /* Restart autoneg */
3445 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003446 bnx2x_cl45_write(bp, params->port,
3447 ext_phy_type,
3448 ext_phy_addr,
3449 MDIO_AN_DEVAD,
3450 MDIO_AN_REG_CTRL, 0x1200);
3451 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
3452 "Advertise 1G=%x, 10G=%x\n",
3453 ((val & (1<<5)) > 0),
3454 ((val & (1<<7)) > 0));
3455 break;
3456 }
3457 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003458 {
3459 u16 fw_ver1, fw_ver2;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003460 DP(NETIF_MSG_LINK,
3461 "Setting the SFX7101 LASI indication\n");
3462
3463 bnx2x_cl45_write(bp, params->port,
3464 ext_phy_type,
3465 ext_phy_addr,
3466 MDIO_PMA_DEVAD,
3467 MDIO_PMA_REG_LASI_CTRL, 0x1);
3468 DP(NETIF_MSG_LINK,
3469 "Setting the SFX7101 LED to blink on traffic\n");
3470 bnx2x_cl45_write(bp, params->port,
3471 ext_phy_type,
3472 ext_phy_addr,
3473 MDIO_PMA_DEVAD,
3474 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
3475
3476 bnx2x_ext_phy_set_pause(params, vars);
3477 /* Restart autoneg */
3478 bnx2x_cl45_read(bp, params->port,
3479 ext_phy_type,
3480 ext_phy_addr,
3481 MDIO_AN_DEVAD,
3482 MDIO_AN_REG_CTRL, &val);
3483 val |= 0x200;
3484 bnx2x_cl45_write(bp, params->port,
3485 ext_phy_type,
3486 ext_phy_addr,
3487 MDIO_AN_DEVAD,
3488 MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003489
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003490 /* Save spirom version */
3491 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3492 ext_phy_addr, MDIO_PMA_DEVAD,
3493 MDIO_PMA_REG_7101_VER1, &fw_ver1);
3494
3495 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3496 ext_phy_addr, MDIO_PMA_DEVAD,
3497 MDIO_PMA_REG_7101_VER2, &fw_ver2);
3498
3499 bnx2x_save_spirom_version(params->bp, params->port,
3500 params->shmem_base,
3501 (u32)(fw_ver1<<16 | fw_ver2));
3502
Eilon Greenstein28577182009-02-12 08:37:00 +00003503 break;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003504 }
Eilon Greenstein28577182009-02-12 08:37:00 +00003505 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
3506 DP(NETIF_MSG_LINK,
3507 "Setting the BCM8481 LASI control\n");
3508
3509 bnx2x_cl45_write(bp, params->port,
3510 ext_phy_type,
3511 ext_phy_addr,
3512 MDIO_PMA_DEVAD,
3513 MDIO_PMA_REG_LASI_CTRL, 0x1);
3514
3515 /* Restart autoneg */
3516 bnx2x_cl45_read(bp, params->port,
3517 ext_phy_type,
3518 ext_phy_addr,
3519 MDIO_AN_DEVAD,
3520 MDIO_AN_REG_CTRL, &val);
3521 val |= 0x200;
3522 bnx2x_cl45_write(bp, params->port,
3523 ext_phy_type,
3524 ext_phy_addr,
3525 MDIO_AN_DEVAD,
3526 MDIO_AN_REG_CTRL, val);
3527
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003528 bnx2x_save_bcm_spirom_ver(bp, params->port,
3529 ext_phy_type,
3530 ext_phy_addr,
3531 params->shmem_base);
3532
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003533 break;
3534 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
3535 DP(NETIF_MSG_LINK,
3536 "XGXS PHY Failure detected 0x%x\n",
3537 params->ext_phy_config);
3538 rc = -EINVAL;
3539 break;
3540 default:
3541 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3542 params->ext_phy_config);
3543 rc = -EINVAL;
3544 break;
3545 }
3546
3547 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003548
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003549 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3550 switch (ext_phy_type) {
3551 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3552 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3553 break;
3554
3555 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3556 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3557 break;
3558
3559 default:
3560 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
3561 params->ext_phy_config);
3562 break;
3563 }
3564 }
3565 return rc;
3566}
3567
3568
3569static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003570 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003571{
3572 struct bnx2x *bp = params->bp;
3573 u32 ext_phy_type;
3574 u8 ext_phy_addr;
3575 u16 val1 = 0, val2;
3576 u16 rx_sd, pcs_status;
3577 u8 ext_phy_link_up = 0;
3578 u8 port = params->port;
3579 if (vars->phy_flags & PHY_XGXS_FLAG) {
3580 ext_phy_addr = ((params->ext_phy_config &
3581 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3582 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3583
3584 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3585 switch (ext_phy_type) {
3586 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3587 DP(NETIF_MSG_LINK, "XGXS Direct\n");
3588 ext_phy_link_up = 1;
3589 break;
3590
3591 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3592 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3593 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3594 ext_phy_addr,
3595 MDIO_WIS_DEVAD,
3596 MDIO_WIS_REG_LASI_STATUS, &val1);
3597 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3598
3599 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3600 ext_phy_addr,
3601 MDIO_WIS_DEVAD,
3602 MDIO_WIS_REG_LASI_STATUS, &val1);
3603 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3604
3605 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3606 ext_phy_addr,
3607 MDIO_PMA_DEVAD,
3608 MDIO_PMA_REG_RX_SD, &rx_sd);
3609 DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
3610 ext_phy_link_up = (rx_sd & 0x1);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003611 if (ext_phy_link_up)
3612 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003613 break;
3614
3615 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00003616 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3617 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
3618 /* Clear RX Alarm*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003619 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3620 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00003621 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
3622 &val2);
3623 /* clear LASI indication*/
3624 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3625 ext_phy_addr,
3626 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
3627 &val1);
3628 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3629 ext_phy_addr,
3630 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
3631 &val2);
3632 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
3633 "0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003634
3635 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3636 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00003637 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
3638 &rx_sd);
3639 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3640 ext_phy_addr,
3641 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
3642 &pcs_status);
3643 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3644 ext_phy_addr,
3645 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
3646 &val2);
3647 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3648 ext_phy_addr,
3649 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
3650 &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003651
Eilon Greenstein589abe32009-02-12 08:36:55 +00003652 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003653 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
3654 rx_sd, pcs_status, val2);
3655 /* link is up if both bit 0 of pmd_rx_sd and
3656 * bit 0 of pcs_status are set, or if the autoneg bit
3657 1 is set
3658 */
3659 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
3660 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003661 if (ext_phy_link_up) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003662 if (ext_phy_type ==
3663 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
3664 /* If transmitter is disabled,
3665 ignore false link up indication */
3666 bnx2x_cl45_read(bp, params->port,
3667 ext_phy_type,
3668 ext_phy_addr,
3669 MDIO_PMA_DEVAD,
3670 MDIO_PMA_REG_PHY_IDENTIFIER,
3671 &val1);
3672 if (val1 & (1<<15)) {
3673 DP(NETIF_MSG_LINK, "Tx is "
3674 "disabled\n");
3675 ext_phy_link_up = 0;
3676 break;
3677 }
3678 }
3679
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003680 if (val2 & (1<<1))
3681 vars->line_speed = SPEED_1000;
3682 else
3683 vars->line_speed = SPEED_10000;
3684 }
3685
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003686 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003687 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3688 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3689 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003690 u16 link_status = 0;
3691 u16 an1000_status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003692 if (ext_phy_type ==
3693 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3694 bnx2x_cl45_read(bp, params->port,
3695 ext_phy_type,
3696 ext_phy_addr,
3697 MDIO_PCS_DEVAD,
3698 MDIO_PCS_REG_LASI_STATUS, &val1);
3699 bnx2x_cl45_read(bp, params->port,
3700 ext_phy_type,
3701 ext_phy_addr,
3702 MDIO_PCS_DEVAD,
3703 MDIO_PCS_REG_LASI_STATUS, &val2);
3704 DP(NETIF_MSG_LINK,
3705 "870x LASI status 0x%x->0x%x\n",
3706 val1, val2);
3707
3708 } else {
3709 /* In 8073, port1 is directed through emac0 and
3710 * port0 is directed through emac1
3711 */
3712 bnx2x_cl45_read(bp, params->port,
3713 ext_phy_type,
3714 ext_phy_addr,
3715 MDIO_PMA_DEVAD,
3716 MDIO_PMA_REG_LASI_STATUS, &val1);
3717
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003718 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003719 "8703 LASI status 0x%x\n",
3720 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003721 }
3722
3723 /* clear the interrupt LASI status register */
3724 bnx2x_cl45_read(bp, params->port,
3725 ext_phy_type,
3726 ext_phy_addr,
3727 MDIO_PCS_DEVAD,
3728 MDIO_PCS_REG_STATUS, &val2);
3729 bnx2x_cl45_read(bp, params->port,
3730 ext_phy_type,
3731 ext_phy_addr,
3732 MDIO_PCS_DEVAD,
3733 MDIO_PCS_REG_STATUS, &val1);
3734 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
3735 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003736 /* Clear MSG-OUT */
3737 bnx2x_cl45_read(bp, params->port,
3738 ext_phy_type,
3739 ext_phy_addr,
3740 MDIO_PMA_DEVAD,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003741 MDIO_PMA_REG_M8051_MSGOUT_REG,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003742 &val1);
3743
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003744 /* Check the LASI */
3745 bnx2x_cl45_read(bp, params->port,
3746 ext_phy_type,
3747 ext_phy_addr,
3748 MDIO_PMA_DEVAD,
3749 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003750
3751 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3752
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003753 /* Check the link status */
3754 bnx2x_cl45_read(bp, params->port,
3755 ext_phy_type,
3756 ext_phy_addr,
3757 MDIO_PCS_DEVAD,
3758 MDIO_PCS_REG_STATUS, &val2);
3759 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3760
3761 bnx2x_cl45_read(bp, params->port,
3762 ext_phy_type,
3763 ext_phy_addr,
3764 MDIO_PMA_DEVAD,
3765 MDIO_PMA_REG_STATUS, &val2);
3766 bnx2x_cl45_read(bp, params->port,
3767 ext_phy_type,
3768 ext_phy_addr,
3769 MDIO_PMA_DEVAD,
3770 MDIO_PMA_REG_STATUS, &val1);
3771 ext_phy_link_up = ((val1 & 4) == 4);
3772 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3773 if (ext_phy_type ==
3774 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003775
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003776 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003777 ((params->req_line_speed !=
3778 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003779 if (bnx2x_bcm8073_xaui_wa(params)
3780 != 0) {
3781 ext_phy_link_up = 0;
3782 break;
3783 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003784 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003785 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003786 ext_phy_type,
3787 ext_phy_addr,
3788 MDIO_AN_DEVAD,
3789 MDIO_AN_REG_LINK_STATUS,
3790 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003791 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003792 ext_phy_type,
3793 ext_phy_addr,
3794 MDIO_AN_DEVAD,
3795 MDIO_AN_REG_LINK_STATUS,
3796 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003797
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003798 /* Check the link status on 1.1.2 */
3799 bnx2x_cl45_read(bp, params->port,
3800 ext_phy_type,
3801 ext_phy_addr,
3802 MDIO_PMA_DEVAD,
3803 MDIO_PMA_REG_STATUS, &val2);
3804 bnx2x_cl45_read(bp, params->port,
3805 ext_phy_type,
3806 ext_phy_addr,
3807 MDIO_PMA_DEVAD,
3808 MDIO_PMA_REG_STATUS, &val1);
3809 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3810 "an_link_status=0x%x\n",
3811 val2, val1, an1000_status);
3812
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003813 ext_phy_link_up = (((val1 & 4) == 4) ||
3814 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003815 if (ext_phy_link_up &&
3816 bnx2x_8073_is_snr_needed(params)) {
3817 /* The SNR will improve about 2dbby
3818 changing the BW and FEE main tap.*/
3819
3820 /* The 1st write to change FFE main
3821 tap is set before restart AN */
3822 /* Change PLL Bandwidth in EDC
3823 register */
3824 bnx2x_cl45_write(bp, port, ext_phy_type,
3825 ext_phy_addr,
3826 MDIO_PMA_DEVAD,
3827 MDIO_PMA_REG_PLL_BANDWIDTH,
3828 0x26BC);
3829
3830 /* Change CDR Bandwidth in EDC
3831 register */
3832 bnx2x_cl45_write(bp, port, ext_phy_type,
3833 ext_phy_addr,
3834 MDIO_PMA_DEVAD,
3835 MDIO_PMA_REG_CDR_BANDWIDTH,
3836 0x0333);
3837
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003838
3839 }
3840 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003841 ext_phy_type,
3842 ext_phy_addr,
3843 MDIO_PMA_DEVAD,
3844 MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
3845 &link_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003846
3847 /* Bits 0..2 --> speed detected,
3848 bits 13..15--> link is down */
3849 if ((link_status & (1<<2)) &&
3850 (!(link_status & (1<<15)))) {
3851 ext_phy_link_up = 1;
3852 vars->line_speed = SPEED_10000;
3853 DP(NETIF_MSG_LINK,
3854 "port %x: External link"
3855 " up in 10G\n", params->port);
3856 } else if ((link_status & (1<<1)) &&
3857 (!(link_status & (1<<14)))) {
3858 ext_phy_link_up = 1;
3859 vars->line_speed = SPEED_2500;
3860 DP(NETIF_MSG_LINK,
3861 "port %x: External link"
3862 " up in 2.5G\n", params->port);
3863 } else if ((link_status & (1<<0)) &&
3864 (!(link_status & (1<<13)))) {
3865 ext_phy_link_up = 1;
3866 vars->line_speed = SPEED_1000;
3867 DP(NETIF_MSG_LINK,
3868 "port %x: External link"
3869 " up in 1G\n", params->port);
3870 } else {
3871 ext_phy_link_up = 0;
3872 DP(NETIF_MSG_LINK,
3873 "port %x: External link"
3874 " is down\n", params->port);
3875 }
3876 } else {
3877 /* See if 1G link is up for the 8072 */
3878 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003879 ext_phy_type,
3880 ext_phy_addr,
3881 MDIO_AN_DEVAD,
3882 MDIO_AN_REG_LINK_STATUS,
3883 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003884 bnx2x_cl45_read(bp, params->port,
Eilon Greenstein052a38e2009-02-12 08:37:16 +00003885 ext_phy_type,
3886 ext_phy_addr,
3887 MDIO_AN_DEVAD,
3888 MDIO_AN_REG_LINK_STATUS,
3889 &an1000_status);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003890 if (an1000_status & (1<<1)) {
3891 ext_phy_link_up = 1;
3892 vars->line_speed = SPEED_1000;
3893 DP(NETIF_MSG_LINK,
3894 "port %x: External link"
3895 " up in 1G\n", params->port);
3896 } else if (ext_phy_link_up) {
3897 ext_phy_link_up = 1;
3898 vars->line_speed = SPEED_10000;
3899 DP(NETIF_MSG_LINK,
3900 "port %x: External link"
3901 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003902 }
3903 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003904
3905
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003906 break;
3907 }
3908 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3909 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3910 ext_phy_addr,
3911 MDIO_PMA_DEVAD,
3912 MDIO_PMA_REG_LASI_STATUS, &val2);
3913 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3914 ext_phy_addr,
3915 MDIO_PMA_DEVAD,
3916 MDIO_PMA_REG_LASI_STATUS, &val1);
3917 DP(NETIF_MSG_LINK,
3918 "10G-base-T LASI status 0x%x->0x%x\n",
3919 val2, val1);
3920 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3921 ext_phy_addr,
3922 MDIO_PMA_DEVAD,
3923 MDIO_PMA_REG_STATUS, &val2);
3924 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3925 ext_phy_addr,
3926 MDIO_PMA_DEVAD,
3927 MDIO_PMA_REG_STATUS, &val1);
3928 DP(NETIF_MSG_LINK,
3929 "10G-base-T PMA status 0x%x->0x%x\n",
3930 val2, val1);
3931 ext_phy_link_up = ((val1 & 4) == 4);
3932 /* if link is up
3933 * print the AN outcome of the SFX7101 PHY
3934 */
3935 if (ext_phy_link_up) {
3936 bnx2x_cl45_read(bp, params->port,
3937 ext_phy_type,
3938 ext_phy_addr,
3939 MDIO_AN_DEVAD,
3940 MDIO_AN_REG_MASTER_STATUS,
3941 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003942 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003943 DP(NETIF_MSG_LINK,
3944 "SFX7101 AN status 0x%x->Master=%x\n",
3945 val2,
3946 (val2 & (1<<14)));
3947 }
3948 break;
Eilon Greenstein28577182009-02-12 08:37:00 +00003949 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
3950 /* Clear LASI interrupt */
3951 bnx2x_cl45_read(bp, params->port,
3952 ext_phy_type,
3953 ext_phy_addr,
3954 MDIO_PMA_DEVAD,
3955 MDIO_PMA_REG_LASI_STATUS, &val1);
3956 DP(NETIF_MSG_LINK, "8481 LASI status reg = 0x%x\n",
3957 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003958
Eilon Greenstein28577182009-02-12 08:37:00 +00003959 /* Check 10G-BaseT link status */
3960 /* Check Global PMD signal ok */
3961 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3962 ext_phy_addr,
3963 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
3964 &rx_sd);
3965 /* Check PCS block lock */
3966 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3967 ext_phy_addr,
3968 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
3969 &pcs_status);
3970 DP(NETIF_MSG_LINK, "8481 1.a = 0x%x, 1.20 = 0x%x\n",
3971 rx_sd, pcs_status);
3972 if (rx_sd & pcs_status & 0x1) {
3973 vars->line_speed = SPEED_10000;
3974 ext_phy_link_up = 1;
3975 } else {
3976
3977 /* Check 1000-BaseT link status */
3978 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3979 ext_phy_addr,
3980 MDIO_AN_DEVAD, 0xFFE1,
3981 &val1);
3982
3983 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3984 ext_phy_addr,
3985 MDIO_AN_DEVAD, 0xFFE1,
3986 &val2);
3987 DP(NETIF_MSG_LINK, "8481 7.FFE1 ="
3988 "0x%x-->0x%x\n", val1, val2);
3989 if (val2 & (1<<2)) {
3990 vars->line_speed = SPEED_1000;
3991 ext_phy_link_up = 1;
3992 }
3993 }
3994
3995 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003996 default:
3997 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3998 params->ext_phy_config);
3999 ext_phy_link_up = 0;
4000 break;
4001 }
4002
4003 } else { /* SerDes */
4004 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4005 switch (ext_phy_type) {
4006 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
4007 DP(NETIF_MSG_LINK, "SerDes Direct\n");
4008 ext_phy_link_up = 1;
4009 break;
4010
4011 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
4012 DP(NETIF_MSG_LINK, "SerDes 5482\n");
4013 ext_phy_link_up = 1;
4014 break;
4015
4016 default:
4017 DP(NETIF_MSG_LINK,
4018 "BAD SerDes ext_phy_config 0x%x\n",
4019 params->ext_phy_config);
4020 ext_phy_link_up = 0;
4021 break;
4022 }
4023 }
4024
4025 return ext_phy_link_up;
4026}
4027
4028static void bnx2x_link_int_enable(struct link_params *params)
4029{
4030 u8 port = params->port;
4031 u32 ext_phy_type;
4032 u32 mask;
4033 struct bnx2x *bp = params->bp;
4034 /* setting the status to report on link up
4035 for either XGXS or SerDes */
4036
4037 if (params->switch_cfg == SWITCH_CFG_10G) {
4038 mask = (NIG_MASK_XGXS0_LINK10G |
4039 NIG_MASK_XGXS0_LINK_STATUS);
4040 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
4041 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4042 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
4043 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
4044 (ext_phy_type !=
4045 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
4046 mask |= NIG_MASK_MI_INT;
4047 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4048 }
4049
4050 } else { /* SerDes */
4051 mask = NIG_MASK_SERDES0_LINK_STATUS;
4052 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
4053 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4054 if ((ext_phy_type !=
4055 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
4056 (ext_phy_type !=
4057 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
4058 mask |= NIG_MASK_MI_INT;
4059 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4060 }
4061 }
4062 bnx2x_bits_en(bp,
4063 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4064 mask);
4065 DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port,
4066 (params->switch_cfg == SWITCH_CFG_10G),
4067 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
4068
4069 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
4070 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4071 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4072 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
4073 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4074 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4075 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4076}
4077
4078
4079/*
4080 * link management
4081 */
4082static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07004083 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004084{
4085 struct bnx2x *bp = params->bp;
4086 u8 port = params->port;
4087
4088 /* first reset all status
4089 * we assume only one line will be change at a time */
4090 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4091 (NIG_STATUS_XGXS0_LINK10G |
4092 NIG_STATUS_XGXS0_LINK_STATUS |
4093 NIG_STATUS_SERDES0_LINK_STATUS));
4094 if (vars->phy_link_up) {
4095 if (is_10g) {
4096 /* Disable the 10G link interrupt
4097 * by writing 1 to the status register
4098 */
4099 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
4100 bnx2x_bits_en(bp,
4101 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4102 NIG_STATUS_XGXS0_LINK10G);
4103
4104 } else if (params->switch_cfg == SWITCH_CFG_10G) {
4105 /* Disable the link interrupt
4106 * by writing 1 to the relevant lane
4107 * in the status register
4108 */
4109 u32 ser_lane = ((params->lane_config &
4110 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
4111 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
4112
4113 DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
4114 bnx2x_bits_en(bp,
4115 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4116 ((1 << ser_lane) <<
4117 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
4118
4119 } else { /* SerDes */
4120 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
4121 /* Disable the link interrupt
4122 * by writing 1 to the status register
4123 */
4124 bnx2x_bits_en(bp,
4125 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4126 NIG_STATUS_SERDES0_LINK_STATUS);
4127 }
4128
4129 } else { /* link_down */
4130 }
4131}
4132
4133static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
4134{
4135 u8 *str_ptr = str;
4136 u32 mask = 0xf0000000;
4137 u8 shift = 8*4;
4138 u8 digit;
4139 if (len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02004140 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004141 *str_ptr = '\0';
4142 return -EINVAL;
4143 }
4144 while (shift > 0) {
4145
4146 shift -= 4;
4147 digit = ((num & mask) >> shift);
4148 if (digit < 0xa)
4149 *str_ptr = digit + '0';
4150 else
4151 *str_ptr = digit - 0xa + 'a';
4152 str_ptr++;
4153 mask = mask >> 4;
4154 if (shift == 4*4) {
4155 *str_ptr = ':';
4156 str_ptr++;
4157 }
4158 }
4159 *str_ptr = '\0';
4160 return 0;
4161}
4162
4163
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004164static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr,
4165 u32 ext_phy_type)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004166{
4167 u32 cnt = 0;
4168 u16 ctrl = 0;
4169 /* Enable EMAC0 in to enable MDIO */
4170 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
4171 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
4172 msleep(5);
4173
4174 /* take ext phy out of reset */
4175 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004176 MISC_REGISTERS_GPIO_2,
4177 MISC_REGISTERS_GPIO_HIGH,
4178 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004179
4180 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004181 MISC_REGISTERS_GPIO_1,
4182 MISC_REGISTERS_GPIO_HIGH,
4183 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004184
4185 /* wait for 5ms */
4186 msleep(5);
4187
4188 for (cnt = 0; cnt < 1000; cnt++) {
4189 msleep(1);
4190 bnx2x_cl45_read(bp, port,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004191 ext_phy_type,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004192 ext_phy_addr,
4193 MDIO_PMA_DEVAD,
4194 MDIO_PMA_REG_CTRL,
4195 &ctrl);
4196 if (!(ctrl & (1<<15))) {
4197 DP(NETIF_MSG_LINK, "Reset completed\n\n");
4198 break;
4199 }
4200 }
4201}
4202
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004203static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004204{
4205 /* put sf to reset */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004206 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004207 MISC_REGISTERS_GPIO_1,
4208 MISC_REGISTERS_GPIO_LOW,
4209 port);
4210 bnx2x_set_gpio(bp,
4211 MISC_REGISTERS_GPIO_2,
4212 MISC_REGISTERS_GPIO_LOW,
4213 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004214}
4215
4216u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
4217 u8 *version, u16 len)
4218{
4219 struct bnx2x *bp = params->bp;
4220 u32 ext_phy_type = 0;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004221 u32 spirom_ver = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004222 u8 status = 0 ;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004223
4224 if (version == NULL || params == NULL)
4225 return -EINVAL;
4226
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004227 spirom_ver = REG_RD(bp, params->shmem_base +
4228 offsetof(struct shmem_region,
4229 port_mb[params->port].ext_phy_fw_version));
4230
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004231 /* reset the returned value to zero */
4232 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004233 switch (ext_phy_type) {
4234 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4235
4236 if (len < 5)
4237 return -EINVAL;
4238
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004239 version[0] = (spirom_ver & 0xFF);
4240 version[1] = (spirom_ver & 0xFF00) >> 8;
4241 version[2] = (spirom_ver & 0xFF0000) >> 16;
4242 version[3] = (spirom_ver & 0xFF000000) >> 24;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004243 version[4] = '\0';
4244
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004245 break;
4246 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4247 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004248 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4249 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00004250 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004251 status = bnx2x_format_ver(spirom_ver, version, len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004252 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004253 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4254 break;
4255
4256 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4257 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
4258 " type is FAILURE!\n");
4259 status = -EINVAL;
4260 break;
4261
4262 default:
4263 break;
4264 }
4265 return status;
4266}
4267
4268static void bnx2x_set_xgxs_loopback(struct link_params *params,
4269 struct link_vars *vars,
4270 u8 is_10g)
4271{
4272 u8 port = params->port;
4273 struct bnx2x *bp = params->bp;
4274
4275 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07004276 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004277
4278 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
4279
4280 /* change the uni_phy_addr in the nig */
4281 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
4282 port*0x18));
4283
4284 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
4285
4286 bnx2x_cl45_write(bp, port, 0,
4287 params->phy_addr,
4288 5,
4289 (MDIO_REG_BANK_AER_BLOCK +
4290 (MDIO_AER_BLOCK_AER_REG & 0xf)),
4291 0x2800);
4292
4293 bnx2x_cl45_write(bp, port, 0,
4294 params->phy_addr,
4295 5,
4296 (MDIO_REG_BANK_CL73_IEEEB0 +
4297 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
4298 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00004299 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004300 /* set aer mmd back */
4301 bnx2x_set_aer_mmd(params, vars);
4302
4303 /* and md_devad */
4304 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
4305 md_devad);
4306
4307 } else {
4308 u16 mii_control;
4309
4310 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
4311
4312 CL45_RD_OVER_CL22(bp, port,
4313 params->phy_addr,
4314 MDIO_REG_BANK_COMBO_IEEE0,
4315 MDIO_COMBO_IEEE0_MII_CONTROL,
4316 &mii_control);
4317
4318 CL45_WR_OVER_CL22(bp, port,
4319 params->phy_addr,
4320 MDIO_REG_BANK_COMBO_IEEE0,
4321 MDIO_COMBO_IEEE0_MII_CONTROL,
4322 (mii_control |
4323 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
4324 }
4325}
4326
4327
4328static void bnx2x_ext_phy_loopback(struct link_params *params)
4329{
4330 struct bnx2x *bp = params->bp;
4331 u8 ext_phy_addr;
4332 u32 ext_phy_type;
4333
4334 if (params->switch_cfg == SWITCH_CFG_10G) {
4335 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4336 /* CL37 Autoneg Enabled */
4337 ext_phy_addr = ((params->ext_phy_config &
4338 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4339 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4340 switch (ext_phy_type) {
4341 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4342 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
4343 DP(NETIF_MSG_LINK,
4344 "ext_phy_loopback: We should not get here\n");
4345 break;
4346 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4347 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
4348 break;
4349 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
4350 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
4351 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00004352 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4353 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4354 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4355 ext_phy_addr,
4356 MDIO_PMA_DEVAD,
4357 MDIO_PMA_REG_CTRL,
4358 0x0001);
4359 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004360 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4361 /* SFX7101_XGXS_TEST1 */
4362 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4363 ext_phy_addr,
4364 MDIO_XS_DEVAD,
4365 MDIO_XS_SFX7101_XGXS_TEST1,
4366 0x100);
4367 DP(NETIF_MSG_LINK,
4368 "ext_phy_loopback: set ext phy loopback\n");
4369 break;
4370 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4371
4372 break;
4373 } /* switch external PHY type */
4374 } else {
4375 /* serdes */
4376 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4377 ext_phy_addr = (params->ext_phy_config &
4378 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
4379 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
4380 }
4381}
4382
4383
4384/*
4385 *------------------------------------------------------------------------
4386 * bnx2x_override_led_value -
4387 *
4388 * Override the led value of the requsted led
4389 *
4390 *------------------------------------------------------------------------
4391 */
4392u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
4393 u32 led_idx, u32 value)
4394{
4395 u32 reg_val;
4396
4397 /* If port 0 then use EMAC0, else use EMAC1*/
4398 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
4399
4400 DP(NETIF_MSG_LINK,
4401 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
4402 port, led_idx, value);
4403
4404 switch (led_idx) {
4405 case 0: /* 10MB led */
4406 /* Read the current value of the LED register in
4407 the EMAC block */
4408 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4409 /* Set the OVERRIDE bit to 1 */
4410 reg_val |= EMAC_LED_OVERRIDE;
4411 /* If value is 1, set the 10M_OVERRIDE bit,
4412 otherwise reset it.*/
4413 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
4414 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
4415 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4416 break;
4417 case 1: /*100MB led */
4418 /*Read the current value of the LED register in
4419 the EMAC block */
4420 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4421 /* Set the OVERRIDE bit to 1 */
4422 reg_val |= EMAC_LED_OVERRIDE;
4423 /* If value is 1, set the 100M_OVERRIDE bit,
4424 otherwise reset it.*/
4425 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
4426 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
4427 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4428 break;
4429 case 2: /* 1000MB led */
4430 /* Read the current value of the LED register in the
4431 EMAC block */
4432 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4433 /* Set the OVERRIDE bit to 1 */
4434 reg_val |= EMAC_LED_OVERRIDE;
4435 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
4436 reset it. */
4437 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
4438 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
4439 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4440 break;
4441 case 3: /* 2500MB led */
4442 /* Read the current value of the LED register in the
4443 EMAC block*/
4444 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4445 /* Set the OVERRIDE bit to 1 */
4446 reg_val |= EMAC_LED_OVERRIDE;
4447 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
4448 reset it.*/
4449 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
4450 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
4451 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4452 break;
4453 case 4: /*10G led */
4454 if (port == 0) {
4455 REG_WR(bp, NIG_REG_LED_10G_P0,
4456 value);
4457 } else {
4458 REG_WR(bp, NIG_REG_LED_10G_P1,
4459 value);
4460 }
4461 break;
4462 case 5: /* TRAFFIC led */
4463 /* Find if the traffic control is via BMAC or EMAC */
4464 if (port == 0)
4465 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
4466 else
4467 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
4468
4469 /* Override the traffic led in the EMAC:*/
4470 if (reg_val == 1) {
4471 /* Read the current value of the LED register in
4472 the EMAC block */
4473 reg_val = REG_RD(bp, emac_base +
4474 EMAC_REG_EMAC_LED);
4475 /* Set the TRAFFIC_OVERRIDE bit to 1 */
4476 reg_val |= EMAC_LED_OVERRIDE;
4477 /* If value is 1, set the TRAFFIC bit, otherwise
4478 reset it.*/
4479 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
4480 (reg_val & ~EMAC_LED_TRAFFIC);
4481 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4482 } else { /* Override the traffic led in the BMAC: */
4483 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4484 + port*4, 1);
4485 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
4486 value);
4487 }
4488 break;
4489 default:
4490 DP(NETIF_MSG_LINK,
4491 "bnx2x_override_led_value() unknown led index %d "
4492 "(should be 0-5)\n", led_idx);
4493 return -EINVAL;
4494 }
4495
4496 return 0;
4497}
4498
4499
4500u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
4501 u16 hw_led_mode, u32 chip_id)
4502{
4503 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004504 u32 tmp;
4505 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004506 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
4507 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
4508 speed, hw_led_mode);
4509 switch (mode) {
4510 case LED_MODE_OFF:
4511 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
4512 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4513 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004514
4515 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004516 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004517 break;
4518
4519 case LED_MODE_OPER:
4520 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
4521 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
4522 port*4, 0);
4523 /* Set blinking rate to ~15.9Hz */
4524 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
4525 LED_BLINK_RATE_VAL);
4526 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
4527 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004528 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004529 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004530 (tmp & (~EMAC_LED_OVERRIDE)));
4531
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004532 if (!CHIP_IS_E1H(bp) &&
4533 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004534 (speed == SPEED_1000) ||
4535 (speed == SPEED_100) ||
4536 (speed == SPEED_10))) {
4537 /* On Everest 1 Ax chip versions for speeds less than
4538 10G LED scheme is different */
4539 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4540 + port*4, 1);
4541 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
4542 port*4, 0);
4543 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
4544 port*4, 1);
4545 }
4546 break;
4547
4548 default:
4549 rc = -EINVAL;
4550 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
4551 mode);
4552 break;
4553 }
4554 return rc;
4555
4556}
4557
4558u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
4559{
4560 struct bnx2x *bp = params->bp;
4561 u16 gp_status = 0;
4562
4563 CL45_RD_OVER_CL22(bp, params->port,
4564 params->phy_addr,
4565 MDIO_REG_BANK_GP_STATUS,
4566 MDIO_GP_STATUS_TOP_AN_STATUS1,
4567 &gp_status);
4568 /* link is up only if both local phy and external phy are up */
4569 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
4570 bnx2x_ext_phy_is_link_up(params, vars))
4571 return 0;
4572
4573 return -ESRCH;
4574}
4575
4576static u8 bnx2x_link_initialize(struct link_params *params,
4577 struct link_vars *vars)
4578{
4579 struct bnx2x *bp = params->bp;
4580 u8 port = params->port;
4581 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004582 u8 non_ext_phy;
4583 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004584 /* Activate the external PHY */
4585 bnx2x_ext_phy_reset(params, vars);
4586
4587 bnx2x_set_aer_mmd(params, vars);
4588
4589 if (vars->phy_flags & PHY_XGXS_FLAG)
4590 bnx2x_set_master_ln(params);
4591
4592 rc = bnx2x_reset_unicore(params);
4593 /* reset the SerDes and wait for reset bit return low */
4594 if (rc != 0)
4595 return rc;
4596
4597 bnx2x_set_aer_mmd(params, vars);
4598
4599 /* setting the masterLn_def again after the reset */
4600 if (vars->phy_flags & PHY_XGXS_FLAG) {
4601 bnx2x_set_master_ln(params);
4602 bnx2x_set_swap_lanes(params);
4603 }
4604
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004605 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00004606 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004607 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00004608 (params->req_line_speed == SPEED_10))) ||
4609 (!params->req_line_speed &&
4610 (params->speed_cap_mask >=
4611 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
4612 (params->speed_cap_mask <
4613 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
4614 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004615 vars->phy_flags |= PHY_SGMII_FLAG;
4616 } else {
4617 vars->phy_flags &= ~PHY_SGMII_FLAG;
4618 }
4619 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004620 /* In case of external phy existance, the line speed would be the
4621 line speed linked up by the external phy. In case it is direct only,
4622 then the line_speed during initialization will be equal to the
4623 req_line_speed*/
4624 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004625
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004626 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004627
4628 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004629 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
4630 (params->loopback_mode == LOOPBACK_XGXS_10) ||
4631 (params->loopback_mode == LOOPBACK_EXT_PHY));
4632
4633 if (non_ext_phy ||
Eilon Greenstein589abe32009-02-12 08:36:55 +00004634 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Eilon Greenstein28577182009-02-12 08:37:00 +00004635 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
4636 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004637 if (params->req_line_speed == SPEED_AUTO_NEG)
4638 bnx2x_set_parallel_detection(params, vars->phy_flags);
4639 bnx2x_init_internal_phy(params, vars);
4640 }
4641
4642 if (!non_ext_phy)
4643 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004644
4645 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004646 (NIG_STATUS_XGXS0_LINK10G |
4647 NIG_STATUS_XGXS0_LINK_STATUS |
4648 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004649
4650 return rc;
4651
4652}
4653
4654
4655u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
4656{
4657 struct bnx2x *bp = params->bp;
4658
4659 u32 val;
Eilon Greenstein3196a882008-08-13 15:58:49 -07004660 DP(NETIF_MSG_LINK, "Phy Initialization started \n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004661 DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
4662 params->req_line_speed, params->req_flow_ctrl);
4663 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004664 vars->phy_link_up = 0;
4665 vars->link_up = 0;
4666 vars->line_speed = 0;
4667 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004668 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004669 vars->mac_type = MAC_TYPE_NONE;
4670
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004671 if (params->switch_cfg == SWITCH_CFG_1G)
4672 vars->phy_flags = PHY_SERDES_FLAG;
4673 else
4674 vars->phy_flags = PHY_XGXS_FLAG;
4675
Eilon Greenstein3196a882008-08-13 15:58:49 -07004676
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004677 /* disable attentions */
4678 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
4679 (NIG_MASK_XGXS0_LINK_STATUS |
4680 NIG_MASK_XGXS0_LINK10G |
4681 NIG_MASK_SERDES0_LINK_STATUS |
4682 NIG_MASK_MI_INT));
4683
4684 bnx2x_emac_init(params, vars);
4685
4686 if (CHIP_REV_IS_FPGA(bp)) {
4687 vars->link_up = 1;
4688 vars->line_speed = SPEED_10000;
4689 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004690 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004691 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004692 /* enable on E1.5 FPGA */
4693 if (CHIP_IS_E1H(bp)) {
4694 vars->flow_ctrl |=
David S. Millerc0700f92008-12-16 23:53:20 -08004695 (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004696 vars->link_status |=
4697 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
4698 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
4699 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004700
4701 bnx2x_emac_enable(params, vars, 0);
4702 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4703 /* disable drain */
4704 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4705 + params->port*4, 0);
4706
4707 /* update shared memory */
4708 bnx2x_update_mng(params, vars->link_status);
4709
4710 return 0;
4711
4712 } else
4713 if (CHIP_REV_IS_EMUL(bp)) {
4714
4715 vars->link_up = 1;
4716 vars->line_speed = SPEED_10000;
4717 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004718 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004719 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
4720
4721 bnx2x_bmac_enable(params, vars, 0);
4722
4723 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4724 /* Disable drain */
4725 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4726 + params->port*4, 0);
4727
4728 /* update shared memory */
4729 bnx2x_update_mng(params, vars->link_status);
4730
4731 return 0;
4732
4733 } else
4734 if (params->loopback_mode == LOOPBACK_BMAC) {
4735 vars->link_up = 1;
4736 vars->line_speed = SPEED_10000;
4737 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004738 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004739 vars->mac_type = MAC_TYPE_BMAC;
4740
4741 vars->phy_flags = PHY_XGXS_FLAG;
4742
4743 bnx2x_phy_deassert(params, vars->phy_flags);
4744 /* set bmac loopback */
4745 bnx2x_bmac_enable(params, vars, 1);
4746
4747 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4748 params->port*4, 0);
4749 } else if (params->loopback_mode == LOOPBACK_EMAC) {
4750 vars->link_up = 1;
4751 vars->line_speed = SPEED_1000;
4752 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004753 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004754 vars->mac_type = MAC_TYPE_EMAC;
4755
4756 vars->phy_flags = PHY_XGXS_FLAG;
4757
4758 bnx2x_phy_deassert(params, vars->phy_flags);
4759 /* set bmac loopback */
4760 bnx2x_emac_enable(params, vars, 1);
4761 bnx2x_emac_program(params, vars->line_speed,
4762 vars->duplex);
4763 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4764 params->port*4, 0);
4765 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
4766 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
4767 vars->link_up = 1;
4768 vars->line_speed = SPEED_10000;
4769 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004770 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004771
4772 vars->phy_flags = PHY_XGXS_FLAG;
4773
4774 val = REG_RD(bp,
4775 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4776 params->port*0x18);
4777 params->phy_addr = (u8)val;
4778
4779 bnx2x_phy_deassert(params, vars->phy_flags);
4780 bnx2x_link_initialize(params, vars);
4781
4782 vars->mac_type = MAC_TYPE_BMAC;
4783
4784 bnx2x_bmac_enable(params, vars, 0);
4785
4786 if (params->loopback_mode == LOOPBACK_XGXS_10) {
4787 /* set 10G XGXS loopback */
4788 bnx2x_set_xgxs_loopback(params, vars, 1);
4789 } else {
4790 /* set external phy loopback */
4791 bnx2x_ext_phy_loopback(params);
4792 }
4793 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4794 params->port*4, 0);
4795 } else
4796 /* No loopback */
4797 {
4798
4799 bnx2x_phy_deassert(params, vars->phy_flags);
4800 switch (params->switch_cfg) {
4801 case SWITCH_CFG_1G:
4802 vars->phy_flags |= PHY_SERDES_FLAG;
4803 if ((params->ext_phy_config &
4804 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
4805 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
4806 vars->phy_flags |=
4807 PHY_SGMII_FLAG;
4808 }
4809
4810 val = REG_RD(bp,
4811 NIG_REG_SERDES0_CTRL_PHY_ADDR+
4812 params->port*0x10);
4813
4814 params->phy_addr = (u8)val;
4815
4816 break;
4817 case SWITCH_CFG_10G:
4818 vars->phy_flags |= PHY_XGXS_FLAG;
4819 val = REG_RD(bp,
4820 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4821 params->port*0x18);
4822 params->phy_addr = (u8)val;
4823
4824 break;
4825 default:
4826 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
4827 return -EINVAL;
4828 break;
4829 }
4830
4831 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004832 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004833 bnx2x_link_int_enable(params);
4834 }
4835 return 0;
4836}
4837
Eilon Greenstein589abe32009-02-12 08:36:55 +00004838static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
4839{
4840 DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
4841
4842 /* Set serial boot control for external load */
4843 bnx2x_cl45_write(bp, port,
4844 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
4845 MDIO_PMA_DEVAD,
4846 MDIO_PMA_REG_GEN_CTRL, 0x0001);
4847
4848 /* Disable Transmitter */
4849 bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
4850
4851}
4852
4853u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
4854 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004855{
4856
4857 struct bnx2x *bp = params->bp;
4858 u32 ext_phy_config = params->ext_phy_config;
4859 u16 hw_led_mode = params->hw_led_mode;
4860 u32 chip_id = params->chip_id;
4861 u8 port = params->port;
4862 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4863 /* disable attentions */
4864
4865 vars->link_status = 0;
4866 bnx2x_update_mng(params, vars->link_status);
4867 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4868 (NIG_MASK_XGXS0_LINK_STATUS |
4869 NIG_MASK_XGXS0_LINK10G |
4870 NIG_MASK_SERDES0_LINK_STATUS |
4871 NIG_MASK_MI_INT));
4872
4873 /* activate nig drain */
4874 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4875
4876 /* disable nig egress interface */
4877 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4878 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4879
4880 /* Stop BigMac rx */
4881 bnx2x_bmac_rx_disable(bp, port);
4882
4883 /* disable emac */
4884 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4885
4886 msleep(10);
4887 /* The PHY reset is controled by GPIO 1
4888 * Hold it as vars low
4889 */
4890 /* clear link led */
4891 bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
Eilon Greenstein589abe32009-02-12 08:36:55 +00004892 if (reset_ext_phy) {
4893 switch (ext_phy_type) {
4894 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4895 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4896 break;
4897 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4898 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
4899 "low power mode\n",
4900 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004901 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004902 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4903 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00004904 break;
4905 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4906 {
4907 u8 ext_phy_addr = ((params->ext_phy_config &
4908 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4909 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4910 /* Set soft reset */
4911 bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
4912 break;
4913 }
4914 default:
4915 /* HW reset */
4916 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4917 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4918 port);
4919 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4920 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4921 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004922 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004923 }
4924 }
4925 /* reset the SerDes/XGXS */
4926 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
4927 (0x1ff << (port*16)));
4928
4929 /* reset BigMac */
4930 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
4931 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4932
4933 /* disable nig ingress interface */
4934 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
4935 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
4936 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4937 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4938 vars->link_up = 0;
4939 return 0;
4940}
4941
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004942static u8 bnx2x_update_link_down(struct link_params *params,
4943 struct link_vars *vars)
4944{
4945 struct bnx2x *bp = params->bp;
4946 u8 port = params->port;
4947 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
4948 bnx2x_set_led(bp, port, LED_MODE_OFF,
4949 0, params->hw_led_mode,
4950 params->chip_id);
4951
4952 /* indicate no mac active */
4953 vars->mac_type = MAC_TYPE_NONE;
4954
4955 /* update shared memory */
4956 vars->link_status = 0;
4957 vars->line_speed = 0;
4958 bnx2x_update_mng(params, vars->link_status);
4959
4960 /* activate nig drain */
4961 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4962
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004963 /* disable emac */
4964 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4965
4966 msleep(10);
4967
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004968 /* reset BigMac */
4969 bnx2x_bmac_rx_disable(bp, params->port);
4970 REG_WR(bp, GRCBASE_MISC +
4971 MISC_REGISTERS_RESET_REG_2_CLEAR,
4972 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4973 return 0;
4974}
4975
4976static u8 bnx2x_update_link_up(struct link_params *params,
4977 struct link_vars *vars,
4978 u8 link_10g, u32 gp_status)
4979{
4980 struct bnx2x *bp = params->bp;
4981 u8 port = params->port;
4982 u8 rc = 0;
4983 vars->link_status |= LINK_STATUS_LINK_UP;
4984 if (link_10g) {
4985 bnx2x_bmac_enable(params, vars, 0);
4986 bnx2x_set_led(bp, port, LED_MODE_OPER,
4987 SPEED_10000, params->hw_led_mode,
4988 params->chip_id);
4989
4990 } else {
4991 bnx2x_emac_enable(params, vars, 0);
4992 rc = bnx2x_emac_program(params, vars->line_speed,
4993 vars->duplex);
4994
4995 /* AN complete? */
4996 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
4997 if (!(vars->phy_flags &
4998 PHY_SGMII_FLAG))
Eilon Greensteined8680a2009-02-12 08:37:12 +00004999 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005000 }
5001 }
5002
5003 /* PBF - link up */
5004 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
5005 vars->line_speed);
5006
5007 /* disable drain */
5008 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
5009
5010 /* update shared memory */
5011 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005012 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005013 return rc;
5014}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005015/* This function should called upon link interrupt */
5016/* In case vars->link_up, driver needs to
5017 1. Update the pbf
5018 2. Disable drain
5019 3. Update the shared memory
5020 4. Indicate link up
5021 5. Set LEDs
5022 Otherwise,
5023 1. Update shared memory
5024 2. Reset BigMac
5025 3. Report link down
5026 4. Unset LEDs
5027*/
5028u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
5029{
5030 struct bnx2x *bp = params->bp;
5031 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005032 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005033 u8 link_10g;
5034 u8 ext_phy_link_up, rc = 0;
5035 u32 ext_phy_type;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005036
5037 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
5038 port,
5039 (vars->phy_flags & PHY_XGXS_FLAG),
5040 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
5041
5042 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
5043 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5044 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
5045 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
5046
5047 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5048 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5049 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5050
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005051 /* disable emac */
5052 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5053
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005054 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005055
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005056 /* Check external link change only for non-direct */
5057 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
5058
5059 /* Read gp_status */
5060 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
5061 MDIO_REG_BANK_GP_STATUS,
5062 MDIO_GP_STATUS_TOP_AN_STATUS1,
5063 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005064
5065 rc = bnx2x_link_settings_status(params, vars, gp_status);
5066 if (rc != 0)
5067 return rc;
5068
5069 /* anything 10 and over uses the bmac */
5070 link_10g = ((vars->line_speed == SPEED_10000) ||
5071 (vars->line_speed == SPEED_12000) ||
5072 (vars->line_speed == SPEED_12500) ||
5073 (vars->line_speed == SPEED_13000) ||
5074 (vars->line_speed == SPEED_15000) ||
5075 (vars->line_speed == SPEED_16000));
5076
5077 bnx2x_link_int_ack(params, vars, link_10g);
5078
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005079 /* In case external phy link is up, and internal link is down
5080 ( not initialized yet probably after link initialization, it needs
5081 to be initialized.
5082 Note that after link down-up as result of cable plug,
5083 the xgxs link would probably become up again without the need to
5084 initialize it*/
5085
5086 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
5087 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
Eilon Greenstein589abe32009-02-12 08:36:55 +00005088 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005089 (ext_phy_link_up && !vars->phy_link_up))
5090 bnx2x_init_internal_phy(params, vars);
5091
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005092 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005093 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005094
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005095 if (vars->link_up)
5096 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
5097 else
5098 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005099
5100 return rc;
5101}
5102
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005103static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5104{
5105 u8 ext_phy_addr[PORT_MAX];
5106 u16 val;
5107 s8 port;
5108
5109 /* PART1 - Reset both phys */
5110 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5111 /* Extract the ext phy address for the port */
5112 u32 ext_phy_config = REG_RD(bp, shmem_base +
5113 offsetof(struct shmem_region,
5114 dev_info.port_hw_config[port].external_phy_config));
5115
5116 /* disable attentions */
5117 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5118 (NIG_MASK_XGXS0_LINK_STATUS |
5119 NIG_MASK_XGXS0_LINK10G |
5120 NIG_MASK_SERDES0_LINK_STATUS |
5121 NIG_MASK_MI_INT));
5122
5123 ext_phy_addr[port] =
5124 ((ext_phy_config &
5125 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5126 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5127
5128 /* Need to take the phy out of low power mode in order
5129 to write to access its registers */
5130 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5131 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
5132
5133 /* Reset the phy */
5134 bnx2x_cl45_write(bp, port,
5135 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5136 ext_phy_addr[port],
5137 MDIO_PMA_DEVAD,
5138 MDIO_PMA_REG_CTRL,
5139 1<<15);
5140 }
5141
5142 /* Add delay of 150ms after reset */
5143 msleep(150);
5144
5145 /* PART2 - Download firmware to both phys */
5146 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5147 u16 fw_ver1;
5148
5149 bnx2x_bcm8073_external_rom_boot(bp, port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005150 ext_phy_addr[port], shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005151
5152 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5153 ext_phy_addr[port],
5154 MDIO_PMA_DEVAD,
5155 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00005156 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005157 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00005158 "bnx2x_8073_common_init_phy port %x:"
5159 "Download failed. fw version = 0x%x\n",
5160 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005161 return -EINVAL;
5162 }
5163
5164 /* Only set bit 10 = 1 (Tx power down) */
5165 bnx2x_cl45_read(bp, port,
5166 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5167 ext_phy_addr[port],
5168 MDIO_PMA_DEVAD,
5169 MDIO_PMA_REG_TX_POWER_DOWN, &val);
5170
5171 /* Phase1 of TX_POWER_DOWN reset */
5172 bnx2x_cl45_write(bp, port,
5173 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5174 ext_phy_addr[port],
5175 MDIO_PMA_DEVAD,
5176 MDIO_PMA_REG_TX_POWER_DOWN,
5177 (val | 1<<10));
5178 }
5179
5180 /* Toggle Transmitter: Power down and then up with 600ms
5181 delay between */
5182 msleep(600);
5183
5184 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
5185 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5186 /* Phase2 of POWER_DOWN_RESET*/
5187 /* Release bit 10 (Release Tx power down) */
5188 bnx2x_cl45_read(bp, port,
5189 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5190 ext_phy_addr[port],
5191 MDIO_PMA_DEVAD,
5192 MDIO_PMA_REG_TX_POWER_DOWN, &val);
5193
5194 bnx2x_cl45_write(bp, port,
5195 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5196 ext_phy_addr[port],
5197 MDIO_PMA_DEVAD,
5198 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
5199 msleep(15);
5200
5201 /* Read modify write the SPI-ROM version select register */
5202 bnx2x_cl45_read(bp, port,
5203 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5204 ext_phy_addr[port],
5205 MDIO_PMA_DEVAD,
5206 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
5207 bnx2x_cl45_write(bp, port,
5208 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5209 ext_phy_addr[port],
5210 MDIO_PMA_DEVAD,
5211 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
5212
5213 /* set GPIO2 back to LOW */
5214 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5215 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
5216 }
5217 return 0;
5218
5219}
5220
Eilon Greenstein589abe32009-02-12 08:36:55 +00005221
5222static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5223{
5224 u8 ext_phy_addr;
5225 u32 val;
5226 s8 port;
5227 /* Use port1 because of the static port-swap */
5228 /* Enable the module detection interrupt */
5229 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
5230 val |= ((1<<MISC_REGISTERS_GPIO_3)|
5231 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
5232 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
5233
5234 bnx2x_hw_reset(bp, 1);
5235 msleep(5);
5236 for (port = 0; port < PORT_MAX; port++) {
5237 /* Extract the ext phy address for the port */
5238 u32 ext_phy_config = REG_RD(bp, shmem_base +
5239 offsetof(struct shmem_region,
5240 dev_info.port_hw_config[port].external_phy_config));
5241
5242 ext_phy_addr =
5243 ((ext_phy_config &
5244 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5245 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5246 DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
5247 ext_phy_addr);
5248
5249 bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
5250
5251 /* Set fault module detected LED on */
5252 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5253 MISC_REGISTERS_GPIO_HIGH,
5254 port);
5255 }
5256
5257 return 0;
5258}
5259
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005260u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5261{
5262 u8 rc = 0;
5263 u32 ext_phy_type;
5264
5265 DP(NETIF_MSG_LINK, "bnx2x_common_init_phy\n");
5266
5267 /* Read the ext_phy_type for arbitrary port(0) */
5268 ext_phy_type = XGXS_EXT_PHY_TYPE(
5269 REG_RD(bp, shmem_base +
5270 offsetof(struct shmem_region,
5271 dev_info.port_hw_config[0].external_phy_config)));
5272
5273 switch (ext_phy_type) {
5274 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
5275 {
5276 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
5277 break;
5278 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00005279 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5280 /* GPIO1 affects both ports, so there's need to pull
5281 it for single port alone */
5282 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
5283
5284 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005285 default:
5286 DP(NETIF_MSG_LINK,
5287 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
5288 ext_phy_type);
5289 break;
5290 }
5291
5292 return rc;
5293}
5294
5295
5296
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005297static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
5298{
5299 u16 val, cnt;
5300
5301 bnx2x_cl45_read(bp, port,
5302 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5303 phy_addr,
5304 MDIO_PMA_DEVAD,
5305 MDIO_PMA_REG_7101_RESET, &val);
5306
5307 for (cnt = 0; cnt < 10; cnt++) {
5308 msleep(50);
5309 /* Writes a self-clearing reset */
5310 bnx2x_cl45_write(bp, port,
5311 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5312 phy_addr,
5313 MDIO_PMA_DEVAD,
5314 MDIO_PMA_REG_7101_RESET,
5315 (val | (1<<15)));
5316 /* Wait for clear */
5317 bnx2x_cl45_read(bp, port,
5318 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5319 phy_addr,
5320 MDIO_PMA_DEVAD,
5321 MDIO_PMA_REG_7101_RESET, &val);
5322
5323 if ((val & (1<<15)) == 0)
5324 break;
5325 }
5326}
5327#define RESERVED_SIZE 256
5328/* max application is 160K bytes - data at end of RAM */
Eilon Greenstein6378c022008-08-13 15:59:25 -07005329#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005330
5331/* Header is 14 bytes */
5332#define HEADER_SIZE 14
5333#define DATA_OFFSET HEADER_SIZE
5334
5335#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \
5336 bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \
5337 ext_phy_addr, \
5338 MDIO_PCS_DEVAD, \
5339 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1)
5340
5341/* Programs an image to DSP's flash via the SPI port*/
5342static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port,
5343 u8 ext_phy_addr,
5344 char data[], u32 size)
5345{
5346 const u16 num_trans = size/4; /* 4 bytes can be sent at a time */
5347 /* Doesn't include last trans!*/
5348 const u16 last_trans_size = size%4; /* Num bytes on last trans */
5349 u16 trans_cnt, byte_cnt;
5350 u32 data_index;
5351 u16 tmp;
5352 u16 code_started = 0;
5353 u16 image_revision1, image_revision2;
5354 u16 cnt;
5355
5356 DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size);
5357 /* Going to flash*/
5358 if ((size-HEADER_SIZE) > MAX_APP_SIZE) {
5359 /* This very often will be the case, because the image is built
5360 with 160Kbytes size whereas the total image size must actually
5361 be 160Kbytes-RESERVED_SIZE */
5362 DP(NETIF_MSG_LINK, "Warning, file size was %d bytes "
5363 "truncated to %d bytes\n", size, MAX_APP_SIZE);
5364 size = MAX_APP_SIZE+HEADER_SIZE;
5365 }
5366 DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005367 DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005368 /* Put the DSP in download mode by setting FLASH_CFG[2] to 1
5369 and issuing a reset.*/
5370
5371 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005372 MISC_REGISTERS_GPIO_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005373
5374 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
5375
5376 /* wait 0.5 sec */
5377 for (cnt = 0; cnt < 100; cnt++)
5378 msleep(5);
5379
5380 /* Make sure we can access the DSP
5381 And it's in the correct mode (waiting for download) */
5382
5383 bnx2x_cl45_read(bp, port,
5384 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5385 ext_phy_addr,
5386 MDIO_PCS_DEVAD,
5387 MDIO_PCS_REG_7101_DSP_ACCESS, &tmp);
5388
5389 if (tmp != 0x000A) {
5390 DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. "
5391 "Expected 0x000A, read 0x%04X\n", tmp);
5392 DP(NETIF_MSG_LINK, "Download failed\n");
5393 return -EINVAL;
5394 }
5395
5396 /* Mux the SPI interface away from the internal processor */
5397 bnx2x_cl45_write(bp, port,
5398 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5399 ext_phy_addr,
5400 MDIO_PCS_DEVAD,
5401 MDIO_PCS_REG_7101_SPI_MUX, 1);
5402
5403 /* Reset the SPI port */
5404 bnx2x_cl45_write(bp, port,
5405 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5406 ext_phy_addr,
5407 MDIO_PCS_DEVAD,
5408 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
5409 bnx2x_cl45_write(bp, port,
5410 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5411 ext_phy_addr,
5412 MDIO_PCS_DEVAD,
5413 MDIO_PCS_REG_7101_SPI_CTRL_ADDR,
5414 (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT));
5415 bnx2x_cl45_write(bp, port,
5416 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5417 ext_phy_addr,
5418 MDIO_PCS_DEVAD,
5419 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
5420
5421 /* Erase the flash */
5422 bnx2x_cl45_write(bp, port,
5423 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5424 ext_phy_addr,
5425 MDIO_PCS_DEVAD,
5426 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5427 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5428
5429 bnx2x_cl45_write(bp, port,
5430 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5431 ext_phy_addr,
5432 MDIO_PCS_DEVAD,
5433 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5434 1);
5435
5436 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5437 bnx2x_cl45_write(bp, port,
5438 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5439 ext_phy_addr,
5440 MDIO_PCS_DEVAD,
5441 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5442 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD);
5443
5444 bnx2x_cl45_write(bp, port,
5445 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5446 ext_phy_addr,
5447 MDIO_PCS_DEVAD,
5448 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5449 1);
5450 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5451
5452 /* Wait 10 seconds, the maximum time for the erase to complete */
5453 DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n");
5454 for (cnt = 0; cnt < 1000; cnt++)
5455 msleep(10);
5456
5457 DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n");
5458 data_index = 0;
5459 for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) {
5460 bnx2x_cl45_write(bp, port,
5461 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5462 ext_phy_addr,
5463 MDIO_PCS_DEVAD,
5464 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5465 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5466
5467 bnx2x_cl45_write(bp, port,
5468 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5469 ext_phy_addr,
5470 MDIO_PCS_DEVAD,
5471 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5472 1);
5473 SPI_START_TRANSFER(bp, port, ext_phy_addr);
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_FIFO_ADDR,
5480 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
5481
5482 /* Bits 23-16 of address */
5483 bnx2x_cl45_write(bp, port,
5484 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5485 ext_phy_addr,
5486 MDIO_PCS_DEVAD,
5487 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5488 (data_index>>16));
5489 /* Bits 15-8 of address */
5490 bnx2x_cl45_write(bp, port,
5491 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5492 ext_phy_addr,
5493 MDIO_PCS_DEVAD,
5494 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5495 (data_index>>8));
5496
5497 /* Bits 7-0 of address */
5498 bnx2x_cl45_write(bp, port,
5499 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5500 ext_phy_addr,
5501 MDIO_PCS_DEVAD,
5502 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5503 ((u16)data_index));
5504
5505 byte_cnt = 0;
5506 while (byte_cnt < 4 && data_index < size) {
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 data[data_index++]);
5513 byte_cnt++;
5514 }
5515
5516 bnx2x_cl45_write(bp, port,
5517 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5518 ext_phy_addr,
5519 MDIO_PCS_DEVAD,
5520 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5521 byte_cnt+4);
5522
5523 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5524 msleep(5); /* Wait 5 ms minimum between transs */
5525
5526 /* Let the user know something's going on.*/
5527 /* a pacifier ever 4K */
5528 if ((data_index % 1023) == 0)
5529 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
5530 }
5531
5532 DP(NETIF_MSG_LINK, "\n");
5533 /* Transfer the last block if there is data remaining */
5534 if (last_trans_size) {
5535 bnx2x_cl45_write(bp, port,
5536 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5537 ext_phy_addr,
5538 MDIO_PCS_DEVAD,
5539 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5540 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5541
5542 bnx2x_cl45_write(bp, port,
5543 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5544 ext_phy_addr,
5545 MDIO_PCS_DEVAD,
5546 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5547 1);
5548
5549 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5550
5551 bnx2x_cl45_write(bp, port,
5552 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5553 ext_phy_addr,
5554 MDIO_PCS_DEVAD,
5555 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5556 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
5557
5558 /* Bits 23-16 of address */
5559 bnx2x_cl45_write(bp, port,
5560 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5561 ext_phy_addr,
5562 MDIO_PCS_DEVAD,
5563 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5564 (data_index>>16));
5565 /* Bits 15-8 of address */
5566 bnx2x_cl45_write(bp, port,
5567 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5568 ext_phy_addr,
5569 MDIO_PCS_DEVAD,
5570 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5571 (data_index>>8));
5572
5573 /* Bits 7-0 of address */
5574 bnx2x_cl45_write(bp, port,
5575 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5576 ext_phy_addr,
5577 MDIO_PCS_DEVAD,
5578 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5579 ((u16)data_index));
5580
5581 byte_cnt = 0;
5582 while (byte_cnt < last_trans_size && data_index < size) {
5583 /* Bits 7-0 of address */
5584 bnx2x_cl45_write(bp, port,
5585 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5586 ext_phy_addr,
5587 MDIO_PCS_DEVAD,
5588 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5589 data[data_index++]);
5590 byte_cnt++;
5591 }
5592
5593 bnx2x_cl45_write(bp, port,
5594 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5595 ext_phy_addr,
5596 MDIO_PCS_DEVAD,
5597 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5598 byte_cnt+4);
5599
5600 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5601 }
5602
5603 /* DSP Remove Download Mode */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005604 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5605 MISC_REGISTERS_GPIO_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005606
5607 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
5608
5609 /* wait 0.5 sec to allow it to run */
5610 for (cnt = 0; cnt < 100; cnt++)
5611 msleep(5);
5612
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005613 bnx2x_hw_reset(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005614
5615 for (cnt = 0; cnt < 100; cnt++)
5616 msleep(5);
5617
5618 /* Check that the code is started. In case the download
5619 checksum failed, the code won't be started. */
5620 bnx2x_cl45_read(bp, port,
5621 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5622 ext_phy_addr,
5623 MDIO_PCS_DEVAD,
5624 MDIO_PCS_REG_7101_DSP_ACCESS,
5625 &tmp);
5626
5627 code_started = (tmp & (1<<4));
5628 if (!code_started) {
5629 DP(NETIF_MSG_LINK, "Download failed. Please check file.\n");
5630 return -EINVAL;
5631 }
5632
5633 /* Verify that the file revision is now equal to the image
5634 revision within the DSP */
5635 bnx2x_cl45_read(bp, port,
5636 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5637 ext_phy_addr,
5638 MDIO_PMA_DEVAD,
5639 MDIO_PMA_REG_7101_VER1,
5640 &image_revision1);
5641
5642 bnx2x_cl45_read(bp, port,
5643 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5644 ext_phy_addr,
5645 MDIO_PMA_DEVAD,
5646 MDIO_PMA_REG_7101_VER2,
5647 &image_revision2);
5648
Eilon Greenstein3196a882008-08-13 15:58:49 -07005649 if (data[0x14e] != (image_revision2&0xFF) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005650 data[0x14f] != ((image_revision2&0xFF00)>>8) ||
5651 data[0x150] != (image_revision1&0xFF) ||
5652 data[0x151] != ((image_revision1&0xFF00)>>8)) {
5653 DP(NETIF_MSG_LINK, "Download failed.\n");
5654 return -EINVAL;
5655 }
5656 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
5657 return 0;
5658}
5659
5660u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
5661 u8 driver_loaded, char data[], u32 size)
5662{
5663 u8 rc = 0;
5664 u32 ext_phy_type;
5665 u8 ext_phy_addr;
5666 ext_phy_addr = ((ext_phy_config &
5667 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5668 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5669
5670 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
5671
5672 switch (ext_phy_type) {
5673 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5674 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
5675 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5676 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
5677 DP(NETIF_MSG_LINK,
5678 "Flash download not supported for this ext phy\n");
5679 rc = -EINVAL;
5680 break;
5681 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5682 /* Take ext phy out of reset */
5683 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005684 bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005685 rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
5686 data, size);
5687 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005688 bnx2x_turn_off_sf(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005689 break;
5690 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
5691 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
5692 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
5693 default:
5694 DP(NETIF_MSG_LINK, "Invalid ext phy type\n");
5695 rc = -EINVAL;
5696 break;
5697 }
5698 return rc;
5699}
5700