forked from sonic-net/sonic-buildimage
-
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 for linux igb driver making bcm54616 Broadcom PHY work (sonic-n…
…et#9) Signed-off-by: Nadiya.Stetskovych <Nadiya.Stetskovych@cavium.com>
- Loading branch information
Showing
3 changed files
with
379 additions
and
0 deletions.
There are no files selected for viewing
90 changes: 90 additions & 0 deletions
90
patch/driver-support-intel-avoton-ethernet-with-broadcom-phy.patch
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,90 @@ | ||
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c | ||
index ee74f95..007b7f0 100644 | ||
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c | ||
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c | ||
@@ -226,9 +226,14 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw) | ||
case I347AT4_E_PHY_ID: | ||
case M88E1112_E_PHY_ID: | ||
case M88E1111_I_PHY_ID: | ||
+ case BCM54616_E_PHY_ID: | ||
phy->type = e1000_phy_m88; | ||
phy->ops.check_polarity = igb_check_polarity_m88; | ||
phy->ops.get_phy_info = igb_get_phy_info_m88; | ||
+ | ||
+ if (phy->id == BCM54616_E_PHY_ID) | ||
+ phy->type = e1000_phy_bcm54616; | ||
+ | ||
if (phy->id != M88E1111_I_PHY_ID) | ||
phy->ops.get_cable_length = | ||
igb_get_cable_length_m88_gen2; | ||
@@ -559,6 +564,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) | ||
case E1000_DEV_ID_I350_FIBER: | ||
case E1000_DEV_ID_I350_SERDES: | ||
case E1000_DEV_ID_I350_SGMII: | ||
+ case E1000_DEV_ID_I354_SGMII: | ||
mac->type = e1000_i350; | ||
break; | ||
case E1000_DEV_ID_I210_COPPER: | ||
@@ -573,7 +579,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) | ||
mac->type = e1000_i211; | ||
break; | ||
case E1000_DEV_ID_I354_BACKPLANE_1GBPS: | ||
- case E1000_DEV_ID_I354_SGMII: | ||
case E1000_DEV_ID_I354_BACKPLANE_2_5GBPS: | ||
mac->type = e1000_i354; | ||
break; | ||
@@ -1595,6 +1600,9 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) | ||
case e1000_phy_82580: | ||
ret_val = igb_copper_link_setup_82580(hw); | ||
break; | ||
+ case e1000_phy_bcm54616: | ||
+ ret_val = E1000_SUCCESS; | ||
+ break; | ||
default: | ||
ret_val = -E1000_ERR_PHY; | ||
break; | ||
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h | ||
index 217f813..a2ed2e2 100644 | ||
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h | ||
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h | ||
@@ -461,6 +461,7 @@ | ||
#define E1000_RAH_POOL_1 0x00040000 | ||
|
||
/* Error Codes */ | ||
+#define E1000_SUCCESS 0 | ||
#define E1000_ERR_NVM 1 | ||
#define E1000_ERR_PHY 2 | ||
#define E1000_ERR_CONFIG 3 | ||
@@ -857,6 +858,7 @@ | ||
#define IGP03E1000_E_PHY_ID 0x02A80390 | ||
#define I82580_I_PHY_ID 0x015403A0 | ||
#define I350_I_PHY_ID 0x015403B0 | ||
+#define BCM54616_E_PHY_ID 0x03625D10 | ||
#define M88_VENDOR 0x0141 | ||
#define I210_I_PHY_ID 0x01410C00 | ||
#define M88E1543_E_PHY_ID 0x01410EA0 | ||
diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h | ||
index ce55ea5..762679c 100644 | ||
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h | ||
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h | ||
@@ -128,6 +128,7 @@ enum e1000_phy_type { | ||
e1000_phy_ife, | ||
e1000_phy_82580, | ||
e1000_phy_i210, | ||
+ e1000_phy_bcm54616, | ||
}; | ||
|
||
enum e1000_bus_type { | ||
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c | ||
index 4d2dc17..fe09534 100644 | ||
--- a/drivers/net/ethernet/intel/igb/igb_main.c | ||
+++ b/drivers/net/ethernet/intel/igb/igb_main.c | ||
@@ -74,7 +74,7 @@ static const struct e1000_info *igb_info_tbl[] = { | ||
|
||
static const struct pci_device_id igb_pci_tbl[] = { | ||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_1GBPS) }, | ||
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII) }, | ||
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII), board_82575 }, | ||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) }, | ||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER), board_82575 }, | ||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER), board_82575 }, |
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,287 @@ | ||
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c | ||
index 34088d6..5356cc9 100644 | ||
--- a/drivers/net/phy/broadcom.c | ||
+++ b/drivers/net/phy/broadcom.c | ||
@@ -17,6 +17,7 @@ | ||
#include <linux/module.h> | ||
#include <linux/phy.h> | ||
#include <linux/brcmphy.h> | ||
+#include <linux/delay.h> | ||
|
||
|
||
#define BRCM_PHY_MODEL(phydev) \ | ||
@@ -75,6 +76,8 @@ | ||
/* | ||
* EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17) | ||
*/ | ||
+#define MII_BCM54XX_CR 0x00 /* BCM54xx control register */ | ||
+#define MII_BCM54XX_CR_RESET 0x8000 /* Reset */ | ||
#define MII_BCM54XX_EXP_AADJ1CH0 0x001f | ||
#define MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200 | ||
#define MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF 0x0100 | ||
@@ -91,6 +94,13 @@ | ||
#define MII_BCM54XX_EXP_EXP97 0x0f97 | ||
#define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c | ||
|
||
+#define MII_BCM54XX_AUX_CTL 0x18 /* Auxiliary control */ | ||
+#define MII_BCM54XX_AUX_CTL_ENCODE(val) (((val & 0x7) << 12)|(val & 0x7)) | ||
+ | ||
+#define MII_BCM54XX_AUX_STATUS 0x19 /* Auxiliary status */ | ||
+#define MII_BCM54XX_AUX_STATUS_LINKMODE_MASK 0x0700 | ||
+#define MII_BCM54XX_AUX_STATUS_LINKMODE_SHIFT 8 | ||
+ | ||
/* | ||
* BCM5482: Secondary SerDes registers | ||
*/ | ||
@@ -115,6 +125,10 @@ | ||
#define MII_BRCM_FET_BRCMTEST 0x1f /* Brcm test register */ | ||
#define MII_BRCM_FET_BT_SRE 0x0080 /* Shadow register enable */ | ||
|
||
+#define MII_BCM54XX_SHD_WR_ENCODE(val, data) \ | ||
+ (MII_BCM54XX_SHD_WRITE | MII_BCM54XX_SHD_VAL(val) | \ | ||
+ MII_BCM54XX_SHD_DATA(data)) | ||
+ | ||
|
||
/*** Shadow register definitions ***/ | ||
|
||
@@ -366,6 +380,31 @@ static int bcm54xx_config_init(struct phy_device *phydev) | ||
return 0; | ||
} | ||
|
||
+static int bcm54616_config_init(struct phy_device *phydev) | ||
+{ | ||
+ int reg; | ||
+ | ||
+ /* reset the PHY */ | ||
+ reg = phy_read(phydev, MII_BCM54XX_CR); | ||
+ reg |= MII_BCM54XX_CR_RESET; | ||
+ phy_write(phydev, MII_BCM54XX_CR, reg); | ||
+ | ||
+ /* Setup read from auxilary control shadow register 7 */ | ||
+ phy_write(phydev, MII_BCM54XX_AUX_CTL, | ||
+ MII_BCM54XX_AUX_CTL_ENCODE(7)); | ||
+ /* Read Misc Control register */ | ||
+ reg = (phy_read(phydev, MII_BCM54XX_AUX_CTL) & 0x8FFF) | 0x8010; | ||
+ phy_write(phydev, MII_BCM54XX_AUX_CTL, reg); | ||
+ | ||
+ /* Enable copper/fiber auto-detect */ | ||
+ phy_write(phydev, MII_BCM54XX_SHD, | ||
+ MII_BCM54XX_SHD_WR_ENCODE(0x1e, 0x027)); | ||
+ | ||
+ genphy_config_aneg(phydev); | ||
+ | ||
+ return 0; | ||
+} | ||
+ | ||
static int bcm5482_config_init(struct phy_device *phydev) | ||
{ | ||
int err, reg; | ||
@@ -456,6 +495,125 @@ static int bcm5482_read_status(struct phy_device *phydev) | ||
return err; | ||
} | ||
|
||
+/* | ||
+ * Find out if PHY is in copper or serdes mode by looking at Shadow Reg | ||
+ * 0x1F - "Mode Control Register" | ||
+ */ | ||
+static int bcm54616_is_serdes(struct phy_device *phydev) | ||
+{ | ||
+ u16 val; | ||
+ | ||
+ phy_write(phydev, MII_BCM54XX_SHD, | ||
+ MII_BCM54XX_SHD_VAL(0x1F)); | ||
+ val = phy_read(phydev, MII_BCM54XX_SHD); | ||
+ return (val & 0x0001); | ||
+} | ||
+ | ||
+/* | ||
+ * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating | ||
+ * Mode Status Register" | ||
+ */ | ||
+static u32 bcm54616_parse_serdes_sr(struct phy_device *phydev) | ||
+{ | ||
+ u16 val; | ||
+ int i = 0; | ||
+ | ||
+ /* Wait 1s for link - Clause 37 autonegotiation happens very fast */ | ||
+ while (1) { | ||
+ phy_write(phydev, MII_BCM54XX_SHD, | ||
+ MII_BCM54XX_SHD_VAL(0x15)); | ||
+ val = phy_read(phydev, MII_BCM54XX_SHD); | ||
+ | ||
+ if (val & 0x0200) | ||
+ break; | ||
+ | ||
+ if (i++ > 1000) { | ||
+ phydev->link = 0; | ||
+ return 1; | ||
+ } | ||
+ | ||
+ udelay(1000); /* 1 ms */ | ||
+ } | ||
+ | ||
+ phydev->link = 1; | ||
+ switch ((val >> 6) & 0x3) { | ||
+ case (0x00): | ||
+ phydev->speed = 10; | ||
+ break; | ||
+ case (0x01): | ||
+ phydev->speed = 100; | ||
+ break; | ||
+ case (0x02): | ||
+ phydev->speed = 1000; | ||
+ break; | ||
+ } | ||
+ | ||
+ phydev->duplex = (val & 0x0100) == 0x0100; | ||
+ | ||
+ return 0; | ||
+} | ||
+ | ||
+static int bcm54xx_parse_status(struct phy_device *phydev) | ||
+{ | ||
+ unsigned int mii_reg; | ||
+ | ||
+ mii_reg = phy_read(phydev, MII_BCM54XX_AUX_STATUS); | ||
+ | ||
+ switch ((mii_reg & MII_BCM54XX_AUX_STATUS_LINKMODE_MASK) >> | ||
+ MII_BCM54XX_AUX_STATUS_LINKMODE_SHIFT) { | ||
+ case 1: | ||
+ phydev->duplex = DUPLEX_HALF; | ||
+ phydev->speed = SPEED_10; | ||
+ break; | ||
+ case 2: | ||
+ phydev->duplex = DUPLEX_FULL; | ||
+ phydev->speed = SPEED_10; | ||
+ break; | ||
+ case 3: | ||
+ phydev->duplex = DUPLEX_HALF; | ||
+ phydev->speed = SPEED_100; | ||
+ break; | ||
+ case 5: | ||
+ phydev->duplex = DUPLEX_FULL; | ||
+ phydev->speed = SPEED_100; | ||
+ break; | ||
+ case 6: | ||
+ phydev->duplex = DUPLEX_HALF; | ||
+ phydev->speed = SPEED_1000; | ||
+ break; | ||
+ case 7: | ||
+ phydev->duplex = DUPLEX_FULL; | ||
+ phydev->speed = SPEED_1000; | ||
+ break; | ||
+ default: | ||
+ printk("Auto-neg error, defaulting to 1000/HD\n"); | ||
+ phydev->duplex = DUPLEX_FULL; | ||
+ phydev->speed = SPEED_1000; | ||
+ break; | ||
+ } | ||
+ | ||
+ return 0; | ||
+} | ||
+ | ||
+/* | ||
+ * Figure out if BCM54616 is in serdes or copper mode and determine link | ||
+ * configuration accordingly | ||
+ */ | ||
+static int bcm54616_read_status(struct phy_device *phydev) | ||
+{ | ||
+ if (bcm54616_is_serdes(phydev)) { | ||
+ bcm54616_parse_serdes_sr(phydev); | ||
+ /* phydev->port = PORT_FIBRE; */ | ||
+ } else { | ||
+ /* Wait for auto-negotiation to complete or fail */ | ||
+ genphy_update_link(phydev); | ||
+ /* Parse BCM54xx copper aux status register */ | ||
+ bcm54xx_parse_status(phydev); | ||
+ } | ||
+ | ||
+ return 0; | ||
+} | ||
+ | ||
static int bcm54xx_ack_interrupt(struct phy_device *phydev) | ||
{ | ||
int reg; | ||
@@ -468,6 +626,18 @@ static int bcm54xx_ack_interrupt(struct phy_device *phydev) | ||
return 0; | ||
} | ||
|
||
+static int bcm54616_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; | ||
@@ -485,6 +655,23 @@ static int bcm54xx_config_intr(struct phy_device *phydev) | ||
return err; | ||
} | ||
|
||
+static int bcm54616_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 int bcm5481_config_aneg(struct phy_device *phydev) | ||
{ | ||
int ret; | ||
@@ -671,6 +858,19 @@ static struct phy_driver broadcom_drivers[] = { | ||
.config_intr = bcm54xx_config_intr, | ||
.driver = { .owner = THIS_MODULE }, | ||
}, { | ||
+ .phy_id = PHY_ID_BCM54616, | ||
+ .phy_id_mask = 0xfffffff0, | ||
+ .name = "Broadcom BCM54616", | ||
+ .features = PHY_GBIT_FEATURES | | ||
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause, | ||
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | ||
+ .config_init = bcm54616_config_init, | ||
+ .config_aneg = genphy_config_aneg, | ||
+ .read_status = bcm54616_read_status, | ||
+ .ack_interrupt = bcm54616_ack_interrupt, | ||
+ .config_intr = bcm54616_config_intr, | ||
+ .driver = { .owner = THIS_MODULE }, | ||
+}, { | ||
.phy_id = PHY_ID_BCM5464, | ||
.phy_id_mask = 0xfffffff0, | ||
.name = "Broadcom BCM5464", | ||
@@ -795,6 +995,7 @@ static struct mdio_device_id __maybe_unused broadcom_tbl[] = { | ||
{ PHY_ID_BCM5411, 0xfffffff0 }, | ||
{ PHY_ID_BCM5421, 0xfffffff0 }, | ||
{ PHY_ID_BCM5461, 0xfffffff0 }, | ||
+ { PHY_ID_BCM54616, 0xfffffff0 }, | ||
{ PHY_ID_BCM5464, 0xfffffff0 }, | ||
{ PHY_ID_BCM5482, 0xfffffff0 }, | ||
{ PHY_ID_BCM5482, 0xfffffff0 }, | ||
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h | ||
index 6f76277..63b1d5e 100644 | ||
--- a/include/linux/brcmphy.h | ||
+++ b/include/linux/brcmphy.h | ||
@@ -11,6 +11,7 @@ | ||
#define PHY_ID_BCM5421 0x002060e0 | ||
#define PHY_ID_BCM5464 0x002060b0 | ||
#define PHY_ID_BCM5461 0x002060c0 | ||
+#define PHY_ID_BCM54616 0x03625d10 | ||
#define PHY_ID_BCM57780 0x03625d90 | ||
|
||
#define PHY_ID_BCM7366 0x600d8490 |
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