Skip to content
Snippets Groups Projects
fec.c 67.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	status = *s & ~(PHY_STAT_SPMASK);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	switch((mii_reg >> 2) & 7) {
    
    	case 1: status |= PHY_STAT_10HDX; break;
    	case 2: status |= PHY_STAT_100HDX; break;
    	case 5: status |= PHY_STAT_10FDX; break;
    	case 6: status |= PHY_STAT_100FDX; break;
    
    	*s = status;
    }
    
    static phy_cmd_t const phy_cmd_qs6612_config[] = {
    
    		/* The PHY powers up isolated on the RPX,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		 * so send a command to allow operation.
    		 */
    		{ mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL },
    
    		/* parse cr and anar to get some info */
    		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
    		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
    		{ mk_mii_end, }
    
    	};
    static phy_cmd_t const phy_cmd_qs6612_startup[] = {  /* enable interrupts */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		{ mk_mii_write(MII_QS6612_IMR, 0x003a), NULL },
    		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
    		{ mk_mii_end, }
    
    	};
    static phy_cmd_t const phy_cmd_qs6612_ack_int[] = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		/* we need to read ISR, SR and ANER to acknowledge */
    		{ mk_mii_read(MII_QS6612_ISR), NULL },
    		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
    		{ mk_mii_read(MII_REG_ANER), NULL },
    
    		/* read pcr to get info */
    		{ mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr },
    		{ mk_mii_end, }
    
    	};
    static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		{ mk_mii_write(MII_QS6612_IMR, 0x0000), NULL },
    		{ mk_mii_end, }
    
    	};
    static phy_info_t const phy_info_qs6612 = {
    
    	.id = 0x00181440,
    
    	.name = "QS6612",
    	.config = phy_cmd_qs6612_config,
    	.startup = phy_cmd_qs6612_startup,
    	.ack_int = phy_cmd_qs6612_ack_int,
    	.shutdown = phy_cmd_qs6612_shutdown
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    };
    
    /* ------------------------------------------------------------------------- */
    /* AMD AM79C874 phy                                                          */
    
    /* register definitions for the 874 */
    
    #define MII_AM79C874_MFR       16  /* Miscellaneous Feature Register */
    #define MII_AM79C874_ICSR      17  /* Interrupt/Status Register      */
    #define MII_AM79C874_DR        18  /* Diagnostic Register            */
    #define MII_AM79C874_PMLR      19  /* Power and Loopback Register    */
    #define MII_AM79C874_MCR       21  /* ModeControl Register           */
    #define MII_AM79C874_DC        23  /* Disconnect Counter             */
    #define MII_AM79C874_REC       24  /* Recieve Error Counter          */
    
    static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev)
    {
    	struct fec_enet_private *fep = netdev_priv(dev);
    	volatile uint *s = &(fep->phy_status);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	if (mii_reg & 0x0080)
    
    		status |= PHY_STAT_ANC;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (mii_reg & 0x0400)
    
    		status |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	else
    
    		status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX);
    
    	*s = status;
    
    static phy_cmd_t const phy_cmd_am79c874_config[] = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
    		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
    		{ mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },
    		{ mk_mii_end, }
    
    	};
    static phy_cmd_t const phy_cmd_am79c874_startup[] = {  /* enable interrupts */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		{ mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL },
    		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
    
    		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		{ mk_mii_end, }
    
    	};
    static phy_cmd_t const phy_cmd_am79c874_ack_int[] = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		/* find out the current status */
    		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
    		{ mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },
    		/* we only need to read ISR to acknowledge */
    		{ mk_mii_read(MII_AM79C874_ICSR), NULL },
    		{ mk_mii_end, }
    
    	};
    static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		{ mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL },
    		{ mk_mii_end, }
    
    	};
    static phy_info_t const phy_info_am79c874 = {
    	.id = 0x00022561,
    	.name = "AM79C874",
    	.config = phy_cmd_am79c874_config,
    	.startup = phy_cmd_am79c874_startup,
    	.ack_int = phy_cmd_am79c874_ack_int,
    	.shutdown = phy_cmd_am79c874_shutdown
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /* ------------------------------------------------------------------------- */
    /* Kendin KS8721BL phy                                                       */
    
    /* register definitions for the 8721 */
    
    #define MII_KS8721BL_RXERCR	21
    #define MII_KS8721BL_ICSR	22
    #define	MII_KS8721BL_PHYCR	31
    
    
    static phy_cmd_t const phy_cmd_ks8721bl_config[] = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
    		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
    		{ mk_mii_end, }
    
    	};
    static phy_cmd_t const phy_cmd_ks8721bl_startup[] = {  /* enable interrupts */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		{ mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL },
    		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
    
    		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		{ mk_mii_end, }
    
    	};
    static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		/* find out the current status */
    		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
    		/* we only need to read ISR to acknowledge */
    		{ mk_mii_read(MII_KS8721BL_ICSR), NULL },
    		{ mk_mii_end, }
    
    	};
    static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		{ mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL },
    		{ mk_mii_end, }
    
    	};
    static phy_info_t const phy_info_ks8721bl = {
    
    	.id = 0x00022161,
    
    	.name = "KS8721BL",
    	.config = phy_cmd_ks8721bl_config,
    	.startup = phy_cmd_ks8721bl_startup,
    	.ack_int = phy_cmd_ks8721bl_ack_int,
    	.shutdown = phy_cmd_ks8721bl_shutdown
    
    /* ------------------------------------------------------------------------- */
    /* register definitions for the DP83848 */
    
    #define MII_DP8384X_PHYSTST    16  /* PHY Status Register */
    
    static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev)
    {
    	struct fec_enet_private *fep = dev->priv;
    	volatile uint *s = &(fep->phy_status);
    
    	*s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
    
    	/* Link up */
    	if (mii_reg & 0x0001) {
    		fep->link = 1;
    		*s |= PHY_STAT_LINK;
    	} else
    		fep->link = 0;
    	/* Status of link */
    	if (mii_reg & 0x0010)   /* Autonegotioation complete */
    		*s |= PHY_STAT_ANC;
    	if (mii_reg & 0x0002) {   /* 10MBps? */
    		if (mii_reg & 0x0004)   /* Full Duplex? */
    			*s |= PHY_STAT_10FDX;
    		else
    			*s |= PHY_STAT_10HDX;
    	} else {                  /* 100 Mbps? */
    		if (mii_reg & 0x0004)   /* Full Duplex? */
    			*s |= PHY_STAT_100FDX;
    		else
    			*s |= PHY_STAT_100HDX;
    	}
    	if (mii_reg & 0x0008)
    		*s |= PHY_STAT_FAULT;
    }
    
    static phy_info_t phy_info_dp83848= {
    	0x020005c9,
    	"DP83848",
    
    	(const phy_cmd_t []) {  /* config */
    		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
    		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
    		{ mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 },
    		{ mk_mii_end, }
    	},
    	(const phy_cmd_t []) {  /* startup - enable interrupts */
    		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
    		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
    		{ mk_mii_end, }
    	},
    	(const phy_cmd_t []) { /* ack_int - never happens, no interrupt */
    		{ mk_mii_end, }
    	},
    	(const phy_cmd_t []) {  /* shutdown */
    		{ mk_mii_end, }
    	},
    };
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /* ------------------------------------------------------------------------- */
    
    
    static phy_info_t const * const phy_info[] = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	&phy_info_lxt970,
    	&phy_info_lxt971,
    	&phy_info_qs6612,
    	&phy_info_am79c874,
    	&phy_info_ks8721bl,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	NULL
    };
    
    /* ------------------------------------------------------------------------- */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #ifdef CONFIG_RPXCLASSIC
    static void
    mii_link_interrupt(void *dev_id);
    #else
    static irqreturn_t
    
    mii_link_interrupt(int irq, void * dev_id);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #endif
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    #if defined(CONFIG_M5272)
    
    /*
     *	Code specific to Coldfire 5272 setup.
     */
    static void __inline__ fec_request_intrs(struct net_device *dev)
    {
    	volatile unsigned long *icrp;
    
    	static const struct idesc {
    		char *name;
    		unsigned short irq;
    
    	} *idp, id[] = {
    		{ "fec(RX)", 86, fec_enet_interrupt },
    		{ "fec(TX)", 87, fec_enet_interrupt },
    		{ "fec(OTHER)", 88, fec_enet_interrupt },
    		{ "fec(MII)", 66, mii_link_interrupt },
    		{ NULL },
    	};
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	/* Setup interrupt handlers. */
    
    	for (idp = id; idp->name; idp++) {
    		if (request_irq(idp->irq, idp->handler, 0, idp->name, dev) != 0)
    			printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, idp->irq);
    	}
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	/* Unmask interrupt at ColdFire 5272 SIM */
    	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3);
    	*icrp = 0x00000ddd;
    	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
    
    	*icrp = 0x0d000000;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
    {
    	volatile fec_t *fecp;
    
    	fecp = fep->hwp;
    	fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
    	fecp->fec_x_cntrl = 0x00;
    
    	/*
    	 * Set MII speed to 2.5 MHz
    	 * See 5272 manual section 11.5.8: MSCR
    	 */
    	fep->phy_speed = ((((MCF_CLK / 4) / (2500000 / 10)) + 5) / 10) * 2;
    	fecp->fec_mii_speed = fep->phy_speed;
    
    	fec_restart(dev, 0);
    }
    
    static void __inline__ fec_get_mac(struct net_device *dev)
    {
    	struct fec_enet_private *fep = netdev_priv(dev);
    	volatile fec_t *fecp;
    
    	unsigned char *iap, tmpaddr[ETH_ALEN];
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	fecp = fep->hwp;
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		/*
    		 * Get MAC address from FLASH.
    		 * If it is all 1's or 0's, use the default.
    		 */
    
    		iap = (unsigned char *)FEC_FLASHMAC;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
    		    (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
    			iap = fec_mac_default;
    		if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
    		    (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
    			iap = fec_mac_default;
    	} else {
    		*((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
    		*((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
    		iap = &tmpaddr[0];
    	}
    
    
    	memcpy(dev->dev_addr, iap, ETH_ALEN);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	/* Adjust MAC if using default MAC address */
    
    	if (iap == fec_mac_default)
    		 dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static void __inline__ fec_enable_phy_intr(void)
    {
    }
    
    static void __inline__ fec_disable_phy_intr(void)
    {
    	volatile unsigned long *icrp;
    	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
    
    	*icrp = 0x08000000;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static void __inline__ fec_phy_ack_intr(void)
    {
    	volatile unsigned long *icrp;
    	/* Acknowledge the interrupt */
    	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
    
    	*icrp = 0x0d000000;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static void __inline__ fec_localhw_setup(void)
    {
    }
    
    /*
     *	Do not need to make region uncached on 5272.
     */
    static void __inline__ fec_uncache(unsigned long addr)
    {
    }
    
    /* ------------------------------------------------------------------------- */
    
    
    #elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
    
     *	Code specific to Coldfire 5230/5231/5232/5234/5235,
     *	the 5270/5271/5274/5275 and 5280/5282 setups.
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    static void __inline__ fec_request_intrs(struct net_device *dev)
    {
    	struct fec_enet_private *fep;
    	int b;
    
    	static const struct idesc {
    		char *name;
    		unsigned short irq;
    	} *idp, id[] = {
    		{ "fec(TXF)", 23 },
    		{ "fec(TXB)", 24 },
    		{ "fec(TXFIFO)", 25 },
    		{ "fec(TXCR)", 26 },
    		{ "fec(RXF)", 27 },
    		{ "fec(RXB)", 28 },
    		{ "fec(MII)", 29 },
    		{ "fec(LC)", 30 },
    		{ "fec(HBERR)", 31 },
    		{ "fec(GRA)", 32 },
    		{ "fec(EBERR)", 33 },
    		{ "fec(BABT)", 34 },
    		{ "fec(BABR)", 35 },
    		{ NULL },
    	};
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	fep = netdev_priv(dev);
    	b = (fep->index) ? 128 : 64;
    
    	/* Setup interrupt handlers. */
    
    	for (idp = id; idp->name; idp++) {
    		if (request_irq(b+idp->irq, fec_enet_interrupt, 0, idp->name, dev) != 0)
    			printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq);
    	}
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	/* Unmask interrupts at ColdFire 5280/5282 interrupt controller */
    	{
    		volatile unsigned char  *icrp;
    		volatile unsigned long  *imrp;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    		b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0;
    		icrp = (volatile unsigned char *) (MCF_IPSBAR + b +
    			MCFINTC_ICR0);
    
    		for (i = 23, ilip = 0x28; (i < 36); i++)
    			icrp[i] = ilip--;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    		imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
    			MCFINTC_IMRH);
    		*imrp &= ~0x0000000f;
    		imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
    			MCFINTC_IMRL);
    		*imrp &= ~0xff800001;
    	}
    
    #if defined(CONFIG_M528x)
    	/* Set up gpio outputs for MII lines */
    	{
    
    		volatile u16 *gpio_paspar;
    		volatile u8 *gpio_pehlpar;
    
    		gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056);
    		gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058);
    		*gpio_paspar |= 0x0f00;
    		*gpio_pehlpar = 0xc0;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    #endif
    
    
    #if defined(CONFIG_M527x)
    	/* Set up gpio outputs for MII lines */
    	{
    		volatile u8 *gpio_par_fec;
    		volatile u16 *gpio_par_feci2c;
    
    		gpio_par_feci2c = (volatile u16 *)(MCF_IPSBAR + 0x100082);
    		/* Set up gpio outputs for FEC0 MII lines */
    		gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100078);
    
    		*gpio_par_feci2c |= 0x0f00;
    		*gpio_par_fec |= 0xc0;
    
    #if defined(CONFIG_FEC2)
    		/* Set up gpio outputs for FEC1 MII lines */
    		gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100079);
    
    		*gpio_par_feci2c |= 0x00a0;
    		*gpio_par_fec |= 0xc0;
    #endif /* CONFIG_FEC2 */
    	}
    #endif /* CONFIG_M527x */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
    {
    	volatile fec_t *fecp;
    
    	fecp = fep->hwp;
    	fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
    	fecp->fec_x_cntrl = 0x00;
    
    	/*
    	 * Set MII speed to 2.5 MHz
    	 * See 5282 manual section 17.5.4.7: MSCR
    	 */
    	fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
    	fecp->fec_mii_speed = fep->phy_speed;
    
    	fec_restart(dev, 0);
    }
    
    static void __inline__ fec_get_mac(struct net_device *dev)
    {
    	struct fec_enet_private *fep = netdev_priv(dev);
    	volatile fec_t *fecp;
    
    	unsigned char *iap, tmpaddr[ETH_ALEN];
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	fecp = fep->hwp;
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		/*
    		 * Get MAC address from FLASH.
    		 * If it is all 1's or 0's, use the default.
    		 */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
    		    (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
    			iap = fec_mac_default;
    		if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
    		    (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
    			iap = fec_mac_default;
    	} else {
    		*((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
    		*((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
    		iap = &tmpaddr[0];
    	}
    
    
    	memcpy(dev->dev_addr, iap, ETH_ALEN);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	/* Adjust MAC if using default MAC address */
    
    	if (iap == fec_mac_default)
    		dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static void __inline__ fec_enable_phy_intr(void)
    {
    }
    
    static void __inline__ fec_disable_phy_intr(void)
    {
    }
    
    static void __inline__ fec_phy_ack_intr(void)
    {
    }
    
    static void __inline__ fec_localhw_setup(void)
    {
    }
    
    /*
     *	Do not need to make region uncached on 5272.
     */
    static void __inline__ fec_uncache(unsigned long addr)
    {
    }
    
    /* ------------------------------------------------------------------------- */
    
    
    #elif defined(CONFIG_M520x)
    
    /*
     *	Code specific to Coldfire 520x
     */
    static void __inline__ fec_request_intrs(struct net_device *dev)
    {
    	struct fec_enet_private *fep;
    	int b;
    	static const struct idesc {
    		char *name;
    		unsigned short irq;
    	} *idp, id[] = {
    		{ "fec(TXF)", 23 },
    		{ "fec(TXB)", 24 },
    		{ "fec(TXFIFO)", 25 },
    		{ "fec(TXCR)", 26 },
    		{ "fec(RXF)", 27 },
    		{ "fec(RXB)", 28 },
    		{ "fec(MII)", 29 },
    		{ "fec(LC)", 30 },
    		{ "fec(HBERR)", 31 },
    		{ "fec(GRA)", 32 },
    		{ "fec(EBERR)", 33 },
    		{ "fec(BABT)", 34 },
    		{ "fec(BABR)", 35 },
    		{ NULL },
    	};
    
    	fep = netdev_priv(dev);
    	b = 64 + 13;
    
    	/* Setup interrupt handlers. */
    	for (idp = id; idp->name; idp++) {
    		if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0)
    			printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq);
    	}
    
    	/* Unmask interrupts at ColdFire interrupt controller */
    	{
    		volatile unsigned char  *icrp;
    		volatile unsigned long  *imrp;
    
    		icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
    			MCFINTC_ICR0);
    		for (b = 36; (b < 49); b++)
    			icrp[b] = 0x04;
    		imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 +
    			MCFINTC_IMRH);
    		*imrp &= ~0x0001FFF0;
    	}
    	*(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FEC) |= 0xf0;
    	*(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C) |= 0x0f;
    }
    
    static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
    {
    	volatile fec_t *fecp;
    
    	fecp = fep->hwp;
    	fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
    	fecp->fec_x_cntrl = 0x00;
    
    	/*
    	 * Set MII speed to 2.5 MHz
    	 * See 5282 manual section 17.5.4.7: MSCR
    	 */
    	fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
    	fecp->fec_mii_speed = fep->phy_speed;
    
    	fec_restart(dev, 0);
    }
    
    static void __inline__ fec_get_mac(struct net_device *dev)
    {
    	struct fec_enet_private *fep = netdev_priv(dev);
    	volatile fec_t *fecp;
    	unsigned char *iap, tmpaddr[ETH_ALEN];
    
    	fecp = fep->hwp;
    
    	if (FEC_FLASHMAC) {
    		/*
    		 * Get MAC address from FLASH.
    		 * If it is all 1's or 0's, use the default.
    		 */
    		iap = FEC_FLASHMAC;
    		if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
    		   (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
    			iap = fec_mac_default;
    		if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
    		   (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
    			iap = fec_mac_default;
    	} else {
    		*((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
    		*((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
    		iap = &tmpaddr[0];
    	}
    
    	memcpy(dev->dev_addr, iap, ETH_ALEN);
    
    	/* Adjust MAC if using default MAC address */
    	if (iap == fec_mac_default)
    		dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
    }
    
    static void __inline__ fec_enable_phy_intr(void)
    {
    }
    
    static void __inline__ fec_disable_phy_intr(void)
    {
    }
    
    static void __inline__ fec_phy_ack_intr(void)
    {
    }
    
    static void __inline__ fec_localhw_setup(void)
    {
    }
    
    static void __inline__ fec_uncache(unsigned long addr)
    {
    }
    
    /* ------------------------------------------------------------------------- */
    
    
    #elif defined(CONFIG_M532x)
    /*
     * Code specific for M532x
     */
    static void __inline__ fec_request_intrs(struct net_device *dev)
    {
    	struct fec_enet_private *fep;
    	int b;
    	static const struct idesc {
    		char *name;
    		unsigned short irq;
    	} *idp, id[] = {
    	    { "fec(TXF)", 36 },
    	    { "fec(TXB)", 37 },
    	    { "fec(TXFIFO)", 38 },
    	    { "fec(TXCR)", 39 },
    	    { "fec(RXF)", 40 },
    	    { "fec(RXB)", 41 },
    	    { "fec(MII)", 42 },
    	    { "fec(LC)", 43 },
    	    { "fec(HBERR)", 44 },
    	    { "fec(GRA)", 45 },
    	    { "fec(EBERR)", 46 },
    	    { "fec(BABT)", 47 },
    	    { "fec(BABR)", 48 },
    	    { NULL },
    	};
    
    	fep = netdev_priv(dev);
    	b = (fep->index) ? 128 : 64;
    
    	/* Setup interrupt handlers. */
    	for (idp = id; idp->name; idp++) {
    		if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0)
    
    			printk("FEC: Could not allocate %s IRQ(%d)!\n",
    
    				idp->name, b+idp->irq);
    	}
    
    	/* Unmask interrupts */
    	MCF_INTC0_ICR36 = 0x2;
    	MCF_INTC0_ICR37 = 0x2;
    	MCF_INTC0_ICR38 = 0x2;
    	MCF_INTC0_ICR39 = 0x2;
    	MCF_INTC0_ICR40 = 0x2;
    	MCF_INTC0_ICR41 = 0x2;
    	MCF_INTC0_ICR42 = 0x2;
    	MCF_INTC0_ICR43 = 0x2;
    	MCF_INTC0_ICR44 = 0x2;
    	MCF_INTC0_ICR45 = 0x2;
    	MCF_INTC0_ICR46 = 0x2;
    	MCF_INTC0_ICR47 = 0x2;
    	MCF_INTC0_ICR48 = 0x2;
    
    	MCF_INTC0_IMRH &= ~(
    		MCF_INTC_IMRH_INT_MASK36 |
    		MCF_INTC_IMRH_INT_MASK37 |
    		MCF_INTC_IMRH_INT_MASK38 |
    		MCF_INTC_IMRH_INT_MASK39 |
    		MCF_INTC_IMRH_INT_MASK40 |
    		MCF_INTC_IMRH_INT_MASK41 |
    		MCF_INTC_IMRH_INT_MASK42 |
    		MCF_INTC_IMRH_INT_MASK43 |
    		MCF_INTC_IMRH_INT_MASK44 |
    		MCF_INTC_IMRH_INT_MASK45 |
    		MCF_INTC_IMRH_INT_MASK46 |
    		MCF_INTC_IMRH_INT_MASK47 |
    		MCF_INTC_IMRH_INT_MASK48 );
    
    	/* Set up gpio outputs for MII lines */
    	MCF_GPIO_PAR_FECI2C |= (0 |
    		MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
    		MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
    	MCF_GPIO_PAR_FEC = (0 |
    		MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
    		MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
    }
    
    static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
    {
    	volatile fec_t *fecp;
    
    	fecp = fep->hwp;
    	fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
    	fecp->fec_x_cntrl = 0x00;
    
    	/*
    	 * Set MII speed to 2.5 MHz
    	 */
    	fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
    	fecp->fec_mii_speed = fep->phy_speed;
    
    	fec_restart(dev, 0);
    }
    
    static void __inline__ fec_get_mac(struct net_device *dev)
    {
    	struct fec_enet_private *fep = netdev_priv(dev);
    	volatile fec_t *fecp;
    	unsigned char *iap, tmpaddr[ETH_ALEN];
    
    	fecp = fep->hwp;
    
    	if (FEC_FLASHMAC) {
    		/*
    		 * Get MAC address from FLASH.
    		 * If it is all 1's or 0's, use the default.
    		 */
    		iap = FEC_FLASHMAC;
    		if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
    		    (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
    			iap = fec_mac_default;
    		if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
    		    (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
    			iap = fec_mac_default;
    	} else {
    		*((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
    		*((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
    		iap = &tmpaddr[0];
    	}
    
    	memcpy(dev->dev_addr, iap, ETH_ALEN);
    
    	/* Adjust MAC if using default MAC address */
    	if (iap == fec_mac_default)
    		dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
    }
    
    static void __inline__ fec_enable_phy_intr(void)
    {
    }
    
    static void __inline__ fec_disable_phy_intr(void)
    {
    }
    
    static void __inline__ fec_phy_ack_intr(void)
    {
    }
    
    static void __inline__ fec_localhw_setup(void)
    {
    }
    
    /*
     *	Do not need to make region uncached on 532x.
     */
    static void __inline__ fec_uncache(unsigned long addr)
    {
    }
    
    /* ------------------------------------------------------------------------- */
    
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #else
    
    /*
    
     *	Code specific to the MPC860T setup.
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    static void __inline__ fec_request_intrs(struct net_device *dev)
    {
    	volatile immap_t *immap;
    
    	immap = (immap_t *)IMAP_ADDR;	/* pointer to internal registers */
    
    	if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
    		panic("Could not allocate FEC IRQ!");
    
    #ifdef CONFIG_RPXCLASSIC
    	/* Make Port C, bit 15 an input that causes interrupts.
    	*/
    	immap->im_ioport.iop_pcpar &= ~0x0001;
    	immap->im_ioport.iop_pcdir &= ~0x0001;
    	immap->im_ioport.iop_pcso &= ~0x0001;
    	immap->im_ioport.iop_pcint |= 0x0001;
    	cpm_install_handler(CPMVEC_PIO_PC15, mii_link_interrupt, dev);
    
    	/* Make LEDS reflect Link status.
    	*/
    	*((uint *) RPX_CSR_ADDR) &= ~BCSR2_FETHLEDMODE;
    #endif
    #ifdef CONFIG_FADS
    	if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0)
    		panic("Could not allocate MII IRQ!");
    #endif
    }
    
    static void __inline__ fec_get_mac(struct net_device *dev)
    {
    	bd_t *bd;
    
    	bd = (bd_t *)__res;
    
    	memcpy(dev->dev_addr, bd->bi_enetaddr, ETH_ALEN);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    #ifdef CONFIG_RPXCLASSIC
    	/* The Embedded Planet boards have only one MAC address in
    	 * the EEPROM, but can have two Ethernet ports.  For the
    	 * FEC port, we create another address by setting one of
    	 * the address bits above something that would have (up to
    	 * now) been allocated.
    	 */
    
    	dev->dev_adrd[3] |= 0x80;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #endif
    }
    
    static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
    {
    	extern uint _get_IMMR(void);
    	volatile immap_t *immap;
    	volatile fec_t *fecp;
    
    	fecp = fep->hwp;
    	immap = (immap_t *)IMAP_ADDR;	/* pointer to internal registers */
    
    	/* Configure all of port D for MII.
    	*/
    	immap->im_ioport.iop_pdpar = 0x1fff;
    
    	/* Bits moved from Rev. D onward.
    	*/
    	if ((_get_IMMR() & 0xffff) < 0x0501)
    		immap->im_ioport.iop_pddir = 0x1c58;	/* Pre rev. D */
    	else
    		immap->im_ioport.iop_pddir = 0x1fff;	/* Rev. D and later */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	/* Set MII speed to 2.5 MHz
    	*/
    
    	fecp->fec_mii_speed = fep->phy_speed =
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		((bd->bi_busfreq * 1000000) / 2500000) & 0x7e;
    }
    
    static void __inline__ fec_enable_phy_intr(void)
    {
    	volatile fec_t *fecp;
    
    	fecp = fep->hwp;
    
    
    	/* Enable MII command finished interrupt
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	*/
    	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
    }
    
    static void __inline__ fec_disable_phy_intr(void)
    {
    }
    
    static void __inline__ fec_phy_ack_intr(void)
    {
    }
    
    static void __inline__ fec_localhw_setup(void)
    {
    	volatile fec_t *fecp;
    
    	fecp = fep->hwp;
    	fecp->fec_r_hash = PKT_MAXBUF_SIZE;
    	/* Enable big endian and don't care about SDMA FC.
    	*/
    	fecp->fec_fun_code = 0x78000000;
    }
    
    static void __inline__ fec_uncache(unsigned long addr)
    {
    	pte_t *pte;
    	pte = va_to_pte(mem_addr);
    	pte_val(*pte) |= _PAGE_NO_CACHE;
    	flush_tlb_page(init_mm.mmap, mem_addr);
    }
    
    #endif
    
    /* ------------------------------------------------------------------------- */
    
    static void mii_display_status(struct net_device *dev)
    {
    	struct fec_enet_private *fep = netdev_priv(dev);
    	volatile uint *s = &(fep->phy_status);
    
    	if (!fep->link && !fep->old_link) {
    		/* Link is still down - don't print anything */
    		return;
    	}
    
    	printk("%s: status: ", dev->name);
    
    	if (!fep->link) {
    		printk("link down");
    	} else {
    		printk("link up");
    
    		switch(*s & PHY_STAT_SPMASK) {
    		case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break;
    		case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break;
    		case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break;
    		case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break;
    		default:
    			printk(", Unknown speed/duplex");
    		}
    
    		if (*s & PHY_STAT_ANC)
    			printk(", auto-negotiation complete");
    	}
    
    	if (*s & PHY_STAT_FAULT)
    		printk(", remote fault");
    
    	printk(".\n");
    }
    
    
    static void mii_display_config(struct work_struct *work)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task);
    	struct net_device *dev = fep->netdev;
    
    	uint status = fep->phy_status;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	/*
    	** When we get here, phy_task is already removed from
    	** the workqueue.  It is thus safe to allow to reuse it.
    	*/
    	fep->mii_phy_task_queued = 0;
    	printk("%s: config: auto-negotiation ", dev->name);
    
    
    	if (status & PHY_CONF_ANE)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		printk("on");
    	else
    		printk("off");
    
    
    	if (status & PHY_CONF_100FDX)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		printk(", 100FDX");
    
    	if (status & PHY_CONF_100HDX)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		printk(", 100HDX");
    
    	if (status & PHY_CONF_10FDX)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		printk(", 10FDX");
    
    	if (status & PHY_CONF_10HDX)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		printk(", 10HDX");
    
    	if (!(status & PHY_CONF_SPMASK))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		printk(", No speed/duplex selected?");
    
    
    	if (status & PHY_CONF_LOOP)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		printk(", loopback enabled");
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	printk(".\n");
    
    	fep->sequence_done = 1;
    }