sungem_phy.c

来自「linux 内核源代码」· C语言 代码 · 共 1,200 行 · 第 1/2 页

C
1,200
字号
	/* find out in what mode we are */	phy_write(phy, MII_NCONFIG, 0x1000);	phy_reg = phy_read(phy, MII_NCONFIG);	mode = (phy_reg & BCM5421_MODE_MASK) >> 5;	if ( mode == BCM54XX_COPPER)		return genmii_poll_link(phy);	/* try to find out wether we have a link */	phy_write(phy, MII_NCONFIG, 0x2000);	phy_reg = phy_read(phy, MII_NCONFIG);	if (phy_reg & 0x0020)		return 0;	else		return 1;}static int bcm5421_read_link(struct mii_phy* phy){	u32 phy_reg;	int mode;	/* find out in what mode we are */	phy_write(phy, MII_NCONFIG, 0x1000);	phy_reg = phy_read(phy, MII_NCONFIG);	mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;	if ( mode == BCM54XX_COPPER)		return bcm54xx_read_link(phy);	phy->speed = SPEED_1000;	/* find out wether we are running half- or full duplex */	phy_write(phy, MII_NCONFIG, 0x2000);	phy_reg = phy_read(phy, MII_NCONFIG);	if ( (phy_reg & 0x0080) >> 7)		phy->duplex |=  DUPLEX_HALF;	else		phy->duplex |=  DUPLEX_FULL;	return 0;}static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg){	/* enable fiber mode */	phy_write(phy, MII_NCONFIG, 0x9020);	/* LEDs active in both modes, autosense prio = fiber */	phy_write(phy, MII_NCONFIG, 0x945f);	if (!autoneg) {		/* switch off fibre autoneg */		phy_write(phy, MII_NCONFIG, 0xfc01);		phy_write(phy, 0x0b, 0x0004);	}	phy->autoneg = autoneg;	return 0;}#define BCM5461_FIBER_LINK	(1 << 2)#define BCM5461_MODE_MASK	(3 << 1)static int bcm5461_poll_link(struct mii_phy* phy){	u32 phy_reg;	int mode;	/* find out in what mode we are */	phy_write(phy, MII_NCONFIG, 0x7c00);	phy_reg = phy_read(phy, MII_NCONFIG);	mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;	if ( mode == BCM54XX_COPPER)		return genmii_poll_link(phy);	/* find out wether we have a link */	phy_write(phy, MII_NCONFIG, 0x7000);	phy_reg = phy_read(phy, MII_NCONFIG);	if (phy_reg & BCM5461_FIBER_LINK)		return 1;	else		return 0;}#define BCM5461_FIBER_DUPLEX	(1 << 3)static int bcm5461_read_link(struct mii_phy* phy){	u32 phy_reg;	int mode;	/* find out in what mode we are */	phy_write(phy, MII_NCONFIG, 0x7c00);	phy_reg = phy_read(phy, MII_NCONFIG);	mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;	if ( mode == BCM54XX_COPPER) {		return bcm54xx_read_link(phy);	}	phy->speed = SPEED_1000;	/* find out wether we are running half- or full duplex */	phy_write(phy, MII_NCONFIG, 0x7000);	phy_reg = phy_read(phy, MII_NCONFIG);	if (phy_reg & BCM5461_FIBER_DUPLEX)		phy->duplex |=  DUPLEX_FULL;	else		phy->duplex |=  DUPLEX_HALF;	return 0;}static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg){	/* select fiber mode, enable 1000 base-X registers */	phy_write(phy, MII_NCONFIG, 0xfc0b);	if (autoneg) {		/* enable fiber with no autonegotiation */		phy_write(phy, MII_ADVERTISE, 0x01e0);		phy_write(phy, MII_BMCR, 0x1140);	} else {		/* enable fiber with autonegotiation */		phy_write(phy, MII_BMCR, 0x0140);	}	phy->autoneg = autoneg;	return 0;}static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise){	u16 ctl, adv;	phy->autoneg = 1;	phy->speed = SPEED_10;	phy->duplex = DUPLEX_HALF;	phy->pause = 0;	phy->advertising = advertise;	/* Setup standard advertise */	adv = phy_read(phy, MII_ADVERTISE);	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);	if (advertise & ADVERTISED_10baseT_Half)		adv |= ADVERTISE_10HALF;	if (advertise & ADVERTISED_10baseT_Full)		adv |= ADVERTISE_10FULL;	if (advertise & ADVERTISED_100baseT_Half)		adv |= ADVERTISE_100HALF;	if (advertise & ADVERTISED_100baseT_Full)		adv |= ADVERTISE_100FULL;	if (advertise & ADVERTISED_Pause)		adv |= ADVERTISE_PAUSE_CAP;	if (advertise & ADVERTISED_Asym_Pause)		adv |= ADVERTISE_PAUSE_ASYM;	phy_write(phy, MII_ADVERTISE, adv);	/* Setup 1000BT advertise & enable crossover detect	 * XXX How do we advertise 1000BT ? Darwin source is	 * confusing here, they read from specific control and	 * write to control... Someone has specs for those	 * beasts ?	 */	adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);	adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |			MII_1000BASETCONTROL_HALFDUPLEXCAP);	if (advertise & SUPPORTED_1000baseT_Half)		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;	if (advertise & SUPPORTED_1000baseT_Full)		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;	phy_write(phy, MII_1000BASETCONTROL, adv);	/* Start/Restart aneg */	ctl = phy_read(phy, MII_BMCR);	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);	phy_write(phy, MII_BMCR, ctl);	return 0;}static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd){	u16 ctl, ctl2;	phy->autoneg = 0;	phy->speed = speed;	phy->duplex = fd;	phy->pause = 0;	ctl = phy_read(phy, MII_BMCR);	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);	ctl |= BMCR_RESET;	/* Select speed & duplex */	switch(speed) {	case SPEED_10:		break;	case SPEED_100:		ctl |= BMCR_SPEED100;		break;	/* I'm not sure about the one below, again, Darwin source is	 * quite confusing and I lack chip specs	 */	case SPEED_1000:		ctl |= BMCR_SPD2;	}	if (fd == DUPLEX_FULL)		ctl |= BMCR_FULLDPLX;	/* Disable crossover. Again, the way Apple does it is strange,	 * though I don't assume they are wrong ;)	 */	ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);	ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |		MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |		MII_1000BASETCONTROL_FULLDUPLEXCAP |		MII_1000BASETCONTROL_HALFDUPLEXCAP);	if (speed == SPEED_1000)		ctl2 |= (fd == DUPLEX_FULL) ?			MII_1000BASETCONTROL_FULLDUPLEXCAP :			MII_1000BASETCONTROL_HALFDUPLEXCAP;	phy_write(phy, MII_1000BASETCONTROL, ctl2);	// XXX Should we set the sungem to GII now on 1000BT ?	phy_write(phy, MII_BMCR, ctl);	return 0;}static int marvell_read_link(struct mii_phy *phy){	u16 status, pmask;	if (phy->autoneg) {		status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);		if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)			return -EAGAIN;		if (status & MII_M1011_PHY_SPEC_STATUS_1000)			phy->speed = SPEED_1000;		else if (status & MII_M1011_PHY_SPEC_STATUS_100)			phy->speed = SPEED_100;		else			phy->speed = SPEED_10;		if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)			phy->duplex = DUPLEX_FULL;		else			phy->duplex = DUPLEX_HALF;		pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |			MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;		phy->pause = (status & pmask) == pmask;	}	/* On non-aneg, we assume what we put in BMCR is the speed,	 * though magic-aneg shouldn't prevent this case from occurring	 */	return 0;}#define MII_BASIC_FEATURES \	(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |	\	 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |	\	 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |	\	 SUPPORTED_Pause)/* On gigabit capable PHYs, we advertise Pause support but not asym pause * support for now as I'm not sure it's supported and Darwin doesn't do * it neither. --BenH. */#define MII_GBIT_FEATURES \	(MII_BASIC_FEATURES |	\	 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)/* Broadcom BCM 5201 */static struct mii_phy_ops bcm5201_phy_ops = {	.init		= bcm5201_init,	.suspend	= bcm5201_suspend,	.setup_aneg	= genmii_setup_aneg,	.setup_forced	= genmii_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= genmii_read_link,};static struct mii_phy_def bcm5201_phy_def = {	.phy_id		= 0x00406210,	.phy_id_mask	= 0xfffffff0,	.name		= "BCM5201",	.features	= MII_BASIC_FEATURES,	.magic_aneg	= 1,	.ops		= &bcm5201_phy_ops};/* Broadcom BCM 5221 */static struct mii_phy_ops bcm5221_phy_ops = {	.suspend	= bcm5221_suspend,	.init		= bcm5221_init,	.setup_aneg	= genmii_setup_aneg,	.setup_forced	= genmii_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= genmii_read_link,};static struct mii_phy_def bcm5221_phy_def = {	.phy_id		= 0x004061e0,	.phy_id_mask	= 0xfffffff0,	.name		= "BCM5221",	.features	= MII_BASIC_FEATURES,	.magic_aneg	= 1,	.ops		= &bcm5221_phy_ops};/* Broadcom BCM 5241 */static struct mii_phy_ops bcm5241_phy_ops = {	.suspend	= bcm5241_suspend,	.init		= bcm5241_init,	.setup_aneg	= genmii_setup_aneg,	.setup_forced	= genmii_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= genmii_read_link,};static struct mii_phy_def bcm5241_phy_def = {	.phy_id		= 0x0143bc30,	.phy_id_mask	= 0xfffffff0,	.name		= "BCM5241",	.features	= MII_BASIC_FEATURES,	.magic_aneg	= 1,	.ops		= &bcm5241_phy_ops};/* Broadcom BCM 5400 */static struct mii_phy_ops bcm5400_phy_ops = {	.init		= bcm5400_init,	.suspend	= bcm5400_suspend,	.setup_aneg	= bcm54xx_setup_aneg,	.setup_forced	= bcm54xx_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= bcm54xx_read_link,};static struct mii_phy_def bcm5400_phy_def = {	.phy_id		= 0x00206040,	.phy_id_mask	= 0xfffffff0,	.name		= "BCM5400",	.features	= MII_GBIT_FEATURES,	.magic_aneg	= 1,	.ops		= &bcm5400_phy_ops};/* Broadcom BCM 5401 */static struct mii_phy_ops bcm5401_phy_ops = {	.init		= bcm5401_init,	.suspend	= bcm5401_suspend,	.setup_aneg	= bcm54xx_setup_aneg,	.setup_forced	= bcm54xx_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= bcm54xx_read_link,};static struct mii_phy_def bcm5401_phy_def = {	.phy_id		= 0x00206050,	.phy_id_mask	= 0xfffffff0,	.name		= "BCM5401",	.features	= MII_GBIT_FEATURES,	.magic_aneg	= 1,	.ops		= &bcm5401_phy_ops};/* Broadcom BCM 5411 */static struct mii_phy_ops bcm5411_phy_ops = {	.init		= bcm5411_init,	.suspend	= generic_suspend,	.setup_aneg	= bcm54xx_setup_aneg,	.setup_forced	= bcm54xx_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= bcm54xx_read_link,};static struct mii_phy_def bcm5411_phy_def = {	.phy_id		= 0x00206070,	.phy_id_mask	= 0xfffffff0,	.name		= "BCM5411",	.features	= MII_GBIT_FEATURES,	.magic_aneg	= 1,	.ops		= &bcm5411_phy_ops};/* Broadcom BCM 5421 */static struct mii_phy_ops bcm5421_phy_ops = {	.init		= bcm5421_init,	.suspend	= generic_suspend,	.setup_aneg	= bcm54xx_setup_aneg,	.setup_forced	= bcm54xx_setup_forced,	.poll_link	= bcm5421_poll_link,	.read_link	= bcm5421_read_link,	.enable_fiber   = bcm5421_enable_fiber,};static struct mii_phy_def bcm5421_phy_def = {	.phy_id		= 0x002060e0,	.phy_id_mask	= 0xfffffff0,	.name		= "BCM5421",	.features	= MII_GBIT_FEATURES,	.magic_aneg	= 1,	.ops		= &bcm5421_phy_ops};/* Broadcom BCM 5421 built-in K2 */static struct mii_phy_ops bcm5421k2_phy_ops = {	.init		= bcm5421_init,	.suspend	= generic_suspend,	.setup_aneg	= bcm54xx_setup_aneg,	.setup_forced	= bcm54xx_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= bcm54xx_read_link,};static struct mii_phy_def bcm5421k2_phy_def = {	.phy_id		= 0x002062e0,	.phy_id_mask	= 0xfffffff0,	.name		= "BCM5421-K2",	.features	= MII_GBIT_FEATURES,	.magic_aneg	= 1,	.ops		= &bcm5421k2_phy_ops};static struct mii_phy_ops bcm5461_phy_ops = {	.init		= bcm5421_init,	.suspend	= generic_suspend,	.setup_aneg	= bcm54xx_setup_aneg,	.setup_forced	= bcm54xx_setup_forced,	.poll_link	= bcm5461_poll_link,	.read_link	= bcm5461_read_link,	.enable_fiber   = bcm5461_enable_fiber,};static struct mii_phy_def bcm5461_phy_def = {	.phy_id		= 0x002060c0,	.phy_id_mask	= 0xfffffff0,	.name		= "BCM5461",	.features	= MII_GBIT_FEATURES,	.magic_aneg	= 1,	.ops		= &bcm5461_phy_ops};/* Broadcom BCM 5462 built-in Vesta */static struct mii_phy_ops bcm5462V_phy_ops = {	.init		= bcm5421_init,	.suspend	= generic_suspend,	.setup_aneg	= bcm54xx_setup_aneg,	.setup_forced	= bcm54xx_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= bcm54xx_read_link,};static struct mii_phy_def bcm5462V_phy_def = {	.phy_id		= 0x002060d0,	.phy_id_mask	= 0xfffffff0,	.name		= "BCM5462-Vesta",	.features	= MII_GBIT_FEATURES,	.magic_aneg	= 1,	.ops		= &bcm5462V_phy_ops};/* Marvell 88E1101 amd 88E1111 */static struct mii_phy_ops marvell88e1101_phy_ops = {	.suspend	= generic_suspend,	.setup_aneg	= marvell_setup_aneg,	.setup_forced	= marvell_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= marvell_read_link};static struct mii_phy_ops marvell88e1111_phy_ops = {	.init		= marvell88e1111_init,	.suspend	= generic_suspend,	.setup_aneg	= marvell_setup_aneg,	.setup_forced	= marvell_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= marvell_read_link};/* two revs in darwin for the 88e1101 ... I could use a datasheet * to get the proper names... */static struct mii_phy_def marvell88e1101v1_phy_def = {	.phy_id		= 0x01410c20,	.phy_id_mask	= 0xfffffff0,	.name		= "Marvell 88E1101v1",	.features	= MII_GBIT_FEATURES,	.magic_aneg	= 1,	.ops		= &marvell88e1101_phy_ops};static struct mii_phy_def marvell88e1101v2_phy_def = {	.phy_id		= 0x01410c60,	.phy_id_mask	= 0xfffffff0,	.name		= "Marvell 88E1101v2",	.features	= MII_GBIT_FEATURES,	.magic_aneg	= 1,	.ops		= &marvell88e1101_phy_ops};static struct mii_phy_def marvell88e1111_phy_def = {	.phy_id		= 0x01410cc0,	.phy_id_mask	= 0xfffffff0,	.name		= "Marvell 88E1111",	.features	= MII_GBIT_FEATURES,	.magic_aneg	= 1,	.ops		= &marvell88e1111_phy_ops};/* Generic implementation for most 10/100 PHYs */static struct mii_phy_ops generic_phy_ops = {	.setup_aneg	= genmii_setup_aneg,	.setup_forced	= genmii_setup_forced,	.poll_link	= genmii_poll_link,	.read_link	= genmii_read_link};static struct mii_phy_def genmii_phy_def = {	.phy_id		= 0x00000000,	.phy_id_mask	= 0x00000000,	.name		= "Generic MII",	.features	= MII_BASIC_FEATURES,	.magic_aneg	= 0,	.ops		= &generic_phy_ops};static struct mii_phy_def* mii_phy_table[] = {	&bcm5201_phy_def,	&bcm5221_phy_def,	&bcm5241_phy_def,	&bcm5400_phy_def,	&bcm5401_phy_def,	&bcm5411_phy_def,	&bcm5421_phy_def,	&bcm5421k2_phy_def,	&bcm5461_phy_def,	&bcm5462V_phy_def,	&marvell88e1101v1_phy_def,	&marvell88e1101v2_phy_def,	&marvell88e1111_phy_def,	&genmii_phy_def,	NULL};int mii_phy_probe(struct mii_phy *phy, int mii_id){	int rc;	u32 id;	struct mii_phy_def* def;	int i;	/* We do not reset the mii_phy structure as the driver	 * may re-probe the PHY regulary	 */	phy->mii_id = mii_id;	/* Take PHY out of isloate mode and reset it. */	rc = reset_one_mii_phy(phy, mii_id);	if (rc)		goto fail;	/* Read ID and find matching entry */	id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));	printk(KERN_DEBUG "PHY ID: %x, addr: %x\n", id, mii_id);	for (i=0; (def = mii_phy_table[i]) != NULL; i++)		if ((id & def->phy_id_mask) == def->phy_id)			break;	/* Should never be NULL (we have a generic entry), but... */	if (def == NULL)		goto fail;	phy->def = def;	return 0;fail:	phy->speed = 0;	phy->duplex = 0;	phy->pause = 0;	phy->advertising = 0;	return -ENODEV;}EXPORT_SYMBOL(mii_phy_probe);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?