openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

serdesassumed.c (27811B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        serdes.c
      8  * Purpose:
      9  * Requires:    
     10  */
     11 
     12 #include <sal/types.h>
     13 #include <sal/core/spl.h>
     14 
     15 #include <soc/drv.h>
     16 #include <soc/debug.h>
     17 #include <soc/error.h>
     18 #include <soc/phyreg.h>
     19 #include <shared/bsl.h>
     20 #include <soc/phy.h>
     21 #include <soc/phy/phyctrl.h>
     22 #include <soc/phy/drv.h>
     23 
     24 #include "phydefs.h"      /* Must include before other phy related includes */
     25 
     26 #if defined(_INCLUDE_SERDES_ASSUMED)
     27 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */
     28 #include "phyident.h"
     29 #include "phynull.h"
     30 #include "serdesassumed.h"
     31 
     32 /************************************************************************
     33  *									*
     34  *			SERDES Support					*
     35  */
     36 
     37 #define	SERDES_STABLE_TIME	2	/* # seconds to stablize */
     38 
     39 /*
     40  * Variable:
     41  *	serdes_state
     42  * Purpose:
     43  *	The serdes devices flap LINKOK/SYNCOK around in the wind
     44  *	for a long time as links are being negotiated etc. For this
     45  *	reason states for the GE ports that use the SERDES driver
     46  *	keeps state around. Those states marked as (timed) are required 
     47  *	to maintain their current state (or move forward) for 
     48  *	SERDES_STABLE_TIME. State transitions are:
     49  *
     50  *  	      | serReset|  serDOWN  | serSYNCOK |   serAN   | serUP
     51  *------------+---------+-----------+-----------+-----------+--------
     52  * SYNCOK=0   |		|	    |		|	    |
     53  * AN-Enable=0| serDOWN	|  serDOWN  |  serDOWN  |  serDOWN  | serRESET 
     54  * AN-Cmplt=0 |	(timed)	|	    |	        |  	    |
     55  *------------+---------+-----------+-----------+-----------+--------
     56  * SYNCOK=1   |		|	    |		|  	    |
     57  * AN-Enable=0| serDOWN | serSYNKOK |   serUP   |  serDOWN  | serUP
     58  * AN-Cmplt=0 |	(timed)	|  (timed)  |  (timed)  |  	    |
     59  *------------+---------+-----------+-----------+-----------+--------
     60  * SYNCOK=1   |		|	    |           |	    |
     61  * AN-Enable=1| serDOWN	| serSYNKOK |   serAN   |   serAN   |serRESET
     62  * AN-Cmplt=0 |	(timed)	|  (timed)  |  (timed)  |	    |
     63  *------------+---------+-----------+-----------+-----------+--------
     64  * SYNCOK=1   |		|	    |	      	|	    |
     65  * AN-Enable=1| serDOWN	| serSYNKOK |   serUP   |   serUP   | serUP
     66  * AN-Cmplt=1 |	(timed)	|  (timed)  |  (timed)  |	    |
     67  *------------+---------+-----------+----------+------------+--------
     68  */
     69 typedef struct {
     70     enum {    
     71 	serDISABLED,			/* Port is disabled */
     72 	serRESET,
     73 	serDOWN,
     74 	serSYNCOK,			/* SYNOK detected */
     75 	serAN,				/* Autonegotiation in progress */
     76 	serUP				/* Running */
     77     }			ser_state;
     78     sal_time_t		ser_time;	/* First LINKOK time */
     79 } serdes_state_t;
     80 
     81 STATIC serdes_state_t	*serdes_state[SOC_MAX_NUM_DEVICES];
     82 
     83 #define	SERDES_ALLOC(_u)	do { \
     84 	serdes_state[_u] = sal_alloc(SOC_MAX_NUM_PORTS * \
     85 					sizeof(serdes_state_t), \
     86 					"serdes_state"); \
     87 	sal_memset(serdes_state[_u], 0, SOC_MAX_NUM_PORTS * \
     88 					sizeof(serdes_state_t)); \
     89 	} while (0)
     90 #define	SERDES_IS_ALLOC(_u)	(serdes_state[_u])
     91 
     92 #define	SERDES(_u, _p)	(serdes_state[(_u)][(_p)])
     93 #define	SERDES_STABLE(_u, _p)	\
     94     ((sal_time() - SERDES((_u), (_p)).ser_time) >= SERDES_STABLE_TIME)
     95 
     96 #if defined(BROADCOM_DEBUG) 
     97 
     98 STATIC char *serdes_state_desc[] = {
     99     "serDISABLED", "serRESET", "serDOWN", "serSYNCOK", "serAN", "serUP"};
    100 
    101 #define	SERDES_TRANSITION(_u, _p, _s, _r) 			\
    102     LOG_VERBOSE(BSL_LS_SOC_LINK, \
    103                 (BSL_META_U((_u), \
    104                             "Unit %d Port %s Serdes State %s --> %s (%s)\n"),	\
    105                  (_u), SOC_PORT_NAME(_u, _p),			\
    106                  serdes_state_desc[SERDES((_u), (_p)).ser_state], 	\
    107                  serdes_state_desc[(_s)], (_r)));			\
    108      SERDES((_u), (_p)).ser_state = (_s);			\
    109      SERDES((_u), (_p)).ser_time  = sal_time()
    110 
    111 #define SERDES_RESET(_u, _p, _s)                                \
    112     LOG_VERBOSE(BSL_LS_SOC_LINK, \
    113                 (BSL_META_U((_u), \
    114                             "Unit %d Port %s Serdes RESET (%s)\n"),	\
    115                  (_u), SOC_PORT_NAME(_u, _p), (_s)));		\
    116      _phy_serdesassumed_reset((_u), (_p), FALSE)
    117 
    118 #else /* !defined(BROADCOM_DEBUG) */
    119 
    120 #define	SERDES_TRANSITION(_u, _p, _s, _r) 			\
    121      SERDES((_u), (_p)).ser_state = (_s);			\
    122      SERDES((_u), (_p)).ser_time  = sal_time()
    123 
    124 #define SERDES_RESET(_u, _p, _s) _phy_serdesassumed_reset((_u), (_p), FALSE)
    125 
    126 #endif  /* BROADCOM_DEBUG */
    127 
    128 /*
    129  * Function: 	
    130  *	_phy_serdesassumed_reset
    131  * Purpose:	
    132  *	Reset SERDES state machines.
    133  * Parameters:
    134  *	unit - StrataSwitch unit #.
    135  *	port - StrataSwitch port #. 
    136  *	enable - TRUE, enable port, FALSE, disable port
    137  * Returns:	
    138  *	SOC_E_XXXX
    139  * Notes:
    140  *	If the port is in disabled state, nothing is done. 
    141  */
    142 
    143 STATIC int
    144 _phy_serdesassumed_reset(int unit, soc_port_t port, int enable)
    145 {
    146     uint64	gpcsc;
    147     int		isdisabled;
    148 
    149     if (!SERDES_IS_ALLOC(unit)) {
    150 	isdisabled = 1;
    151     } else {
    152 	isdisabled = SERDES(unit, port).ser_state == serDISABLED;
    153     }
    154     if (enable || !isdisabled) {
    155 	if (!SERDES_IS_ALLOC(unit)) {
    156 	    SERDES_ALLOC(unit);
    157 	}
    158 	/*
    159 	 * Attempt to make sure the other end notices that we have dropped
    160 	 * the link.
    161 	 */
    162 	SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc));
    163 	soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DTRDf, 1);
    164 	soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DRRDf, 1);
    165 	SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc));
    166 	SERDES_TRANSITION(unit, port, serRESET, "Reset");
    167     }
    168 
    169     return(SOC_E_NONE);
    170 }
    171 
    172 /*
    173  * Function: 	
    174  *	phy_serdesassumed_enable_set
    175  * Purpose:	
    176  *	Enable or disable the physical interface.
    177  * Parameters:
    178  *	unit - StrataSwitch unit #.
    179  *	port - StrataSwitch port #. 
    180  *	enable - Boolean, true = enable PHY, false = disable.
    181  * Returns:	
    182  *	SOC_E_XXXX
    183  */
    184 
    185 STATIC int
    186 phy_serdesassumed_enable_set(int unit, soc_port_t port, int enable)
    187 {
    188     uint64	gpcsc;
    189 
    190     if (enable) {
    191 	SOC_IF_ERROR_RETURN(_phy_serdesassumed_reset(unit, port, TRUE));
    192     } else {
    193 	/*
    194 	 * Disable Disparity.
    195 	 */
    196 	SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc));
    197 	soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DTRDf, 1);
    198 	soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DRRDf, 1);
    199 	SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc));
    200 	SERDES_TRANSITION(unit, port, serDISABLED, "Disabled");
    201     }
    202 
    203     return(SOC_E_NONE);
    204 }
    205 
    206 /*
    207  * Function: 	
    208  *	phy_serdesassumed_enable_get
    209  * Purpose:	
    210  *	Enable or disable the physical interface for a SERDES device.
    211  * Parameters:
    212  *	unit - StrataSwitch unit #.
    213  *	port - StrataSwitch port #. 
    214  *	enable - (OUT) Boolean, true = enable PHY, false = disable.
    215  * Returns:	
    216  *	SOC_E_XXXX
    217  */
    218 
    219 STATIC int
    220 phy_serdesassumed_enable_get(int unit, soc_port_t port, int *enable)
    221 {
    222     if (SERDES_IS_ALLOC(unit)) {
    223 	*enable = (SERDES(unit, port).ser_state != serDISABLED);
    224     } else {
    225 	*enable = 0;
    226     }
    227     return(SOC_E_NONE);
    228 }
    229 
    230 /*
    231  * Function: 	
    232  *	_phy_serdesassumed_link
    233  * Purpose:	
    234  *	Determine the current link up/down status for a SERDES device, 
    235  * 	using the timeds state machine.
    236  * Parameters:
    237  *	unit - StrataSwitch unit #.
    238  *	port - StrataSwitch port #. 
    239  *	p_link - (OUT) Boolean, true indicates link established (may be NULL).
    240  *	p_an - (OUT) Boolean, true indicates AN is enabled (may be NULL).
    241  *	p_an_done - (OUT) Boolean, true indicates AN is complete (undefined
    242  *		if p_an is false, may be NULL).
    243  * Returns:	
    244  *	SOC_E_XXXX
    245  */
    246 
    247 STATIC int
    248 _phy_serdesassumed_link(int unit, soc_port_t port, 
    249 		 int *p_link, int *p_an, int *p_an_done)
    250 {
    251     uint64	anstt, anctl;
    252     int		sync_ok, an_enabled, an_done;
    253 
    254     SOC_IF_ERROR_RETURN(READ_ANSTTr(unit, port, &anstt));
    255     SOC_IF_ERROR_RETURN(READ_ANCTLr(unit, port, &anctl));
    256 
    257     sync_ok    = soc_reg64_field32_get(unit, ANSTTr, anstt, SYNCOKf);
    258     an_done    = soc_reg64_field32_get(unit, ANSTTr, anstt, ANCPLTf);
    259     an_enabled = soc_reg64_field32_get(unit, ANCTLr, anctl, ANENf);
    260 
    261     switch(SERDES(unit, port).ser_state) {
    262     case serDISABLED:
    263 	break;
    264     case serRESET:
    265 	if (SERDES_STABLE(unit, port)) {
    266 	    uint64	gpcsc;
    267 
    268 	    SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc));
    269 	    SERDES_TRANSITION(unit, port, serDOWN, "Reset Complete");
    270 	    soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DTRDf, 0);
    271 	    soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DRRDf, 0);
    272 	    SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc));
    273 	} else {
    274 	    break;
    275 	}
    276 	/* *** NOBREAK *** */
    277     case serDOWN:
    278 	if (!sync_ok) {
    279 	    break;
    280 	}
    281 	SERDES_TRANSITION(unit, port, serSYNCOK, "Sync OK detected");
    282 	/* *** NOBREAK *** */
    283     case serSYNCOK:
    284 	if (!sync_ok) {
    285 	    SERDES_TRANSITION(unit, port, serDOWN, "SYNCOK lost");
    286 	    break;
    287 	} 
    288 
    289 	if (SERDES_STABLE(unit, port)) {
    290 	    if (!an_enabled) {
    291 		SERDES_TRANSITION(unit, port, serUP, "SYNCOK stable, no AN");
    292 	    } else {
    293 		SERDES_TRANSITION(unit, port, serAN, "SYNCOK stable, AN");
    294 	    }
    295 	}
    296 	break;
    297     case serAN:
    298 	if (!an_enabled) {
    299 	    SERDES_TRANSITION(unit, port, serDOWN, "AN disabled");
    300 	} else if (!sync_ok) {
    301 	    SERDES_TRANSITION(unit, port, serDOWN, "SYNCOK lost");
    302 	} else if (an_done) {
    303 	    uint64	anlpa;
    304 
    305 	    SOC_IF_ERROR_RETURN(READ_ANLPAr(unit, port, &anlpa));
    306 
    307 	    if (soc_reg64_field32_get(unit, ANLPAr, anlpa, LPANERRf) != 0) {
    308 		uint64	anctl;
    309 
    310 		COMPILER_64_ZERO(anctl);
    311 
    312 		soc_reg64_field32_set(unit, ANCTLr, &anctl, ANENf, 1);
    313 		soc_reg64_field32_set(unit, ANCTLr, &anctl, RSTANf, 1);
    314 
    315 		SOC_IF_ERROR_RETURN(WRITE_ANCTLr(unit, port, anctl));
    316 
    317 		soc_reg64_field32_set(unit, ANCTLr, &anctl, RSTANf, 0);
    318 		SOC_IF_ERROR_RETURN(WRITE_ANCTLr(unit, port, anctl));
    319 		SERDES_TRANSITION(unit, port, serAN, "Remote Fault");
    320 	    } else {
    321 		SERDES_TRANSITION(unit, port, serUP, "AN Complete");
    322 	    }
    323 	}
    324 	break;
    325     case serUP:
    326 	if (!sync_ok) {
    327 	    SERDES_RESET(unit, port, "SYNCOK lost");
    328 	} else if (an_enabled && !an_done) {
    329 	    SERDES_RESET(unit, port, "AN-DONE lost");
    330         }
    331 	break;
    332     default:
    333 	assert(0);
    334     }
    335 
    336     if (p_link)    *p_link    = SERDES(unit, port).ser_state == serUP;
    337     if (p_an_done) *p_an_done = SERDES(unit, port).ser_state == serUP;
    338     if (p_an)      *p_an      = an_enabled;
    339 
    340     return(SOC_E_NONE);
    341 }
    342 
    343 #undef SERDES				/* Used in above routine ONLY */
    344 #undef SERDES_ALLOC			/* Used in above routine ONLY */
    345 #undef SERDES_IS_ALLOC			/* Used in above routine ONLY */
    346 #undef SERDES_STABLE			/* Used in above routine ONLY */
    347 #undef SERDES_TRANSITION		/* Used in above routnes ONLY */
    348 #undef SERDES_RESET			/* Used in above routnes ONLY */
    349 
    350 /*
    351  * Function: 	
    352  *	phy_serdesassumed_init
    353  * Purpose:	
    354  *	Initialize the SERDES to a known good state.
    355  * Parameters:
    356  *	unit - StrataSwitch unit #.
    357  *	port - StrataSwitch port #. 
    358  * Returns:	
    359  *	SOC_E_XXXX
    360  * Notes: 
    361  *	No synchronization performed at this level.
    362  */
    363 
    364 STATIC int
    365 phy_serdesassumed_init(int unit, soc_port_t port)
    366 {
    367     soc_phy_info_t	*pi = &SOC_PHY_INFO(unit, port);
    368     uint64		gpcsc, anctl, annpg, anstt;
    369 
    370     SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc));
    371     soc_reg64_field32_set(unit, GPCSCr, &gpcsc, AUTOSf, 0); /* AN off */
    372     soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DRRDf, 0);
    373     soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DTRDf, 0);
    374 
    375     if (!(pi->phy_flags & PHY_FLAGS_5421S)) {
    376 	soc_reg64_field32_set(unit, GPCSCr, &gpcsc, EWRAPf, 0);	/* loopback */
    377     }
    378     soc_reg64_field32_set(unit, GPCSCr, &gpcsc, JTRPSf, 4);
    379     soc_reg64_field32_set(unit, GPCSCr, &gpcsc, JTRPTf, 0);
    380     /* RCSELf set in mac.c */
    381     soc_reg64_field32_set(unit, GPCSCr, &gpcsc, SCLTf, 0);
    382     SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc));
    383 
    384     COMPILER_64_ZERO(anctl);
    385     soc_reg64_field32_set(unit, ANCTLr, &anctl, ANENf, 0);
    386     soc_reg64_field32_set(unit, ANCTLr, &anctl, RSTANf, 0);
    387     SOC_IF_ERROR_RETURN(WRITE_ANCTLr(unit, port, anctl));
    388 
    389     COMPILER_64_ZERO(anstt);
    390     soc_reg64_field32_set(unit, ANSTTr, &anstt, SYNCOKf, 0);
    391     soc_reg64_field32_set(unit, ANSTTr, &anstt, LINKOKf, 0);
    392     soc_reg64_field32_set(unit, ANSTTr, &anstt, PGRXf, 0);
    393     soc_reg64_field32_set(unit, ANSTTr, &anstt, ANCPLTf, 0);
    394     soc_reg64_field32_set(unit, ANSTTr, &anstt, RFINDf, 0);
    395     SOC_IF_ERROR_RETURN(WRITE_ANSTTr(unit, port, anstt));
    396 
    397     COMPILER_64_ZERO(annpg);
    398     soc_reg64_field32_set(unit, ANNPGr, &annpg, FDf, 1); /* Default advert FD */
    399     SOC_IF_ERROR_RETURN(WRITE_ANNPGr(unit, port, annpg));
    400 
    401     _phy_serdesassumed_reset(unit, port, TRUE);
    402 
    403     return(SOC_E_NONE);
    404 }
    405 
    406 /*
    407  * Function: 	
    408  *	phy_serdesassumed_link_get
    409  * Purpose:	
    410  *	Determine the current link up/down status for a SERDES device.
    411  * Parameters:
    412  *	unit - StrataSwitch unit #.
    413  *	port - StrataSwitch port #. 
    414  *	link - (OUT) Boolean, true indicates link established.
    415  * Returns:	
    416  *	SOC_E_XXXX
    417  * Notes: 
    418  *	No synchronization performed at this level. This routine will
    419  *	POLL the LINKOK/SYNCOK status if the link was not previously 
    420  *	detected as being up, but now appears so.
    421  */
    422 
    423 STATIC int
    424 phy_serdesassumed_link_get(int unit, soc_port_t port, int *link)
    425 {
    426     return(_phy_serdesassumed_link(unit, port, link, NULL, NULL));
    427 }
    428 
    429 /*
    430  * Function: 	
    431  *	phy_serdesassumed_duplex_set
    432  * Purpose:	
    433  *	Set the current duplex mode (forced).
    434  * Parameters:
    435  *	unit - StrataSwitch unit #.
    436  *	port - StrataSwitch port #. 
    437  *	duplex -Boolean, true indicates full duplex, false indicates half.
    438  * Returns:	
    439  *	SOC_E_NONE
    440  *	SOC_E_UNAVAIL - Half duplex requested, and not supported.
    441  * Notes: 
    442  *	No synchronization performed at this level. Autonegotiation is 
    443  *	not manipulated. 
    444  */
    445 
    446 STATIC int
    447 phy_serdesassumed_duplex_set(int unit, soc_port_t port, int duplex)
    448 {
    449     if (duplex) {
    450 	return (_phy_serdesassumed_reset(unit, port, FALSE));
    451     } else {
    452 	return (SOC_E_UNAVAIL);
    453     }
    454 }
    455 
    456 /*
    457  * Function: 	
    458  *	phy_serdesassumed_duplex_get
    459  * Purpose:	
    460  *	Get the current operating duplex mode. If autoneg is enabled, 
    461  *	then operating mode is returned, otherwise forced mode is returned.
    462  * Parameters:
    463  *	unit - StrataSwitch unit #.
    464  *	port - StrataSwitch port #. 
    465  *	duplex - (OUT) Boolean, true indicates full duplex, false 
    466  *		indicates half.
    467  * Returns:	
    468  *	SOC_E_NONE
    469  * Notes: 
    470  *	No synchronization performed at this level. Autonegotiation is 
    471  *	not manipulated. 
    472  */
    473 
    474 STATIC int
    475 phy_serdesassumed_duplex_get(int unit, soc_port_t port, int *duplex)
    476 {
    477     COMPILER_REFERENCE(unit);
    478     COMPILER_REFERENCE(port);
    479 
    480     *duplex = TRUE;
    481 
    482     return(SOC_E_NONE);
    483 }
    484 
    485 
    486 /*
    487  * Function: 	
    488  *	phy_serdesassumed_speed_set
    489  * Purpose:	
    490  *	Set the current operating speed (forced).
    491  * Parameters:
    492  *	unit - StrataSwitch unit #.
    493  *	port - StrataSwitch port #. 
    494  *	speed - Requested speed, only 1000 supported.
    495  * Returns:	
    496  *	SOC_E_XXXX
    497  */
    498 
    499 STATIC int
    500 phy_serdesassumed_speed_set(int unit, soc_port_t port, int speed)
    501 {
    502     if (speed == 0 || speed == 1000) {
    503 	return (_phy_serdesassumed_reset(unit, port, FALSE));
    504     } else {
    505 	return (SOC_E_CONFIG);
    506     }
    507 }
    508 
    509 /*
    510  * Function: 	
    511  *	phy_serdesassumed_speed_get
    512  * Purpose:	
    513  *	Get the current operating speed for a SERDES device.
    514  * Parameters:
    515  *	unit - StrataSwitch unit #.
    516  *	port - StrataSwitch port #. 
    517  *	duplex - (OUT) Boolean, true indicates full duplex, false 
    518  *		indicates half.
    519  * Returns:	
    520  *	SOC_E_NONE
    521  */
    522 
    523 STATIC int
    524 phy_serdesassumed_speed_get(int unit, soc_port_t port, int *speed)
    525 {
    526     COMPILER_REFERENCE(unit);
    527     COMPILER_REFERENCE(port);
    528 
    529     *speed = 1000;
    530 
    531     return(SOC_E_NONE);
    532 }
    533 
    534 /*
    535  * Function: 	
    536  *	phy_serdesassumed_master_set
    537  * Purpose:	
    538  *	Set the current master mode
    539  * Parameters:
    540  *	unit - StrataSwitch unit #.
    541  *	port - StrataSwitch port #. 
    542  *	master - SOC_PORT_MS_*
    543  * Returns:	
    544  *	SOC_E_XXXX
    545  */
    546 
    547 STATIC int
    548 phy_serdesassumed_master_set(int unit, soc_port_t port, int master)
    549 {
    550     COMPILER_REFERENCE(unit);
    551     COMPILER_REFERENCE(port);
    552     COMPILER_REFERENCE(master);
    553 
    554     return(SOC_E_NONE);
    555 }
    556 
    557 /*
    558  * Function: 	
    559  *	phy_serdesassumed_master_get
    560  * Purpose:	
    561  *	Get the current master mode for a SERDES device.
    562  * Parameters:
    563  *	unit - StrataSwitch unit #.
    564  *	port - StrataSwitch port #. 
    565  *	master - (OUT) SOC_PORT_MS_*
    566  * Returns:	
    567  *	SOC_E_NONE
    568  */
    569 
    570 STATIC int
    571 phy_serdesassumed_master_get(int unit, soc_port_t port, int *master)
    572 {
    573     COMPILER_REFERENCE(unit);
    574     COMPILER_REFERENCE(port);
    575 
    576     *master = SOC_PORT_MS_NONE;
    577 
    578     return(SOC_E_NONE);
    579 }
    580 
    581 /*
    582  * Function: 	
    583  *	phy_serdesassumed_an_set
    584  * Purpose:	
    585  *	Enable or disabled auto-negotiation on the specified port for a 
    586  *	SERDES device.
    587  * Parameters:
    588  *	unit - StrataSwitch unit #.
    589  *	port - StrataSwitch port #. 
    590  *	an   - Boolean, if true, auto-negotiation is enabled 
    591  *		(and/or restarted). If false, autonegotiation is disabled.
    592  * Returns:	
    593  *	SOC_E_XXXX - success
    594  */
    595 
    596 STATIC int
    597 phy_serdesassumed_an_set(int unit, soc_port_t port, int an)
    598 {
    599     uint64	anctl, gpcsc;
    600     int		autos;
    601 
    602     autos = soc_property_port_get(unit, port, spn_PHY_SERDES_AUTOS, 0);
    603 
    604     SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc));
    605     soc_reg64_field32_set(unit, GPCSCr, &gpcsc, AUTOSf,
    606                           (an && autos) ? 1 : 0);
    607     SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc));
    608 
    609     COMPILER_64_ZERO(anctl);
    610     soc_reg64_field32_set(unit, ANCTLr, &anctl, ANENf, an ? 1 : 0);
    611     soc_reg64_field32_set(unit, ANCTLr, &anctl, RSTANf, an ? 1 : 0);
    612     soc_reg64_field32_set(unit, GPCSCr, &gpcsc, AUTOSf, 0);
    613 
    614     SOC_IF_ERROR_RETURN(WRITE_ANCTLr(unit, port, anctl));
    615 
    616     soc_reg64_field32_set(unit, ANCTLr, &anctl, RSTANf, 0);
    617     SOC_IF_ERROR_RETURN(WRITE_ANCTLr(unit, port, anctl));
    618 
    619     return(_phy_serdesassumed_reset(unit, port, FALSE));
    620 }
    621 
    622 /*
    623  * Function: 	
    624  *	phy_serdesassumed_an_get
    625  * Purpose:	
    626  *	Get the current auto-negotiation status (enabled/busy)
    627  * Parameters:
    628  *	unit - StrataSwitch unit #.
    629  *	port - StrataSwitch port #. 
    630  *	an   - (OUT) if true, auto-negotiation is enabled.
    631  *	an_done - (OUT) if true, auto-negotioation is complete. This
    632  *	     	value is undefined if an == FALSE. 
    633  * Returns:	
    634  *	SOC_E_XXXX
    635  * Notes:
    636  *	This routine basis it's decision on the serdes S/W state, and not the 
    637  *	Hardware bit. This allows proper
    638  */
    639 
    640 STATIC int
    641 phy_serdesassumed_an_get(int unit, soc_port_t port, int *an, int *an_done)
    642 {
    643     return(_phy_serdesassumed_link(unit, port, NULL, an, an_done));
    644 }
    645 
    646 /*
    647  * Function: 	
    648  *	phy_serdesassumed_adv_local_set
    649  * Purpose:	
    650  *	Set the current advertisement for auto-negotiation.
    651  * Parameters:
    652  *	unit - StrataSwitch unit #.
    653  *	port - StrataSwitch port #. 
    654  *	mode - Port mode mask indicating supported options/speeds.
    655  * Returns:	
    656  *	SOC_E_XXXX
    657  * Notes: 
    658  *	No synchronization performed at this level. The only options
    659  *	that are supported are pause and FD/HD. Although this routine
    660  *	supports FD/HD, in reality, the MAC only supports FULL so we
    661  *	should never really see it.
    662  */
    663 
    664 STATIC int 
    665 phy_serdesassumed_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode)
    666 {
    667     uint64	annpg, gmacc0;
    668 
    669     mode &= SOC_PM_1000MB_FD | SOC_PM_PAUSE;
    670     COMPILER_64_ZERO(annpg);
    671 
    672     if (mode & SOC_PM_1000MB_FD) {
    673 	soc_reg64_field32_set(unit, ANNPGr, &annpg, FDf, 1);
    674     } else if (mode & SOC_PM_1000MB_HD) {
    675 	soc_reg64_field32_set(unit, ANNPGr, &annpg, FDf, 0);
    676     } else {
    677 	return(SOC_E_UNAVAIL);
    678     }
    679 
    680     switch (mode & SOC_PM_PAUSE) {
    681     case SOC_PM_PAUSE_TX:
    682 	soc_reg64_field32_set(unit, ANNPGr, &annpg, PAUSEf, 0);
    683 	soc_reg64_field32_set(unit, ANNPGr, &annpg, ASMDRf, 1);
    684 	break;
    685     case SOC_PM_PAUSE_RX:
    686 	soc_reg64_field32_set(unit, ANNPGr, &annpg, PAUSEf, 0);
    687 	soc_reg64_field32_set(unit, ANNPGr, &annpg, ASMDRf, 1);
    688 	break;
    689     case SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX:
    690 	soc_reg64_field32_set(unit, ANNPGr, &annpg, PAUSEf, 1);
    691 	soc_reg64_field32_set(unit, ANNPGr, &annpg, ASMDRf, 0);
    692 	break;
    693     default:				/* No flow control */
    694 	soc_reg64_field32_set(unit, ANNPGr, &annpg, PAUSEf, 0);
    695 	soc_reg64_field32_set(unit, ANNPGr, &annpg, ASMDRf, 0);
    696 	break;
    697     }
    698 
    699     SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0)); /* into reset */
    700     soc_reg64_field32_set(unit, GMACC0r, &gmacc0, SRSTf, 1);
    701     SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, gmacc0));
    702 
    703     SOC_IF_ERROR_RETURN(WRITE_ANNPGr(unit, port, annpg));
    704 
    705     soc_reg64_field32_set(unit, GMACC0r, &gmacc0, SRSTf, 0);
    706     SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, gmacc0)); /* out of reset */
    707 
    708     return(SOC_E_NONE);
    709 }
    710 
    711 /*
    712  * Function: 	
    713  *	phy_serdesassumed_adv_local_get
    714  * Purpose:	
    715  *	Get the current advertisement for auto-negotiation.
    716  * Parameters:
    717  *	unit - StrataSwitch unit #.
    718  *	port - StrataSwitch port #. 
    719  *	mode - (OUT) Port mode mask indicating supported options/speeds.
    720  * Returns:	
    721  *	SOC_E_XXXX
    722  * Notes: 
    723  *	No synchronization performed at this level.
    724  */
    725 
    726 STATIC int
    727 phy_serdesassumed_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    728 {
    729     uint64	annpg;
    730 
    731     *mode = 0;
    732 
    733     SOC_IF_ERROR_RETURN(READ_ANNPGr(unit, port, &annpg));
    734 
    735     if (soc_reg64_field32_get(unit, ANNPGr, annpg, FDf)) {
    736 	*mode = SOC_PM_1000MB_FD;
    737     } else {
    738 	*mode = SOC_PM_1000MB_HD;
    739     }
    740 
    741     /* PAUSE */
    742 
    743     if (soc_reg64_field32_get(unit, ANNPGr, annpg, ASMDRf)) {
    744 	if (soc_reg64_field32_get(unit, ANNPGr, annpg, PAUSEf)) {
    745 	    *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX;
    746 	} else {
    747 	    *mode |= SOC_PM_PAUSE_TX;
    748 	}
    749     } else {
    750 	if (soc_reg64_field32_get(unit, ANNPGr, annpg, PAUSEf)) {
    751 	    *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX;
    752 	} 
    753     }	
    754     return(SOC_E_NONE);
    755 }
    756 
    757 /*
    758  * Function: 	
    759  *	phy_serdesassumed_adv_remote_get
    760  * Purpose:	
    761  *	Get partners current advertisement for auto-negotiation.
    762  * Parameters:
    763  *	unit - StrataSwitch unit #.
    764  *	port - StrataSwitch port #. 
    765  *	mode - (OUT) Port mode mask indicating supported options/speeds.
    766  * Returns:	
    767  *	SOC_E_XXXX
    768  * Notes: 
    769  *	No synchronization performed at this level. If Autonegotiation is
    770  *	disabled or in progress, this routine will return an error.
    771  */
    772 
    773 STATIC int
    774 phy_serdesassumed_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    775 {
    776     uint64	anlpa;
    777     int		link, an, an_done;
    778 
    779     *mode = 0;
    780 
    781     SOC_IF_ERROR_RETURN(_phy_serdesassumed_link(unit, port, &link, &an, &an_done));
    782 
    783     if (!an) {
    784 	return(SOC_E_DISABLED);
    785     } else if (!an_done) {
    786 	return(SOC_E_BUSY);
    787     }
    788 	
    789     SOC_IF_ERROR_RETURN(READ_ANLPAr(unit, port, &anlpa));
    790 
    791     if (soc_reg64_field32_get(unit, ANLPAr, anlpa, LPANERRf)) {
    792 	return(SOC_E_FAIL);
    793     }
    794 
    795     /* Remote duplex negotiation */
    796     if (soc_reg64_field32_get(unit, ANLPAr, anlpa, LPFDf)) {
    797 	*mode |= SOC_PM_1000MB_FD;
    798     } else {
    799 	*mode |= SOC_PM_1000MB_HD;
    800     }
    801 
    802     /* Remote pause negotiation */
    803  
    804     if (soc_reg64_field32_get(unit, ANLPAr, anlpa, LPPAUSEf)) {
    805 	*mode |= SOC_PM_PAUSE;
    806     } else {
    807 	if (soc_reg64_field32_get(unit, ANLPAr, anlpa, LPASMDRf)) {
    808 	    *mode |= SOC_PM_PAUSE_TX;
    809 	}
    810     }
    811 
    812     return(SOC_E_NONE);
    813 }
    814 
    815 /*
    816  * Function: 	
    817  *	phy_serdesassumed_lb_set
    818  * Purpose:	
    819  *	Set the local PHY loopback mode.
    820  * Parameters:
    821  *	unit - StrataSwitch unit #.
    822  *	port - StrataSwitch port #. 
    823  *	loopback - Boolean: true = enable loopback, false = disable.
    824  * Returns:	
    825  *	SOC_E_XXXX
    826  * Notes: 
    827  *	No synchronization performed at this level.
    828  *
    829  *	Only the Even numbered EWRAP lines are visible outside
    830  *	the chip. Thus, the even numbered EWRAP line controls 
    831  *	both the specified port, and the specified port + 1.
    832  *	
    833  *	Although this is a matter of how the board is physically 
    834  *	wired, this is the only general mechanism that makes sense 
    835  *	for all the current chips. 
    836  */
    837 
    838 STATIC int
    839 phy_serdesassumed_lb_set(int unit, soc_port_t port, int enable)
    840 {
    841     soc_port_t		gp;
    842     uint64		gpcsc;
    843     int			poff;
    844 
    845     /*
    846      * The EWRAP line for GE0 fans out to both of the GIGs.
    847      * This means they are both in loopback at the same time, 
    848      * and we make this routine work by setting the port to GE0 if
    849      * we see GE1.
    850      */
    851 
    852     poff = SOC_PORT_OFFSET(unit, port);		/* eg: 3 if ge3 */
    853     poff &= ~1;					/* now 2 if ge3 */
    854     gp = SOC_PORT(unit, ge, poff);		/* get ge2 */
    855 
    856     SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, gp, &gpcsc));
    857     soc_reg64_field32_set(unit, GPCSCr, &gpcsc, EWRAPf, enable ? 1 : 0);
    858     SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, gp, gpcsc));
    859 
    860     return(SOC_E_NONE);
    861 }
    862 
    863 /*
    864  * Function: 	
    865  *	phy_serdesassumed_lb_get
    866  * Purpose:	
    867  *	Get the local SERDES loopback mode.
    868  * Parameters:
    869  *	unit - StrataSwitch unit #.
    870  *	port - StrataSwitch port #. 
    871  *	loopback - (OUT) Boolean: true = enable loopback, false = disable.
    872  * Returns:	
    873  *	SOC_E_XXXX
    874  */
    875 
    876 STATIC int
    877 phy_serdesassumed_lb_get(int unit, soc_port_t port, int *enable)
    878 {
    879     soc_port_t	gp;
    880     uint64	gpcsc;
    881     int		poff;
    882 
    883     /*
    884      * See phy_serdesassumed_lb_set()
    885      */
    886     poff = SOC_PORT_OFFSET(unit, port);		/* eg: 3 if ge3 */
    887     poff &= ~1;					/* now 2 if ge3 */
    888     gp = SOC_PORT(unit, ge, poff);		/* get ge2 */
    889 
    890     SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, gp, &gpcsc));
    891     *enable = soc_reg64_field32_get(unit, GPCSCr, gpcsc, EWRAPf) ? TRUE : FALSE;
    892 
    893     return(SOC_E_NONE);
    894 }
    895 
    896 /*
    897  * Function:
    898  *	phy_serdesassumed_interface_set
    899  * Purpose:
    900  *	Set the current operating mode of the PHY (TBI or MII/GMII)
    901  * Parameters:
    902  *	unit - StrataSwitch unit #.
    903  *	port - StrataSwitch port #. 
    904  *	pif - one of SOC_PORT_IF_*
    905  * Returns:
    906  *	SOC_E_XXXX
    907  */
    908 
    909 STATIC int
    910 phy_serdesassumed_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
    911 {
    912     COMPILER_REFERENCE(unit);
    913     COMPILER_REFERENCE(port);
    914 
    915     switch (pif) {
    916     case SOC_PORT_IF_TBI:
    917 	return SOC_E_NONE;
    918     default:
    919 	return SOC_E_UNAVAIL;
    920     }
    921 }
    922 
    923 /*
    924  * Function:
    925  *	phy_serdesassumed_interface_get
    926  * Purpose:
    927  *	Get the current operating mode of the PHY (TBI or MII/GMII)
    928  *	for SERDES device.
    929  * Parameters:
    930  *	unit - StrataSwitch unit #.
    931  *	port - StrataSwitch port #. 
    932  *	pif - (OUT) Interface
    933  * Returns:
    934  *	SOC_E_XXXX
    935  */
    936 
    937 STATIC int
    938 phy_serdesassumed_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
    939 {
    940     COMPILER_REFERENCE(unit);
    941     COMPILER_REFERENCE(port);
    942 
    943     *pif = SOC_PORT_IF_TBI;
    944     return(SOC_E_NONE);
    945 }
    946 
    947 /*
    948  * Function: 	
    949  *	phy_serdesassumed_ability_get
    950  * Purpose:	
    951  *	Get the abilities of the local gigabit phy.
    952  * Parameters:
    953  *	unit - StrataSwitch unit #.
    954  *	port - StrataSwitch port #. 
    955  *	mode - (OUT) Port mode mask indicating supported options/speeds.
    956  * Returns:	
    957  *	SOC_E_NONE
    958  */
    959 
    960 STATIC int 
    961 phy_serdesassumed_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
    962 {
    963     COMPILER_REFERENCE(unit);
    964     COMPILER_REFERENCE(port);
    965 
    966     *mode = (SOC_PM_AN | SOC_PM_LB_PHY |
    967 	     SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM |
    968 	     SOC_PM_TBI | SOC_PM_1000MB_FD);
    969 
    970     return(SOC_E_NONE);
    971 }
    972 
    973 /*
    974  * Variable:	phy_serdesassumed_ge
    975  * Purpose:	Phy driver callouts for SERDES interface
    976  */
    977 phy_driver_t phy_serdesassumed_ge = {
    978     "Assumed SERDES Driver",
    979     phy_serdesassumed_init, 
    980     phy_null_reset,
    981     phy_serdesassumed_link_get, 
    982     phy_serdesassumed_enable_set, 
    983     phy_serdesassumed_enable_get, 
    984     phy_serdesassumed_duplex_set, 
    985     phy_serdesassumed_duplex_get, 
    986     phy_serdesassumed_speed_set, 
    987     phy_serdesassumed_speed_get, 
    988     phy_serdesassumed_master_set,
    989     phy_serdesassumed_master_get,
    990     phy_serdesassumed_an_set, 
    991     phy_serdesassumed_an_get, 
    992     phy_serdesassumed_adv_local_set,
    993     phy_serdesassumed_adv_local_get, 
    994     phy_serdesassumed_adv_remote_get,
    995     phy_serdesassumed_lb_set,
    996     phy_serdesassumed_lb_get,
    997     phy_serdesassumed_interface_set, 
    998     phy_serdesassumed_interface_get, 
    999     phy_serdesassumed_ability_get,
   1000     NULL,
   1001     NULL,
   1002     phy_null_mdix_set,
   1003     phy_null_mdix_get,
   1004     phy_null_mdix_status_get,
   1005     NULL,
   1006     NULL,
   1007     phy_null_medium_get,
   1008     NULL,                       /* phy_cable_diag  */
   1009     NULL,                       /* phy_link_change */
   1010     NULL,                       /* phy_control_set */
   1011     NULL,                       /* phy_control_get */
   1012     NULL,                       /* phy_reg_read */
   1013     NULL,                       /* phy_reg_write */
   1014     NULL                        /* phy_reg_modify */
   1015 };
   1016 
   1017 #else /* INCLUDE_SERDES_ASSUMED */
   1018 int _phy_serdesassumed_not_empty;
   1019 #endif /* INCLUDE_SERDES_ASSUMED */
   1020