blob: 4a594b84ba201c431c6c851a3ca91ec52ef9dafd [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,
2097 0xc801, &val);
2098
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,
2129 0xc801, &val);
2130
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,
2145 0xc820, &val);
2146 /* If bit [14] = 0 or bit [13] = 0, continue on with
2147 system initialization (XAUI work-around not required,
2148 as these bits indicate 2.5G or 1G link up). */
2149 if (!(val & (1<<14)) || !(val & (1<<13))) {
2150 DP(NETIF_MSG_LINK, "XAUI work-around not required\n");
2151 return 0;
2152 } else if (!(val & (1<<15))) {
2153 DP(NETIF_MSG_LINK, "clc bit 15 went off\n");
2154 /* If bit 15 is 0, then poll Dev1, Reg $C841 until
2155 it's MSB (bit 15) goes to 1 (indicating that the
2156 XAUI workaround has completed),
2157 then continue on with system initialization.*/
2158 for (cnt1 = 0; cnt1 < 1000; cnt1++) {
2159 bnx2x_cl45_read(bp, params->port,
2160 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2161 ext_phy_addr,
2162 MDIO_PMA_DEVAD,
2163 0xc841, &val);
2164 if (val & (1<<15)) {
2165 DP(NETIF_MSG_LINK,
2166 "XAUI workaround has completed\n");
2167 return 0;
2168 }
2169 msleep(3);
2170 }
2171 break;
2172 }
2173 msleep(3);
2174 }
2175 DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n");
2176 return -EINVAL;
2177
2178}
2179
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002180static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002181 u8 ext_phy_addr, u32 shmem_base)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002182{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002183 /* Boot port from external ROM */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002184 /* EDC grst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002185 bnx2x_cl45_write(bp, port,
2186 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2187 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002188 MDIO_PMA_DEVAD,
2189 MDIO_PMA_REG_GEN_CTRL,
2190 0x0001);
2191
2192 /* ucode reboot and rst */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002193 bnx2x_cl45_write(bp, port,
2194 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2195 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002196 MDIO_PMA_DEVAD,
2197 MDIO_PMA_REG_GEN_CTRL,
2198 0x008c);
2199
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002200 bnx2x_cl45_write(bp, port,
2201 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2202 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002203 MDIO_PMA_DEVAD,
2204 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2205
2206 /* Reset internal microprocessor */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002207 bnx2x_cl45_write(bp, port,
2208 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2209 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002210 MDIO_PMA_DEVAD,
2211 MDIO_PMA_REG_GEN_CTRL,
2212 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2213
2214 /* Release srst bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002215 bnx2x_cl45_write(bp, port,
2216 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2217 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002218 MDIO_PMA_DEVAD,
2219 MDIO_PMA_REG_GEN_CTRL,
2220 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2221
2222 /* wait for 100ms for code download via SPI port */
2223 msleep(100);
2224
2225 /* Clear ser_boot_ctl bit */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002226 bnx2x_cl45_write(bp, port,
2227 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2228 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002229 MDIO_PMA_DEVAD,
2230 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2231
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002232 bnx2x_save_bcm_spirom_ver(bp, port,
2233 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2234 ext_phy_addr,
2235 shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002236}
2237
Eilon Greenstein589abe32009-02-12 08:36:55 +00002238static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
2239{
2240 struct bnx2x *bp = params->bp;
2241 u8 port = params->port;
2242 u8 ext_phy_addr = ((params->ext_phy_config &
2243 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2244 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2245 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2246
2247 /* Need to wait 100ms after reset */
2248 msleep(100);
2249
2250 /* Set serial boot control for external load */
2251 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2252 MDIO_PMA_DEVAD,
2253 MDIO_PMA_REG_MISC_CTRL1, 0x0001);
2254
2255 /* Micro controller re-boot */
2256 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2257 MDIO_PMA_DEVAD,
2258 MDIO_PMA_REG_GEN_CTRL,
2259 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2260
2261 /* Set soft reset */
2262 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2263 MDIO_PMA_DEVAD,
2264 MDIO_PMA_REG_GEN_CTRL,
2265 MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
2266
2267 /* Clear soft reset.
2268 Will automatically reset micro-controller re-boot */
2269 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2270 MDIO_PMA_DEVAD,
2271 MDIO_PMA_REG_GEN_CTRL,
2272 MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
2273
2274 /* wait for 100ms for microcode load */
2275 msleep(100);
2276
2277 /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
2278 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2279 MDIO_PMA_DEVAD,
2280 MDIO_PMA_REG_MISC_CTRL1, 0x0000);
2281
2282 msleep(200);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00002283 bnx2x_save_bcm_spirom_ver(bp, port,
2284 ext_phy_type,
2285 ext_phy_addr,
2286 params->shmem_base);
Eilon Greenstein589abe32009-02-12 08:36:55 +00002287}
2288
2289static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
2290 u8 ext_phy_addr, u8 tx_en)
2291{
2292 u16 val;
2293 DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
2294 tx_en, port);
2295 /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
2296 bnx2x_cl45_read(bp, port,
2297 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2298 ext_phy_addr,
2299 MDIO_PMA_DEVAD,
2300 MDIO_PMA_REG_PHY_IDENTIFIER,
2301 &val);
2302
2303 if (tx_en)
2304 val &= ~(1<<15);
2305 else
2306 val |= (1<<15);
2307
2308 bnx2x_cl45_write(bp, port,
2309 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2310 ext_phy_addr,
2311 MDIO_PMA_DEVAD,
2312 MDIO_PMA_REG_PHY_IDENTIFIER,
2313 val);
2314}
2315
2316
2317static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
2318 u8 byte_cnt, u8 *o_buf) {
2319 struct bnx2x *bp = params->bp;
2320 u16 val, i;
2321 u8 port = params->port;
2322 u8 ext_phy_addr = ((params->ext_phy_config &
2323 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2324 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2325 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2326 if (byte_cnt > 16) {
2327 DP(NETIF_MSG_LINK, "Reading from eeprom is"
2328 " is limited to 0xf\n");
2329 return -EINVAL;
2330 }
2331 /* Set the read command byte count */
2332 bnx2x_cl45_write(bp, port,
2333 ext_phy_type,
2334 ext_phy_addr,
2335 MDIO_PMA_DEVAD,
2336 MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
2337 (byte_cnt | 0xa000));
2338
2339 /* Set the read command address */
2340 bnx2x_cl45_write(bp, port,
2341 ext_phy_type,
2342 ext_phy_addr,
2343 MDIO_PMA_DEVAD,
2344 MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
2345 addr);
2346
2347 /* Activate read command */
2348 bnx2x_cl45_write(bp, port,
2349 ext_phy_type,
2350 ext_phy_addr,
2351 MDIO_PMA_DEVAD,
2352 MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
2353 0x2c0f);
2354
2355 /* Wait up to 500us for command complete status */
2356 for (i = 0; i < 100; i++) {
2357 bnx2x_cl45_read(bp, port,
2358 ext_phy_type,
2359 ext_phy_addr,
2360 MDIO_PMA_DEVAD,
2361 MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
2362 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
2363 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
2364 break;
2365 udelay(5);
2366 }
2367
2368 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
2369 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
2370 DP(NETIF_MSG_LINK,
2371 "Got bad status 0x%x when reading from SFP+ EEPROM\n",
2372 (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
2373 return -EINVAL;
2374 }
2375
2376 /* Read the buffer */
2377 for (i = 0; i < byte_cnt; i++) {
2378 bnx2x_cl45_read(bp, port,
2379 ext_phy_type,
2380 ext_phy_addr,
2381 MDIO_PMA_DEVAD,
2382 MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
2383 o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
2384 }
2385
2386 for (i = 0; i < 100; i++) {
2387 bnx2x_cl45_read(bp, port,
2388 ext_phy_type,
2389 ext_phy_addr,
2390 MDIO_PMA_DEVAD,
2391 MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
2392 if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
2393 MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
2394 return 0;;
2395 msleep(1);
2396 }
2397 return -EINVAL;
2398}
2399
2400
2401static u8 bnx2x_get_sfp_module_type(struct link_params *params,
2402 u8 *module_type)
2403{
2404 struct bnx2x *bp = params->bp;
2405 u8 val;
2406 *module_type = SFP_MODULE_TYPE_UNKNOWN;
2407
2408 /* First check for copper cable */
2409 if (bnx2x_read_sfp_module_eeprom(params,
2410 SFP_EEPROM_CON_TYPE_ADDR,
2411 1,
2412 &val) != 0) {
2413 DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
2414 return -EINVAL;
2415 }
2416
2417 switch (val) {
2418 case SFP_EEPROM_CON_TYPE_VAL_COPPER:
2419 {
2420 u8 copper_module_type;
2421 /* Check if its active cable( includes SFP+ module)
2422 of passive cable*/
2423 if (bnx2x_read_sfp_module_eeprom(params,
2424 SFP_EEPROM_FC_TX_TECH_ADDR,
2425 1,
2426 &copper_module_type) !=
2427 0) {
2428 DP(NETIF_MSG_LINK,
2429 "Failed to read copper-cable-type"
2430 " from SFP+ EEPROM\n");
2431 return -EINVAL;
2432 }
2433
2434 if (copper_module_type &
2435 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
2436 DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
2437 *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
2438 } else if (copper_module_type &
2439 SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
2440 DP(NETIF_MSG_LINK, "Passive Copper"
2441 " cable detected\n");
2442 *module_type =
2443 SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
2444 } else {
2445 DP(NETIF_MSG_LINK, "Unknown copper-cable-"
2446 "type 0x%x !!!\n", copper_module_type);
2447 return -EINVAL;
2448 }
2449 break;
2450 }
2451 case SFP_EEPROM_CON_TYPE_VAL_LC:
2452 DP(NETIF_MSG_LINK, "Optic module detected\n");
2453 *module_type = SFP_MODULE_TYPE_LC;
2454 break;
2455
2456 default:
2457 DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
2458 val);
2459 return -EINVAL;
2460 }
2461 return 0;
2462}
2463
2464
2465/* This function read the relevant field from the module ( SFP+ ),
2466 and verify it is compliant with this board */
2467static u8 bnx2x_verify_sfp_module(struct link_params *params,
2468 u8 module_type)
2469{
2470 struct bnx2x *bp = params->bp;
2471 u8 *str_p, *tmp_buf;
2472 u16 i;
2473
2474#define COMPLIANCE_STR_CNT 6
2475 u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
2476 "FINISAR CORP. ", "Amphenol"};
2477 u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
2478 /* Passive Copper cables are allowed to participate,
2479 since the module is hardwired to the copper cable */
2480
2481 if (!(params->feature_config_flags &
2482 FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
2483 DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
2484 return 0;
2485 }
2486
2487 if (module_type != SFP_MODULE_TYPE_LC) {
2488 DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
2489 return 0;
2490 }
2491
2492 /* In case of non copper cable or Active copper cable,
2493 verify that the SFP+ module is compliant with this board*/
2494 if (bnx2x_read_sfp_module_eeprom(params,
2495 SFP_EEPROM_VENDOR_NAME_ADDR,
2496 SFP_EEPROM_VENDOR_NAME_SIZE,
2497 buf) != 0) {
2498 DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
2499 " module EEPROM\n");
2500 return -EINVAL;
2501 }
2502 for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
2503 str_p = compliance_str[i];
2504 tmp_buf = buf;
2505 while (*str_p) {
2506 if ((u8)(*tmp_buf) != (u8)(*str_p))
2507 break;
2508 str_p++;
2509 tmp_buf++;
2510 }
2511
2512 if (!(*str_p)) {
2513 DP(NETIF_MSG_LINK, "SFP+ Module verified, "
2514 "index=%x\n", i);
2515 return 0;
2516 }
2517 }
2518 DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
2519 return -EINVAL;
2520}
2521
2522
2523static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
2524 u8 module_type)
2525{
2526 struct bnx2x *bp = params->bp;
2527 u8 port = params->port;
2528 u8 options[SFP_EEPROM_OPTIONS_SIZE];
2529 u8 limiting_mode;
2530 u8 ext_phy_addr = ((params->ext_phy_config &
2531 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2532 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2533
2534 if (bnx2x_read_sfp_module_eeprom(params,
2535 SFP_EEPROM_OPTIONS_ADDR,
2536 SFP_EEPROM_OPTIONS_SIZE,
2537 options) != 0) {
2538 DP(NETIF_MSG_LINK, "Failed to read Option field from"
2539 " module EEPROM\n");
2540 return -EINVAL;
2541 }
2542 limiting_mode = !(options[0] &
2543 SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
2544 if (limiting_mode &&
2545 (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
2546 DP(NETIF_MSG_LINK,
2547 "Module options = 0x%x.Setting LIMITING MODE\n",
2548 options[0]);
2549 bnx2x_cl45_write(bp, port,
2550 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2551 ext_phy_addr,
2552 MDIO_PMA_DEVAD,
2553 MDIO_PMA_REG_ROM_VER2,
2554 SFP_LIMITING_MODE_VALUE);
2555 } else { /* LRM mode ( default )*/
2556 u16 cur_limiting_mode;
2557 DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
2558 options[0]);
2559
2560 bnx2x_cl45_read(bp, port,
2561 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2562 ext_phy_addr,
2563 MDIO_PMA_DEVAD,
2564 MDIO_PMA_REG_ROM_VER2,
2565 &cur_limiting_mode);
2566
2567 /* Changing to LRM mode takes quite few seconds.
2568 So do it only if current mode is limiting
2569 ( default is LRM )*/
2570 if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
2571 return 0;
2572
2573 bnx2x_cl45_write(bp, port,
2574 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2575 ext_phy_addr,
2576 MDIO_PMA_DEVAD,
2577 MDIO_PMA_REG_LRM_MODE,
2578 0);
2579 bnx2x_cl45_write(bp, port,
2580 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2581 ext_phy_addr,
2582 MDIO_PMA_DEVAD,
2583 MDIO_PMA_REG_ROM_VER2,
2584 0x128);
2585 bnx2x_cl45_write(bp, port,
2586 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2587 ext_phy_addr,
2588 MDIO_PMA_DEVAD,
2589 MDIO_PMA_REG_MISC_CTRL0,
2590 0x4008);
2591 bnx2x_cl45_write(bp, port,
2592 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
2593 ext_phy_addr,
2594 MDIO_PMA_DEVAD,
2595 MDIO_PMA_REG_LRM_MODE,
2596 0xaaaa);
2597 }
2598 return 0;
2599}
2600
2601static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
2602{
2603 u8 val;
2604 struct bnx2x *bp = params->bp;
2605 u16 timeout;
2606 /* Initialization time after hot-plug may take up to 300ms for some
2607 phys type ( e.g. JDSU ) */
2608 for (timeout = 0; timeout < 60; timeout++) {
2609 if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
2610 == 0) {
2611 DP(NETIF_MSG_LINK, "SFP+ module initialization "
2612 "took %d ms\n", timeout * 5);
2613 return 0;
2614 }
2615 msleep(5);
2616 }
2617 return -EINVAL;
2618}
2619
2620static u8 bnx2x_sfp_module_detection(struct link_params *params)
2621{
2622 struct bnx2x *bp = params->bp;
2623 u8 module_type;
2624 u8 ext_phy_addr = ((params->ext_phy_config &
2625 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2626 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2627 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2628
2629 if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
2630 DP(NETIF_MSG_LINK, "Module detection is not required "
2631 "for this phy\n");
2632 return 0;
2633 }
2634
2635 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
2636 params->port);
2637
2638 if (bnx2x_get_sfp_module_type(params,
2639 &module_type) != 0) {
2640 DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
2641 if (!(params->feature_config_flags &
2642 FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
2643 /* In case module detection is disabled, it trys to
2644 link up. The issue that can happen here is LRM /
2645 LIMITING mode which set according to the module-type*/
2646 DP(NETIF_MSG_LINK, "Unable to read module-type."
2647 "Probably due to Bit Stretching."
2648 " Proceeding...\n");
2649 } else {
2650 return -EINVAL;
2651 }
2652 } else if (bnx2x_verify_sfp_module(params, module_type) !=
2653 0) {
2654 /* check SFP+ module compatibility */
2655 DP(NETIF_MSG_LINK, "Module verification failed!!\n");
2656 /* Turn on fault module-detected led */
2657 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2658 MISC_REGISTERS_GPIO_HIGH,
2659 params->port);
2660 return -EINVAL;
2661 }
2662
2663 /* Turn off fault module-detected led */
2664 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2665 MISC_REGISTERS_GPIO_LOW,
2666 params->port);
2667
2668 /* Check and set limiting mode / LRM mode */
2669 if (bnx2x_bcm8726_set_limiting_mode(params, module_type)
2670 != 0) {
2671 DP(NETIF_MSG_LINK, "Setting limiting mode failed!!\n");
2672 return -EINVAL;
2673 }
2674
2675 /* Enable transmit for this module */
2676 bnx2x_bcm8726_set_transmitter(bp, params->port,
2677 ext_phy_addr, 1);
2678 return 0;
2679}
2680
2681void bnx2x_handle_module_detect_int(struct link_params *params)
2682{
2683 struct bnx2x *bp = params->bp;
2684 u32 gpio_val;
2685 u8 port = params->port;
2686 /* Set valid module led off */
2687 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
2688 MISC_REGISTERS_GPIO_HIGH,
2689 params->port);
2690
2691 /* Get current gpio val refelecting module plugged in / out*/
2692 gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
2693
2694 /* Call the handling function in case module is detected */
2695 if (gpio_val == 0) {
2696
2697 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
2698 MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
2699 port);
2700
2701 if (bnx2x_wait_for_sfp_module_initialized(params)
2702 == 0)
2703 bnx2x_sfp_module_detection(params);
2704 else
2705 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
2706 } else {
2707 u8 ext_phy_addr = ((params->ext_phy_config &
2708 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2709 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2710 bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
2711 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
2712 port);
2713 /* Module was plugged out. */
2714 /* Disable transmit for this module */
2715 bnx2x_bcm8726_set_transmitter(bp, params->port,
2716 ext_phy_addr, 0);
2717 }
2718}
2719
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002720static void bnx2x_bcm807x_force_10G(struct link_params *params)
2721{
2722 struct bnx2x *bp = params->bp;
2723 u8 port = params->port;
2724 u8 ext_phy_addr = ((params->ext_phy_config &
2725 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2726 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2727 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2728
2729 /* Force KR or KX */
2730 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2731 MDIO_PMA_DEVAD,
2732 MDIO_PMA_REG_CTRL,
2733 0x2040);
2734 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2735 MDIO_PMA_DEVAD,
2736 MDIO_PMA_REG_10G_CTRL2,
2737 0x000b);
2738 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2739 MDIO_PMA_DEVAD,
2740 MDIO_PMA_REG_BCM_CTRL,
2741 0x0000);
2742 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2743 MDIO_AN_DEVAD,
2744 MDIO_AN_REG_CTRL,
2745 0x0000);
2746}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002747static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
2748{
2749 struct bnx2x *bp = params->bp;
2750 u8 port = params->port;
2751 u16 val;
2752 u8 ext_phy_addr = ((params->ext_phy_config &
2753 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2754 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2755 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2756
2757 bnx2x_cl45_read(bp, params->port,
2758 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
2759 ext_phy_addr,
2760 MDIO_PMA_DEVAD,
2761 0xc801, &val);
2762
2763 if (val == 0) {
2764 /* Mustn't set low power mode in 8073 A0 */
2765 return;
2766 }
2767
2768 /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
2769 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2770 MDIO_XS_DEVAD,
2771 MDIO_XS_PLL_SEQUENCER, &val);
2772 val &= ~(1<<13);
2773 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2774 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2775
2776 /* PLL controls */
2777 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2778 MDIO_XS_DEVAD, 0x805E, 0x1077);
2779 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2780 MDIO_XS_DEVAD, 0x805D, 0x0000);
2781 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2782 MDIO_XS_DEVAD, 0x805C, 0x030B);
2783 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2784 MDIO_XS_DEVAD, 0x805B, 0x1240);
2785 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2786 MDIO_XS_DEVAD, 0x805A, 0x2490);
2787
2788 /* Tx Controls */
2789 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2790 MDIO_XS_DEVAD, 0x80A7, 0x0C74);
2791 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2792 MDIO_XS_DEVAD, 0x80A6, 0x9041);
2793 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2794 MDIO_XS_DEVAD, 0x80A5, 0x4640);
2795
2796 /* Rx Controls */
2797 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2798 MDIO_XS_DEVAD, 0x80FE, 0x01C4);
2799 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2800 MDIO_XS_DEVAD, 0x80FD, 0x9249);
2801 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2802 MDIO_XS_DEVAD, 0x80FC, 0x2015);
2803
2804 /* Enable PLL sequencer (use read-modify-write to set bit 13) */
2805 bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
2806 MDIO_XS_DEVAD,
2807 MDIO_XS_PLL_SEQUENCER, &val);
2808 val |= (1<<13);
2809 bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
2810 MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
2811}
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002812
2813static void bnx2x_8073_set_pause_cl37(struct link_params *params,
2814 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002815{
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002816
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002817 struct bnx2x *bp = params->bp;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002818 u16 cl37_val;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002819 u8 ext_phy_addr = ((params->ext_phy_config &
2820 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2821 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2822 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2823
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002824 bnx2x_cl45_read(bp, params->port,
2825 ext_phy_type,
2826 ext_phy_addr,
2827 MDIO_AN_DEVAD,
2828 MDIO_AN_REG_CL37_FC_LD, &cl37_val);
2829
2830 cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2831 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2832
2833 if ((vars->ieee_fc &
2834 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
2835 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
2836 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
2837 }
2838 if ((vars->ieee_fc &
2839 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
2840 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2841 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
2842 }
2843 if ((vars->ieee_fc &
2844 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
2845 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2846 cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
2847 }
2848 DP(NETIF_MSG_LINK,
2849 "Ext phy AN advertize cl37 0x%x\n", cl37_val);
2850
2851 bnx2x_cl45_write(bp, params->port,
2852 ext_phy_type,
2853 ext_phy_addr,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002854 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07002855 MDIO_AN_REG_CL37_FC_LD, cl37_val);
2856 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002857}
2858
2859static void bnx2x_ext_phy_set_pause(struct link_params *params,
2860 struct link_vars *vars)
2861{
2862 struct bnx2x *bp = params->bp;
2863 u16 val;
2864 u8 ext_phy_addr = ((params->ext_phy_config &
2865 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2866 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2867 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2868
2869 /* read modify write pause advertizing */
2870 bnx2x_cl45_read(bp, params->port,
2871 ext_phy_type,
2872 ext_phy_addr,
2873 MDIO_AN_DEVAD,
2874 MDIO_AN_REG_ADV_PAUSE, &val);
2875
2876 val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002877
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002878 /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
2879
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002880 if ((vars->ieee_fc &
2881 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002882 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
2883 val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
2884 }
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002885 if ((vars->ieee_fc &
2886 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002887 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
2888 val |=
2889 MDIO_AN_REG_ADV_PAUSE_PAUSE;
2890 }
2891 DP(NETIF_MSG_LINK,
2892 "Ext phy AN advertize 0x%x\n", val);
2893 bnx2x_cl45_write(bp, params->port,
2894 ext_phy_type,
2895 ext_phy_addr,
2896 MDIO_AN_DEVAD,
2897 MDIO_AN_REG_ADV_PAUSE, val);
2898}
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002899static void bnx2x_set_preemphasis(struct link_params *params)
2900{
2901 u16 bank, i = 0;
2902 struct bnx2x *bp = params->bp;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002903
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002904 for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
2905 bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
2906 CL45_WR_OVER_CL22(bp, params->port,
2907 params->phy_addr,
2908 bank,
2909 MDIO_RX0_RX_EQ_BOOST,
2910 params->xgxs_config_rx[i]);
2911 }
2912
2913 for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
2914 bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
2915 CL45_WR_OVER_CL22(bp, params->port,
2916 params->phy_addr,
2917 bank,
2918 MDIO_TX0_TX_DRIVER,
2919 params->xgxs_config_tx[i]);
2920 }
2921}
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002922
2923static void bnx2x_init_internal_phy(struct link_params *params,
2924 struct link_vars *vars)
2925{
2926 struct bnx2x *bp = params->bp;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002927 if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00002928 if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
2929 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
2930 (params->feature_config_flags &
2931 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
2932 bnx2x_set_preemphasis(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002933
2934 /* forced speed requested? */
2935 if (vars->line_speed != SPEED_AUTO_NEG) {
2936 DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
2937
2938 /* disable autoneg */
2939 bnx2x_set_autoneg(params, vars);
2940
2941 /* program speed and duplex */
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002942 bnx2x_program_serdes(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002943
2944 } else { /* AN_mode */
2945 DP(NETIF_MSG_LINK, "not SGMII, AN\n");
2946
2947 /* AN enabled */
2948 bnx2x_set_brcm_cl37_advertisment(params);
2949
2950 /* program duplex & pause advertisement (for aneg) */
2951 bnx2x_set_ieee_aneg_advertisment(params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002952 vars->ieee_fc);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002953
2954 /* enable autoneg */
2955 bnx2x_set_autoneg(params, vars);
2956
2957 /* enable and restart AN */
2958 bnx2x_restart_autoneg(params);
2959 }
2960
2961 } else { /* SGMII mode */
2962 DP(NETIF_MSG_LINK, "SGMII\n");
2963
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07002964 bnx2x_initialize_sgmii_process(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07002965 }
2966}
2967
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07002968static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
2969{
2970 struct bnx2x *bp = params->bp;
2971 u32 ext_phy_type;
2972 u8 ext_phy_addr;
2973 u16 cnt;
2974 u16 ctrl = 0;
2975 u16 val = 0;
2976 u8 rc = 0;
2977 if (vars->phy_flags & PHY_XGXS_FLAG) {
2978 ext_phy_addr = ((params->ext_phy_config &
2979 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
2980 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
2981
2982 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
2983 /* Make sure that the soft reset is off (expect for the 8072:
2984 * due to the lock, it will be done inside the specific
2985 * handling)
2986 */
2987 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
2988 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
2989 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
2990 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
2991 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
2992 /* Wait for soft reset to get cleared upto 1 sec */
2993 for (cnt = 0; cnt < 1000; cnt++) {
2994 bnx2x_cl45_read(bp, params->port,
2995 ext_phy_type,
2996 ext_phy_addr,
2997 MDIO_PMA_DEVAD,
2998 MDIO_PMA_REG_CTRL, &ctrl);
2999 if (!(ctrl & (1<<15)))
3000 break;
3001 msleep(1);
3002 }
3003 DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
3004 ctrl, cnt);
3005 }
3006
3007 switch (ext_phy_type) {
3008 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003009 break;
3010
3011 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3012 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3013
3014 bnx2x_cl45_write(bp, params->port,
3015 ext_phy_type,
3016 ext_phy_addr,
3017 MDIO_PMA_DEVAD,
3018 MDIO_PMA_REG_MISC_CTRL,
3019 0x8288);
3020 bnx2x_cl45_write(bp, params->port,
3021 ext_phy_type,
3022 ext_phy_addr,
3023 MDIO_PMA_DEVAD,
3024 MDIO_PMA_REG_PHY_IDENTIFIER,
3025 0x7fbf);
3026 bnx2x_cl45_write(bp, params->port,
3027 ext_phy_type,
3028 ext_phy_addr,
3029 MDIO_PMA_DEVAD,
3030 MDIO_PMA_REG_CMU_PLL_BYPASS,
3031 0x0100);
3032 bnx2x_cl45_write(bp, params->port,
3033 ext_phy_type,
3034 ext_phy_addr,
3035 MDIO_WIS_DEVAD,
3036 MDIO_WIS_REG_LASI_CNTL, 0x1);
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003037
3038 bnx2x_save_bcm_spirom_ver(bp, params->port,
3039 ext_phy_type,
3040 ext_phy_addr,
3041 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003042 break;
3043
3044 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003045 /* Wait until fw is loaded */
3046 for (cnt = 0; cnt < 100; cnt++) {
3047 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3048 ext_phy_addr, MDIO_PMA_DEVAD,
3049 MDIO_PMA_REG_ROM_VER1, &val);
3050 if (val)
3051 break;
3052 msleep(10);
3053 }
3054 DP(NETIF_MSG_LINK, "XGXS 8706 is initialized "
3055 "after %d ms\n", cnt);
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003056 if ((params->feature_config_flags &
3057 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3058 u8 i;
3059 u16 reg;
3060 for (i = 0; i < 4; i++) {
3061 reg = MDIO_XS_8706_REG_BANK_RX0 +
3062 i*(MDIO_XS_8706_REG_BANK_RX1 -
3063 MDIO_XS_8706_REG_BANK_RX0);
3064 bnx2x_cl45_read(bp, params->port,
3065 ext_phy_type,
3066 ext_phy_addr,
3067 MDIO_XS_DEVAD,
3068 reg, &val);
3069 /* Clear first 3 bits of the control */
3070 val &= ~0x7;
3071 /* Set control bits according to
3072 configuation */
3073 val |= (params->xgxs_config_rx[i] &
3074 0x7);
3075 DP(NETIF_MSG_LINK, "Setting RX"
3076 "Equalizer to BCM8706 reg 0x%x"
3077 " <-- val 0x%x\n", reg, val);
3078 bnx2x_cl45_write(bp, params->port,
3079 ext_phy_type,
3080 ext_phy_addr,
3081 MDIO_XS_DEVAD,
3082 reg, val);
3083 }
3084 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003085 /* Force speed */
3086 /* First enable LASI */
3087 bnx2x_cl45_write(bp, params->port,
3088 ext_phy_type,
3089 ext_phy_addr,
3090 MDIO_PMA_DEVAD,
3091 MDIO_PMA_REG_RX_ALARM_CTRL,
3092 0x0400);
3093 bnx2x_cl45_write(bp, params->port,
3094 ext_phy_type,
3095 ext_phy_addr,
3096 MDIO_PMA_DEVAD,
3097 MDIO_PMA_REG_LASI_CTRL, 0x0004);
3098
3099 if (params->req_line_speed == SPEED_10000) {
3100 DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
3101
3102 bnx2x_cl45_write(bp, params->port,
3103 ext_phy_type,
3104 ext_phy_addr,
3105 MDIO_PMA_DEVAD,
3106 MDIO_PMA_REG_DIGITAL_CTRL,
3107 0x400);
3108 } else {
3109 /* Force 1Gbps using autoneg with 1G
3110 advertisment */
3111
3112 /* Allow CL37 through CL73 */
3113 DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
3114 bnx2x_cl45_write(bp, params->port,
3115 ext_phy_type,
3116 ext_phy_addr,
3117 MDIO_AN_DEVAD,
3118 MDIO_AN_REG_CL37_CL73,
3119 0x040c);
3120
3121 /* Enable Full-Duplex advertisment on CL37 */
3122 bnx2x_cl45_write(bp, params->port,
3123 ext_phy_type,
3124 ext_phy_addr,
3125 MDIO_AN_DEVAD,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003126 MDIO_AN_REG_CL37_FC_LP,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003127 0x0020);
3128 /* Enable CL37 AN */
3129 bnx2x_cl45_write(bp, params->port,
3130 ext_phy_type,
3131 ext_phy_addr,
3132 MDIO_AN_DEVAD,
3133 MDIO_AN_REG_CL37_AN,
3134 0x1000);
3135 /* 1G support */
3136 bnx2x_cl45_write(bp, params->port,
3137 ext_phy_type,
3138 ext_phy_addr,
3139 MDIO_AN_DEVAD,
3140 MDIO_AN_REG_ADV, (1<<5));
3141
3142 /* Enable clause 73 AN */
3143 bnx2x_cl45_write(bp, params->port,
3144 ext_phy_type,
3145 ext_phy_addr,
3146 MDIO_AN_DEVAD,
3147 MDIO_AN_REG_CTRL,
3148 0x1200);
3149
3150 }
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003151 bnx2x_save_bcm_spirom_ver(bp, params->port,
3152 ext_phy_type,
3153 ext_phy_addr,
3154 params->shmem_base);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003155 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00003156 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3157 DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
3158 bnx2x_bcm8726_external_rom_boot(params);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003159
Eilon Greenstein589abe32009-02-12 08:36:55 +00003160 /* Need to call module detected on initialization since
3161 the module detection triggered by actual module
3162 insertion might occur before driver is loaded, and when
3163 driver is loaded, it reset all registers, including the
3164 transmitter */
3165 bnx2x_sfp_module_detection(params);
3166 if (params->req_line_speed == SPEED_1000) {
3167 DP(NETIF_MSG_LINK, "Setting 1G force\n");
3168 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3169 ext_phy_addr, MDIO_PMA_DEVAD,
3170 MDIO_PMA_REG_CTRL, 0x40);
3171 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3172 ext_phy_addr, MDIO_PMA_DEVAD,
3173 MDIO_PMA_REG_10G_CTRL2, 0xD);
3174 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3175 ext_phy_addr, MDIO_PMA_DEVAD,
3176 MDIO_PMA_REG_LASI_CTRL, 0x5);
3177 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3178 ext_phy_addr, MDIO_PMA_DEVAD,
3179 MDIO_PMA_REG_RX_ALARM_CTRL,
3180 0x400);
3181 } else if ((params->req_line_speed ==
3182 SPEED_AUTO_NEG) &&
3183 ((params->speed_cap_mask &
3184 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
3185 DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
3186 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3187 ext_phy_addr, MDIO_AN_DEVAD,
3188 MDIO_AN_REG_ADV, 0x20);
3189 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3190 ext_phy_addr, MDIO_AN_DEVAD,
3191 MDIO_AN_REG_CL37_CL73, 0x040c);
3192 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3193 ext_phy_addr, MDIO_AN_DEVAD,
3194 MDIO_AN_REG_CL37_FC_LD, 0x0020);
3195 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3196 ext_phy_addr, MDIO_AN_DEVAD,
3197 MDIO_AN_REG_CL37_AN, 0x1000);
3198 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3199 ext_phy_addr, MDIO_AN_DEVAD,
3200 MDIO_AN_REG_CTRL, 0x1200);
3201
3202 /* Enable RX-ALARM control to receive
3203 interrupt for 1G speed change */
3204 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3205 ext_phy_addr, MDIO_PMA_DEVAD,
3206 MDIO_PMA_REG_LASI_CTRL, 0x4);
3207 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3208 ext_phy_addr, MDIO_PMA_DEVAD,
3209 MDIO_PMA_REG_RX_ALARM_CTRL,
3210 0x400);
3211
3212 } else { /* Default 10G. Set only LASI control */
3213 bnx2x_cl45_write(bp, params->port, ext_phy_type,
3214 ext_phy_addr, MDIO_PMA_DEVAD,
3215 MDIO_PMA_REG_LASI_CTRL, 1);
3216 }
Eilon Greensteinc2c8b032009-02-12 08:37:14 +00003217
3218 /* Set TX PreEmphasis if needed */
3219 if ((params->feature_config_flags &
3220 FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
3221 DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
3222 "TX_CTRL2 0x%x\n",
3223 params->xgxs_config_tx[0],
3224 params->xgxs_config_tx[1]);
3225 bnx2x_cl45_write(bp, params->port,
3226 ext_phy_type,
3227 ext_phy_addr,
3228 MDIO_PMA_DEVAD,
3229 MDIO_PMA_REG_8726_TX_CTRL1,
3230 params->xgxs_config_tx[0]);
3231
3232 bnx2x_cl45_write(bp, params->port,
3233 ext_phy_type,
3234 ext_phy_addr,
3235 MDIO_PMA_DEVAD,
3236 MDIO_PMA_REG_8726_TX_CTRL2,
3237 params->xgxs_config_tx[1]);
3238 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00003239 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003240 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3241 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3242 {
3243 u16 tmp1;
3244 u16 rx_alarm_ctrl_val;
3245 u16 lasi_ctrl_val;
3246 if (ext_phy_type ==
3247 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3248 rx_alarm_ctrl_val = 0x400;
3249 lasi_ctrl_val = 0x0004;
3250 } else {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003251 rx_alarm_ctrl_val = (1<<2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003252 lasi_ctrl_val = 0x0004;
3253 }
3254
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003255 /* enable LASI */
3256 bnx2x_cl45_write(bp, params->port,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003257 ext_phy_type,
3258 ext_phy_addr,
3259 MDIO_PMA_DEVAD,
3260 MDIO_PMA_REG_RX_ALARM_CTRL,
3261 rx_alarm_ctrl_val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003262
3263 bnx2x_cl45_write(bp, params->port,
3264 ext_phy_type,
3265 ext_phy_addr,
3266 MDIO_PMA_DEVAD,
3267 MDIO_PMA_REG_LASI_CTRL,
3268 lasi_ctrl_val);
3269
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003270 bnx2x_8073_set_pause_cl37(params, vars);
3271
3272 if (ext_phy_type ==
3273 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){
3274 bnx2x_bcm8072_external_rom_boot(params);
3275 } else {
3276
3277 /* In case of 8073 with long xaui lines,
3278 don't set the 8073 xaui low power*/
3279 bnx2x_bcm8073_set_xaui_low_power_mode(params);
3280 }
3281
3282 bnx2x_cl45_read(bp, params->port,
3283 ext_phy_type,
3284 ext_phy_addr,
3285 MDIO_PMA_DEVAD,
3286 0xca13,
3287 &tmp1);
3288
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003289 bnx2x_cl45_read(bp, params->port,
3290 ext_phy_type,
3291 ext_phy_addr,
3292 MDIO_PMA_DEVAD,
3293 MDIO_PMA_REG_RX_ALARM, &tmp1);
3294
3295 DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
3296 "0x%x\n", tmp1);
3297
3298 /* If this is forced speed, set to KR or KX
3299 * (all other are not supported)
3300 */
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003301 if (params->loopback_mode == LOOPBACK_EXT) {
3302 bnx2x_bcm807x_force_10G(params);
3303 DP(NETIF_MSG_LINK,
3304 "Forced speed 10G on 807X\n");
3305 break;
3306 } else {
3307 bnx2x_cl45_write(bp, params->port,
3308 ext_phy_type, ext_phy_addr,
3309 MDIO_PMA_DEVAD,
3310 MDIO_PMA_REG_BCM_CTRL,
3311 0x0002);
3312 }
3313 if (params->req_line_speed != SPEED_AUTO_NEG) {
3314 if (params->req_line_speed == SPEED_10000) {
3315 val = (1<<7);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003316 } else if (params->req_line_speed ==
3317 SPEED_2500) {
3318 val = (1<<5);
3319 /* Note that 2.5G works only
3320 when used with 1G advertisment */
3321 } else
3322 val = (1<<5);
3323 } else {
3324
3325 val = 0;
3326 if (params->speed_cap_mask &
3327 PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
3328 val |= (1<<7);
3329
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003330 /* Note that 2.5G works only when
3331 used with 1G advertisment */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003332 if (params->speed_cap_mask &
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003333 (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
3334 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003335 val |= (1<<5);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003336 DP(NETIF_MSG_LINK,
3337 "807x autoneg val = 0x%x\n", val);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003338 }
3339
3340 bnx2x_cl45_write(bp, params->port,
3341 ext_phy_type,
3342 ext_phy_addr,
3343 MDIO_AN_DEVAD,
3344 MDIO_AN_REG_ADV, val);
3345
3346 if (ext_phy_type ==
3347 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003348
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003349 bnx2x_cl45_read(bp, params->port,
3350 ext_phy_type,
3351 ext_phy_addr,
3352 MDIO_AN_DEVAD,
3353 0x8329, &tmp1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003354
3355 if (((params->speed_cap_mask &
3356 PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
3357 (params->req_line_speed ==
3358 SPEED_AUTO_NEG)) ||
3359 (params->req_line_speed ==
3360 SPEED_2500)) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003361 u16 phy_ver;
3362 /* Allow 2.5G for A1 and above */
3363 bnx2x_cl45_read(bp, params->port,
3364 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
3365 ext_phy_addr,
3366 MDIO_PMA_DEVAD,
3367 0xc801, &phy_ver);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003368 DP(NETIF_MSG_LINK, "Add 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003369 if (phy_ver > 0)
3370 tmp1 |= 1;
3371 else
3372 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003373 } else {
3374 DP(NETIF_MSG_LINK, "Disable 2.5G\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003375 tmp1 &= 0xfffe;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003376 }
3377
3378 bnx2x_cl45_write(bp, params->port,
3379 ext_phy_type,
3380 ext_phy_addr,
3381 MDIO_AN_DEVAD,
3382 0x8329, tmp1);
3383 }
3384
3385 /* Add support for CL37 (passive mode) II */
3386
3387 bnx2x_cl45_read(bp, params->port,
3388 ext_phy_type,
3389 ext_phy_addr,
3390 MDIO_AN_DEVAD,
3391 MDIO_AN_REG_CL37_FC_LD,
3392 &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003393
3394 bnx2x_cl45_write(bp, params->port,
3395 ext_phy_type,
3396 ext_phy_addr,
3397 MDIO_AN_DEVAD,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003398 MDIO_AN_REG_CL37_FC_LD, (tmp1 |
3399 ((params->req_duplex == DUPLEX_FULL) ?
3400 0x20 : 0x40)));
3401
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003402 /* Add support for CL37 (passive mode) III */
3403 bnx2x_cl45_write(bp, params->port,
3404 ext_phy_type,
3405 ext_phy_addr,
3406 MDIO_AN_DEVAD,
3407 MDIO_AN_REG_CL37_AN, 0x1000);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003408
3409 if (ext_phy_type ==
3410 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003411 /* The SNR will improve about 2db by changing
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003412 BW and FEE main tap. Rest commands are executed
3413 after link is up*/
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003414 /*Change FFE main cursor to 5 in EDC register*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003415 if (bnx2x_8073_is_snr_needed(params))
3416 bnx2x_cl45_write(bp, params->port,
3417 ext_phy_type,
3418 ext_phy_addr,
3419 MDIO_PMA_DEVAD,
3420 MDIO_PMA_REG_EDC_FFE_MAIN,
3421 0xFB0C);
3422
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003423 /* Enable FEC (Forware Error Correction)
3424 Request in the AN */
3425 bnx2x_cl45_read(bp, params->port,
3426 ext_phy_type,
3427 ext_phy_addr,
3428 MDIO_AN_DEVAD,
3429 MDIO_AN_REG_ADV2, &tmp1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003430
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003431 tmp1 |= (1<<15);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003432
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003433 bnx2x_cl45_write(bp, params->port,
3434 ext_phy_type,
3435 ext_phy_addr,
3436 MDIO_AN_DEVAD,
3437 MDIO_AN_REG_ADV2, tmp1);
3438
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003439 }
3440
3441 bnx2x_ext_phy_set_pause(params, vars);
3442
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003443 /* Restart autoneg */
3444 msleep(500);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003445 bnx2x_cl45_write(bp, params->port,
3446 ext_phy_type,
3447 ext_phy_addr,
3448 MDIO_AN_DEVAD,
3449 MDIO_AN_REG_CTRL, 0x1200);
3450 DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
3451 "Advertise 1G=%x, 10G=%x\n",
3452 ((val & (1<<5)) > 0),
3453 ((val & (1<<7)) > 0));
3454 break;
3455 }
3456 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003457 {
3458 u16 fw_ver1, fw_ver2;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003459 DP(NETIF_MSG_LINK,
3460 "Setting the SFX7101 LASI indication\n");
3461
3462 bnx2x_cl45_write(bp, params->port,
3463 ext_phy_type,
3464 ext_phy_addr,
3465 MDIO_PMA_DEVAD,
3466 MDIO_PMA_REG_LASI_CTRL, 0x1);
3467 DP(NETIF_MSG_LINK,
3468 "Setting the SFX7101 LED to blink on traffic\n");
3469 bnx2x_cl45_write(bp, params->port,
3470 ext_phy_type,
3471 ext_phy_addr,
3472 MDIO_PMA_DEVAD,
3473 MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
3474
3475 bnx2x_ext_phy_set_pause(params, vars);
3476 /* Restart autoneg */
3477 bnx2x_cl45_read(bp, params->port,
3478 ext_phy_type,
3479 ext_phy_addr,
3480 MDIO_AN_DEVAD,
3481 MDIO_AN_REG_CTRL, &val);
3482 val |= 0x200;
3483 bnx2x_cl45_write(bp, params->port,
3484 ext_phy_type,
3485 ext_phy_addr,
3486 MDIO_AN_DEVAD,
3487 MDIO_AN_REG_CTRL, val);
Eilon Greenstein28577182009-02-12 08:37:00 +00003488
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003489 /* Save spirom version */
3490 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3491 ext_phy_addr, MDIO_PMA_DEVAD,
3492 MDIO_PMA_REG_7101_VER1, &fw_ver1);
3493
3494 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3495 ext_phy_addr, MDIO_PMA_DEVAD,
3496 MDIO_PMA_REG_7101_VER2, &fw_ver2);
3497
3498 bnx2x_save_spirom_version(params->bp, params->port,
3499 params->shmem_base,
3500 (u32)(fw_ver1<<16 | fw_ver2));
3501
Eilon Greenstein28577182009-02-12 08:37:00 +00003502 break;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003503 }
Eilon Greenstein28577182009-02-12 08:37:00 +00003504 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
3505 DP(NETIF_MSG_LINK,
3506 "Setting the BCM8481 LASI control\n");
3507
3508 bnx2x_cl45_write(bp, params->port,
3509 ext_phy_type,
3510 ext_phy_addr,
3511 MDIO_PMA_DEVAD,
3512 MDIO_PMA_REG_LASI_CTRL, 0x1);
3513
3514 /* Restart autoneg */
3515 bnx2x_cl45_read(bp, params->port,
3516 ext_phy_type,
3517 ext_phy_addr,
3518 MDIO_AN_DEVAD,
3519 MDIO_AN_REG_CTRL, &val);
3520 val |= 0x200;
3521 bnx2x_cl45_write(bp, params->port,
3522 ext_phy_type,
3523 ext_phy_addr,
3524 MDIO_AN_DEVAD,
3525 MDIO_AN_REG_CTRL, val);
3526
Eilon Greensteina35da8d2009-02-12 08:37:02 +00003527 bnx2x_save_bcm_spirom_ver(bp, params->port,
3528 ext_phy_type,
3529 ext_phy_addr,
3530 params->shmem_base);
3531
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003532 break;
3533 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
3534 DP(NETIF_MSG_LINK,
3535 "XGXS PHY Failure detected 0x%x\n",
3536 params->ext_phy_config);
3537 rc = -EINVAL;
3538 break;
3539 default:
3540 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3541 params->ext_phy_config);
3542 rc = -EINVAL;
3543 break;
3544 }
3545
3546 } else { /* SerDes */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003547
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003548 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
3549 switch (ext_phy_type) {
3550 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
3551 DP(NETIF_MSG_LINK, "SerDes Direct\n");
3552 break;
3553
3554 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
3555 DP(NETIF_MSG_LINK, "SerDes 5482\n");
3556 break;
3557
3558 default:
3559 DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
3560 params->ext_phy_config);
3561 break;
3562 }
3563 }
3564 return rc;
3565}
3566
3567
3568static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003569 struct link_vars *vars)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003570{
3571 struct bnx2x *bp = params->bp;
3572 u32 ext_phy_type;
3573 u8 ext_phy_addr;
3574 u16 val1 = 0, val2;
3575 u16 rx_sd, pcs_status;
3576 u8 ext_phy_link_up = 0;
3577 u8 port = params->port;
3578 if (vars->phy_flags & PHY_XGXS_FLAG) {
3579 ext_phy_addr = ((params->ext_phy_config &
3580 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
3581 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
3582
3583 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
3584 switch (ext_phy_type) {
3585 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
3586 DP(NETIF_MSG_LINK, "XGXS Direct\n");
3587 ext_phy_link_up = 1;
3588 break;
3589
3590 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
3591 DP(NETIF_MSG_LINK, "XGXS 8705\n");
3592 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3593 ext_phy_addr,
3594 MDIO_WIS_DEVAD,
3595 MDIO_WIS_REG_LASI_STATUS, &val1);
3596 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3597
3598 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3599 ext_phy_addr,
3600 MDIO_WIS_DEVAD,
3601 MDIO_WIS_REG_LASI_STATUS, &val1);
3602 DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
3603
3604 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3605 ext_phy_addr,
3606 MDIO_PMA_DEVAD,
3607 MDIO_PMA_REG_RX_SD, &rx_sd);
3608 DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
3609 ext_phy_link_up = (rx_sd & 0x1);
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07003610 if (ext_phy_link_up)
3611 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003612 break;
3613
3614 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00003615 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
3616 DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
3617 /* Clear RX Alarm*/
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003618 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3619 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00003620 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
3621 &val2);
3622 /* clear LASI indication*/
3623 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3624 ext_phy_addr,
3625 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
3626 &val1);
3627 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3628 ext_phy_addr,
3629 MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
3630 &val2);
3631 DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
3632 "0x%x\n", val1, val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003633
3634 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3635 ext_phy_addr,
Eilon Greenstein589abe32009-02-12 08:36:55 +00003636 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
3637 &rx_sd);
3638 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3639 ext_phy_addr,
3640 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
3641 &pcs_status);
3642 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3643 ext_phy_addr,
3644 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
3645 &val2);
3646 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3647 ext_phy_addr,
3648 MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
3649 &val2);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003650
Eilon Greenstein589abe32009-02-12 08:36:55 +00003651 DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003652 " pcs_status 0x%x 1Gbps link_status 0x%x\n",
3653 rx_sd, pcs_status, val2);
3654 /* link is up if both bit 0 of pmd_rx_sd and
3655 * bit 0 of pcs_status are set, or if the autoneg bit
3656 1 is set
3657 */
3658 ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
3659 (val2 & (1<<1)));
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003660 if (ext_phy_link_up) {
Eilon Greenstein589abe32009-02-12 08:36:55 +00003661 if (ext_phy_type ==
3662 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
3663 /* If transmitter is disabled,
3664 ignore false link up indication */
3665 bnx2x_cl45_read(bp, params->port,
3666 ext_phy_type,
3667 ext_phy_addr,
3668 MDIO_PMA_DEVAD,
3669 MDIO_PMA_REG_PHY_IDENTIFIER,
3670 &val1);
3671 if (val1 & (1<<15)) {
3672 DP(NETIF_MSG_LINK, "Tx is "
3673 "disabled\n");
3674 ext_phy_link_up = 0;
3675 break;
3676 }
3677 }
3678
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003679 if (val2 & (1<<1))
3680 vars->line_speed = SPEED_1000;
3681 else
3682 vars->line_speed = SPEED_10000;
3683 }
3684
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003685 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003686 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
3687 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
3688 {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003689 u16 link_status = 0;
3690 u16 an1000_status = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003691 if (ext_phy_type ==
3692 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
3693 bnx2x_cl45_read(bp, params->port,
3694 ext_phy_type,
3695 ext_phy_addr,
3696 MDIO_PCS_DEVAD,
3697 MDIO_PCS_REG_LASI_STATUS, &val1);
3698 bnx2x_cl45_read(bp, params->port,
3699 ext_phy_type,
3700 ext_phy_addr,
3701 MDIO_PCS_DEVAD,
3702 MDIO_PCS_REG_LASI_STATUS, &val2);
3703 DP(NETIF_MSG_LINK,
3704 "870x LASI status 0x%x->0x%x\n",
3705 val1, val2);
3706
3707 } else {
3708 /* In 8073, port1 is directed through emac0 and
3709 * port0 is directed through emac1
3710 */
3711 bnx2x_cl45_read(bp, params->port,
3712 ext_phy_type,
3713 ext_phy_addr,
3714 MDIO_PMA_DEVAD,
3715 MDIO_PMA_REG_LASI_STATUS, &val1);
3716
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003717 DP(NETIF_MSG_LINK,
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003718 "8703 LASI status 0x%x\n",
3719 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003720 }
3721
3722 /* clear the interrupt LASI status register */
3723 bnx2x_cl45_read(bp, params->port,
3724 ext_phy_type,
3725 ext_phy_addr,
3726 MDIO_PCS_DEVAD,
3727 MDIO_PCS_REG_STATUS, &val2);
3728 bnx2x_cl45_read(bp, params->port,
3729 ext_phy_type,
3730 ext_phy_addr,
3731 MDIO_PCS_DEVAD,
3732 MDIO_PCS_REG_STATUS, &val1);
3733 DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
3734 val2, val1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003735 /* Clear MSG-OUT */
3736 bnx2x_cl45_read(bp, params->port,
3737 ext_phy_type,
3738 ext_phy_addr,
3739 MDIO_PMA_DEVAD,
3740 0xca13,
3741 &val1);
3742
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003743 /* Check the LASI */
3744 bnx2x_cl45_read(bp, params->port,
3745 ext_phy_type,
3746 ext_phy_addr,
3747 MDIO_PMA_DEVAD,
3748 MDIO_PMA_REG_RX_ALARM, &val2);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003749
3750 DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
3751
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003752 /* Check the link status */
3753 bnx2x_cl45_read(bp, params->port,
3754 ext_phy_type,
3755 ext_phy_addr,
3756 MDIO_PCS_DEVAD,
3757 MDIO_PCS_REG_STATUS, &val2);
3758 DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
3759
3760 bnx2x_cl45_read(bp, params->port,
3761 ext_phy_type,
3762 ext_phy_addr,
3763 MDIO_PMA_DEVAD,
3764 MDIO_PMA_REG_STATUS, &val2);
3765 bnx2x_cl45_read(bp, params->port,
3766 ext_phy_type,
3767 ext_phy_addr,
3768 MDIO_PMA_DEVAD,
3769 MDIO_PMA_REG_STATUS, &val1);
3770 ext_phy_link_up = ((val1 & 4) == 4);
3771 DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
3772 if (ext_phy_type ==
3773 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003774
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003775 if (ext_phy_link_up &&
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003776 ((params->req_line_speed !=
3777 SPEED_10000))) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003778 if (bnx2x_bcm8073_xaui_wa(params)
3779 != 0) {
3780 ext_phy_link_up = 0;
3781 break;
3782 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003783 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003784 bnx2x_cl45_read(bp, params->port,
3785 ext_phy_type,
3786 ext_phy_addr,
3787 MDIO_AN_DEVAD,
3788 0x8304,
3789 &an1000_status);
3790 bnx2x_cl45_read(bp, params->port,
3791 ext_phy_type,
3792 ext_phy_addr,
3793 MDIO_AN_DEVAD,
3794 0x8304,
3795 &an1000_status);
3796
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003797 /* Check the link status on 1.1.2 */
3798 bnx2x_cl45_read(bp, params->port,
3799 ext_phy_type,
3800 ext_phy_addr,
3801 MDIO_PMA_DEVAD,
3802 MDIO_PMA_REG_STATUS, &val2);
3803 bnx2x_cl45_read(bp, params->port,
3804 ext_phy_type,
3805 ext_phy_addr,
3806 MDIO_PMA_DEVAD,
3807 MDIO_PMA_REG_STATUS, &val1);
3808 DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
3809 "an_link_status=0x%x\n",
3810 val2, val1, an1000_status);
3811
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003812 ext_phy_link_up = (((val1 & 4) == 4) ||
3813 (an1000_status & (1<<1)));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003814 if (ext_phy_link_up &&
3815 bnx2x_8073_is_snr_needed(params)) {
3816 /* The SNR will improve about 2dbby
3817 changing the BW and FEE main tap.*/
3818
3819 /* The 1st write to change FFE main
3820 tap is set before restart AN */
3821 /* Change PLL Bandwidth in EDC
3822 register */
3823 bnx2x_cl45_write(bp, port, ext_phy_type,
3824 ext_phy_addr,
3825 MDIO_PMA_DEVAD,
3826 MDIO_PMA_REG_PLL_BANDWIDTH,
3827 0x26BC);
3828
3829 /* Change CDR Bandwidth in EDC
3830 register */
3831 bnx2x_cl45_write(bp, port, ext_phy_type,
3832 ext_phy_addr,
3833 MDIO_PMA_DEVAD,
3834 MDIO_PMA_REG_CDR_BANDWIDTH,
3835 0x0333);
3836
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003837
3838 }
3839 bnx2x_cl45_read(bp, params->port,
3840 ext_phy_type,
3841 ext_phy_addr,
3842 MDIO_PMA_DEVAD,
3843 0xc820,
3844 &link_status);
3845
3846 /* Bits 0..2 --> speed detected,
3847 bits 13..15--> link is down */
3848 if ((link_status & (1<<2)) &&
3849 (!(link_status & (1<<15)))) {
3850 ext_phy_link_up = 1;
3851 vars->line_speed = SPEED_10000;
3852 DP(NETIF_MSG_LINK,
3853 "port %x: External link"
3854 " up in 10G\n", params->port);
3855 } else if ((link_status & (1<<1)) &&
3856 (!(link_status & (1<<14)))) {
3857 ext_phy_link_up = 1;
3858 vars->line_speed = SPEED_2500;
3859 DP(NETIF_MSG_LINK,
3860 "port %x: External link"
3861 " up in 2.5G\n", params->port);
3862 } else if ((link_status & (1<<0)) &&
3863 (!(link_status & (1<<13)))) {
3864 ext_phy_link_up = 1;
3865 vars->line_speed = SPEED_1000;
3866 DP(NETIF_MSG_LINK,
3867 "port %x: External link"
3868 " up in 1G\n", params->port);
3869 } else {
3870 ext_phy_link_up = 0;
3871 DP(NETIF_MSG_LINK,
3872 "port %x: External link"
3873 " is down\n", params->port);
3874 }
3875 } else {
3876 /* See if 1G link is up for the 8072 */
3877 bnx2x_cl45_read(bp, params->port,
3878 ext_phy_type,
3879 ext_phy_addr,
3880 MDIO_AN_DEVAD,
3881 0x8304,
3882 &an1000_status);
3883 bnx2x_cl45_read(bp, params->port,
3884 ext_phy_type,
3885 ext_phy_addr,
3886 MDIO_AN_DEVAD,
3887 0x8304,
3888 &an1000_status);
3889 if (an1000_status & (1<<1)) {
3890 ext_phy_link_up = 1;
3891 vars->line_speed = SPEED_1000;
3892 DP(NETIF_MSG_LINK,
3893 "port %x: External link"
3894 " up in 1G\n", params->port);
3895 } else if (ext_phy_link_up) {
3896 ext_phy_link_up = 1;
3897 vars->line_speed = SPEED_10000;
3898 DP(NETIF_MSG_LINK,
3899 "port %x: External link"
3900 " up in 10G\n", params->port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003901 }
3902 }
Yaniv Rosner6bbca912008-08-13 15:57:28 -07003903
3904
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003905 break;
3906 }
3907 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
3908 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3909 ext_phy_addr,
3910 MDIO_PMA_DEVAD,
3911 MDIO_PMA_REG_LASI_STATUS, &val2);
3912 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3913 ext_phy_addr,
3914 MDIO_PMA_DEVAD,
3915 MDIO_PMA_REG_LASI_STATUS, &val1);
3916 DP(NETIF_MSG_LINK,
3917 "10G-base-T LASI status 0x%x->0x%x\n",
3918 val2, val1);
3919 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3920 ext_phy_addr,
3921 MDIO_PMA_DEVAD,
3922 MDIO_PMA_REG_STATUS, &val2);
3923 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3924 ext_phy_addr,
3925 MDIO_PMA_DEVAD,
3926 MDIO_PMA_REG_STATUS, &val1);
3927 DP(NETIF_MSG_LINK,
3928 "10G-base-T PMA status 0x%x->0x%x\n",
3929 val2, val1);
3930 ext_phy_link_up = ((val1 & 4) == 4);
3931 /* if link is up
3932 * print the AN outcome of the SFX7101 PHY
3933 */
3934 if (ext_phy_link_up) {
3935 bnx2x_cl45_read(bp, params->port,
3936 ext_phy_type,
3937 ext_phy_addr,
3938 MDIO_AN_DEVAD,
3939 MDIO_AN_REG_MASTER_STATUS,
3940 &val2);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07003941 vars->line_speed = SPEED_10000;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003942 DP(NETIF_MSG_LINK,
3943 "SFX7101 AN status 0x%x->Master=%x\n",
3944 val2,
3945 (val2 & (1<<14)));
3946 }
3947 break;
Eilon Greenstein28577182009-02-12 08:37:00 +00003948 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
3949 /* Clear LASI interrupt */
3950 bnx2x_cl45_read(bp, params->port,
3951 ext_phy_type,
3952 ext_phy_addr,
3953 MDIO_PMA_DEVAD,
3954 MDIO_PMA_REG_LASI_STATUS, &val1);
3955 DP(NETIF_MSG_LINK, "8481 LASI status reg = 0x%x\n",
3956 val1);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003957
Eilon Greenstein28577182009-02-12 08:37:00 +00003958 /* Check 10G-BaseT link status */
3959 /* Check Global PMD signal ok */
3960 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3961 ext_phy_addr,
3962 MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
3963 &rx_sd);
3964 /* Check PCS block lock */
3965 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3966 ext_phy_addr,
3967 MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
3968 &pcs_status);
3969 DP(NETIF_MSG_LINK, "8481 1.a = 0x%x, 1.20 = 0x%x\n",
3970 rx_sd, pcs_status);
3971 if (rx_sd & pcs_status & 0x1) {
3972 vars->line_speed = SPEED_10000;
3973 ext_phy_link_up = 1;
3974 } else {
3975
3976 /* Check 1000-BaseT link status */
3977 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3978 ext_phy_addr,
3979 MDIO_AN_DEVAD, 0xFFE1,
3980 &val1);
3981
3982 bnx2x_cl45_read(bp, params->port, ext_phy_type,
3983 ext_phy_addr,
3984 MDIO_AN_DEVAD, 0xFFE1,
3985 &val2);
3986 DP(NETIF_MSG_LINK, "8481 7.FFE1 ="
3987 "0x%x-->0x%x\n", val1, val2);
3988 if (val2 & (1<<2)) {
3989 vars->line_speed = SPEED_1000;
3990 ext_phy_link_up = 1;
3991 }
3992 }
3993
3994 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07003995 default:
3996 DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
3997 params->ext_phy_config);
3998 ext_phy_link_up = 0;
3999 break;
4000 }
4001
4002 } else { /* SerDes */
4003 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4004 switch (ext_phy_type) {
4005 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
4006 DP(NETIF_MSG_LINK, "SerDes Direct\n");
4007 ext_phy_link_up = 1;
4008 break;
4009
4010 case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
4011 DP(NETIF_MSG_LINK, "SerDes 5482\n");
4012 ext_phy_link_up = 1;
4013 break;
4014
4015 default:
4016 DP(NETIF_MSG_LINK,
4017 "BAD SerDes ext_phy_config 0x%x\n",
4018 params->ext_phy_config);
4019 ext_phy_link_up = 0;
4020 break;
4021 }
4022 }
4023
4024 return ext_phy_link_up;
4025}
4026
4027static void bnx2x_link_int_enable(struct link_params *params)
4028{
4029 u8 port = params->port;
4030 u32 ext_phy_type;
4031 u32 mask;
4032 struct bnx2x *bp = params->bp;
4033 /* setting the status to report on link up
4034 for either XGXS or SerDes */
4035
4036 if (params->switch_cfg == SWITCH_CFG_10G) {
4037 mask = (NIG_MASK_XGXS0_LINK10G |
4038 NIG_MASK_XGXS0_LINK_STATUS);
4039 DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
4040 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4041 if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
4042 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
4043 (ext_phy_type !=
4044 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
4045 mask |= NIG_MASK_MI_INT;
4046 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4047 }
4048
4049 } else { /* SerDes */
4050 mask = NIG_MASK_SERDES0_LINK_STATUS;
4051 DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
4052 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4053 if ((ext_phy_type !=
4054 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
4055 (ext_phy_type !=
4056 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
4057 mask |= NIG_MASK_MI_INT;
4058 DP(NETIF_MSG_LINK, "enabled external phy int\n");
4059 }
4060 }
4061 bnx2x_bits_en(bp,
4062 NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4063 mask);
4064 DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port,
4065 (params->switch_cfg == SWITCH_CFG_10G),
4066 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
4067
4068 DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
4069 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
4070 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
4071 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
4072 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
4073 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
4074 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
4075}
4076
4077
4078/*
4079 * link management
4080 */
4081static void bnx2x_link_int_ack(struct link_params *params,
Eilon Greenstein3196a882008-08-13 15:58:49 -07004082 struct link_vars *vars, u8 is_10g)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004083{
4084 struct bnx2x *bp = params->bp;
4085 u8 port = params->port;
4086
4087 /* first reset all status
4088 * we assume only one line will be change at a time */
4089 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4090 (NIG_STATUS_XGXS0_LINK10G |
4091 NIG_STATUS_XGXS0_LINK_STATUS |
4092 NIG_STATUS_SERDES0_LINK_STATUS));
4093 if (vars->phy_link_up) {
4094 if (is_10g) {
4095 /* Disable the 10G link interrupt
4096 * by writing 1 to the status register
4097 */
4098 DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
4099 bnx2x_bits_en(bp,
4100 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4101 NIG_STATUS_XGXS0_LINK10G);
4102
4103 } else if (params->switch_cfg == SWITCH_CFG_10G) {
4104 /* Disable the link interrupt
4105 * by writing 1 to the relevant lane
4106 * in the status register
4107 */
4108 u32 ser_lane = ((params->lane_config &
4109 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
4110 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
4111
4112 DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
4113 bnx2x_bits_en(bp,
4114 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4115 ((1 << ser_lane) <<
4116 NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
4117
4118 } else { /* SerDes */
4119 DP(NETIF_MSG_LINK, "SerDes phy link up\n");
4120 /* Disable the link interrupt
4121 * by writing 1 to the status register
4122 */
4123 bnx2x_bits_en(bp,
4124 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
4125 NIG_STATUS_SERDES0_LINK_STATUS);
4126 }
4127
4128 } else { /* link_down */
4129 }
4130}
4131
4132static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
4133{
4134 u8 *str_ptr = str;
4135 u32 mask = 0xf0000000;
4136 u8 shift = 8*4;
4137 u8 digit;
4138 if (len < 10) {
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02004139 /* Need more than 10chars for this format */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004140 *str_ptr = '\0';
4141 return -EINVAL;
4142 }
4143 while (shift > 0) {
4144
4145 shift -= 4;
4146 digit = ((num & mask) >> shift);
4147 if (digit < 0xa)
4148 *str_ptr = digit + '0';
4149 else
4150 *str_ptr = digit - 0xa + 'a';
4151 str_ptr++;
4152 mask = mask >> 4;
4153 if (shift == 4*4) {
4154 *str_ptr = ':';
4155 str_ptr++;
4156 }
4157 }
4158 *str_ptr = '\0';
4159 return 0;
4160}
4161
4162
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004163static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr,
4164 u32 ext_phy_type)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004165{
4166 u32 cnt = 0;
4167 u16 ctrl = 0;
4168 /* Enable EMAC0 in to enable MDIO */
4169 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
4170 (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
4171 msleep(5);
4172
4173 /* take ext phy out of reset */
4174 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004175 MISC_REGISTERS_GPIO_2,
4176 MISC_REGISTERS_GPIO_HIGH,
4177 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004178
4179 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004180 MISC_REGISTERS_GPIO_1,
4181 MISC_REGISTERS_GPIO_HIGH,
4182 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004183
4184 /* wait for 5ms */
4185 msleep(5);
4186
4187 for (cnt = 0; cnt < 1000; cnt++) {
4188 msleep(1);
4189 bnx2x_cl45_read(bp, port,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004190 ext_phy_type,
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004191 ext_phy_addr,
4192 MDIO_PMA_DEVAD,
4193 MDIO_PMA_REG_CTRL,
4194 &ctrl);
4195 if (!(ctrl & (1<<15))) {
4196 DP(NETIF_MSG_LINK, "Reset completed\n\n");
4197 break;
4198 }
4199 }
4200}
4201
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004202static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004203{
4204 /* put sf to reset */
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004205 bnx2x_set_gpio(bp,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004206 MISC_REGISTERS_GPIO_1,
4207 MISC_REGISTERS_GPIO_LOW,
4208 port);
4209 bnx2x_set_gpio(bp,
4210 MISC_REGISTERS_GPIO_2,
4211 MISC_REGISTERS_GPIO_LOW,
4212 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004213}
4214
4215u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
4216 u8 *version, u16 len)
4217{
4218 struct bnx2x *bp = params->bp;
4219 u32 ext_phy_type = 0;
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004220 u32 spirom_ver = 0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004221 u8 status = 0 ;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004222
4223 if (version == NULL || params == NULL)
4224 return -EINVAL;
4225
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004226 spirom_ver = REG_RD(bp, params->shmem_base +
4227 offsetof(struct shmem_region,
4228 port_mb[params->port].ext_phy_fw_version));
4229
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004230 /* reset the returned value to zero */
4231 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004232 switch (ext_phy_type) {
4233 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4234
4235 if (len < 5)
4236 return -EINVAL;
4237
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004238 version[0] = (spirom_ver & 0xFF);
4239 version[1] = (spirom_ver & 0xFF00) >> 8;
4240 version[2] = (spirom_ver & 0xFF0000) >> 16;
4241 version[3] = (spirom_ver & 0xFF000000) >> 24;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004242 version[4] = '\0';
4243
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004244 break;
4245 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4246 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004247 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4248 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
Eilon Greenstein589abe32009-02-12 08:36:55 +00004249 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
Eilon Greensteina35da8d2009-02-12 08:37:02 +00004250 status = bnx2x_format_ver(spirom_ver, version, len);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004251 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004252 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4253 break;
4254
4255 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
4256 DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
4257 " type is FAILURE!\n");
4258 status = -EINVAL;
4259 break;
4260
4261 default:
4262 break;
4263 }
4264 return status;
4265}
4266
4267static void bnx2x_set_xgxs_loopback(struct link_params *params,
4268 struct link_vars *vars,
4269 u8 is_10g)
4270{
4271 u8 port = params->port;
4272 struct bnx2x *bp = params->bp;
4273
4274 if (is_10g) {
Eilon Greenstein6378c022008-08-13 15:59:25 -07004275 u32 md_devad;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004276
4277 DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
4278
4279 /* change the uni_phy_addr in the nig */
4280 md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
4281 port*0x18));
4282
4283 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
4284
4285 bnx2x_cl45_write(bp, port, 0,
4286 params->phy_addr,
4287 5,
4288 (MDIO_REG_BANK_AER_BLOCK +
4289 (MDIO_AER_BLOCK_AER_REG & 0xf)),
4290 0x2800);
4291
4292 bnx2x_cl45_write(bp, port, 0,
4293 params->phy_addr,
4294 5,
4295 (MDIO_REG_BANK_CL73_IEEEB0 +
4296 (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
4297 0x6041);
Eilon Greenstein38582762009-01-14 06:44:16 +00004298 msleep(200);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004299 /* set aer mmd back */
4300 bnx2x_set_aer_mmd(params, vars);
4301
4302 /* and md_devad */
4303 REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
4304 md_devad);
4305
4306 } else {
4307 u16 mii_control;
4308
4309 DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
4310
4311 CL45_RD_OVER_CL22(bp, port,
4312 params->phy_addr,
4313 MDIO_REG_BANK_COMBO_IEEE0,
4314 MDIO_COMBO_IEEE0_MII_CONTROL,
4315 &mii_control);
4316
4317 CL45_WR_OVER_CL22(bp, port,
4318 params->phy_addr,
4319 MDIO_REG_BANK_COMBO_IEEE0,
4320 MDIO_COMBO_IEEE0_MII_CONTROL,
4321 (mii_control |
4322 MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
4323 }
4324}
4325
4326
4327static void bnx2x_ext_phy_loopback(struct link_params *params)
4328{
4329 struct bnx2x *bp = params->bp;
4330 u8 ext_phy_addr;
4331 u32 ext_phy_type;
4332
4333 if (params->switch_cfg == SWITCH_CFG_10G) {
4334 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
4335 /* CL37 Autoneg Enabled */
4336 ext_phy_addr = ((params->ext_phy_config &
4337 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4338 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4339 switch (ext_phy_type) {
4340 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4341 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
4342 DP(NETIF_MSG_LINK,
4343 "ext_phy_loopback: We should not get here\n");
4344 break;
4345 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
4346 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
4347 break;
4348 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
4349 DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
4350 break;
Eilon Greenstein589abe32009-02-12 08:36:55 +00004351 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4352 DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
4353 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4354 ext_phy_addr,
4355 MDIO_PMA_DEVAD,
4356 MDIO_PMA_REG_CTRL,
4357 0x0001);
4358 break;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004359 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
4360 /* SFX7101_XGXS_TEST1 */
4361 bnx2x_cl45_write(bp, params->port, ext_phy_type,
4362 ext_phy_addr,
4363 MDIO_XS_DEVAD,
4364 MDIO_XS_SFX7101_XGXS_TEST1,
4365 0x100);
4366 DP(NETIF_MSG_LINK,
4367 "ext_phy_loopback: set ext phy loopback\n");
4368 break;
4369 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4370
4371 break;
4372 } /* switch external PHY type */
4373 } else {
4374 /* serdes */
4375 ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
4376 ext_phy_addr = (params->ext_phy_config &
4377 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
4378 >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
4379 }
4380}
4381
4382
4383/*
4384 *------------------------------------------------------------------------
4385 * bnx2x_override_led_value -
4386 *
4387 * Override the led value of the requsted led
4388 *
4389 *------------------------------------------------------------------------
4390 */
4391u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
4392 u32 led_idx, u32 value)
4393{
4394 u32 reg_val;
4395
4396 /* If port 0 then use EMAC0, else use EMAC1*/
4397 u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
4398
4399 DP(NETIF_MSG_LINK,
4400 "bnx2x_override_led_value() port %x led_idx %d value %d\n",
4401 port, led_idx, value);
4402
4403 switch (led_idx) {
4404 case 0: /* 10MB led */
4405 /* Read the current value of the LED register in
4406 the EMAC block */
4407 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4408 /* Set the OVERRIDE bit to 1 */
4409 reg_val |= EMAC_LED_OVERRIDE;
4410 /* If value is 1, set the 10M_OVERRIDE bit,
4411 otherwise reset it.*/
4412 reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
4413 (reg_val & ~EMAC_LED_10MB_OVERRIDE);
4414 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4415 break;
4416 case 1: /*100MB led */
4417 /*Read the current value of the LED register in
4418 the EMAC block */
4419 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4420 /* Set the OVERRIDE bit to 1 */
4421 reg_val |= EMAC_LED_OVERRIDE;
4422 /* If value is 1, set the 100M_OVERRIDE bit,
4423 otherwise reset it.*/
4424 reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
4425 (reg_val & ~EMAC_LED_100MB_OVERRIDE);
4426 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4427 break;
4428 case 2: /* 1000MB led */
4429 /* Read the current value of the LED register in the
4430 EMAC block */
4431 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4432 /* Set the OVERRIDE bit to 1 */
4433 reg_val |= EMAC_LED_OVERRIDE;
4434 /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
4435 reset it. */
4436 reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
4437 (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
4438 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4439 break;
4440 case 3: /* 2500MB led */
4441 /* Read the current value of the LED register in the
4442 EMAC block*/
4443 reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
4444 /* Set the OVERRIDE bit to 1 */
4445 reg_val |= EMAC_LED_OVERRIDE;
4446 /* If value is 1, set the 2500M_OVERRIDE bit, otherwise
4447 reset it.*/
4448 reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
4449 (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
4450 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4451 break;
4452 case 4: /*10G led */
4453 if (port == 0) {
4454 REG_WR(bp, NIG_REG_LED_10G_P0,
4455 value);
4456 } else {
4457 REG_WR(bp, NIG_REG_LED_10G_P1,
4458 value);
4459 }
4460 break;
4461 case 5: /* TRAFFIC led */
4462 /* Find if the traffic control is via BMAC or EMAC */
4463 if (port == 0)
4464 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
4465 else
4466 reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
4467
4468 /* Override the traffic led in the EMAC:*/
4469 if (reg_val == 1) {
4470 /* Read the current value of the LED register in
4471 the EMAC block */
4472 reg_val = REG_RD(bp, emac_base +
4473 EMAC_REG_EMAC_LED);
4474 /* Set the TRAFFIC_OVERRIDE bit to 1 */
4475 reg_val |= EMAC_LED_OVERRIDE;
4476 /* If value is 1, set the TRAFFIC bit, otherwise
4477 reset it.*/
4478 reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
4479 (reg_val & ~EMAC_LED_TRAFFIC);
4480 REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
4481 } else { /* Override the traffic led in the BMAC: */
4482 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4483 + port*4, 1);
4484 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
4485 value);
4486 }
4487 break;
4488 default:
4489 DP(NETIF_MSG_LINK,
4490 "bnx2x_override_led_value() unknown led index %d "
4491 "(should be 0-5)\n", led_idx);
4492 return -EINVAL;
4493 }
4494
4495 return 0;
4496}
4497
4498
4499u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
4500 u16 hw_led_mode, u32 chip_id)
4501{
4502 u8 rc = 0;
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004503 u32 tmp;
4504 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004505 DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
4506 DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
4507 speed, hw_led_mode);
4508 switch (mode) {
4509 case LED_MODE_OFF:
4510 REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
4511 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
4512 SHARED_HW_CFG_LED_MAC1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004513
4514 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004515 EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004516 break;
4517
4518 case LED_MODE_OPER:
4519 REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode);
4520 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
4521 port*4, 0);
4522 /* Set blinking rate to ~15.9Hz */
4523 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
4524 LED_BLINK_RATE_VAL);
4525 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
4526 port*4, 1);
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004527 tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
Eilon Greenstein3196a882008-08-13 15:58:49 -07004528 EMAC_WR(bp, EMAC_REG_EMAC_LED,
Eilon Greenstein345b5d52008-08-13 15:58:12 -07004529 (tmp & (~EMAC_LED_OVERRIDE)));
4530
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004531 if (!CHIP_IS_E1H(bp) &&
4532 ((speed == SPEED_2500) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004533 (speed == SPEED_1000) ||
4534 (speed == SPEED_100) ||
4535 (speed == SPEED_10))) {
4536 /* On Everest 1 Ax chip versions for speeds less than
4537 10G LED scheme is different */
4538 REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
4539 + port*4, 1);
4540 REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
4541 port*4, 0);
4542 REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
4543 port*4, 1);
4544 }
4545 break;
4546
4547 default:
4548 rc = -EINVAL;
4549 DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
4550 mode);
4551 break;
4552 }
4553 return rc;
4554
4555}
4556
4557u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
4558{
4559 struct bnx2x *bp = params->bp;
4560 u16 gp_status = 0;
4561
4562 CL45_RD_OVER_CL22(bp, params->port,
4563 params->phy_addr,
4564 MDIO_REG_BANK_GP_STATUS,
4565 MDIO_GP_STATUS_TOP_AN_STATUS1,
4566 &gp_status);
4567 /* link is up only if both local phy and external phy are up */
4568 if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
4569 bnx2x_ext_phy_is_link_up(params, vars))
4570 return 0;
4571
4572 return -ESRCH;
4573}
4574
4575static u8 bnx2x_link_initialize(struct link_params *params,
4576 struct link_vars *vars)
4577{
4578 struct bnx2x *bp = params->bp;
4579 u8 port = params->port;
4580 u8 rc = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004581 u8 non_ext_phy;
4582 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004583 /* Activate the external PHY */
4584 bnx2x_ext_phy_reset(params, vars);
4585
4586 bnx2x_set_aer_mmd(params, vars);
4587
4588 if (vars->phy_flags & PHY_XGXS_FLAG)
4589 bnx2x_set_master_ln(params);
4590
4591 rc = bnx2x_reset_unicore(params);
4592 /* reset the SerDes and wait for reset bit return low */
4593 if (rc != 0)
4594 return rc;
4595
4596 bnx2x_set_aer_mmd(params, vars);
4597
4598 /* setting the masterLn_def again after the reset */
4599 if (vars->phy_flags & PHY_XGXS_FLAG) {
4600 bnx2x_set_master_ln(params);
4601 bnx2x_set_swap_lanes(params);
4602 }
4603
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004604 if (vars->phy_flags & PHY_XGXS_FLAG) {
Eilon Greenstein44722d12009-01-14 06:44:21 +00004605 if ((params->req_line_speed &&
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004606 ((params->req_line_speed == SPEED_100) ||
Eilon Greenstein44722d12009-01-14 06:44:21 +00004607 (params->req_line_speed == SPEED_10))) ||
4608 (!params->req_line_speed &&
4609 (params->speed_cap_mask >=
4610 PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
4611 (params->speed_cap_mask <
4612 PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
4613 )) {
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004614 vars->phy_flags |= PHY_SGMII_FLAG;
4615 } else {
4616 vars->phy_flags &= ~PHY_SGMII_FLAG;
4617 }
4618 }
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004619 /* In case of external phy existance, the line speed would be the
4620 line speed linked up by the external phy. In case it is direct only,
4621 then the line_speed during initialization will be equal to the
4622 req_line_speed*/
4623 vars->line_speed = params->req_line_speed;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004624
Yaniv Rosner8c99e7b2008-08-13 15:56:17 -07004625 bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004626
4627 /* init ext phy and enable link state int */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004628 non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
4629 (params->loopback_mode == LOOPBACK_XGXS_10) ||
4630 (params->loopback_mode == LOOPBACK_EXT_PHY));
4631
4632 if (non_ext_phy ||
Eilon Greenstein589abe32009-02-12 08:36:55 +00004633 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
Eilon Greenstein28577182009-02-12 08:37:00 +00004634 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
4635 (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481)) {
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004636 if (params->req_line_speed == SPEED_AUTO_NEG)
4637 bnx2x_set_parallel_detection(params, vars->phy_flags);
4638 bnx2x_init_internal_phy(params, vars);
4639 }
4640
4641 if (!non_ext_phy)
4642 rc |= bnx2x_ext_phy_init(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004643
4644 bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004645 (NIG_STATUS_XGXS0_LINK10G |
4646 NIG_STATUS_XGXS0_LINK_STATUS |
4647 NIG_STATUS_SERDES0_LINK_STATUS));
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004648
4649 return rc;
4650
4651}
4652
4653
4654u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
4655{
4656 struct bnx2x *bp = params->bp;
4657
4658 u32 val;
Eilon Greenstein3196a882008-08-13 15:58:49 -07004659 DP(NETIF_MSG_LINK, "Phy Initialization started \n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004660 DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
4661 params->req_line_speed, params->req_flow_ctrl);
4662 vars->link_status = 0;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004663 vars->phy_link_up = 0;
4664 vars->link_up = 0;
4665 vars->line_speed = 0;
4666 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004667 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004668 vars->mac_type = MAC_TYPE_NONE;
4669
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004670 if (params->switch_cfg == SWITCH_CFG_1G)
4671 vars->phy_flags = PHY_SERDES_FLAG;
4672 else
4673 vars->phy_flags = PHY_XGXS_FLAG;
4674
Eilon Greenstein3196a882008-08-13 15:58:49 -07004675
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004676 /* disable attentions */
4677 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
4678 (NIG_MASK_XGXS0_LINK_STATUS |
4679 NIG_MASK_XGXS0_LINK10G |
4680 NIG_MASK_SERDES0_LINK_STATUS |
4681 NIG_MASK_MI_INT));
4682
4683 bnx2x_emac_init(params, vars);
4684
4685 if (CHIP_REV_IS_FPGA(bp)) {
4686 vars->link_up = 1;
4687 vars->line_speed = SPEED_10000;
4688 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004689 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004690 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004691 /* enable on E1.5 FPGA */
4692 if (CHIP_IS_E1H(bp)) {
4693 vars->flow_ctrl |=
David S. Millerc0700f92008-12-16 23:53:20 -08004694 (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX);
Eilon Greenstein34f80b02008-06-23 20:33:01 -07004695 vars->link_status |=
4696 (LINK_STATUS_TX_FLOW_CONTROL_ENABLED |
4697 LINK_STATUS_RX_FLOW_CONTROL_ENABLED);
4698 }
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004699
4700 bnx2x_emac_enable(params, vars, 0);
4701 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4702 /* disable drain */
4703 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4704 + params->port*4, 0);
4705
4706 /* update shared memory */
4707 bnx2x_update_mng(params, vars->link_status);
4708
4709 return 0;
4710
4711 } else
4712 if (CHIP_REV_IS_EMUL(bp)) {
4713
4714 vars->link_up = 1;
4715 vars->line_speed = SPEED_10000;
4716 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004717 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004718 vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD);
4719
4720 bnx2x_bmac_enable(params, vars, 0);
4721
4722 bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed);
4723 /* Disable drain */
4724 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
4725 + params->port*4, 0);
4726
4727 /* update shared memory */
4728 bnx2x_update_mng(params, vars->link_status);
4729
4730 return 0;
4731
4732 } else
4733 if (params->loopback_mode == LOOPBACK_BMAC) {
4734 vars->link_up = 1;
4735 vars->line_speed = SPEED_10000;
4736 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004737 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004738 vars->mac_type = MAC_TYPE_BMAC;
4739
4740 vars->phy_flags = PHY_XGXS_FLAG;
4741
4742 bnx2x_phy_deassert(params, vars->phy_flags);
4743 /* set bmac loopback */
4744 bnx2x_bmac_enable(params, vars, 1);
4745
4746 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4747 params->port*4, 0);
4748 } else if (params->loopback_mode == LOOPBACK_EMAC) {
4749 vars->link_up = 1;
4750 vars->line_speed = SPEED_1000;
4751 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004752 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004753 vars->mac_type = MAC_TYPE_EMAC;
4754
4755 vars->phy_flags = PHY_XGXS_FLAG;
4756
4757 bnx2x_phy_deassert(params, vars->phy_flags);
4758 /* set bmac loopback */
4759 bnx2x_emac_enable(params, vars, 1);
4760 bnx2x_emac_program(params, vars->line_speed,
4761 vars->duplex);
4762 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4763 params->port*4, 0);
4764 } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
4765 (params->loopback_mode == LOOPBACK_EXT_PHY)) {
4766 vars->link_up = 1;
4767 vars->line_speed = SPEED_10000;
4768 vars->duplex = DUPLEX_FULL;
David S. Millerc0700f92008-12-16 23:53:20 -08004769 vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004770
4771 vars->phy_flags = PHY_XGXS_FLAG;
4772
4773 val = REG_RD(bp,
4774 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4775 params->port*0x18);
4776 params->phy_addr = (u8)val;
4777
4778 bnx2x_phy_deassert(params, vars->phy_flags);
4779 bnx2x_link_initialize(params, vars);
4780
4781 vars->mac_type = MAC_TYPE_BMAC;
4782
4783 bnx2x_bmac_enable(params, vars, 0);
4784
4785 if (params->loopback_mode == LOOPBACK_XGXS_10) {
4786 /* set 10G XGXS loopback */
4787 bnx2x_set_xgxs_loopback(params, vars, 1);
4788 } else {
4789 /* set external phy loopback */
4790 bnx2x_ext_phy_loopback(params);
4791 }
4792 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
4793 params->port*4, 0);
4794 } else
4795 /* No loopback */
4796 {
4797
4798 bnx2x_phy_deassert(params, vars->phy_flags);
4799 switch (params->switch_cfg) {
4800 case SWITCH_CFG_1G:
4801 vars->phy_flags |= PHY_SERDES_FLAG;
4802 if ((params->ext_phy_config &
4803 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
4804 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
4805 vars->phy_flags |=
4806 PHY_SGMII_FLAG;
4807 }
4808
4809 val = REG_RD(bp,
4810 NIG_REG_SERDES0_CTRL_PHY_ADDR+
4811 params->port*0x10);
4812
4813 params->phy_addr = (u8)val;
4814
4815 break;
4816 case SWITCH_CFG_10G:
4817 vars->phy_flags |= PHY_XGXS_FLAG;
4818 val = REG_RD(bp,
4819 NIG_REG_XGXS0_CTRL_PHY_ADDR+
4820 params->port*0x18);
4821 params->phy_addr = (u8)val;
4822
4823 break;
4824 default:
4825 DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
4826 return -EINVAL;
4827 break;
4828 }
4829
4830 bnx2x_link_initialize(params, vars);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004831 msleep(30);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004832 bnx2x_link_int_enable(params);
4833 }
4834 return 0;
4835}
4836
Eilon Greenstein589abe32009-02-12 08:36:55 +00004837static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
4838{
4839 DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
4840
4841 /* Set serial boot control for external load */
4842 bnx2x_cl45_write(bp, port,
4843 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
4844 MDIO_PMA_DEVAD,
4845 MDIO_PMA_REG_GEN_CTRL, 0x0001);
4846
4847 /* Disable Transmitter */
4848 bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
4849
4850}
4851
4852u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
4853 u8 reset_ext_phy)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004854{
4855
4856 struct bnx2x *bp = params->bp;
4857 u32 ext_phy_config = params->ext_phy_config;
4858 u16 hw_led_mode = params->hw_led_mode;
4859 u32 chip_id = params->chip_id;
4860 u8 port = params->port;
4861 u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
4862 /* disable attentions */
4863
4864 vars->link_status = 0;
4865 bnx2x_update_mng(params, vars->link_status);
4866 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
4867 (NIG_MASK_XGXS0_LINK_STATUS |
4868 NIG_MASK_XGXS0_LINK10G |
4869 NIG_MASK_SERDES0_LINK_STATUS |
4870 NIG_MASK_MI_INT));
4871
4872 /* activate nig drain */
4873 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4874
4875 /* disable nig egress interface */
4876 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4877 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4878
4879 /* Stop BigMac rx */
4880 bnx2x_bmac_rx_disable(bp, port);
4881
4882 /* disable emac */
4883 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4884
4885 msleep(10);
4886 /* The PHY reset is controled by GPIO 1
4887 * Hold it as vars low
4888 */
4889 /* clear link led */
4890 bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
Eilon Greenstein589abe32009-02-12 08:36:55 +00004891 if (reset_ext_phy) {
4892 switch (ext_phy_type) {
4893 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
4894 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
4895 break;
4896 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
4897 DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
4898 "low power mode\n",
4899 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004900 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07004901 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4902 port);
Eilon Greenstein589abe32009-02-12 08:36:55 +00004903 break;
4904 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
4905 {
4906 u8 ext_phy_addr = ((params->ext_phy_config &
4907 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
4908 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
4909 /* Set soft reset */
4910 bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
4911 break;
4912 }
4913 default:
4914 /* HW reset */
4915 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
4916 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4917 port);
4918 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
4919 MISC_REGISTERS_GPIO_OUTPUT_LOW,
4920 port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004921 DP(NETIF_MSG_LINK, "reset external PHY\n");
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07004922 }
4923 }
4924 /* reset the SerDes/XGXS */
4925 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
4926 (0x1ff << (port*16)));
4927
4928 /* reset BigMac */
4929 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
4930 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4931
4932 /* disable nig ingress interface */
4933 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
4934 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
4935 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
4936 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
4937 vars->link_up = 0;
4938 return 0;
4939}
4940
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004941static u8 bnx2x_update_link_down(struct link_params *params,
4942 struct link_vars *vars)
4943{
4944 struct bnx2x *bp = params->bp;
4945 u8 port = params->port;
4946 DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
4947 bnx2x_set_led(bp, port, LED_MODE_OFF,
4948 0, params->hw_led_mode,
4949 params->chip_id);
4950
4951 /* indicate no mac active */
4952 vars->mac_type = MAC_TYPE_NONE;
4953
4954 /* update shared memory */
4955 vars->link_status = 0;
4956 vars->line_speed = 0;
4957 bnx2x_update_mng(params, vars->link_status);
4958
4959 /* activate nig drain */
4960 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
4961
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00004962 /* disable emac */
4963 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
4964
4965 msleep(10);
4966
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004967 /* reset BigMac */
4968 bnx2x_bmac_rx_disable(bp, params->port);
4969 REG_WR(bp, GRCBASE_MISC +
4970 MISC_REGISTERS_RESET_REG_2_CLEAR,
4971 (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
4972 return 0;
4973}
4974
4975static u8 bnx2x_update_link_up(struct link_params *params,
4976 struct link_vars *vars,
4977 u8 link_10g, u32 gp_status)
4978{
4979 struct bnx2x *bp = params->bp;
4980 u8 port = params->port;
4981 u8 rc = 0;
4982 vars->link_status |= LINK_STATUS_LINK_UP;
4983 if (link_10g) {
4984 bnx2x_bmac_enable(params, vars, 0);
4985 bnx2x_set_led(bp, port, LED_MODE_OPER,
4986 SPEED_10000, params->hw_led_mode,
4987 params->chip_id);
4988
4989 } else {
4990 bnx2x_emac_enable(params, vars, 0);
4991 rc = bnx2x_emac_program(params, vars->line_speed,
4992 vars->duplex);
4993
4994 /* AN complete? */
4995 if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
4996 if (!(vars->phy_flags &
4997 PHY_SGMII_FLAG))
Eilon Greensteined8680a2009-02-12 08:37:12 +00004998 bnx2x_set_gmii_tx_driver(params);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07004999 }
5000 }
5001
5002 /* PBF - link up */
5003 rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
5004 vars->line_speed);
5005
5006 /* disable drain */
5007 REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
5008
5009 /* update shared memory */
5010 bnx2x_update_mng(params, vars->link_status);
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005011 msleep(20);
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005012 return rc;
5013}
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005014/* This function should called upon link interrupt */
5015/* In case vars->link_up, driver needs to
5016 1. Update the pbf
5017 2. Disable drain
5018 3. Update the shared memory
5019 4. Indicate link up
5020 5. Set LEDs
5021 Otherwise,
5022 1. Update shared memory
5023 2. Reset BigMac
5024 3. Report link down
5025 4. Unset LEDs
5026*/
5027u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
5028{
5029 struct bnx2x *bp = params->bp;
5030 u8 port = params->port;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005031 u16 gp_status;
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005032 u8 link_10g;
5033 u8 ext_phy_link_up, rc = 0;
5034 u32 ext_phy_type;
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005035
5036 DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
5037 port,
5038 (vars->phy_flags & PHY_XGXS_FLAG),
5039 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
5040
5041 DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
5042 REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
5043 REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
5044 REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
5045
5046 DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
5047 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
5048 REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
5049
Eilon Greenstein6c55c3cd2009-01-14 06:44:13 +00005050 /* disable emac */
5051 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
5052
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005053 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005054
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005055 /* Check external link change only for non-direct */
5056 ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
5057
5058 /* Read gp_status */
5059 CL45_RD_OVER_CL22(bp, port, params->phy_addr,
5060 MDIO_REG_BANK_GP_STATUS,
5061 MDIO_GP_STATUS_TOP_AN_STATUS1,
5062 &gp_status);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005063
5064 rc = bnx2x_link_settings_status(params, vars, gp_status);
5065 if (rc != 0)
5066 return rc;
5067
5068 /* anything 10 and over uses the bmac */
5069 link_10g = ((vars->line_speed == SPEED_10000) ||
5070 (vars->line_speed == SPEED_12000) ||
5071 (vars->line_speed == SPEED_12500) ||
5072 (vars->line_speed == SPEED_13000) ||
5073 (vars->line_speed == SPEED_15000) ||
5074 (vars->line_speed == SPEED_16000));
5075
5076 bnx2x_link_int_ack(params, vars, link_10g);
5077
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005078 /* In case external phy link is up, and internal link is down
5079 ( not initialized yet probably after link initialization, it needs
5080 to be initialized.
5081 Note that after link down-up as result of cable plug,
5082 the xgxs link would probably become up again without the need to
5083 initialize it*/
5084
5085 if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
5086 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
Eilon Greenstein589abe32009-02-12 08:36:55 +00005087 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005088 (ext_phy_link_up && !vars->phy_link_up))
5089 bnx2x_init_internal_phy(params, vars);
5090
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005091 /* link is up only if both local phy and external phy are up */
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005092 vars->link_up = (ext_phy_link_up && vars->phy_link_up);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005093
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005094 if (vars->link_up)
5095 rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
5096 else
5097 rc = bnx2x_update_link_down(params, vars);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005098
5099 return rc;
5100}
5101
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005102static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5103{
5104 u8 ext_phy_addr[PORT_MAX];
5105 u16 val;
5106 s8 port;
5107
5108 /* PART1 - Reset both phys */
5109 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5110 /* Extract the ext phy address for the port */
5111 u32 ext_phy_config = REG_RD(bp, shmem_base +
5112 offsetof(struct shmem_region,
5113 dev_info.port_hw_config[port].external_phy_config));
5114
5115 /* disable attentions */
5116 bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
5117 (NIG_MASK_XGXS0_LINK_STATUS |
5118 NIG_MASK_XGXS0_LINK10G |
5119 NIG_MASK_SERDES0_LINK_STATUS |
5120 NIG_MASK_MI_INT));
5121
5122 ext_phy_addr[port] =
5123 ((ext_phy_config &
5124 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5125 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5126
5127 /* Need to take the phy out of low power mode in order
5128 to write to access its registers */
5129 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5130 MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
5131
5132 /* Reset the phy */
5133 bnx2x_cl45_write(bp, port,
5134 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5135 ext_phy_addr[port],
5136 MDIO_PMA_DEVAD,
5137 MDIO_PMA_REG_CTRL,
5138 1<<15);
5139 }
5140
5141 /* Add delay of 150ms after reset */
5142 msleep(150);
5143
5144 /* PART2 - Download firmware to both phys */
5145 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5146 u16 fw_ver1;
5147
5148 bnx2x_bcm8073_external_rom_boot(bp, port,
Eilon Greensteina35da8d2009-02-12 08:37:02 +00005149 ext_phy_addr[port], shmem_base);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005150
5151 bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5152 ext_phy_addr[port],
5153 MDIO_PMA_DEVAD,
5154 MDIO_PMA_REG_ROM_VER1, &fw_ver1);
Eilon Greenstein16b311c2009-01-14 06:44:24 +00005155 if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005156 DP(NETIF_MSG_LINK,
Eilon Greenstein16b311c2009-01-14 06:44:24 +00005157 "bnx2x_8073_common_init_phy port %x:"
5158 "Download failed. fw version = 0x%x\n",
5159 port, fw_ver1);
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005160 return -EINVAL;
5161 }
5162
5163 /* Only set bit 10 = 1 (Tx power down) */
5164 bnx2x_cl45_read(bp, port,
5165 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5166 ext_phy_addr[port],
5167 MDIO_PMA_DEVAD,
5168 MDIO_PMA_REG_TX_POWER_DOWN, &val);
5169
5170 /* Phase1 of TX_POWER_DOWN reset */
5171 bnx2x_cl45_write(bp, port,
5172 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5173 ext_phy_addr[port],
5174 MDIO_PMA_DEVAD,
5175 MDIO_PMA_REG_TX_POWER_DOWN,
5176 (val | 1<<10));
5177 }
5178
5179 /* Toggle Transmitter: Power down and then up with 600ms
5180 delay between */
5181 msleep(600);
5182
5183 /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
5184 for (port = PORT_MAX - 1; port >= PORT_0; port--) {
5185 /* Phase2 of POWER_DOWN_RESET*/
5186 /* Release bit 10 (Release Tx power down) */
5187 bnx2x_cl45_read(bp, port,
5188 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5189 ext_phy_addr[port],
5190 MDIO_PMA_DEVAD,
5191 MDIO_PMA_REG_TX_POWER_DOWN, &val);
5192
5193 bnx2x_cl45_write(bp, port,
5194 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5195 ext_phy_addr[port],
5196 MDIO_PMA_DEVAD,
5197 MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
5198 msleep(15);
5199
5200 /* Read modify write the SPI-ROM version select register */
5201 bnx2x_cl45_read(bp, port,
5202 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5203 ext_phy_addr[port],
5204 MDIO_PMA_DEVAD,
5205 MDIO_PMA_REG_EDC_FFE_MAIN, &val);
5206 bnx2x_cl45_write(bp, port,
5207 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
5208 ext_phy_addr[port],
5209 MDIO_PMA_DEVAD,
5210 MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
5211
5212 /* set GPIO2 back to LOW */
5213 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
5214 MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
5215 }
5216 return 0;
5217
5218}
5219
Eilon Greenstein589abe32009-02-12 08:36:55 +00005220
5221static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5222{
5223 u8 ext_phy_addr;
5224 u32 val;
5225 s8 port;
5226 /* Use port1 because of the static port-swap */
5227 /* Enable the module detection interrupt */
5228 val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
5229 val |= ((1<<MISC_REGISTERS_GPIO_3)|
5230 (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
5231 REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
5232
5233 bnx2x_hw_reset(bp, 1);
5234 msleep(5);
5235 for (port = 0; port < PORT_MAX; port++) {
5236 /* Extract the ext phy address for the port */
5237 u32 ext_phy_config = REG_RD(bp, shmem_base +
5238 offsetof(struct shmem_region,
5239 dev_info.port_hw_config[port].external_phy_config));
5240
5241 ext_phy_addr =
5242 ((ext_phy_config &
5243 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5244 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5245 DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
5246 ext_phy_addr);
5247
5248 bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
5249
5250 /* Set fault module detected LED on */
5251 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5252 MISC_REGISTERS_GPIO_HIGH,
5253 port);
5254 }
5255
5256 return 0;
5257}
5258
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005259u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
5260{
5261 u8 rc = 0;
5262 u32 ext_phy_type;
5263
5264 DP(NETIF_MSG_LINK, "bnx2x_common_init_phy\n");
5265
5266 /* Read the ext_phy_type for arbitrary port(0) */
5267 ext_phy_type = XGXS_EXT_PHY_TYPE(
5268 REG_RD(bp, shmem_base +
5269 offsetof(struct shmem_region,
5270 dev_info.port_hw_config[0].external_phy_config)));
5271
5272 switch (ext_phy_type) {
5273 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
5274 {
5275 rc = bnx2x_8073_common_init_phy(bp, shmem_base);
5276 break;
5277 }
Eilon Greenstein589abe32009-02-12 08:36:55 +00005278 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
5279 /* GPIO1 affects both ports, so there's need to pull
5280 it for single port alone */
5281 rc = bnx2x_8726_common_init_phy(bp, shmem_base);
5282
5283 break;
Yaniv Rosner6bbca912008-08-13 15:57:28 -07005284 default:
5285 DP(NETIF_MSG_LINK,
5286 "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
5287 ext_phy_type);
5288 break;
5289 }
5290
5291 return rc;
5292}
5293
5294
5295
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005296static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
5297{
5298 u16 val, cnt;
5299
5300 bnx2x_cl45_read(bp, port,
5301 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5302 phy_addr,
5303 MDIO_PMA_DEVAD,
5304 MDIO_PMA_REG_7101_RESET, &val);
5305
5306 for (cnt = 0; cnt < 10; cnt++) {
5307 msleep(50);
5308 /* Writes a self-clearing reset */
5309 bnx2x_cl45_write(bp, port,
5310 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5311 phy_addr,
5312 MDIO_PMA_DEVAD,
5313 MDIO_PMA_REG_7101_RESET,
5314 (val | (1<<15)));
5315 /* Wait for clear */
5316 bnx2x_cl45_read(bp, port,
5317 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5318 phy_addr,
5319 MDIO_PMA_DEVAD,
5320 MDIO_PMA_REG_7101_RESET, &val);
5321
5322 if ((val & (1<<15)) == 0)
5323 break;
5324 }
5325}
5326#define RESERVED_SIZE 256
5327/* max application is 160K bytes - data at end of RAM */
Eilon Greenstein6378c022008-08-13 15:59:25 -07005328#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE)
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005329
5330/* Header is 14 bytes */
5331#define HEADER_SIZE 14
5332#define DATA_OFFSET HEADER_SIZE
5333
5334#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \
5335 bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \
5336 ext_phy_addr, \
5337 MDIO_PCS_DEVAD, \
5338 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1)
5339
5340/* Programs an image to DSP's flash via the SPI port*/
5341static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port,
5342 u8 ext_phy_addr,
5343 char data[], u32 size)
5344{
5345 const u16 num_trans = size/4; /* 4 bytes can be sent at a time */
5346 /* Doesn't include last trans!*/
5347 const u16 last_trans_size = size%4; /* Num bytes on last trans */
5348 u16 trans_cnt, byte_cnt;
5349 u32 data_index;
5350 u16 tmp;
5351 u16 code_started = 0;
5352 u16 image_revision1, image_revision2;
5353 u16 cnt;
5354
5355 DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size);
5356 /* Going to flash*/
5357 if ((size-HEADER_SIZE) > MAX_APP_SIZE) {
5358 /* This very often will be the case, because the image is built
5359 with 160Kbytes size whereas the total image size must actually
5360 be 160Kbytes-RESERVED_SIZE */
5361 DP(NETIF_MSG_LINK, "Warning, file size was %d bytes "
5362 "truncated to %d bytes\n", size, MAX_APP_SIZE);
5363 size = MAX_APP_SIZE+HEADER_SIZE;
5364 }
5365 DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]);
Eilon Greenstein3196a882008-08-13 15:58:49 -07005366 DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005367 /* Put the DSP in download mode by setting FLASH_CFG[2] to 1
5368 and issuing a reset.*/
5369
5370 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005371 MISC_REGISTERS_GPIO_HIGH, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005372
5373 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
5374
5375 /* wait 0.5 sec */
5376 for (cnt = 0; cnt < 100; cnt++)
5377 msleep(5);
5378
5379 /* Make sure we can access the DSP
5380 And it's in the correct mode (waiting for download) */
5381
5382 bnx2x_cl45_read(bp, port,
5383 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5384 ext_phy_addr,
5385 MDIO_PCS_DEVAD,
5386 MDIO_PCS_REG_7101_DSP_ACCESS, &tmp);
5387
5388 if (tmp != 0x000A) {
5389 DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. "
5390 "Expected 0x000A, read 0x%04X\n", tmp);
5391 DP(NETIF_MSG_LINK, "Download failed\n");
5392 return -EINVAL;
5393 }
5394
5395 /* Mux the SPI interface away from the internal processor */
5396 bnx2x_cl45_write(bp, port,
5397 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5398 ext_phy_addr,
5399 MDIO_PCS_DEVAD,
5400 MDIO_PCS_REG_7101_SPI_MUX, 1);
5401
5402 /* Reset the SPI port */
5403 bnx2x_cl45_write(bp, port,
5404 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5405 ext_phy_addr,
5406 MDIO_PCS_DEVAD,
5407 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
5408 bnx2x_cl45_write(bp, port,
5409 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5410 ext_phy_addr,
5411 MDIO_PCS_DEVAD,
5412 MDIO_PCS_REG_7101_SPI_CTRL_ADDR,
5413 (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT));
5414 bnx2x_cl45_write(bp, port,
5415 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5416 ext_phy_addr,
5417 MDIO_PCS_DEVAD,
5418 MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0);
5419
5420 /* Erase the flash */
5421 bnx2x_cl45_write(bp, port,
5422 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5423 ext_phy_addr,
5424 MDIO_PCS_DEVAD,
5425 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5426 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5427
5428 bnx2x_cl45_write(bp, port,
5429 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5430 ext_phy_addr,
5431 MDIO_PCS_DEVAD,
5432 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5433 1);
5434
5435 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5436 bnx2x_cl45_write(bp, port,
5437 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5438 ext_phy_addr,
5439 MDIO_PCS_DEVAD,
5440 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5441 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD);
5442
5443 bnx2x_cl45_write(bp, port,
5444 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5445 ext_phy_addr,
5446 MDIO_PCS_DEVAD,
5447 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5448 1);
5449 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5450
5451 /* Wait 10 seconds, the maximum time for the erase to complete */
5452 DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n");
5453 for (cnt = 0; cnt < 1000; cnt++)
5454 msleep(10);
5455
5456 DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n");
5457 data_index = 0;
5458 for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) {
5459 bnx2x_cl45_write(bp, port,
5460 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5461 ext_phy_addr,
5462 MDIO_PCS_DEVAD,
5463 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5464 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5465
5466 bnx2x_cl45_write(bp, port,
5467 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5468 ext_phy_addr,
5469 MDIO_PCS_DEVAD,
5470 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5471 1);
5472 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5473
5474 bnx2x_cl45_write(bp, port,
5475 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5476 ext_phy_addr,
5477 MDIO_PCS_DEVAD,
5478 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5479 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
5480
5481 /* Bits 23-16 of address */
5482 bnx2x_cl45_write(bp, port,
5483 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5484 ext_phy_addr,
5485 MDIO_PCS_DEVAD,
5486 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5487 (data_index>>16));
5488 /* Bits 15-8 of address */
5489 bnx2x_cl45_write(bp, port,
5490 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5491 ext_phy_addr,
5492 MDIO_PCS_DEVAD,
5493 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5494 (data_index>>8));
5495
5496 /* Bits 7-0 of address */
5497 bnx2x_cl45_write(bp, port,
5498 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5499 ext_phy_addr,
5500 MDIO_PCS_DEVAD,
5501 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5502 ((u16)data_index));
5503
5504 byte_cnt = 0;
5505 while (byte_cnt < 4 && data_index < size) {
5506 bnx2x_cl45_write(bp, port,
5507 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5508 ext_phy_addr,
5509 MDIO_PCS_DEVAD,
5510 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5511 data[data_index++]);
5512 byte_cnt++;
5513 }
5514
5515 bnx2x_cl45_write(bp, port,
5516 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5517 ext_phy_addr,
5518 MDIO_PCS_DEVAD,
5519 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5520 byte_cnt+4);
5521
5522 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5523 msleep(5); /* Wait 5 ms minimum between transs */
5524
5525 /* Let the user know something's going on.*/
5526 /* a pacifier ever 4K */
5527 if ((data_index % 1023) == 0)
5528 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
5529 }
5530
5531 DP(NETIF_MSG_LINK, "\n");
5532 /* Transfer the last block if there is data remaining */
5533 if (last_trans_size) {
5534 bnx2x_cl45_write(bp, port,
5535 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5536 ext_phy_addr,
5537 MDIO_PCS_DEVAD,
5538 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5539 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD);
5540
5541 bnx2x_cl45_write(bp, port,
5542 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5543 ext_phy_addr,
5544 MDIO_PCS_DEVAD,
5545 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5546 1);
5547
5548 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5549
5550 bnx2x_cl45_write(bp, port,
5551 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5552 ext_phy_addr,
5553 MDIO_PCS_DEVAD,
5554 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5555 MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD);
5556
5557 /* Bits 23-16 of address */
5558 bnx2x_cl45_write(bp, port,
5559 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5560 ext_phy_addr,
5561 MDIO_PCS_DEVAD,
5562 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5563 (data_index>>16));
5564 /* Bits 15-8 of address */
5565 bnx2x_cl45_write(bp, port,
5566 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5567 ext_phy_addr,
5568 MDIO_PCS_DEVAD,
5569 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5570 (data_index>>8));
5571
5572 /* Bits 7-0 of address */
5573 bnx2x_cl45_write(bp, port,
5574 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5575 ext_phy_addr,
5576 MDIO_PCS_DEVAD,
5577 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5578 ((u16)data_index));
5579
5580 byte_cnt = 0;
5581 while (byte_cnt < last_trans_size && data_index < size) {
5582 /* Bits 7-0 of address */
5583 bnx2x_cl45_write(bp, port,
5584 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5585 ext_phy_addr,
5586 MDIO_PCS_DEVAD,
5587 MDIO_PCS_REG_7101_SPI_FIFO_ADDR,
5588 data[data_index++]);
5589 byte_cnt++;
5590 }
5591
5592 bnx2x_cl45_write(bp, port,
5593 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5594 ext_phy_addr,
5595 MDIO_PCS_DEVAD,
5596 MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR,
5597 byte_cnt+4);
5598
5599 SPI_START_TRANSFER(bp, port, ext_phy_addr);
5600 }
5601
5602 /* DSP Remove Download Mode */
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005603 bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
5604 MISC_REGISTERS_GPIO_LOW, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005605
5606 bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
5607
5608 /* wait 0.5 sec to allow it to run */
5609 for (cnt = 0; cnt < 100; cnt++)
5610 msleep(5);
5611
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005612 bnx2x_hw_reset(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005613
5614 for (cnt = 0; cnt < 100; cnt++)
5615 msleep(5);
5616
5617 /* Check that the code is started. In case the download
5618 checksum failed, the code won't be started. */
5619 bnx2x_cl45_read(bp, port,
5620 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5621 ext_phy_addr,
5622 MDIO_PCS_DEVAD,
5623 MDIO_PCS_REG_7101_DSP_ACCESS,
5624 &tmp);
5625
5626 code_started = (tmp & (1<<4));
5627 if (!code_started) {
5628 DP(NETIF_MSG_LINK, "Download failed. Please check file.\n");
5629 return -EINVAL;
5630 }
5631
5632 /* Verify that the file revision is now equal to the image
5633 revision within the DSP */
5634 bnx2x_cl45_read(bp, port,
5635 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5636 ext_phy_addr,
5637 MDIO_PMA_DEVAD,
5638 MDIO_PMA_REG_7101_VER1,
5639 &image_revision1);
5640
5641 bnx2x_cl45_read(bp, port,
5642 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
5643 ext_phy_addr,
5644 MDIO_PMA_DEVAD,
5645 MDIO_PMA_REG_7101_VER2,
5646 &image_revision2);
5647
Eilon Greenstein3196a882008-08-13 15:58:49 -07005648 if (data[0x14e] != (image_revision2&0xFF) ||
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005649 data[0x14f] != ((image_revision2&0xFF00)>>8) ||
5650 data[0x150] != (image_revision1&0xFF) ||
5651 data[0x151] != ((image_revision1&0xFF00)>>8)) {
5652 DP(NETIF_MSG_LINK, "Download failed.\n");
5653 return -EINVAL;
5654 }
5655 DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size);
5656 return 0;
5657}
5658
5659u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
5660 u8 driver_loaded, char data[], u32 size)
5661{
5662 u8 rc = 0;
5663 u32 ext_phy_type;
5664 u8 ext_phy_addr;
5665 ext_phy_addr = ((ext_phy_config &
5666 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
5667 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
5668
5669 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
5670
5671 switch (ext_phy_type) {
5672 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
5673 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
5674 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
5675 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
5676 DP(NETIF_MSG_LINK,
5677 "Flash download not supported for this ext phy\n");
5678 rc = -EINVAL;
5679 break;
5680 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
5681 /* Take ext phy out of reset */
5682 if (!driver_loaded)
Yaniv Rosner57963ed2008-08-13 15:55:28 -07005683 bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005684 rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
5685 data, size);
5686 if (!driver_loaded)
Eilon Greenstein17de50b2008-08-13 15:56:59 -07005687 bnx2x_turn_off_sf(bp, port);
Yaniv Rosnerea4e0402008-06-23 20:27:26 -07005688 break;
5689 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
5690 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
5691 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
5692 default:
5693 DP(NETIF_MSG_LINK, "Invalid ext phy type\n");
5694 rc = -EINVAL;
5695 break;
5696 }
5697 return rc;
5698}
5699