Newer
Older
/*-----------------------------------------------------------------------------+
*
* 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.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
* 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 <commproc.h>
#include <ppc4xx.h>
#include <ppc4xx_enet.h>
#include <405_mal.h>
#include <miiphy.h>
#include <malloc.h>
#include "vecnum.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 (CONFIG_COMMANDS & CFG_CMD_NET) && !defined(CONFIG_405) && !defined(CONFIG_IOP480)
#if !(defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII))
#error "CONFIG_MII has to be defined!"
#endif
#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_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
#define EMAC_UIC_DEF1 UIC_ENET1
#define SEL_UIC_DEF(p) (p ? UIC_ENET1 : UIC_ENET )
#undef INFO_4XX_ENET
#define BI_PHYMODE_NONE 0
#define BI_PHYMODE_ZMII 1
/*-----------------------------------------------------------------------------+
* Global variables. TX and RX descriptors and buffers.
*-----------------------------------------------------------------------------*/
/* IER globals */
static uint32_t mal_ier;
#if !defined(CONFIG_NET_MULTI)
struct eth_device *emac0_dev;
#endif
/*-----------------------------------------------------------------------------+
* 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_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;
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 */
#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));
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 */
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);
Stefan Roese
committed
#if defined (CONFIG_440GX)
int ppc_4xx_eth_setup_bridge(int devnum, bd_t * bis)
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
{
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);
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);
out32 (ZMII_FER, zmiifer);
out32 (RGMII_FER, rmiifer);
return ((int)pfc1);
}
#endif
static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
int i, j;
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;
Stefan Roese
committed
#if defined(CONFIG_440GX)
sys_info_t sysinfo;
#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)
return -1;
#if defined(CONFIG_440GX)
/* 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;
#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)
/* 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);
Stefan Roese
committed
#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
out32 (ZMII_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum));
Stefan Roese
committed
#elif defined(CONFIG_440GX)
ethgroup = ppc_4xx_eth_setup_bridge(devnum, bis);
#elif defined(CONFIG_440GP)
/* set RMII mode */
out32 (ZMII_FER, ZMII_RMII | ZMII_MDI0);
#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))));
out32 (ZMII_SSR, ZMII_SSR_SP << ZMII_SSR_V(devnum));
#endif /* defined(CONFIG_440) */
__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--;
}
Stefan Roese
committed
#if defined(CONFIG_440GX)
/* 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);
Stefan Roese
committed
#endif /* defined(CONFIG_440GX) */
/* 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;
Stefan Roese
committed
#if defined (CONFIG_440GX)
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;
#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) {
miiphy_reset (reg);
Stefan Roese
committed
#if defined(CONFIG_440GX)
* 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 (reg, 23, 0x1300);
#else
miiphy_write (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 (reg, 0x1f, 0x2a30);
miiphy_write (reg, 0x08, 0x0200);
miiphy_write (reg, 0x1f, 0x52b5);
miiphy_write (reg, 0x02, 0x0004);
miiphy_write (reg, 0x01, 0x0671);
miiphy_write (reg, 0x00, 0x8fae);
miiphy_write (reg, 0x1f, 0x2a30);
miiphy_write (reg, 0x08, 0x0000);
miiphy_write (reg, 0x1f, 0x0000);
/* end Vitesse/Cicada errata */
}
/* Start/Restart autonegotiation */
phy_setup_aneg (reg);
udelay (1000);
}
#endif /* defined(CONFIG_PHY_RESET) */
miiphy_read (reg, PHY_BMSR, ®_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 (reg, PHY_BMSR, ®_short);
}
puts (" done\n");
udelay (500000); /* another 500 ms (results in faster booting) */
}
#endif /* #ifndef CONFIG_CS8952_PHY */
speed = miiphy_speed (reg);
duplex = miiphy_duplex (reg);
if (hw_p->print_speed) {
hw_p->print_speed = 0;
printf ("ENET Speed is %d Mbps - %s duplex connection\n",
(int) speed, (duplex == HALF) ? "HALF" : "FULL");
}
#if defined(CONFIG_440)
Stefan Roese
committed
#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 = in32 (ZMII_SSR);
if ( (speed == 100) || (speed == 1000) )
out32 (ZMII_SSR, reg | (ZMII_SSR_SP << ZMII_SSR_V (devnum)));
else
out32 (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
reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V (devnum));
out32 (RGMII_SSR, reg);
}
#endif /* defined(CONFIG_440) */
/* set the Mal configuration reg */
Stefan Roese
committed
#if defined(CONFIG_440GX)
mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA |
MAL_CR_PLBLT_DEFAULT | MAL_CR_EOPIE | 0x00330000);
#else
mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
/* Errata 1.12: MAL_1 -- Disable MAL bursting */
if (get_pvr() == PVR_440GP_RB) {
mtdcr (malmcr, mfdcr(malmcr) & ~MAL_CR_PLBB);
}
#endif
/* Free "old" buffers */
if (hw_p->alloc_tx_buf)
free (hw_p->alloc_tx_buf);
if (hw_p->alloc_rx_buf)
free (hw_p->alloc_rx_buf);
/*
* Malloc MAL buffer desciptors, make sure they are
* aligned on cache line boundary size
* (401/403/IOP480 = 16, 405 = 32)
* and doesn't cross cache block boundaries.
*/
hw_p->alloc_tx_buf =
(mal_desc_t *) malloc ((sizeof (mal_desc_t) * NUM_TX_BUFF) +
((2 * CFG_CACHELINE_SIZE) - 2));
if (NULL == hw_p->alloc_tx_buf)
return -1;
if (((int) hw_p->alloc_tx_buf & CACHELINE_MASK) != 0) {
hw_p->tx =
(mal_desc_t *) ((int) hw_p->alloc_tx_buf +
CFG_CACHELINE_SIZE -
((int) hw_p->
alloc_tx_buf & CACHELINE_MASK));
} else {
hw_p->tx = hw_p->alloc_tx_buf;
}
hw_p->alloc_rx_buf =
(mal_desc_t *) malloc ((sizeof (mal_desc_t) * NUM_RX_BUFF) +
((2 * CFG_CACHELINE_SIZE) - 2));
if (NULL == hw_p->alloc_rx_buf) {
free(hw_p->alloc_tx_buf);
hw_p->alloc_tx_buf = NULL;
return -1;
}
if (((int) hw_p->alloc_rx_buf & CACHELINE_MASK) != 0) {
hw_p->rx =
(mal_desc_t *) ((int) hw_p->alloc_rx_buf +
CFG_CACHELINE_SIZE -
((int) hw_p->
alloc_rx_buf & CACHELINE_MASK));
} else {
hw_p->rx = hw_p->alloc_rx_buf;
}
for (i = 0; i < NUM_TX_BUFF; i++) {
hw_p->tx[i].ctrl = 0;
hw_p->tx[i].data_len = 0;
if (hw_p->first_init == 0) {
hw_p->txbuf_ptr =
(char *) malloc (ENET_MAX_MTU_ALIGNED);
if (NULL == hw_p->txbuf_ptr) {
free(hw_p->alloc_rx_buf);
free(hw_p->alloc_tx_buf);
hw_p->alloc_rx_buf = NULL;
hw_p->alloc_tx_buf = NULL;
for(j = 0; j < i; j++) {
free(hw_p->tx[i].data_ptr);
hw_p->tx[i].data_ptr = NULL;
}
}
}
hw_p->tx[i].data_ptr = hw_p->txbuf_ptr;
if ((NUM_TX_BUFF - 1) == i)
hw_p->tx[i].ctrl |= MAL_TX_CTRL_WRAP;
hw_p->tx_run[i] = -1;
#if 0
printf ("TX_BUFF %d @ 0x%08lx\n", i,
(ulong) hw_p->tx[i].data_ptr);
#endif
}
for (i = 0; i < NUM_RX_BUFF; i++) {
hw_p->rx[i].ctrl = 0;
hw_p->rx[i].data_len = 0;
/* rx[i].data_ptr = (char *) &rx_buff[i]; */
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
hw_p->rx[i].data_ptr = (char *) NetRxPackets[i];
if ((NUM_RX_BUFF - 1) == i)
hw_p->rx[i].ctrl |= MAL_RX_CTRL_WRAP;
hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
hw_p->rx_ready[i] = -1;
#if 0
printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) rx[i].data_ptr);
#endif
}
reg = 0x00000000;
reg |= dev->enetaddr[0]; /* set high address */
reg = reg << 8;
reg |= dev->enetaddr[1];
out32 (EMAC_IAH + hw_p->hw_addr, reg);
reg = 0x00000000;
reg |= dev->enetaddr[2]; /* set low address */
reg = reg << 8;
reg |= dev->enetaddr[3];
reg = reg << 8;
reg |= dev->enetaddr[4];
reg = reg << 8;
reg |= dev->enetaddr[5];
out32 (EMAC_IAL + hw_p->hw_addr, reg);
switch (devnum) {
case 1:
/* setup MAL tx & rx channel pointers */
#if defined (CONFIG_405EP) || defined (CONFIG_440EP) || defined (CONFIG_440GR)
mtdcr (maltxctp2r, hw_p->tx);
#else
#endif
#if defined(CONFIG_440)
mtdcr (maltxbattr, 0x0);
mtdcr (malrxctp1r, hw_p->rx);
/* set RX buffer size */
mtdcr (malrcbs1, ENET_MAX_MTU_ALIGNED / 16);
break;
Stefan Roese
committed
#if defined (CONFIG_440GX)
case 2:
/* setup MAL tx & rx channel pointers */
mtdcr (maltxbattr, 0x0);
mtdcr (malrxbattr, 0x0);
mtdcr (maltxctp2r, hw_p->tx);
mtdcr (malrxctp2r, hw_p->rx);
/* set RX buffer size */
mtdcr (malrcbs2, ENET_MAX_MTU_ALIGNED / 16);
break;
case 3:
/* setup MAL tx & rx channel pointers */
mtdcr (maltxbattr, 0x0);
mtdcr (maltxctp3r, hw_p->tx);
mtdcr (malrxbattr, 0x0);
mtdcr (malrxctp3r, hw_p->rx);
/* set RX buffer size */
mtdcr (malrcbs3, ENET_MAX_MTU_ALIGNED / 16);
break;
#endif /* CONFIG_440GX */
case 0:
default:
/* setup MAL tx & rx channel pointers */
#if defined(CONFIG_440)
mtdcr (maltxbattr, 0x0);
mtdcr (malrxbattr, 0x0);
#endif
mtdcr (maltxctp0r, hw_p->tx);
mtdcr (malrxctp0r, hw_p->rx);
/* set RX buffer size */
mtdcr (malrcbs0, ENET_MAX_MTU_ALIGNED / 16);
break;
}
/* Enable MAL transmit and receive channels */
#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
mtdcr (maltxcasr, (MAL_TXRX_CASR >> (hw_p->devnum*2)));
#else
mtdcr (maltxcasr, (MAL_TXRX_CASR >> hw_p->devnum));
#endif
mtdcr (malrxcasr, (MAL_TXRX_CASR >> hw_p->devnum));
/* set transmit enable & receive enable */
out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_TXE | EMAC_M0_RXE);
/* set receive fifo to 4k and tx fifo to 2k */
mode_reg = in32 (EMAC_M1 + hw_p->hw_addr);
mode_reg |= EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K;
/* set speed */
if (speed == _1000BASET)
mode_reg = mode_reg | EMAC_M1_MF_1000MBPS | EMAC_M1_IST;
else if (speed == _100BASET)
mode_reg = mode_reg | EMAC_M1_MF_100MBPS | EMAC_M1_IST;
else
mode_reg = mode_reg & ~0x00C00000; /* 10 MBPS */
if (duplex == FULL)
mode_reg = mode_reg | 0x80000000 | EMAC_M1_IST;
out32 (EMAC_M1 + hw_p->hw_addr, mode_reg);
/* Enable broadcast and indvidual address */
/* TBS: enabling runts as some misbehaved nics will send runts */
out32 (EMAC_RXM + hw_p->hw_addr, EMAC_RMR_BAE | EMAC_RMR_IAE);
/* we probably need to set the tx mode1 reg? maybe at tx time */
/* set transmit request threshold register */
out32 (EMAC_TRTR + hw_p->hw_addr, 0x18000000); /* 256 byte threshold */
/* set receive low/high water mark register */
#if defined(CONFIG_440)
/* 440GP has a 64 byte burst length */
out32 (EMAC_RX_HI_LO_WMARK + hw_p->hw_addr, 0x80009000);
#else
/* 405s have a 16 byte burst length */
out32 (EMAC_RX_HI_LO_WMARK + hw_p->hw_addr, 0x0f002000);
#endif /* defined(CONFIG_440) */
out32 (EMAC_TXM1 + hw_p->hw_addr, 0xf8640000);
/* Set fifo limit entry in tx mode 0 */
out32 (EMAC_TXM0 + hw_p->hw_addr, 0x00000003);
/* Frame gap set */
out32 (EMAC_I_FRAME_GAP_REG + hw_p->hw_addr, 0x00000008);
/* Set EMAC IER */
hw_p->emac_ier = EMAC_ISR_PTLE | EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE;
if (speed == _100BASET)
hw_p->emac_ier = hw_p->emac_ier | EMAC_ISR_SYE;
out32 (EMAC_ISR + hw_p->hw_addr, 0xffffffff); /* clear pending interrupts */
out32 (EMAC_IER + hw_p->hw_addr, hw_p->emac_ier);
if (hw_p->first_init == 0) {
/*
* Connect interrupt service routines
*/
irq_install_handler (VECNUM_ETH0 + (hw_p->devnum * 2),
(interrupt_handler_t *) enetInt, dev);
}
mtmsr (msr); /* enable interrupts again */
hw_p->bis = bis;
hw_p->first_init = 1;
return (1);
}
static int ppc_4xx_eth_send (struct eth_device *dev, volatile void *ptr,
int len)
{
struct enet_frame *ef_ptr;
ulong time_start, time_now;
unsigned long temp_txm0;
EMAC_4XX_HW_PST hw_p = dev->priv;
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
ef_ptr = (struct enet_frame *) ptr;
/*-----------------------------------------------------------------------+
* Copy in our address into the frame.
*-----------------------------------------------------------------------*/
(void) memcpy (ef_ptr->source_addr, dev->enetaddr, ENET_ADDR_LENGTH);
/*-----------------------------------------------------------------------+
* If frame is too long or too short, modify length.
*-----------------------------------------------------------------------*/
/* TBS: where does the fragment go???? */
if (len > ENET_MAX_MTU)
len = ENET_MAX_MTU;
/* memcpy ((void *) &tx_buff[tx_slot], (const void *) ptr, len); */
memcpy ((void *) hw_p->txbuf_ptr, (const void *) ptr, len);
/*-----------------------------------------------------------------------+
* set TX Buffer busy, and send it
*-----------------------------------------------------------------------*/
hw_p->tx[hw_p->tx_slot].ctrl = (MAL_TX_CTRL_LAST |
EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP) &
~(EMAC_TX_CTRL_ISA | EMAC_TX_CTRL_RSA);
if ((NUM_TX_BUFF - 1) == hw_p->tx_slot)
hw_p->tx[hw_p->tx_slot].ctrl |= MAL_TX_CTRL_WRAP;
hw_p->tx[hw_p->tx_slot].data_len = (short) len;
hw_p->tx[hw_p->tx_slot].ctrl |= MAL_TX_CTRL_READY;
__asm__ volatile ("eieio");
out32 (EMAC_TXM0 + hw_p->hw_addr,
in32 (EMAC_TXM0 + hw_p->hw_addr) | EMAC_TXM0_GNP0);
#ifdef INFO_4XX_ENET
hw_p->stats.pkts_tx++;
#endif
/*-----------------------------------------------------------------------+
* poll unitl the packet is sent and then make sure it is OK
*-----------------------------------------------------------------------*/
time_start = get_timer (0);
while (1) {
temp_txm0 = in32 (EMAC_TXM0 + hw_p->hw_addr);
/* loop until either TINT turns on or 3 seconds elapse */
if ((temp_txm0 & EMAC_TXM0_GNP0) != 0) {
/* transmit is done, so now check for errors
* If there is an error, an interrupt should
* happen when we return
*/
time_now = get_timer (0);
if ((time_now - time_start) > 3000) {
return (-1);
}
} else {
return (len);
}
}
}
#if defined (CONFIG_440)
int enetInt (struct eth_device *dev)
{
int serviced;
int rc = -1; /* default to not us */
unsigned long mal_isr;
unsigned long emac_isr = 0;
unsigned long mal_rx_eob;
unsigned long my_uic0msr, my_uic1msr;
Stefan Roese
committed
#if defined(CONFIG_440GX)
unsigned long my_uic2msr;
#endif
EMAC_4XX_HW_PST hw_p;
/*
* Because the mal is generic, we need to get the current
* eth device
*/
#if defined(CONFIG_NET_MULTI)
dev = eth_get_dev();
#else
dev = emac0_dev;
#endif
hw_p = dev->priv;
/* enter loop that stays in interrupt code until nothing to service */
do {
serviced = 0;
my_uic0msr = mfdcr (uic0msr);
my_uic1msr = mfdcr (uic1msr);
Stefan Roese
committed
#if defined(CONFIG_440GX)
my_uic2msr = mfdcr (uic2msr);
#endif
if (!(my_uic0msr & (UIC_MRE | UIC_MTE))
&& !(my_uic1msr &
(UIC_ETH0 | UIC_ETH1 | UIC_MS | UIC_MTDE |
UIC_MRDE))) {
/* not for us */
return (rc);
}
Stefan Roese
committed
#if defined (CONFIG_440GX)
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
if (!(my_uic0msr & (UIC_MRE | UIC_MTE))
&& !(my_uic2msr & (UIC_ETH2 | UIC_ETH3))) {
/* not for us */
return (rc);
}
#endif
/* get and clear controller status interrupts */
/* look at Mal and EMAC interrupts */
if ((my_uic0msr & (UIC_MRE | UIC_MTE))
|| (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
/* we have a MAL interrupt */
mal_isr = mfdcr (malesr);
/* look for mal error */
if (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE)) {
mal_err (dev, mal_isr, my_uic0msr,
MAL_UIC_DEF, MAL_UIC_ERR);
serviced = 1;
rc = 0;
}
}
/* port by port dispatch of emac interrupts */
if (hw_p->devnum == 0) {
if (UIC_ETH0 & my_uic1msr) { /* look for EMAC errors */
emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
if ((hw_p->emac_ier & emac_isr) != 0) {
emac_err (dev, emac_isr);
serviced = 1;
rc = 0;
}
}
if ((hw_p->emac_ier & emac_isr)
|| (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
mtdcr (uic0sr, UIC_MRE | UIC_MTE); /* Clear */
mtdcr (uic1sr, UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
return (rc); /* we had errors so get out */
}
}
if (hw_p->devnum == 1) {
if (UIC_ETH1 & my_uic1msr) { /* look for EMAC errors */
emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
if ((hw_p->emac_ier & emac_isr) != 0) {
emac_err (dev, emac_isr);
serviced = 1;
rc = 0;
}
}
if ((hw_p->emac_ier & emac_isr)
|| (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
mtdcr (uic0sr, UIC_MRE | UIC_MTE); /* Clear */
mtdcr (uic1sr, UIC_ETH1 | UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
return (rc); /* we had errors so get out */
}
}
Stefan Roese
committed
#if defined (CONFIG_440GX)
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
if (hw_p->devnum == 2) {
if (UIC_ETH2 & my_uic2msr) { /* look for EMAC errors */
emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
if ((hw_p->emac_ier & emac_isr) != 0) {
emac_err (dev, emac_isr);
serviced = 1;
rc = 0;
}
}
if ((hw_p->emac_ier & emac_isr)
|| (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
mtdcr (uic0sr, UIC_MRE | UIC_MTE); /* Clear */
mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
mtdcr (uic2sr, UIC_ETH2);
return (rc); /* we had errors so get out */
}
}
if (hw_p->devnum == 3) {
if (UIC_ETH3 & my_uic2msr) { /* look for EMAC errors */
emac_isr = in32 (EMAC_ISR + hw_p->hw_addr);
if ((hw_p->emac_ier & emac_isr) != 0) {
emac_err (dev, emac_isr);
serviced = 1;
rc = 0;
}
}
if ((hw_p->emac_ier & emac_isr)
|| (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
mtdcr (uic0sr, UIC_MRE | UIC_MTE); /* Clear */
mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
mtdcr (uic2sr, UIC_ETH3);