1eef4f27bSRobert Mustacchi /*
2eef4f27bSRobert Mustacchi  * Copyright 2014-2017 Cavium, Inc.
3eef4f27bSRobert Mustacchi  * The contents of this file are subject to the terms of the Common Development
4eef4f27bSRobert Mustacchi  * and Distribution License, v.1,  (the "License").
5eef4f27bSRobert Mustacchi  *
6eef4f27bSRobert Mustacchi  * You may not use this file except in compliance with the License.
7eef4f27bSRobert Mustacchi  *
8eef4f27bSRobert Mustacchi  * You can obtain a copy of the License at available
9eef4f27bSRobert Mustacchi  * at http://opensource.org/licenses/CDDL-1.0
10eef4f27bSRobert Mustacchi  *
11eef4f27bSRobert Mustacchi  * See the License for the specific language governing permissions and
12eef4f27bSRobert Mustacchi  * limitations under the License.
13eef4f27bSRobert Mustacchi  */
14eef4f27bSRobert Mustacchi 
15eef4f27bSRobert Mustacchi #include "54xx_reg.h"
16eef4f27bSRobert Mustacchi #include "serdes.h"
17eef4f27bSRobert Mustacchi #include "lm5706.h"
18eef4f27bSRobert Mustacchi #include "netlink.h"
19eef4f27bSRobert Mustacchi 
20eef4f27bSRobert Mustacchi 
21eef4f27bSRobert Mustacchi 
22eef4f27bSRobert Mustacchi /*******************************************************************************
23eef4f27bSRobert Mustacchi  * Macros.
24eef4f27bSRobert Mustacchi  ******************************************************************************/
25eef4f27bSRobert Mustacchi 
26eef4f27bSRobert Mustacchi #define MII_REG(_type, _field)          (OFFSETOF(_type, _field)/2)
27eef4f27bSRobert Mustacchi 
28eef4f27bSRobert Mustacchi 
29eef4f27bSRobert Mustacchi 
30eef4f27bSRobert Mustacchi /*******************************************************************************
31eef4f27bSRobert Mustacchi  * Description:
32eef4f27bSRobert Mustacchi  *
33eef4f27bSRobert Mustacchi  * Return:
34eef4f27bSRobert Mustacchi  ******************************************************************************/
35eef4f27bSRobert Mustacchi lm_status_t
lm_mwrite(lm_device_t * pdev,u32_t phy_addr,u32_t reg,u32_t val)36eef4f27bSRobert Mustacchi lm_mwrite(
37eef4f27bSRobert Mustacchi     lm_device_t *pdev,
38eef4f27bSRobert Mustacchi     u32_t phy_addr,
39eef4f27bSRobert Mustacchi     u32_t reg,
40eef4f27bSRobert Mustacchi     u32_t val)
41eef4f27bSRobert Mustacchi {
42eef4f27bSRobert Mustacchi     lm_status_t lm_status;
43eef4f27bSRobert Mustacchi     u32_t tmp;
44eef4f27bSRobert Mustacchi     u32_t cnt;
45eef4f27bSRobert Mustacchi 
46eef4f27bSRobert Mustacchi     DbgBreakIf(pdev->params.enable_remote_phy);
47eef4f27bSRobert Mustacchi 
48eef4f27bSRobert Mustacchi     if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
49eef4f27bSRobert Mustacchi     {
50eef4f27bSRobert Mustacchi         REG_RD(pdev, emac.emac_mdio_mode, &tmp);
51eef4f27bSRobert Mustacchi         tmp &= ~EMAC_MDIO_MODE_AUTO_POLL;
52eef4f27bSRobert Mustacchi 
53eef4f27bSRobert Mustacchi         REG_WR(pdev, emac.emac_mdio_mode, tmp);
54eef4f27bSRobert Mustacchi 
55eef4f27bSRobert Mustacchi         mm_wait(pdev, 40);
56eef4f27bSRobert Mustacchi     }
57eef4f27bSRobert Mustacchi 
58*55fea89dSDan Cross     tmp = (phy_addr << 21) |
59*55fea89dSDan Cross         (reg << 16) |
60eef4f27bSRobert Mustacchi         val |
61eef4f27bSRobert Mustacchi         EMAC_MDIO_COMM_COMMAND_WRITE_TE |
62eef4f27bSRobert Mustacchi         EMAC_MDIO_COMM_START_BUSY |
63eef4f27bSRobert Mustacchi         EMAC_MDIO_COMM_DISEXT;
64eef4f27bSRobert Mustacchi 
65eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_mdio_comm, tmp);
66*55fea89dSDan Cross 
67eef4f27bSRobert Mustacchi     for(cnt = 0; cnt < 1000; cnt++)
68eef4f27bSRobert Mustacchi     {
69eef4f27bSRobert Mustacchi         mm_wait(pdev, 10);
70eef4f27bSRobert Mustacchi 
71eef4f27bSRobert Mustacchi         REG_RD(pdev, emac.emac_mdio_comm, &tmp);
72eef4f27bSRobert Mustacchi         if(!(tmp & EMAC_MDIO_COMM_START_BUSY))
73eef4f27bSRobert Mustacchi         {
74eef4f27bSRobert Mustacchi             mm_wait(pdev, 5);
75eef4f27bSRobert Mustacchi             break;
76eef4f27bSRobert Mustacchi         }
77eef4f27bSRobert Mustacchi     }
78eef4f27bSRobert Mustacchi 
79eef4f27bSRobert Mustacchi     if(tmp & EMAC_MDIO_COMM_START_BUSY)
80eef4f27bSRobert Mustacchi     {
81eef4f27bSRobert Mustacchi         DbgBreakMsg("Write phy register failed\n");
82eef4f27bSRobert Mustacchi 
83eef4f27bSRobert Mustacchi         lm_status = LM_STATUS_FAILURE;
84eef4f27bSRobert Mustacchi     }
85eef4f27bSRobert Mustacchi     else
86eef4f27bSRobert Mustacchi     {
87eef4f27bSRobert Mustacchi         lm_status = LM_STATUS_SUCCESS;
88eef4f27bSRobert Mustacchi     }
89eef4f27bSRobert Mustacchi 
90eef4f27bSRobert Mustacchi     if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
91eef4f27bSRobert Mustacchi     {
92eef4f27bSRobert Mustacchi         REG_RD(pdev, emac.emac_mdio_mode, &tmp);
93eef4f27bSRobert Mustacchi         tmp |= EMAC_MDIO_MODE_AUTO_POLL;
94eef4f27bSRobert Mustacchi 
95eef4f27bSRobert Mustacchi         REG_WR(pdev, emac.emac_mdio_mode, tmp);
96eef4f27bSRobert Mustacchi     }
97eef4f27bSRobert Mustacchi 
98eef4f27bSRobert Mustacchi     return lm_status;
99eef4f27bSRobert Mustacchi } /* lm_mwrite */
100eef4f27bSRobert Mustacchi 
101eef4f27bSRobert Mustacchi 
102eef4f27bSRobert Mustacchi 
103eef4f27bSRobert Mustacchi /*******************************************************************************
104eef4f27bSRobert Mustacchi  * Description:
105eef4f27bSRobert Mustacchi  *
106eef4f27bSRobert Mustacchi  * Return:
107eef4f27bSRobert Mustacchi  ******************************************************************************/
108eef4f27bSRobert Mustacchi lm_status_t
lm_mread(lm_device_t * pdev,u32_t phy_addr,u32_t reg,u32_t * ret_val)109eef4f27bSRobert Mustacchi lm_mread(
110eef4f27bSRobert Mustacchi     lm_device_t *pdev,
111eef4f27bSRobert Mustacchi     u32_t phy_addr,
112eef4f27bSRobert Mustacchi     u32_t reg,
113eef4f27bSRobert Mustacchi     u32_t *ret_val)
114eef4f27bSRobert Mustacchi {
115eef4f27bSRobert Mustacchi     lm_status_t lm_status;
116eef4f27bSRobert Mustacchi     u32_t val;
117eef4f27bSRobert Mustacchi     u32_t cnt;
118eef4f27bSRobert Mustacchi 
119eef4f27bSRobert Mustacchi     DbgBreakIf(pdev->params.enable_remote_phy);
120eef4f27bSRobert Mustacchi 
121eef4f27bSRobert Mustacchi     if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
122eef4f27bSRobert Mustacchi     {
123eef4f27bSRobert Mustacchi         REG_RD(pdev, emac.emac_mdio_mode, &val);
124eef4f27bSRobert Mustacchi         val &= ~EMAC_MDIO_MODE_AUTO_POLL;
125eef4f27bSRobert Mustacchi 
126eef4f27bSRobert Mustacchi         REG_WR(pdev, emac.emac_mdio_mode, val);
127eef4f27bSRobert Mustacchi 
128eef4f27bSRobert Mustacchi         mm_wait(pdev, 40);
129eef4f27bSRobert Mustacchi     }
130eef4f27bSRobert Mustacchi 
131*55fea89dSDan Cross     val = (phy_addr << 21) |
132eef4f27bSRobert Mustacchi         (reg << 16) |
133eef4f27bSRobert Mustacchi         EMAC_MDIO_COMM_COMMAND_READ_TE |
134eef4f27bSRobert Mustacchi         EMAC_MDIO_COMM_DISEXT |
135eef4f27bSRobert Mustacchi         EMAC_MDIO_COMM_START_BUSY;
136eef4f27bSRobert Mustacchi 
137eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_mdio_comm, val);
138eef4f27bSRobert Mustacchi 
139eef4f27bSRobert Mustacchi     for(cnt = 0; cnt < 1000; cnt++)
140eef4f27bSRobert Mustacchi     {
141eef4f27bSRobert Mustacchi         mm_wait(pdev, 10);
142eef4f27bSRobert Mustacchi 
143eef4f27bSRobert Mustacchi         REG_RD(pdev, emac.emac_mdio_comm, &val);
144eef4f27bSRobert Mustacchi         if(!(val & EMAC_MDIO_COMM_START_BUSY))
145eef4f27bSRobert Mustacchi         {
146eef4f27bSRobert Mustacchi             /* There is a bug here.  The MI_COM_BUSY bit may be cleared
147eef4f27bSRobert Mustacchi              * before the data is loaded into the register. */
148eef4f27bSRobert Mustacchi             REG_RD(pdev, emac.emac_mdio_comm, &val);
149eef4f27bSRobert Mustacchi 
150eef4f27bSRobert Mustacchi             REG_RD(pdev, emac.emac_mdio_comm, &val);
151eef4f27bSRobert Mustacchi             val &= EMAC_MDIO_COMM_DATA;
152eef4f27bSRobert Mustacchi 
153eef4f27bSRobert Mustacchi             break;
154eef4f27bSRobert Mustacchi         }
155eef4f27bSRobert Mustacchi     }
156eef4f27bSRobert Mustacchi 
157eef4f27bSRobert Mustacchi     if(val & EMAC_MDIO_COMM_START_BUSY)
158eef4f27bSRobert Mustacchi     {
159eef4f27bSRobert Mustacchi         DbgBreakMsg("Read phy register failed\n");
160eef4f27bSRobert Mustacchi 
161eef4f27bSRobert Mustacchi         val = 0;
162eef4f27bSRobert Mustacchi 
163eef4f27bSRobert Mustacchi         lm_status = LM_STATUS_FAILURE;
164eef4f27bSRobert Mustacchi     }
165eef4f27bSRobert Mustacchi     else
166eef4f27bSRobert Mustacchi     {
167eef4f27bSRobert Mustacchi         lm_status = LM_STATUS_SUCCESS;
168eef4f27bSRobert Mustacchi     }
169eef4f27bSRobert Mustacchi 
170eef4f27bSRobert Mustacchi     *ret_val = val;
171eef4f27bSRobert Mustacchi 
172eef4f27bSRobert Mustacchi     if(pdev->params.phy_int_mode == PHY_INT_MODE_AUTO_POLLING)
173eef4f27bSRobert Mustacchi     {
174eef4f27bSRobert Mustacchi         REG_RD(pdev, emac.emac_mdio_mode, &val);
175eef4f27bSRobert Mustacchi         val |= EMAC_MDIO_MODE_AUTO_POLL;
176eef4f27bSRobert Mustacchi 
177eef4f27bSRobert Mustacchi         REG_WR(pdev, emac.emac_mdio_mode, val);
178eef4f27bSRobert Mustacchi     }
179eef4f27bSRobert Mustacchi 
180eef4f27bSRobert Mustacchi     return lm_status;
181eef4f27bSRobert Mustacchi } /* lm_mread */
182eef4f27bSRobert Mustacchi 
183eef4f27bSRobert Mustacchi 
184eef4f27bSRobert Mustacchi 
185eef4f27bSRobert Mustacchi /*******************************************************************************
186eef4f27bSRobert Mustacchi  * Description:
187eef4f27bSRobert Mustacchi  *
188eef4f27bSRobert Mustacchi  * Return:
189eef4f27bSRobert Mustacchi  ******************************************************************************/
190eef4f27bSRobert Mustacchi STATIC u32_t
phy_ad_settings(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_ctrl)191eef4f27bSRobert Mustacchi phy_ad_settings(
192eef4f27bSRobert Mustacchi     lm_device_t *pdev,
193eef4f27bSRobert Mustacchi     lm_medium_t req_medium,
194eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl)
195eef4f27bSRobert Mustacchi {
196eef4f27bSRobert Mustacchi     u32_t val;
197eef4f27bSRobert Mustacchi 
198eef4f27bSRobert Mustacchi     val = 0;
199eef4f27bSRobert Mustacchi 
200eef4f27bSRobert Mustacchi     /* Please refer to Table 28B-3 of the 802.3ab-1999 spec. */
201eef4f27bSRobert Mustacchi     if((flow_ctrl == LM_FLOW_CONTROL_AUTO_PAUSE) ||
202eef4f27bSRobert Mustacchi         ((flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE) &&
203eef4f27bSRobert Mustacchi         (flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)))
204eef4f27bSRobert Mustacchi     {
205eef4f27bSRobert Mustacchi         if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_TYPE_FIBER)
206eef4f27bSRobert Mustacchi         {
207eef4f27bSRobert Mustacchi             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
208eef4f27bSRobert Mustacchi             {
209eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_1000X_PAUSE_CAPABLE |
210eef4f27bSRobert Mustacchi                     PHY_AN_AD_1000X_ASYM_PAUSE;
211eef4f27bSRobert Mustacchi             }
212eef4f27bSRobert Mustacchi             else
213eef4f27bSRobert Mustacchi             {
214eef4f27bSRobert Mustacchi                 val |= MII_ADVERT_PAUSE;
215eef4f27bSRobert Mustacchi             }
216eef4f27bSRobert Mustacchi         }
217eef4f27bSRobert Mustacchi         else
218eef4f27bSRobert Mustacchi         {
219eef4f27bSRobert Mustacchi             val |= PHY_AN_AD_PAUSE_CAPABLE | PHY_AN_AD_ASYM_PAUSE;
220eef4f27bSRobert Mustacchi         }
221eef4f27bSRobert Mustacchi     }
222eef4f27bSRobert Mustacchi     else if(flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
223eef4f27bSRobert Mustacchi     {
224eef4f27bSRobert Mustacchi         if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_TYPE_FIBER)
225eef4f27bSRobert Mustacchi         {
226eef4f27bSRobert Mustacchi             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
227eef4f27bSRobert Mustacchi             {
228eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_1000X_ASYM_PAUSE;
229eef4f27bSRobert Mustacchi             }
230eef4f27bSRobert Mustacchi             else
231eef4f27bSRobert Mustacchi             {
232eef4f27bSRobert Mustacchi                 val |= MII_ADVERT_ASYM_PAUSE;
233eef4f27bSRobert Mustacchi             }
234eef4f27bSRobert Mustacchi         }
235eef4f27bSRobert Mustacchi         else
236eef4f27bSRobert Mustacchi         {
237eef4f27bSRobert Mustacchi             val |= PHY_AN_AD_ASYM_PAUSE;
238eef4f27bSRobert Mustacchi         }
239eef4f27bSRobert Mustacchi     }
240eef4f27bSRobert Mustacchi     else if(flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE)
241eef4f27bSRobert Mustacchi     {
242eef4f27bSRobert Mustacchi         if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_TYPE_FIBER)
243eef4f27bSRobert Mustacchi         {
244eef4f27bSRobert Mustacchi             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
245eef4f27bSRobert Mustacchi             {
246eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_1000X_PAUSE_CAPABLE |
247eef4f27bSRobert Mustacchi                     PHY_AN_AD_1000X_ASYM_PAUSE;
248eef4f27bSRobert Mustacchi             }
249eef4f27bSRobert Mustacchi             else
250eef4f27bSRobert Mustacchi             {
251eef4f27bSRobert Mustacchi                 val |= MII_ADVERT_PAUSE;
252eef4f27bSRobert Mustacchi             }
253eef4f27bSRobert Mustacchi         }
254eef4f27bSRobert Mustacchi         else
255eef4f27bSRobert Mustacchi         {
256eef4f27bSRobert Mustacchi             val |= PHY_AN_AD_PAUSE_CAPABLE | PHY_AN_AD_ASYM_PAUSE;
257eef4f27bSRobert Mustacchi         }
258eef4f27bSRobert Mustacchi     }
259eef4f27bSRobert Mustacchi 
260eef4f27bSRobert Mustacchi     return val;
261eef4f27bSRobert Mustacchi } /* phy_ad_settings */
262eef4f27bSRobert Mustacchi 
263eef4f27bSRobert Mustacchi 
264eef4f27bSRobert Mustacchi 
265eef4f27bSRobert Mustacchi /*******************************************************************************
266eef4f27bSRobert Mustacchi  * Description:
267eef4f27bSRobert Mustacchi  *
268eef4f27bSRobert Mustacchi  * Return:
269eef4f27bSRobert Mustacchi  ******************************************************************************/
270eef4f27bSRobert Mustacchi STATIC lm_status_t
init_utp(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_ctrl,u32_t selective_autoneg,u32_t wire_speed,u32_t wait_link_timeout_us)271eef4f27bSRobert Mustacchi init_utp(
272eef4f27bSRobert Mustacchi     lm_device_t *pdev,
273eef4f27bSRobert Mustacchi     lm_medium_t req_medium,
274eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl,
275eef4f27bSRobert Mustacchi     u32_t selective_autoneg,
276eef4f27bSRobert Mustacchi     u32_t wire_speed,
277eef4f27bSRobert Mustacchi     u32_t wait_link_timeout_us)
278eef4f27bSRobert Mustacchi {
279eef4f27bSRobert Mustacchi     u32_t restart_autoneg;
280eef4f27bSRobert Mustacchi     lm_status_t lm_status;
281eef4f27bSRobert Mustacchi     lm_medium_t duplex;
282eef4f27bSRobert Mustacchi     lm_medium_t speed;
283eef4f27bSRobert Mustacchi     u32_t val;
284eef4f27bSRobert Mustacchi     u32_t cnt;
285eef4f27bSRobert Mustacchi 
286eef4f27bSRobert Mustacchi     if(GET_MEDIUM_TYPE(req_medium) != LM_MEDIUM_TYPE_UTP)
287eef4f27bSRobert Mustacchi     {
288eef4f27bSRobert Mustacchi         return LM_STATUS_INVALID_PARAMETER;
289eef4f27bSRobert Mustacchi     }
290eef4f27bSRobert Mustacchi 
291eef4f27bSRobert Mustacchi     speed = GET_MEDIUM_SPEED(req_medium);
292eef4f27bSRobert Mustacchi     duplex = GET_MEDIUM_DUPLEX(req_medium);
293eef4f27bSRobert Mustacchi 
294eef4f27bSRobert Mustacchi     lm_status = LM_STATUS_SUCCESS;
295eef4f27bSRobert Mustacchi 
296eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_CTRL_REG, PHY_CTRL_PHY_RESET);
297eef4f27bSRobert Mustacchi     for(cnt = 0; cnt < 1000; cnt++)
298eef4f27bSRobert Mustacchi     {
299eef4f27bSRobert Mustacchi         mm_wait(pdev, 5);
300*55fea89dSDan Cross 
301eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &val);
302eef4f27bSRobert Mustacchi 
303eef4f27bSRobert Mustacchi         if(!(val & PHY_CTRL_PHY_RESET))
304eef4f27bSRobert Mustacchi         {
305eef4f27bSRobert Mustacchi             mm_wait(pdev, 5);
306eef4f27bSRobert Mustacchi 
307eef4f27bSRobert Mustacchi             break;
308eef4f27bSRobert Mustacchi         }
309eef4f27bSRobert Mustacchi     }
310eef4f27bSRobert Mustacchi 
311eef4f27bSRobert Mustacchi     DbgBreakIf(val & PHY_CTRL_PHY_RESET);
312eef4f27bSRobert Mustacchi 
313eef4f27bSRobert Mustacchi     /* Get the PHY id. */
314eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID1_REG, &val);
315eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id = val << 16;
316eef4f27bSRobert Mustacchi     DbgMessage1(pdev, INFORM, "Phy Id1 0x%x\n", val);
317eef4f27bSRobert Mustacchi 
318eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID2_REG, &val);
319eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id |= val & 0xffff;
320eef4f27bSRobert Mustacchi     DbgMessage1(pdev, INFORM, "Phy Id2 0x%x\n", val);
321eef4f27bSRobert Mustacchi 
322eef4f27bSRobert Mustacchi     DbgBreakIf(
323eef4f27bSRobert Mustacchi         (pdev->hw_info.phy_id & 0x0fffffff) == 0x0fffffff ||
324eef4f27bSRobert Mustacchi         pdev->hw_info.phy_id == 0);
325eef4f27bSRobert Mustacchi 
326eef4f27bSRobert Mustacchi     if(CHIP_REV(pdev) == CHIP_REV_FPGA)
327eef4f27bSRobert Mustacchi     {
328eef4f27bSRobert Mustacchi         /* Configure how the MAC obtain link from the external PHY.
329eef4f27bSRobert Mustacchi          * On the FPGA board, LED2 is used as a link signal into the
330eef4f27bSRobert Mustacchi          * MAC.  Configure LED2 to a link event on the AC101L PHY. */
331eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 28, 0x3044);
332eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 29, 0x0100);
333eef4f27bSRobert Mustacchi     }
334eef4f27bSRobert Mustacchi     else
335eef4f27bSRobert Mustacchi     {
336eef4f27bSRobert Mustacchi         if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
337eef4f27bSRobert Mustacchi         {
338eef4f27bSRobert Mustacchi             /* Gen6 PHY core has a slight increase in CRC error.
339eef4f27bSRobert Mustacchi              * This will workaround the problem which will be
340eef4f27bSRobert Mustacchi              * fixed in Gen7 PHY core. */
341eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x0c00);
342eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0x000a);
343eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x15, 0x310b);
344eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0x201f);
345eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x15, 0x9506);
346eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0x401f);
347eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x15, 0x14e2);
348eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x0400);
349eef4f27bSRobert Mustacchi         }
350eef4f27bSRobert Mustacchi 
351eef4f27bSRobert Mustacchi         /* Enable/Disable Ethernet@WireSpeed. */
352eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x7007);
353eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x18, &val);
354*55fea89dSDan Cross 
355eef4f27bSRobert Mustacchi         val &= 0x0ff8;
356eef4f27bSRobert Mustacchi 
357eef4f27bSRobert Mustacchi         if(wire_speed)
358eef4f27bSRobert Mustacchi         {
359eef4f27bSRobert Mustacchi             val |= 0x10;
360eef4f27bSRobert Mustacchi         }
361eef4f27bSRobert Mustacchi         else
362eef4f27bSRobert Mustacchi         {
363eef4f27bSRobert Mustacchi             val &= ~0x10;
364eef4f27bSRobert Mustacchi         }
365eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, val | 0x8000 | 0x7);
366eef4f27bSRobert Mustacchi 
367eef4f27bSRobert Mustacchi         /*
368*55fea89dSDan Cross          * Cont00039501	Issue Description: Auto MDIX mode doesn't work in forced speed
369eef4f27bSRobert Mustacchi          * while two 5716 connected back-to-back
370eef4f27bSRobert Mustacchi          */
371eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x7007);
372eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x18, &val);
373eef4f27bSRobert Mustacchi         val |= BIT_9; /*auto mdix*/
374eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, BCM5401_AUX_CTRL, val | 0x8000 | 0x7);
375*55fea89dSDan Cross 
376eef4f27bSRobert Mustacchi     }
377eef4f27bSRobert Mustacchi 
378eef4f27bSRobert Mustacchi     /* Expansion register 0x8 is the 10BT control register.  BIT 8 of this
379eef4f27bSRobert Mustacchi      * register controls the Early DAC Wakeup Enable.  this bit allows the
380eef4f27bSRobert Mustacchi      * transmitter to be shutdown in 10BT mode except for sending out link
381eef4f27bSRobert Mustacchi      * pulses. This allows for a low power operation in 10BT mode which is
382eef4f27bSRobert Mustacchi      * useful in WOL application.  The default value of this register bit
383eef4f27bSRobert Mustacchi      * gets loaded from a strap value on the GPHY provided by the chip that
384eef4f27bSRobert Mustacchi      * instantiates the PHY.  in Xinan this strap value is 1, meaning that
385eef4f27bSRobert Mustacchi      * the early DAC Wakeup Enable bit is set by default. FW/Driver needs to
386eef4f27bSRobert Mustacchi      * clear this bit when bringing the PHY out of reset. */
387eef4f27bSRobert Mustacchi     if(CHIP_ID(pdev) == CHIP_ID_5709_A0 ||
388eef4f27bSRobert Mustacchi         CHIP_ID(pdev) == CHIP_ID_5709_A1 ||
389eef4f27bSRobert Mustacchi         CHIP_ID(pdev) == CHIP_ID_5709_B0 ||
390eef4f27bSRobert Mustacchi         CHIP_ID(pdev) == CHIP_ID_5709_B1)
391eef4f27bSRobert Mustacchi     {
392eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0xf08);
393eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x15, &val);
394eef4f27bSRobert Mustacchi         val &= ~0x100;
395eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x15, val);
396eef4f27bSRobert Mustacchi     }
397eef4f27bSRobert Mustacchi 
398eef4f27bSRobert Mustacchi     /* Configure the PHY for jumbo frame. */
399eef4f27bSRobert Mustacchi     if(pdev->params.mtu > MAX_ETHERNET_PACKET_SIZE)
400eef4f27bSRobert Mustacchi     {
401eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, 0x0001);
402eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x4400);
403eef4f27bSRobert Mustacchi     }
404eef4f27bSRobert Mustacchi     else
405eef4f27bSRobert Mustacchi     {
406eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, 0x0000);
407eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x0400);
408eef4f27bSRobert Mustacchi     }
409eef4f27bSRobert Mustacchi 
410eef4f27bSRobert Mustacchi     /* Configure line speed. */
411eef4f27bSRobert Mustacchi     restart_autoneg = FALSE;
412eef4f27bSRobert Mustacchi 
413eef4f27bSRobert Mustacchi     switch(speed)
414eef4f27bSRobert Mustacchi     {
415eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_10MBPS:
416eef4f27bSRobert Mustacchi             /* Don't advertise 1000mb.  This register is undefined on a
417eef4f27bSRobert Mustacchi              * 10/100 Mb PHY. */
418*55fea89dSDan Cross             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_1000BASET_CTRL_REG, 0);
419eef4f27bSRobert Mustacchi 
420eef4f27bSRobert Mustacchi             /* Setup AN_AD to advertise 10mb. */
421eef4f27bSRobert Mustacchi             val = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD;
422eef4f27bSRobert Mustacchi             val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
423eef4f27bSRobert Mustacchi 
424eef4f27bSRobert Mustacchi             if(duplex == LM_MEDIUM_FULL_DUPLEX)
425eef4f27bSRobert Mustacchi             {
426eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_10BASET_FULL;
427eef4f27bSRobert Mustacchi 
428eef4f27bSRobert Mustacchi                 if(selective_autoneg == SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
429eef4f27bSRobert Mustacchi                 {
430eef4f27bSRobert Mustacchi                     val |= PHY_AN_AD_10BASET_HALF;
431eef4f27bSRobert Mustacchi                 }
432eef4f27bSRobert Mustacchi             }
433eef4f27bSRobert Mustacchi             else
434eef4f27bSRobert Mustacchi             {
435eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_10BASET_HALF;
436eef4f27bSRobert Mustacchi             }
437eef4f27bSRobert Mustacchi 
438eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, val);
439eef4f27bSRobert Mustacchi 
440eef4f27bSRobert Mustacchi             /* Forcing or advertising 10mb. */
441eef4f27bSRobert Mustacchi             if(selective_autoneg)
442eef4f27bSRobert Mustacchi             {
443eef4f27bSRobert Mustacchi                 restart_autoneg = TRUE;
444eef4f27bSRobert Mustacchi 
445eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "autoneg 10mb hd\n");
446eef4f27bSRobert Mustacchi                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
447eef4f27bSRobert Mustacchi                 {
448eef4f27bSRobert Mustacchi                     DbgMessage(pdev, INFORM, "and 10mb fd\n");
449eef4f27bSRobert Mustacchi                 }
450eef4f27bSRobert Mustacchi             }
451eef4f27bSRobert Mustacchi             else
452eef4f27bSRobert Mustacchi             {
453eef4f27bSRobert Mustacchi                 if(duplex == LM_MEDIUM_HALF_DUPLEX)
454eef4f27bSRobert Mustacchi                 {
455eef4f27bSRobert Mustacchi                     DbgMessage(pdev, INFORM, "force 10mb hd\n");
456eef4f27bSRobert Mustacchi                     (void) lm_mwrite(
457*55fea89dSDan Cross                         pdev,
458eef4f27bSRobert Mustacchi                         pdev->params.phy_addr,
459*55fea89dSDan Cross                         PHY_CTRL_REG,
460eef4f27bSRobert Mustacchi                         PHY_CTRL_SPEED_SELECT_10MBPS);
461eef4f27bSRobert Mustacchi                 }
462eef4f27bSRobert Mustacchi                 else
463eef4f27bSRobert Mustacchi                 {
464eef4f27bSRobert Mustacchi                     DbgMessage(pdev, INFORM, "force 10mb fd\n");
465eef4f27bSRobert Mustacchi                     (void) lm_mwrite(
466*55fea89dSDan Cross                         pdev,
467eef4f27bSRobert Mustacchi                         pdev->params.phy_addr,
468*55fea89dSDan Cross                         PHY_CTRL_REG,
469eef4f27bSRobert Mustacchi                         PHY_CTRL_SPEED_SELECT_10MBPS |
470eef4f27bSRobert Mustacchi                             PHY_CTRL_FULL_DUPLEX_MODE);
471eef4f27bSRobert Mustacchi                 }
472eef4f27bSRobert Mustacchi             }
473eef4f27bSRobert Mustacchi 
474eef4f27bSRobert Mustacchi             break;
475eef4f27bSRobert Mustacchi 
476eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_100MBPS:
477eef4f27bSRobert Mustacchi             /* Don't advertise 1000mb.  This register is undefined on a
478eef4f27bSRobert Mustacchi              * 10/100 PHY. */
479*55fea89dSDan Cross             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_1000BASET_CTRL_REG, 0);
480eef4f27bSRobert Mustacchi 
481eef4f27bSRobert Mustacchi             /* Setup AN_AD to advertise 10/100mb. */
482eef4f27bSRobert Mustacchi             val = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD;
483eef4f27bSRobert Mustacchi             val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
484eef4f27bSRobert Mustacchi 
485eef4f27bSRobert Mustacchi             if(selective_autoneg == SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
486eef4f27bSRobert Mustacchi             {
487eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_10BASET_HALF | PHY_AN_AD_10BASET_FULL;
488eef4f27bSRobert Mustacchi             }
489eef4f27bSRobert Mustacchi 
490eef4f27bSRobert Mustacchi             if(duplex == LM_MEDIUM_FULL_DUPLEX)
491eef4f27bSRobert Mustacchi             {
492eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_100BASETX_FULL;
493eef4f27bSRobert Mustacchi 
494eef4f27bSRobert Mustacchi                 if(selective_autoneg == SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
495eef4f27bSRobert Mustacchi                 {
496eef4f27bSRobert Mustacchi                     val |= PHY_AN_AD_100BASETX_HALF;
497eef4f27bSRobert Mustacchi                 }
498eef4f27bSRobert Mustacchi             }
499eef4f27bSRobert Mustacchi             else
500eef4f27bSRobert Mustacchi             {
501eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_100BASETX_HALF;
502eef4f27bSRobert Mustacchi             }
503eef4f27bSRobert Mustacchi 
504eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, val);
505eef4f27bSRobert Mustacchi 
506eef4f27bSRobert Mustacchi             /* Forcing or advertising 100mb. */
507eef4f27bSRobert Mustacchi             if(selective_autoneg)
508eef4f27bSRobert Mustacchi             {
509eef4f27bSRobert Mustacchi                 restart_autoneg = TRUE;
510eef4f27bSRobert Mustacchi 
511eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "autoneg 10mb and 100mb hd\n");
512eef4f27bSRobert Mustacchi                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
513eef4f27bSRobert Mustacchi                 {
514eef4f27bSRobert Mustacchi                     DbgMessage(pdev, INFORM, "and 100mb fd\n");
515eef4f27bSRobert Mustacchi                 }
516eef4f27bSRobert Mustacchi             }
517eef4f27bSRobert Mustacchi             else
518eef4f27bSRobert Mustacchi             {
519eef4f27bSRobert Mustacchi                 if(duplex == LM_MEDIUM_HALF_DUPLEX)
520eef4f27bSRobert Mustacchi                 {
521eef4f27bSRobert Mustacchi                     DbgMessage(pdev, INFORM, "force 100mb hd\n");
522eef4f27bSRobert Mustacchi                     (void) lm_mwrite(
523*55fea89dSDan Cross                         pdev,
524eef4f27bSRobert Mustacchi                         pdev->params.phy_addr,
525eef4f27bSRobert Mustacchi                         PHY_CTRL_REG,
526eef4f27bSRobert Mustacchi                         PHY_CTRL_SPEED_SELECT_100MBPS);
527eef4f27bSRobert Mustacchi                 }
528eef4f27bSRobert Mustacchi                 else
529eef4f27bSRobert Mustacchi                 {
530eef4f27bSRobert Mustacchi                     DbgMessage(pdev, INFORM, "force 100mb fd\n");
531eef4f27bSRobert Mustacchi                     (void) lm_mwrite(
532*55fea89dSDan Cross                         pdev,
533eef4f27bSRobert Mustacchi                         pdev->params.phy_addr,
534eef4f27bSRobert Mustacchi                         PHY_CTRL_REG,
535eef4f27bSRobert Mustacchi                         PHY_CTRL_SPEED_SELECT_100MBPS |
536eef4f27bSRobert Mustacchi                             PHY_CTRL_FULL_DUPLEX_MODE);
537eef4f27bSRobert Mustacchi                 }
538eef4f27bSRobert Mustacchi             }
539eef4f27bSRobert Mustacchi 
540eef4f27bSRobert Mustacchi             break;
541eef4f27bSRobert Mustacchi 
542eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_1000MBPS:
543eef4f27bSRobert Mustacchi             /* Don't advertise 10/100mb. */
544eef4f27bSRobert Mustacchi             val = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD;
545eef4f27bSRobert Mustacchi             val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
546eef4f27bSRobert Mustacchi 
547eef4f27bSRobert Mustacchi             if(selective_autoneg == SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
548eef4f27bSRobert Mustacchi             {
549eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_10BASET_HALF | PHY_AN_AD_10BASET_FULL;
550eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_100BASETX_HALF | PHY_AN_AD_100BASETX_FULL;
551eef4f27bSRobert Mustacchi             }
552eef4f27bSRobert Mustacchi 
553eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, val);
554eef4f27bSRobert Mustacchi 
555eef4f27bSRobert Mustacchi             /* Setup AN_AD to advertise 1000mb.  This register is defined on
556eef4f27bSRobert Mustacchi              * a 10/100 Mb PHY. */
557eef4f27bSRobert Mustacchi             if(duplex == LM_MEDIUM_FULL_DUPLEX)
558eef4f27bSRobert Mustacchi             {
559eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_1000BASET_FULL;
560eef4f27bSRobert Mustacchi 
561eef4f27bSRobert Mustacchi                 if(selective_autoneg == SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
562eef4f27bSRobert Mustacchi                 {
563eef4f27bSRobert Mustacchi                     val |= PHY_AN_AD_1000BASET_HALF;
564eef4f27bSRobert Mustacchi                 }
565eef4f27bSRobert Mustacchi             }
566eef4f27bSRobert Mustacchi             else
567eef4f27bSRobert Mustacchi             {
568eef4f27bSRobert Mustacchi                 val |= PHY_AN_AD_1000BASET_HALF;
569eef4f27bSRobert Mustacchi             }
570eef4f27bSRobert Mustacchi 
571eef4f27bSRobert Mustacchi             /* Forcing or advertising 1000mb. */
572eef4f27bSRobert Mustacchi             if(selective_autoneg)
573eef4f27bSRobert Mustacchi             {
574eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "autoneg 10/100mb and 1000mb hd\n");
575eef4f27bSRobert Mustacchi                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
576eef4f27bSRobert Mustacchi                 {
577eef4f27bSRobert Mustacchi                     DbgMessage(pdev, INFORM, "and 1000mb fd\n");
578eef4f27bSRobert Mustacchi                 }
579eef4f27bSRobert Mustacchi 
580eef4f27bSRobert Mustacchi                 restart_autoneg = TRUE;
581eef4f27bSRobert Mustacchi             }
582eef4f27bSRobert Mustacchi             else
583eef4f27bSRobert Mustacchi             {
584eef4f27bSRobert Mustacchi                 /* external loopback at 1gb link. */
585eef4f27bSRobert Mustacchi                 (void) lm_mwrite(
586*55fea89dSDan Cross                         pdev,
587*55fea89dSDan Cross                         pdev->params.phy_addr,
588*55fea89dSDan Cross                         PHY_CTRL_REG,
589eef4f27bSRobert Mustacchi                         PHY_CTRL_SPEED_SELECT_1000MBPS);
590eef4f27bSRobert Mustacchi 
591eef4f27bSRobert Mustacchi                 (void) lm_mwrite(pdev, pdev->params.phy_addr, BCM5401_AUX_CTRL, 0x7);
592eef4f27bSRobert Mustacchi                 (void) lm_mread(pdev, pdev->params.phy_addr, BCM5401_AUX_CTRL, &val);
593eef4f27bSRobert Mustacchi                 val |= BCM5401_SHDW_NORMAL_EXTERNAL_LOOPBACK;
594eef4f27bSRobert Mustacchi                 (void) lm_mwrite(pdev, pdev->params.phy_addr, BCM5401_AUX_CTRL, val);
595eef4f27bSRobert Mustacchi 
596eef4f27bSRobert Mustacchi                 val = PHY_CONFIG_AS_MASTER | PHY_ENABLE_CONFIG_AS_MASTER;
597eef4f27bSRobert Mustacchi             }
598eef4f27bSRobert Mustacchi 
599eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_1000BASET_CTRL_REG, val);
600eef4f27bSRobert Mustacchi             break;
601eef4f27bSRobert Mustacchi 
602eef4f27bSRobert Mustacchi         default:
603eef4f27bSRobert Mustacchi             val = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD |
604eef4f27bSRobert Mustacchi                 PHY_AN_AD_10BASET_HALF |
605eef4f27bSRobert Mustacchi                 PHY_AN_AD_10BASET_FULL |
606eef4f27bSRobert Mustacchi                 PHY_AN_AD_100BASETX_FULL |
607eef4f27bSRobert Mustacchi                 PHY_AN_AD_100BASETX_HALF;
608eef4f27bSRobert Mustacchi             val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
609eef4f27bSRobert Mustacchi 
610eef4f27bSRobert Mustacchi             /* Set up the 10/100 advertisement register. */
611eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, val);
612eef4f27bSRobert Mustacchi 
613eef4f27bSRobert Mustacchi             /* Advertise 1000Mbps.  This register is undefined on a
614eef4f27bSRobert Mustacchi              * 10/100 Mb PHY. */
615eef4f27bSRobert Mustacchi             (void) lm_mwrite(
616*55fea89dSDan Cross                 pdev,
617eef4f27bSRobert Mustacchi                 pdev->params.phy_addr,
618eef4f27bSRobert Mustacchi                 PHY_1000BASET_CTRL_REG,
619eef4f27bSRobert Mustacchi                 PHY_AN_AD_1000BASET_HALF |
620eef4f27bSRobert Mustacchi                     PHY_AN_AD_1000BASET_FULL);
621eef4f27bSRobert Mustacchi 
622eef4f27bSRobert Mustacchi             restart_autoneg = TRUE;
623eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_AUTONEG;
624eef4f27bSRobert Mustacchi             break;
625eef4f27bSRobert Mustacchi     }
626eef4f27bSRobert Mustacchi 
627eef4f27bSRobert Mustacchi     /* exit mac loopback.  we could be in mac loopback mode if previously
628eef4f27bSRobert Mustacchi      * the upper module calls lm_init_phy with LM_MEDIUM_TYPE_MAC_LOOPBACK
629eef4f27bSRobert Mustacchi      * medium type for diagnostic. */
630eef4f27bSRobert Mustacchi     REG_RD(pdev, emac.emac_mode, &val);
631eef4f27bSRobert Mustacchi     val &= ~(EMAC_MODE_MAC_LOOP | EMAC_MODE_FORCE_LINK);
632eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_mode, val);
633eef4f27bSRobert Mustacchi 
634eef4f27bSRobert Mustacchi     /* Restart auto-negotation. */
635eef4f27bSRobert Mustacchi     if(restart_autoneg)
636eef4f27bSRobert Mustacchi     {
637eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "phy init - restart autoneg\n");
638eef4f27bSRobert Mustacchi 
639eef4f27bSRobert Mustacchi         (void) lm_mwrite(
640*55fea89dSDan Cross             pdev,
641eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
642eef4f27bSRobert Mustacchi             PHY_CTRL_REG,
643eef4f27bSRobert Mustacchi             PHY_CTRL_AUTO_NEG_ENABLE | PHY_CTRL_RESTART_AUTO_NEG);
644eef4f27bSRobert Mustacchi     }
645eef4f27bSRobert Mustacchi 
646eef4f27bSRobert Mustacchi     /* Save current medium settings. */
647eef4f27bSRobert Mustacchi     SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_UTP);
648eef4f27bSRobert Mustacchi     SET_MEDIUM_SPEED(pdev->vars.medium, speed);
649eef4f27bSRobert Mustacchi     SET_MEDIUM_DUPLEX(pdev->vars.medium, duplex);
650eef4f27bSRobert Mustacchi 
651eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = FALSE;
652eef4f27bSRobert Mustacchi 
653eef4f27bSRobert Mustacchi     /* Wait for link. */
654eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &val);
655eef4f27bSRobert Mustacchi 
656eef4f27bSRobert Mustacchi     if(CHIP_REV(pdev) != CHIP_REV_FPGA)
657eef4f27bSRobert Mustacchi     {
658eef4f27bSRobert Mustacchi         /* Wait for link only if the cable is connected. */
659eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0x7c00);
660eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x1c, &val);
661eef4f27bSRobert Mustacchi         if(val & 0x20)
662eef4f27bSRobert Mustacchi         {
663eef4f27bSRobert Mustacchi             for(; ;)
664eef4f27bSRobert Mustacchi             {
665eef4f27bSRobert Mustacchi                 (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &val);
666eef4f27bSRobert Mustacchi                 if(val & PHY_STATUS_LINK_PASS)
667eef4f27bSRobert Mustacchi                 {
668eef4f27bSRobert Mustacchi                     break;
669eef4f27bSRobert Mustacchi                 }
670eef4f27bSRobert Mustacchi 
671eef4f27bSRobert Mustacchi                 mm_wait(pdev, 10);
672eef4f27bSRobert Mustacchi 
673eef4f27bSRobert Mustacchi                 if(wait_link_timeout_us <= 10)
674eef4f27bSRobert Mustacchi                 {
675eef4f27bSRobert Mustacchi                     break;
676eef4f27bSRobert Mustacchi                 }
677eef4f27bSRobert Mustacchi 
678eef4f27bSRobert Mustacchi                 wait_link_timeout_us -= 10;
679eef4f27bSRobert Mustacchi             }
680eef4f27bSRobert Mustacchi 
681eef4f27bSRobert Mustacchi             pdev->vars.cable_is_attached = TRUE;
682eef4f27bSRobert Mustacchi         }
683eef4f27bSRobert Mustacchi     }
684eef4f27bSRobert Mustacchi 
685eef4f27bSRobert Mustacchi     /* Need to read a second time to get the current link status. */
686eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &val);
687eef4f27bSRobert Mustacchi     if(val & PHY_STATUS_LINK_PASS)
688eef4f27bSRobert Mustacchi     {
689eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
690eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "phy init link up\n");
691eef4f27bSRobert Mustacchi 
692eef4f27bSRobert Mustacchi         pdev->vars.cable_is_attached = TRUE;
693eef4f27bSRobert Mustacchi     }
694eef4f27bSRobert Mustacchi     else
695eef4f27bSRobert Mustacchi     {
696eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_DOWN;
697eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "phy init link down\n");
698eef4f27bSRobert Mustacchi     }
699eef4f27bSRobert Mustacchi 
700eef4f27bSRobert Mustacchi     return lm_status;
701eef4f27bSRobert Mustacchi } /* init_utp */
702eef4f27bSRobert Mustacchi 
703eef4f27bSRobert Mustacchi 
704eef4f27bSRobert Mustacchi 
705eef4f27bSRobert Mustacchi /*******************************************************************************
706eef4f27bSRobert Mustacchi  * Description:
707eef4f27bSRobert Mustacchi  *
708eef4f27bSRobert Mustacchi  * Return:
709eef4f27bSRobert Mustacchi  ******************************************************************************/
710eef4f27bSRobert Mustacchi STATIC u32_t
mii_get_serdes_link_status(lm_device_t * pdev)711eef4f27bSRobert Mustacchi mii_get_serdes_link_status(
712eef4f27bSRobert Mustacchi     lm_device_t *pdev)
713eef4f27bSRobert Mustacchi {
714eef4f27bSRobert Mustacchi     u32_t val;
715eef4f27bSRobert Mustacchi 
716eef4f27bSRobert Mustacchi     /* The link status in the MII status register is not reliable for
717eef4f27bSRobert Mustacchi      * the SERDES part.  We need to get the link info from the MAC. */
718eef4f27bSRobert Mustacchi     if(CHIP_NUM(pdev) == CHIP_NUM_5706 &&
719eef4f27bSRobert Mustacchi         lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
720eef4f27bSRobert Mustacchi     {
721eef4f27bSRobert Mustacchi         REG_RD(pdev, emac.emac_status, &val);
722eef4f27bSRobert Mustacchi         if(val & EMAC_STATUS_LINK)
723eef4f27bSRobert Mustacchi         {
724eef4f27bSRobert Mustacchi             val = PHY_STATUS_LINK_PASS;
725eef4f27bSRobert Mustacchi         }
726eef4f27bSRobert Mustacchi         else
727eef4f27bSRobert Mustacchi         {
728eef4f27bSRobert Mustacchi             val = 0;
729eef4f27bSRobert Mustacchi         }
730eef4f27bSRobert Mustacchi     }
731eef4f27bSRobert Mustacchi     else
732eef4f27bSRobert Mustacchi     {
733eef4f27bSRobert Mustacchi         /* The second read returns the current status. */
734eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &val);
735eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &val);
736eef4f27bSRobert Mustacchi     }
737eef4f27bSRobert Mustacchi 
738eef4f27bSRobert Mustacchi     return val;
739eef4f27bSRobert Mustacchi } /* mii_get_serdes_link_status */
740eef4f27bSRobert Mustacchi 
741eef4f27bSRobert Mustacchi 
742eef4f27bSRobert Mustacchi 
743eef4f27bSRobert Mustacchi /*******************************************************************************
744eef4f27bSRobert Mustacchi  * Description:
745eef4f27bSRobert Mustacchi  *
746eef4f27bSRobert Mustacchi  * Return:
747eef4f27bSRobert Mustacchi  ******************************************************************************/
748eef4f27bSRobert Mustacchi STATIC u8_t
set_5708_serdes_pre_emphasis(lm_device_t * pdev,u32_t pre_emphasis)749eef4f27bSRobert Mustacchi set_5708_serdes_pre_emphasis(
750eef4f27bSRobert Mustacchi     lm_device_t *pdev,
751eef4f27bSRobert Mustacchi     u32_t pre_emphasis)
752eef4f27bSRobert Mustacchi {
753eef4f27bSRobert Mustacchi     u8_t restart_autoneg;
754eef4f27bSRobert Mustacchi     u32_t val;
755eef4f27bSRobert Mustacchi 
756eef4f27bSRobert Mustacchi     restart_autoneg = FALSE;
757eef4f27bSRobert Mustacchi 
758eef4f27bSRobert Mustacchi     if(pre_emphasis == 0)
759eef4f27bSRobert Mustacchi     {
760eef4f27bSRobert Mustacchi         (void) lm_mread(
761*55fea89dSDan Cross             pdev,
762eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
763eef4f27bSRobert Mustacchi             MII_REG(serdes_reg_t, mii_aneg_nxt_pg_rcv2),
764eef4f27bSRobert Mustacchi             &pre_emphasis);
765eef4f27bSRobert Mustacchi         pre_emphasis &= 0xf;
766eef4f27bSRobert Mustacchi 
767eef4f27bSRobert Mustacchi         if(pre_emphasis != pdev->vars.serdes_pre_emphasis)
768eef4f27bSRobert Mustacchi         {
769eef4f27bSRobert Mustacchi             pdev->vars.serdes_pre_emphasis = pre_emphasis;
770eef4f27bSRobert Mustacchi 
771eef4f27bSRobert Mustacchi             restart_autoneg = TRUE;
772eef4f27bSRobert Mustacchi 
773eef4f27bSRobert Mustacchi             /* Switch to Bank 5. */
774eef4f27bSRobert Mustacchi             (void) lm_mwrite(
775*55fea89dSDan Cross                 pdev,
776eef4f27bSRobert Mustacchi                 pdev->params.phy_addr,
777eef4f27bSRobert Mustacchi                 MII_REG(serdes_reg_t, mii_block_addr),
778eef4f27bSRobert Mustacchi                 MII_BLK_ADDR_TXMISC);
779eef4f27bSRobert Mustacchi 
780eef4f27bSRobert Mustacchi             /* Write the new pre-emphasis. */
781eef4f27bSRobert Mustacchi             (void) lm_mread(
782*55fea89dSDan Cross                 pdev,
783eef4f27bSRobert Mustacchi                 pdev->params.phy_addr,
784eef4f27bSRobert Mustacchi                 0x10+MII_REG(serdes_tx_misc_reg_t, mii_txactl3),
785eef4f27bSRobert Mustacchi                 &val);
786eef4f27bSRobert Mustacchi 
787eef4f27bSRobert Mustacchi             pre_emphasis =
788eef4f27bSRobert Mustacchi                 ((pre_emphasis & 0x1) << 15) |
789eef4f27bSRobert Mustacchi                 ((pre_emphasis & 0x2) << 13) |
790eef4f27bSRobert Mustacchi                 ((pre_emphasis & 0x4) << 11) |
791eef4f27bSRobert Mustacchi                 ((pre_emphasis & 0x8) << 9);
792eef4f27bSRobert Mustacchi             val = (val & 0x0fff) | pre_emphasis;
793eef4f27bSRobert Mustacchi 
794eef4f27bSRobert Mustacchi             (void) lm_mwrite(
795*55fea89dSDan Cross                 pdev,
796eef4f27bSRobert Mustacchi                 pdev->params.phy_addr,
797eef4f27bSRobert Mustacchi                 0x10+MII_REG(serdes_tx_misc_reg_t, mii_txactl3),
798eef4f27bSRobert Mustacchi                 val);
799*55fea89dSDan Cross 
800eef4f27bSRobert Mustacchi             /* Select Bank 0. */
801eef4f27bSRobert Mustacchi             (void) lm_mwrite(
802*55fea89dSDan Cross                 pdev,
803eef4f27bSRobert Mustacchi                 pdev->params.phy_addr,
804eef4f27bSRobert Mustacchi                 MII_REG(serdes_reg_t, mii_block_addr),
805eef4f27bSRobert Mustacchi                 MII_BLK_ADDR_DIGITAL);
806eef4f27bSRobert Mustacchi 
807eef4f27bSRobert Mustacchi             /* Restart autoneg. */
808eef4f27bSRobert Mustacchi             (void) lm_mwrite(
809*55fea89dSDan Cross                 pdev,
810eef4f27bSRobert Mustacchi                 pdev->params.phy_addr,
811eef4f27bSRobert Mustacchi                 MII_REG(serdes_reg_t, mii_ctrl),
812eef4f27bSRobert Mustacchi                 MII_CTRL_RESTART_ANEG | MII_CTRL_ANEG_ENA);
813eef4f27bSRobert Mustacchi         }
814eef4f27bSRobert Mustacchi     }
815eef4f27bSRobert Mustacchi     else
816eef4f27bSRobert Mustacchi     {
817eef4f27bSRobert Mustacchi         (void) lm_mwrite(
818*55fea89dSDan Cross             pdev,
819eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
820eef4f27bSRobert Mustacchi             MII_REG(serdes_reg_t, mii_block_addr),
821eef4f27bSRobert Mustacchi             MII_BLK_ADDR_TXMISC);
822eef4f27bSRobert Mustacchi 
823eef4f27bSRobert Mustacchi         (void) lm_mwrite(
824*55fea89dSDan Cross             pdev,
825eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
826eef4f27bSRobert Mustacchi             0x10+MII_REG(serdes_tx_misc_reg_t, mii_txactl3),
827eef4f27bSRobert Mustacchi             pre_emphasis);
828*55fea89dSDan Cross 
829eef4f27bSRobert Mustacchi         (void) lm_mwrite(
830*55fea89dSDan Cross             pdev,
831eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
832eef4f27bSRobert Mustacchi             MII_REG(serdes_reg_t, mii_block_addr),
833eef4f27bSRobert Mustacchi             MII_BLK_ADDR_DIGITAL);
834eef4f27bSRobert Mustacchi     }
835eef4f27bSRobert Mustacchi 
836eef4f27bSRobert Mustacchi     return restart_autoneg;
837eef4f27bSRobert Mustacchi } /* set_5708_serdes_pre_emphasis */
838eef4f27bSRobert Mustacchi 
839eef4f27bSRobert Mustacchi 
840eef4f27bSRobert Mustacchi 
841eef4f27bSRobert Mustacchi /*******************************************************************************
842eef4f27bSRobert Mustacchi  * Description:
843eef4f27bSRobert Mustacchi  *
844eef4f27bSRobert Mustacchi  * Return:
845eef4f27bSRobert Mustacchi  ******************************************************************************/
846eef4f27bSRobert Mustacchi STATIC lm_status_t
init_5708_serdes(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_ctrl,u32_t selective_autoneg,u32_t wait_link_timeout_us)847eef4f27bSRobert Mustacchi init_5708_serdes(
848eef4f27bSRobert Mustacchi     lm_device_t *pdev,
849eef4f27bSRobert Mustacchi     lm_medium_t req_medium,
850eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl,
851eef4f27bSRobert Mustacchi     u32_t selective_autoneg,
852eef4f27bSRobert Mustacchi     u32_t wait_link_timeout_us)
853eef4f27bSRobert Mustacchi {
854eef4f27bSRobert Mustacchi     lm_medium_t duplex;
855eef4f27bSRobert Mustacchi     lm_medium_t speed;
856eef4f27bSRobert Mustacchi     u32_t cnt;
857eef4f27bSRobert Mustacchi     u32_t val;
858eef4f27bSRobert Mustacchi 
859eef4f27bSRobert Mustacchi     if(GET_MEDIUM_SPEED(req_medium) == LM_MEDIUM_SPEED_UNKNOWN)
860eef4f27bSRobert Mustacchi     {
861eef4f27bSRobert Mustacchi         selective_autoneg = FALSE;
862eef4f27bSRobert Mustacchi     }
863eef4f27bSRobert Mustacchi 
864eef4f27bSRobert Mustacchi     speed = GET_MEDIUM_SPEED(req_medium);
865eef4f27bSRobert Mustacchi     duplex = GET_MEDIUM_DUPLEX(req_medium);
866eef4f27bSRobert Mustacchi 
867eef4f27bSRobert Mustacchi     if(speed == LM_MEDIUM_SPEED_HARDWARE_DEFAULT)
868eef4f27bSRobert Mustacchi     {
869eef4f27bSRobert Mustacchi         REG_RD_IND(
870eef4f27bSRobert Mustacchi             pdev,
871eef4f27bSRobert Mustacchi             pdev->hw_info.shmem_base +
872eef4f27bSRobert Mustacchi                 OFFSETOF(shmem_region_t, dev_info.port_hw_config.config),
873eef4f27bSRobert Mustacchi             &val);
874eef4f27bSRobert Mustacchi 
875eef4f27bSRobert Mustacchi         switch(val & PORT_HW_CFG_DEFAULT_LINK_MASK)
876eef4f27bSRobert Mustacchi         {
877eef4f27bSRobert Mustacchi             case PORT_HW_CFG_DEFAULT_LINK_1G:
878eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_1000MBPS;
879eef4f27bSRobert Mustacchi                 break;
880eef4f27bSRobert Mustacchi 
881eef4f27bSRobert Mustacchi             case PORT_HW_CFG_DEFAULT_LINK_2_5G:
882eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_2500MBPS;
883eef4f27bSRobert Mustacchi                 break;
884eef4f27bSRobert Mustacchi 
885eef4f27bSRobert Mustacchi             default:
886eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_UNKNOWN;
887eef4f27bSRobert Mustacchi                 break;
888eef4f27bSRobert Mustacchi         }
889eef4f27bSRobert Mustacchi     }
890eef4f27bSRobert Mustacchi 
891eef4f27bSRobert Mustacchi     /* Reset the SERDES. */
892eef4f27bSRobert Mustacchi     (void) lm_mwrite(
893*55fea89dSDan Cross             pdev,
894*55fea89dSDan Cross             pdev->params.phy_addr,
895*55fea89dSDan Cross             MII_REG(serdes_reg_t, mii_ctrl),
896eef4f27bSRobert Mustacchi             MII_CTRL_RESET);
897eef4f27bSRobert Mustacchi 
898eef4f27bSRobert Mustacchi     for(cnt = 0; cnt < 1000; cnt++)
899eef4f27bSRobert Mustacchi     {
900eef4f27bSRobert Mustacchi         mm_wait(pdev, 5);
901*55fea89dSDan Cross 
902eef4f27bSRobert Mustacchi         (void) lm_mread(
903*55fea89dSDan Cross                 pdev,
904*55fea89dSDan Cross                 pdev->params.phy_addr,
905*55fea89dSDan Cross                 MII_REG(serdes_reg_t, mii_ctrl),
906eef4f27bSRobert Mustacchi                 &val);
907eef4f27bSRobert Mustacchi 
908eef4f27bSRobert Mustacchi         if(!(val & MII_CTRL_RESET))
909eef4f27bSRobert Mustacchi         {
910eef4f27bSRobert Mustacchi             mm_wait(pdev, 5);
911eef4f27bSRobert Mustacchi 
912eef4f27bSRobert Mustacchi             break;
913eef4f27bSRobert Mustacchi         }
914eef4f27bSRobert Mustacchi     }
915eef4f27bSRobert Mustacchi 
916eef4f27bSRobert Mustacchi     DbgBreakIf(val & MII_CTRL_RESET);
917eef4f27bSRobert Mustacchi 
918eef4f27bSRobert Mustacchi     /* Workaround for 5708A0 and B0.
919eef4f27bSRobert Mustacchi      *
920eef4f27bSRobert Mustacchi      * Errata 1.75: Tx peak-to-peak amplitude was measured as low
921eef4f27bSRobert Mustacchi      * as 765mV under full PVT testing, whereas 800mV is considered
922eef4f27bSRobert Mustacchi      * a passing result. */
923eef4f27bSRobert Mustacchi     if(CHIP_NUM(pdev) == CHIP_NUM_5708)
924eef4f27bSRobert Mustacchi     {
925eef4f27bSRobert Mustacchi         /* Switch to Bank 5. */
926eef4f27bSRobert Mustacchi         (void) lm_mwrite(
927*55fea89dSDan Cross             pdev,
928eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
929eef4f27bSRobert Mustacchi             MII_REG(serdes_reg_t, mii_block_addr),
930eef4f27bSRobert Mustacchi             MII_BLK_ADDR_TXMISC);
931eef4f27bSRobert Mustacchi 
932eef4f27bSRobert Mustacchi         (void) lm_mread(
933*55fea89dSDan Cross             pdev,
934eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
935eef4f27bSRobert Mustacchi             0x10+MII_REG(serdes_tx_misc_reg_t, mii_txactl1),
936eef4f27bSRobert Mustacchi             &val);
937eef4f27bSRobert Mustacchi 
938eef4f27bSRobert Mustacchi         val &= ~ MII_TXACTL1_DRIVER_VCM;
939eef4f27bSRobert Mustacchi 
940eef4f27bSRobert Mustacchi         (void) lm_mwrite(
941*55fea89dSDan Cross             pdev,
942eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
943eef4f27bSRobert Mustacchi             0x10+MII_REG(serdes_tx_misc_reg_t, mii_txactl1),
944eef4f27bSRobert Mustacchi             val);
945eef4f27bSRobert Mustacchi     }
946eef4f27bSRobert Mustacchi 
947eef4f27bSRobert Mustacchi     /* Set up pre-emphasis for a backplane application. */
948eef4f27bSRobert Mustacchi     if(pdev->hw_info.nvm_hw_config & SHARED_HW_CFG_BACKPLANE_APP)
949eef4f27bSRobert Mustacchi     {
950eef4f27bSRobert Mustacchi         (void) set_5708_serdes_pre_emphasis(pdev, pdev->params.serdes_pre_emphasis);
951eef4f27bSRobert Mustacchi     }
952eef4f27bSRobert Mustacchi 
953eef4f27bSRobert Mustacchi     /* Reset the pre_emphasis. */
954eef4f27bSRobert Mustacchi     pdev->vars.serdes_pre_emphasis = 0;
955eef4f27bSRobert Mustacchi 
956eef4f27bSRobert Mustacchi     /* Get the PHY id. */
957eef4f27bSRobert Mustacchi     (void) lm_mread(
958*55fea89dSDan Cross             pdev,
959*55fea89dSDan Cross             pdev->params.phy_addr,
960*55fea89dSDan Cross             MII_REG(serdes_reg_t, mii_phy_id_msb),
961eef4f27bSRobert Mustacchi             &val);
962eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id = val << 16;
963eef4f27bSRobert Mustacchi     DbgMessage1(pdev, INFORM, "Phy Id1 0x%x\n", val);
964eef4f27bSRobert Mustacchi 
965eef4f27bSRobert Mustacchi     (void) lm_mread(
966*55fea89dSDan Cross             pdev,
967*55fea89dSDan Cross             pdev->params.phy_addr,
968*55fea89dSDan Cross             MII_REG(serdes_reg_t, mii_phy_id_lsb),
969eef4f27bSRobert Mustacchi             &val);
970eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id |= val & 0xffff;
971eef4f27bSRobert Mustacchi     DbgMessage1(pdev, INFORM, "Phy Id2 0x%x\n", val);
972eef4f27bSRobert Mustacchi 
973eef4f27bSRobert Mustacchi     DbgBreakIf((pdev->hw_info.phy_id & 0x0fffffff) == 0x0fffffff ||
974eef4f27bSRobert Mustacchi         pdev->hw_info.phy_id == 0);
975eef4f27bSRobert Mustacchi 
976eef4f27bSRobert Mustacchi     /* Enable 2.5G register set to be accessible in the IEEE registers. */
977eef4f27bSRobert Mustacchi     (void) lm_mwrite(
978*55fea89dSDan Cross         pdev,
979eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
980eef4f27bSRobert Mustacchi         MII_REG(serdes_reg_t, mii_block_addr),
981eef4f27bSRobert Mustacchi         MII_BLK_ADDR_DIGITAL3);
982eef4f27bSRobert Mustacchi     (void) lm_mwrite(
983*55fea89dSDan Cross         pdev,
984eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
985eef4f27bSRobert Mustacchi         0x10+MII_REG(serdes_digital3_reg_t, mii_digctl_3_0),
986eef4f27bSRobert Mustacchi         MII_DIG3_USE_IEEE);
987eef4f27bSRobert Mustacchi 
988eef4f27bSRobert Mustacchi     /* Switch back to the IEEE Bank. */
989eef4f27bSRobert Mustacchi     (void) lm_mwrite(
990*55fea89dSDan Cross         pdev,
991eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
992eef4f27bSRobert Mustacchi         MII_REG(serdes_reg_t, mii_block_addr),
993eef4f27bSRobert Mustacchi         MII_BLK_ADDR_DIGITAL);
994eef4f27bSRobert Mustacchi 
995eef4f27bSRobert Mustacchi     /* Enable SGMII/Fiber mode autodetection. */
996eef4f27bSRobert Mustacchi     (void) lm_mread(
997*55fea89dSDan Cross         pdev,
998eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
999eef4f27bSRobert Mustacchi         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1000eef4f27bSRobert Mustacchi         &val);
1001eef4f27bSRobert Mustacchi 
1002eef4f27bSRobert Mustacchi     val |= MII_1000X_CTL1_FIBER_MODE | MII_1000X_CTL1_AUTODET_EN;
1003eef4f27bSRobert Mustacchi 
1004eef4f27bSRobert Mustacchi     /* Sigdet is enabled by default.  For backplane application, we need
1005eef4f27bSRobert Mustacchi      * to disable Sigdet by clearing 0*0x10.2 of the Digital Bank. */
1006eef4f27bSRobert Mustacchi     if(pdev->hw_info.nvm_hw_config & SHARED_HW_CFG_BACKPLANE_APP)
1007eef4f27bSRobert Mustacchi     {
1008eef4f27bSRobert Mustacchi         val &= ~MII_1000X_CTL1_SIG_DET_EN;
1009eef4f27bSRobert Mustacchi     }
1010eef4f27bSRobert Mustacchi     else
1011eef4f27bSRobert Mustacchi     {
1012eef4f27bSRobert Mustacchi         val |= MII_1000X_CTL1_SIG_DET_EN;
1013eef4f27bSRobert Mustacchi     }
1014eef4f27bSRobert Mustacchi 
1015eef4f27bSRobert Mustacchi     (void) lm_mwrite(
1016*55fea89dSDan Cross         pdev,
1017eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
1018eef4f27bSRobert Mustacchi         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1019eef4f27bSRobert Mustacchi         val);
1020eef4f27bSRobert Mustacchi 
1021eef4f27bSRobert Mustacchi     /* We should always enable parallel detection. */
1022eef4f27bSRobert Mustacchi     (void) lm_mread(
1023*55fea89dSDan Cross         pdev,
1024eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
1025eef4f27bSRobert Mustacchi         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl2),
1026eef4f27bSRobert Mustacchi         &val);
1027eef4f27bSRobert Mustacchi 
1028eef4f27bSRobert Mustacchi     val |= MII_1000X_CTL2_PAR_DET_EN;
1029eef4f27bSRobert Mustacchi 
1030eef4f27bSRobert Mustacchi     (void) lm_mwrite(
1031*55fea89dSDan Cross         pdev,
1032eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
1033eef4f27bSRobert Mustacchi         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl2),
1034eef4f27bSRobert Mustacchi         val);
1035eef4f27bSRobert Mustacchi 
1036eef4f27bSRobert Mustacchi     /* Enable/disable 2.5G capability. */
1037eef4f27bSRobert Mustacchi     (void) lm_mread(
1038*55fea89dSDan Cross         pdev,
1039eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
1040eef4f27bSRobert Mustacchi         MII_REG(serdes_reg_t, mii_aneg_nxt_pg_xmit1),
1041eef4f27bSRobert Mustacchi         &val);
1042eef4f27bSRobert Mustacchi 
1043eef4f27bSRobert Mustacchi     val &= ~MII_ANEG_NXT_PG_XMIT1_2G5;
1044eef4f27bSRobert Mustacchi 
1045eef4f27bSRobert Mustacchi     if(selective_autoneg)
1046eef4f27bSRobert Mustacchi     {
1047eef4f27bSRobert Mustacchi         if(speed == LM_MEDIUM_SPEED_2500MBPS)
1048eef4f27bSRobert Mustacchi         {
1049eef4f27bSRobert Mustacchi             val |= MII_ANEG_NXT_PG_XMIT1_2G5;
1050eef4f27bSRobert Mustacchi         }
1051eef4f27bSRobert Mustacchi     }
1052eef4f27bSRobert Mustacchi     else if(speed == LM_MEDIUM_SPEED_AUTONEG)
1053eef4f27bSRobert Mustacchi     {
1054eef4f27bSRobert Mustacchi         if(pdev->hw_info.nvm_hw_config & SHARED_HW_CFG_PHY_FIBER_2_5G)
1055eef4f27bSRobert Mustacchi         {
1056eef4f27bSRobert Mustacchi             val |= MII_ANEG_NXT_PG_XMIT1_2G5;
1057eef4f27bSRobert Mustacchi         }
1058eef4f27bSRobert Mustacchi     }
1059eef4f27bSRobert Mustacchi     else if(speed == LM_MEDIUM_SPEED_2500MBPS)
1060eef4f27bSRobert Mustacchi     {
1061eef4f27bSRobert Mustacchi         val |= MII_ANEG_NXT_PG_XMIT1_2G5;
1062eef4f27bSRobert Mustacchi     }
1063eef4f27bSRobert Mustacchi 
1064eef4f27bSRobert Mustacchi     (void) lm_mwrite(
1065*55fea89dSDan Cross         pdev,
1066eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
1067eef4f27bSRobert Mustacchi         MII_REG(serdes_reg_t, mii_aneg_nxt_pg_xmit1),
1068eef4f27bSRobert Mustacchi         val);
1069eef4f27bSRobert Mustacchi 
1070eef4f27bSRobert Mustacchi     val = 0;
1071eef4f27bSRobert Mustacchi 
1072eef4f27bSRobert Mustacchi     if(selective_autoneg || speed == LM_MEDIUM_SPEED_UNKNOWN)
1073eef4f27bSRobert Mustacchi     {
1074eef4f27bSRobert Mustacchi         val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
1075eef4f27bSRobert Mustacchi 
1076eef4f27bSRobert Mustacchi         if((selective_autoneg && speed == LM_MEDIUM_SPEED_1000MBPS) ||
1077eef4f27bSRobert Mustacchi             speed == LM_MEDIUM_SPEED_UNKNOWN)
1078eef4f27bSRobert Mustacchi         {
1079eef4f27bSRobert Mustacchi             val |= MII_ABILITY_HALF | MII_ABILITY_FULL;
1080eef4f27bSRobert Mustacchi         }
1081eef4f27bSRobert Mustacchi 
1082eef4f27bSRobert Mustacchi         (void) lm_mwrite(
1083*55fea89dSDan Cross                 pdev,
1084*55fea89dSDan Cross                 pdev->params.phy_addr,
1085*55fea89dSDan Cross                 MII_REG(serdes_reg_t, mii_aneg_advert),
1086eef4f27bSRobert Mustacchi                 val);
1087eef4f27bSRobert Mustacchi 
1088eef4f27bSRobert Mustacchi         (void) lm_mwrite(
1089*55fea89dSDan Cross             pdev,
1090eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
1091eef4f27bSRobert Mustacchi             MII_REG(serdes_reg_t, mii_ctrl),
1092eef4f27bSRobert Mustacchi             MII_CTRL_RESTART_ANEG | MII_CTRL_ANEG_ENA);
1093eef4f27bSRobert Mustacchi 
1094eef4f27bSRobert Mustacchi         speed = LM_MEDIUM_SPEED_AUTONEG;
1095eef4f27bSRobert Mustacchi     }
1096eef4f27bSRobert Mustacchi     else
1097eef4f27bSRobert Mustacchi     {
1098eef4f27bSRobert Mustacchi         switch(speed)
1099eef4f27bSRobert Mustacchi         {
1100eef4f27bSRobert Mustacchi             case LM_MEDIUM_SPEED_10MBPS:
1101eef4f27bSRobert Mustacchi                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
1102eef4f27bSRobert Mustacchi                 {
1103eef4f27bSRobert Mustacchi                     val |= MII_CTRL_DUPLEX_MODE;
1104eef4f27bSRobert Mustacchi                 }
1105eef4f27bSRobert Mustacchi 
1106eef4f27bSRobert Mustacchi                 (void) lm_mwrite(
1107*55fea89dSDan Cross                         pdev,
1108*55fea89dSDan Cross                         pdev->params.phy_addr,
1109*55fea89dSDan Cross                         MII_REG(serdes_reg_t, mii_ctrl),
1110eef4f27bSRobert Mustacchi                         val);
1111eef4f27bSRobert Mustacchi                 /* Switch to SGMII mode and disable auto-detect */
1112eef4f27bSRobert Mustacchi                 (void) lm_mread(
1113*55fea89dSDan Cross                         pdev,
1114eef4f27bSRobert Mustacchi                         pdev->params.phy_addr,
1115eef4f27bSRobert Mustacchi                         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1116eef4f27bSRobert Mustacchi                         &val);
1117eef4f27bSRobert Mustacchi                 (void) lm_mwrite(
1118*55fea89dSDan Cross                         pdev,
1119eef4f27bSRobert Mustacchi                         pdev->params.phy_addr,
1120eef4f27bSRobert Mustacchi                         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1121eef4f27bSRobert Mustacchi                         val & ~(MII_1000X_CTL1_FIBER_MODE | MII_1000X_CTL1_AUTODET_EN));
1122eef4f27bSRobert Mustacchi                 break;
1123eef4f27bSRobert Mustacchi 
1124eef4f27bSRobert Mustacchi             case LM_MEDIUM_SPEED_100MBPS:
1125eef4f27bSRobert Mustacchi                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
1126eef4f27bSRobert Mustacchi                 {
1127eef4f27bSRobert Mustacchi                     val |= MII_CTRL_DUPLEX_MODE;
1128eef4f27bSRobert Mustacchi                 }
1129eef4f27bSRobert Mustacchi 
1130eef4f27bSRobert Mustacchi                 val |= MII_CTRL_MANUAL_SPD0;
1131eef4f27bSRobert Mustacchi 
1132eef4f27bSRobert Mustacchi                 (void) lm_mwrite(
1133*55fea89dSDan Cross                         pdev,
1134*55fea89dSDan Cross                         pdev->params.phy_addr,
1135*55fea89dSDan Cross                         MII_REG(serdes_reg_t, mii_ctrl),
1136eef4f27bSRobert Mustacchi                         val);
1137eef4f27bSRobert Mustacchi                 /* Switch to SGMII mode and disable auto-detect */
1138eef4f27bSRobert Mustacchi                 (void) lm_mread(
1139*55fea89dSDan Cross                         pdev,
1140eef4f27bSRobert Mustacchi                         pdev->params.phy_addr,
1141eef4f27bSRobert Mustacchi                         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1142eef4f27bSRobert Mustacchi                         &val);
1143eef4f27bSRobert Mustacchi                 (void) lm_mwrite(
1144*55fea89dSDan Cross                         pdev,
1145eef4f27bSRobert Mustacchi                         pdev->params.phy_addr,
1146eef4f27bSRobert Mustacchi                         0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl1),
1147eef4f27bSRobert Mustacchi                         val & ~(MII_1000X_CTL1_FIBER_MODE | MII_1000X_CTL1_AUTODET_EN));
1148eef4f27bSRobert Mustacchi                 break;
1149eef4f27bSRobert Mustacchi 
1150eef4f27bSRobert Mustacchi             case LM_MEDIUM_SPEED_1000MBPS:
1151eef4f27bSRobert Mustacchi                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
1152eef4f27bSRobert Mustacchi                 {
1153eef4f27bSRobert Mustacchi                     val |= MII_CTRL_DUPLEX_MODE;
1154eef4f27bSRobert Mustacchi                 }
1155eef4f27bSRobert Mustacchi 
1156eef4f27bSRobert Mustacchi                 val |= MII_CTRL_MANUAL_SPD1;
1157eef4f27bSRobert Mustacchi 
1158eef4f27bSRobert Mustacchi                 (void) lm_mwrite(
1159*55fea89dSDan Cross                         pdev,
1160*55fea89dSDan Cross                         pdev->params.phy_addr,
1161*55fea89dSDan Cross                         MII_REG(serdes_reg_t, mii_ctrl),
1162eef4f27bSRobert Mustacchi                         val);
1163eef4f27bSRobert Mustacchi                 break;
1164eef4f27bSRobert Mustacchi 
1165eef4f27bSRobert Mustacchi             case LM_MEDIUM_SPEED_2500MBPS:
1166eef4f27bSRobert Mustacchi                 if(duplex == LM_MEDIUM_FULL_DUPLEX)
1167eef4f27bSRobert Mustacchi                 {
1168eef4f27bSRobert Mustacchi                     val |= MII_CTRL_DUPLEX_MODE;
1169eef4f27bSRobert Mustacchi                 }
1170eef4f27bSRobert Mustacchi 
1171eef4f27bSRobert Mustacchi                 val |= MII_CTRL_MANUAL_FORCE_2500;
1172eef4f27bSRobert Mustacchi 
1173eef4f27bSRobert Mustacchi                 (void) lm_mwrite(
1174*55fea89dSDan Cross                         pdev,
1175*55fea89dSDan Cross                         pdev->params.phy_addr,
1176*55fea89dSDan Cross                         MII_REG(serdes_reg_t, mii_ctrl),
1177eef4f27bSRobert Mustacchi                         val);
1178eef4f27bSRobert Mustacchi                 break;
1179eef4f27bSRobert Mustacchi         }
1180eef4f27bSRobert Mustacchi     }
1181eef4f27bSRobert Mustacchi 
1182eef4f27bSRobert Mustacchi     /* exit mac loopback.  we could be in mac loopback mode if previously
1183eef4f27bSRobert Mustacchi      * the upper module calls lm_init_phy with LM_MEDIUM_TYPE_MAC_LOOPBACK
1184eef4f27bSRobert Mustacchi      * medium type for diagnostic. */
1185eef4f27bSRobert Mustacchi     REG_RD(pdev, emac.emac_mode, &val);
1186eef4f27bSRobert Mustacchi     val &= ~(EMAC_MODE_MAC_LOOP | EMAC_MODE_FORCE_LINK);
1187eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_mode, val);
1188eef4f27bSRobert Mustacchi 
1189eef4f27bSRobert Mustacchi     /* Configure the PHY for jumbo frame. */
1190eef4f27bSRobert Mustacchi     if(pdev->params.mtu > MAX_ETHERNET_PACKET_SIZE)
1191eef4f27bSRobert Mustacchi     {
1192eef4f27bSRobert Mustacchi         (void) lm_mwrite(
1193*55fea89dSDan Cross             pdev,
1194eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
1195eef4f27bSRobert Mustacchi             0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl3),
1196eef4f27bSRobert Mustacchi             MII_1000X_CTL3_FIFO_ELAST_10K);
1197eef4f27bSRobert Mustacchi     }
1198eef4f27bSRobert Mustacchi     else
1199eef4f27bSRobert Mustacchi     {
1200eef4f27bSRobert Mustacchi         (void) lm_mwrite(
1201*55fea89dSDan Cross             pdev,
1202eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
1203eef4f27bSRobert Mustacchi             0x10+MII_REG(serdes_digital_reg_t, mii_1000x_ctl3),
1204eef4f27bSRobert Mustacchi             0);
1205eef4f27bSRobert Mustacchi     }
1206eef4f27bSRobert Mustacchi 
1207eef4f27bSRobert Mustacchi     /* Save current medium settings. */
1208eef4f27bSRobert Mustacchi     SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_FIBER);
1209eef4f27bSRobert Mustacchi     SET_MEDIUM_SPEED(pdev->vars.medium, speed);
1210eef4f27bSRobert Mustacchi     SET_MEDIUM_DUPLEX(pdev->vars.medium, duplex);
1211eef4f27bSRobert Mustacchi 
1212eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = FALSE;
1213eef4f27bSRobert Mustacchi 
1214eef4f27bSRobert Mustacchi     /* Wait for link. */
1215eef4f27bSRobert Mustacchi     (void) lm_mread(
1216*55fea89dSDan Cross         pdev,
1217eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
1218eef4f27bSRobert Mustacchi         MII_REG(serdes_reg_t, mii_status),
1219eef4f27bSRobert Mustacchi         &val);
1220eef4f27bSRobert Mustacchi 
1221eef4f27bSRobert Mustacchi     for(; ;)
1222eef4f27bSRobert Mustacchi     {
1223eef4f27bSRobert Mustacchi         (void) lm_mread(
1224*55fea89dSDan Cross             pdev,
1225eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
1226eef4f27bSRobert Mustacchi             MII_REG(serdes_reg_t, mii_status),
1227eef4f27bSRobert Mustacchi             &val);
1228eef4f27bSRobert Mustacchi         if(val & MII_STAT_LINK_STATUS)
1229eef4f27bSRobert Mustacchi         {
1230eef4f27bSRobert Mustacchi             break;
1231eef4f27bSRobert Mustacchi         }
1232eef4f27bSRobert Mustacchi 
1233eef4f27bSRobert Mustacchi         mm_wait(pdev, 10);
1234eef4f27bSRobert Mustacchi 
1235eef4f27bSRobert Mustacchi         if(wait_link_timeout_us <= 10)
1236eef4f27bSRobert Mustacchi         {
1237eef4f27bSRobert Mustacchi             break;
1238eef4f27bSRobert Mustacchi         }
1239eef4f27bSRobert Mustacchi 
1240eef4f27bSRobert Mustacchi         wait_link_timeout_us -= 10;
1241eef4f27bSRobert Mustacchi     }
1242eef4f27bSRobert Mustacchi 
1243eef4f27bSRobert Mustacchi     /* Need to read a second time to get the current link status. */
1244eef4f27bSRobert Mustacchi     (void) lm_mread(
1245*55fea89dSDan Cross         pdev,
1246eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
1247eef4f27bSRobert Mustacchi         MII_REG(serdes_reg_t, mii_status),
1248eef4f27bSRobert Mustacchi         &val);
1249eef4f27bSRobert Mustacchi     if(val & MII_STAT_LINK_STATUS)
1250eef4f27bSRobert Mustacchi     {
1251eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
1252eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "phy init link up\n");
1253eef4f27bSRobert Mustacchi 
1254eef4f27bSRobert Mustacchi         pdev->vars.cable_is_attached = TRUE;
1255eef4f27bSRobert Mustacchi     }
1256eef4f27bSRobert Mustacchi     else
1257eef4f27bSRobert Mustacchi     {
1258eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_DOWN;
1259eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "phy init link down\n");
1260eef4f27bSRobert Mustacchi     }
1261eef4f27bSRobert Mustacchi 
1262eef4f27bSRobert Mustacchi     return LM_STATUS_SUCCESS;
1263eef4f27bSRobert Mustacchi } /* init_5708_serdes */
1264eef4f27bSRobert Mustacchi 
1265eef4f27bSRobert Mustacchi 
1266eef4f27bSRobert Mustacchi 
1267eef4f27bSRobert Mustacchi /*******************************************************************************
1268eef4f27bSRobert Mustacchi  * Description:
1269eef4f27bSRobert Mustacchi  *
1270eef4f27bSRobert Mustacchi  * Return:
1271eef4f27bSRobert Mustacchi  ******************************************************************************/
1272eef4f27bSRobert Mustacchi STATIC void
force_5709_serdes_link(lm_device_t * pdev,lm_medium_t speed,lm_medium_t duplex)1273eef4f27bSRobert Mustacchi force_5709_serdes_link(
1274eef4f27bSRobert Mustacchi     lm_device_t *pdev,
1275eef4f27bSRobert Mustacchi     lm_medium_t speed,
1276eef4f27bSRobert Mustacchi     lm_medium_t duplex)
1277eef4f27bSRobert Mustacchi {
1278eef4f27bSRobert Mustacchi     u32_t val;
1279eef4f27bSRobert Mustacchi 
1280eef4f27bSRobert Mustacchi     /* select serdes digital block. */
1281eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8300);
1282eef4f27bSRobert Mustacchi 
1283eef4f27bSRobert Mustacchi     /* disable sgmii/fiber mode autodetection. */
1284eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1285eef4f27bSRobert Mustacchi     val &= ~0x10;
1286eef4f27bSRobert Mustacchi 
1287eef4f27bSRobert Mustacchi     /* sgmii or 1000x_fiber mode. */
1288eef4f27bSRobert Mustacchi     val &= ~1;
1289eef4f27bSRobert Mustacchi     if(speed == LM_MEDIUM_SPEED_2500MBPS)
1290eef4f27bSRobert Mustacchi     {
1291eef4f27bSRobert Mustacchi         val |= 1;
1292eef4f27bSRobert Mustacchi     }
1293eef4f27bSRobert Mustacchi 
1294eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, val);
1295eef4f27bSRobert Mustacchi 
1296eef4f27bSRobert Mustacchi     /* select combo ieee0 block. */
1297eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1298eef4f27bSRobert Mustacchi 
1299eef4f27bSRobert Mustacchi     /* phy control register. */
1300eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1301eef4f27bSRobert Mustacchi 
1302eef4f27bSRobert Mustacchi     val &= ~0x1000; /* autoneg. */
1303eef4f27bSRobert Mustacchi     val &= ~0x100;  /* duplex. */
1304eef4f27bSRobert Mustacchi     val &= ~0x2060; /* speed. */
1305eef4f27bSRobert Mustacchi 
1306eef4f27bSRobert Mustacchi     if(duplex == LM_MEDIUM_FULL_DUPLEX)
1307eef4f27bSRobert Mustacchi     {
1308eef4f27bSRobert Mustacchi         val |= 0x100;
1309eef4f27bSRobert Mustacchi     }
1310eef4f27bSRobert Mustacchi 
1311eef4f27bSRobert Mustacchi     if(speed == LM_MEDIUM_SPEED_10MBPS)
1312eef4f27bSRobert Mustacchi     {
1313eef4f27bSRobert Mustacchi         /* bit 13 and 6 are already cleared. */
1314eef4f27bSRobert Mustacchi         ;
1315eef4f27bSRobert Mustacchi     }
1316eef4f27bSRobert Mustacchi     else if(speed == LM_MEDIUM_SPEED_100MBPS)
1317eef4f27bSRobert Mustacchi     {
1318eef4f27bSRobert Mustacchi         val |= 0x2000;
1319eef4f27bSRobert Mustacchi     }
1320eef4f27bSRobert Mustacchi     else if(speed == LM_MEDIUM_SPEED_1000MBPS)
1321eef4f27bSRobert Mustacchi     {
1322eef4f27bSRobert Mustacchi         val |= 0x2040;
1323eef4f27bSRobert Mustacchi     }
1324eef4f27bSRobert Mustacchi     else if(speed == LM_MEDIUM_SPEED_2500MBPS)
1325eef4f27bSRobert Mustacchi     {
1326eef4f27bSRobert Mustacchi         val |= 0x20;
1327eef4f27bSRobert Mustacchi     }
1328eef4f27bSRobert Mustacchi     else
1329eef4f27bSRobert Mustacchi     {
1330eef4f27bSRobert Mustacchi         DbgBreakMsg("unknown forced speed.\n");
1331eef4f27bSRobert Mustacchi     }
1332eef4f27bSRobert Mustacchi 
1333eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, val);
1334eef4f27bSRobert Mustacchi 
1335eef4f27bSRobert Mustacchi     /* set speed. */
1336eef4f27bSRobert Mustacchi     if(speed == LM_MEDIUM_SPEED_2500MBPS)
1337eef4f27bSRobert Mustacchi     {
1338eef4f27bSRobert Mustacchi         /* select serdes digital block. */
1339eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8300);
1340eef4f27bSRobert Mustacchi 
1341eef4f27bSRobert Mustacchi         /* set 2.5g speed. */
1342eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x18, &val);
1343eef4f27bSRobert Mustacchi         val &= 0xfff0;
1344eef4f27bSRobert Mustacchi         val |= 0x10;
1345eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, val);
1346eef4f27bSRobert Mustacchi     }
1347eef4f27bSRobert Mustacchi } /* force_5709_serdes_link */
1348eef4f27bSRobert Mustacchi 
1349eef4f27bSRobert Mustacchi 
1350eef4f27bSRobert Mustacchi 
1351eef4f27bSRobert Mustacchi /*******************************************************************************
1352eef4f27bSRobert Mustacchi  * Description:
1353eef4f27bSRobert Mustacchi  *
1354eef4f27bSRobert Mustacchi  * Return:
1355eef4f27bSRobert Mustacchi  ******************************************************************************/
1356eef4f27bSRobert Mustacchi STATIC void
init_5709_serdes_for_autoneg(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_ctrl,u32_t selective_autoneg)1357eef4f27bSRobert Mustacchi init_5709_serdes_for_autoneg(
1358eef4f27bSRobert Mustacchi     lm_device_t *pdev,
1359eef4f27bSRobert Mustacchi     lm_medium_t req_medium,
1360eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl,
1361eef4f27bSRobert Mustacchi     u32_t selective_autoneg)
1362eef4f27bSRobert Mustacchi {
1363eef4f27bSRobert Mustacchi     u32_t val;
1364eef4f27bSRobert Mustacchi 
1365eef4f27bSRobert Mustacchi     if(GET_MEDIUM_SPEED(req_medium) == LM_MEDIUM_SPEED_UNKNOWN)
1366eef4f27bSRobert Mustacchi     {
1367eef4f27bSRobert Mustacchi         selective_autoneg = FALSE;
1368eef4f27bSRobert Mustacchi     }
1369eef4f27bSRobert Mustacchi 
1370eef4f27bSRobert Mustacchi     if(!(pdev->hw_info.nvm_hw_config & SHARED_HW_CFG_PHY_FIBER_2_5G) ||
1371eef4f27bSRobert Mustacchi         (selective_autoneg &&
1372eef4f27bSRobert Mustacchi             GET_MEDIUM_SPEED(req_medium) != LM_MEDIUM_SPEED_2500MBPS))
1373eef4f27bSRobert Mustacchi     {
1374eef4f27bSRobert Mustacchi         /* disable 2.5g adv */
1375eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8320);
1376eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x19, &val);
1377eef4f27bSRobert Mustacchi 	val &= ~1;
1378eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x19, val);
1379eef4f27bSRobert Mustacchi     }
1380eef4f27bSRobert Mustacchi 
1381eef4f27bSRobert Mustacchi     /* select serdes digital block. */
1382eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8300);
1383eef4f27bSRobert Mustacchi 
1384eef4f27bSRobert Mustacchi     /* enable sgmii/fiber mode autodetection. */
1385eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1386eef4f27bSRobert Mustacchi     val |= 0x10;
1387eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, val);
1388eef4f27bSRobert Mustacchi 
1389eef4f27bSRobert Mustacchi     /* disable parallel detection. */
1390eef4f27bSRobert Mustacchi     if(selective_autoneg)
1391eef4f27bSRobert Mustacchi     {
1392eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x11, &val);
1393eef4f27bSRobert Mustacchi         val &= ~0x1;
1394eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x11, val);
1395eef4f27bSRobert Mustacchi     }
1396eef4f27bSRobert Mustacchi 
1397eef4f27bSRobert Mustacchi     /* select bam next page block. */
1398eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8350);
1399*55fea89dSDan Cross 
1400eef4f27bSRobert Mustacchi     /* mp5_next_page_control. */
1401eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1402eef4f27bSRobert Mustacchi     val &= ~3;
1403eef4f27bSRobert Mustacchi     val |= 1;   /* set bam mode. */
1404eef4f27bSRobert Mustacchi     val |= 2;   /* enable t2 mode. */
1405eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, val);
1406eef4f27bSRobert Mustacchi 
1407eef4f27bSRobert Mustacchi     /* select cl73_userb0 block. */
1408eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8370);
1409eef4f27bSRobert Mustacchi 
1410eef4f27bSRobert Mustacchi     /* enable bam_en, bam_station_mngr_en, bam_np_after_bp_en. */
1411eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x12, 0xe000);
1412eef4f27bSRobert Mustacchi 
1413eef4f27bSRobert Mustacchi     /* select ieee1 block. */
1414eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x10);
1415eef4f27bSRobert Mustacchi 
1416eef4f27bSRobert Mustacchi     /* advertise 1000kx. */
1417eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x1, &val);
1418eef4f27bSRobert Mustacchi     val |= 0x20;
1419eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1, val);
1420eef4f27bSRobert Mustacchi 
1421eef4f27bSRobert Mustacchi     /* select ieee0 block. */
1422eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0);
1423eef4f27bSRobert Mustacchi 
1424eef4f27bSRobert Mustacchi     /* enable cl73 aneg. */
1425eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x0, &val);
1426eef4f27bSRobert Mustacchi     val |= 0x1200;
1427eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x0, val);
1428eef4f27bSRobert Mustacchi 
1429eef4f27bSRobert Mustacchi     /* select combo ieee0 block. */
1430eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1431eef4f27bSRobert Mustacchi 
1432eef4f27bSRobert Mustacchi     /* advertise pause capability and duplex mode. */
1433eef4f27bSRobert Mustacchi     val = phy_ad_settings(pdev, req_medium, flow_ctrl);
1434eef4f27bSRobert Mustacchi     if(selective_autoneg &&
1435eef4f27bSRobert Mustacchi         GET_MEDIUM_SPEED(req_medium) == LM_MEDIUM_SPEED_2500MBPS)
1436eef4f27bSRobert Mustacchi     {
1437eef4f27bSRobert Mustacchi         val &= ~0x60;
1438eef4f27bSRobert Mustacchi     }
1439eef4f27bSRobert Mustacchi     else
1440eef4f27bSRobert Mustacchi     {
1441eef4f27bSRobert Mustacchi         val |= 0x60;    /* half/full duplex. */
1442eef4f27bSRobert Mustacchi     }
1443eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x14, val);
1444eef4f27bSRobert Mustacchi 
1445eef4f27bSRobert Mustacchi     /* autoneg_enable and restart. */
1446eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1447*55fea89dSDan Cross     val |= 0x1200;
1448eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, val);
1449eef4f27bSRobert Mustacchi } /* init_5709_serdes_for_autoneg */
1450eef4f27bSRobert Mustacchi 
1451eef4f27bSRobert Mustacchi 
1452eef4f27bSRobert Mustacchi 
1453eef4f27bSRobert Mustacchi /*******************************************************************************
1454eef4f27bSRobert Mustacchi  * Description:
1455eef4f27bSRobert Mustacchi  *
1456eef4f27bSRobert Mustacchi  * Return:
1457eef4f27bSRobert Mustacchi  ******************************************************************************/
1458eef4f27bSRobert Mustacchi STATIC lm_status_t
init_5709_serdes(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_ctrl,u32_t selective_autoneg,u32_t wait_link_timeout_us)1459eef4f27bSRobert Mustacchi init_5709_serdes(
1460eef4f27bSRobert Mustacchi     lm_device_t *pdev,
1461eef4f27bSRobert Mustacchi     lm_medium_t req_medium,
1462eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl,
1463eef4f27bSRobert Mustacchi     u32_t selective_autoneg,
1464eef4f27bSRobert Mustacchi     u32_t wait_link_timeout_us)
1465eef4f27bSRobert Mustacchi {
1466eef4f27bSRobert Mustacchi     lm_medium_t duplex;
1467eef4f27bSRobert Mustacchi     lm_medium_t speed;
1468eef4f27bSRobert Mustacchi     u32_t idx;
1469eef4f27bSRobert Mustacchi     u32_t val;
1470eef4f27bSRobert Mustacchi 
1471eef4f27bSRobert Mustacchi     speed = GET_MEDIUM_SPEED(req_medium);
1472eef4f27bSRobert Mustacchi     duplex = GET_MEDIUM_DUPLEX(req_medium);
1473eef4f27bSRobert Mustacchi 
1474eef4f27bSRobert Mustacchi     /* use nvram link speed configuration. */
1475eef4f27bSRobert Mustacchi     if(speed == LM_MEDIUM_SPEED_HARDWARE_DEFAULT)
1476eef4f27bSRobert Mustacchi     {
1477eef4f27bSRobert Mustacchi         REG_RD_IND(
1478eef4f27bSRobert Mustacchi             pdev,
1479eef4f27bSRobert Mustacchi             pdev->hw_info.shmem_base +
1480eef4f27bSRobert Mustacchi                 OFFSETOF(shmem_region_t, dev_info.port_hw_config.config),
1481eef4f27bSRobert Mustacchi             &val);
1482eef4f27bSRobert Mustacchi 
1483eef4f27bSRobert Mustacchi         switch(val & PORT_HW_CFG_DEFAULT_LINK_MASK)
1484eef4f27bSRobert Mustacchi         {
1485eef4f27bSRobert Mustacchi             case PORT_HW_CFG_DEFAULT_LINK_1G:
1486eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_1000MBPS;
1487eef4f27bSRobert Mustacchi                 break;
1488eef4f27bSRobert Mustacchi 
1489eef4f27bSRobert Mustacchi             case PORT_HW_CFG_DEFAULT_LINK_2_5G:
1490eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_2500MBPS;
1491eef4f27bSRobert Mustacchi                 break;
1492eef4f27bSRobert Mustacchi 
1493eef4f27bSRobert Mustacchi             default:
1494eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_UNKNOWN;
1495eef4f27bSRobert Mustacchi                 break;
1496eef4f27bSRobert Mustacchi         }
1497eef4f27bSRobert Mustacchi 
1498eef4f27bSRobert Mustacchi         selective_autoneg = FALSE;
1499eef4f27bSRobert Mustacchi     }
1500eef4f27bSRobert Mustacchi 
1501eef4f27bSRobert Mustacchi     /* set an_mmd.  an_mmd is the only register set we need for
1502eef4f27bSRobert Mustacchi      * programming xinan serdes.  all other registers are can
1503eef4f27bSRobert Mustacchi      * be access through an_mmd. */
1504eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffd0);
1505eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1e, 0x3800);
1506eef4f27bSRobert Mustacchi 
1507eef4f27bSRobert Mustacchi     /* select combo_ieee0 block. */
1508eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1509eef4f27bSRobert Mustacchi 
1510eef4f27bSRobert Mustacchi     /* reset. */
1511eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, MII_CTRL_RESET);
1512eef4f27bSRobert Mustacchi     for(idx = 0; idx < 1000; idx++)
1513eef4f27bSRobert Mustacchi     {
1514eef4f27bSRobert Mustacchi         mm_wait(pdev, 5);
1515*55fea89dSDan Cross 
1516eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1517eef4f27bSRobert Mustacchi         if(!(val & MII_CTRL_RESET))
1518eef4f27bSRobert Mustacchi         {
1519eef4f27bSRobert Mustacchi             mm_wait(pdev, 5);
1520eef4f27bSRobert Mustacchi             break;
1521eef4f27bSRobert Mustacchi         }
1522eef4f27bSRobert Mustacchi     }
1523eef4f27bSRobert Mustacchi     DbgBreakIf(val & MII_CTRL_RESET);
1524eef4f27bSRobert Mustacchi 
1525eef4f27bSRobert Mustacchi     /* get phy id. */
1526eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x12, &val);
1527eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id = val << 16;
1528eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x13, &val);
1529eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id |= val & 0xffff;
1530eef4f27bSRobert Mustacchi 
1531eef4f27bSRobert Mustacchi     if(speed == LM_MEDIUM_SPEED_AUTONEG_1G_FALLBACK)
1532eef4f27bSRobert Mustacchi     {
1533eef4f27bSRobert Mustacchi         speed = LM_MEDIUM_SPEED_AUTONEG;
1534eef4f27bSRobert Mustacchi     }
1535eef4f27bSRobert Mustacchi 
1536eef4f27bSRobert Mustacchi     /* config link speed or autoneg setting. */
1537eef4f27bSRobert Mustacchi     if(speed == LM_MEDIUM_SPEED_AUTONEG || selective_autoneg)
1538eef4f27bSRobert Mustacchi     {
1539eef4f27bSRobert Mustacchi         init_5709_serdes_for_autoneg(
1540eef4f27bSRobert Mustacchi             pdev,
1541eef4f27bSRobert Mustacchi             req_medium,
1542eef4f27bSRobert Mustacchi             flow_ctrl,
1543eef4f27bSRobert Mustacchi             selective_autoneg);
1544eef4f27bSRobert Mustacchi     }
1545eef4f27bSRobert Mustacchi     else
1546eef4f27bSRobert Mustacchi     {
1547eef4f27bSRobert Mustacchi         force_5709_serdes_link(pdev, speed, duplex);
1548eef4f27bSRobert Mustacchi     }
1549eef4f27bSRobert Mustacchi 
1550eef4f27bSRobert Mustacchi     /* exit mac loopback.  we could be in mac loopback mode if previously
1551eef4f27bSRobert Mustacchi      * the upper module calls lm_init_phy with LM_MEDIUM_TYPE_MAC_LOOPBACK
1552eef4f27bSRobert Mustacchi      * medium type for diagnostic. */
1553eef4f27bSRobert Mustacchi     REG_RD(pdev, emac.emac_mode, &val);
1554eef4f27bSRobert Mustacchi     val &= ~(EMAC_MODE_MAC_LOOP | EMAC_MODE_FORCE_LINK);
1555eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_mode, val);
1556eef4f27bSRobert Mustacchi 
1557eef4f27bSRobert Mustacchi     SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_FIBER);
1558eef4f27bSRobert Mustacchi     SET_MEDIUM_SPEED(pdev->vars.medium, speed);
1559eef4f27bSRobert Mustacchi     SET_MEDIUM_DUPLEX(pdev->vars.medium, duplex);
1560eef4f27bSRobert Mustacchi 
1561eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = FALSE;
1562eef4f27bSRobert Mustacchi 
1563eef4f27bSRobert Mustacchi     /* select combo_ieee0 block. */
1564eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1565eef4f27bSRobert Mustacchi 
1566eef4f27bSRobert Mustacchi     /* wait for link. */
1567eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x11, &val);
1568eef4f27bSRobert Mustacchi 
1569eef4f27bSRobert Mustacchi     for(; ;)
1570eef4f27bSRobert Mustacchi     {
1571eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x11, &val);
1572eef4f27bSRobert Mustacchi         if(val & 0x4)
1573eef4f27bSRobert Mustacchi         {
1574eef4f27bSRobert Mustacchi             break;
1575eef4f27bSRobert Mustacchi         }
1576eef4f27bSRobert Mustacchi 
1577eef4f27bSRobert Mustacchi         mm_wait(pdev, 10);
1578eef4f27bSRobert Mustacchi 
1579eef4f27bSRobert Mustacchi         if(wait_link_timeout_us <= 10)
1580eef4f27bSRobert Mustacchi         {
1581eef4f27bSRobert Mustacchi             break;
1582eef4f27bSRobert Mustacchi         }
1583eef4f27bSRobert Mustacchi 
1584eef4f27bSRobert Mustacchi         wait_link_timeout_us -= 10;
1585eef4f27bSRobert Mustacchi     }
1586eef4f27bSRobert Mustacchi 
1587eef4f27bSRobert Mustacchi     /* need to read a second time to get the current link status. */
1588eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x11, &val);
1589eef4f27bSRobert Mustacchi 
1590eef4f27bSRobert Mustacchi     if(val & MII_STAT_LINK_STATUS)
1591eef4f27bSRobert Mustacchi     {
1592eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
1593eef4f27bSRobert Mustacchi         pdev->vars.cable_is_attached = TRUE;
1594eef4f27bSRobert Mustacchi     }
1595eef4f27bSRobert Mustacchi     else
1596eef4f27bSRobert Mustacchi     {
1597eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_DOWN;
1598eef4f27bSRobert Mustacchi     }
1599eef4f27bSRobert Mustacchi 
1600eef4f27bSRobert Mustacchi     return LM_STATUS_SUCCESS;
1601eef4f27bSRobert Mustacchi } /* init_5709_serdes */
1602eef4f27bSRobert Mustacchi 
1603eef4f27bSRobert Mustacchi 
1604eef4f27bSRobert Mustacchi 
1605eef4f27bSRobert Mustacchi /*******************************************************************************
1606eef4f27bSRobert Mustacchi  * Description:
1607eef4f27bSRobert Mustacchi  *
1608eef4f27bSRobert Mustacchi  * Return:
1609eef4f27bSRobert Mustacchi  ******************************************************************************/
1610eef4f27bSRobert Mustacchi STATIC lm_status_t
init_5706_serdes(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_ctrl,u32_t wait_link_timeout_us)1611eef4f27bSRobert Mustacchi init_5706_serdes(
1612eef4f27bSRobert Mustacchi     lm_device_t *pdev,
1613eef4f27bSRobert Mustacchi     lm_medium_t req_medium,
1614eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl,
1615eef4f27bSRobert Mustacchi     u32_t wait_link_timeout_us)
1616eef4f27bSRobert Mustacchi {
1617eef4f27bSRobert Mustacchi     lm_medium_t duplex;
1618eef4f27bSRobert Mustacchi     lm_medium_t speed;
1619eef4f27bSRobert Mustacchi     u32_t val;
1620eef4f27bSRobert Mustacchi     u32_t cnt;
1621eef4f27bSRobert Mustacchi 
1622eef4f27bSRobert Mustacchi     speed = GET_MEDIUM_SPEED(req_medium);
1623eef4f27bSRobert Mustacchi     duplex = GET_MEDIUM_DUPLEX(req_medium);
1624eef4f27bSRobert Mustacchi 
1625eef4f27bSRobert Mustacchi     if(speed == LM_MEDIUM_SPEED_HARDWARE_DEFAULT)
1626eef4f27bSRobert Mustacchi     {
1627eef4f27bSRobert Mustacchi         REG_RD_IND(
1628eef4f27bSRobert Mustacchi             pdev,
1629eef4f27bSRobert Mustacchi             pdev->hw_info.shmem_base +
1630eef4f27bSRobert Mustacchi                 OFFSETOF(shmem_region_t, dev_info.port_hw_config.config),
1631eef4f27bSRobert Mustacchi             &val);
1632eef4f27bSRobert Mustacchi         switch(val & PORT_HW_CFG_DEFAULT_LINK_MASK)
1633eef4f27bSRobert Mustacchi         {
1634eef4f27bSRobert Mustacchi             case PORT_HW_CFG_DEFAULT_LINK_1G:
1635eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_1000MBPS;
1636eef4f27bSRobert Mustacchi                 break;
1637eef4f27bSRobert Mustacchi 
1638eef4f27bSRobert Mustacchi             case PORT_HW_CFG_DEFAULT_LINK_2_5G:
1639eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_2500MBPS;
1640eef4f27bSRobert Mustacchi                 break;
1641eef4f27bSRobert Mustacchi 
1642eef4f27bSRobert Mustacchi             case PORT_HW_CFG_DEFAULT_LINK_AN_1G_FALLBACK:
1643eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_AUTONEG_1G_FALLBACK;
1644eef4f27bSRobert Mustacchi                 break;
1645eef4f27bSRobert Mustacchi 
1646eef4f27bSRobert Mustacchi             case PORT_HW_CFG_DEFAULT_LINK_AN_2_5G_FALLBACK:
1647eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_AUTONEG_2_5G_FALLBACK;
1648eef4f27bSRobert Mustacchi                 break;
1649eef4f27bSRobert Mustacchi 
1650eef4f27bSRobert Mustacchi             default:
1651eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_UNKNOWN;
1652eef4f27bSRobert Mustacchi         }
1653eef4f27bSRobert Mustacchi     }
1654eef4f27bSRobert Mustacchi 
1655eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_CTRL_REG, PHY_CTRL_PHY_RESET);
1656eef4f27bSRobert Mustacchi     for(cnt = 0; cnt < 1000; cnt++)
1657eef4f27bSRobert Mustacchi     {
1658eef4f27bSRobert Mustacchi         mm_wait(pdev, 5);
1659*55fea89dSDan Cross 
1660eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &val);
1661eef4f27bSRobert Mustacchi 
1662eef4f27bSRobert Mustacchi         if(!(val & PHY_CTRL_PHY_RESET))
1663eef4f27bSRobert Mustacchi         {
1664eef4f27bSRobert Mustacchi             mm_wait(pdev, 5);
1665eef4f27bSRobert Mustacchi 
1666eef4f27bSRobert Mustacchi             break;
1667eef4f27bSRobert Mustacchi         }
1668eef4f27bSRobert Mustacchi     }
1669eef4f27bSRobert Mustacchi 
1670eef4f27bSRobert Mustacchi     DbgBreakIf(val & PHY_CTRL_PHY_RESET);
1671eef4f27bSRobert Mustacchi 
1672eef4f27bSRobert Mustacchi     /* Get the PHY id. */
1673eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID1_REG, &val);
1674eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id = val << 16;
1675eef4f27bSRobert Mustacchi     DbgMessage1(pdev, INFORM, "Phy Id1 0x%x\n", val);
1676eef4f27bSRobert Mustacchi 
1677eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID2_REG, &val);
1678eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id |= val & 0xffff;
1679eef4f27bSRobert Mustacchi     DbgMessage1(pdev, INFORM, "Phy Id2 0x%x\n", val);
1680eef4f27bSRobert Mustacchi 
1681eef4f27bSRobert Mustacchi     DbgBreakIf((pdev->hw_info.phy_id & 0x0fffffff) == 0x0fffffff ||
1682eef4f27bSRobert Mustacchi         pdev->hw_info.phy_id == 0);
1683eef4f27bSRobert Mustacchi 
1684eef4f27bSRobert Mustacchi     /* The 5706S has problem determining link so getting link from
1685eef4f27bSRobert Mustacchi      * the MII status register is not reliable.  This will force
1686eef4f27bSRobert Mustacchi      * the MAC to qualify the link ready signal with signal detect.
1687eef4f27bSRobert Mustacchi      * We will need to get the link status from the MAC instead of
1688eef4f27bSRobert Mustacchi      * the SERDES (MII status register). */
1689eef4f27bSRobert Mustacchi     if(CHIP_NUM(pdev) == CHIP_NUM_5706 &&
1690eef4f27bSRobert Mustacchi         lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
1691eef4f27bSRobert Mustacchi     {
1692*55fea89dSDan Cross         REG_WR(pdev, misc.misc_gp_hw_ctl0,
1693eef4f27bSRobert Mustacchi                 MISC_GP_HW_CTL0_ENA_SEL_VAUX_B_IN_L2_TE |
1694eef4f27bSRobert Mustacchi                 MISC_GP_HW_CTL0_GRC_BNK_FREE_FIX_TE);
1695eef4f27bSRobert Mustacchi     }
1696eef4f27bSRobert Mustacchi 
1697eef4f27bSRobert Mustacchi     /* Setup flow control capabilities advertisement. */
1698eef4f27bSRobert Mustacchi     val = PHY_AN_AD_1000X_HALF_DUPLEX;
1699eef4f27bSRobert Mustacchi     if(duplex == LM_MEDIUM_FULL_DUPLEX)
1700eef4f27bSRobert Mustacchi     {
1701eef4f27bSRobert Mustacchi         val |= PHY_AN_AD_1000X_FULL_DUPLEX;
1702eef4f27bSRobert Mustacchi     }
1703eef4f27bSRobert Mustacchi     val |= phy_ad_settings(pdev, req_medium, flow_ctrl);
1704eef4f27bSRobert Mustacchi 
1705eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, val);
1706eef4f27bSRobert Mustacchi 
1707eef4f27bSRobert Mustacchi     /* Determine the fallback selection. */
1708eef4f27bSRobert Mustacchi     switch(speed)
1709eef4f27bSRobert Mustacchi     {
1710eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_AUTONEG_1G_FALLBACK:
1711eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "enable serdes_fallback_1g\n");
1712eef4f27bSRobert Mustacchi             pdev->vars.serdes_fallback_select = SERDES_FALLBACK_1G;
1713eef4f27bSRobert Mustacchi             break;
1714eef4f27bSRobert Mustacchi 
1715eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_AUTONEG_2_5G_FALLBACK:
1716eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "enable serdes_fallback_2.5g\n");
1717eef4f27bSRobert Mustacchi             pdev->vars.serdes_fallback_select = SERDES_FALLBACK_2_5G;
1718eef4f27bSRobert Mustacchi             break;
1719eef4f27bSRobert Mustacchi 
1720eef4f27bSRobert Mustacchi         default:
1721eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "disable serdes_fallback.\n");
1722eef4f27bSRobert Mustacchi             pdev->vars.serdes_fallback_select = SERDES_FALLBACK_NONE;
1723eef4f27bSRobert Mustacchi             pdev->vars.serdes_fallback_status = SERDES_FALLBACK_NONE;
1724eef4f27bSRobert Mustacchi             break;
1725eef4f27bSRobert Mustacchi     }
1726eef4f27bSRobert Mustacchi 
1727eef4f27bSRobert Mustacchi     /* This routine could be called anytime.  So if has not gone down
1728eef4f27bSRobert Mustacchi      * yet, we want to perserve the fallback setting. */
1729eef4f27bSRobert Mustacchi     if(pdev->vars.serdes_fallback_select != SERDES_FALLBACK_NONE)
1730eef4f27bSRobert Mustacchi     {
1731eef4f27bSRobert Mustacchi         speed = LM_MEDIUM_SPEED_AUTONEG;
1732eef4f27bSRobert Mustacchi 
1733eef4f27bSRobert Mustacchi         if(pdev->vars.link_status == LM_STATUS_LINK_ACTIVE)
1734eef4f27bSRobert Mustacchi         {
1735eef4f27bSRobert Mustacchi             if(pdev->vars.serdes_fallback_status == SERDES_FALLBACK_1G)
1736eef4f27bSRobert Mustacchi             {
1737eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_1000MBPS;
1738eef4f27bSRobert Mustacchi             }
1739eef4f27bSRobert Mustacchi             else if(pdev->vars.serdes_fallback_status == SERDES_FALLBACK_2_5G)
1740eef4f27bSRobert Mustacchi             {
1741eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_2500MBPS;
1742eef4f27bSRobert Mustacchi             }
1743eef4f27bSRobert Mustacchi         }
1744eef4f27bSRobert Mustacchi     }
1745eef4f27bSRobert Mustacchi 
1746eef4f27bSRobert Mustacchi     if(speed == LM_MEDIUM_SPEED_1000MBPS)
1747eef4f27bSRobert Mustacchi     {
1748eef4f27bSRobert Mustacchi         val = PHY_CTRL_SPEED_SELECT_1000MBPS;
1749eef4f27bSRobert Mustacchi         if(duplex == LM_MEDIUM_FULL_DUPLEX)
1750eef4f27bSRobert Mustacchi         {
1751eef4f27bSRobert Mustacchi             val |= PHY_CTRL_FULL_DUPLEX_MODE;
1752eef4f27bSRobert Mustacchi         }
1753eef4f27bSRobert Mustacchi 
1754eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_CTRL_REG, val);
1755eef4f27bSRobert Mustacchi     }
1756eef4f27bSRobert Mustacchi     else
1757eef4f27bSRobert Mustacchi     {
1758eef4f27bSRobert Mustacchi         val = PHY_CTRL_AUTO_NEG_ENABLE | PHY_CTRL_RESTART_AUTO_NEG;
1759eef4f27bSRobert Mustacchi 
1760eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, PHY_CTRL_REG, val);
1761eef4f27bSRobert Mustacchi 
1762eef4f27bSRobert Mustacchi         speed = LM_MEDIUM_SPEED_AUTONEG;
1763eef4f27bSRobert Mustacchi     }
1764eef4f27bSRobert Mustacchi 
1765eef4f27bSRobert Mustacchi     /* exit mac loopback.  we could be in mac loopback mode if previously
1766eef4f27bSRobert Mustacchi      * the upper module calls lm_init_phy with LM_MEDIUM_TYPE_MAC_LOOPBACK
1767eef4f27bSRobert Mustacchi      * medium type for diagnostic. */
1768eef4f27bSRobert Mustacchi     REG_RD(pdev, emac.emac_mode, &val);
1769eef4f27bSRobert Mustacchi     val &= ~(EMAC_MODE_MAC_LOOP | EMAC_MODE_FORCE_LINK);
1770eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_mode, val);
1771eef4f27bSRobert Mustacchi 
1772eef4f27bSRobert Mustacchi     /* Configure the PHY for jumbo frame. */
1773eef4f27bSRobert Mustacchi     if(pdev->params.mtu > MAX_ETHERNET_PACKET_SIZE)
1774eef4f27bSRobert Mustacchi     {
1775eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x4400);
1776eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0xec87);
1777eef4f27bSRobert Mustacchi     }
1778eef4f27bSRobert Mustacchi     else
1779eef4f27bSRobert Mustacchi     {
1780eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x18, 0x0400);
1781eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0xec85);
1782eef4f27bSRobert Mustacchi     }
1783eef4f27bSRobert Mustacchi 
1784eef4f27bSRobert Mustacchi     SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_FIBER);
1785eef4f27bSRobert Mustacchi     SET_MEDIUM_SPEED(pdev->vars.medium, speed);
1786eef4f27bSRobert Mustacchi     SET_MEDIUM_DUPLEX(pdev->vars.medium, duplex);
1787eef4f27bSRobert Mustacchi 
1788eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = FALSE;
1789eef4f27bSRobert Mustacchi 
1790eef4f27bSRobert Mustacchi     /* Clear the latch bits.  The second read below will get the
1791eef4f27bSRobert Mustacchi      * current status. */
1792eef4f27bSRobert Mustacchi     val = mii_get_serdes_link_status(pdev);
1793eef4f27bSRobert Mustacchi 
1794eef4f27bSRobert Mustacchi     /* Wait for link only if the cable is connected. */
1795eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0x7c00);
1796eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x1c, &val);
1797eef4f27bSRobert Mustacchi     if(val & 0x10)
1798eef4f27bSRobert Mustacchi     {
1799eef4f27bSRobert Mustacchi         for(; ;)
1800eef4f27bSRobert Mustacchi         {
1801eef4f27bSRobert Mustacchi             val = mii_get_serdes_link_status(pdev);
1802eef4f27bSRobert Mustacchi 
1803eef4f27bSRobert Mustacchi             if(val & PHY_STATUS_LINK_PASS)
1804eef4f27bSRobert Mustacchi             {
1805eef4f27bSRobert Mustacchi                 break;
1806eef4f27bSRobert Mustacchi             }
1807eef4f27bSRobert Mustacchi 
1808eef4f27bSRobert Mustacchi             mm_wait(pdev, 10);
1809eef4f27bSRobert Mustacchi 
1810eef4f27bSRobert Mustacchi             if(wait_link_timeout_us <= 10)
1811eef4f27bSRobert Mustacchi             {
1812eef4f27bSRobert Mustacchi                 break;
1813eef4f27bSRobert Mustacchi             }
1814eef4f27bSRobert Mustacchi 
1815eef4f27bSRobert Mustacchi             wait_link_timeout_us -= 10;
1816eef4f27bSRobert Mustacchi         }
1817eef4f27bSRobert Mustacchi 
1818eef4f27bSRobert Mustacchi         pdev->vars.cable_is_attached = TRUE;
1819eef4f27bSRobert Mustacchi     }
1820eef4f27bSRobert Mustacchi 
1821eef4f27bSRobert Mustacchi     /* Need to read a second time to get the current link status. */
1822eef4f27bSRobert Mustacchi     val = mii_get_serdes_link_status(pdev);
1823eef4f27bSRobert Mustacchi 
1824eef4f27bSRobert Mustacchi     if(val & PHY_STATUS_LINK_PASS)
1825eef4f27bSRobert Mustacchi     {
1826eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
1827eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "phy init link up\n");
1828eef4f27bSRobert Mustacchi     }
1829eef4f27bSRobert Mustacchi     else
1830eef4f27bSRobert Mustacchi     {
1831eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_DOWN;
1832eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "phy init link down\n");
1833eef4f27bSRobert Mustacchi     }
1834eef4f27bSRobert Mustacchi 
1835eef4f27bSRobert Mustacchi     return LM_STATUS_SUCCESS;
1836eef4f27bSRobert Mustacchi } /* init_5706_serdes */
1837eef4f27bSRobert Mustacchi 
1838eef4f27bSRobert Mustacchi 
1839eef4f27bSRobert Mustacchi 
1840eef4f27bSRobert Mustacchi /*******************************************************************************
1841eef4f27bSRobert Mustacchi  * Description:
1842eef4f27bSRobert Mustacchi  *
1843eef4f27bSRobert Mustacchi  * Return:
1844eef4f27bSRobert Mustacchi  ******************************************************************************/
1845eef4f27bSRobert Mustacchi STATIC void
init_serdes_or_phy_loopback(lm_device_t * pdev)1846eef4f27bSRobert Mustacchi init_serdes_or_phy_loopback(
1847eef4f27bSRobert Mustacchi     lm_device_t *pdev)
1848eef4f27bSRobert Mustacchi {
1849eef4f27bSRobert Mustacchi     u32_t cnt;
1850eef4f27bSRobert Mustacchi     u32_t val;
1851eef4f27bSRobert Mustacchi 
1852eef4f27bSRobert Mustacchi     (void) lm_mwrite(
1853*55fea89dSDan Cross         pdev,
1854*55fea89dSDan Cross         pdev->params.phy_addr,
1855*55fea89dSDan Cross         PHY_CTRL_REG,
1856eef4f27bSRobert Mustacchi         PHY_CTRL_PHY_RESET);
1857eef4f27bSRobert Mustacchi     for(cnt = 0; cnt < 1000; cnt++)
1858eef4f27bSRobert Mustacchi     {
1859eef4f27bSRobert Mustacchi         mm_wait(pdev, 5);
1860*55fea89dSDan Cross 
1861eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &val);
1862eef4f27bSRobert Mustacchi 
1863eef4f27bSRobert Mustacchi         if(!(val & PHY_CTRL_PHY_RESET))
1864eef4f27bSRobert Mustacchi         {
1865eef4f27bSRobert Mustacchi             mm_wait(pdev, 5);
1866eef4f27bSRobert Mustacchi             break;
1867eef4f27bSRobert Mustacchi         }
1868eef4f27bSRobert Mustacchi     }
1869eef4f27bSRobert Mustacchi 
1870eef4f27bSRobert Mustacchi     DbgBreakIf(val & PHY_CTRL_PHY_RESET);
1871eef4f27bSRobert Mustacchi 
1872eef4f27bSRobert Mustacchi     /* Get the PHY id. */
1873eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID1_REG, &val);
1874eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id = val << 16;
1875eef4f27bSRobert Mustacchi     DbgMessage1(pdev, INFORM, "Phy Id1 0x%x\n", val);
1876eef4f27bSRobert Mustacchi 
1877eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_ID2_REG, &val);
1878eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id |= val & 0xffff;
1879eef4f27bSRobert Mustacchi     DbgMessage1(pdev, INFORM, "Phy Id2 0x%x\n", val);
1880eef4f27bSRobert Mustacchi 
1881eef4f27bSRobert Mustacchi     DbgBreakIf((pdev->hw_info.phy_id & 0x0fffffff) == 0x0fffffff ||
1882eef4f27bSRobert Mustacchi         pdev->hw_info.phy_id == 0);
1883eef4f27bSRobert Mustacchi 
1884eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_tx_lengths, 0x26ff);
1885eef4f27bSRobert Mustacchi 
1886eef4f27bSRobert Mustacchi     /* Set the phy into loopback mode. */
1887eef4f27bSRobert Mustacchi     (void) lm_mwrite(
1888*55fea89dSDan Cross         pdev,
1889eef4f27bSRobert Mustacchi         pdev->params.phy_addr,
1890eef4f27bSRobert Mustacchi         PHY_CTRL_REG,
1891*55fea89dSDan Cross         PHY_CTRL_LOOPBACK_MODE |
1892eef4f27bSRobert Mustacchi             PHY_CTRL_FULL_DUPLEX_MODE |
1893eef4f27bSRobert Mustacchi             PHY_CTRL_SPEED_SELECT_1000MBPS);
1894eef4f27bSRobert Mustacchi } /* init_serdes_or_phy_loopback */
1895eef4f27bSRobert Mustacchi 
1896eef4f27bSRobert Mustacchi 
1897eef4f27bSRobert Mustacchi 
1898eef4f27bSRobert Mustacchi /*******************************************************************************
1899eef4f27bSRobert Mustacchi  * Description:
1900eef4f27bSRobert Mustacchi  *
1901eef4f27bSRobert Mustacchi  * Return:
1902eef4f27bSRobert Mustacchi  ******************************************************************************/
1903eef4f27bSRobert Mustacchi STATIC void
init_5709_serdes_loopback(lm_device_t * pdev)1904eef4f27bSRobert Mustacchi init_5709_serdes_loopback(
1905eef4f27bSRobert Mustacchi     lm_device_t *pdev)
1906eef4f27bSRobert Mustacchi {
1907eef4f27bSRobert Mustacchi     u32_t val;
1908eef4f27bSRobert Mustacchi 
1909eef4f27bSRobert Mustacchi     /*
1910eef4f27bSRobert Mustacchi      * reset causes the speed not be back to 2.5g intermittently
1911eef4f27bSRobert Mustacchi      * after phy lookback test when connecting to a switch.
1912eef4f27bSRobert Mustacchi      */
1913eef4f27bSRobert Mustacchi #if 0
1914eef4f27bSRobert Mustacchi     /* select combo_ieee0 block. */
1915eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1916eef4f27bSRobert Mustacchi 
1917eef4f27bSRobert Mustacchi     /* reset. */
1918eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, MII_CTRL_RESET);
1919eef4f27bSRobert Mustacchi     for(idx = 0; idx < 1000; idx++)
1920eef4f27bSRobert Mustacchi     {
1921eef4f27bSRobert Mustacchi         mm_wait(pdev, 5);
1922*55fea89dSDan Cross 
1923eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
1924eef4f27bSRobert Mustacchi         if(!(val & MII_CTRL_RESET))
1925eef4f27bSRobert Mustacchi         {
1926eef4f27bSRobert Mustacchi             mm_wait(pdev, 5);
1927eef4f27bSRobert Mustacchi             break;
1928eef4f27bSRobert Mustacchi         }
1929eef4f27bSRobert Mustacchi     }
1930eef4f27bSRobert Mustacchi     DbgBreakIf(val & MII_CTRL_RESET);
1931eef4f27bSRobert Mustacchi #endif
1932eef4f27bSRobert Mustacchi 
1933eef4f27bSRobert Mustacchi     /* set an_mmd.  an_mmd is the only register set we need for
1934eef4f27bSRobert Mustacchi      * programming xinan serdes.  all other registers are can
1935eef4f27bSRobert Mustacchi      * be access through an_mmd. */
1936eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffd0);
1937eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1e, 0x3800);
1938eef4f27bSRobert Mustacchi 
1939eef4f27bSRobert Mustacchi     /* get phy id. */
1940eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x12, &val);
1941eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id = val << 16;
1942eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x13, &val);
1943eef4f27bSRobert Mustacchi     pdev->hw_info.phy_id |= val & 0xffff;
1944eef4f27bSRobert Mustacchi 
1945eef4f27bSRobert Mustacchi     /* select combo_ieee0 block. */
1946eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
1947eef4f27bSRobert Mustacchi 
1948eef4f27bSRobert Mustacchi     /*CQ31687:set autoneg_enable bit too.*/
1949*55fea89dSDan Cross     /* Set the phy into loopback mode. */
1950eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x10, 0x5140);
1951eef4f27bSRobert Mustacchi 
1952eef4f27bSRobert Mustacchi } /* init_5709_serdes_loopback */
1953eef4f27bSRobert Mustacchi 
1954eef4f27bSRobert Mustacchi 
1955eef4f27bSRobert Mustacchi 
1956eef4f27bSRobert Mustacchi /*******************************************************************************
1957eef4f27bSRobert Mustacchi  * Description:
1958eef4f27bSRobert Mustacchi  *
1959eef4f27bSRobert Mustacchi  * Return:
1960eef4f27bSRobert Mustacchi  ******************************************************************************/
1961eef4f27bSRobert Mustacchi STATIC lm_status_t
init_loopback_mac_link(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_ctrl)1962eef4f27bSRobert Mustacchi init_loopback_mac_link(
1963eef4f27bSRobert Mustacchi     lm_device_t *pdev,
1964eef4f27bSRobert Mustacchi     lm_medium_t req_medium,
1965eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl)
1966eef4f27bSRobert Mustacchi {
1967eef4f27bSRobert Mustacchi     lm_status_t lm_status;
1968eef4f27bSRobert Mustacchi     u32_t val;
1969eef4f27bSRobert Mustacchi 
1970eef4f27bSRobert Mustacchi     lm_status = LM_STATUS_SUCCESS;
1971eef4f27bSRobert Mustacchi 
1972eef4f27bSRobert Mustacchi     if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_TYPE_PHY_LOOPBACK)
1973eef4f27bSRobert Mustacchi     {
1974*55fea89dSDan Cross         if(CHIP_NUM(pdev) == CHIP_NUM_5709 &&
1975eef4f27bSRobert Mustacchi             lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
1976eef4f27bSRobert Mustacchi         {
1977eef4f27bSRobert Mustacchi             init_5709_serdes_loopback(pdev);
1978eef4f27bSRobert Mustacchi         }
1979eef4f27bSRobert Mustacchi         else
1980eef4f27bSRobert Mustacchi         {
1981eef4f27bSRobert Mustacchi             init_serdes_or_phy_loopback(pdev);
1982eef4f27bSRobert Mustacchi         }
1983eef4f27bSRobert Mustacchi 
1984eef4f27bSRobert Mustacchi         REG_WR(pdev, emac.emac_tx_lengths, 0x26ff);
1985eef4f27bSRobert Mustacchi 
1986eef4f27bSRobert Mustacchi         REG_RD(pdev, emac.emac_mode, &val);
1987eef4f27bSRobert Mustacchi         val &= ~(EMAC_MODE_MAC_LOOP | EMAC_MODE_PORT);
1988eef4f27bSRobert Mustacchi         val |= EMAC_MODE_FORCE_LINK | EMAC_MODE_PORT_GMII;
1989eef4f27bSRobert Mustacchi         REG_WR(pdev, emac.emac_mode, val);
1990eef4f27bSRobert Mustacchi 
1991eef4f27bSRobert Mustacchi         SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_PHY_LOOPBACK);
1992eef4f27bSRobert Mustacchi         SET_MEDIUM_SPEED(pdev->vars.medium, LM_MEDIUM_SPEED_UNKNOWN);
1993eef4f27bSRobert Mustacchi         SET_MEDIUM_DUPLEX(pdev->vars.medium, LM_MEDIUM_FULL_DUPLEX);
1994eef4f27bSRobert Mustacchi 
1995eef4f27bSRobert Mustacchi         /* Save current link status. */
1996eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
1997eef4f27bSRobert Mustacchi 
1998eef4f27bSRobert Mustacchi         pdev->vars.cable_is_attached = TRUE;
1999eef4f27bSRobert Mustacchi     }
2000eef4f27bSRobert Mustacchi     else if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_TYPE_MAC_LOOPBACK)
2001eef4f27bSRobert Mustacchi     {
2002eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "Set up MAC loopback mode.\n");
2003eef4f27bSRobert Mustacchi 
2004eef4f27bSRobert Mustacchi         /* Set the MAC into loopback mode.  Mac loopback will intermittenly
2005eef4f27bSRobert Mustacchi          * fail if half_duplex bit is set.  CQ#24594. */
2006eef4f27bSRobert Mustacchi         REG_RD(pdev, emac.emac_mode, &val);
2007eef4f27bSRobert Mustacchi         val &= ~(EMAC_MODE_PORT | EMAC_MODE_HALF_DUPLEX);
2008eef4f27bSRobert Mustacchi         val |= EMAC_MODE_MAC_LOOP | EMAC_MODE_FORCE_LINK;
2009eef4f27bSRobert Mustacchi 
2010eef4f27bSRobert Mustacchi         /* The port mode must be set to none on the real chip. */
2011eef4f27bSRobert Mustacchi         if(CHIP_REV(pdev) == CHIP_REV_FPGA)
2012eef4f27bSRobert Mustacchi         {
2013eef4f27bSRobert Mustacchi             val |= EMAC_MODE_PORT_GMII;
2014eef4f27bSRobert Mustacchi         }
2015eef4f27bSRobert Mustacchi 
2016eef4f27bSRobert Mustacchi         REG_WR(pdev, emac.emac_mode, val);
2017eef4f27bSRobert Mustacchi 
2018eef4f27bSRobert Mustacchi         SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_MAC_LOOPBACK);
2019eef4f27bSRobert Mustacchi         SET_MEDIUM_SPEED(pdev->vars.medium, LM_MEDIUM_SPEED_UNKNOWN);
2020eef4f27bSRobert Mustacchi         SET_MEDIUM_DUPLEX(pdev->vars.medium, LM_MEDIUM_FULL_DUPLEX);
2021eef4f27bSRobert Mustacchi 
2022eef4f27bSRobert Mustacchi         /* Save current link status. */
2023eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_ACTIVE;
2024eef4f27bSRobert Mustacchi 
2025eef4f27bSRobert Mustacchi         pdev->vars.cable_is_attached = TRUE;
2026eef4f27bSRobert Mustacchi     }
2027eef4f27bSRobert Mustacchi     else
2028eef4f27bSRobert Mustacchi     {
2029eef4f27bSRobert Mustacchi         DbgBreakMsg("Not loopback medium type.\n");
2030eef4f27bSRobert Mustacchi 
2031eef4f27bSRobert Mustacchi         lm_status = LM_STATUS_FAILURE;
2032eef4f27bSRobert Mustacchi 
2033eef4f27bSRobert Mustacchi         /* Save current link status. */
2034eef4f27bSRobert Mustacchi         pdev->vars.link_status = LM_STATUS_LINK_DOWN;
2035eef4f27bSRobert Mustacchi 
2036eef4f27bSRobert Mustacchi         pdev->vars.cable_is_attached = FALSE;
2037eef4f27bSRobert Mustacchi     }
2038eef4f27bSRobert Mustacchi 
2039eef4f27bSRobert Mustacchi     /* Enable status block link attention. */
2040eef4f27bSRobert Mustacchi     REG_RD(pdev, hc.hc_attn_bits_enable, &val);
2041eef4f27bSRobert Mustacchi     val |= STATUS_ATTN_BITS_LINK_STATE;
2042eef4f27bSRobert Mustacchi     REG_WR(pdev, hc.hc_attn_bits_enable, val);
2043eef4f27bSRobert Mustacchi 
2044eef4f27bSRobert Mustacchi     return lm_status;
2045eef4f27bSRobert Mustacchi } /* init_loopback_mac_link */
2046eef4f27bSRobert Mustacchi 
2047eef4f27bSRobert Mustacchi 
2048eef4f27bSRobert Mustacchi 
2049eef4f27bSRobert Mustacchi /*******************************************************************************
2050eef4f27bSRobert Mustacchi  * Description:
2051eef4f27bSRobert Mustacchi  *
2052eef4f27bSRobert Mustacchi  * Return:
2053eef4f27bSRobert Mustacchi  ******************************************************************************/
2054eef4f27bSRobert Mustacchi STATIC lm_status_t
init_null_phy(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_ctrl,u32_t wait_link_timeout_us)2055eef4f27bSRobert Mustacchi init_null_phy(
2056eef4f27bSRobert Mustacchi     lm_device_t *pdev,
2057eef4f27bSRobert Mustacchi     lm_medium_t req_medium,
2058eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl,
2059eef4f27bSRobert Mustacchi     u32_t wait_link_timeout_us)
2060eef4f27bSRobert Mustacchi {
2061eef4f27bSRobert Mustacchi     DbgMessage(pdev, INFORM, "### init_null_phy\n");
2062eef4f27bSRobert Mustacchi 
2063eef4f27bSRobert Mustacchi     if(GET_MEDIUM_TYPE(req_medium) != LM_MEDIUM_TYPE_NULL)
2064eef4f27bSRobert Mustacchi     {
2065eef4f27bSRobert Mustacchi         return LM_STATUS_INVALID_PARAMETER;
2066eef4f27bSRobert Mustacchi     }
2067eef4f27bSRobert Mustacchi 
2068eef4f27bSRobert Mustacchi     /* Save current medium settings. */
2069eef4f27bSRobert Mustacchi     SET_MEDIUM_TYPE(pdev->vars.medium, LM_MEDIUM_TYPE_NULL);
2070eef4f27bSRobert Mustacchi     SET_MEDIUM_SPEED(pdev->vars.medium, LM_MEDIUM_SPEED_1000MBPS);
2071eef4f27bSRobert Mustacchi     SET_MEDIUM_DUPLEX(pdev->vars.medium, LM_MEDIUM_FULL_DUPLEX);
2072eef4f27bSRobert Mustacchi 
2073eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = TRUE;
2074eef4f27bSRobert Mustacchi 
2075eef4f27bSRobert Mustacchi     return LM_STATUS_SUCCESS;
2076eef4f27bSRobert Mustacchi } /* init_null_phy */
2077eef4f27bSRobert Mustacchi 
2078eef4f27bSRobert Mustacchi 
2079eef4f27bSRobert Mustacchi 
2080eef4f27bSRobert Mustacchi /*******************************************************************************
2081eef4f27bSRobert Mustacchi  * Description:
2082eef4f27bSRobert Mustacchi  *
2083eef4f27bSRobert Mustacchi  * Return:
2084eef4f27bSRobert Mustacchi  ******************************************************************************/
2085eef4f27bSRobert Mustacchi STATIC u32_t
netlink_pause_ad(lm_flow_control_t flow_ctrl)2086eef4f27bSRobert Mustacchi netlink_pause_ad(
2087eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl)
2088eef4f27bSRobert Mustacchi {
2089eef4f27bSRobert Mustacchi     u32_t pause_ad;
2090eef4f27bSRobert Mustacchi 
2091eef4f27bSRobert Mustacchi     pause_ad = 0;
2092eef4f27bSRobert Mustacchi 
2093eef4f27bSRobert Mustacchi     if((flow_ctrl == LM_FLOW_CONTROL_AUTO_PAUSE) ||
2094eef4f27bSRobert Mustacchi         ((flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE) &&
2095eef4f27bSRobert Mustacchi         (flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)))
2096eef4f27bSRobert Mustacchi     {
2097eef4f27bSRobert Mustacchi         pause_ad |= NETLINK_DRV_SET_LINK_FC_SYM_PAUSE |
2098eef4f27bSRobert Mustacchi                     NETLINK_DRV_SET_LINK_FC_ASYM_PAUSE;
2099eef4f27bSRobert Mustacchi     }
2100eef4f27bSRobert Mustacchi     else if(flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
2101eef4f27bSRobert Mustacchi     {
2102eef4f27bSRobert Mustacchi         pause_ad |= NETLINK_DRV_SET_LINK_FC_ASYM_PAUSE;
2103eef4f27bSRobert Mustacchi     }
2104eef4f27bSRobert Mustacchi     else if(flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE)
2105eef4f27bSRobert Mustacchi     {
2106eef4f27bSRobert Mustacchi         pause_ad |= NETLINK_DRV_SET_LINK_FC_SYM_PAUSE |
2107eef4f27bSRobert Mustacchi                     NETLINK_DRV_SET_LINK_FC_ASYM_PAUSE;
2108eef4f27bSRobert Mustacchi     }
2109eef4f27bSRobert Mustacchi 
2110eef4f27bSRobert Mustacchi     return pause_ad;
2111eef4f27bSRobert Mustacchi } /* netlink_pause_ad */
2112eef4f27bSRobert Mustacchi 
2113eef4f27bSRobert Mustacchi 
2114eef4f27bSRobert Mustacchi 
2115eef4f27bSRobert Mustacchi /*******************************************************************************
2116eef4f27bSRobert Mustacchi  * Description:
2117eef4f27bSRobert Mustacchi  *
2118eef4f27bSRobert Mustacchi  * Return:
2119eef4f27bSRobert Mustacchi  ******************************************************************************/
2120eef4f27bSRobert Mustacchi STATIC u32_t
link_setting_to_netlink(lm_link_settings_t * link_settings,u32_t serdes)2121eef4f27bSRobert Mustacchi link_setting_to_netlink(
2122eef4f27bSRobert Mustacchi     lm_link_settings_t *link_settings,
2123eef4f27bSRobert Mustacchi     u32_t serdes)
2124eef4f27bSRobert Mustacchi {
2125eef4f27bSRobert Mustacchi     lm_medium_t duplex;
2126eef4f27bSRobert Mustacchi     lm_medium_t speed;
2127eef4f27bSRobert Mustacchi     u32_t netlink;
2128eef4f27bSRobert Mustacchi 
2129eef4f27bSRobert Mustacchi     speed = GET_MEDIUM_SPEED(link_settings->req_medium);
2130eef4f27bSRobert Mustacchi     duplex = GET_MEDIUM_DUPLEX(link_settings->req_medium);
2131eef4f27bSRobert Mustacchi     netlink = 0;
2132eef4f27bSRobert Mustacchi 
2133eef4f27bSRobert Mustacchi     switch(speed)
2134eef4f27bSRobert Mustacchi     {
2135eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_10MBPS:
2136eef4f27bSRobert Mustacchi             if(duplex == LM_MEDIUM_FULL_DUPLEX)
2137eef4f27bSRobert Mustacchi             {
2138eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10FULL;
2139eef4f27bSRobert Mustacchi 
2140eef4f27bSRobert Mustacchi                 if((link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK) ==
2141eef4f27bSRobert Mustacchi                     LINK_FLAG_SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
2142eef4f27bSRobert Mustacchi                 {
2143eef4f27bSRobert Mustacchi                     netlink |= NETLINK_DRV_SET_LINK_SPEED_10HALF;
2144eef4f27bSRobert Mustacchi                 }
2145eef4f27bSRobert Mustacchi             }
2146eef4f27bSRobert Mustacchi             else
2147eef4f27bSRobert Mustacchi             {
2148eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10HALF;
2149eef4f27bSRobert Mustacchi             }
2150eef4f27bSRobert Mustacchi             break;
2151eef4f27bSRobert Mustacchi 
2152eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_100MBPS:
2153eef4f27bSRobert Mustacchi             if((link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK) ==
2154eef4f27bSRobert Mustacchi                 LINK_FLAG_SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
2155eef4f27bSRobert Mustacchi             {
2156eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10FULL;
2157eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10HALF;
2158eef4f27bSRobert Mustacchi             }
2159eef4f27bSRobert Mustacchi 
2160eef4f27bSRobert Mustacchi             if(duplex == LM_MEDIUM_FULL_DUPLEX)
2161eef4f27bSRobert Mustacchi             {
2162eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_100FULL;
2163eef4f27bSRobert Mustacchi 
2164eef4f27bSRobert Mustacchi                 if((link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK) ==
2165eef4f27bSRobert Mustacchi                     LINK_FLAG_SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
2166eef4f27bSRobert Mustacchi                 {
2167eef4f27bSRobert Mustacchi                     netlink |= NETLINK_DRV_SET_LINK_SPEED_100HALF;
2168eef4f27bSRobert Mustacchi                 }
2169eef4f27bSRobert Mustacchi             }
2170eef4f27bSRobert Mustacchi             else
2171eef4f27bSRobert Mustacchi             {
2172eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_100HALF;
2173eef4f27bSRobert Mustacchi             }
2174eef4f27bSRobert Mustacchi             break;
2175eef4f27bSRobert Mustacchi 
2176eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_1000MBPS:
2177eef4f27bSRobert Mustacchi             if((link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK) ==
2178eef4f27bSRobert Mustacchi                 LINK_FLAG_SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
2179eef4f27bSRobert Mustacchi             {
2180eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10FULL;
2181eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_10HALF;
2182eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_100FULL;
2183eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_100HALF;
2184eef4f27bSRobert Mustacchi             }
2185eef4f27bSRobert Mustacchi 
2186eef4f27bSRobert Mustacchi             if(duplex == LM_MEDIUM_FULL_DUPLEX)
2187eef4f27bSRobert Mustacchi             {
2188eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_1GFULL;
2189eef4f27bSRobert Mustacchi 
2190eef4f27bSRobert Mustacchi                 if((link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK) ==
2191eef4f27bSRobert Mustacchi                     LINK_FLAG_SELECTIVE_AUTONEG_ENABLE_SLOWER_SPEEDS)
2192eef4f27bSRobert Mustacchi                 {
2193eef4f27bSRobert Mustacchi                     netlink |= NETLINK_DRV_SET_LINK_SPEED_1GHALF;
2194eef4f27bSRobert Mustacchi                 }
2195eef4f27bSRobert Mustacchi             }
2196eef4f27bSRobert Mustacchi             else
2197eef4f27bSRobert Mustacchi             {
2198eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_SPEED_1GHALF;
2199eef4f27bSRobert Mustacchi             }
2200eef4f27bSRobert Mustacchi             break;
2201eef4f27bSRobert Mustacchi 
2202eef4f27bSRobert Mustacchi         default:
2203eef4f27bSRobert Mustacchi             if (serdes)
2204eef4f27bSRobert Mustacchi             {
2205eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_ENABLE_AUTONEG |
2206eef4f27bSRobert Mustacchi                     NETLINK_DRV_SET_LINK_SPEED_1GHALF |
2207eef4f27bSRobert Mustacchi                     NETLINK_DRV_SET_LINK_SPEED_1GFULL;
2208eef4f27bSRobert Mustacchi             }
2209eef4f27bSRobert Mustacchi             else
2210eef4f27bSRobert Mustacchi             {
2211eef4f27bSRobert Mustacchi                 netlink |= NETLINK_DRV_SET_LINK_ENABLE_AUTONEG |
2212eef4f27bSRobert Mustacchi                     NETLINK_DRV_SET_LINK_SPEED_10HALF |
2213eef4f27bSRobert Mustacchi                     NETLINK_DRV_SET_LINK_SPEED_10FULL |
2214eef4f27bSRobert Mustacchi                     NETLINK_DRV_SET_LINK_SPEED_100HALF |
2215eef4f27bSRobert Mustacchi                     NETLINK_DRV_SET_LINK_SPEED_100FULL |
2216eef4f27bSRobert Mustacchi                     NETLINK_DRV_SET_LINK_SPEED_1GHALF |
2217eef4f27bSRobert Mustacchi                     NETLINK_DRV_SET_LINK_SPEED_1GFULL;
2218eef4f27bSRobert Mustacchi             }
2219eef4f27bSRobert Mustacchi             break;
2220eef4f27bSRobert Mustacchi     }
2221eef4f27bSRobert Mustacchi 
2222eef4f27bSRobert Mustacchi     netlink |= NETLINK_DRV_SET_LINK_PHY_RESET;
2223eef4f27bSRobert Mustacchi 
2224eef4f27bSRobert Mustacchi     if(link_settings->flag & LINK_FLAG_SELECTIVE_AUTONEG_MASK)
2225eef4f27bSRobert Mustacchi     {
2226eef4f27bSRobert Mustacchi         netlink |= NETLINK_DRV_SET_LINK_ENABLE_AUTONEG;
2227eef4f27bSRobert Mustacchi     }
2228eef4f27bSRobert Mustacchi 
2229eef4f27bSRobert Mustacchi     if(link_settings->flag & LINK_FLAG_WIRE_SPEED)
2230eef4f27bSRobert Mustacchi     {
2231eef4f27bSRobert Mustacchi         netlink |= NETLINK_DRV_SET_LINK_ETH_AT_WIRESPEED_ENABLE;
2232eef4f27bSRobert Mustacchi     }
2233eef4f27bSRobert Mustacchi 
2234eef4f27bSRobert Mustacchi     netlink |= netlink_pause_ad(link_settings->flow_ctrl);
2235eef4f27bSRobert Mustacchi 
2236eef4f27bSRobert Mustacchi     return netlink;
2237eef4f27bSRobert Mustacchi } /* link_settings_to_netlink */
2238eef4f27bSRobert Mustacchi 
2239eef4f27bSRobert Mustacchi 
2240eef4f27bSRobert Mustacchi 
2241eef4f27bSRobert Mustacchi /*******************************************************************************
2242eef4f27bSRobert Mustacchi  * Description:
2243eef4f27bSRobert Mustacchi  *
2244eef4f27bSRobert Mustacchi  * Return:
2245eef4f27bSRobert Mustacchi  ******************************************************************************/
2246eef4f27bSRobert Mustacchi lm_status_t
lm_init_remote_phy(lm_device_t * pdev,lm_link_settings_t * serdes_link,lm_link_settings_t * rphy_link)2247eef4f27bSRobert Mustacchi lm_init_remote_phy(
2248eef4f27bSRobert Mustacchi     lm_device_t *pdev,
2249eef4f27bSRobert Mustacchi     lm_link_settings_t *serdes_link,
2250eef4f27bSRobert Mustacchi     lm_link_settings_t *rphy_link)
2251eef4f27bSRobert Mustacchi {
2252eef4f27bSRobert Mustacchi     u32_t serdes_netlink;
2253eef4f27bSRobert Mustacchi     u32_t rphy_netlink;
2254eef4f27bSRobert Mustacchi     u32_t set_link_arg;
2255eef4f27bSRobert Mustacchi     u32_t val;
2256eef4f27bSRobert Mustacchi 
2257eef4f27bSRobert Mustacchi     DbgBreakIf(pdev->params.enable_remote_phy == FALSE);
2258eef4f27bSRobert Mustacchi 
2259eef4f27bSRobert Mustacchi     serdes_netlink = link_setting_to_netlink(serdes_link, TRUE);
2260eef4f27bSRobert Mustacchi     rphy_netlink = link_setting_to_netlink(rphy_link, FALSE);
2261eef4f27bSRobert Mustacchi 
2262eef4f27bSRobert Mustacchi     REG_WR_IND(
2263eef4f27bSRobert Mustacchi         pdev,
2264eef4f27bSRobert Mustacchi         pdev->hw_info.shmem_base +
2265eef4f27bSRobert Mustacchi             OFFSETOF(shmem_region_t, remotephy.serdes_link_pref),
2266eef4f27bSRobert Mustacchi         serdes_netlink);
2267eef4f27bSRobert Mustacchi 
2268eef4f27bSRobert Mustacchi     REG_WR_IND(
2269eef4f27bSRobert Mustacchi         pdev,
2270eef4f27bSRobert Mustacchi         pdev->hw_info.shmem_base +
2271eef4f27bSRobert Mustacchi             OFFSETOF(shmem_region_t, remotephy.copper_phy_link_pref),
2272eef4f27bSRobert Mustacchi         rphy_netlink | NETLINK_DRV_SET_LINK_PHY_APP_REMOTE);
2273eef4f27bSRobert Mustacchi 
2274eef4f27bSRobert Mustacchi     REG_RD_IND(
2275eef4f27bSRobert Mustacchi         pdev,
2276eef4f27bSRobert Mustacchi         pdev->hw_info.shmem_base +
2277eef4f27bSRobert Mustacchi             OFFSETOF(shmem_region_t, drv_fw_mb.link_status),
2278eef4f27bSRobert Mustacchi         &val);
2279eef4f27bSRobert Mustacchi     if(val & NETLINK_GET_LINK_STATUS_SERDES_LINK)
2280eef4f27bSRobert Mustacchi     {
2281eef4f27bSRobert Mustacchi         set_link_arg = serdes_netlink;
2282eef4f27bSRobert Mustacchi     }
2283eef4f27bSRobert Mustacchi     else
2284eef4f27bSRobert Mustacchi     {
2285eef4f27bSRobert Mustacchi         set_link_arg = rphy_netlink | NETLINK_DRV_SET_LINK_PHY_APP_REMOTE;
2286eef4f27bSRobert Mustacchi     }
2287eef4f27bSRobert Mustacchi 
2288eef4f27bSRobert Mustacchi     REG_WR_IND(
2289eef4f27bSRobert Mustacchi         pdev,
2290eef4f27bSRobert Mustacchi         pdev->hw_info.shmem_base +
2291eef4f27bSRobert Mustacchi             OFFSETOF(shmem_region_t, drv_fw_mb.mb_args[0]),
2292eef4f27bSRobert Mustacchi         set_link_arg);
2293eef4f27bSRobert Mustacchi 
2294eef4f27bSRobert Mustacchi     (void) lm_submit_fw_cmd(pdev, DRV_MSG_CODE_CMD_SET_LINK);
2295eef4f27bSRobert Mustacchi 
2296eef4f27bSRobert Mustacchi     return LM_STATUS_SUCCESS;
2297eef4f27bSRobert Mustacchi } /* lm_init_remote_phy */
2298eef4f27bSRobert Mustacchi 
2299eef4f27bSRobert Mustacchi 
2300eef4f27bSRobert Mustacchi 
2301eef4f27bSRobert Mustacchi /*******************************************************************************
2302eef4f27bSRobert Mustacchi  * Description:
2303eef4f27bSRobert Mustacchi  *
2304eef4f27bSRobert Mustacchi  * Return:
2305eef4f27bSRobert Mustacchi  ******************************************************************************/
2306eef4f27bSRobert Mustacchi lm_status_t
lm_init_phy(lm_device_t * pdev,lm_medium_t req_medium,lm_flow_control_t flow_ctrl,u32_t selective_autoneg,u32_t wire_speed,u32_t wait_link_timeout_us)2307eef4f27bSRobert Mustacchi lm_init_phy(
2308eef4f27bSRobert Mustacchi     lm_device_t *pdev,
2309eef4f27bSRobert Mustacchi     lm_medium_t req_medium,
2310eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl,
2311eef4f27bSRobert Mustacchi     u32_t selective_autoneg,
2312eef4f27bSRobert Mustacchi     u32_t wire_speed,
2313eef4f27bSRobert Mustacchi     u32_t wait_link_timeout_us)
2314eef4f27bSRobert Mustacchi {
2315eef4f27bSRobert Mustacchi     lm_status_t lm_status;
2316eef4f27bSRobert Mustacchi 
2317eef4f27bSRobert Mustacchi     DbgBreakIf(pdev->params.enable_remote_phy);
2318eef4f27bSRobert Mustacchi 
2319eef4f27bSRobert Mustacchi     if(GET_MEDIUM_AUTONEG_MODE(req_medium) == LM_MEDIUM_SELECTIVE_AUTONEG)
2320eef4f27bSRobert Mustacchi     {
2321eef4f27bSRobert Mustacchi         selective_autoneg = TRUE;
2322eef4f27bSRobert Mustacchi     }
2323eef4f27bSRobert Mustacchi 
2324eef4f27bSRobert Mustacchi     if(GET_MEDIUM_TYPE(req_medium) == LM_MEDIUM_AUTO_DETECT)
2325eef4f27bSRobert Mustacchi     {
2326eef4f27bSRobert Mustacchi         if(CHIP_REV(pdev) == CHIP_REV_IKOS)
2327eef4f27bSRobert Mustacchi         {
2328eef4f27bSRobert Mustacchi             req_medium = LM_MEDIUM_TYPE_NULL;
2329eef4f27bSRobert Mustacchi         }
2330eef4f27bSRobert Mustacchi         else if(CHIP_REV(pdev) == CHIP_REV_FPGA)
2331eef4f27bSRobert Mustacchi         {
2332eef4f27bSRobert Mustacchi             selective_autoneg = TRUE;
2333eef4f27bSRobert Mustacchi             req_medium = LM_MEDIUM_TYPE_UTP |
2334eef4f27bSRobert Mustacchi                 LM_MEDIUM_SPEED_10MBPS |
2335eef4f27bSRobert Mustacchi                 LM_MEDIUM_FULL_DUPLEX;
2336eef4f27bSRobert Mustacchi         }
2337eef4f27bSRobert Mustacchi         else if(lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
2338eef4f27bSRobert Mustacchi         {
2339eef4f27bSRobert Mustacchi             if(req_medium == LM_MEDIUM_AUTO_DETECT)
2340eef4f27bSRobert Mustacchi             {
2341eef4f27bSRobert Mustacchi                 req_medium = LM_MEDIUM_TYPE_FIBER;
2342eef4f27bSRobert Mustacchi             }
2343eef4f27bSRobert Mustacchi             else
2344eef4f27bSRobert Mustacchi             {
2345eef4f27bSRobert Mustacchi                 SET_MEDIUM_TYPE(req_medium, LM_MEDIUM_TYPE_FIBER);
2346eef4f27bSRobert Mustacchi             }
2347eef4f27bSRobert Mustacchi         }
2348eef4f27bSRobert Mustacchi         else
2349eef4f27bSRobert Mustacchi         {
2350eef4f27bSRobert Mustacchi             if(req_medium == LM_MEDIUM_AUTO_DETECT)
2351eef4f27bSRobert Mustacchi             {
2352eef4f27bSRobert Mustacchi                 req_medium = LM_MEDIUM_TYPE_UTP;
2353eef4f27bSRobert Mustacchi             }
2354eef4f27bSRobert Mustacchi             else
2355eef4f27bSRobert Mustacchi             {
2356eef4f27bSRobert Mustacchi                 SET_MEDIUM_TYPE(req_medium, LM_MEDIUM_TYPE_UTP);
2357eef4f27bSRobert Mustacchi             }
2358eef4f27bSRobert Mustacchi         }
2359eef4f27bSRobert Mustacchi     }
2360eef4f27bSRobert Mustacchi 
2361eef4f27bSRobert Mustacchi     switch(GET_MEDIUM_TYPE(req_medium))
2362eef4f27bSRobert Mustacchi     {
2363eef4f27bSRobert Mustacchi         case LM_MEDIUM_TYPE_UTP:
2364eef4f27bSRobert Mustacchi             lm_status = init_utp(
2365eef4f27bSRobert Mustacchi                 pdev,
2366eef4f27bSRobert Mustacchi                 req_medium,
2367*55fea89dSDan Cross                 flow_ctrl,
2368eef4f27bSRobert Mustacchi                 selective_autoneg,
2369eef4f27bSRobert Mustacchi                 wire_speed,
2370eef4f27bSRobert Mustacchi                 wait_link_timeout_us);
2371eef4f27bSRobert Mustacchi             break;
2372eef4f27bSRobert Mustacchi 
2373eef4f27bSRobert Mustacchi         case LM_MEDIUM_TYPE_FIBER:
2374eef4f27bSRobert Mustacchi             DbgBreakIf(CHIP_NUM(pdev) != CHIP_NUM_5706 &&
2375eef4f27bSRobert Mustacchi                        CHIP_NUM(pdev) != CHIP_NUM_5708 &&
2376eef4f27bSRobert Mustacchi                        CHIP_NUM(pdev) != CHIP_NUM_5709);
2377eef4f27bSRobert Mustacchi 
2378eef4f27bSRobert Mustacchi             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
2379eef4f27bSRobert Mustacchi             {
2380eef4f27bSRobert Mustacchi                 lm_status = init_5706_serdes(
2381eef4f27bSRobert Mustacchi                     pdev,
2382eef4f27bSRobert Mustacchi                     req_medium,
2383eef4f27bSRobert Mustacchi                     flow_ctrl,
2384eef4f27bSRobert Mustacchi                     wait_link_timeout_us);
2385eef4f27bSRobert Mustacchi             }
2386eef4f27bSRobert Mustacchi             else if(CHIP_NUM(pdev) == CHIP_NUM_5708)
2387eef4f27bSRobert Mustacchi             {
2388eef4f27bSRobert Mustacchi                 lm_status = init_5708_serdes(
2389eef4f27bSRobert Mustacchi                     pdev,
2390eef4f27bSRobert Mustacchi                     req_medium,
2391eef4f27bSRobert Mustacchi                     flow_ctrl,
2392eef4f27bSRobert Mustacchi                     selective_autoneg,
2393eef4f27bSRobert Mustacchi                     wait_link_timeout_us);
2394eef4f27bSRobert Mustacchi             }
2395eef4f27bSRobert Mustacchi             else
2396eef4f27bSRobert Mustacchi             {
2397eef4f27bSRobert Mustacchi                 lm_status = init_5709_serdes(
2398eef4f27bSRobert Mustacchi                     pdev,
2399eef4f27bSRobert Mustacchi                     req_medium,
2400eef4f27bSRobert Mustacchi                     flow_ctrl,
2401eef4f27bSRobert Mustacchi                     selective_autoneg,
2402eef4f27bSRobert Mustacchi                     wait_link_timeout_us);
2403eef4f27bSRobert Mustacchi             }
2404eef4f27bSRobert Mustacchi 
2405eef4f27bSRobert Mustacchi             break;
2406eef4f27bSRobert Mustacchi 
2407eef4f27bSRobert Mustacchi         case LM_MEDIUM_TYPE_NULL:
2408eef4f27bSRobert Mustacchi             lm_status = init_null_phy(
2409eef4f27bSRobert Mustacchi                 pdev,
2410eef4f27bSRobert Mustacchi                 req_medium,
2411eef4f27bSRobert Mustacchi                 flow_ctrl,
2412eef4f27bSRobert Mustacchi                 wait_link_timeout_us);
2413eef4f27bSRobert Mustacchi             break;
2414eef4f27bSRobert Mustacchi 
2415eef4f27bSRobert Mustacchi         case LM_MEDIUM_TYPE_PHY_LOOPBACK:
2416eef4f27bSRobert Mustacchi         case LM_MEDIUM_TYPE_MAC_LOOPBACK:
2417eef4f27bSRobert Mustacchi             lm_status = init_loopback_mac_link(
2418eef4f27bSRobert Mustacchi                 pdev,
2419eef4f27bSRobert Mustacchi                 req_medium,
2420eef4f27bSRobert Mustacchi                 flow_ctrl);
2421eef4f27bSRobert Mustacchi             break;
2422eef4f27bSRobert Mustacchi 
2423eef4f27bSRobert Mustacchi         default:
2424eef4f27bSRobert Mustacchi             lm_status = LM_STATUS_UNKNOWN_MEDIUM;
2425eef4f27bSRobert Mustacchi             break;
2426eef4f27bSRobert Mustacchi     }
2427eef4f27bSRobert Mustacchi 
2428eef4f27bSRobert Mustacchi     return lm_status;
2429eef4f27bSRobert Mustacchi } /* lm_init_phy */
2430eef4f27bSRobert Mustacchi 
2431eef4f27bSRobert Mustacchi 
2432eef4f27bSRobert Mustacchi 
2433eef4f27bSRobert Mustacchi /*******************************************************************************
2434eef4f27bSRobert Mustacchi  * Description:
2435eef4f27bSRobert Mustacchi  *
2436eef4f27bSRobert Mustacchi  * Return:
2437eef4f27bSRobert Mustacchi  ******************************************************************************/
2438eef4f27bSRobert Mustacchi STATIC void
get_serdes_phy_ad(lm_device_t * pdev,u32_t * local_phy_ad,u32_t * remote_phy_ad)2439eef4f27bSRobert Mustacchi get_serdes_phy_ad(
2440eef4f27bSRobert Mustacchi     lm_device_t *pdev,
2441eef4f27bSRobert Mustacchi     u32_t *local_phy_ad,
2442eef4f27bSRobert Mustacchi     u32_t *remote_phy_ad)
2443eef4f27bSRobert Mustacchi {
2444eef4f27bSRobert Mustacchi     u32_t val;
2445eef4f27bSRobert Mustacchi 
2446eef4f27bSRobert Mustacchi     *local_phy_ad = 0;
2447eef4f27bSRobert Mustacchi     *remote_phy_ad = 0;
2448eef4f27bSRobert Mustacchi 
2449eef4f27bSRobert Mustacchi     if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
2450eef4f27bSRobert Mustacchi     {
2451eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_AN_AD_REG, &val);
2452eef4f27bSRobert Mustacchi 
2453eef4f27bSRobert Mustacchi         if(val & PHY_AN_AD_1000X_PAUSE_CAPABLE)
2454eef4f27bSRobert Mustacchi         {
2455eef4f27bSRobert Mustacchi             *local_phy_ad |= PHY_AN_AD_PAUSE_CAPABLE;
2456eef4f27bSRobert Mustacchi         }
2457eef4f27bSRobert Mustacchi 
2458eef4f27bSRobert Mustacchi         if(val & PHY_AN_AD_1000X_ASYM_PAUSE)
2459eef4f27bSRobert Mustacchi         {
2460eef4f27bSRobert Mustacchi             *local_phy_ad |= PHY_AN_AD_ASYM_PAUSE;
2461eef4f27bSRobert Mustacchi         }
2462eef4f27bSRobert Mustacchi 
2463eef4f27bSRobert Mustacchi         (void) lm_mread(pdev,pdev->params.phy_addr,PHY_LINK_PARTNER_ABILITY_REG,&val);
2464eef4f27bSRobert Mustacchi 
2465eef4f27bSRobert Mustacchi         if(val & PHY_AN_AD_1000X_PAUSE_CAPABLE)
2466eef4f27bSRobert Mustacchi         {
2467eef4f27bSRobert Mustacchi             *remote_phy_ad |= PHY_AN_AD_PAUSE_CAPABLE;
2468eef4f27bSRobert Mustacchi         }
2469eef4f27bSRobert Mustacchi 
2470eef4f27bSRobert Mustacchi         if(val & PHY_AN_AD_1000X_ASYM_PAUSE)
2471eef4f27bSRobert Mustacchi         {
2472eef4f27bSRobert Mustacchi             *remote_phy_ad |= PHY_AN_AD_ASYM_PAUSE;
2473eef4f27bSRobert Mustacchi         }
2474eef4f27bSRobert Mustacchi     }
2475eef4f27bSRobert Mustacchi     else
2476eef4f27bSRobert Mustacchi     {
2477eef4f27bSRobert Mustacchi         /* select combo ieee0 block. */
2478eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
2479eef4f27bSRobert Mustacchi 
2480eef4f27bSRobert Mustacchi         /* local advertisement. */
2481eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x14, &val);
2482eef4f27bSRobert Mustacchi 
2483eef4f27bSRobert Mustacchi         if(val & 0x80)
2484eef4f27bSRobert Mustacchi         {
2485eef4f27bSRobert Mustacchi             *local_phy_ad |= PHY_AN_AD_PAUSE_CAPABLE;
2486eef4f27bSRobert Mustacchi         }
2487eef4f27bSRobert Mustacchi 
2488eef4f27bSRobert Mustacchi         if(val & 0x100)
2489eef4f27bSRobert Mustacchi         {
2490eef4f27bSRobert Mustacchi             *local_phy_ad |= PHY_AN_AD_ASYM_PAUSE;
2491eef4f27bSRobert Mustacchi         }
2492eef4f27bSRobert Mustacchi 
2493eef4f27bSRobert Mustacchi         /* remote advertisement. */
2494eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x15, &val);
2495eef4f27bSRobert Mustacchi 
2496eef4f27bSRobert Mustacchi         if(val & 0x80)
2497eef4f27bSRobert Mustacchi         {
2498eef4f27bSRobert Mustacchi             *remote_phy_ad |= PHY_AN_AD_PAUSE_CAPABLE;
2499eef4f27bSRobert Mustacchi         }
2500eef4f27bSRobert Mustacchi 
2501eef4f27bSRobert Mustacchi         if(val & 0x100)
2502eef4f27bSRobert Mustacchi         {
2503eef4f27bSRobert Mustacchi             *remote_phy_ad |= PHY_AN_AD_ASYM_PAUSE;
2504eef4f27bSRobert Mustacchi         }
2505eef4f27bSRobert Mustacchi     }
2506eef4f27bSRobert Mustacchi } /* get_serdes_phy_ad */
2507eef4f27bSRobert Mustacchi 
2508eef4f27bSRobert Mustacchi 
2509eef4f27bSRobert Mustacchi 
2510eef4f27bSRobert Mustacchi /*******************************************************************************
2511eef4f27bSRobert Mustacchi  * Description:
2512eef4f27bSRobert Mustacchi  *
2513eef4f27bSRobert Mustacchi  * Return:
2514eef4f27bSRobert Mustacchi  ******************************************************************************/
2515eef4f27bSRobert Mustacchi STATIC lm_flow_control_t
set_mac_flow_control(lm_device_t * pdev,lm_medium_t medium,lm_flow_control_t flow_control_cap)2516eef4f27bSRobert Mustacchi set_mac_flow_control(
2517eef4f27bSRobert Mustacchi     lm_device_t *pdev,
2518eef4f27bSRobert Mustacchi     lm_medium_t medium,
2519eef4f27bSRobert Mustacchi     lm_flow_control_t flow_control_cap)
2520eef4f27bSRobert Mustacchi {
2521eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl;
2522eef4f27bSRobert Mustacchi     u32_t remote_phy_link;
2523eef4f27bSRobert Mustacchi     u32_t remote_phy_ad;
2524eef4f27bSRobert Mustacchi     u32_t local_phy_ad;
2525eef4f27bSRobert Mustacchi     u32_t val;
2526eef4f27bSRobert Mustacchi     lm_rx_chain_t *rxq;
2527eef4f27bSRobert Mustacchi     u32_t idx;
2528eef4f27bSRobert Mustacchi 
2529eef4f27bSRobert Mustacchi     if(pdev->params.enable_remote_phy)
2530eef4f27bSRobert Mustacchi     {
2531eef4f27bSRobert Mustacchi         local_phy_ad = 0;
2532eef4f27bSRobert Mustacchi 
2533eef4f27bSRobert Mustacchi         if((flow_control_cap == LM_FLOW_CONTROL_AUTO_PAUSE) ||
2534eef4f27bSRobert Mustacchi             ((flow_control_cap & LM_FLOW_CONTROL_RECEIVE_PAUSE) &&
2535eef4f27bSRobert Mustacchi             (flow_control_cap & LM_FLOW_CONTROL_TRANSMIT_PAUSE)) ||
2536eef4f27bSRobert Mustacchi             (flow_control_cap & LM_FLOW_CONTROL_RECEIVE_PAUSE))
2537eef4f27bSRobert Mustacchi         {
2538eef4f27bSRobert Mustacchi             local_phy_ad |= (PHY_AN_AD_PAUSE_CAPABLE | PHY_AN_AD_ASYM_PAUSE);
2539eef4f27bSRobert Mustacchi         }
2540eef4f27bSRobert Mustacchi         else if(flow_control_cap & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
2541eef4f27bSRobert Mustacchi         {
2542eef4f27bSRobert Mustacchi             local_phy_ad |= PHY_AN_AD_ASYM_PAUSE;
2543eef4f27bSRobert Mustacchi         }
2544eef4f27bSRobert Mustacchi 
2545eef4f27bSRobert Mustacchi         remote_phy_ad = 0;
2546eef4f27bSRobert Mustacchi 
2547eef4f27bSRobert Mustacchi         REG_RD_IND(
2548eef4f27bSRobert Mustacchi             pdev,
2549eef4f27bSRobert Mustacchi             pdev->hw_info.shmem_base +
2550eef4f27bSRobert Mustacchi                 OFFSETOF(shmem_region_t, drv_fw_mb.link_status),
2551eef4f27bSRobert Mustacchi             &remote_phy_link);
2552eef4f27bSRobert Mustacchi 
2553eef4f27bSRobert Mustacchi         if(remote_phy_link & NETLINK_GET_LINK_STATUS_PARTNER_SYM_PAUSE_CAP)
2554eef4f27bSRobert Mustacchi         {
2555eef4f27bSRobert Mustacchi             remote_phy_ad |= PHY_LINK_PARTNER_PAUSE_CAPABLE;
2556eef4f27bSRobert Mustacchi         }
2557eef4f27bSRobert Mustacchi 
2558eef4f27bSRobert Mustacchi         if(remote_phy_link & NETLINK_GET_LINK_STATUS_PARTNER_ASYM_PAUSE_CAP)
2559eef4f27bSRobert Mustacchi         {
2560eef4f27bSRobert Mustacchi             remote_phy_ad |= PHY_LINK_PARTNER_ASYM_PAUSE;
2561eef4f27bSRobert Mustacchi         }
2562eef4f27bSRobert Mustacchi     }
2563eef4f27bSRobert Mustacchi     else
2564eef4f27bSRobert Mustacchi     {
2565eef4f27bSRobert Mustacchi         if(GET_MEDIUM_TYPE(medium) == LM_MEDIUM_TYPE_FIBER)
2566eef4f27bSRobert Mustacchi         {
2567eef4f27bSRobert Mustacchi             get_serdes_phy_ad(pdev, &local_phy_ad, &remote_phy_ad);
2568eef4f27bSRobert Mustacchi         }
2569eef4f27bSRobert Mustacchi         else
2570eef4f27bSRobert Mustacchi         {
2571eef4f27bSRobert Mustacchi             (void) lm_mread(
2572*55fea89dSDan Cross                 pdev,
2573*55fea89dSDan Cross                 pdev->params.phy_addr,
2574*55fea89dSDan Cross                 PHY_AN_AD_REG,
2575eef4f27bSRobert Mustacchi                 &local_phy_ad);
2576eef4f27bSRobert Mustacchi 
2577eef4f27bSRobert Mustacchi             (void) lm_mread(
2578*55fea89dSDan Cross                 pdev,
2579*55fea89dSDan Cross                 pdev->params.phy_addr,
2580*55fea89dSDan Cross                 PHY_LINK_PARTNER_ABILITY_REG,
2581eef4f27bSRobert Mustacchi                 &remote_phy_ad);
2582eef4f27bSRobert Mustacchi         }
2583eef4f27bSRobert Mustacchi     }
2584eef4f27bSRobert Mustacchi 
2585eef4f27bSRobert Mustacchi     DbgMessage(pdev, INFORM, "Local flow control settings.\n");
2586eef4f27bSRobert Mustacchi 
2587eef4f27bSRobert Mustacchi     if(local_phy_ad & PHY_AN_AD_PAUSE_CAPABLE)
2588eef4f27bSRobert Mustacchi     {
2589eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "   PAUSE capable.\n");
2590eef4f27bSRobert Mustacchi     }
2591eef4f27bSRobert Mustacchi 
2592eef4f27bSRobert Mustacchi     if(local_phy_ad & PHY_AN_AD_ASYM_PAUSE)
2593eef4f27bSRobert Mustacchi     {
2594eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "   ASYM_PAUSE capable.\n");
2595eef4f27bSRobert Mustacchi     }
2596*55fea89dSDan Cross 
2597eef4f27bSRobert Mustacchi     DbgMessage(pdev, INFORM, "Remote flow control settings.\n");
2598eef4f27bSRobert Mustacchi 
2599eef4f27bSRobert Mustacchi     if(remote_phy_ad & PHY_LINK_PARTNER_PAUSE_CAPABLE)
2600eef4f27bSRobert Mustacchi     {
2601eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "   PAUSE capable.\n");
2602eef4f27bSRobert Mustacchi     }
2603eef4f27bSRobert Mustacchi 
2604eef4f27bSRobert Mustacchi     if(remote_phy_ad & PHY_LINK_PARTNER_ASYM_PAUSE)
2605eef4f27bSRobert Mustacchi     {
2606eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "   ASYM_PAUSE capable.\n");
2607eef4f27bSRobert Mustacchi     }
2608eef4f27bSRobert Mustacchi 
2609eef4f27bSRobert Mustacchi     /* Resultant flow control setting. */
2610eef4f27bSRobert Mustacchi     flow_ctrl = LM_FLOW_CONTROL_NONE;
2611eef4f27bSRobert Mustacchi 
2612eef4f27bSRobert Mustacchi     if((flow_control_cap & LM_FLOW_CONTROL_AUTO_PAUSE) ||
2613eef4f27bSRobert Mustacchi         pdev->params.flow_control_reporting_mode)
2614eef4f27bSRobert Mustacchi     {
2615eef4f27bSRobert Mustacchi         /* See Table 28B-3 of 802.3ab-1999 spec. */
2616eef4f27bSRobert Mustacchi         if(local_phy_ad & PHY_AN_AD_PAUSE_CAPABLE)
2617eef4f27bSRobert Mustacchi         {
2618eef4f27bSRobert Mustacchi             if(local_phy_ad & PHY_AN_AD_ASYM_PAUSE)
2619eef4f27bSRobert Mustacchi             {
2620eef4f27bSRobert Mustacchi                 if(remote_phy_ad & PHY_LINK_PARTNER_PAUSE_CAPABLE)
2621eef4f27bSRobert Mustacchi                 {
2622eef4f27bSRobert Mustacchi                     DbgMessage(pdev, INFORM, "FlowCap: tx/rx\n");
2623eef4f27bSRobert Mustacchi 
2624eef4f27bSRobert Mustacchi                     flow_ctrl =
2625eef4f27bSRobert Mustacchi                         LM_FLOW_CONTROL_TRANSMIT_PAUSE |
2626eef4f27bSRobert Mustacchi                         LM_FLOW_CONTROL_RECEIVE_PAUSE;
2627eef4f27bSRobert Mustacchi                 }
2628eef4f27bSRobert Mustacchi                 else if(remote_phy_ad & PHY_LINK_PARTNER_ASYM_PAUSE)
2629eef4f27bSRobert Mustacchi                 {
2630eef4f27bSRobert Mustacchi                     DbgMessage(pdev, INFORM, "FlowCap: rx PAUSE\n");
2631eef4f27bSRobert Mustacchi 
2632eef4f27bSRobert Mustacchi                     flow_ctrl = LM_FLOW_CONTROL_RECEIVE_PAUSE;
2633eef4f27bSRobert Mustacchi                 }
2634eef4f27bSRobert Mustacchi             }
2635eef4f27bSRobert Mustacchi             else
2636eef4f27bSRobert Mustacchi             {
2637eef4f27bSRobert Mustacchi                 if(remote_phy_ad & PHY_LINK_PARTNER_PAUSE_CAPABLE)
2638eef4f27bSRobert Mustacchi                 {
2639eef4f27bSRobert Mustacchi                     DbgMessage(pdev, INFORM, "FlowCap: tx/rx\n");
2640eef4f27bSRobert Mustacchi 
2641eef4f27bSRobert Mustacchi                     flow_ctrl =
2642eef4f27bSRobert Mustacchi                         LM_FLOW_CONTROL_TRANSMIT_PAUSE |
2643eef4f27bSRobert Mustacchi                         LM_FLOW_CONTROL_RECEIVE_PAUSE;
2644eef4f27bSRobert Mustacchi                 }
2645eef4f27bSRobert Mustacchi             }
2646eef4f27bSRobert Mustacchi         }
2647eef4f27bSRobert Mustacchi         else if(local_phy_ad & PHY_AN_AD_ASYM_PAUSE)
2648eef4f27bSRobert Mustacchi         {
2649eef4f27bSRobert Mustacchi             if((remote_phy_ad & PHY_LINK_PARTNER_PAUSE_CAPABLE) &&
2650eef4f27bSRobert Mustacchi                 (remote_phy_ad & PHY_LINK_PARTNER_ASYM_PAUSE))
2651eef4f27bSRobert Mustacchi             {
2652eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "FlowCap: tx PAUSE\n");
2653eef4f27bSRobert Mustacchi 
2654eef4f27bSRobert Mustacchi                 flow_ctrl = LM_FLOW_CONTROL_TRANSMIT_PAUSE;
2655eef4f27bSRobert Mustacchi             }
2656eef4f27bSRobert Mustacchi         }
2657eef4f27bSRobert Mustacchi     }
2658eef4f27bSRobert Mustacchi     else
2659eef4f27bSRobert Mustacchi     {
2660eef4f27bSRobert Mustacchi         flow_ctrl = flow_control_cap;
2661eef4f27bSRobert Mustacchi     }
2662eef4f27bSRobert Mustacchi 
2663eef4f27bSRobert Mustacchi     DbgMessage(pdev, INFORM, "Flow control capabilities.\n");
2664eef4f27bSRobert Mustacchi 
2665eef4f27bSRobert Mustacchi     if(flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
2666eef4f27bSRobert Mustacchi     {
2667eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "   tx PAUSE\n");
2668eef4f27bSRobert Mustacchi     }
2669eef4f27bSRobert Mustacchi 
2670eef4f27bSRobert Mustacchi     if(flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE)
2671eef4f27bSRobert Mustacchi     {
2672eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "   rx PAUSE\n");
2673eef4f27bSRobert Mustacchi     }
2674eef4f27bSRobert Mustacchi 
2675eef4f27bSRobert Mustacchi     if(flow_ctrl == LM_FLOW_CONTROL_NONE)
2676eef4f27bSRobert Mustacchi     {
2677eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "   none.\n");
2678eef4f27bSRobert Mustacchi     }
2679eef4f27bSRobert Mustacchi 
2680eef4f27bSRobert Mustacchi     /* Enable/disable rx PAUSE. */
2681eef4f27bSRobert Mustacchi     REG_RD(pdev, emac.emac_rx_mode, &val);
2682eef4f27bSRobert Mustacchi     val &= ~EMAC_RX_MODE_FLOW_EN;
2683eef4f27bSRobert Mustacchi 
2684eef4f27bSRobert Mustacchi     if(flow_ctrl & LM_FLOW_CONTROL_RECEIVE_PAUSE)
2685eef4f27bSRobert Mustacchi     {
2686eef4f27bSRobert Mustacchi         val |= EMAC_RX_MODE_FLOW_EN;
2687eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "Enable rx PAUSE.\n");
2688eef4f27bSRobert Mustacchi     }
2689eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_rx_mode, val);
2690eef4f27bSRobert Mustacchi 
2691eef4f27bSRobert Mustacchi     /* Enable/disable tx PAUSE. */
2692eef4f27bSRobert Mustacchi     REG_RD(pdev, emac.emac_tx_mode, &val);
2693eef4f27bSRobert Mustacchi     val &= ~EMAC_TX_MODE_FLOW_EN;
2694eef4f27bSRobert Mustacchi 
2695eef4f27bSRobert Mustacchi     if(flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
2696eef4f27bSRobert Mustacchi     {
2697eef4f27bSRobert Mustacchi         val |= EMAC_TX_MODE_FLOW_EN;
2698eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "Enable tx PAUSE.\n");
2699eef4f27bSRobert Mustacchi     }
2700eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_tx_mode, val);
2701eef4f27bSRobert Mustacchi 
2702eef4f27bSRobert Mustacchi     for(idx = 0; idx < pdev->rx_info.num_rxq; idx++)
2703eef4f27bSRobert Mustacchi     {
2704eef4f27bSRobert Mustacchi         rxq = &pdev->rx_info.chain[idx];
2705eef4f27bSRobert Mustacchi         val = CTX_RD(
2706eef4f27bSRobert Mustacchi             pdev,
2707eef4f27bSRobert Mustacchi             rxq->cid_addr,
2708eef4f27bSRobert Mustacchi             WORD_ALIGNED_OFFSETOF(l2_bd_chain_context_t, l2ctx_ctx_type));
2709eef4f27bSRobert Mustacchi 
2710eef4f27bSRobert Mustacchi         /* Enable/disable RV2P wait (i.e. watermark field) for buffer post based on flow control setting. */
2711eef4f27bSRobert Mustacchi         if(flow_ctrl & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
2712eef4f27bSRobert Mustacchi         {
2713eef4f27bSRobert Mustacchi             val |= 0xFF;
2714eef4f27bSRobert Mustacchi         }
2715eef4f27bSRobert Mustacchi         else
2716eef4f27bSRobert Mustacchi         {
2717eef4f27bSRobert Mustacchi             // RV2P is checking for non-zero in this byte field
2718*55fea89dSDan Cross             val &= ~0xFF;
2719eef4f27bSRobert Mustacchi         }
2720eef4f27bSRobert Mustacchi         CTX_WR(
2721eef4f27bSRobert Mustacchi             pdev,
2722eef4f27bSRobert Mustacchi             rxq->cid_addr,
2723eef4f27bSRobert Mustacchi             WORD_ALIGNED_OFFSETOF(l2_bd_chain_context_t, l2ctx_ctx_type),
2724eef4f27bSRobert Mustacchi             val);
2725eef4f27bSRobert Mustacchi     }
2726eef4f27bSRobert Mustacchi 
2727eef4f27bSRobert Mustacchi     return flow_ctrl;
2728eef4f27bSRobert Mustacchi } /* set_mac_flow_control */
2729eef4f27bSRobert Mustacchi 
2730eef4f27bSRobert Mustacchi 
2731eef4f27bSRobert Mustacchi 
2732eef4f27bSRobert Mustacchi /*******************************************************************************
2733eef4f27bSRobert Mustacchi  * Description:
2734eef4f27bSRobert Mustacchi  *
2735eef4f27bSRobert Mustacchi  * Return:
2736eef4f27bSRobert Mustacchi  ******************************************************************************/
2737eef4f27bSRobert Mustacchi STATIC lm_status_t
get_copper_phy_link(lm_device_t * pdev,lm_medium_t * medium)2738eef4f27bSRobert Mustacchi get_copper_phy_link(
2739eef4f27bSRobert Mustacchi     lm_device_t *pdev,
2740eef4f27bSRobert Mustacchi     lm_medium_t *medium)
2741eef4f27bSRobert Mustacchi {
2742eef4f27bSRobert Mustacchi     lm_medium_t duplex;
2743eef4f27bSRobert Mustacchi     lm_medium_t speed;
2744eef4f27bSRobert Mustacchi     lm_status_t link;
2745eef4f27bSRobert Mustacchi     u32_t phy_status;
2746eef4f27bSRobert Mustacchi     u32_t remote_adv;
2747eef4f27bSRobert Mustacchi     u32_t local_adv;
2748eef4f27bSRobert Mustacchi     u32_t phy_ctrl;
2749eef4f27bSRobert Mustacchi     u32_t val;
2750eef4f27bSRobert Mustacchi 
2751eef4f27bSRobert Mustacchi     DbgMessage(pdev, INFORM, "### get_copper_phy_link\n");
2752eef4f27bSRobert Mustacchi 
2753eef4f27bSRobert Mustacchi     *medium = LM_MEDIUM_TYPE_UTP |
2754eef4f27bSRobert Mustacchi         LM_MEDIUM_SPEED_UNKNOWN |
2755eef4f27bSRobert Mustacchi         LM_MEDIUM_FULL_DUPLEX;
2756eef4f27bSRobert Mustacchi 
2757eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = FALSE;
2758eef4f27bSRobert Mustacchi 
2759eef4f27bSRobert Mustacchi     /* Check for link.  The first read returns the latched value, the
2760eef4f27bSRobert Mustacchi      * second read returns the current value. */
2761eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &phy_status);
2762eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &phy_status);
2763eef4f27bSRobert Mustacchi     if((phy_status & PHY_STATUS_LINK_PASS) == 0)
2764eef4f27bSRobert Mustacchi     {
2765eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "link down.\n");
2766eef4f27bSRobert Mustacchi 
2767eef4f27bSRobert Mustacchi         if(CHIP_REV(pdev) != CHIP_REV_FPGA)
2768eef4f27bSRobert Mustacchi         {
2769eef4f27bSRobert Mustacchi             (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0x7c00);
2770eef4f27bSRobert Mustacchi             (void) lm_mread(pdev, pdev->params.phy_addr, 0x1c, &val);
2771eef4f27bSRobert Mustacchi             if(val & 0x20)
2772eef4f27bSRobert Mustacchi             {
2773eef4f27bSRobert Mustacchi                 pdev->vars.cable_is_attached = TRUE;
2774eef4f27bSRobert Mustacchi             }
2775eef4f27bSRobert Mustacchi         }
2776eef4f27bSRobert Mustacchi 
2777eef4f27bSRobert Mustacchi         return LM_STATUS_LINK_DOWN;
2778eef4f27bSRobert Mustacchi     }
2779eef4f27bSRobert Mustacchi 
2780eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &phy_ctrl);
2781eef4f27bSRobert Mustacchi 
2782eef4f27bSRobert Mustacchi     /* Make sure the PHY control register is valid. */
2783eef4f27bSRobert Mustacchi     DbgBreakIf(phy_ctrl & (
2784eef4f27bSRobert Mustacchi         PHY_CTRL_COLLISION_TEST_ENABLE |
2785eef4f27bSRobert Mustacchi         PHY_CTRL_RESTART_AUTO_NEG |
2786eef4f27bSRobert Mustacchi         PHY_CTRL_ISOLATE_PHY |
2787eef4f27bSRobert Mustacchi         PHY_CTRL_LOOPBACK_MODE |
2788eef4f27bSRobert Mustacchi         PHY_CTRL_PHY_RESET));
2789eef4f27bSRobert Mustacchi 
2790eef4f27bSRobert Mustacchi     link = LM_STATUS_LINK_ACTIVE;
2791eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = TRUE;
2792eef4f27bSRobert Mustacchi 
2793eef4f27bSRobert Mustacchi     /* Determine duplex mode.  Link is present also means autoneg is done. */
2794eef4f27bSRobert Mustacchi     if(phy_ctrl & PHY_CTRL_AUTO_NEG_ENABLE)
2795eef4f27bSRobert Mustacchi     {
2796eef4f27bSRobert Mustacchi         /* Autonegotiation is enabled.  And since we have link, we know
2797eef4f27bSRobert Mustacchi          * autonegotiation has completed.
2798eef4f27bSRobert Mustacchi          *
2799eef4f27bSRobert Mustacchi          * Infer the link speed by figuring out the highest common speed
2800eef4f27bSRobert Mustacchi          * between us and our link partner. */
2801eef4f27bSRobert Mustacchi 
2802eef4f27bSRobert Mustacchi         /* Get local and remote 1000BASET advertisement. */
2803eef4f27bSRobert Mustacchi         (void) lm_mread(
2804*55fea89dSDan Cross                 pdev,
2805*55fea89dSDan Cross                 pdev->params.phy_addr,
2806*55fea89dSDan Cross                 PHY_1000BASET_CTRL_REG,
2807eef4f27bSRobert Mustacchi                 &local_adv);
2808eef4f27bSRobert Mustacchi         (void) lm_mread(
2809*55fea89dSDan Cross                 pdev,
2810*55fea89dSDan Cross                 pdev->params.phy_addr,
2811*55fea89dSDan Cross                 PHY_1000BASET_STATUS_REG,
2812eef4f27bSRobert Mustacchi                 &remote_adv);
2813eef4f27bSRobert Mustacchi 
2814eef4f27bSRobert Mustacchi         val = local_adv & (remote_adv >> 2);
2815eef4f27bSRobert Mustacchi         if(val & PHY_AN_AD_1000BASET_FULL)
2816eef4f27bSRobert Mustacchi         {
2817eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "detected 1gb full autoneg.\n");
2818eef4f27bSRobert Mustacchi 
2819eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_1000MBPS;
2820eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_FULL_DUPLEX;
2821eef4f27bSRobert Mustacchi         }
2822eef4f27bSRobert Mustacchi         else if(val & PHY_AN_AD_1000BASET_HALF)
2823eef4f27bSRobert Mustacchi         {
2824eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "detected 1gb half autoneg.\n");
2825eef4f27bSRobert Mustacchi 
2826eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_1000MBPS;
2827eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_HALF_DUPLEX;
2828eef4f27bSRobert Mustacchi         }
2829eef4f27bSRobert Mustacchi         else
2830eef4f27bSRobert Mustacchi         {
2831eef4f27bSRobert Mustacchi             /* Get local and remote 10/100 mb advertisement. */
2832eef4f27bSRobert Mustacchi             (void) lm_mread(
2833*55fea89dSDan Cross                     pdev,
2834*55fea89dSDan Cross                     pdev->params.phy_addr,
2835*55fea89dSDan Cross                     PHY_AN_AD_REG,
2836eef4f27bSRobert Mustacchi                     &local_adv);
2837eef4f27bSRobert Mustacchi 
2838eef4f27bSRobert Mustacchi             (void) lm_mread(
2839*55fea89dSDan Cross                     pdev,
2840*55fea89dSDan Cross                     pdev->params.phy_addr,
2841*55fea89dSDan Cross                     PHY_LINK_PARTNER_ABILITY_REG,
2842eef4f27bSRobert Mustacchi                     &remote_adv);
2843eef4f27bSRobert Mustacchi 
2844eef4f27bSRobert Mustacchi             val = local_adv & remote_adv;
2845eef4f27bSRobert Mustacchi             if(val & PHY_AN_AD_100BASETX_FULL)
2846eef4f27bSRobert Mustacchi             {
2847eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "detected 100mb full autoneg.\n");
2848eef4f27bSRobert Mustacchi 
2849eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_100MBPS;
2850eef4f27bSRobert Mustacchi                 duplex = LM_MEDIUM_FULL_DUPLEX;
2851eef4f27bSRobert Mustacchi             }
2852eef4f27bSRobert Mustacchi             else if(val & PHY_AN_AD_100BASETX_HALF)
2853eef4f27bSRobert Mustacchi             {
2854eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "detected 100mb half autoneg.\n");
2855eef4f27bSRobert Mustacchi 
2856eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_100MBPS;
2857eef4f27bSRobert Mustacchi                 duplex = LM_MEDIUM_HALF_DUPLEX;
2858eef4f27bSRobert Mustacchi             }
2859eef4f27bSRobert Mustacchi             else if(val & PHY_AN_AD_10BASET_FULL)
2860eef4f27bSRobert Mustacchi             {
2861eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "detected 10mb full autoneg.\n");
2862eef4f27bSRobert Mustacchi 
2863eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_10MBPS;
2864eef4f27bSRobert Mustacchi                 duplex = LM_MEDIUM_FULL_DUPLEX;
2865eef4f27bSRobert Mustacchi             }
2866eef4f27bSRobert Mustacchi             else if(val & PHY_AN_AD_10BASET_HALF)
2867eef4f27bSRobert Mustacchi             {
2868eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "detected 10mb half autoneg.\n");
2869eef4f27bSRobert Mustacchi 
2870eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_10MBPS;
2871eef4f27bSRobert Mustacchi                 duplex = LM_MEDIUM_HALF_DUPLEX;
2872eef4f27bSRobert Mustacchi             }
2873eef4f27bSRobert Mustacchi             else
2874eef4f27bSRobert Mustacchi             {
2875eef4f27bSRobert Mustacchi                 DbgBreakMsg("unable to determine autoneg speed.\n");
2876eef4f27bSRobert Mustacchi 
2877eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_UNKNOWN;
2878eef4f27bSRobert Mustacchi                 duplex = LM_MEDIUM_FULL_DUPLEX;
2879eef4f27bSRobert Mustacchi                 link = LM_STATUS_LINK_DOWN;
2880eef4f27bSRobert Mustacchi             }
2881eef4f27bSRobert Mustacchi         }
2882eef4f27bSRobert Mustacchi     }
2883eef4f27bSRobert Mustacchi     else
2884eef4f27bSRobert Mustacchi     {
2885eef4f27bSRobert Mustacchi         /* The link speed speed and duplex mode are forced.  Get the forced
2886eef4f27bSRobert Mustacchi          * line settings from the PHY control register. */
2887eef4f27bSRobert Mustacchi         if(phy_ctrl & PHY_CTRL_SPEED_SELECT_100MBPS)
2888eef4f27bSRobert Mustacchi         {
2889eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "PHY forced to 100mb.\n");
2890eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_100MBPS;
2891eef4f27bSRobert Mustacchi         }
2892eef4f27bSRobert Mustacchi         else if(phy_ctrl & PHY_CTRL_SPEED_SELECT_1000MBPS)
2893eef4f27bSRobert Mustacchi         {
2894eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "PHY forced to 1gb.\n");
2895eef4f27bSRobert Mustacchi 
2896eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_1000MBPS;
2897eef4f27bSRobert Mustacchi         }
2898eef4f27bSRobert Mustacchi         else
2899eef4f27bSRobert Mustacchi         {
2900eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "PHY forced to 10mb.\n");
2901eef4f27bSRobert Mustacchi 
2902eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_10MBPS;
2903eef4f27bSRobert Mustacchi         }
2904eef4f27bSRobert Mustacchi 
2905eef4f27bSRobert Mustacchi         if(phy_ctrl & PHY_CTRL_FULL_DUPLEX_MODE)
2906eef4f27bSRobert Mustacchi         {
2907eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "PHY forced to full duplex.\n");
2908eef4f27bSRobert Mustacchi 
2909eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_FULL_DUPLEX;
2910eef4f27bSRobert Mustacchi         }
2911eef4f27bSRobert Mustacchi         else
2912eef4f27bSRobert Mustacchi         {
2913eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "PHY forced to half duplex.\n");
2914eef4f27bSRobert Mustacchi 
2915eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_HALF_DUPLEX;
2916eef4f27bSRobert Mustacchi         }
2917eef4f27bSRobert Mustacchi     }
2918eef4f27bSRobert Mustacchi 
2919eef4f27bSRobert Mustacchi     *medium = LM_MEDIUM_TYPE_UTP | speed | duplex;
2920eef4f27bSRobert Mustacchi 
2921eef4f27bSRobert Mustacchi     return link;
2922eef4f27bSRobert Mustacchi } /* get_copper_phy_link */
2923eef4f27bSRobert Mustacchi 
2924eef4f27bSRobert Mustacchi 
2925eef4f27bSRobert Mustacchi 
2926eef4f27bSRobert Mustacchi /*******************************************************************************
2927eef4f27bSRobert Mustacchi  * Description:
2928eef4f27bSRobert Mustacchi  *
2929eef4f27bSRobert Mustacchi  * Return:
2930eef4f27bSRobert Mustacchi  ******************************************************************************/
2931eef4f27bSRobert Mustacchi STATIC void
init_mac_link(lm_device_t * pdev,lm_status_t link,lm_medium_t medium,lm_flow_control_t flow_ctrl)2932eef4f27bSRobert Mustacchi init_mac_link(
2933eef4f27bSRobert Mustacchi     lm_device_t *pdev,
2934eef4f27bSRobert Mustacchi     lm_status_t link,
2935eef4f27bSRobert Mustacchi     lm_medium_t medium,
2936eef4f27bSRobert Mustacchi     lm_flow_control_t flow_ctrl)
2937eef4f27bSRobert Mustacchi {
2938eef4f27bSRobert Mustacchi     u32_t val;
2939eef4f27bSRobert Mustacchi 
2940eef4f27bSRobert Mustacchi     /* Configure slot time, IPG, and 802.3 flow control. */
2941eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_tx_lengths, 0x2620);
2942eef4f27bSRobert Mustacchi     if(link == LM_STATUS_LINK_ACTIVE)
2943eef4f27bSRobert Mustacchi     {
2944eef4f27bSRobert Mustacchi         if(GET_MEDIUM_SPEED(medium) == LM_MEDIUM_SPEED_1000MBPS &&
2945eef4f27bSRobert Mustacchi             GET_MEDIUM_DUPLEX(medium) == LM_MEDIUM_HALF_DUPLEX)
2946eef4f27bSRobert Mustacchi         {
2947eef4f27bSRobert Mustacchi             REG_WR(pdev, emac.emac_tx_lengths, 0x26ff);
2948eef4f27bSRobert Mustacchi         }
2949eef4f27bSRobert Mustacchi 
2950eef4f27bSRobert Mustacchi         pdev->vars.flow_control = set_mac_flow_control(pdev, medium, flow_ctrl);
2951eef4f27bSRobert Mustacchi     }
2952eef4f27bSRobert Mustacchi 
2953eef4f27bSRobert Mustacchi     /* Configure the EMAC mode register. */
2954eef4f27bSRobert Mustacchi     REG_RD(pdev, emac.emac_mode, &val);
2955eef4f27bSRobert Mustacchi 
2956eef4f27bSRobert Mustacchi     val &= ~(EMAC_MODE_PORT | EMAC_MODE_FORCE_LINK);
2957eef4f27bSRobert Mustacchi 
2958eef4f27bSRobert Mustacchi     if(link == LM_STATUS_LINK_ACTIVE)
2959eef4f27bSRobert Mustacchi     {
2960eef4f27bSRobert Mustacchi         if(GET_MEDIUM_SPEED(medium) == LM_MEDIUM_SPEED_10MBPS)
2961eef4f27bSRobert Mustacchi         {
2962eef4f27bSRobert Mustacchi             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
2963eef4f27bSRobert Mustacchi             {
2964eef4f27bSRobert Mustacchi                 val |= EMAC_MODE_PORT_MII;
2965eef4f27bSRobert Mustacchi             }
2966eef4f27bSRobert Mustacchi             else
2967eef4f27bSRobert Mustacchi             {
2968eef4f27bSRobert Mustacchi                 /* 5708 setting. */
2969eef4f27bSRobert Mustacchi                 val |= EMAC_MODE_PORT_MII_10M;
2970eef4f27bSRobert Mustacchi             }
2971eef4f27bSRobert Mustacchi         }
2972eef4f27bSRobert Mustacchi         else if(GET_MEDIUM_SPEED(medium) == LM_MEDIUM_SPEED_100MBPS)
2973eef4f27bSRobert Mustacchi         {
2974eef4f27bSRobert Mustacchi             val |= EMAC_MODE_PORT_MII;
2975eef4f27bSRobert Mustacchi         }
2976eef4f27bSRobert Mustacchi         else
2977eef4f27bSRobert Mustacchi         {
2978eef4f27bSRobert Mustacchi             val |= EMAC_MODE_PORT_GMII;
2979eef4f27bSRobert Mustacchi         }
2980eef4f27bSRobert Mustacchi 
2981eef4f27bSRobert Mustacchi         if(GET_MEDIUM_SPEED(medium) == LM_MEDIUM_SPEED_2500MBPS)
2982eef4f27bSRobert Mustacchi         {
2983eef4f27bSRobert Mustacchi             val |= EMAC_MODE_25G_MODE;
2984eef4f27bSRobert Mustacchi         }
2985eef4f27bSRobert Mustacchi 
2986eef4f27bSRobert Mustacchi         /* We need to set the port mode to GMII when we are running in
2987eef4f27bSRobert Mustacchi          * the FPGA mode, regardless of the actual line speed. */
2988eef4f27bSRobert Mustacchi         if(CHIP_REV(pdev) == CHIP_REV_FPGA)
2989eef4f27bSRobert Mustacchi         {
2990eef4f27bSRobert Mustacchi             val &= ~EMAC_MODE_PORT;
2991eef4f27bSRobert Mustacchi             val |= EMAC_MODE_PORT_GMII;
2992eef4f27bSRobert Mustacchi         }
2993eef4f27bSRobert Mustacchi     }
2994eef4f27bSRobert Mustacchi     else
2995eef4f27bSRobert Mustacchi     {
2996eef4f27bSRobert Mustacchi         val |= EMAC_MODE_PORT_GMII;
2997eef4f27bSRobert Mustacchi     }
2998eef4f27bSRobert Mustacchi 
2999eef4f27bSRobert Mustacchi     if(GET_MEDIUM_TYPE(medium) == LM_MEDIUM_TYPE_NULL)
3000eef4f27bSRobert Mustacchi     {
3001eef4f27bSRobert Mustacchi         val |= EMAC_MODE_FORCE_LINK;
3002eef4f27bSRobert Mustacchi     }
3003eef4f27bSRobert Mustacchi 
3004eef4f27bSRobert Mustacchi     /* Set the MAC to operate in the appropriate duplex mode. */
3005eef4f27bSRobert Mustacchi     val &= ~EMAC_MODE_HALF_DUPLEX;
3006eef4f27bSRobert Mustacchi     if(GET_MEDIUM_DUPLEX(medium) == LM_MEDIUM_HALF_DUPLEX)
3007eef4f27bSRobert Mustacchi     {
3008eef4f27bSRobert Mustacchi         val |= EMAC_MODE_HALF_DUPLEX;
3009eef4f27bSRobert Mustacchi     }
3010eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_mode, val);
3011eef4f27bSRobert Mustacchi 
3012eef4f27bSRobert Mustacchi     /* Acknowledge the interrupt. */
3013eef4f27bSRobert Mustacchi     REG_WR(pdev, emac.emac_status, EMAC_STATUS_LINK_CHANGE);
3014eef4f27bSRobert Mustacchi 
3015eef4f27bSRobert Mustacchi     /* Enable phy link change attention. */
3016eef4f27bSRobert Mustacchi     if(pdev->params.phy_int_mode == PHY_INT_MODE_MI_INTERRUPT)
3017eef4f27bSRobert Mustacchi     {
3018eef4f27bSRobert Mustacchi         REG_WR(pdev, emac.emac_attention_ena, EMAC_ATTENTION_ENA_MI_INT);
3019eef4f27bSRobert Mustacchi     }
3020eef4f27bSRobert Mustacchi     else
3021eef4f27bSRobert Mustacchi     {
3022eef4f27bSRobert Mustacchi         REG_WR(pdev, emac.emac_attention_ena, EMAC_ATTENTION_ENA_LINK);
3023eef4f27bSRobert Mustacchi     }
3024eef4f27bSRobert Mustacchi 
3025eef4f27bSRobert Mustacchi     /* Enable status block link attention. */
3026eef4f27bSRobert Mustacchi     REG_RD(pdev, hc.hc_attn_bits_enable, &val);
3027eef4f27bSRobert Mustacchi     val &= ~STATUS_ATTN_BITS_LINK_STATE;
3028eef4f27bSRobert Mustacchi     if(pdev->params.link_chng_mode == LINK_CHNG_MODE_USE_STATUS_BLOCK)
3029eef4f27bSRobert Mustacchi     {
3030eef4f27bSRobert Mustacchi         val |= STATUS_ATTN_BITS_LINK_STATE;
3031eef4f27bSRobert Mustacchi     }
3032eef4f27bSRobert Mustacchi     REG_WR(pdev, hc.hc_attn_bits_enable, val);
3033eef4f27bSRobert Mustacchi 
3034eef4f27bSRobert Mustacchi     pdev->vars.medium = medium;
3035eef4f27bSRobert Mustacchi     pdev->vars.link_status = link;
3036eef4f27bSRobert Mustacchi } /* init_mac_link */
3037eef4f27bSRobert Mustacchi 
3038eef4f27bSRobert Mustacchi 
3039eef4f27bSRobert Mustacchi 
3040eef4f27bSRobert Mustacchi /*******************************************************************************
3041eef4f27bSRobert Mustacchi  * Description:
3042eef4f27bSRobert Mustacchi  *
3043eef4f27bSRobert Mustacchi  * Return:
3044eef4f27bSRobert Mustacchi  ******************************************************************************/
3045eef4f27bSRobert Mustacchi STATIC lm_status_t
serdes_fallback(lm_device_t * pdev,u8_t fallback_select)3046eef4f27bSRobert Mustacchi serdes_fallback(
3047eef4f27bSRobert Mustacchi     lm_device_t *pdev,
3048eef4f27bSRobert Mustacchi     u8_t fallback_select)
3049eef4f27bSRobert Mustacchi {
3050eef4f27bSRobert Mustacchi     u32_t intr_exp_status;
3051eef4f27bSRobert Mustacchi     u8_t fallback_to;
3052eef4f27bSRobert Mustacchi     u32_t phy_status;
3053eef4f27bSRobert Mustacchi     u32_t phy_ctrl;
3054eef4f27bSRobert Mustacchi     u32_t val;
3055eef4f27bSRobert Mustacchi     u32_t cnt;
3056eef4f27bSRobert Mustacchi 
3057eef4f27bSRobert Mustacchi     pdev->vars.serdes_fallback_status = SERDES_FALLBACK_NONE;
3058eef4f27bSRobert Mustacchi 
3059eef4f27bSRobert Mustacchi     if(fallback_select == SERDES_FALLBACK_NONE)
3060eef4f27bSRobert Mustacchi     {
3061eef4f27bSRobert Mustacchi         return LM_STATUS_LINK_DOWN;
3062eef4f27bSRobert Mustacchi     }
3063eef4f27bSRobert Mustacchi 
3064eef4f27bSRobert Mustacchi     /* See if the cable is connected. */
3065eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0x7c00);
3066eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x1c, &val);
3067eef4f27bSRobert Mustacchi 
3068eef4f27bSRobert Mustacchi     /* We think the cable is not attached, set up the serdes to
3069eef4f27bSRobert Mustacchi      * autoneg as the default. */
3070eef4f27bSRobert Mustacchi     if(!(val & 0x10))       /* SIG_DETECT */
3071eef4f27bSRobert Mustacchi     {
3072eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "no cable, default to autoneg.\n");
3073eef4f27bSRobert Mustacchi 
3074eef4f27bSRobert Mustacchi         (void) lm_mwrite(
3075*55fea89dSDan Cross             pdev,
3076eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
3077eef4f27bSRobert Mustacchi             PHY_CTRL_REG,
3078eef4f27bSRobert Mustacchi             PHY_CTRL_AUTO_NEG_ENABLE);
3079eef4f27bSRobert Mustacchi 
3080eef4f27bSRobert Mustacchi         return LM_STATUS_LINK_DOWN;
3081eef4f27bSRobert Mustacchi     }
3082eef4f27bSRobert Mustacchi 
3083eef4f27bSRobert Mustacchi     /* Read the interrupt expansion register to see if rudi_c is set.
3084eef4f27bSRobert Mustacchi      * rudi_c is set when we are receiving config words which means
3085eef4f27bSRobert Mustacchi      * the link partner is attempting to autonegotiate.
3086eef4f27bSRobert Mustacchi      *
3087eef4f27bSRobert Mustacchi      * When the link partner is attempting to autonegotiate and we
3088eef4f27bSRobert Mustacchi      * are not able to get linke, it could mean our transmit cable
3089eef4f27bSRobert Mustacchi      * is not plugged in.  In this case we don't want to fallback
3090eef4f27bSRobert Mustacchi      * to the force mode.  We want to remain in autonegotiation mode. */
3091eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0x0f01);
3092eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x15, &intr_exp_status);
3093eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x15, &intr_exp_status);
3094eef4f27bSRobert Mustacchi 
3095eef4f27bSRobert Mustacchi     /* See if autoneg is enabled and the remote is not sending us
3096eef4f27bSRobert Mustacchi      * configs.  If this is the case and link is currently down, we
3097eef4f27bSRobert Mustacchi      * will switch to the force mode and disable autonegotiation.
3098eef4f27bSRobert Mustacchi      *
3099eef4f27bSRobert Mustacchi      * If we are current in the forced mode or the link partner is
3100eef4f27bSRobert Mustacchi      * sending use configs, we'll enable autoneg and restart it. */
3101eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &phy_ctrl);
3102eef4f27bSRobert Mustacchi     if((phy_ctrl & PHY_CTRL_AUTO_NEG_ENABLE) && !(intr_exp_status & 0x20))
3103eef4f27bSRobert Mustacchi     {
3104eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "switch to force mode - 1G full\n");
3105eef4f27bSRobert Mustacchi 
3106eef4f27bSRobert Mustacchi         (void) lm_mwrite(
3107*55fea89dSDan Cross             pdev,
3108eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
3109eef4f27bSRobert Mustacchi             PHY_CTRL_REG,
3110eef4f27bSRobert Mustacchi             PHY_CTRL_SPEED_SELECT_1000MBPS | PHY_CTRL_FULL_DUPLEX_MODE);
3111eef4f27bSRobert Mustacchi 
3112eef4f27bSRobert Mustacchi         fallback_to = SERDES_FALLBACK_1G;
3113eef4f27bSRobert Mustacchi     }
3114eef4f27bSRobert Mustacchi     else
3115eef4f27bSRobert Mustacchi     {
3116eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "switch to autoneg mode - 1G full\n");
3117eef4f27bSRobert Mustacchi 
3118eef4f27bSRobert Mustacchi         /* Switch to autoneg mode. */
3119eef4f27bSRobert Mustacchi         (void) lm_mwrite(
3120*55fea89dSDan Cross             pdev,
3121eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
3122eef4f27bSRobert Mustacchi             PHY_CTRL_REG,
3123eef4f27bSRobert Mustacchi             PHY_CTRL_AUTO_NEG_ENABLE | PHY_CTRL_RESTART_AUTO_NEG);
3124eef4f27bSRobert Mustacchi 
3125eef4f27bSRobert Mustacchi         fallback_to = SERDES_FALLBACK_NONE;
3126eef4f27bSRobert Mustacchi     }
3127eef4f27bSRobert Mustacchi 
3128eef4f27bSRobert Mustacchi     for(cnt = 0; cnt < 100; cnt++)
3129eef4f27bSRobert Mustacchi     {
3130eef4f27bSRobert Mustacchi         mm_wait(pdev, 10);
3131eef4f27bSRobert Mustacchi     }
3132eef4f27bSRobert Mustacchi 
3133eef4f27bSRobert Mustacchi     phy_status = mii_get_serdes_link_status(pdev);
3134eef4f27bSRobert Mustacchi 
3135eef4f27bSRobert Mustacchi     if(phy_status & PHY_STATUS_LINK_PASS)
3136eef4f27bSRobert Mustacchi     {
3137eef4f27bSRobert Mustacchi         pdev->vars.serdes_fallback_status = fallback_to;
3138eef4f27bSRobert Mustacchi 
3139eef4f27bSRobert Mustacchi         return LM_STATUS_LINK_ACTIVE;
3140eef4f27bSRobert Mustacchi     }
3141eef4f27bSRobert Mustacchi 
3142eef4f27bSRobert Mustacchi     return LM_STATUS_LINK_DOWN;
3143eef4f27bSRobert Mustacchi } /* serdes_fallback */
3144eef4f27bSRobert Mustacchi 
3145eef4f27bSRobert Mustacchi 
3146eef4f27bSRobert Mustacchi 
3147eef4f27bSRobert Mustacchi /*******************************************************************************
3148eef4f27bSRobert Mustacchi  * Description:
3149eef4f27bSRobert Mustacchi  *
3150eef4f27bSRobert Mustacchi  * Return:
3151eef4f27bSRobert Mustacchi  ******************************************************************************/
3152eef4f27bSRobert Mustacchi STATIC lm_status_t
get_5708_serdes_link(lm_device_t * pdev,lm_medium_t * medium)3153eef4f27bSRobert Mustacchi get_5708_serdes_link(
3154eef4f27bSRobert Mustacchi     lm_device_t *pdev,
3155eef4f27bSRobert Mustacchi     lm_medium_t *medium)
3156eef4f27bSRobert Mustacchi {
3157eef4f27bSRobert Mustacchi     u8_t restarted_autoneg;
3158eef4f27bSRobert Mustacchi     lm_medium_t duplex;
3159eef4f27bSRobert Mustacchi     lm_medium_t speed;
3160eef4f27bSRobert Mustacchi     lm_status_t link;
3161eef4f27bSRobert Mustacchi     u32_t val;
3162eef4f27bSRobert Mustacchi     u32_t idx;
3163eef4f27bSRobert Mustacchi 
3164eef4f27bSRobert Mustacchi     *medium = LM_MEDIUM_TYPE_FIBER |
3165eef4f27bSRobert Mustacchi         LM_MEDIUM_SPEED_UNKNOWN |
3166eef4f27bSRobert Mustacchi         LM_MEDIUM_FULL_DUPLEX;
3167eef4f27bSRobert Mustacchi 
3168eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = FALSE;
3169eef4f27bSRobert Mustacchi 
3170eef4f27bSRobert Mustacchi     /* Check for link.  The first read returns the latched value, the
3171eef4f27bSRobert Mustacchi      * second read returns the current value. */
3172eef4f27bSRobert Mustacchi     (void) lm_mread(
3173*55fea89dSDan Cross             pdev,
3174*55fea89dSDan Cross             pdev->params.phy_addr,
3175*55fea89dSDan Cross             MII_REG(serdes_reg_t, mii_status),
3176eef4f27bSRobert Mustacchi             &val);
3177eef4f27bSRobert Mustacchi     (void) lm_mread(
3178*55fea89dSDan Cross             pdev,
3179*55fea89dSDan Cross             pdev->params.phy_addr,
3180*55fea89dSDan Cross             MII_REG(serdes_reg_t, mii_status),
3181eef4f27bSRobert Mustacchi             &val);
3182eef4f27bSRobert Mustacchi 
3183eef4f27bSRobert Mustacchi     /* CQ#23742 - Link status in the status block and the link status
3184eef4f27bSRobert Mustacchi      * in the mii_status are not consistent.  mii_status appears to
3185eef4f27bSRobert Mustacchi      * return invalid value.  Added a workaround here. */
3186eef4f27bSRobert Mustacchi     for(idx = 0; idx < 10 && val == 0; idx++)
3187eef4f27bSRobert Mustacchi     {
3188eef4f27bSRobert Mustacchi         mm_wait(pdev, 10);
3189eef4f27bSRobert Mustacchi 
3190eef4f27bSRobert Mustacchi         (void) lm_mread(
3191*55fea89dSDan Cross                 pdev,
3192*55fea89dSDan Cross                 pdev->params.phy_addr,
3193*55fea89dSDan Cross                 MII_REG(serdes_reg_t, mii_status),
3194eef4f27bSRobert Mustacchi                 &val);
3195eef4f27bSRobert Mustacchi     }
3196eef4f27bSRobert Mustacchi 
3197eef4f27bSRobert Mustacchi     if((val & MII_STAT_LINK_STATUS) == 0)
3198eef4f27bSRobert Mustacchi     {
3199eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "serdes link down.\n");
3200eef4f27bSRobert Mustacchi 
3201eef4f27bSRobert Mustacchi         pdev->vars.cable_is_attached = FALSE;
3202eef4f27bSRobert Mustacchi 
3203eef4f27bSRobert Mustacchi         return LM_STATUS_LINK_DOWN;
3204eef4f27bSRobert Mustacchi     }
3205eef4f27bSRobert Mustacchi 
3206eef4f27bSRobert Mustacchi     link = LM_STATUS_LINK_ACTIVE;
3207eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = TRUE;
3208eef4f27bSRobert Mustacchi 
3209eef4f27bSRobert Mustacchi     /* Determine duplex mode.  Link is present also means autoneg is done. */
3210eef4f27bSRobert Mustacchi     (void) lm_mread(
3211*55fea89dSDan Cross             pdev,
3212*55fea89dSDan Cross             pdev->params.phy_addr,
3213*55fea89dSDan Cross             MII_REG(serdes_reg_t, mii_ctrl),
3214eef4f27bSRobert Mustacchi             &val);
3215eef4f27bSRobert Mustacchi     if(val & MII_CTRL_ANEG_ENA)
3216eef4f27bSRobert Mustacchi     {
3217eef4f27bSRobert Mustacchi         /* Select Bank 0. */
3218eef4f27bSRobert Mustacchi         (void) lm_mwrite(
3219*55fea89dSDan Cross             pdev,
3220eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
3221eef4f27bSRobert Mustacchi             MII_REG(serdes_reg_t, mii_block_addr),
3222eef4f27bSRobert Mustacchi             MII_BLK_ADDR_DIGITAL);
3223eef4f27bSRobert Mustacchi 
3224eef4f27bSRobert Mustacchi         /* Get the negotiated speed and duplex mode. */
3225eef4f27bSRobert Mustacchi         (void) lm_mread(
3226*55fea89dSDan Cross             pdev,
3227eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
3228eef4f27bSRobert Mustacchi             0x10+MII_REG(serdes_digital_reg_t, mii_1000x_stat1),
3229eef4f27bSRobert Mustacchi             &val);
3230eef4f27bSRobert Mustacchi         switch(val & MII_1000X_STAT1_SPEED)
3231eef4f27bSRobert Mustacchi         {
3232eef4f27bSRobert Mustacchi             case MII_1000X_STAT1_SPEED_2G5:
3233eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "serdes autoneg to 2.5gb.\n");
3234eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_2500MBPS;
3235eef4f27bSRobert Mustacchi                 break;
3236eef4f27bSRobert Mustacchi 
3237eef4f27bSRobert Mustacchi             case MII_1000X_STAT1_SPEED_1G:
3238eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "serdes autoneg to 1gb.\n");
3239eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_1000MBPS;
3240eef4f27bSRobert Mustacchi                 break;
3241eef4f27bSRobert Mustacchi 
3242eef4f27bSRobert Mustacchi             case MII_1000X_STAT1_SPEED_100:
3243eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "serdes autoneg to 100mb.\n");
3244eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_100MBPS;
3245eef4f27bSRobert Mustacchi                 break;
3246eef4f27bSRobert Mustacchi 
3247eef4f27bSRobert Mustacchi             case MII_1000X_STAT1_SPEED_10:
3248eef4f27bSRobert Mustacchi             default:
3249eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "serdes autoneg to 10mb.\n");
3250eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_10MBPS;
3251eef4f27bSRobert Mustacchi                 break;
3252eef4f27bSRobert Mustacchi         }
3253eef4f27bSRobert Mustacchi 
3254eef4f27bSRobert Mustacchi         /* Get the duplex mode. */
3255eef4f27bSRobert Mustacchi         duplex = LM_MEDIUM_FULL_DUPLEX;
3256eef4f27bSRobert Mustacchi         if(val & MII_1000X_STAT1_DUPLEX)
3257eef4f27bSRobert Mustacchi         {
3258eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "serdes autoneg to full duplex.\n");
3259eef4f27bSRobert Mustacchi         }
3260eef4f27bSRobert Mustacchi         else
3261eef4f27bSRobert Mustacchi         {
3262eef4f27bSRobert Mustacchi             (void) lm_mread(
3263*55fea89dSDan Cross                     pdev,
3264*55fea89dSDan Cross                     pdev->params.phy_addr,
3265*55fea89dSDan Cross                     MII_REG(serdes_reg_t, mii_status),
3266eef4f27bSRobert Mustacchi                     &val);
3267eef4f27bSRobert Mustacchi             if(val & MII_STAT_ANEG_CMPL)
3268eef4f27bSRobert Mustacchi             {
3269eef4f27bSRobert Mustacchi                 duplex = LM_MEDIUM_HALF_DUPLEX;
3270eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "serdes autoneg to half duplex.\n");
3271eef4f27bSRobert Mustacchi             }
3272eef4f27bSRobert Mustacchi             else
3273eef4f27bSRobert Mustacchi             {
3274eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "serdes autoneg to full duplex.\n");
3275eef4f27bSRobert Mustacchi             }
3276eef4f27bSRobert Mustacchi         }
3277eef4f27bSRobert Mustacchi 
3278eef4f27bSRobert Mustacchi         /* Set up pre-emphasis for a backplane application. */
3279eef4f27bSRobert Mustacchi         if(pdev->hw_info.nvm_hw_config & SHARED_HW_CFG_BACKPLANE_APP)
3280eef4f27bSRobert Mustacchi         {
3281eef4f27bSRobert Mustacchi             restarted_autoneg = set_5708_serdes_pre_emphasis(
3282eef4f27bSRobert Mustacchi                 pdev,
3283eef4f27bSRobert Mustacchi                 pdev->params.serdes_pre_emphasis);
3284eef4f27bSRobert Mustacchi 
3285eef4f27bSRobert Mustacchi             if(restarted_autoneg)
3286eef4f27bSRobert Mustacchi             {
3287eef4f27bSRobert Mustacchi                 speed = LM_MEDIUM_SPEED_UNKNOWN;
3288eef4f27bSRobert Mustacchi                 duplex = LM_MEDIUM_FULL_DUPLEX;
3289eef4f27bSRobert Mustacchi                 link = LM_STATUS_LINK_DOWN;
3290eef4f27bSRobert Mustacchi             }
3291eef4f27bSRobert Mustacchi         }
3292eef4f27bSRobert Mustacchi     }
3293eef4f27bSRobert Mustacchi     else
3294eef4f27bSRobert Mustacchi     {
3295eef4f27bSRobert Mustacchi         /* Determine the forced link settings. */
3296eef4f27bSRobert Mustacchi         if(val & MII_CTRL_MANUAL_FORCE_2500)
3297eef4f27bSRobert Mustacchi         {
3298eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "serdes forced to 2.5gb.\n");
3299eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_2500MBPS;
3300eef4f27bSRobert Mustacchi         }
3301eef4f27bSRobert Mustacchi         else if(val & MII_CTRL_MANUAL_SPD1)
3302eef4f27bSRobert Mustacchi         {
3303eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "serdes forced to 1gb.\n");
3304eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_1000MBPS;
3305eef4f27bSRobert Mustacchi         }
3306eef4f27bSRobert Mustacchi         else if(val & MII_CTRL_MANUAL_SPD0)
3307eef4f27bSRobert Mustacchi         {
3308eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "serdes forced to 100mb.\n");
3309eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_100MBPS;
3310eef4f27bSRobert Mustacchi         }
3311eef4f27bSRobert Mustacchi         else
3312eef4f27bSRobert Mustacchi         {
3313eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "serdes forced to 10mb.\n");
3314eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_10MBPS;
3315eef4f27bSRobert Mustacchi         }
3316eef4f27bSRobert Mustacchi 
3317eef4f27bSRobert Mustacchi         if(val & MII_CTRL_DUPLEX_MODE)
3318eef4f27bSRobert Mustacchi         {
3319eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "serdes forced to full duplex.\n");
3320eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_FULL_DUPLEX;
3321eef4f27bSRobert Mustacchi         }
3322eef4f27bSRobert Mustacchi         else
3323eef4f27bSRobert Mustacchi         {
3324eef4f27bSRobert Mustacchi             DbgMessage(pdev, INFORM, "serdes forced to half duplex.\n");
3325eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_HALF_DUPLEX;
3326eef4f27bSRobert Mustacchi         }
3327eef4f27bSRobert Mustacchi     }
3328eef4f27bSRobert Mustacchi 
3329eef4f27bSRobert Mustacchi     *medium = LM_MEDIUM_TYPE_FIBER | speed | duplex;
3330eef4f27bSRobert Mustacchi 
3331eef4f27bSRobert Mustacchi     return link;
3332eef4f27bSRobert Mustacchi } /* get_5708_serdes_link */
3333eef4f27bSRobert Mustacchi 
3334eef4f27bSRobert Mustacchi 
3335eef4f27bSRobert Mustacchi 
3336eef4f27bSRobert Mustacchi /*******************************************************************************
3337eef4f27bSRobert Mustacchi  * Description:
3338eef4f27bSRobert Mustacchi  *
3339eef4f27bSRobert Mustacchi  * Return:
3340eef4f27bSRobert Mustacchi  ******************************************************************************/
3341eef4f27bSRobert Mustacchi STATIC lm_status_t
get_5709_serdes_link(lm_device_t * pdev,lm_medium_t * medium)3342eef4f27bSRobert Mustacchi get_5709_serdes_link(
3343eef4f27bSRobert Mustacchi     lm_device_t *pdev,
3344eef4f27bSRobert Mustacchi     lm_medium_t *medium)
3345eef4f27bSRobert Mustacchi {
3346eef4f27bSRobert Mustacchi     lm_medium_t duplex = LM_MEDIUM_FULL_DUPLEX;
3347eef4f27bSRobert Mustacchi     lm_medium_t speed = LM_MEDIUM_SPEED_UNKNOWN;
3348eef4f27bSRobert Mustacchi     lm_status_t link = LM_STATUS_LINK_UNKNOWN;
3349eef4f27bSRobert Mustacchi     u32_t mac_status;
3350eef4f27bSRobert Mustacchi     u32_t val;
3351eef4f27bSRobert Mustacchi 
3352eef4f27bSRobert Mustacchi     *medium = LM_MEDIUM_TYPE_FIBER |
3353eef4f27bSRobert Mustacchi         LM_MEDIUM_SPEED_UNKNOWN |
3354eef4f27bSRobert Mustacchi         LM_MEDIUM_FULL_DUPLEX;
3355eef4f27bSRobert Mustacchi 
3356eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = FALSE;
3357eef4f27bSRobert Mustacchi 
3358eef4f27bSRobert Mustacchi     /* select gp_status block. */
3359eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8120);
3360eef4f27bSRobert Mustacchi 
3361eef4f27bSRobert Mustacchi     /* get status. */
3362eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x1b, &val);
3363eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x1b, &val);  /* is this needed? */
3364eef4f27bSRobert Mustacchi 
3365eef4f27bSRobert Mustacchi     /* sometimes when we get a link event, mii register 0x1b does not
3366eef4f27bSRobert Mustacchi      * reflect the current link status but mac_status does reflect the
3367eef4f27bSRobert Mustacchi      * correct link status. */
3368eef4f27bSRobert Mustacchi     REG_RD(pdev, emac.emac_status, &mac_status);
3369eef4f27bSRobert Mustacchi 
3370eef4f27bSRobert Mustacchi     /* link down. */
3371eef4f27bSRobert Mustacchi     if((val & 0x4) == 0 && (mac_status & EMAC_STATUS_LINK) == 0)
3372eef4f27bSRobert Mustacchi     {
3373eef4f27bSRobert Mustacchi         return LM_STATUS_LINK_DOWN;
3374eef4f27bSRobert Mustacchi     }
3375eef4f27bSRobert Mustacchi 
3376eef4f27bSRobert Mustacchi     link = LM_STATUS_LINK_ACTIVE;
3377eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = TRUE;
3378*55fea89dSDan Cross 
3379eef4f27bSRobert Mustacchi     /* select combo ieee0 block. */
3380eef4f27bSRobert Mustacchi     (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0xffe0);
3381eef4f27bSRobert Mustacchi 
3382eef4f27bSRobert Mustacchi     /* phy_ctrl register. */
3383eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, 0x10, &val);
3384eef4f27bSRobert Mustacchi 
3385eef4f27bSRobert Mustacchi     if(val & 0x1000)
3386eef4f27bSRobert Mustacchi     {
3387eef4f27bSRobert Mustacchi         /* select gp_status block. */
3388eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1f, 0x8120);
3389eef4f27bSRobert Mustacchi 
3390eef4f27bSRobert Mustacchi         /* get status. */
3391eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x1b, &val);
3392eef4f27bSRobert Mustacchi 
3393eef4f27bSRobert Mustacchi         /* duplex mode. */
3394eef4f27bSRobert Mustacchi         if(val & 0x8)
3395eef4f27bSRobert Mustacchi         {
3396eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_FULL_DUPLEX;
3397eef4f27bSRobert Mustacchi         }
3398eef4f27bSRobert Mustacchi         else
3399eef4f27bSRobert Mustacchi         {
3400eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_HALF_DUPLEX;
3401eef4f27bSRobert Mustacchi         }
3402eef4f27bSRobert Mustacchi 
3403eef4f27bSRobert Mustacchi         /* Determine autoneg speed. */
3404eef4f27bSRobert Mustacchi         val = (val >> 8) & 0x3f;
3405eef4f27bSRobert Mustacchi         if(val == 0)
3406eef4f27bSRobert Mustacchi         {
3407eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_10MBPS;
3408eef4f27bSRobert Mustacchi         }
3409eef4f27bSRobert Mustacchi         else if(val == 1)
3410eef4f27bSRobert Mustacchi         {
3411eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_100MBPS;
3412eef4f27bSRobert Mustacchi         }
3413eef4f27bSRobert Mustacchi         else if(val == 2 || val == 13)
3414eef4f27bSRobert Mustacchi         {
3415eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_1000MBPS;
3416eef4f27bSRobert Mustacchi         }
3417eef4f27bSRobert Mustacchi         else if(val == 3)
3418eef4f27bSRobert Mustacchi         {
3419eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_2500MBPS;
3420eef4f27bSRobert Mustacchi         }
3421eef4f27bSRobert Mustacchi         else
3422eef4f27bSRobert Mustacchi         {
3423eef4f27bSRobert Mustacchi             DbgBreakMsg("unknown link speed status.\n");
3424eef4f27bSRobert Mustacchi         }
3425eef4f27bSRobert Mustacchi     }
3426eef4f27bSRobert Mustacchi     else
3427eef4f27bSRobert Mustacchi     {
3428eef4f27bSRobert Mustacchi         /* get forced duplex mode. */
3429eef4f27bSRobert Mustacchi         if(val & 0x100)
3430eef4f27bSRobert Mustacchi         {
3431eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_FULL_DUPLEX;
3432eef4f27bSRobert Mustacchi         }
3433eef4f27bSRobert Mustacchi         else
3434eef4f27bSRobert Mustacchi         {
3435eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_HALF_DUPLEX;
3436eef4f27bSRobert Mustacchi         }
3437eef4f27bSRobert Mustacchi 
3438eef4f27bSRobert Mustacchi         /* get forced speed. */
3439eef4f27bSRobert Mustacchi         if(val & 0x20)
3440eef4f27bSRobert Mustacchi         {
3441eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_2500MBPS;
3442eef4f27bSRobert Mustacchi         }
3443eef4f27bSRobert Mustacchi         else if((val & 0x2040) == 0)
3444eef4f27bSRobert Mustacchi         {
3445eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_10MBPS;
3446eef4f27bSRobert Mustacchi         }
3447eef4f27bSRobert Mustacchi         else if((val & 0x2040) == 0x2000)
3448eef4f27bSRobert Mustacchi         {
3449eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_100MBPS;
3450eef4f27bSRobert Mustacchi         }
3451eef4f27bSRobert Mustacchi         else if((val & 0x2040) == 0x40)
3452eef4f27bSRobert Mustacchi         {
3453eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_1000MBPS;
3454eef4f27bSRobert Mustacchi         }
3455eef4f27bSRobert Mustacchi         else
3456eef4f27bSRobert Mustacchi         {
3457eef4f27bSRobert Mustacchi             DbgBreakMsg("unknown speed.\n");
3458eef4f27bSRobert Mustacchi         }
3459eef4f27bSRobert Mustacchi     }
3460eef4f27bSRobert Mustacchi 
3461eef4f27bSRobert Mustacchi     *medium = LM_MEDIUM_TYPE_FIBER | speed | duplex;
3462eef4f27bSRobert Mustacchi 
3463eef4f27bSRobert Mustacchi     return link;
3464eef4f27bSRobert Mustacchi } /* get_5709_serdes_link */
3465eef4f27bSRobert Mustacchi 
3466eef4f27bSRobert Mustacchi 
3467eef4f27bSRobert Mustacchi 
3468eef4f27bSRobert Mustacchi /*******************************************************************************
3469eef4f27bSRobert Mustacchi  * Description:
3470eef4f27bSRobert Mustacchi  *
3471eef4f27bSRobert Mustacchi  * Return:
3472eef4f27bSRobert Mustacchi  ******************************************************************************/
3473eef4f27bSRobert Mustacchi STATIC lm_status_t
get_5706_serdes_link(lm_device_t * pdev,lm_medium_t * medium)3474eef4f27bSRobert Mustacchi get_5706_serdes_link(
3475eef4f27bSRobert Mustacchi     lm_device_t *pdev,
3476eef4f27bSRobert Mustacchi     lm_medium_t *medium)
3477eef4f27bSRobert Mustacchi {
3478eef4f27bSRobert Mustacchi     lm_status_t link;
3479eef4f27bSRobert Mustacchi     u32_t phy_status;
3480eef4f27bSRobert Mustacchi     u32_t remote_adv;
3481eef4f27bSRobert Mustacchi     u32_t local_adv;
3482eef4f27bSRobert Mustacchi     u32_t phy_ctrl;
3483eef4f27bSRobert Mustacchi     u32_t val;
3484eef4f27bSRobert Mustacchi 
3485eef4f27bSRobert Mustacchi     *medium = LM_MEDIUM_TYPE_FIBER;
3486eef4f27bSRobert Mustacchi 
3487eef4f27bSRobert Mustacchi     phy_status = mii_get_serdes_link_status(pdev);
3488eef4f27bSRobert Mustacchi 
3489eef4f27bSRobert Mustacchi     if(phy_status & PHY_STATUS_LINK_PASS)
3490eef4f27bSRobert Mustacchi     {
3491eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "serdes link up.\n");
3492eef4f27bSRobert Mustacchi 
3493eef4f27bSRobert Mustacchi         link = LM_STATUS_LINK_ACTIVE;
3494eef4f27bSRobert Mustacchi         *medium |= LM_MEDIUM_SPEED_1000MBPS;
3495eef4f27bSRobert Mustacchi 
3496eef4f27bSRobert Mustacchi         /* Determine duplex mode.  Link is present also means
3497eef4f27bSRobert Mustacchi          * autoneg is done. */
3498eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &phy_ctrl);
3499eef4f27bSRobert Mustacchi         if(phy_ctrl & PHY_CTRL_AUTO_NEG_ENABLE)
3500eef4f27bSRobert Mustacchi         {
3501eef4f27bSRobert Mustacchi             (void) lm_mread(
3502*55fea89dSDan Cross                     pdev,
3503*55fea89dSDan Cross                     pdev->params.phy_addr,
3504*55fea89dSDan Cross                     PHY_AN_AD_REG,
3505eef4f27bSRobert Mustacchi                     &local_adv);
3506eef4f27bSRobert Mustacchi             (void) lm_mread(
3507*55fea89dSDan Cross                     pdev,
3508*55fea89dSDan Cross                     pdev->params.phy_addr,
3509*55fea89dSDan Cross                     PHY_LINK_PARTNER_ABILITY_REG,
3510eef4f27bSRobert Mustacchi                     &remote_adv);
3511eef4f27bSRobert Mustacchi 
3512eef4f27bSRobert Mustacchi             val = local_adv & remote_adv;
3513eef4f27bSRobert Mustacchi             if(val & PHY_AN_AD_1000X_FULL_DUPLEX)
3514eef4f27bSRobert Mustacchi             {
3515eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "serdes autoneg to full duplex.\n");
3516eef4f27bSRobert Mustacchi 
3517eef4f27bSRobert Mustacchi                 *medium |= LM_MEDIUM_FULL_DUPLEX;
3518eef4f27bSRobert Mustacchi             }
3519eef4f27bSRobert Mustacchi             else
3520eef4f27bSRobert Mustacchi             {
3521eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "serdes autoneg to half duplex.\n");
3522eef4f27bSRobert Mustacchi 
3523eef4f27bSRobert Mustacchi                 *medium |= LM_MEDIUM_HALF_DUPLEX;
3524eef4f27bSRobert Mustacchi             }
3525eef4f27bSRobert Mustacchi 
3526eef4f27bSRobert Mustacchi             pdev->vars.serdes_fallback_status = SERDES_FALLBACK_NONE;
3527eef4f27bSRobert Mustacchi         }
3528eef4f27bSRobert Mustacchi         else
3529eef4f27bSRobert Mustacchi         {
3530eef4f27bSRobert Mustacchi             if(phy_ctrl & PHY_CTRL_FULL_DUPLEX_MODE)
3531eef4f27bSRobert Mustacchi             {
3532eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "serdes forced to full duplex.\n");
3533eef4f27bSRobert Mustacchi 
3534eef4f27bSRobert Mustacchi                 *medium |= LM_MEDIUM_FULL_DUPLEX;
3535eef4f27bSRobert Mustacchi             }
3536eef4f27bSRobert Mustacchi             else
3537eef4f27bSRobert Mustacchi             {
3538eef4f27bSRobert Mustacchi                 DbgMessage(pdev, INFORM, "serdes forced to half duplex.\n");
3539eef4f27bSRobert Mustacchi 
3540eef4f27bSRobert Mustacchi                 *medium |= LM_MEDIUM_HALF_DUPLEX;
3541eef4f27bSRobert Mustacchi             }
3542eef4f27bSRobert Mustacchi 
3543eef4f27bSRobert Mustacchi             if(pdev->vars.serdes_fallback_select)
3544eef4f27bSRobert Mustacchi             {
3545eef4f27bSRobert Mustacchi                 pdev->vars.serdes_fallback_status = SERDES_FALLBACK_1G;
3546eef4f27bSRobert Mustacchi             }
3547eef4f27bSRobert Mustacchi         }
3548eef4f27bSRobert Mustacchi     }
3549eef4f27bSRobert Mustacchi     else
3550eef4f27bSRobert Mustacchi     {
3551eef4f27bSRobert Mustacchi         DbgMessage(pdev, INFORM, "serdes link down.\n");
3552eef4f27bSRobert Mustacchi 
3553eef4f27bSRobert Mustacchi         /* This routine is called only when the link is down. */
3554eef4f27bSRobert Mustacchi         link = serdes_fallback(pdev, pdev->vars.serdes_fallback_select);
3555eef4f27bSRobert Mustacchi     }
3556eef4f27bSRobert Mustacchi 
3557eef4f27bSRobert Mustacchi     /* cq#30504 - restore the tx driver current so we can get link. */
3558eef4f27bSRobert Mustacchi     if(pdev->vars.bcm5706s_tx_drv_cur)
3559eef4f27bSRobert Mustacchi     {
3560eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x17, 0x0f03);
3561eef4f27bSRobert Mustacchi 
3562eef4f27bSRobert Mustacchi         (void) lm_mwrite(
3563eef4f27bSRobert Mustacchi             pdev,
3564eef4f27bSRobert Mustacchi             pdev->params.phy_addr,
3565eef4f27bSRobert Mustacchi             0x15,
3566eef4f27bSRobert Mustacchi             pdev->vars.bcm5706s_tx_drv_cur);
3567eef4f27bSRobert Mustacchi 
3568eef4f27bSRobert Mustacchi         pdev->vars.bcm5706s_tx_drv_cur = 0;
3569eef4f27bSRobert Mustacchi     }
3570eef4f27bSRobert Mustacchi 
3571eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = TRUE;
3572eef4f27bSRobert Mustacchi 
3573eef4f27bSRobert Mustacchi     if(link == LM_STATUS_LINK_DOWN)
3574eef4f27bSRobert Mustacchi     {
3575eef4f27bSRobert Mustacchi         (void) lm_mwrite(pdev, pdev->params.phy_addr, 0x1c, 0x7c00);
3576eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, 0x1c, &val);
3577eef4f27bSRobert Mustacchi         if(!(val & 0x10))
3578eef4f27bSRobert Mustacchi         {
3579eef4f27bSRobert Mustacchi             pdev->vars.cable_is_attached = FALSE;
3580eef4f27bSRobert Mustacchi         }
3581eef4f27bSRobert Mustacchi     }
3582eef4f27bSRobert Mustacchi 
3583eef4f27bSRobert Mustacchi     return link;
3584eef4f27bSRobert Mustacchi } /* get_5706_serdes_link */
3585eef4f27bSRobert Mustacchi 
3586eef4f27bSRobert Mustacchi 
3587eef4f27bSRobert Mustacchi 
3588eef4f27bSRobert Mustacchi /*******************************************************************************
3589eef4f27bSRobert Mustacchi  * Description:
3590eef4f27bSRobert Mustacchi  *
3591eef4f27bSRobert Mustacchi  * Return:
3592eef4f27bSRobert Mustacchi  ******************************************************************************/
3593eef4f27bSRobert Mustacchi STATIC lm_status_t
get_remote_phy_link(lm_device_t * pdev,lm_medium_t * medium)3594eef4f27bSRobert Mustacchi get_remote_phy_link(
3595eef4f27bSRobert Mustacchi     lm_device_t *pdev,
3596eef4f27bSRobert Mustacchi     lm_medium_t *medium)
3597eef4f27bSRobert Mustacchi {
3598eef4f27bSRobert Mustacchi     u32_t remote_phy_link;
3599eef4f27bSRobert Mustacchi     lm_medium_t duplex;
3600eef4f27bSRobert Mustacchi     lm_medium_t speed;
3601eef4f27bSRobert Mustacchi     lm_status_t link;
3602eef4f27bSRobert Mustacchi 
3603eef4f27bSRobert Mustacchi     DbgBreakIf(pdev->params.enable_remote_phy == FALSE);
3604eef4f27bSRobert Mustacchi 
3605eef4f27bSRobert Mustacchi     *medium = LM_MEDIUM_TYPE_FIBER |
3606eef4f27bSRobert Mustacchi         LM_MEDIUM_SPEED_UNKNOWN |
3607eef4f27bSRobert Mustacchi         LM_MEDIUM_FULL_DUPLEX;
3608eef4f27bSRobert Mustacchi 
3609eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = FALSE;
3610eef4f27bSRobert Mustacchi 
3611eef4f27bSRobert Mustacchi     REG_RD_IND(
3612eef4f27bSRobert Mustacchi         pdev,
3613eef4f27bSRobert Mustacchi         pdev->hw_info.shmem_base +
3614eef4f27bSRobert Mustacchi             OFFSETOF(shmem_region_t, drv_fw_mb.link_status),
3615eef4f27bSRobert Mustacchi         &remote_phy_link);
3616eef4f27bSRobert Mustacchi 
3617eef4f27bSRobert Mustacchi     pdev->vars.rphy_status = 0;
3618eef4f27bSRobert Mustacchi 
3619eef4f27bSRobert Mustacchi     if((remote_phy_link & NETLINK_GET_LINK_STATUS_SERDES_LINK) == 0)
3620eef4f27bSRobert Mustacchi     {
3621eef4f27bSRobert Mustacchi         pdev->vars.rphy_status |= RPHY_STATUS_ACTIVE;
3622eef4f27bSRobert Mustacchi     }
3623eef4f27bSRobert Mustacchi 
3624eef4f27bSRobert Mustacchi     if((remote_phy_link & NETLINK_GET_LINK_STATUS_NO_MEDIA_DETECTED) == 0)
3625eef4f27bSRobert Mustacchi     {
3626eef4f27bSRobert Mustacchi         pdev->vars.rphy_status |= RPHY_STATUS_MODULE_PRESENT;
3627eef4f27bSRobert Mustacchi     }
3628eef4f27bSRobert Mustacchi 
3629eef4f27bSRobert Mustacchi     if((remote_phy_link & NETLINK_GET_LINK_STATUS_LINK_UP) == 0)
3630eef4f27bSRobert Mustacchi     {
3631eef4f27bSRobert Mustacchi         return LM_STATUS_LINK_DOWN;
3632eef4f27bSRobert Mustacchi     }
3633eef4f27bSRobert Mustacchi 
3634eef4f27bSRobert Mustacchi     link = LM_STATUS_LINK_ACTIVE;
3635eef4f27bSRobert Mustacchi     pdev->vars.cable_is_attached = TRUE;
3636eef4f27bSRobert Mustacchi 
3637eef4f27bSRobert Mustacchi     switch(remote_phy_link & NETLINK_GET_LINK_STATUS_SPEED_MASK)
3638eef4f27bSRobert Mustacchi     {
3639eef4f27bSRobert Mustacchi         case NETLINK_GET_LINK_STATUS_10HALF:
3640eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_10MBPS;
3641eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_HALF_DUPLEX;
3642eef4f27bSRobert Mustacchi             break;
3643eef4f27bSRobert Mustacchi 
3644eef4f27bSRobert Mustacchi         case NETLINK_GET_LINK_STATUS_10FULL:
3645eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_10MBPS;
3646eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_FULL_DUPLEX;
3647eef4f27bSRobert Mustacchi             break;
3648eef4f27bSRobert Mustacchi 
3649eef4f27bSRobert Mustacchi         case NETLINK_GET_LINK_STATUS_100HALF:
3650eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_100MBPS;
3651eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_HALF_DUPLEX;
3652eef4f27bSRobert Mustacchi             break;
3653eef4f27bSRobert Mustacchi 
3654eef4f27bSRobert Mustacchi         case NETLINK_GET_LINK_STATUS_100FULL:
3655eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_100MBPS;
3656eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_FULL_DUPLEX;
3657eef4f27bSRobert Mustacchi             break;
3658eef4f27bSRobert Mustacchi 
3659eef4f27bSRobert Mustacchi         case NETLINK_GET_LINK_STATUS_1000HALF:
3660eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_1000MBPS;
3661eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_HALF_DUPLEX;
3662eef4f27bSRobert Mustacchi             break;
3663eef4f27bSRobert Mustacchi 
3664eef4f27bSRobert Mustacchi         case NETLINK_GET_LINK_STATUS_1000FULL:
3665eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_1000MBPS;
3666eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_FULL_DUPLEX;
3667eef4f27bSRobert Mustacchi             break;
3668eef4f27bSRobert Mustacchi 
3669eef4f27bSRobert Mustacchi         case NETLINK_GET_LINK_STATUS_2500HALF:
3670eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_2500MBPS;
3671eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_HALF_DUPLEX;
3672eef4f27bSRobert Mustacchi             break;
3673eef4f27bSRobert Mustacchi 
3674eef4f27bSRobert Mustacchi         case NETLINK_GET_LINK_STATUS_2500FULL:
3675eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_2500MBPS;
3676eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_FULL_DUPLEX;
3677eef4f27bSRobert Mustacchi             break;
3678eef4f27bSRobert Mustacchi 
3679eef4f27bSRobert Mustacchi         default:
3680eef4f27bSRobert Mustacchi             speed = LM_MEDIUM_SPEED_UNKNOWN;
3681eef4f27bSRobert Mustacchi             duplex = LM_MEDIUM_FULL_DUPLEX;
3682eef4f27bSRobert Mustacchi             break;
3683eef4f27bSRobert Mustacchi     }
3684eef4f27bSRobert Mustacchi 
3685eef4f27bSRobert Mustacchi     *medium = LM_MEDIUM_TYPE_FIBER | speed | duplex;
3686eef4f27bSRobert Mustacchi 
3687eef4f27bSRobert Mustacchi     return link;
3688eef4f27bSRobert Mustacchi } /* get_remote_phy_link */
3689eef4f27bSRobert Mustacchi 
3690eef4f27bSRobert Mustacchi 
3691eef4f27bSRobert Mustacchi 
3692eef4f27bSRobert Mustacchi /*******************************************************************************
3693eef4f27bSRobert Mustacchi  * Description:
3694eef4f27bSRobert Mustacchi  *
3695eef4f27bSRobert Mustacchi  * Return:
3696eef4f27bSRobert Mustacchi  ******************************************************************************/
3697eef4f27bSRobert Mustacchi lm_status_t
lm_init_mac_link(lm_device_t * pdev)3698eef4f27bSRobert Mustacchi lm_init_mac_link(
3699eef4f27bSRobert Mustacchi     lm_device_t *pdev)
3700eef4f27bSRobert Mustacchi {
3701eef4f27bSRobert Mustacchi     lm_status_t lm_status;
3702eef4f27bSRobert Mustacchi     lm_medium_t medium;
3703eef4f27bSRobert Mustacchi     lm_status_t link;
3704eef4f27bSRobert Mustacchi     u32_t val, phy_ctrl, phy_status;
3705eef4f27bSRobert Mustacchi 
3706eef4f27bSRobert Mustacchi     if(pdev->params.enable_remote_phy)
3707eef4f27bSRobert Mustacchi     {
3708eef4f27bSRobert Mustacchi         link = get_remote_phy_link(pdev, &medium);
3709eef4f27bSRobert Mustacchi         init_mac_link(pdev, link, medium, pdev->params.flow_ctrl_cap);
3710eef4f27bSRobert Mustacchi 
3711eef4f27bSRobert Mustacchi         return LM_STATUS_SUCCESS;
3712eef4f27bSRobert Mustacchi     }
3713eef4f27bSRobert Mustacchi 
3714eef4f27bSRobert Mustacchi     switch(GET_MEDIUM_TYPE(pdev->vars.medium))
3715eef4f27bSRobert Mustacchi     {
3716eef4f27bSRobert Mustacchi         case LM_MEDIUM_TYPE_UTP:
3717eef4f27bSRobert Mustacchi             link = get_copper_phy_link(pdev, &medium);
3718eef4f27bSRobert Mustacchi             init_mac_link(pdev, link, medium, pdev->params.flow_ctrl_cap);
3719eef4f27bSRobert Mustacchi 
3720eef4f27bSRobert Mustacchi             lm_status = LM_STATUS_SUCCESS;
3721eef4f27bSRobert Mustacchi             break;
3722eef4f27bSRobert Mustacchi 
3723eef4f27bSRobert Mustacchi         case LM_MEDIUM_TYPE_FIBER:
3724eef4f27bSRobert Mustacchi             DbgBreakIf(CHIP_NUM(pdev) != CHIP_NUM_5706 &&
3725eef4f27bSRobert Mustacchi                        CHIP_NUM(pdev) != CHIP_NUM_5708 &&
3726eef4f27bSRobert Mustacchi                        CHIP_NUM(pdev) != CHIP_NUM_5709);
3727eef4f27bSRobert Mustacchi 
3728eef4f27bSRobert Mustacchi             if(CHIP_NUM(pdev) == CHIP_NUM_5706)
3729eef4f27bSRobert Mustacchi             {
3730eef4f27bSRobert Mustacchi                 link = get_5706_serdes_link(pdev, &medium);
3731eef4f27bSRobert Mustacchi             }
3732eef4f27bSRobert Mustacchi             else if(CHIP_NUM(pdev) == CHIP_NUM_5708)
3733eef4f27bSRobert Mustacchi             {
3734eef4f27bSRobert Mustacchi                 link = get_5708_serdes_link(pdev, &medium);
3735eef4f27bSRobert Mustacchi             }
3736eef4f27bSRobert Mustacchi             else
3737eef4f27bSRobert Mustacchi             {
3738eef4f27bSRobert Mustacchi                 link = get_5709_serdes_link(pdev, &medium);
3739eef4f27bSRobert Mustacchi             }
3740eef4f27bSRobert Mustacchi 
3741eef4f27bSRobert Mustacchi             init_mac_link(pdev, link, medium, pdev->params.flow_ctrl_cap);
3742eef4f27bSRobert Mustacchi 
3743eef4f27bSRobert Mustacchi             lm_status = LM_STATUS_SUCCESS;
3744eef4f27bSRobert Mustacchi             break;
3745eef4f27bSRobert Mustacchi 
3746eef4f27bSRobert Mustacchi         case LM_MEDIUM_TYPE_PHY_LOOPBACK:
3747eef4f27bSRobert Mustacchi         case LM_MEDIUM_TYPE_MAC_LOOPBACK:
3748eef4f27bSRobert Mustacchi             lm_status = init_loopback_mac_link(
3749eef4f27bSRobert Mustacchi                 pdev,
3750eef4f27bSRobert Mustacchi                 pdev->params.req_medium,
3751eef4f27bSRobert Mustacchi                 pdev->params.flow_ctrl_cap);
3752eef4f27bSRobert Mustacchi             break;
3753eef4f27bSRobert Mustacchi 
3754eef4f27bSRobert Mustacchi         case LM_MEDIUM_TYPE_NULL:
3755eef4f27bSRobert Mustacchi             init_mac_link(
3756eef4f27bSRobert Mustacchi                 pdev,
3757eef4f27bSRobert Mustacchi                 LM_STATUS_LINK_ACTIVE,
3758eef4f27bSRobert Mustacchi                 LM_MEDIUM_TYPE_NULL |
3759eef4f27bSRobert Mustacchi                     LM_MEDIUM_SPEED_1000MBPS |
3760eef4f27bSRobert Mustacchi                     LM_MEDIUM_FULL_DUPLEX,
3761eef4f27bSRobert Mustacchi                 pdev->params.flow_ctrl_cap);
3762eef4f27bSRobert Mustacchi 
3763eef4f27bSRobert Mustacchi             lm_status = LM_STATUS_SUCCESS;
3764eef4f27bSRobert Mustacchi             break;
3765eef4f27bSRobert Mustacchi 
3766eef4f27bSRobert Mustacchi         default:
3767eef4f27bSRobert Mustacchi             lm_status = LM_STATUS_UNKNOWN_MEDIUM;
3768eef4f27bSRobert Mustacchi             break;
3769eef4f27bSRobert Mustacchi     }
3770eef4f27bSRobert Mustacchi 
3771eef4f27bSRobert Mustacchi     /* Report the currnet link status to the management firmware. */
3772eef4f27bSRobert Mustacchi     val = 0;
3773eef4f27bSRobert Mustacchi 
3774eef4f27bSRobert Mustacchi     if(pdev->vars.link_status == LM_STATUS_LINK_ACTIVE)
3775eef4f27bSRobert Mustacchi     {
3776eef4f27bSRobert Mustacchi         val |= NETLINK_GET_LINK_STATUS_LINK_UP;
3777eef4f27bSRobert Mustacchi 
3778eef4f27bSRobert Mustacchi         if(lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
3779eef4f27bSRobert Mustacchi         {
3780eef4f27bSRobert Mustacchi             val |= NETLINK_GET_LINK_STATUS_SERDES_LINK;
3781eef4f27bSRobert Mustacchi         }
3782eef4f27bSRobert Mustacchi     }
3783eef4f27bSRobert Mustacchi 
3784eef4f27bSRobert Mustacchi     switch(GET_MEDIUM_SPEED(pdev->vars.medium))
3785eef4f27bSRobert Mustacchi     {
3786eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_10MBPS:
3787eef4f27bSRobert Mustacchi             if(GET_MEDIUM_DUPLEX(pdev->vars.medium) == LM_MEDIUM_FULL_DUPLEX)
3788eef4f27bSRobert Mustacchi             {
3789eef4f27bSRobert Mustacchi                 val |= NETLINK_GET_LINK_STATUS_10FULL;
3790eef4f27bSRobert Mustacchi             }
3791eef4f27bSRobert Mustacchi             else
3792eef4f27bSRobert Mustacchi             {
3793eef4f27bSRobert Mustacchi                 val |= NETLINK_GET_LINK_STATUS_10HALF;
3794eef4f27bSRobert Mustacchi             }
3795eef4f27bSRobert Mustacchi             break;
3796eef4f27bSRobert Mustacchi 
3797eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_100MBPS:
3798eef4f27bSRobert Mustacchi             if(GET_MEDIUM_DUPLEX(pdev->vars.medium) == LM_MEDIUM_FULL_DUPLEX)
3799eef4f27bSRobert Mustacchi             {
3800eef4f27bSRobert Mustacchi                 val |= NETLINK_GET_LINK_STATUS_100FULL;
3801eef4f27bSRobert Mustacchi             }
3802eef4f27bSRobert Mustacchi             else
3803eef4f27bSRobert Mustacchi             {
3804eef4f27bSRobert Mustacchi                 val |= NETLINK_GET_LINK_STATUS_100HALF;
3805eef4f27bSRobert Mustacchi             }
3806eef4f27bSRobert Mustacchi             break;
3807eef4f27bSRobert Mustacchi 
3808eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_1000MBPS:
3809eef4f27bSRobert Mustacchi             if(GET_MEDIUM_DUPLEX(pdev->vars.medium) == LM_MEDIUM_FULL_DUPLEX)
3810eef4f27bSRobert Mustacchi             {
3811eef4f27bSRobert Mustacchi                 val |= NETLINK_GET_LINK_STATUS_1000FULL;
3812eef4f27bSRobert Mustacchi             }
3813eef4f27bSRobert Mustacchi             else
3814eef4f27bSRobert Mustacchi             {
3815eef4f27bSRobert Mustacchi                 val |= NETLINK_GET_LINK_STATUS_1000HALF;
3816eef4f27bSRobert Mustacchi             }
3817eef4f27bSRobert Mustacchi             break;
3818eef4f27bSRobert Mustacchi 
3819eef4f27bSRobert Mustacchi         case LM_MEDIUM_SPEED_2500MBPS:
3820eef4f27bSRobert Mustacchi             if(GET_MEDIUM_DUPLEX(pdev->vars.medium) == LM_MEDIUM_FULL_DUPLEX)
3821eef4f27bSRobert Mustacchi             {
3822eef4f27bSRobert Mustacchi                 val |= NETLINK_GET_LINK_STATUS_2500FULL;
3823eef4f27bSRobert Mustacchi             }
3824eef4f27bSRobert Mustacchi             else
3825eef4f27bSRobert Mustacchi             {
3826eef4f27bSRobert Mustacchi                 val |= NETLINK_GET_LINK_STATUS_2500HALF;
3827eef4f27bSRobert Mustacchi             }
3828eef4f27bSRobert Mustacchi             break;
3829eef4f27bSRobert Mustacchi     }
3830eef4f27bSRobert Mustacchi 
3831eef4f27bSRobert Mustacchi     // read PHY_CTRL_REG to see if auto-negotiation is enabled/completed
3832eef4f27bSRobert Mustacchi     (void) lm_mread(pdev, pdev->params.phy_addr, PHY_CTRL_REG, &phy_ctrl);
3833eef4f27bSRobert Mustacchi 
3834eef4f27bSRobert Mustacchi     if(phy_ctrl & PHY_CTRL_AUTO_NEG_ENABLE)
3835eef4f27bSRobert Mustacchi     {
3836eef4f27bSRobert Mustacchi         val |= NETLINK_GET_LINK_STATUS_AN_ENABLED;
3837eef4f27bSRobert Mustacchi         (void) lm_mread(pdev, pdev->params.phy_addr, PHY_STATUS_REG, &phy_status);
3838eef4f27bSRobert Mustacchi         if(phy_status & PHY_STATUS_AUTO_NEG_COMPLETE)
3839eef4f27bSRobert Mustacchi         {
3840eef4f27bSRobert Mustacchi             val |= NETLINK_GET_LINK_STATUS_AN_COMPLETE;
3841eef4f27bSRobert Mustacchi             // Following bits are valid for copper (i.e. SerDes flag == 0)
3842eef4f27bSRobert Mustacchi             if ((val & NETLINK_GET_LINK_STATUS_SERDES_LINK) == 0)
3843eef4f27bSRobert Mustacchi             {
3844eef4f27bSRobert Mustacchi                 u32_t remote_phy_ad;
3845eef4f27bSRobert Mustacchi                 (void) lm_mread(
3846*55fea89dSDan Cross                         pdev,
3847*55fea89dSDan Cross                         pdev->params.phy_addr,
3848*55fea89dSDan Cross                         PHY_1000BASET_STATUS_REG,
3849eef4f27bSRobert Mustacchi                         &remote_phy_ad);
3850eef4f27bSRobert Mustacchi 
3851eef4f27bSRobert Mustacchi                 if(remote_phy_ad & PHY_LINK_PARTNER_1000BASET_FULL)
3852eef4f27bSRobert Mustacchi                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_1000FULL;
3853eef4f27bSRobert Mustacchi                 if(remote_phy_ad & PHY_LINK_PARTNER_1000BASET_HALF)
3854eef4f27bSRobert Mustacchi                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_1000HALF;
3855eef4f27bSRobert Mustacchi 
3856eef4f27bSRobert Mustacchi                 (void) lm_mread(
3857*55fea89dSDan Cross                     pdev,
3858*55fea89dSDan Cross                     pdev->params.phy_addr,
3859*55fea89dSDan Cross                     PHY_LINK_PARTNER_ABILITY_REG,
3860eef4f27bSRobert Mustacchi                     &remote_phy_ad);
3861*55fea89dSDan Cross                 if (remote_phy_ad & PHY_LINK_PARTNER_10BASET_HALF)
3862eef4f27bSRobert Mustacchi                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_10HALF;
3863*55fea89dSDan Cross                 if (remote_phy_ad & PHY_LINK_PARTNER_10BASET_FULL)
3864eef4f27bSRobert Mustacchi                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_10FULL;
3865eef4f27bSRobert Mustacchi                 if (remote_phy_ad & PHY_LINK_PARTNER_100BASETX_HALF)
3866eef4f27bSRobert Mustacchi                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_100HALF;
3867eef4f27bSRobert Mustacchi                 if (remote_phy_ad & PHY_LINK_PARTNER_100BASETX_FULL)
3868eef4f27bSRobert Mustacchi                     val |= NETLINK_GET_LINK_STATUS_PARTNER_AD_100FULL;
3869eef4f27bSRobert Mustacchi                 if (remote_phy_ad & PHY_LINK_PARTNER_PAUSE_CAPABLE)
3870eef4f27bSRobert Mustacchi                     val |= NETLINK_GET_LINK_STATUS_PARTNER_SYM_PAUSE_CAP;
3871eef4f27bSRobert Mustacchi                 if (remote_phy_ad & PHY_LINK_PARTNER_ASYM_PAUSE)
3872eef4f27bSRobert Mustacchi                     val |= NETLINK_GET_LINK_STATUS_PARTNER_ASYM_PAUSE_CAP;
3873eef4f27bSRobert Mustacchi                 // Read PHY_AN_EXPANSION_REG to see if Link partner support auto
3874*55fea89dSDan Cross                 // negotiation
3875eef4f27bSRobert Mustacchi                 (void) lm_mread(
3876*55fea89dSDan Cross                     pdev,
3877*55fea89dSDan Cross                     pdev->params.phy_addr,
3878*55fea89dSDan Cross                     PHY_AN_EXPANSION_REG,
3879eef4f27bSRobert Mustacchi                     &remote_phy_ad);
3880eef4f27bSRobert Mustacchi                 // If Link partner does not support auto negotiation,  we assume
3881eef4f27bSRobert Mustacchi                 // parallel detection was used to get link.
3882*55fea89dSDan Cross                 if ((remote_phy_ad & PHY_LINK_PARTNER_AUTONEG_ABILITY) == 0)
3883eef4f27bSRobert Mustacchi                     val |= NETLINK_GET_LINK_STATUS_PARALLEL_DET;
3884eef4f27bSRobert Mustacchi             }
3885eef4f27bSRobert Mustacchi         }
3886eef4f27bSRobert Mustacchi     }
3887eef4f27bSRobert Mustacchi     if(pdev->vars.flow_control & LM_FLOW_CONTROL_TRANSMIT_PAUSE)
3888eef4f27bSRobert Mustacchi     {
3889eef4f27bSRobert Mustacchi         val |= NETLINK_GET_LINK_STATUS_TX_FC_ENABLED;
3890eef4f27bSRobert Mustacchi     }
3891eef4f27bSRobert Mustacchi     if(pdev->vars.flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE)
3892eef4f27bSRobert Mustacchi     {
3893eef4f27bSRobert Mustacchi         val |= NETLINK_GET_LINK_STATUS_RX_FC_ENABLED;
3894eef4f27bSRobert Mustacchi     }
3895eef4f27bSRobert Mustacchi     // Following bits are not supported yet
3896eef4f27bSRobert Mustacchi     // NETLINK_GET_LINK_STATUS_NO_MEDIA_DETECTED;
3897eef4f27bSRobert Mustacchi     // NETLINK_GET_LINK_STATUS_CABLESENSE;
3898eef4f27bSRobert Mustacchi     // NETLINK_GET_LINK_STATUS_SW_TIMER_EVENT;
3899eef4f27bSRobert Mustacchi     REG_WR_IND(
3900eef4f27bSRobert Mustacchi         pdev,
3901eef4f27bSRobert Mustacchi         pdev->hw_info.shmem_base +
3902eef4f27bSRobert Mustacchi             OFFSETOF(shmem_region_t, drv_fw_mb.link_status),
3903eef4f27bSRobert Mustacchi         val);
3904*55fea89dSDan Cross 
3905eef4f27bSRobert Mustacchi     return lm_status;
3906eef4f27bSRobert Mustacchi } /* lm_init_mac_link */
3907eef4f27bSRobert Mustacchi 
3908eef4f27bSRobert Mustacchi 
3909eef4f27bSRobert Mustacchi 
3910eef4f27bSRobert Mustacchi /*******************************************************************************
3911eef4f27bSRobert Mustacchi  * Description:
3912eef4f27bSRobert Mustacchi  *
3913eef4f27bSRobert Mustacchi  * Return:
3914eef4f27bSRobert Mustacchi  ******************************************************************************/
3915eef4f27bSRobert Mustacchi void
lm_service_phy_int(lm_device_t * pdev,u32_t force_service_int)3916eef4f27bSRobert Mustacchi lm_service_phy_int(
3917eef4f27bSRobert Mustacchi     lm_device_t *pdev,
3918eef4f27bSRobert Mustacchi     u32_t force_service_int)
3919eef4f27bSRobert Mustacchi {
3920eef4f27bSRobert Mustacchi     u32_t deasserted_attns;
3921eef4f27bSRobert Mustacchi     u32_t asserted_attns;
3922eef4f27bSRobert Mustacchi     u32_t link_chng;
3923eef4f27bSRobert Mustacchi     u32_t val;
3924eef4f27bSRobert Mustacchi 
3925eef4f27bSRobert Mustacchi     link_chng = FALSE;
3926eef4f27bSRobert Mustacchi 
3927eef4f27bSRobert Mustacchi     if(pdev->params.link_chng_mode == LINK_CHNG_MODE_USE_STATUS_REG)
3928eef4f27bSRobert Mustacchi     {
3929eef4f27bSRobert Mustacchi         REG_RD(pdev, emac.emac_status, &val);
3930eef4f27bSRobert Mustacchi         if(pdev->params.phy_int_mode == PHY_INT_MODE_MI_INTERRUPT)
3931eef4f27bSRobert Mustacchi         {
3932eef4f27bSRobert Mustacchi             if(val & EMAC_STATUS_MI_INT)
3933eef4f27bSRobert Mustacchi             {
3934eef4f27bSRobert Mustacchi                 link_chng = TRUE;
3935eef4f27bSRobert Mustacchi             }
3936eef4f27bSRobert Mustacchi         }
3937eef4f27bSRobert Mustacchi         else if(val & EMAC_STATUS_LINK_CHANGE)
3938eef4f27bSRobert Mustacchi         {
3939eef4f27bSRobert Mustacchi             link_chng = TRUE;
3940eef4f27bSRobert Mustacchi         }
3941eef4f27bSRobert Mustacchi     }
3942eef4f27bSRobert Mustacchi     else
3943eef4f27bSRobert Mustacchi     {
3944eef4f27bSRobert Mustacchi         link_chng = FALSE;
3945eef4f27bSRobert Mustacchi 
3946eef4f27bSRobert Mustacchi         GET_ATTN_CHNG_BITS(pdev, &asserted_attns, &deasserted_attns);
3947eef4f27bSRobert Mustacchi 
3948eef4f27bSRobert Mustacchi         asserted_attns &= STATUS_ATTN_BITS_LINK_STATE;
3949eef4f27bSRobert Mustacchi         deasserted_attns &= STATUS_ATTN_BITS_LINK_STATE;
3950eef4f27bSRobert Mustacchi 
3951eef4f27bSRobert Mustacchi         if(asserted_attns)
3952eef4f27bSRobert Mustacchi         {
3953eef4f27bSRobert Mustacchi             link_chng = TRUE;
3954eef4f27bSRobert Mustacchi 
3955eef4f27bSRobert Mustacchi             REG_WR(
3956eef4f27bSRobert Mustacchi                 pdev,
3957eef4f27bSRobert Mustacchi                 pci_config.pcicfg_status_bit_set_cmd,
3958eef4f27bSRobert Mustacchi                 asserted_attns);
3959eef4f27bSRobert Mustacchi         }
3960eef4f27bSRobert Mustacchi         else if(deasserted_attns)
3961eef4f27bSRobert Mustacchi         {
3962eef4f27bSRobert Mustacchi             link_chng = TRUE;
3963eef4f27bSRobert Mustacchi 
3964eef4f27bSRobert Mustacchi             REG_WR(
3965eef4f27bSRobert Mustacchi                 pdev,
3966eef4f27bSRobert Mustacchi                 pci_config.pcicfg_status_bit_clear_cmd,
3967eef4f27bSRobert Mustacchi                 deasserted_attns);
3968eef4f27bSRobert Mustacchi         }
3969eef4f27bSRobert Mustacchi     }
3970eef4f27bSRobert Mustacchi 
3971eef4f27bSRobert Mustacchi     if(link_chng || force_service_int || pdev->params.enable_remote_phy)
3972eef4f27bSRobert Mustacchi     {
3973eef4f27bSRobert Mustacchi         (void) lm_init_mac_link(pdev);
3974eef4f27bSRobert Mustacchi 
3975eef4f27bSRobert Mustacchi         mm_indicate_link(pdev, pdev->vars.link_status, pdev->vars.medium);
3976eef4f27bSRobert Mustacchi     }
3977eef4f27bSRobert Mustacchi } /* lm_service_phy_int */
3978eef4f27bSRobert Mustacchi 
3979eef4f27bSRobert Mustacchi 
3980eef4f27bSRobert Mustacchi 
3981eef4f27bSRobert Mustacchi /*******************************************************************************
3982eef4f27bSRobert Mustacchi  * Description:
3983eef4f27bSRobert Mustacchi  *
3984eef4f27bSRobert Mustacchi  * Return:
3985eef4f27bSRobert Mustacchi  ******************************************************************************/
3986eef4f27bSRobert Mustacchi lm_medium_t
lm_get_medium(lm_device_t * pdev)3987eef4f27bSRobert Mustacchi lm_get_medium(
3988eef4f27bSRobert Mustacchi     lm_device_t *pdev)
3989eef4f27bSRobert Mustacchi {
3990eef4f27bSRobert Mustacchi     u32_t decode;
3991eef4f27bSRobert Mustacchi     u32_t val;
3992eef4f27bSRobert Mustacchi 
3993eef4f27bSRobert Mustacchi     if(CHIP_REV(pdev) == CHIP_REV_IKOS)
3994eef4f27bSRobert Mustacchi     {
3995eef4f27bSRobert Mustacchi         return LM_MEDIUM_TYPE_NULL;
3996eef4f27bSRobert Mustacchi     }
3997eef4f27bSRobert Mustacchi 
3998eef4f27bSRobert Mustacchi     if(CHIP_REV(pdev) == CHIP_REV_FPGA)
3999eef4f27bSRobert Mustacchi     {
4000eef4f27bSRobert Mustacchi         return LM_MEDIUM_TYPE_UTP;
4001eef4f27bSRobert Mustacchi     }
4002eef4f27bSRobert Mustacchi 
4003eef4f27bSRobert Mustacchi     if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
4004eef4f27bSRobert Mustacchi     {
4005eef4f27bSRobert Mustacchi         if(CHIP_BOND_ID(pdev) & CHIP_BOND_ID_SERDES_BIT)
4006eef4f27bSRobert Mustacchi         {
4007eef4f27bSRobert Mustacchi             return LM_MEDIUM_TYPE_FIBER;
4008eef4f27bSRobert Mustacchi         }
4009eef4f27bSRobert Mustacchi 
4010eef4f27bSRobert Mustacchi         return LM_MEDIUM_TYPE_UTP;
4011eef4f27bSRobert Mustacchi     }
4012eef4f27bSRobert Mustacchi 
4013eef4f27bSRobert Mustacchi     if(CHIP_NUM(pdev) == CHIP_NUM_5709)
4014eef4f27bSRobert Mustacchi     {
4015eef4f27bSRobert Mustacchi         REG_RD(pdev, misc.misc_dual_media_ctrl, &val);
4016eef4f27bSRobert Mustacchi 
4017eef4f27bSRobert Mustacchi         if((val & MISC_DUAL_MEDIA_CTRL_BOND_ID) ==
4018eef4f27bSRobert Mustacchi             MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
4019eef4f27bSRobert Mustacchi         {
4020eef4f27bSRobert Mustacchi             return LM_MEDIUM_TYPE_UTP;
4021eef4f27bSRobert Mustacchi         }
4022eef4f27bSRobert Mustacchi 
4023eef4f27bSRobert Mustacchi         if((val & MISC_DUAL_MEDIA_CTRL_BOND_ID) ==
4024eef4f27bSRobert Mustacchi             MISC_DUAL_MEDIA_CTRL_BOND_ID_S)
4025eef4f27bSRobert Mustacchi         {
4026eef4f27bSRobert Mustacchi             return LM_MEDIUM_TYPE_FIBER;
4027eef4f27bSRobert Mustacchi         }
4028eef4f27bSRobert Mustacchi 
4029eef4f27bSRobert Mustacchi         /* mac to phy/serdes decode.
4030eef4f27bSRobert Mustacchi          *    swap strap mac0 mac1
4031eef4f27bSRobert Mustacchi          *    ==== ===== ==== ====
4032eef4f27bSRobert Mustacchi          *    0    000   phy0 phy1
4033eef4f27bSRobert Mustacchi          *    0    001   phy0 ser0
4034eef4f27bSRobert Mustacchi          *    0    010   phy0 ser1
4035eef4f27bSRobert Mustacchi          *    0    110   ser0 phy0
4036eef4f27bSRobert Mustacchi          *    0    101   ser0 phy1
4037eef4f27bSRobert Mustacchi          *    0    100   ser0 ser1
4038eef4f27bSRobert Mustacchi          *
4039eef4f27bSRobert Mustacchi          *    1    000   phy1 phy0
4040eef4f27bSRobert Mustacchi          *    1    001   phy1 ser1
4041eef4f27bSRobert Mustacchi          *    1    010   phy1 ser0
4042eef4f27bSRobert Mustacchi          *    1    110   ser1 phy1
4043eef4f27bSRobert Mustacchi          *    1    101   ser1 phy0
4044eef4f27bSRobert Mustacchi          *    1    100   ser1 ser0 */
4045eef4f27bSRobert Mustacchi         if(val & MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
4046eef4f27bSRobert Mustacchi         {
4047eef4f27bSRobert Mustacchi             decode = (val & MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
4048eef4f27bSRobert Mustacchi 
4049eef4f27bSRobert Mustacchi             if(val & MISC_DUAL_MEDIA_CTRL_PORT_SWAP)
4050eef4f27bSRobert Mustacchi             {
4051eef4f27bSRobert Mustacchi                 decode |= 0x8;
4052eef4f27bSRobert Mustacchi             }
4053eef4f27bSRobert Mustacchi         }
4054eef4f27bSRobert Mustacchi         else
4055eef4f27bSRobert Mustacchi         {
4056eef4f27bSRobert Mustacchi             decode = (val & MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
4057eef4f27bSRobert Mustacchi 
4058eef4f27bSRobert Mustacchi             if(val & MISC_DUAL_MEDIA_CTRL_PORT_SWAP_PIN)
4059eef4f27bSRobert Mustacchi             {
4060eef4f27bSRobert Mustacchi                 decode |= 0x8;
4061eef4f27bSRobert Mustacchi             }
4062eef4f27bSRobert Mustacchi         }
4063eef4f27bSRobert Mustacchi 
4064eef4f27bSRobert Mustacchi         decode |= pdev->hw_info.mac_id << 4;
4065eef4f27bSRobert Mustacchi 
4066eef4f27bSRobert Mustacchi         /* mac:4, swap:3, strap:2-0. */
4067eef4f27bSRobert Mustacchi         switch(decode)
4068eef4f27bSRobert Mustacchi         {
4069eef4f27bSRobert Mustacchi             case 0x00: /* 00000 - mac0, phy0 */
4070eef4f27bSRobert Mustacchi             case 0x01: /* 00001 - mac0, phy0 */
4071eef4f27bSRobert Mustacchi             case 0x02: /* 00010 - mac0, phy0 */
4072eef4f27bSRobert Mustacchi             case 0x08: /* 01000 - mac0, phy1 */
4073eef4f27bSRobert Mustacchi             case 0x09: /* 01001 - mac0, phy1 */
4074eef4f27bSRobert Mustacchi             case 0x0a: /* 01010 - mac0, phy1 */
4075eef4f27bSRobert Mustacchi             case 0x10: /* 10000 - mac1, phy1 */
4076eef4f27bSRobert Mustacchi             case 0x15: /* 10101 - mac1, phy1 */
4077eef4f27bSRobert Mustacchi             case 0x16: /* 10110 - mac1, phy0 */
4078eef4f27bSRobert Mustacchi             case 0x18: /* 11000 - mac1, phy0 */
4079eef4f27bSRobert Mustacchi             case 0x1d: /* 11101 - mac1, phy0 */
4080eef4f27bSRobert Mustacchi             case 0x1e: /* 11110 - mac1, phy1 */
4081eef4f27bSRobert Mustacchi                 return LM_MEDIUM_TYPE_UTP;
4082eef4f27bSRobert Mustacchi 
4083eef4f27bSRobert Mustacchi             case 0x04: /* 00100 - mac0, ser0 */
4084eef4f27bSRobert Mustacchi             case 0x05: /* 00101 - mac0, ser0 */
4085eef4f27bSRobert Mustacchi             case 0x06: /* 00110 - mac0, ser0 */
4086eef4f27bSRobert Mustacchi             case 0x0c: /* 01100 - mac0, ser1 */
4087eef4f27bSRobert Mustacchi             case 0x0d: /* 01101 - mac0, ser1 */
4088eef4f27bSRobert Mustacchi             case 0x0e: /* 01110 - mac0, ser1 */
4089eef4f27bSRobert Mustacchi             case 0x11: /* 10001 - mac1, ser0 */
4090eef4f27bSRobert Mustacchi             case 0x12: /* 10010 - mac1, ser1 */
4091eef4f27bSRobert Mustacchi             case 0x14: /* 10100 - mac1, ser1 */
4092eef4f27bSRobert Mustacchi             case 0x19: /* 11001 - mac1, ser1 */
4093eef4f27bSRobert Mustacchi             case 0x1a: /* 11010 - mac1, ser0 */
4094eef4f27bSRobert Mustacchi             case 0x1c: /* 11100 - mac1, ser0 */
4095eef4f27bSRobert Mustacchi                 return LM_MEDIUM_TYPE_FIBER;
4096eef4f27bSRobert Mustacchi         }
4097eef4f27bSRobert Mustacchi     }
4098eef4f27bSRobert Mustacchi 
4099eef4f27bSRobert Mustacchi     return LM_MEDIUM_TYPE_NULL;
4100eef4f27bSRobert Mustacchi } /* lm_get_medium */
4101