⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ns9750_eth.c

📁 F:worksip2440a board可启动u-boot-like.tar.gz F:worksip2440a board可启动u-boot-like.tar.gz
💻 C
📖 第 1 页 / 共 2 页
字号:
	*get_eth_reg_addr (NS9750_ETH_MCFG) =		ns9750_mii_get_clock_divisor (nPhyMaxMdioClock);	/* reset PHY */	ns9750_mii_write (PHY_COMMON_CTRL, PHY_COMMON_CTRL_RESET);	ns9750_mii_write (PHY_COMMON_CTRL, 0);	/* @TODO check time */	udelay (3000);		/* [2] p.70 says at least 300us reset recovery time. But				   go sure, it didn't worked stable at higher timer				   frequencies under LxNETES-2.x */	/* MII clock has been setup to default, ns9750_mii_identify_phy should	   work for all */	if (!ns9750_mii_identify_phy ()) {		printk (KERN_ERR NS9750_DRIVER_NAME			": Unsupported PHY, aborting\n");		return 0;	}	/* now take the highest MDIO clock possible after detection */	*get_eth_reg_addr (NS9750_ETH_MCFG) =		ns9750_mii_get_clock_divisor (nPhyMaxMdioClock);	/* PHY has been detected, so there can be no abort reason and we can	   finish initializing ethernet */	uiLastLinkStatus = 0xff;	/* undefined */	if ((ucLinkMode & FS_EEPROM_AUTONEG_ENABLE_MASK) ==	    FS_EEPROM_AUTONEG_DISABLE)		/* use parameters defined */		ns9750_link_force ();	else		ns9750_link_auto_negotiate ();	if (phyDetected == PHY_LXT971A)		/* set LED2 to link mode */		ns9750_mii_write (PHY_LXT971_LED_CFG,				  PHY_LXT971_LED_CFG_LINK_ACT <<				  PHY_LXT971_LED_CFG_SHIFT_LED2);	return 1;}/*********************************************************************** * @Function: ns9750_link_force * @Return: void * @Descr: configures eth and MII to use the link mode defined in *	   ucLinkMode ***********************************************************************/static void ns9750_link_force (void){	unsigned short uiControl;	DEBUG_FN (DEBUG_LINK);	uiControl = ns9750_mii_read (PHY_COMMON_CTRL);	uiControl &= ~(PHY_COMMON_CTRL_SPD_MA |		       PHY_COMMON_CTRL_AUTO_NEG | PHY_COMMON_CTRL_DUPLEX);	uiLastLinkStatus = 0;	if ((ucLinkMode & FS_EEPROM_AUTONEG_SPEED_MASK) ==	    FS_EEPROM_AUTONEG_SPEED_100) {		uiControl |= PHY_COMMON_CTRL_SPD_100;		uiLastLinkStatus |= PHY_LXT971_STAT2_100BTX;	} else		uiControl |= PHY_COMMON_CTRL_SPD_10;	if ((ucLinkMode & FS_EEPROM_AUTONEG_DUPLEX_MASK) ==	    FS_EEPROM_AUTONEG_DUPLEX_FULL) {		uiControl |= PHY_COMMON_CTRL_DUPLEX;		uiLastLinkStatus |= PHY_LXT971_STAT2_DUPLEX_MODE;	}	ns9750_mii_write (PHY_COMMON_CTRL, uiControl);	ns9750_link_print_changed ();	ns9750_link_update_egcr ();}/*********************************************************************** * @Function: ns9750_link_auto_negotiate * @Return: void * @Descr: performs auto-negotation of link. ***********************************************************************/static void ns9750_link_auto_negotiate (void){	unsigned long ulStartJiffies;	unsigned short uiStatus;	DEBUG_FN (DEBUG_LINK);	/* run auto-negotation */	/* define what we are capable of */	ns9750_mii_write (PHY_COMMON_AUTO_ADV,			  PHY_COMMON_AUTO_ADV_100BTXFD |			  PHY_COMMON_AUTO_ADV_100BTX |			  PHY_COMMON_AUTO_ADV_10BTFD |			  PHY_COMMON_AUTO_ADV_10BT |			  PHY_COMMON_AUTO_ADV_802_3);	/* start auto-negotiation */	ns9750_mii_write (PHY_COMMON_CTRL,			  PHY_COMMON_CTRL_AUTO_NEG |			  PHY_COMMON_CTRL_RES_AUTO);	/* wait for completion */	ulStartJiffies = get_ticks ();	while (get_ticks () < ulStartJiffies + NS9750_MII_NEG_DELAY) {		uiStatus = ns9750_mii_read (PHY_COMMON_STAT);		if ((uiStatus &		     (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) ==		    (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) {			/* lucky we are, auto-negotiation succeeded */			ns9750_link_print_changed ();			ns9750_link_update_egcr ();			return;		}	}	DEBUG_ARGS0 (DEBUG_LINK, "auto-negotiation timed out\n");	/* ignore invalid link settings */}/*********************************************************************** * @Function: ns9750_link_update_egcr * @Return: void * @Descr: updates the EGCR and MAC2 link status after mode change or *	   auto-negotation ***********************************************************************/static void ns9750_link_update_egcr (void){	unsigned int unEGCR;	unsigned int unMAC2;	unsigned int unIPGT;	DEBUG_FN (DEBUG_LINK);	unEGCR = *get_eth_reg_addr (NS9750_ETH_EGCR1);	unMAC2 = *get_eth_reg_addr (NS9750_ETH_MAC2);	unIPGT = *get_eth_reg_addr (NS9750_ETH_IPGT) & ~NS9750_ETH_IPGT_MA;	unMAC2 &= ~NS9750_ETH_MAC2_FULLD;	if ((uiLastLinkStatus & PHY_LXT971_STAT2_DUPLEX_MODE)	    == PHY_LXT971_STAT2_DUPLEX_MODE) {		unMAC2 |= NS9750_ETH_MAC2_FULLD;		unIPGT |= 0x15; /* see [1] p. 339 */	} else		unIPGT |= 0x12; /* see [1] p. 339 */	*get_eth_reg_addr (NS9750_ETH_MAC2) = unMAC2;	*get_eth_reg_addr (NS9750_ETH_EGCR1) = unEGCR;	*get_eth_reg_addr (NS9750_ETH_IPGT) = unIPGT;}/*********************************************************************** * @Function: ns9750_link_print_changed * @Return: void * @Descr: checks whether the link status has changed and if so prints *	   the new mode ***********************************************************************/static void ns9750_link_print_changed (void){	unsigned short uiStatus;	unsigned short uiControl;	DEBUG_FN (DEBUG_LINK);	uiControl = ns9750_mii_read (PHY_COMMON_CTRL);	if ((uiControl & PHY_COMMON_CTRL_AUTO_NEG) ==	    PHY_COMMON_CTRL_AUTO_NEG) {		/* PHY_COMMON_STAT_LNK_STAT is only set on autonegotiation */		uiStatus = ns9750_mii_read (PHY_COMMON_STAT);		if (!(uiStatus & PHY_COMMON_STAT_LNK_STAT)) {			printk (KERN_WARNING NS9750_DRIVER_NAME				": link down\n");			/* @TODO Linux: carrier_off */		} else {			/* @TODO Linux: carrier_on */			if (phyDetected == PHY_LXT971A) {				uiStatus = ns9750_mii_read (PHY_LXT971_STAT2);				uiStatus &= (PHY_LXT971_STAT2_100BTX |					     PHY_LXT971_STAT2_DUPLEX_MODE |					     PHY_LXT971_STAT2_AUTO_NEG);				/* mask out all uninteresting parts */			}			/* other PHYs must store there link information in			   uiStatus as PHY_LXT971 */		}	} else {		/* mode has been forced, so uiStatus should be the same as the		   last link status, enforce printing */		uiStatus = uiLastLinkStatus;		uiLastLinkStatus = 0xff;	}	if (uiStatus != uiLastLinkStatus) {		/* save current link status */		uiLastLinkStatus = uiStatus;		/* print new link status */		printk (KERN_INFO NS9750_DRIVER_NAME			": link mode %i Mbps %s duplex %s\n",			(uiStatus & PHY_LXT971_STAT2_100BTX) ? 100 : 10,			(uiStatus & PHY_LXT971_STAT2_DUPLEX_MODE) ? "full" :			"half",			(uiStatus & PHY_LXT971_STAT2_AUTO_NEG) ? "(auto)" :			"");	}}/*********************************************************************** * the MII low level stuff ***********************************************************************//*********************************************************************** * @Function: ns9750_mii_identify_phy * @Return: 1 if supported PHY has been detected otherwise 0 * @Descr: checks for supported PHY and prints the IDs. ***********************************************************************/static char ns9750_mii_identify_phy (void){	unsigned short uiID1;	unsigned short uiID2;	unsigned char *szName;	char cRes = 0;	DEBUG_FN (DEBUG_MII);	phyDetected = (PhyType) uiID1 = ns9750_mii_read (PHY_COMMON_ID1);	switch (phyDetected) {	case PHY_LXT971A:		szName = "LXT971A";		uiID2 = ns9750_mii_read (PHY_COMMON_ID2);		nPhyMaxMdioClock = PHY_LXT971_MDIO_MAX_CLK;		cRes = 1;		break;	case PHY_NONE:	default:		/* in case uiID1 == 0 && uiID2 == 0 we may have the wrong		   address or reset sets the wrong NS9750_ETH_MCFG_CLKS */		uiID2 = 0;		szName = "unknown";		nPhyMaxMdioClock = PHY_MDIO_MAX_CLK;		phyDetected = PHY_NONE;	}	printk (KERN_INFO NS9750_DRIVER_NAME		": PHY (0x%x, 0x%x) = %s detected\n", uiID1, uiID2, szName);	return cRes;}/*********************************************************************** * @Function: ns9750_mii_read * @Return: the data read from PHY register uiRegister * @Descr: the data read may be invalid if timed out. If so, a message *	   is printed but the invalid data is returned. *	   The fixed device address is being used. ***********************************************************************/static unsigned short ns9750_mii_read (unsigned short uiRegister){	DEBUG_FN (DEBUG_MII_LOW);	/* write MII register to be read */	*get_eth_reg_addr (NS9750_ETH_MADR) =		NS9750_ETH_PHY_ADDRESS << 8 | uiRegister;	*get_eth_reg_addr (NS9750_ETH_MCMD) = NS9750_ETH_MCMD_READ;	if (!ns9750_mii_poll_busy ())		printk (KERN_WARNING NS9750_DRIVER_NAME			": MII still busy in read\n");	/* continue to read */	*get_eth_reg_addr (NS9750_ETH_MCMD) = 0;	return (unsigned short) (*get_eth_reg_addr (NS9750_ETH_MRDD));}/*********************************************************************** * @Function: ns9750_mii_write * @Return: nothing * @Descr: writes the data to the PHY register. In case of a timeout, *	   no special handling is performed but a message printed *	   The fixed device address is being used. ***********************************************************************/static void ns9750_mii_write (unsigned short uiRegister,			      unsigned short uiData){	DEBUG_FN (DEBUG_MII_LOW);	/* write MII register to be written */	*get_eth_reg_addr (NS9750_ETH_MADR) =		NS9750_ETH_PHY_ADDRESS << 8 | uiRegister;	*get_eth_reg_addr (NS9750_ETH_MWTD) = uiData;	if (!ns9750_mii_poll_busy ()) {		printf (KERN_WARNING NS9750_DRIVER_NAME			": MII still busy in write\n");	}}/*********************************************************************** * @Function: ns9750_mii_get_clock_divisor * @Return: the clock divisor that should be used in NS9750_ETH_MCFG_CLKS * @Descr: if no clock divisor can be calculated for the *	   current SYSCLK and the maximum MDIO Clock, a warning is printed *	   and the greatest divisor is taken ***********************************************************************/static unsigned int ns9750_mii_get_clock_divisor (unsigned int unMaxMDIOClk){	struct {		unsigned int unSysClkDivisor;		unsigned int unClks;	/* field for NS9750_ETH_MCFG_CLKS */	} PHYClockDivisors[] = {		{		4, NS9750_ETH_MCFG_CLKS_4}, {		6, NS9750_ETH_MCFG_CLKS_6}, {		8, NS9750_ETH_MCFG_CLKS_8}, {		10, NS9750_ETH_MCFG_CLKS_10}, {		20, NS9750_ETH_MCFG_CLKS_20}, {		30, NS9750_ETH_MCFG_CLKS_30}, {		40, NS9750_ETH_MCFG_CLKS_40}	};	int nIndexSysClkDiv;	int nArraySize =		sizeof (PHYClockDivisors) / sizeof (PHYClockDivisors[0]);	unsigned int unClks = NS9750_ETH_MCFG_CLKS_40;	/* defaults to							   greatest div */	DEBUG_FN (DEBUG_INIT);	for (nIndexSysClkDiv = 0; nIndexSysClkDiv < nArraySize;	     nIndexSysClkDiv++) {		/* find first sysclock divisor that isn't higher than 2.5 MHz		   clock */		if (AHB_CLK_FREQ /		    PHYClockDivisors[nIndexSysClkDiv].unSysClkDivisor <=		    unMaxMDIOClk) {			unClks = PHYClockDivisors[nIndexSysClkDiv].unClks;			break;		}	}	DEBUG_ARGS2 (DEBUG_INIT,		     "Taking MDIO Clock bit mask 0x%0x for max clock %i\n",		     unClks, unMaxMDIOClk);	/* return greatest divisor */	return unClks;}/*********************************************************************** * @Function: ns9750_mii_poll_busy * @Return: 0 if timed out otherwise the remaing timeout * @Descr: waits until the MII has completed a command or it times out *	   code may be interrupted by hard interrupts. *	   It is not checked what happens on multiple actions when *	   the first is still being busy and we timeout. ***********************************************************************/static unsigned int ns9750_mii_poll_busy (void){	unsigned int unTimeout = 10000;	DEBUG_FN (DEBUG_MII_LOW);	while (((*get_eth_reg_addr (NS9750_ETH_MIND) & NS9750_ETH_MIND_BUSY)		== NS9750_ETH_MIND_BUSY) && unTimeout)		unTimeout--;	return unTimeout;}#endif /* CONFIG_DRIVER_NS9750_ETHERNET */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -