4xx_enet.c

来自「uboot详细解读可用启动引导LINUX2.6内核」· C语言 代码 · 共 2,100 行 · 第 1/4 页

C
2,100
字号
	 *	460EX has 1 RGMII bridge core:	 *	and RGMII1_BASE is disabled	 *		emac0 ------ RGMII0_BASE	 *		           |	 *		emac1 -----+	 */	/*	 * Right now only 2*RGMII is supported. Please extend when needed.	 * sr - 2008-02-19	 */	switch (mode) {	case 1:		/* 1 MII - 460EX */		/* GMC0 EMAC4_0, ZMII Bridge */		zmiifer |= ZMII_FER_MII << ZMII_FER_V(0);		bis->bi_phymode[0] = BI_PHYMODE_MII;		bis->bi_phymode[1] = BI_PHYMODE_NONE;		bis->bi_phymode[2] = BI_PHYMODE_NONE;		bis->bi_phymode[3] = BI_PHYMODE_NONE;		break;	case 2:		/* 2 MII - 460GT */		/* GMC0 EMAC4_0, GMC1 EMAC4_2, ZMII Bridge */		zmiifer |= ZMII_FER_MII << ZMII_FER_V(0);		zmiifer |= ZMII_FER_MII << ZMII_FER_V(2);		bis->bi_phymode[0] = BI_PHYMODE_MII;		bis->bi_phymode[1] = BI_PHYMODE_NONE;		bis->bi_phymode[2] = BI_PHYMODE_MII;		bis->bi_phymode[3] = BI_PHYMODE_NONE;		break;	case 3:		/* 2 RMII - 460EX */		/* GMC0 EMAC4_0, GMC0 EMAC4_1, ZMII Bridge */		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);		bis->bi_phymode[0] = BI_PHYMODE_RMII;		bis->bi_phymode[1] = BI_PHYMODE_RMII;		bis->bi_phymode[2] = BI_PHYMODE_NONE;		bis->bi_phymode[3] = BI_PHYMODE_NONE;		break;	case 4:		/* 4 RMII - 460GT */		/* GMC0 EMAC4_0, GMC0 EMAC4_1, GMC1 EMAC4_2, GMC1, EMAC4_3 */		/* ZMII Bridge */		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(1);		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(2);		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(3);		bis->bi_phymode[0] = BI_PHYMODE_RMII;		bis->bi_phymode[1] = BI_PHYMODE_RMII;		bis->bi_phymode[2] = BI_PHYMODE_RMII;		bis->bi_phymode[3] = BI_PHYMODE_RMII;		break;	case 5:		/* 2 SMII - 460EX */		/* GMC0 EMAC4_0, GMC0 EMAC4_1, ZMII Bridge */		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);		bis->bi_phymode[0] = BI_PHYMODE_SMII;		bis->bi_phymode[1] = BI_PHYMODE_SMII;		bis->bi_phymode[2] = BI_PHYMODE_NONE;		bis->bi_phymode[3] = BI_PHYMODE_NONE;		break;	case 6:		/* 4 SMII - 460GT */		/* GMC0 EMAC4_0, GMC0 EMAC4_1, GMC0 EMAC4_3, GMC0 EMAC4_3 */		/* ZMII Bridge */		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(2);		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(3);		bis->bi_phymode[0] = BI_PHYMODE_SMII;		bis->bi_phymode[1] = BI_PHYMODE_SMII;		bis->bi_phymode[2] = BI_PHYMODE_SMII;		bis->bi_phymode[3] = BI_PHYMODE_SMII;		break;	case 7:		/* This is the default mode that we want for board bringup - Maple */		/* 1 GMII - 460EX */		/* GMC0 EMAC4_0, RGMII Bridge 0 */		rmiifer |= RGMII_FER_MDIO(0);		if (devnum == 0) {			rmiifer |= RGMII_FER_GMII << RGMII_FER_V(2); /* CH0CFG - EMAC0 */			bis->bi_phymode[0] = BI_PHYMODE_GMII;			bis->bi_phymode[1] = BI_PHYMODE_NONE;			bis->bi_phymode[2] = BI_PHYMODE_NONE;			bis->bi_phymode[3] = BI_PHYMODE_NONE;		} else {			rmiifer |= RGMII_FER_GMII << RGMII_FER_V(3); /* CH1CFG - EMAC1 */			bis->bi_phymode[0] = BI_PHYMODE_NONE;			bis->bi_phymode[1] = BI_PHYMODE_GMII;			bis->bi_phymode[2] = BI_PHYMODE_NONE;			bis->bi_phymode[3] = BI_PHYMODE_NONE;		}		break;	case 8:		/* 2 GMII - 460GT */		/* GMC0 EMAC4_0, RGMII Bridge 0 */		/* GMC1 EMAC4_2, RGMII Bridge 1 */		rmiifer |= RGMII_FER_GMII << RGMII_FER_V(2);	/* CH0CFG - EMAC0 */		rmiifer1 |= RGMII_FER_GMII << RGMII_FER_V(2);	/* CH0CFG - EMAC2 */		rmiifer |= RGMII_FER_MDIO(0);			/* enable MDIO - EMAC0 */		rmiifer1 |= RGMII_FER_MDIO(0);			/* enable MDIO - EMAC2 */		bis->bi_phymode[0] = BI_PHYMODE_GMII;		bis->bi_phymode[1] = BI_PHYMODE_NONE;		bis->bi_phymode[2] = BI_PHYMODE_GMII;		bis->bi_phymode[3] = BI_PHYMODE_NONE;		break;	case 9:		/* 2 RGMII - 460EX */		/* GMC0 EMAC4_0, GMC0 EMAC4_1, RGMII Bridge 0 */		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);		rmiifer |= RGMII_FER_MDIO(0);			/* enable MDIO - EMAC0 */		bis->bi_phymode[0] = BI_PHYMODE_RGMII;		bis->bi_phymode[1] = BI_PHYMODE_RGMII;		bis->bi_phymode[2] = BI_PHYMODE_NONE;		bis->bi_phymode[3] = BI_PHYMODE_NONE;		break;	case 10:		/* 4 RGMII - 460GT */		/* GMC0 EMAC4_0, GMC0 EMAC4_1, RGMII Bridge 0 */		/* GMC1 EMAC4_2, GMC1 EMAC4_3, RGMII Bridge 1 */		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);		rmiifer1 |= RGMII_FER_RGMII << RGMII_FER_V(2);		rmiifer1 |= RGMII_FER_RGMII << RGMII_FER_V(3);		bis->bi_phymode[0] = BI_PHYMODE_RGMII;		bis->bi_phymode[1] = BI_PHYMODE_RGMII;		bis->bi_phymode[2] = BI_PHYMODE_RGMII;		bis->bi_phymode[3] = BI_PHYMODE_RGMII;		break;	default:		break;	}	/* Set EMAC for MDIO */	mfsdr(SDR0_ETH_CFG, eth_cfg);	eth_cfg |= SDR0_ETH_CFG_MDIO_SEL_EMAC0;	mtsdr(SDR0_ETH_CFG, eth_cfg);	out_be32((void *)RGMII_FER, rmiifer);#if defined(CONFIG_460GT)	out_be32((void *)RGMII_FER + RGMII1_BASE_OFFSET, rmiifer1);#endif	/* bypass the TAHOE0/TAHOE1 cores for U-Boot */	mfsdr(SDR0_ETH_CFG, eth_cfg);	eth_cfg |= (SDR0_ETH_CFG_TAHOE0_BYPASS | SDR0_ETH_CFG_TAHOE1_BYPASS);	mtsdr(SDR0_ETH_CFG, eth_cfg);	return 0;}#endif /* CONFIG_460EX || CONFIG_460GT */static inline void *malloc_aligned(u32 size, u32 align){	return (void *)(((u32)malloc(size + align) + align - 1) &			~(align - 1));}static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis){	int i;	unsigned long reg = 0;	unsigned long msr;	unsigned long speed;	unsigned long duplex;	unsigned long failsafe;	unsigned mode_reg;	unsigned short devnum;	unsigned short reg_short;#if defined(CONFIG_440GX) || \    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \    defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \    defined(CONFIG_405EX)	sys_info_t sysinfo;#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \    defined(CONFIG_405EX)	int ethgroup = -1;#endif#endif	u32 bd_cached;	u32 bd_uncached = 0;#ifdef CONFIG_4xx_DCACHE	static u32 last_used_ea = 0;#endif#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \    defined(CONFIG_405EX)	int rgmii_channel;#endif	EMAC_4XX_HW_PST hw_p = dev->priv;	/* before doing anything, figure out if we have a MAC address */	/* if not, bail */	if (memcmp (dev->enetaddr, "\0\0\0\0\0\0", 6) == 0) {		printf("ERROR: ethaddr not set!\n");		return -1;	}#if defined(CONFIG_440GX) || \    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \    defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \    defined(CONFIG_405EX)	/* Need to get the OPB frequency so we can access the PHY */	get_sys_info (&sysinfo);#endif	msr = mfmsr ();	mtmsr (msr & ~(MSR_EE));	/* disable interrupts */	devnum = hw_p->devnum;#ifdef INFO_4XX_ENET	/* AS.HARNOIS	 * We should have :	 * hw_p->stats.pkts_handled <=	hw_p->stats.pkts_rx <= hw_p->stats.pkts_handled+PKTBUFSRX	 * In the most cases hw_p->stats.pkts_handled = hw_p->stats.pkts_rx, but it	 * is possible that new packets (without relationship with	 * current transfer) have got the time to arrived before	 * netloop calls eth_halt	 */	printf ("About preceeding transfer (eth%d):\n"		"- Sent packet number %d\n"		"- Received packet number %d\n"		"- Handled packet number %d\n",		hw_p->devnum,		hw_p->stats.pkts_tx,		hw_p->stats.pkts_rx, hw_p->stats.pkts_handled);	hw_p->stats.pkts_tx = 0;	hw_p->stats.pkts_rx = 0;	hw_p->stats.pkts_handled = 0;	hw_p->print_speed = 1;	/* print speed message again next time */#endif	hw_p->tx_err_index = 0; /* Transmit Error Index for tx_err_log */	hw_p->rx_err_index = 0; /* Receive Error Index for rx_err_log */	hw_p->rx_slot = 0;	/* MAL Receive Slot */	hw_p->rx_i_index = 0;	/* Receive Interrupt Queue Index */	hw_p->rx_u_index = 0;	/* Receive User Queue Index */	hw_p->tx_slot = 0;	/* MAL Transmit Slot */	hw_p->tx_i_index = 0;	/* Transmit Interrupt Queue Index */	hw_p->tx_u_index = 0;	/* Transmit User Queue Index */#if defined(CONFIG_440) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)	/* set RMII mode */	/* NOTE: 440GX spec states that mode is mutually exclusive */	/* NOTE: Therefore, disable all other EMACS, since we handle */	/* NOTE: only one emac at a time */	reg = 0;	out_be32((void *)ZMII_FER, 0);	udelay (100);#if defined(CONFIG_440GP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)	out_be32((void *)ZMII_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));#elif defined(CONFIG_440GX) || \    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \    defined(CONFIG_460EX) || defined(CONFIG_460GT)	ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);#endif	out_be32((void *)ZMII_SSR, ZMII_SSR_SP << ZMII_SSR_V(devnum));#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */#if defined(CONFIG_405EX)	ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);#endif	sync();	/* provide clocks for EMAC internal loopback  */	emac_loopback_enable(hw_p);	/* EMAC RESET */	out_be32((void *)EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);	/* remove clocks for EMAC internal loopback  */	emac_loopback_disable(hw_p);	failsafe = 1000;	while ((in_be32((void *)EMAC_M0 + hw_p->hw_addr) & (EMAC_M0_SRST)) && failsafe) {		udelay (1000);		failsafe--;	}	if (failsafe <= 0)		printf("\nProblem resetting EMAC!\n");#if defined(CONFIG_440GX) || \    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \    defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \    defined(CONFIG_405EX)	/* Whack the M1 register */	mode_reg = 0x0;	mode_reg &= ~0x00000038;	if (sysinfo.freqOPB <= 50000000);	else if (sysinfo.freqOPB <= 66666667)		mode_reg |= EMAC_M1_OBCI_66;	else if (sysinfo.freqOPB <= 83333333)		mode_reg |= EMAC_M1_OBCI_83;	else if (sysinfo.freqOPB <= 100000000)		mode_reg |= EMAC_M1_OBCI_100;	else		mode_reg |= EMAC_M1_OBCI_GT100;	out_be32((void *)EMAC_M1 + hw_p->hw_addr, mode_reg);#endif /* defined(CONFIG_440GX) || defined(CONFIG_440SP) */	/* wait for PHY to complete auto negotiation */	reg_short = 0;#ifndef CONFIG_CS8952_PHY	switch (devnum) {	case 0:		reg = CONFIG_PHY_ADDR;		break;#if defined (CONFIG_PHY1_ADDR)	case 1:		reg = CONFIG_PHY1_ADDR;		break;#endif#if defined (CONFIG_PHY2_ADDR)	case 2:		reg = CONFIG_PHY2_ADDR;		break;#endif#if defined (CONFIG_PHY3_ADDR)	case 3:		reg = CONFIG_PHY3_ADDR;		break;#endif	default:		reg = CONFIG_PHY_ADDR;		break;	}	bis->bi_phynum[devnum] = reg;#if defined(CONFIG_PHY_RESET)	/*	 * Reset the phy, only if its the first time through	 * otherwise, just check the speeds & feeds	 */	if (hw_p->first_init == 0) {#if defined(CONFIG_M88E1111_PHY)		miiphy_write (dev->name, reg, 0x14, 0x0ce3);		miiphy_write (dev->name, reg, 0x18, 0x4101);		miiphy_write (dev->name, reg, 0x09, 0x0e00);		miiphy_write (dev->name, reg, 0x04, 0x01e1);#endif		miiphy_reset (dev->name, reg);#if defined(CONFIG_440GX) || \    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \    defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \    defined(CONFIG_405EX)#if defined(CONFIG_CIS8201_PHY)		/*		 * Cicada 8201 PHY needs to have an extended register whacked		 * for RGMII mode.		 */		if (((devnum == 2) || (devnum == 3)) && (4 == ethgroup)) {#if defined(CONFIG_CIS8201_SHORT_ETCH)			miiphy_write (dev->name, reg, 23, 0x1300);#else			miiphy_write (dev->name, reg, 23, 0x1000);#endif			/*			 * Vitesse VSC8201/Cicada CIS8201 errata:			 * Interoperability problem with Intel 82547EI phys			 * This work around (provided by Vitesse) changes			 * the default timer convergence from 8ms to 12ms			 */			miiphy_write (dev->name, reg, 0x1f, 0x2a30);			miiphy_write (dev->name, reg, 0x08, 0x0200);			miiphy_write (dev->name, reg, 0x1f, 0x52b5);			miiphy_write (dev->name, reg, 0x02, 0x0004);			miiphy_write (dev->name, reg, 0x01, 0x0671);			miiphy_write (dev->name, reg, 0x00, 0x8fae);			miiphy_write (dev->name, reg, 0x1f, 0x2a30);			miiphy_write (dev->name, reg, 0x08, 0x0000);			miiphy_write (dev->name, reg, 0x1f, 0x0000);			/* end Vitesse/Cicada errata */		}#endif#if defined(CONFIG_ET1011C_PHY)		/*		 * Agere ET1011c PHY needs to have an extended register whacked		 * for RGMII mode.		 */		if (((devnum == 2) || (devnum ==3)) && (4 == ethgroup)) {			miiphy_read (dev->name, reg, 0x16, &reg_short);			reg_short &= ~(0x7);			reg_short |= 0x6;	/* RGMII DLL Delay*/			miiphy_write (dev->name, reg, 0x16, reg_short);			miiphy_read (dev->name, reg, 0x17, &reg_short);			reg_short &= ~(0x40);			miiphy_write (dev->name, reg, 0x17, reg_short);			miiphy_write(dev->name, reg, 0x1c, 0x74f0);		}#endif#endif		/* Start/Restart autonegotiation */		phy_setup_aneg (dev->name, reg);		udelay (1000);	}#endif /* defined(CONFIG_PHY_RESET) */	miiphy_read (dev->name, reg, PHY_BMSR, &reg_short);	/*	 * Wait if PHY is capable of autonegotiation and autonegotiation is not complete	 */	if ((reg_short & PHY_BMSR_AUTN_ABLE)	    && !(reg_short & PHY_BMSR_AUTN_COMP)) {		puts ("Waiting for PHY auto negotiation to complete");		i = 0;		while (!(reg_short & PHY_BMSR_AUTN_COMP)) {			/*			 * Timeout reached ?			 */			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {				puts (" TIMEOUT !\n");				break;			}			if ((i++ % 1000) == 0) {				putc ('.');			}			udelay (1000);	/* 1 ms */			miiphy_read (dev->name, reg, PHY_BMSR, &reg_short);		}		puts (" done\n");		udelay (500000);	/* another 500 ms (results in faster booting) */	}#endif /* #ifndef CONFIG_CS8952_PHY */	speed = miiphy_speed (dev->name, reg);	duplex = miiphy_duplex (dev->name, reg);	if (hw_p->print_speed) {		hw_p->print_speed = 0;		printf ("ENET Speed is %d Mbps - %s duplex connection (EMAC%d)\n",			(int) speed, (duplex == HALF) ? "HALF" : "FULL",			hw_p->devnum);	}#if defined(CONFIG_440) && \    !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \    !defined(CONFIG_440EPX) && !defined(CONFIG_440GRX) && \    !defined(CONFIG_460EX) && !defined(CONFIG_460GT)#if defined(CONFIG_440EP) || defined(CONFIG_440GR)	mfsdr(sdr_mfr, reg);	if (speed == 100) {		reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_100M;	} else {		reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_10M;	}	mtsdr(sdr_mfr, reg);#endif	/* Set ZMII/RGMII speed according to the phy link speed */	reg = in_be32((void *)ZMII_SSR);	if ( (speed == 100) || (speed == 1000) )		out_be32((void *)ZMII_SSR, reg | (ZMII_SSR_SP << ZMII_SSR_V (devnum)));	else		out_be32((void *)ZMII_SSR, reg & (~(ZMII_SSR_SP << ZMII_SSR_V (devnum))));	if ((devnum == 2) || (devnum == 3)) {		if (speed == 1000)			reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V (devnum));		else if (speed == 100)			reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V (devnum));		else if (speed == 10)			reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V (devnum));		else {			printf("Error in RGMII Speed\n");			return -1;		}		out_be32((void *)RGMII_SSR, reg);	}#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \    defined(CONFIG_405EX)	if (devnum >= 2)		rgmii_channel = devnum - 2;	else		rgmii_channel = devnum;	if (speed == 1000)		reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V(rgmii_channel));	else if (speed == 100)		reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V(rgmii_channel));	else if (speed == 10)		reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V(rgmii_channel));	else {		printf("Error in RGMII Speed\n");		return -1;	}	out_be32((void *)RGMII_SSR, reg);#if defined(CONFIG_460GT)	if ((devnum == 2) || (devnum == 3))		out_be32((void *)RGMII_SSR + RGMII1_BASE_OFFSET, reg);#endif#endif

⌨️ 快捷键说明

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