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

📄 440gx_enet.c.svn-base

📁 u-boot for S3c2443 processor
💻 SVN-BASE
📖 第 1 页 / 共 3 页
字号:
/*-----------------------------------------------------------------------------+ * *       This source code has been made available to you by IBM on an AS-IS *       basis.  Anyone receiving this source is licensed under IBM *       copyrights to use it in any way he or she deems fit, including *       copying it, modifying it, compiling it, and redistributing it either *       with or without modifications.  No license under IBM patents or *       patent applications is to be implied by the copyright license. * *       Any user of this software should understand that IBM cannot provide *       technical support for this software and will not be responsible for *       any consequences resulting from the use of this software. * *       Any person who transfers this source code or any derivative work *       must include the IBM copyright notice, this paragraph, and the *       preceding two paragraphs in the transferred software. * *       COPYRIGHT   I B M   CORPORATION 1995 *       LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M *-----------------------------------------------------------------------------*//*-----------------------------------------------------------------------------+ * *  File Name:  enetemac.c * *  Function:   Device driver for the ethernet EMAC3 macro on the 405GP. * *  Author:     Mark Wisner * *  Change Activity- * *  Date        Description of Change                                       BY *  ---------   ---------------------                                       --- *  05-May-99   Created                                                     MKW *  27-Jun-99   Clean up                                                    JWB *  16-Jul-99   Added MAL error recovery and better IP packet handling      MKW *  29-Jul-99   Added Full duplex support                                   MKW *  06-Aug-99   Changed names for Mal CR reg                                MKW *  23-Aug-99   Turned off SYE when running at 10Mbs                        MKW *  24-Aug-99   Marked descriptor empty after call_xlc                      MKW *  07-Sep-99   Set MAL RX buffer size reg to ENET_MAX_MTU_ALIGNED / 16     MCG *              to avoid chaining maximum sized packets. Push starting *              RX descriptor address up to the next cache line boundary. *  16-Jan-00   Added support for booting with IP of 0x0                    MKW *  15-Mar-00   Updated enetInit() to enable broadcast addresses in the *	        EMAC_RXM register.                                          JWB *  12-Mar-01   anne-sophie.harnois@nextream.fr *               - Variables are compatible with those already defined in *                include/net.h *              - Receive buffer descriptor ring is used to send buffers *                to the user *              - Info print about send/received/handled packet number if *                INFO_405_ENET is set *  17-Apr-01   stefan.roese@esd-electronics.com *              - MAL reset in "eth_halt" included *              - Enet speed and duplex output now in one line *  08-May-01   stefan.roese@esd-electronics.com *              - MAL error handling added (eth_init called again) *  13-Nov-01   stefan.roese@esd-electronics.com *              - Set IST bit in EMAC_M1 reg upon 100MBit or full duplex *  04-Jan-02   stefan.roese@esd-electronics.com *              - Wait for PHY auto negotiation to complete added *  06-Feb-02   stefan.roese@esd-electronics.com *              - Bug fixed in waiting for auto negotiation to complete *  26-Feb-02   stefan.roese@esd-electronics.com *              - rx and tx buffer descriptors now allocated (no fixed address *                used anymore) *  17-Jun-02   stefan.roese@esd-electronics.com *              - MAL error debug printf 'M' removed (rx de interrupt may *                occur upon many incoming packets with only 4 rx buffers). *-----------------------------------------------------------------------------* *  17-Nov-03   travis.sawyer@sandburst.com *              - ported from 405gp_enet.c to utilized upto 4 EMAC ports *                in the 440GX.  This port should work with the 440GP *                (2 EMACs) also *-----------------------------------------------------------------------------*/#include <config.h>#if defined(CONFIG_440) && defined(CONFIG_NET_MULTI)#include <common.h>#include <net.h>#include <asm/processor.h>#include <ppc440.h>#include <commproc.h>#include <440gx_enet.h>#include <405_mal.h>#include <miiphy.h>#include <malloc.h>#include "vecnum.h"#define EMAC_RESET_TIMEOUT 1000	/* 1000 ms reset timeout */#define PHY_AUTONEGOTIATE_TIMEOUT 4000	/* 4000 ms autonegotiate timeout *//* Ethernet Transmit and Receive Buffers *//* AS.HARNOIS * In the same way ENET_MAX_MTU and ENET_MAX_MTU_ALIGNED are set from * PKTSIZE and PKTSIZE_ALIGN (include/net.h) */#define ENET_MAX_MTU           PKTSIZE#define ENET_MAX_MTU_ALIGNED   PKTSIZE_ALIGN/* define the number of channels implemented */#define EMAC_RXCHL      EMAC_NUM_DEV#define EMAC_TXCHL      EMAC_NUM_DEV/*-----------------------------------------------------------------------------+ * Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal * Interrupt Controller). *-----------------------------------------------------------------------------*/#define MAL_UIC_ERR ( UIC_MAL_SERR | UIC_MAL_TXDE  | UIC_MAL_RXDE)#define MAL_UIC_DEF  (UIC_MAL_RXEOB | MAL_UIC_ERR)#define EMAC_UIC_DEF UIC_ENET#undef INFO_440_ENET#define BI_PHYMODE_NONE  0#define BI_PHYMODE_ZMII  1#define BI_PHYMODE_RGMII 2/*-----------------------------------------------------------------------------+ * Global variables. TX and RX descriptors and buffers. *-----------------------------------------------------------------------------*//* IER globals */static uint32_t mal_ier;/*-----------------------------------------------------------------------------+ * Prototypes and externals. *-----------------------------------------------------------------------------*/static void enet_rcv (struct eth_device *dev, unsigned long malisr);int enetInt (struct eth_device *dev);static void mal_err (struct eth_device *dev, unsigned long isr,		     unsigned long uic, unsigned long maldef,		     unsigned long mal_errr);static void emac_err (struct eth_device *dev, unsigned long isr);/*-----------------------------------------------------------------------------+| ppc_440x_eth_halt| Disable MAL channel, and EMACn||+-----------------------------------------------------------------------------*/static void ppc_440x_eth_halt (struct eth_device *dev){	EMAC_440GX_HW_PST hw_p = dev->priv;	uint32_t failsafe = 10000;	out32 (EMAC_IER + hw_p->hw_addr, 0x00000000);	/* disable emac interrupts */	/* 1st reset MAL channel */	/* Note: writing a 0 to a channel has no effect */	mtdcr (maltxcarr, (MAL_CR_MMSR >> hw_p->devnum));	mtdcr (malrxcarr, (MAL_CR_MMSR >> hw_p->devnum));	/* wait for reset */	while (mfdcr (maltxcasr) & (MAL_CR_MMSR >> hw_p->devnum)) {		udelay (1000);	/* Delay 1 MS so as not to hammer the register */		failsafe--;		if (failsafe == 0)			break;	}	/* EMAC RESET */	out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);	hw_p->print_speed = 1;	/* print speed message again next time */	return;}extern int phy_setup_aneg (unsigned char addr);extern int miiphy_reset (unsigned char addr);#if defined (CONFIG_440_GX)int ppc_440x_eth_setup_bridge(int devnum, bd_t * bis){	unsigned long pfc1;	unsigned long zmiifer;	unsigned long rmiifer;	mfsdr(sdr_pfc1, pfc1);	pfc1 = SDR0_PFC1_EPS_DECODE(pfc1);	zmiifer = 0;	rmiifer = 0;	switch (pfc1) {	case 1:		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_ZMII;		bis->bi_phymode[1] = BI_PHYMODE_ZMII;		bis->bi_phymode[2] = BI_PHYMODE_ZMII;		bis->bi_phymode[3] = BI_PHYMODE_ZMII;		break;	case 2:		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_ZMII;		bis->bi_phymode[1] = BI_PHYMODE_ZMII;		bis->bi_phymode[2] = BI_PHYMODE_ZMII;		bis->bi_phymode[3] = BI_PHYMODE_ZMII;		break;	case 3:		zmiifer |= ZMII_FER_RMII << ZMII_FER_V(0);		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);		bis->bi_phymode[0] = BI_PHYMODE_ZMII;		bis->bi_phymode[1] = BI_PHYMODE_NONE;		bis->bi_phymode[2] = BI_PHYMODE_RGMII;		bis->bi_phymode[3] = BI_PHYMODE_NONE;		break;	case 4:		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(0);		zmiifer |= ZMII_FER_SMII << ZMII_FER_V(1);		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V (2);		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V (3);		bis->bi_phymode[0] = BI_PHYMODE_ZMII;		bis->bi_phymode[1] = BI_PHYMODE_ZMII;		bis->bi_phymode[2] = BI_PHYMODE_RGMII;		bis->bi_phymode[3] = BI_PHYMODE_RGMII;		break;	case 5:		zmiifer |= ZMII_FER_SMII << ZMII_FER_V (0);		zmiifer |= ZMII_FER_SMII << ZMII_FER_V (1);		zmiifer |= ZMII_FER_SMII << ZMII_FER_V (2);		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);		bis->bi_phymode[0] = BI_PHYMODE_ZMII;		bis->bi_phymode[1] = BI_PHYMODE_ZMII;		bis->bi_phymode[2] = BI_PHYMODE_ZMII;		bis->bi_phymode[3] = BI_PHYMODE_RGMII;		break;	case 6:		zmiifer |= ZMII_FER_SMII << ZMII_FER_V (0);		zmiifer |= ZMII_FER_SMII << ZMII_FER_V (1);		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(2);		rmiifer |= RGMII_FER_RGMII << RGMII_FER_V(3);		bis->bi_phymode[0] = BI_PHYMODE_ZMII;		bis->bi_phymode[1] = BI_PHYMODE_ZMII;		bis->bi_phymode[2] = BI_PHYMODE_RGMII;		bis->bi_phymode[3] = BI_PHYMODE_RGMII;		break;	case 0:	default:		zmiifer = ZMII_FER_MII << ZMII_FER_V(devnum);		rmiifer = 0x0;		bis->bi_phymode[0] = BI_PHYMODE_ZMII;		bis->bi_phymode[1] = BI_PHYMODE_ZMII;		bis->bi_phymode[2] = BI_PHYMODE_ZMII;		bis->bi_phymode[3] = BI_PHYMODE_ZMII;		break;	}	/* Ensure we setup mdio for this devnum and ONLY this devnum */	zmiifer |= (ZMII_FER_MDI) << ZMII_FER_V(devnum);	out32 (ZMII_FER, zmiifer);	out32 (RGMII_FER, rmiifer);	return ((int)pfc1);}#endifstatic int ppc_440x_eth_init (struct eth_device *dev, bd_t * bis){	int i;	unsigned long reg;	unsigned long msr;	unsigned long speed;	unsigned long duplex;	unsigned long failsafe;	unsigned mode_reg;	unsigned short devnum;	unsigned short reg_short;	sys_info_t sysinfo;	int ethgroup;	EMAC_440GX_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)		return -1;	/* Need to get the OPB frequency so we can access the PHY */	get_sys_info (&sysinfo);	msr = mfmsr ();	mtmsr (msr & ~(MSR_EE));	/* disable interrupts */	devnum = hw_p->devnum;#ifdef INFO_440_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;#endif	/* MAL Channel RESET */	/* 1st reset MAL channel */	/* Note: writing a 0 to a channel has no effect */	mtdcr (maltxcarr, (MAL_TXRX_CASR >> hw_p->devnum));	mtdcr (malrxcarr, (MAL_TXRX_CASR >> hw_p->devnum));	/* wait for reset */	/* TBS:  should have udelay and failsafe here */	failsafe = 10000;	/* wait for reset */	while (mfdcr (maltxcasr) & (MAL_CR_MMSR >> hw_p->devnum)) {		udelay (1000);	/* Delay 1 MS so as not to hammer the register */		failsafe--;		if (failsafe == 0)			break;	}	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 */	/* 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;	out32 (ZMII_FER, 0);	udelay (100);#if defined(CONFIG_440_GX)	ethgroup = ppc_440x_eth_setup_bridge(devnum, bis);#else	if ((devnum == 0) || (devnum == 1)) {		out32 (ZMII_FER, (ZMII_FER_SMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));	}	else { /* ((devnum == 2) || (devnum == 3)) */		out32 (ZMII_FER, ZMII_FER_MDI << ZMII_FER_V (devnum));		out32 (RGMII_FER, ((RGMII_FER_RGMII << RGMII_FER_V (2)) |				   (RGMII_FER_RGMII << RGMII_FER_V (3))));	}#endif	out32 (ZMII_SSR, ZMII_SSR_SP << ZMII_SSR_V(devnum));	__asm__ volatile ("eieio");	/* reset emac so we have access to the phy */	out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST);	__asm__ volatile ("eieio");	failsafe = 1000;	while ((in32 (EMAC_M0 + hw_p->hw_addr) & (EMAC_M0_SRST)) && failsafe) {		udelay (1000);		failsafe--;	}	/* 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;	out32 (EMAC_M1 + hw_p->hw_addr, mode_reg);	/* wait for PHY to complete auto negotiation */	reg_short = 0;#ifndef CONFIG_CS8952_PHY	switch (devnum) {	case 0:		reg = CONFIG_PHY_ADDR;		break;	case 1:		reg = CONFIG_PHY1_ADDR;		break;#if defined (CONFIG_440_GX)	case 2:		reg = CONFIG_PHY2_ADDR;		break;	case 3:		reg = CONFIG_PHY3_ADDR;		break;#endif	default:		reg = CONFIG_PHY_ADDR;		break;	}	bis->bi_phynum[devnum] = reg;	/* Reset the phy */	miiphy_reset (reg);

⌨️ 快捷键说明

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