-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
135 additions
and
159 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,104 @@ | ||
#include "phy.h" | ||
|
||
enum { | ||
MG_PHY_KSZ8x = 0x22, | ||
MG_PHY_DP83x = 0x2000, | ||
MG_PHY_LAN87x = 0x7, | ||
enum { // ID1 ID2 | ||
MG_PHY_KSZ8x = 0x22, // 0022 1561 - KSZ8081RNB | ||
MG_PHY_DP83x = 0x2000, // 2000 a140 - TI DP83825I | ||
MG_PHY_LAN87x = 0x7, // 0007 c0fx - LAN8720 | ||
MG_PHY_RTL8201 = 0x1C // 001c c816 - RTL8201 | ||
}; | ||
|
||
enum { | ||
MG_PHY_REG_BCR = 0, | ||
MG_PHY_REG_BSR = 1, | ||
MG_PHY_REG_ID1 = 2, | ||
MG_PHY_REG_ID2 = 3, | ||
MG_PHY_REG_CSCR = 31, | ||
MG_PHY_DP83x_REG_PHYSTS = 16, | ||
MG_PHY_DP83x_REG_RCSR = 23, | ||
MG_PHY_DP83x_REG_LEDCR = 24, | ||
MG_PHY_KSZ8x_REG_PC1R = 30, | ||
MG_PHY_KSZ8x_REG_PC2R = 31, | ||
MG_PHY_LAN87x_REG_SCSR = 31, | ||
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7 | ||
MG_PHY_RTL8201_REG_PAGESEL = 31, | ||
}; | ||
|
||
static const char *mg_phy_id_to_str(uint16_t id) { | ||
switch (id) { | ||
case MG_PHY_KSZ8x: return "KSZ8x"; | ||
case MG_PHY_DP83x: return "DP83x"; | ||
case MG_PHY_LAN87x: return "LAN87x"; | ||
default: return "unknown"; | ||
static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) { | ||
switch (id1) { | ||
case MG_PHY_DP83x: | ||
return "DP83x"; | ||
case MG_PHY_KSZ8x: | ||
return "KSZ8x"; | ||
case MG_PHY_LAN87x: | ||
return "LAN87x"; | ||
case MG_PHY_RTL8201: | ||
return "RTL8201"; | ||
default: | ||
return "unknown"; | ||
} | ||
(void) id2; | ||
} | ||
|
||
void mg_phy_init(struct mg_phy *phy) { | ||
uint16_t id1 = phy->read_reg(phy->addr, MG_PHY_REG_ID1); | ||
uint16_t id2 = phy->read_reg(phy->addr, MG_PHY_REG_ID2); | ||
MG_INFO(("PHY ID: %#04x %#04x (%s)", id1, id2, mg_phy_id_to_str(id1))); | ||
void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) { | ||
phy->write_reg(phy_addr, MG_PHY_REG_BCR, MG_BIT(15)); // Reset PHY | ||
phy->write_reg(phy_addr, MG_PHY_REG_BCR, MG_BIT(12)); // Autonegotiation | ||
|
||
phy->write_reg(phy->addr, MG_PHY_REG_BCR, MG_BIT(15)); // Reset PHY | ||
phy->write_reg(phy->addr, MG_PHY_REG_BCR, MG_BIT(12)); // Autonegotiation | ||
uint16_t id1 = phy->read_reg(phy_addr, MG_PHY_REG_ID1); | ||
uint16_t id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2); | ||
MG_INFO(("PHY ID: %#04x %#04x (%s)", id1, id2, mg_phy_id_to_str(id1, id2))); | ||
|
||
if (id1 == MG_PHY_KSZ8x) { | ||
phy->write_reg(phy->addr, MG_PHY_REG_CSCR, | ||
MG_BIT(15) | MG_BIT(8) | MG_BIT(7)); | ||
} else if (id1 == MG_PHY_DP83x) { | ||
phy->write_reg(phy->addr, 23, 0x81); // 50MHz clock input | ||
phy->write_reg(phy->addr, 24, 0x280); // LED status, active high | ||
bool clkconfig = config & 1; | ||
if (clkconfig == MG_PHY_CONF_CLOCKING) { | ||
// Use PHY crystal oscillator (preserve defaults) | ||
// nothing to do | ||
} else if (clkconfig == MG_PHY_CONF_CLOCKED) { | ||
// Enable 50 MHz external ref clock at XI (preserve defaults) | ||
if (id1 == MG_PHY_DP83x) { | ||
phy->write_reg(phy_addr, MG_PHY_DP83x_REG_RCSR, MG_BIT(7) | MG_BIT(0)); | ||
} else if (id1 == MG_PHY_KSZ8x) { | ||
phy->write_reg(phy_addr, MG_PHY_KSZ8x_REG_PC2R, | ||
MG_BIT(15) | MG_BIT(8) | MG_BIT(7)); | ||
} else if (id1 == MG_PHY_LAN87x) { | ||
// nothing to do | ||
} else if (id1 == MG_PHY_RTL8201) { | ||
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_PAGESEL, 7); // Select page 7 | ||
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_RMSR, 0x7ffb); | ||
phy->write_reg(phy_addr, MG_PHY_RTL8201_REG_PAGESEL, 0); // Select page 0 | ||
} | ||
} | ||
|
||
bool leddrive = config & 2; | ||
if (leddrive && id1 == MG_PHY_DP83x) { | ||
phy->write_reg(phy_addr, MG_PHY_DP83x_REG_LEDCR, | ||
MG_BIT(9) | MG_BIT(7)); // LED status, active high | ||
} // Other PHYs do not support this feature | ||
} | ||
|
||
bool mg_phy_up(struct mg_phy *phy, bool *full_duplex, uint8_t *speed) { | ||
uint16_t bsr = phy->read_reg(phy->addr, MG_PHY_REG_BSR); | ||
bool mg_phy_up(struct mg_phy *phy, uint8_t phy_addr, bool *full_duplex, | ||
uint8_t *speed) { | ||
uint16_t bsr = phy->read_reg(phy_addr, MG_PHY_REG_BSR); | ||
if ((bsr & MG_BIT(5)) && !(bsr & MG_BIT(2))) // some PHYs latch down events | ||
bsr = phy->read_reg(phy_addr, MG_PHY_REG_BSR); // read again | ||
bool up = bsr & MG_BIT(2); | ||
if (up) { | ||
uint16_t scsr = phy->read_reg(phy->addr, MG_PHY_REG_CSCR); | ||
*full_duplex = scsr & MG_BIT(4); | ||
*speed = scsr & MG_BIT(3) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M; | ||
if (up && full_duplex != NULL && speed != NULL) { | ||
uint16_t id1 = phy->read_reg(phy_addr, MG_PHY_REG_ID1); | ||
if (id1 == MG_PHY_DP83x) { | ||
uint16_t physts = phy->read_reg(phy_addr, MG_PHY_DP83x_REG_PHYSTS); | ||
*full_duplex = physts & MG_BIT(2); | ||
*speed = (physts & MG_BIT(1)) ? MG_PHY_SPEED_10M : MG_PHY_SPEED_100M; | ||
} else if (id1 == MG_PHY_KSZ8x) { | ||
uint16_t pc1r = phy->read_reg(phy_addr, MG_PHY_KSZ8x_REG_PC1R); | ||
*full_duplex = pc1r & MG_BIT(2); | ||
*speed = (pc1r & 3) == 1 ? MG_PHY_SPEED_10M : MG_PHY_SPEED_100M; | ||
} else if (id1 == MG_PHY_LAN87x) { | ||
uint16_t scsr = phy->read_reg(phy_addr, MG_PHY_LAN87x_REG_SCSR); | ||
*full_duplex = scsr & MG_BIT(4); | ||
*speed = (scsr & MG_BIT(3)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M; | ||
} else if (id1 == MG_PHY_RTL8201) { | ||
uint16_t bcr = phy->read_reg(phy_addr, MG_PHY_REG_BCR); | ||
if (bcr & MG_BIT(15)) return 0; // still resetting | ||
*full_duplex = bcr & MG_BIT(8); | ||
*speed = (bcr & MG_BIT(13)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M; | ||
} | ||
} | ||
return up; | ||
} |
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
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
Oops, something went wrong.