-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PATCH] 2.6.18: sb1250-mac: Broadcom PHY support
This patch adds support for interrupt-driven operation of the Broadcom Gigabit Ethernet PHYs. I have included device IDs for the parts used on Broadcom SiByte evaluation boards; more can be added as a need arises. They are apparently generally software-compatible with one another. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> patch-mips-2.6.18-20060920-broadcom-phy-15 Signed-off-by: Jeff Garzik <jeff@garzik.org>
- Loading branch information
Maciej W. Rozycki
authored and
Jeff Garzik
committed
Dec 2, 2006
1 parent
116b23b
commit c4b41c9
Showing
3 changed files
with
182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
/* | ||
* drivers/net/phy/broadcom.c | ||
* | ||
* Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet | ||
* transceivers. | ||
* | ||
* Copyright (c) 2006 Maciej W. Rozycki | ||
* | ||
* Inspired by code written by Amy Fong. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version | ||
* 2 of the License, or (at your option) any later version. | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/phy.h> | ||
|
||
#define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ | ||
#define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ | ||
#define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */ | ||
|
||
#define MII_BCM54XX_ESR 0x11 /* BCM54xx extended status register */ | ||
#define MII_BCM54XX_ESR_IS 0x1000 /* Interrupt status */ | ||
|
||
#define MII_BCM54XX_ISR 0x1a /* BCM54xx interrupt status register */ | ||
#define MII_BCM54XX_IMR 0x1b /* BCM54xx interrupt mask register */ | ||
#define MII_BCM54XX_INT_CRCERR 0x0001 /* CRC error */ | ||
#define MII_BCM54XX_INT_LINK 0x0002 /* Link status changed */ | ||
#define MII_BCM54XX_INT_SPEED 0x0004 /* Link speed change */ | ||
#define MII_BCM54XX_INT_DUPLEX 0x0008 /* Duplex mode changed */ | ||
#define MII_BCM54XX_INT_LRS 0x0010 /* Local receiver status changed */ | ||
#define MII_BCM54XX_INT_RRS 0x0020 /* Remote receiver status changed */ | ||
#define MII_BCM54XX_INT_SSERR 0x0040 /* Scrambler synchronization error */ | ||
#define MII_BCM54XX_INT_UHCD 0x0080 /* Unsupported HCD negotiated */ | ||
#define MII_BCM54XX_INT_NHCD 0x0100 /* No HCD */ | ||
#define MII_BCM54XX_INT_NHCDL 0x0200 /* No HCD link */ | ||
#define MII_BCM54XX_INT_ANPR 0x0400 /* Auto-negotiation page received */ | ||
#define MII_BCM54XX_INT_LC 0x0800 /* All counters below 128 */ | ||
#define MII_BCM54XX_INT_HC 0x1000 /* Counter above 32768 */ | ||
#define MII_BCM54XX_INT_MDIX 0x2000 /* MDIX status change */ | ||
#define MII_BCM54XX_INT_PSERR 0x4000 /* Pair swap error */ | ||
|
||
MODULE_DESCRIPTION("Broadcom PHY driver"); | ||
MODULE_AUTHOR("Maciej W. Rozycki"); | ||
MODULE_LICENSE("GPL"); | ||
|
||
static int bcm54xx_config_init(struct phy_device *phydev) | ||
{ | ||
int reg, err; | ||
|
||
reg = phy_read(phydev, MII_BCM54XX_ECR); | ||
if (reg < 0) | ||
return reg; | ||
|
||
/* Mask interrupts globally. */ | ||
reg |= MII_BCM54XX_ECR_IM; | ||
err = phy_write(phydev, MII_BCM54XX_ECR, reg); | ||
if (err < 0) | ||
return err; | ||
|
||
/* Unmask events we are interested in. */ | ||
reg = ~(MII_BCM54XX_INT_DUPLEX | | ||
MII_BCM54XX_INT_SPEED | | ||
MII_BCM54XX_INT_LINK); | ||
err = phy_write(phydev, MII_BCM54XX_IMR, reg); | ||
if (err < 0) | ||
return err; | ||
return 0; | ||
} | ||
|
||
static int bcm54xx_ack_interrupt(struct phy_device *phydev) | ||
{ | ||
int reg; | ||
|
||
/* Clear pending interrupts. */ | ||
reg = phy_read(phydev, MII_BCM54XX_ISR); | ||
if (reg < 0) | ||
return reg; | ||
|
||
return 0; | ||
} | ||
|
||
static int bcm54xx_config_intr(struct phy_device *phydev) | ||
{ | ||
int reg, err; | ||
|
||
reg = phy_read(phydev, MII_BCM54XX_ECR); | ||
if (reg < 0) | ||
return reg; | ||
|
||
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) | ||
reg &= ~MII_BCM54XX_ECR_IM; | ||
else | ||
reg |= MII_BCM54XX_ECR_IM; | ||
|
||
err = phy_write(phydev, MII_BCM54XX_ECR, reg); | ||
return err; | ||
} | ||
|
||
static struct phy_driver bcm5411_driver = { | ||
.phy_id = 0x00206070, | ||
.phy_id_mask = 0xfffffff0, | ||
.name = "Broadcom BCM5411", | ||
.features = PHY_GBIT_FEATURES, | ||
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | ||
.config_init = bcm54xx_config_init, | ||
.config_aneg = genphy_config_aneg, | ||
.read_status = genphy_read_status, | ||
.ack_interrupt = bcm54xx_ack_interrupt, | ||
.config_intr = bcm54xx_config_intr, | ||
.driver = { .owner = THIS_MODULE }, | ||
}; | ||
|
||
static struct phy_driver bcm5421_driver = { | ||
.phy_id = 0x002060e0, | ||
.phy_id_mask = 0xfffffff0, | ||
.name = "Broadcom BCM5421", | ||
.features = PHY_GBIT_FEATURES, | ||
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | ||
.config_init = bcm54xx_config_init, | ||
.config_aneg = genphy_config_aneg, | ||
.read_status = genphy_read_status, | ||
.ack_interrupt = bcm54xx_ack_interrupt, | ||
.config_intr = bcm54xx_config_intr, | ||
.driver = { .owner = THIS_MODULE }, | ||
}; | ||
|
||
static struct phy_driver bcm5461_driver = { | ||
.phy_id = 0x002060c0, | ||
.phy_id_mask = 0xfffffff0, | ||
.name = "Broadcom BCM5461", | ||
.features = PHY_GBIT_FEATURES, | ||
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | ||
.config_init = bcm54xx_config_init, | ||
.config_aneg = genphy_config_aneg, | ||
.read_status = genphy_read_status, | ||
.ack_interrupt = bcm54xx_ack_interrupt, | ||
.config_intr = bcm54xx_config_intr, | ||
.driver = { .owner = THIS_MODULE }, | ||
}; | ||
|
||
static int __init broadcom_init(void) | ||
{ | ||
int ret; | ||
|
||
ret = phy_driver_register(&bcm5411_driver); | ||
if (ret) | ||
goto out_5411; | ||
ret = phy_driver_register(&bcm5421_driver); | ||
if (ret) | ||
goto out_5421; | ||
ret = phy_driver_register(&bcm5461_driver); | ||
if (ret) | ||
goto out_5461; | ||
return ret; | ||
|
||
out_5461: | ||
phy_driver_unregister(&bcm5421_driver); | ||
out_5421: | ||
phy_driver_unregister(&bcm5411_driver); | ||
out_5411: | ||
return ret; | ||
} | ||
|
||
static void __exit broadcom_exit(void) | ||
{ | ||
phy_driver_unregister(&bcm5461_driver); | ||
phy_driver_unregister(&bcm5421_driver); | ||
phy_driver_unregister(&bcm5411_driver); | ||
} | ||
|
||
module_init(broadcom_init); | ||
module_exit(broadcom_exit); |