4xx_enet.c

来自「最新版的u-boot,2008-10-18发布」· C语言 代码 · 共 2,136 行 · 第 1/5 页

C
2,136
字号
#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) */#if defined(CONFIG_GPCS_PHY_ADDR) || defined(CONFIG_GPCS_PHY1_ADDR) || \    defined(CONFIG_GPCS_PHY2_ADDR) || defined(CONFIG_GPCS_PHY3_ADDR)	if (bis->bi_phymode[devnum] == BI_PHYMODE_SGMII) {		/*		 * In SGMII mode, GPCS access is needed for		 * communication with the internal SGMII SerDes.		 */		switch (devnum) {#if defined(CONFIG_GPCS_PHY_ADDR)		case 0:			reg = CONFIG_GPCS_PHY_ADDR;			break;#endif#if defined(CONFIG_GPCS_PHY1_ADDR)		case 1:			reg = CONFIG_GPCS_PHY1_ADDR;			break;#endif#if defined(CONFIG_GPCS_PHY2_ADDR)		case 2:			reg = CONFIG_GPCS_PHY2_ADDR;			break;#endif#if defined(CONFIG_GPCS_PHY3_ADDR)		case 3:			reg = CONFIG_GPCS_PHY3_ADDR;			break;#endif		}		mode_reg = in_be32((void *)EMAC_M1 + hw_p->hw_addr);		mode_reg |= EMAC_M1_MF_1000GPCS | EMAC_M1_IPPA_SET(reg);		out_be32((void *)EMAC_M1 + hw_p->hw_addr, mode_reg);		/* Configure GPCS interface to recommended setting for SGMII */		miiphy_reset(dev->name, reg);		miiphy_write(dev->name, reg, 0x04, 0x8120); /* AsymPause, FDX */		miiphy_write(dev->name, reg, 0x07, 0x2801); /* msg_pg, toggle */		miiphy_write(dev->name, reg, 0x00, 0x0140); /* 1Gbps, FDX     */	}#endif /* defined(CONFIG_GPCS_PHY_ADDR) */	/* wait for PHY to complete auto negotiation */	reg_short = 0;	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 (reg == CONFIG_FIXED_PHY)		goto get_speed;#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#if defined(CONFIG_M88E1112_PHY)		if (bis->bi_phymode[devnum] == BI_PHYMODE_SGMII) {			/*			 * Marvell 88E1112 PHY needs to have the SGMII MAC			 * interace (page 2) properly configured to			 * communicate with the 460EX/GT GPCS interface.			 */			/* Set access to Page 2 */			miiphy_write(dev->name, reg, 0x16, 0x0002);			miiphy_write(dev->name, reg, 0x00, 0x0040); /* 1Gbps */			miiphy_read(dev->name, reg, 0x1a, &reg_short);			reg_short |= 0x8000; /* bypass Auto-Negotiation */			miiphy_write(dev->name, reg, 0x1a, reg_short);			miiphy_reset(dev->name, reg); /* reset MAC interface */			/* Reset access to Page 0 */			miiphy_write(dev->name, reg, 0x16, 0x0000);		}#endif /* defined(CONFIG_M88E1112_PHY) */		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 /* defined(CONFIG_CIS8201_PHY) */#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 /* defined(CONFIG_ET1011C_PHY) */#endif /* defined(CONFIG_440GX) ... */		/* 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) */	}get_speed:	if (reg == CONFIG_FIXED_PHY) {		for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) {			if (devnum == fixed_phy_port[i].devnum) {				speed = fixed_phy_port[i].speed;				duplex = fixed_phy_port[i].duplex;				break;			}		}		if (i == ARRAY_SIZE(fixed_phy_port)) {			printf("ERROR: PHY (%s) not configured correctly!\n",				dev->name);			return -1;		}	} else {		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)

⌨️ 快捷键说明

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