Newer
Older
/*-----------------------------------------------------------------------------+
* This source code is dual-licensed. You may use it under the terms of the
* GNU General Public License version 2, or under the license below.
* 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
*-----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------+
*
* Function: Device driver for the ethernet EMAC3 macro on the 405GP.
* 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
* 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 EMAC0_MR1 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 <asm/ppc4xx.h>
#include <asm/ppc4xx-emac.h>
#include <asm/ppc4xx-mal.h>
#include <miiphy.h>
#include <malloc.h>
#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
#error "CONFIG_MII has to be defined!"
#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_ALIGNED PKTSIZE_ALIGN
/*-----------------------------------------------------------------------------+
* Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal
* Interrupt Controller).
*-----------------------------------------------------------------------------*/
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#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_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) || \
#define BI_PHYMODE_SMII 6
#define BI_PHYMODE_MII 7
#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
#define BI_PHYMODE_RMII 8
#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) || \
#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 CONFIG_SYS_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 CONFIG_SYS_FIXED_PHY_PORT(devnum,speed,duplex) \
* {devnum, speed, duplex},
*
* #define CONFIG_SYS_FIXED_PHY_PORTS \
* CONFIG_SYS_FIXED_PHY_PORT(0,1000,FULL) \
* CONFIG_SYS_FIXED_PHY_PORT(2,100,HALF)
*/
#ifndef CONFIG_FIXED_PHY
#define CONFIG_FIXED_PHY 0xFFFFFFFF /* Fixed PHY (PHY-less) */
#endif
#ifndef CONFIG_SYS_FIXED_PHY_PORTS
#define CONFIG_SYS_FIXED_PHY_PORTS /* default is an empty array */
#endif
struct 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[] = {
CONFIG_SYS_FIXED_PHY_PORTS /* defined in board configuration file */
/*-----------------------------------------------------------------------------+
* Global variables. TX and RX descriptors and buffers.
*-----------------------------------------------------------------------------*/
/*
* 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 (const char *devname, unsigned char addr,
unsigned char reg, unsigned short *value);
extern int emac4xx_miiphy_write (const 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;
val |= SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum);
#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;
val &= ~SDR0_MFR_ETH_CLK_SEL_V(hw_p->devnum);
#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;
out_be32((void *)EMAC0_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 (MAL0_TXCARR, (MAL_CR_MMSR >> (hw_p->devnum * 2)));
mtdcr (MAL0_TXCARR, (MAL_CR_MMSR >> hw_p->devnum));
mtdcr (MAL0_RXCARR, (MAL_CR_MMSR >> hw_p->devnum));
while (mfdcr (MAL0_RXCASR) & (MAL_CR_MMSR >> hw_p->devnum)) {
udelay (1000); /* Delay 1 MS so as not to hammer the register */
/* provide clocks for EMAC internal loopback */
emac_loopback_enable(hw_p);
out_be32((void *)EMAC0_MR0 + hw_p->hw_addr, EMAC_MR0_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);
Stefan Roese
committed
#if defined (CONFIG_440GX)
int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
{
unsigned long pfc1;
unsigned long zmiifer;
unsigned long rmiifer;
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);
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
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);
bis->bi_phymode[0] = BI_PHYMODE_ZMII;
bis->bi_phymode[1] = BI_PHYMODE_ZMII;
bis->bi_phymode[2] = 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);
out_be32((void *)ZMII0_FER, zmiifer);
out_be32((void *)RGMII_FER, rmiifer);
#endif /* CONFIG_440_GX */
#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
{
unsigned long zmiifer=0x0;
Matthias Fuchs
committed
unsigned long pfc1;
Matthias Fuchs
committed
pfc1 &= SDR0_PFC1_SELECT_MASK;
Matthias Fuchs
committed
case SDR0_PFC1_SELECT_CONFIG_2:
out_be32((void *)RGMII_FER, 0x00000037);
bis->bi_phymode[0] = BI_PHYMODE_GMII;
bis->bi_phymode[1] = BI_PHYMODE_NONE;
break;
Matthias Fuchs
committed
case SDR0_PFC1_SELECT_CONFIG_4:
out_be32((void *)RGMII_FER, 0x00000055);
bis->bi_phymode[0] = BI_PHYMODE_RGMII;
bis->bi_phymode[1] = BI_PHYMODE_RGMII;
break;
Matthias Fuchs
committed
case SDR0_PFC1_SELECT_CONFIG_6:
((ZMII_FER_SMII) << ZMII_FER_V(0)) |
((ZMII_FER_SMII) << ZMII_FER_V(1)));
out_be32((void *)RGMII_FER, 0x00000000);
Matthias Fuchs
committed
bis->bi_phymode[0] = BI_PHYMODE_SMII;
bis->bi_phymode[1] = BI_PHYMODE_SMII;
break;
case SDR0_PFC1_SELECT_CONFIG_1_2:
/* only 1 x MII supported */
out_be32((void *)ZMII0_FER, (ZMII_FER_MII) << ZMII_FER_V(0));
out_be32((void *)RGMII_FER, 0x00000000);
Matthias Fuchs
committed
bis->bi_phymode[0] = BI_PHYMODE_MII;
bis->bi_phymode[1] = BI_PHYMODE_NONE;
break;
default:
break;
}
/* Ensure we setup mdio for this devnum and ONLY this devnum */
zmiifer = in_be32((void *)ZMII0_FER);
zmiifer |= (ZMII_FER_MDI) << ZMII_FER_V(devnum);
out_be32((void *)ZMII0_FER, zmiifer);
return ((int)0x0);
}
#endif /* CONFIG_440EPX */
#if defined(CONFIG_405EX)
int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
{
u32 rgmiifer = 0;
* The 405EX(r)'s RGMII bridge can operate in one of several
* modes, only one of which (2 x RGMII) allows the
* simultaneous use of both EMACs on the 405EX.
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
switch (CONFIG_EMAC_PHY_MODE) {
case EMAC_PHY_MODE_NONE:
/* No ports */
rgmiifer |= RGMII_FER_DIS << 0;
rgmiifer |= RGMII_FER_DIS << 4;
out_be32((void *)RGMII_FER, rgmiifer);
bis->bi_phymode[0] = BI_PHYMODE_NONE;
bis->bi_phymode[1] = BI_PHYMODE_NONE;
break;
case EMAC_PHY_MODE_NONE_RGMII:
/* 1 x RGMII port on channel 0 */
rgmiifer |= RGMII_FER_RGMII << 0;
rgmiifer |= RGMII_FER_DIS << 4;
out_be32((void *)RGMII_FER, rgmiifer);
bis->bi_phymode[0] = BI_PHYMODE_RGMII;
bis->bi_phymode[1] = BI_PHYMODE_NONE;
break;
case EMAC_PHY_MODE_RGMII_NONE:
/* 1 x RGMII port on channel 1 */
rgmiifer |= RGMII_FER_DIS << 0;
rgmiifer |= RGMII_FER_RGMII << 4;
out_be32((void *)RGMII_FER, rgmiifer);
bis->bi_phymode[0] = BI_PHYMODE_NONE;
bis->bi_phymode[1] = BI_PHYMODE_RGMII;
break;
case EMAC_PHY_MODE_RGMII_RGMII:
rgmiifer |= RGMII_FER_RGMII << 0;
rgmiifer |= RGMII_FER_RGMII << 4;
out_be32((void *)RGMII_FER, rgmiifer);
bis->bi_phymode[0] = BI_PHYMODE_RGMII;
bis->bi_phymode[1] = BI_PHYMODE_RGMII;
break;
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
case EMAC_PHY_MODE_NONE_GMII:
/* 1 x GMII port on channel 0 */
rgmiifer |= RGMII_FER_GMII << 0;
rgmiifer |= RGMII_FER_DIS << 4;
out_be32((void *)RGMII_FER, rgmiifer);
bis->bi_phymode[0] = BI_PHYMODE_GMII;
bis->bi_phymode[1] = BI_PHYMODE_NONE;
break;
case EMAC_PHY_MODE_NONE_MII:
/* 1 x MII port on channel 0 */
rgmiifer |= RGMII_FER_MII << 0;
rgmiifer |= RGMII_FER_DIS << 4;
out_be32((void *)RGMII_FER, rgmiifer);
bis->bi_phymode[0] = BI_PHYMODE_MII;
bis->bi_phymode[1] = BI_PHYMODE_NONE;
break;
case EMAC_PHY_MODE_GMII_NONE:
/* 1 x GMII port on channel 1 */
rgmiifer |= RGMII_FER_DIS << 0;
rgmiifer |= RGMII_FER_GMII << 4;
out_be32((void *)RGMII_FER, rgmiifer);
bis->bi_phymode[0] = BI_PHYMODE_NONE;
bis->bi_phymode[1] = BI_PHYMODE_GMII;
break;
case EMAC_PHY_MODE_MII_NONE:
/* 1 x MII port on channel 1 */
rgmiifer |= RGMII_FER_DIS << 0;
rgmiifer |= RGMII_FER_MII << 4;
out_be32((void *)RGMII_FER, rgmiifer);
bis->bi_phymode[0] = BI_PHYMODE_NONE;
bis->bi_phymode[1] = BI_PHYMODE_MII;
break;
default:
break;
}
/* Ensure we setup mdio for this devnum and ONLY this devnum */
rgmiifer = in_be32((void *)RGMII_FER);
rgmiifer |= (1 << (19-devnum));
out_be32((void *)RGMII_FER, rgmiifer);
return ((int)0x0);
}
#endif /* CONFIG_405EX */
#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
{
u32 eth_cfg;
u32 zmiifer; /* ZMII0_FER reg. */
u32 rmiifer; /* RGMII0_FER reg. Bridge 0 */
u32 rmiifer1; /* RGMII0_FER reg. Bridge 1 */
zmiifer = 0;
rmiifer = 0;
rmiifer1 = 0;
#if defined(CONFIG_460EX)
mode = 9;
mfsdr(SDR0_ETH_CFG, eth_cfg);
if (((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) > 0) &&
((eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE) > 0))
mode = 11; /* config SGMII */
mfsdr(SDR0_ETH_CFG, eth_cfg);
if (((eth_cfg & SDR0_ETH_CFG_SGMII0_ENABLE) > 0) &&
((eth_cfg & SDR0_ETH_CFG_SGMII1_ENABLE) > 0) &&
((eth_cfg & SDR0_ETH_CFG_SGMII2_ENABLE) > 0))
mode = 12; /* config SGMII */
/* TODO:
* NOTE: 460GT has 2 RGMII bridge cores:
* emac0 ------ RGMII0_BASE
* |
* emac1 -----+
*
* emac2 ------ RGMII1_BASE
* |
* emac3 -----+
*
* 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
* Add SGMII support.
* vg - 2008-07-28
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
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;
case 11:
/* 2 SGMII - 460EX */
bis->bi_phymode[0] = BI_PHYMODE_SGMII;
bis->bi_phymode[1] = BI_PHYMODE_SGMII;
bis->bi_phymode[2] = BI_PHYMODE_NONE;
bis->bi_phymode[3] = BI_PHYMODE_NONE;
break;
case 12:
/* 3 SGMII - 460GT */
bis->bi_phymode[0] = BI_PHYMODE_SGMII;
bis->bi_phymode[1] = BI_PHYMODE_SGMII;
bis->bi_phymode[2] = BI_PHYMODE_SGMII;
bis->bi_phymode[3] = BI_PHYMODE_NONE;
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)
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) || \
sys_info_t sysinfo;
#if defined(CONFIG_440GX) || \
defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
int ethgroup = -1;
#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");
#if defined(CONFIG_440GX) || \
defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
/* 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_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 */
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;
#if defined(CONFIG_440GP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
out_be32((void *)ZMII0_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);
out_be32((void *)ZMII0_SSR, ZMII0_SSR_SP << ZMII0_SSR_V(devnum));
#endif /* defined(CONFIG_440) && !defined(CONFIG_440SP) */
#if defined(CONFIG_405EX)
ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
#endif
/* provide clocks for EMAC internal loopback */
emac_loopback_enable(hw_p);
out_be32((void *)EMAC0_MR0 + hw_p->hw_addr, EMAC_MR0_SRST);
/* remove clocks for EMAC internal loopback */
emac_loopback_disable(hw_p);
while ((in_be32((void *)EMAC0_MR0 + hw_p->hw_addr) & (EMAC_MR0_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) || \
/* Whack the M1 register */
mode_reg = 0x0;
mode_reg &= ~0x00000038;
opbfreq = sysinfo.freqOPB / 1000000;
if (opbfreq <= 50);
else if (opbfreq <= 66)