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

📄 smc91111.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 3 页
字号:
	     cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5]);	/* Set up hardware address */	for (i = 0; i < sizeof(cpd->enaddr); i += 2)		put_reg(cpd, LAN91CXX_IA01 + i / 2,			cpd->enaddr[i] | (cpd->enaddr[i + 1] << 8));	return 1;}/*  This function is called to "start up" the interface.  It may be called  multiple times, even when the hardware is already running.  It will be  called whenever something "hardware oriented" changes and should leave  the hardware ready to send/receive packets.*/static void lan91cxx_start(struct ifnet *ifp){	struct lan91cxx_priv_data *cpd = ifp->if_softc;	cyg_uint16 intr;	cyg_uint16 phy_ctl;	int delay;	DEBUG_FUNCTION();	HAL_DELAY_US(100000);	/* 91C111 Errata. Internal PHY comes up disabled. Must enable here. */	phy_ctl = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CTRL);	phy_ctl &= ~LAN91CXX_PHY_CTRL_MII_DIS;	lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, phy_ctl);	/* Start auto-negotiation */	put_reg(cpd, LAN91CXX_RPCR,		LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |		LAN91CXX_RPCR_ANEG);	cpd->rpc_cur_mode =	    LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |	    LAN91CXX_RPCR_ANEG;	/* wait for auto-negotiation to finish. */	/* give it ~5 seconds before giving up (no cable?) */	delay = 50;	while (!(lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT) & 0x20)) {		if (--delay <= 0) {			printf("Timeout autonegotiation\n");			break;		}		HAL_DELAY_US(100000);	}	put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);	put_reg(cpd, LAN91CXX_INTERRUPT, 0);	/* disable interrupts */	intr = get_reg(cpd, LAN91CXX_INTERRUPT);	put_reg(cpd, LAN91CXX_INTERRUPT, intr &	/* ack old interrupts */		(LAN91CXX_INTERRUPT_TX_INT |		 LAN91CXX_INTERRUPT_TX_EMPTY_INT |		 LAN91CXX_INTERRUPT_RX_OVRN_INT | LAN91CXX_INTERRUPT_ERCV_INT));	put_reg(cpd, LAN91CXX_RCR,		LAN91CXX_RCR_STRIP_CRC | LAN91CXX_RCR_RXEN |		LAN91CXX_RCR_ALMUL);	put_reg(cpd, LAN91CXX_TCR, LAN91CXX_TCR_TXENA | LAN91CXX_TCR_PAD_EN);	put_reg(cpd, LAN91CXX_CONTROL, LAN91CXX_CONTROL_AUTO_RELEASE);	/*  */	put_reg(cpd, LAN91CXX_INTERRUPT,	/* enable interrupts */		LAN91CXX_INTERRUPT_RCV_INT_M);	if ((0#ifdef ETH_DRV_FLAGS_PROMISC_MODE	     != (flags & ETH_DRV_FLAGS_PROMISC_MODE)#endif	    ) || (ifp->if_flags & IFF_PROMISC)	    ) {		/* Then we select promiscuous mode. */		unsigned short rcr;		rcr = get_reg(cpd, LAN91CXX_RCR);		rcr |= LAN91CXX_RCR_PRMS;		put_reg(cpd, LAN91CXX_RCR, rcr);	}}/* \ ------------- Probe ------------- \ */static const char *chip_ids[15] = {	NULL, NULL, NULL,	/* 3 */ "SMC91C90/91C92",	/* 4 */ "SMC91C94",	/* 5 */ "SMC91C95",	/* 6 */ "SMC91C96",	/* 7 */ "SMC91C100",	/* 8 */ "SMC91C100FD",	/* 9 */ "SMC91C11xFD",	NULL, NULL,	NULL, NULL, NULL};static int smc_probe(struct lan91cxx_priv_data *cpd){	unsigned short bank;	unsigned short revision_register;	DEBUG_FUNCTION();	/* First, see if the high byte is 0x33 */	HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);	bank = CYG_LE16_TO_CPU(bank);	if ((bank & 0xFF00) != 0x3300) {		db_printf("<1>Smc probe bank check 1 failed.\n");		return -ENODEV;	}	/* The above MIGHT indicate a device, but I need to write to further	   test this.  */	HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), CYG_CPU_TO_LE16(0 >> 3));	HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);	bank = CYG_LE16_TO_CPU(bank);	if ((bank & 0xFF00) != 0x3300) {		db_printf("<1>Smc probe bank check 2 failed.\n");		return -ENODEV;	}#if SMC_DEBUG > 3	{		unsigned short bank16, bank16_0, bank16_1;		HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank16);		bank = CYG_LE16_TO_CPU(bank);		HAL_READ_UINT8(cpd->base + (LAN91CXX_BS), bank16_0);		HAL_READ_UINT8(cpd->base + (LAN91CXX_BS + 1), bank16_1);		db_printf		    ("smc_probe:Bank read as a 16 bit value:0x%04x\n", bank16);		db_printf		    ("smc_probe:Bank read as an 8 bit value:0x%02x\n",		     bank16_0);		db_printf		    ("smc_probe:Bank + 1 read as an 8 bit value:0x%02x\n",		     bank16_1);	}#endif	/*  check if the revision register is something that I recognize.	   These might need to be added to later, as future revisions	   could be added.  */	revision_register = get_reg(cpd, LAN91CXX_REVISION);	if (!chip_ids[(revision_register >> 4) & 0xF]) {		/* I don't recognize this chip, so... */		db_printf		    ("smc_probe: IO %x: Unrecognized revision register:"		     " %x, Contact author. \n", (unsigned int)cpd->base,		     revision_register);		return -ENODEV;	}	db_printf("LAN91CXX(0x%x) - type: %s, rev: %01x\n",		  revision_register,		  chip_ids[(revision_register >> 4) & 0xF],		  revision_register & 0xf);	/* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */	if (revision_register == 0x3390) {		db_printf("!Revision A\n");	}	return 0;}#if 0/* \ ------------- PHY read/write ------------- \ *//*Sets the PHY to a configuration as determined by the user*/static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd){	int my_fixed_caps;	int cfg1;	DEBUG_FUNCTION();	db4_printf("lan91cxx_phy_fixed: full duplex: %d, speed: %d\n",		   cpd->config.ctl_rfduplx, cpd->config.ctl_rspeed);	/* Enter Link Disable state */	cfg1 = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CONFIG1);	cfg1 |= PHY_CFG1_LNKDIS;	lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CONFIG1, cfg1);	/* Set our fixed capabilities, Disable auto-negotiation */	my_fixed_caps = 0;	if (cpd->config.ctl_rfduplx)		my_fixed_caps |= LAN91CXX_PHY_CTRL_DPLX;	if (cpd->config.ctl_rspeed == 100)		my_fixed_caps |= LAN91CXX_PHY_CTRL_SPEED;	/* Write capabilities to the phy control register */	lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, my_fixed_caps);	/* Re-Configure the Receive/Phy Control register */	put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);	return (1);}#endif#if 0/*Configures the specified PHY using Autonegotiation. */static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd){	unsigned int phyaddr;	unsigned int my_phy_caps;	/* My PHY capabilities */	unsigned int my_ad_caps;	/* My Advertised capabilities */	unsigned int status = 0;	int failed = 0, delay;	DEBUG_FUNCTION();	/* Set the blocking flag */	cpd->autoneg_active = 1;	/* Get the detected phy address */	phyaddr = cpd->phyaddr;	/* Reset the PHY, setting all other bits to zero */	lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG, PHY_CNTL_RST);	/* Wait for the reset to complete, or time out */	delay = 50;	while (delay--) {		if (!(lan91cxx_read_phy(cpd, 0, PHY_CNTL_REG)		      & PHY_CNTL_RST)) {			break;		}		HAL_DELAY_US(100000);	}	if (delay < 1) {		db_printf("smc91111:!PHY reset timed out\n");		goto smc_phy_configure_exit;	}	/* Read PHY Register 18, Status Output */	cpd->lastPhy18 = lan91cxx_read_phy(cpd, 0, PHY_INT_REG);	/* Enable PHY Interrupts (for register 18) */	/* Interrupts listed here are disabled */	lan91cxx_write_phy(cpd, 0, PHY_MASK_REG,			   PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD			   | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |			   PHY_INT_SPDDET | PHY_INT_DPLXDET);	/* Configure the Receive/Phy Control register */	put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);	/* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */	my_phy_caps = lan91cxx_read_phy(cpd, phyaddr, PHY_STAT_REG);	my_ad_caps = PHY_AD_CSMA;	/* I am CSMA capable */	if (my_phy_caps & PHY_STAT_CAP_T4)		my_ad_caps |= PHY_AD_T4;	if (my_phy_caps & PHY_STAT_CAP_TXF)		my_ad_caps |= PHY_AD_TX_FDX;	if (my_phy_caps & PHY_STAT_CAP_TXH)		my_ad_caps |= PHY_AD_TX_HDX;	if (my_phy_caps & PHY_STAT_CAP_TF)		my_ad_caps |= PHY_AD_10_FDX;	if (my_phy_caps & PHY_STAT_CAP_TH)		my_ad_caps |= PHY_AD_10_HDX;	/* Disable capabilities not selected by our user */	if (cpd->config.ctl_rspeed != 100) {		my_ad_caps &= ~(PHY_AD_T4 | PHY_AD_TX_FDX | PHY_AD_TX_HDX);	}	if (!cpd->config.ctl_rfduplx) {		my_ad_caps &= ~(PHY_AD_TX_FDX | PHY_AD_10_FDX);	}	/* Update our Auto-Neg Advertisement Register */	lan91cxx_write_phy(cpd, 0, PHY_AD_REG, my_ad_caps);	db4_printf("smc91111:phy caps=%x\n", my_phy_caps);	db4_printf("smc91111:phy advertised caps=%x\n", my_ad_caps);	/* If the user requested no auto neg, then go set his request */	if (!(cpd->config.ctl_autoneg)) {		lan91cxx_phy_fixed(cpd);		goto smc_phy_configure_exit;	}	/* Restart auto-negotiation process in order to advertise my caps */	lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,			   PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);	/* wait for auto-negotiation to finish. */	/* give it ~5 seconds before giving up (no cable?) */	delay = 50;	while (!	       ((status =		 lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT)) & 0x20)) {		if (--delay <= 0) {			printf("Timeout autonegotiation\n");			failed = 1;			break;		}		/* Restart auto-negotiation if remote fault */		if (status & PHY_STAT_REM_FLT) {			db_printf("smc91111:PHY remote fault detected\n");			/* Restart auto-negotiation */			db_printf("smc91111:PHY restarting auto-negotiation\n");			lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,					   PHY_CNTL_ANEG_EN |					   PHY_CNTL_ANEG_RST |					   PHY_CNTL_SPEED | PHY_CNTL_DPLX);		}		HAL_DELAY_US(100000);	}	/* Fail if we detected an auto-negotiate remote fault */	if (status & PHY_STAT_REM_FLT) {		db_printf("smc91111:PHY remote fault detected\n");		failed = 1;	}	/* The smc_phy_interrupt() routine will be called to update lastPhy18 */	/* Set our sysctl parameters to match auto-negotiation results */	if (cpd->lastPhy18 & PHY_INT_SPDDET) {		db_printf("smc91111:PHY 100BaseT\n");		cpd->rpc_cur_mode |= LAN91CXX_RPCR_SPEED;	} else {		db_printf("smc91111:PHY 10BaseT\n");		cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_SPEED;	}	if (cpd->lastPhy18 & PHY_INT_DPLXDET) {		db_printf("smc91111:PHY Full Duplex\n");		cpd->rpc_cur_mode |= LAN91CXX_RPCR_DPLX;	} else {		db_printf("smc91111:PHY Half Duplex\n");		cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_DPLX;	}	/* Re-Configure the Receive/Phy Control register */	put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);      smc_phy_configure_exit:	/* Exit auto-negotiation */	cpd->autoneg_active = 0;}#endifstatic cyg_uint16lan91cxx_read_phy(struct lan91cxx_priv_data *cpd, cyg_uint8 phyaddr,		  cyg_uint8 phyreg){	int i, mask, input_idx, clk_idx = 0;	cyg_uint16 mii_reg, value;	cyg_uint8 bits[64];	/* 32 consecutive ones on MDO to establish sync */	for (i = 0; i < 32; ++i)		bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;	/* Start code <01> */	bits[clk_idx++] = LAN91CXX_MGMT_MDOE;	bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;	/* Read command <10> */	bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;	bits[clk_idx++] = LAN91CXX_MGMT_MDOE;	/* Output the PHY address, msb first */	for (mask = 0x10; mask; mask >>= 1) {		if (phyaddr & mask)			bits[clk_idx++] =			    LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;		else			bits[clk_idx++] = LAN91CXX_MGMT_MDOE;	}	/* Output the phy register number, msb first */	for (mask = 0x10; mask; mask >>= 1) {		if (phyreg & mask)			bits[clk_idx++] =			    LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;		else			bits[clk_idx++] = LAN91CXX_MGMT_MDOE;	}	/* Tristate and turnaround (1 bit times) */	bits[clk_idx++] = 0;	/* Input starts at this bit time */	input_idx = clk_idx;	/* Will input 16 bits */	for (i = 0; i < 16; ++i)		bits[clk_idx++] = 0;	/* Final clock bit */	bits[clk_idx++] = 0;	/* Get the current MII register value */	mii_reg = get_reg(cpd, LAN91CXX_MGMT);	/* Turn off all MII Interface bits */	mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |		     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);	HAL_DELAY_US(50);	/* Clock all 64 cycles */	for (i = 0; i < sizeof(bits); ++i) {		/* Clock Low - output data */		put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);		HAL_DELAY_US(50);		/* Clock Hi - input data */		put_reg(cpd, LAN91CXX_MGMT,			mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);		HAL_DELAY_US(50);		bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;	}	/* Return to idle state */	put_reg(cpd, LAN91CXX_MGMT, mii_reg);	HAL_DELAY_US(50);	/* Recover input data */	for (value = 0, i = 0; i < 16; ++i) {		value <<= 1;		if (bits[input_idx++] & LAN91CXX_MGMT_MDI)			value |= 1;	}	db16_printf("phy_read : %d : %04x\n", phyreg, value);	return value;}static voidlan91cxx_write_phy(struct lan91cxx_priv_data *cpd, cyg_uint8 phyaddr,		   cyg_uint8 phyreg, cyg_uint16 value){	int i, mask, clk_idx = 0;	cyg_uint16 mii_reg;	cyg_uint8 bits[65];	/* 32 consecutive ones on MDO to establish sync */	for (i = 0; i < 32; ++i)		bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;	/* Start code <01> */	bits[clk_idx++] = LAN91CXX_MGMT_MDOE;	bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;	/* Write command <01> */	bits[clk_idx++] = LAN91CXX_MGMT_MDOE;	bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;	/* Output the PHY address, msb first */	for (mask = 0x10; mask; mask >>= 1) {		if (phyaddr & mask)			bits[clk_idx++] =			    LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;		else			bits[clk_idx++] = LAN91CXX_MGMT_MDOE;	}	/* Output the phy register number, msb first */	for (mask = 0x10; mask; mask >>= 1) {		if (phyreg & mask)			bits[clk_idx++] =			    LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;		else			bits[clk_idx++] = LAN91CXX_MGMT_MDOE;	}	/* Tristate and turnaround (2 bit times) */	bits[clk_idx++] = 0;	bits[clk_idx++] = 0;	/* Write out 16 bits of data, msb first */	for (mask = 0x8000; mask; mask >>= 1) {		if (value & mask)			bits[clk_idx++] =			    LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;		else			bits[clk_idx++] = LAN91CXX_MGMT_MDOE;	}	/* Final clock bit (tristate) */	bits[clk_idx++] = 0;	/* Get the current MII register value */	mii_reg = get_reg(cpd, LAN91CXX_MGMT);	/* Turn off all MII Interface bits */	mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |		     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);	HAL_DELAY_US(50);	/* Clock all cycles */	for (i = 0; i < sizeof(bits); ++i) {		/* Clock Low - output data */		put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);		HAL_DELAY_US(50);		/* Clock Hi - input data */		put_reg(cpd, LAN91CXX_MGMT,			mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);		HAL_DELAY_US(50);/*	bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;*/	}	/* Return to idle state */	put_reg(cpd, LAN91CXX_MGMT, mii_reg);	HAL_DELAY_US(50);	db16_printf("phy_write: %d : %04x\n", phyreg, value);}#endif

⌨️ 快捷键说明

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