1 /******************************************************************************/
2 /*                                                                            */
3 /* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2001 Broadcom         */
4 /* Corporation.                                                               */
5 /* All rights reserved.                                                       */
6 /*                                                                            */
7 /* This program is free software; you can redistribute it and/or modify       */
8 /* it under the terms of the GNU General Public License as published by       */
9 /* the Free Software Foundation, located in the file LICENSE.                 */
10 /*                                                                            */
11 /* History:                                                                   */
12 /******************************************************************************/
13 #if !defined(CONFIG_NET_MULTI)
14 #if INCLUDE_TBI_SUPPORT
15 #include "bcm570x_autoneg.h"
16 #include "bcm570x_mm.h"
17 
18 
19 /******************************************************************************/
20 /* Description:                                                               */
21 /*                                                                            */
22 /* Return:                                                                    */
23 /******************************************************************************/
24 void
MM_AnTxConfig(PAN_STATE_INFO pAnInfo)25 MM_AnTxConfig(
26     PAN_STATE_INFO pAnInfo)
27 {
28     PLM_DEVICE_BLOCK pDevice;
29 
30     pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
31 
32     REG_WR(pDevice, MacCtrl.TxAutoNeg, (LM_UINT32) pAnInfo->TxConfig.AsUSHORT);
33 
34     pDevice->MacMode |= MAC_MODE_SEND_CONFIGS;
35     REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode);
36 }
37 
38 
39 /******************************************************************************/
40 /* Description:                                                               */
41 /*                                                                            */
42 /* Return:                                                                    */
43 /******************************************************************************/
44 void
MM_AnTxIdle(PAN_STATE_INFO pAnInfo)45 MM_AnTxIdle(
46     PAN_STATE_INFO pAnInfo)
47 {
48     PLM_DEVICE_BLOCK pDevice;
49 
50     pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
51 
52     pDevice->MacMode &= ~MAC_MODE_SEND_CONFIGS;
53     REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode);
54 }
55 
56 
57 /******************************************************************************/
58 /* Description:                                                               */
59 /*                                                                            */
60 /* Return:                                                                    */
61 /******************************************************************************/
62 char
MM_AnRxConfig(PAN_STATE_INFO pAnInfo,unsigned short * pRxConfig)63 MM_AnRxConfig(
64     PAN_STATE_INFO pAnInfo,
65     unsigned short *pRxConfig)
66 {
67     PLM_DEVICE_BLOCK pDevice;
68     LM_UINT32 Value32;
69     char Retcode;
70 
71     Retcode = AN_FALSE;
72 
73     pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
74 
75     Value32 = REG_RD(pDevice, MacCtrl.Status);
76     if(Value32 & MAC_STATUS_RECEIVING_CFG)
77     {
78 	Value32 = REG_RD(pDevice, MacCtrl.RxAutoNeg);
79 	*pRxConfig = (unsigned short) Value32;
80 
81 	Retcode = AN_TRUE;
82     }
83 
84     return Retcode;
85 }
86 
87 
88 /******************************************************************************/
89 /* Description:                                                               */
90 /*                                                                            */
91 /* Return:                                                                    */
92 /******************************************************************************/
93 void
AutonegInit(PAN_STATE_INFO pAnInfo)94 AutonegInit(
95     PAN_STATE_INFO pAnInfo)
96 {
97     unsigned long j;
98 
99     for(j = 0; j < sizeof(AN_STATE_INFO); j++)
100     {
101 	((unsigned char *) pAnInfo)[j] = 0;
102     }
103 
104     /* Initialize the default advertisement register. */
105     pAnInfo->mr_adv_full_duplex = 1;
106     pAnInfo->mr_adv_sym_pause = 1;
107     pAnInfo->mr_adv_asym_pause = 1;
108     pAnInfo->mr_an_enable = 1;
109 }
110 
111 
112 /******************************************************************************/
113 /* Description:                                                               */
114 /*                                                                            */
115 /* Return:                                                                    */
116 /******************************************************************************/
117 AUTONEG_STATUS
Autoneg8023z(PAN_STATE_INFO pAnInfo)118 Autoneg8023z(
119     PAN_STATE_INFO pAnInfo)
120 {
121     unsigned short RxConfig;
122     unsigned long Delta_us;
123     AUTONEG_STATUS AnRet;
124 
125     /* Get the current time. */
126     if(pAnInfo->State == AN_STATE_UNKNOWN)
127     {
128 	pAnInfo->RxConfig.AsUSHORT = 0;
129 	pAnInfo->CurrentTime_us = 0;
130 	pAnInfo->LinkTime_us = 0;
131 	pAnInfo->AbilityMatchCfg = 0;
132 	pAnInfo->AbilityMatchCnt = 0;
133 	pAnInfo->AbilityMatch = AN_FALSE;
134 	pAnInfo->IdleMatch = AN_FALSE;
135 	pAnInfo->AckMatch = AN_FALSE;
136     }
137 
138     /* Increment the timer tick.  This function is called every microsecon. */
139 /*    pAnInfo->CurrentTime_us++; */
140 
141     /* Set the AbilityMatch, IdleMatch, and AckMatch flags if their */
142     /* corresponding conditions are satisfied. */
143     if(MM_AnRxConfig(pAnInfo, &RxConfig))
144     {
145 	if(RxConfig != pAnInfo->AbilityMatchCfg)
146 	{
147 	    pAnInfo->AbilityMatchCfg = RxConfig;
148 	    pAnInfo->AbilityMatch = AN_FALSE;
149 	    pAnInfo->AbilityMatchCnt = 0;
150 	}
151 	else
152 	{
153 	    pAnInfo->AbilityMatchCnt++;
154 	    if(pAnInfo->AbilityMatchCnt > 1)
155 	    {
156 		pAnInfo->AbilityMatch = AN_TRUE;
157 		pAnInfo->AbilityMatchCfg = RxConfig;
158 	    }
159 	}
160 
161 	if(RxConfig & AN_CONFIG_ACK)
162 	{
163 	    pAnInfo->AckMatch = AN_TRUE;
164 	}
165 	else
166 	{
167 	    pAnInfo->AckMatch = AN_FALSE;
168 	}
169 
170 	pAnInfo->IdleMatch = AN_FALSE;
171     }
172     else
173     {
174 	pAnInfo->IdleMatch = AN_TRUE;
175 
176 	pAnInfo->AbilityMatchCfg = 0;
177 	pAnInfo->AbilityMatchCnt = 0;
178 	pAnInfo->AbilityMatch = AN_FALSE;
179 	pAnInfo->AckMatch = AN_FALSE;
180 
181 	RxConfig = 0;
182     }
183 
184     /* Save the last Config. */
185     pAnInfo->RxConfig.AsUSHORT = RxConfig;
186 
187     /* Default return code. */
188     AnRet = AUTONEG_STATUS_OK;
189 
190     /* Autoneg state machine as defined in 802.3z section 37.3.1.5. */
191     switch(pAnInfo->State)
192     {
193 	case AN_STATE_UNKNOWN:
194 	    if(pAnInfo->mr_an_enable || pAnInfo->mr_restart_an)
195 	    {
196 		pAnInfo->CurrentTime_us = 0;
197 		pAnInfo->State = AN_STATE_AN_ENABLE;
198 	    }
199 
200 	    /* Fall through.*/
201 
202 	case AN_STATE_AN_ENABLE:
203 	    pAnInfo->mr_an_complete = AN_FALSE;
204 	    pAnInfo->mr_page_rx = AN_FALSE;
205 
206 	    if(pAnInfo->mr_an_enable)
207 	    {
208 		pAnInfo->LinkTime_us = 0;
209 		pAnInfo->AbilityMatchCfg = 0;
210 		pAnInfo->AbilityMatchCnt = 0;
211 		pAnInfo->AbilityMatch = AN_FALSE;
212 		pAnInfo->IdleMatch = AN_FALSE;
213 		pAnInfo->AckMatch = AN_FALSE;
214 
215 		pAnInfo->State = AN_STATE_AN_RESTART_INIT;
216 	    }
217 	    else
218 	    {
219 		pAnInfo->State = AN_STATE_DISABLE_LINK_OK;
220 	    }
221 	    break;
222 
223 	case AN_STATE_AN_RESTART_INIT:
224 	    pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
225 	    pAnInfo->mr_np_loaded = AN_FALSE;
226 
227 	    pAnInfo->TxConfig.AsUSHORT = 0;
228 	    MM_AnTxConfig(pAnInfo);
229 
230 	    AnRet = AUTONEG_STATUS_TIMER_ENABLED;
231 
232 	    pAnInfo->State = AN_STATE_AN_RESTART;
233 
234 	    /* Fall through.*/
235 
236 	case AN_STATE_AN_RESTART:
237 	    /* Get the current time and compute the delta with the saved */
238 	    /* link timer. */
239 	    Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
240 	    if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
241 	    {
242 		pAnInfo->State = AN_STATE_ABILITY_DETECT_INIT;
243 	    }
244 	    else
245 	    {
246 		AnRet = AUTONEG_STATUS_TIMER_ENABLED;
247 	    }
248 	    break;
249 
250 	case AN_STATE_DISABLE_LINK_OK:
251 	    AnRet = AUTONEG_STATUS_DONE;
252 	    break;
253 
254 	case AN_STATE_ABILITY_DETECT_INIT:
255 	    /* Note: in the state diagram, this variable is set to */
256 	    /* mr_adv_ability<12>.  Is this right?. */
257 	    pAnInfo->mr_toggle_tx = AN_FALSE;
258 
259 	    /* Send the config as advertised in the advertisement register. */
260 	    pAnInfo->TxConfig.AsUSHORT = 0;
261 	    pAnInfo->TxConfig.D5_FD = pAnInfo->mr_adv_full_duplex;
262 	    pAnInfo->TxConfig.D6_HD = pAnInfo->mr_adv_half_duplex;
263 	    pAnInfo->TxConfig.D7_PS1 = pAnInfo->mr_adv_sym_pause;
264 	    pAnInfo->TxConfig.D8_PS2 = pAnInfo->mr_adv_asym_pause;
265 	    pAnInfo->TxConfig.D12_RF1 = pAnInfo->mr_adv_remote_fault1;
266 	    pAnInfo->TxConfig.D13_RF2 = pAnInfo->mr_adv_remote_fault2;
267 	    pAnInfo->TxConfig.D15_NP = pAnInfo->mr_adv_next_page;
268 
269 	    MM_AnTxConfig(pAnInfo);
270 
271 	    pAnInfo->State = AN_STATE_ABILITY_DETECT;
272 
273 	    break;
274 
275 	case AN_STATE_ABILITY_DETECT:
276 	    if(pAnInfo->AbilityMatch == AN_TRUE &&
277 		pAnInfo->RxConfig.AsUSHORT != 0)
278 	    {
279 		pAnInfo->State = AN_STATE_ACK_DETECT_INIT;
280 	    }
281 
282 	    break;
283 
284 	case AN_STATE_ACK_DETECT_INIT:
285 	    pAnInfo->TxConfig.D14_ACK = 1;
286 	    MM_AnTxConfig(pAnInfo);
287 
288 	    pAnInfo->State = AN_STATE_ACK_DETECT;
289 
290 	    /* Fall through. */
291 
292 	case AN_STATE_ACK_DETECT:
293 	    if(pAnInfo->AckMatch == AN_TRUE)
294 	    {
295 		if((pAnInfo->RxConfig.AsUSHORT & ~AN_CONFIG_ACK) ==
296 		    (pAnInfo->AbilityMatchCfg & ~AN_CONFIG_ACK))
297 		{
298 		    pAnInfo->State = AN_STATE_COMPLETE_ACK_INIT;
299 		}
300 		else
301 		{
302 		    pAnInfo->State = AN_STATE_AN_ENABLE;
303 		}
304 	    }
305 	    else if(pAnInfo->AbilityMatch == AN_TRUE &&
306 		pAnInfo->RxConfig.AsUSHORT == 0)
307 	    {
308 		pAnInfo->State = AN_STATE_AN_ENABLE;
309 	    }
310 
311 	    break;
312 
313 	case AN_STATE_COMPLETE_ACK_INIT:
314 	    /* Make sure invalid bits are not set. */
315 	    if(pAnInfo->RxConfig.bits.D0 || pAnInfo->RxConfig.bits.D1 ||
316 		pAnInfo->RxConfig.bits.D2 || pAnInfo->RxConfig.bits.D3 ||
317 		pAnInfo->RxConfig.bits.D4 || pAnInfo->RxConfig.bits.D9 ||
318 		pAnInfo->RxConfig.bits.D10 || pAnInfo->RxConfig.bits.D11)
319 	    {
320 		AnRet = AUTONEG_STATUS_FAILED;
321 		break;
322 	    }
323 
324 	    /* Set up the link partner advertisement register. */
325 	    pAnInfo->mr_lp_adv_full_duplex = pAnInfo->RxConfig.D5_FD;
326 	    pAnInfo->mr_lp_adv_half_duplex = pAnInfo->RxConfig.D6_HD;
327 	    pAnInfo->mr_lp_adv_sym_pause = pAnInfo->RxConfig.D7_PS1;
328 	    pAnInfo->mr_lp_adv_asym_pause = pAnInfo->RxConfig.D8_PS2;
329 	    pAnInfo->mr_lp_adv_remote_fault1 = pAnInfo->RxConfig.D12_RF1;
330 	    pAnInfo->mr_lp_adv_remote_fault2 = pAnInfo->RxConfig.D13_RF2;
331 	    pAnInfo->mr_lp_adv_next_page = pAnInfo->RxConfig.D15_NP;
332 
333 	    pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
334 
335 	    pAnInfo->mr_toggle_tx = !pAnInfo->mr_toggle_tx;
336 	    pAnInfo->mr_toggle_rx = pAnInfo->RxConfig.bits.D11;
337 	    pAnInfo->mr_np_rx = pAnInfo->RxConfig.D15_NP;
338 	    pAnInfo->mr_page_rx = AN_TRUE;
339 
340 	    pAnInfo->State = AN_STATE_COMPLETE_ACK;
341 	    AnRet = AUTONEG_STATUS_TIMER_ENABLED;
342 
343 	    break;
344 
345 	case AN_STATE_COMPLETE_ACK:
346 	    if(pAnInfo->AbilityMatch == AN_TRUE &&
347 		pAnInfo->RxConfig.AsUSHORT == 0)
348 	    {
349 		pAnInfo->State = AN_STATE_AN_ENABLE;
350 		break;
351 	    }
352 
353 	    Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
354 
355 	    if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
356 	    {
357 		if(pAnInfo->mr_adv_next_page == 0 ||
358 		    pAnInfo->mr_lp_adv_next_page == 0)
359 		{
360 		    pAnInfo->State = AN_STATE_IDLE_DETECT_INIT;
361 		}
362 		else
363 		{
364 		    if(pAnInfo->TxConfig.bits.D15 == 0 &&
365 			pAnInfo->mr_np_rx == 0)
366 		    {
367 			pAnInfo->State = AN_STATE_IDLE_DETECT_INIT;
368 		    }
369 		    else
370 		    {
371 			AnRet = AUTONEG_STATUS_FAILED;
372 		    }
373 		}
374 	    }
375 
376 	    break;
377 
378 	case AN_STATE_IDLE_DETECT_INIT:
379 	    pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
380 
381 	    MM_AnTxIdle(pAnInfo);
382 
383 	    pAnInfo->State = AN_STATE_IDLE_DETECT;
384 
385 	    AnRet = AUTONEG_STATUS_TIMER_ENABLED;
386 
387 	    break;
388 
389 	case AN_STATE_IDLE_DETECT:
390 	    if(pAnInfo->AbilityMatch == AN_TRUE &&
391 		pAnInfo->RxConfig.AsUSHORT == 0)
392 	    {
393 		pAnInfo->State = AN_STATE_AN_ENABLE;
394 		break;
395 	    }
396 
397 	    Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
398 	    if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
399 	    {
400 #if 0
401 /*                if(pAnInfo->IdleMatch == AN_TRUE) */
402 /*                { */
403 #endif
404 		    pAnInfo->State = AN_STATE_LINK_OK;
405 #if 0
406 /*                } */
407 /*                else */
408 /*                { */
409 /*                    AnRet = AUTONEG_STATUS_FAILED; */
410 /*                    break; */
411 /*                } */
412 #endif
413 	    }
414 
415 	    break;
416 
417 	case AN_STATE_LINK_OK:
418 	    pAnInfo->mr_an_complete = AN_TRUE;
419 	    pAnInfo->mr_link_ok = AN_TRUE;
420 	    AnRet = AUTONEG_STATUS_DONE;
421 
422 	    break;
423 
424 	case AN_STATE_NEXT_PAGE_WAIT_INIT:
425 	    break;
426 
427 	case AN_STATE_NEXT_PAGE_WAIT:
428 	    break;
429 
430 	default:
431 	    AnRet = AUTONEG_STATUS_FAILED;
432 	    break;
433     }
434 
435     return AnRet;
436 }
437 #endif /* INCLUDE_TBI_SUPPORT */
438 
439 #endif /* !defined(CONFIG_NET_MULTI) */
440