4xx_enet.c
来自「最新版的u-boot,2008-10-18发布」· C语言 代码 · 共 2,136 行 · 第 1/5 页
C
2,136 行
/*-----------------------------------------------------------------------------+ * * 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 * 15-Aug-05 sr@denx.de * - merged 405gp_enet.c and 440gx_enet.c to generic 4xx_enet.c now handling all 4xx cpu's. *-----------------------------------------------------------------------------*/#include <config.h>#include <common.h>#include <net.h>#include <asm/processor.h>#include <asm/io.h>#include <asm/cache.h>#include <asm/mmu.h>#include <commproc.h>#include <ppc4xx.h>#include <ppc4xx_enet.h>#include <405_mal.h>#include <miiphy.h>#include <malloc.h>/* * Only compile for platform with AMCC EMAC ethernet controller and * network support enabled. * Remark: CONFIG_405 describes Xilinx PPC405 FPGA without EMAC controller! */#if defined(CONFIG_CMD_NET) && !defined(CONFIG_405) && !defined(CONFIG_IOP480)#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))#error "CONFIG_MII has to be defined!"#endif#if defined(CONFIG_NETCONSOLE) && !defined(CONFIG_NET_MULTI)#error "CONFIG_NET_MULTI has to be defined for NetConsole"#endif#define EMAC_RESET_TIMEOUT 1000 /* 1000 ms reset timeout */#define PHY_AUTONEGOTIATE_TIMEOUT 5000 /* 5000 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/*-----------------------------------------------------------------------------+ * Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal * Interrupt Controller). *-----------------------------------------------------------------------------*/#define ETH_IRQ_NUM(dev) (VECNUM_ETH0 + ((dev) * VECNUM_ETH1_OFFS))#if defined(CONFIG_HAS_ETH3)#if !defined(CONFIG_440GX)#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)) || \ UIC_MASK(ETH_IRQ_NUM(2)) || UIC_MASK(ETH_IRQ_NUM(3)))#else/* Unfortunately 440GX spreads EMAC interrupts on multiple UIC's */#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)))#define UIC_ETHxB (UIC_MASK(ETH_IRQ_NUM(2)) || UIC_MASK(ETH_IRQ_NUM(3)))#endif /* !defined(CONFIG_440GX) */#elif defined(CONFIG_HAS_ETH2)#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)) || \ UIC_MASK(ETH_IRQ_NUM(2)))#elif defined(CONFIG_HAS_ETH1)#define UIC_ETHx (UIC_MASK(ETH_IRQ_NUM(0)) || UIC_MASK(ETH_IRQ_NUM(1)))#else#define UIC_ETHx UIC_MASK(ETH_IRQ_NUM(0))#endif/* * Define a default version for UIC_ETHxB for non 440GX so that we can * use common code for all 4xx variants */#if !defined(UIC_ETHxB)#define UIC_ETHxB 0#endif#define UIC_MAL_SERR UIC_MASK(VECNUM_MAL_SERR)#define UIC_MAL_TXDE UIC_MASK(VECNUM_MAL_TXDE)#define UIC_MAL_RXDE UIC_MASK(VECNUM_MAL_RXDE)#define UIC_MAL_TXEOB UIC_MASK(VECNUM_MAL_TXEOB)#define UIC_MAL_RXEOB UIC_MASK(VECNUM_MAL_RXEOB)#define MAL_UIC_ERR (UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)#define MAL_UIC_DEF (UIC_MAL_RXEOB | MAL_UIC_ERR)/* * We have 3 different interrupt types: * - MAL interrupts indicating successful transfer * - MAL error interrupts indicating MAL related errors * - EMAC interrupts indicating EMAC related errors * * All those interrupts can be on different UIC's, but since * now at least all interrupts from one type are on the same * UIC. Only exception is 440GX where the EMAC interrupts are * spread over two UIC's! */#if defined(CONFIG_440GX)#define UIC_BASE_MAL UIC1_DCR_BASE#define UIC_BASE_MAL_ERR UIC2_DCR_BASE#define UIC_BASE_EMAC UIC2_DCR_BASE#define UIC_BASE_EMAC_B UIC3_DCR_BASE#else#define UIC_BASE_MAL (UIC0_DCR_BASE + (UIC_NR(VECNUM_MAL_TXEOB) * 0x10))#define UIC_BASE_MAL_ERR (UIC0_DCR_BASE + (UIC_NR(VECNUM_MAL_SERR) * 0x10))#define UIC_BASE_EMAC (UIC0_DCR_BASE + (UIC_NR(ETH_IRQ_NUM(0)) * 0x10))#define UIC_BASE_EMAC_B (UIC0_DCR_BASE + (UIC_NR(ETH_IRQ_NUM(0)) * 0x10))#endif#undef INFO_4XX_ENET#define BI_PHYMODE_NONE 0#define BI_PHYMODE_ZMII 1#define BI_PHYMODE_RGMII 2#define BI_PHYMODE_GMII 3#define BI_PHYMODE_RTBI 4#define BI_PHYMODE_TBI 5#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX)#define BI_PHYMODE_SMII 6#define BI_PHYMODE_MII 7#if defined(CONFIG_460EX) || defined(CONFIG_460GT)#define BI_PHYMODE_RMII 8#endif#endif#define BI_PHYMODE_SGMII 9#if defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX)#define SDR0_MFR_ETH_CLK_SEL_V(n) ((0x01<<27) / (n+1))#endif#if defined(CONFIG_460EX) || defined(CONFIG_460GT)#define SDR0_ETH_CFG_CLK_SEL_V(n) (0x01 << (8 + n))#endif#if defined(CONFIG_460EX) || defined(CONFIG_460GT)#define MAL_RX_CHAN_MUL 8 /* 460EX/GT uses MAL channel 8 for EMAC1 */#else#define MAL_RX_CHAN_MUL 1#endif/*--------------------------------------------------------------------+ * Fixed PHY (PHY-less) support for Ethernet Ports. *--------------------------------------------------------------------*//* * Some boards do not have a PHY for each ethernet port. These ports * are known as Fixed PHY (or PHY-less) ports. For such ports, set * the appropriate CONFIG_PHY_ADDR equal to CONFIG_FIXED_PHY and * then define CFG_FIXED_PHY_PORTS to define what the speed and * duplex should be for these ports in the board configuration * file. * * For Example: * #define CONFIG_FIXED_PHY 0xFFFFFFFF * * #define CONFIG_PHY_ADDR CONFIG_FIXED_PHY * #define CONFIG_PHY1_ADDR 1 * #define CONFIG_PHY2_ADDR CONFIG_FIXED_PHY * #define CONFIG_PHY3_ADDR 3 * * #define CFG_FIXED_PHY_PORT(devnum,speed,duplex) \ * {devnum, speed, duplex}, * * #define CFG_FIXED_PHY_PORTS \ * CFG_FIXED_PHY_PORT(0,1000,FULL) \ * CFG_FIXED_PHY_PORT(2,100,HALF) */#ifndef CONFIG_FIXED_PHY#define CONFIG_FIXED_PHY 0xFFFFFFFF /* Fixed PHY (PHY-less) */#endif#ifndef CFG_FIXED_PHY_PORTS#define CFG_FIXED_PHY_PORTS /* default is an empty array */#endifstruct fixed_phy_port { unsigned int devnum; /* ethernet port */ unsigned int speed; /* specified speed 10,100 or 1000 */ unsigned int duplex; /* specified duplex FULL or HALF */};static const struct fixed_phy_port fixed_phy_port[] = { CFG_FIXED_PHY_PORTS /* defined in board configuration file */};/*-----------------------------------------------------------------------------+ * Global variables. TX and RX descriptors and buffers. *-----------------------------------------------------------------------------*/#if !defined(CONFIG_NET_MULTI)struct eth_device *emac0_dev = NULL;#endif/* * Get count of EMAC devices (doesn't have to be the max. possible number * supported by the cpu) * * CONFIG_BOARD_EMAC_COUNT added so now a "dynamic" way to configure the * EMAC count is possible. As it is needed for the Kilauea/Haleakala * 405EX/405EXr eval board, using the same binary. */#if defined(CONFIG_BOARD_EMAC_COUNT)#define LAST_EMAC_NUM board_emac_count()#else /* CONFIG_BOARD_EMAC_COUNT */#if defined(CONFIG_HAS_ETH3)#define LAST_EMAC_NUM 4#elif defined(CONFIG_HAS_ETH2)#define LAST_EMAC_NUM 3#elif defined(CONFIG_HAS_ETH1)#define LAST_EMAC_NUM 2#else#define LAST_EMAC_NUM 1#endif#endif /* CONFIG_BOARD_EMAC_COUNT *//* normal boards start with EMAC0 */#if !defined(CONFIG_EMAC_NR_START)#define CONFIG_EMAC_NR_START 0#endif#define MAL_RX_DESC_SIZE 2048#define MAL_TX_DESC_SIZE 2048#define MAL_ALLOC_SIZE (MAL_TX_DESC_SIZE + MAL_RX_DESC_SIZE)/*-----------------------------------------------------------------------------+ * 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);extern int phy_setup_aneg (char *devname, unsigned char addr);extern int emac4xx_miiphy_read (char *devname, unsigned char addr, unsigned char reg, unsigned short *value);extern int emac4xx_miiphy_write (char *devname, unsigned char addr, unsigned char reg, unsigned short value);int board_emac_count(void);static void emac_loopback_enable(EMAC_4XX_HW_PST hw_p){#if defined(CONFIG_440SPE) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_405EX) u32 val; mfsdr(sdr_mfr, val); val |= SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum); mtsdr(sdr_mfr, val);#elif defined(CONFIG_460EX) || defined(CONFIG_460GT) u32 val; mfsdr(SDR0_ETH_CFG, val); val |= SDR0_ETH_CFG_CLK_SEL_V(hw_p->devnum); mtsdr(SDR0_ETH_CFG, val);#endif}static void emac_loopback_disable(EMAC_4XX_HW_PST hw_p){#if defined(CONFIG_440SPE) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_405EX) u32 val; mfsdr(sdr_mfr, val); val &= ~SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum); mtsdr(sdr_mfr, val);#elif defined(CONFIG_460EX) || defined(CONFIG_460GT) u32 val; mfsdr(SDR0_ETH_CFG, val); val &= ~SDR0_ETH_CFG_CLK_SEL_V(hw_p->devnum); mtsdr(SDR0_ETH_CFG, val);#endif}/*-----------------------------------------------------------------------------+| ppc_4xx_eth_halt| Disable MAL channel, and EMACn+-----------------------------------------------------------------------------*/static void ppc_4xx_eth_halt (struct eth_device *dev){ EMAC_4XX_HW_PST hw_p = dev->priv; u32 val = 10000; out_be32((void *)EMAC_IER + hw_p->hw_addr, 0x00000000); /* disable emac interrupts */ /* 1st reset MAL channel */ /* Note: writing a 0 to a channel has no effect */#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR) mtdcr (maltxcarr, (MAL_CR_MMSR >> (hw_p->devnum * 2)));#else mtdcr (maltxcarr, (MAL_CR_MMSR >> hw_p->devnum));#endif mtdcr (malrxcarr, (MAL_CR_MMSR >> hw_p->devnum)); /* wait for reset */ while (mfdcr (malrxcasr) & (MAL_CR_MMSR >> hw_p->devnum)) { udelay (1000); /* Delay 1 MS so as not to hammer the register */ val--; if (val == 0) break; } /* 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);#ifndef CONFIG_NETCONSOLE hw_p->print_speed = 1; /* print speed message again next time */#endif#if defined(CONFIG_460EX) || defined(CONFIG_460GT) /* don't bypass the TAHOE0/TAHOE1 cores for Linux */ mfsdr(SDR0_ETH_CFG, val); val &= ~(SDR0_ETH_CFG_TAHOE0_BYPASS | SDR0_ETH_CFG_TAHOE1_BYPASS); mtsdr(SDR0_ETH_CFG, val);#endif return;}#if defined (CONFIG_440GX)int ppc_4xx_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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?