-
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.
Merge pull request #2647 from cesanta/phy
Split PHY code into phy.{c,h}
- Loading branch information
Showing
10 changed files
with
382 additions
and
304 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
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,102 @@ | ||
#include "phy.h" | ||
|
||
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_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 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, 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 | ||
|
||
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 (config & MG_PHY_CLOCKS_MAC) { | ||
// Use PHY crystal oscillator (preserve defaults) | ||
// nothing to do | ||
} else { // MAC clocks PHY, PHY has no xtal | ||
// 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 | ||
} | ||
} | ||
|
||
if (config & MG_PHY_LEDS_ACTIVE_HIGH && 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, 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 && 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#pragma once | ||
|
||
#include "net_builtin.h" | ||
|
||
struct mg_phy { | ||
uint16_t (*read_reg)(uint8_t addr, uint8_t reg); | ||
void (*write_reg)(uint8_t addr, uint8_t reg, uint16_t value); | ||
}; | ||
|
||
// PHY configuration settings, bitmask | ||
enum { | ||
MG_PHY_LEDS_ACTIVE_HIGH = | ||
(1 << 0), // Set if PHY LEDs are connected to ground | ||
MG_PHY_CLOCKS_MAC = | ||
(1 << 1), // Set when PHY clocks MAC. Otherwise, MAC clocks PHY | ||
}; | ||
|
||
enum { MG_PHY_SPEED_10M, MG_PHY_SPEED_100M, MG_PHY_SPEED_1000M }; | ||
|
||
void mg_phy_init(struct mg_phy *, uint8_t addr, uint8_t config); | ||
bool mg_phy_up(struct mg_phy *, uint8_t addr, bool *full_duplex, | ||
uint8_t *speed); |
Oops, something went wrong.