Fix and optimize MII operations on FEC (MPC8xx) controllers

This patch fixes several issues at least on a MPC885 based system with two
FEC interfaces used in MII mode.

1. PHY discovery should first read PHY_PHYIDR2 register and only then
   PHY_PHYIDR1 like cpu/mpc8xx/fec.c::mii_discover_phy() does it,
   otherwise the values read are wrong. Also notice, that PHY discovery
   cannot work on MPC88x / MPC87x in setups with both FECs active at all
   in its present form, because for both interfaces the registers from FEC
   1 are used to communicate over MII.

2. Remove code duplication for resetting the FEC by isolating it into a
   separate function.

3. Initialize MII on FEC 1 when communicating over FEC 2 in fec_init().

4. Optimize mii_init() to only reset the FEC 1 controller once.

5. Fix a typo in mii_init() using index i instead of j thus potentially
   leading to unpredictable results.

Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
This commit is contained in:
Guennadi Liakhovetski 2007-11-29 21:15:56 +01:00 committed by Wolfgang Denk
parent 6a5e1d75bf
commit d197ffd817

View File

@ -143,6 +143,7 @@ static int fec_send(struct eth_device* dev, volatile void *packet, int length);
static int fec_recv(struct eth_device* dev);
static int fec_init(struct eth_device* dev, bd_t * bd);
static void fec_halt(struct eth_device* dev);
static void __mii_init(void);
int fec_initialize(bd_t *bis)
{
@ -539,6 +540,30 @@ static void fec_pin_init(int fecidx)
}
}
static int fec_reset(volatile fec_t *fecp)
{
int i;
/* Whack a reset.
* A delay is required between a reset of the FEC block and
* initialization of other FEC registers because the reset takes
* some time to complete. If you don't delay, subsequent writes
* to FEC registers might get killed by the reset routine which is
* still in progress.
*/
fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
for (i = 0;
(fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
++i) {
udelay (1);
}
if (i == FEC_RESET_DELAY)
return -1;
return 0;
}
static int fec_init (struct eth_device *dev, bd_t * bd)
{
struct ether_fcc_info_s *efis = dev->priv;
@ -573,23 +598,17 @@ static int fec_init (struct eth_device *dev, bd_t * bd)
#endif /* CONFIG_FADS */
}
/* Whack a reset.
* A delay is required between a reset of the FEC block and
* initialization of other FEC registers because the reset takes
* some time to complete. If you don't delay, subsequent writes
* to FEC registers might get killed by the reset routine which is
* still in progress.
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
/* the MII interface is connected to FEC1
* so for the miiphy_xxx function to work we must
* call mii_init since fec_halt messes the thing up
*/
fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
for (i = 0;
(fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
++i) {
udelay (1);
}
if (i == FEC_RESET_DELAY) {
if (efis->ether_index != 0)
__mii_init();
#endif
if (fec_reset(fecp) < 0)
printf ("FEC_RESET_DELAY timeout\n");
return 0;
}
/* We use strictly polling mode only
*/
@ -603,7 +622,7 @@ static int fec_init (struct eth_device *dev, bd_t * bd)
/* Set station address
*/
#define ea eth_get_dev()->enetaddr
#define ea dev->enetaddr
fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
fecp->fec_addr_high = (ea[4] << 8) | (ea[5]);
#undef ea
@ -716,15 +735,8 @@ static int fec_init (struct eth_device *dev, bd_t * bd)
} else {
efis->actual_phy_addr = efis->phy_addr;
}
#if defined(CONFIG_MII) && defined(CONFIG_RMII)
/* the MII interface is connected to FEC1
* so for the miiphy_xxx function to work we must
* call mii_init since fec_halt messes the thing up
*/
if (efis->ether_index != 0)
mii_init();
/*
* adapt the RMII speed to the speed of the phy
*/
@ -874,15 +886,14 @@ static int mii_discover_phy(struct eth_device *dev)
udelay(10000); /* wait 10ms */
}
for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) {
phytype = mii_send(mk_mii_read(phyno, PHY_PHYIDR1));
phytype = mii_send(mk_mii_read(phyno, PHY_PHYIDR2));
#ifdef ET_DEBUG
printf("PHY type 0x%x pass %d type ", phytype, pass);
#endif
if (phytype != 0xffff) {
phyaddr = phyno;
phytype <<= 16;
phytype |= mii_send(mk_mii_read(phyno,
PHY_PHYIDR2));
PHY_PHYIDR1)) << 16;
#ifdef ET_DEBUG
printf("PHY @ 0x%x pass %d type ",phyno,pass);
@ -929,36 +940,17 @@ static int mii_discover_phy(struct eth_device *dev)
#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && !defined(CONFIG_BITBANGMII)
/****************************************************************************
* mii_init -- Initialize the MII for MII command without ethernet
* mii_init -- Initialize the MII via FEC 1 for MII command without ethernet
* This function is a subset of eth_init
****************************************************************************
*/
void mii_init (void)
static void __mii_init(void)
{
volatile immap_t *immr = (immap_t *) CFG_IMMR;
volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
int i, j;
for (j = 0; j < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); j++) {
/* Whack a reset.
* A delay is required between a reset of the FEC block and
* initialization of other FEC registers because the reset takes
* some time to complete. If you don't delay, subsequent writes
* to FEC registers might get killed by the reset routine which is
* still in progress.
*/
fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
for (i = 0;
(fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
++i) {
udelay (1);
}
if (i == FEC_RESET_DELAY) {
if (fec_reset(fecp) < 0)
printf ("FEC_RESET_DELAY timeout\n");
return;
}
/* We use strictly polling mode only
*/
@ -968,14 +960,21 @@ void mii_init (void)
*/
fecp->fec_ievent = 0xffc0;
/* Setup the pin configuration of the FEC(s)
*/
fec_pin_init(ether_fcc_info[i].ether_index);
/* Now enable the transmit and receive processing
*/
fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
}
}
void mii_init (void)
{
int i;
__mii_init();
/* Setup the pin configuration of the FEC(s)
*/
for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++)
fec_pin_init(ether_fcc_info[i].ether_index);
}
/*****************************************************************************