mirror of
https://github.com/cesanta/mongoose.git
synced 2025-01-13 17:34:52 +08:00
Split PHY code into phy.{c,h}; add PHY config to STM32H driver
This commit is contained in:
parent
98782e44c2
commit
928aed4342
305
mongoose.c
305
mongoose.c
@ -14488,33 +14488,20 @@ static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED;
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED;
|
||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||
|
||||
enum {
|
||||
MG_PHYREG_BCR = 0,
|
||||
MG_PHYREG_BSR = 1,
|
||||
MG_PHYREG_ID1 = 2,
|
||||
MG_PHYREG_ID2 = 3
|
||||
};
|
||||
|
||||
static uint16_t enet_phy_read(uint8_t addr, uint8_t reg) {
|
||||
static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) {
|
||||
ENET->EIR |= MG_BIT(23); // MII interrupt clear
|
||||
ENET->MMFR = (1 << 30) | (2 << 28) | (addr << 23) | (reg << 18) | (2 << 16);
|
||||
while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0;
|
||||
return ENET->MMFR & 0xffff;
|
||||
}
|
||||
|
||||
static void enet_phy_write(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
static void enet_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
ENET->EIR |= MG_BIT(23); // MII interrupt clear
|
||||
ENET->MMFR =
|
||||
(1 << 30) | (1 << 28) | (addr << 23) | (reg << 18) | (2 << 16) | val;
|
||||
while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0;
|
||||
}
|
||||
|
||||
static uint32_t enet_phy_id(uint8_t addr) {
|
||||
uint16_t phy_id1 = enet_phy_read(addr, MG_PHYREG_ID1);
|
||||
uint16_t phy_id2 = enet_phy_read(addr, MG_PHYREG_ID2);
|
||||
return (uint32_t) phy_id1 << 16 | phy_id2;
|
||||
}
|
||||
|
||||
// MDC clock is generated from IPS Bus clock (ipg_clk); as per 802.3,
|
||||
// it must not exceed 2.5MHz
|
||||
// The PHY receives the PLL6-generated 50MHz clock
|
||||
@ -14544,28 +14531,8 @@ static bool mg_tcpip_driver_imxrt_init(struct mg_tcpip_if *ifp) {
|
||||
// TODO(): Otherwise, guess (currently assuming max freq)
|
||||
int cr = (d == NULL || d->mdc_cr < 0) ? 24 : d->mdc_cr;
|
||||
ENET->MSCR = (1 << 8) | ((cr & 0x3f) << 1); // HOLDTIME 2 clks
|
||||
|
||||
enet_phy_write(d->phy_addr, MG_PHYREG_BCR, MG_BIT(15)); // Reset PHY
|
||||
enet_phy_write(d->phy_addr, MG_PHYREG_BCR,
|
||||
MG_BIT(12)); // Set autonegotiation
|
||||
|
||||
// PHY: Enable 50 MHz external ref clock at XI (preserve defaults)
|
||||
uint32_t id = enet_phy_id(d->phy_addr);
|
||||
MG_INFO(("PHY ID: %#04x %#04x", (uint16_t) (id >> 16), (uint16_t) id));
|
||||
// 2000 a140 - TI DP83825I
|
||||
// 0007 c0fx - LAN8720
|
||||
// 0022 1561 - KSZ8081RNB
|
||||
|
||||
if ((id & 0xffff0000) == 0x220000) { // KSZ8081RNB, like EVK-RTxxxx boards
|
||||
enet_phy_write(d->phy_addr, 31,
|
||||
MG_BIT(15) | MG_BIT(8) | MG_BIT(7)); // PC2R
|
||||
} else if ((id & 0xffff0000) == 0x20000000) { // DP83825I, like Teensy4.1
|
||||
enet_phy_write(d->phy_addr, 23, 0x81); // 50MHz clock input
|
||||
enet_phy_write(d->phy_addr, 24, 0x280); // LED status, active high
|
||||
} else { // Default to LAN8720
|
||||
MG_INFO(("Defaulting to LAN8720 PHY...")); // TODO()
|
||||
}
|
||||
|
||||
struct mg_phy phy = {enet_read_phy, enet_write_phy};
|
||||
mg_phy_init(&phy, d->phy_addr, MG_PHY_LEDS_ACTIVE_HIGH); // MAC clocks PHY
|
||||
// Select RMII mode, 100M, keep CRC, set max rx length, disable loop
|
||||
ENET->RCR = (1518 << 16) | MG_BIT(8) | MG_BIT(2);
|
||||
// ENET->RCR |= MG_BIT(3); // Receive all
|
||||
@ -14613,28 +14580,18 @@ static size_t mg_tcpip_driver_imxrt_tx(const void *buf, size_t len,
|
||||
static bool mg_tcpip_driver_imxrt_up(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_imxrt_data *d =
|
||||
(struct mg_tcpip_driver_imxrt_data *) ifp->driver_data;
|
||||
uint32_t bsr = enet_phy_read(d->phy_addr, MG_PHYREG_BSR);
|
||||
bool up = bsr & MG_BIT(2) ? 1 : 0;
|
||||
uint8_t speed = MG_PHY_SPEED_10M;
|
||||
bool up = false, full_duplex = false;
|
||||
struct mg_phy phy = {enet_read_phy, enet_write_phy};
|
||||
up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed);
|
||||
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
|
||||
// tmp = reg with flags set to the most likely situation: 100M full-duplex
|
||||
// if(link is slow or half) set flags otherwise
|
||||
// reg = tmp
|
||||
uint32_t tcr = ENET->TCR | MG_BIT(2); // Full-duplex
|
||||
uint32_t rcr = ENET->RCR & ~MG_BIT(9); // 100M
|
||||
uint32_t phy_id = enet_phy_id(d->phy_addr);
|
||||
if ((phy_id & 0xffff0000) == 0x220000) { // KSZ8081RNB
|
||||
uint16_t pc1r = enet_phy_read(d->phy_addr, 30); // Read PC1R
|
||||
if ((pc1r & 3) == 1) rcr |= MG_BIT(9); // 10M
|
||||
if ((pc1r & MG_BIT(2)) == 0) tcr &= ~MG_BIT(2); // Half-duplex
|
||||
} else if ((phy_id & 0xffff0000) == 0x20000000) { // DP83825I
|
||||
uint16_t physts = enet_phy_read(d->phy_addr, 16); // Read PHYSTS
|
||||
if (physts & MG_BIT(1)) rcr |= MG_BIT(9); // 10M
|
||||
if ((physts & MG_BIT(2)) == 0) tcr &= ~MG_BIT(2); // Half-duplex
|
||||
} else { // Default to LAN8720
|
||||
uint16_t scsr = enet_phy_read(d->phy_addr, 31); // Read CSCR
|
||||
if ((scsr & MG_BIT(3)) == 0) rcr |= MG_BIT(9); // 10M
|
||||
if ((scsr & MG_BIT(4)) == 0) tcr &= ~MG_BIT(2); // Half-duplex
|
||||
}
|
||||
uint32_t tcr = ENET->TCR | MG_BIT(2); // Full-duplex
|
||||
uint32_t rcr = ENET->RCR & ~MG_BIT(9); // 100M
|
||||
if (speed == MG_PHY_SPEED_10M) rcr |= MG_BIT(9); // 10M
|
||||
if (full_duplex == false) tcr &= ~MG_BIT(2); // Half-duplex
|
||||
ENET->TCR = tcr; // IRQ handler does not fiddle with these registers
|
||||
ENET->RCR = rcr;
|
||||
MG_DEBUG(("Link is %uM %s-duplex", rcr & MG_BIT(9) ? 10 : 100,
|
||||
@ -14670,6 +14627,112 @@ struct mg_tcpip_driver mg_tcpip_driver_imxrt = {mg_tcpip_driver_imxrt_init,
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MG_ENABLE_LINES
|
||||
#line 1 "src/drivers/phy.c"
|
||||
#endif
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef MG_ENABLE_LINES
|
||||
#line 1 "src/drivers/ra.c"
|
||||
#endif
|
||||
@ -14716,13 +14779,6 @@ static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED;
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED;
|
||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||
|
||||
enum {
|
||||
MG_PHYREG_BCR = 0,
|
||||
MG_PHYREG_BSR = 1,
|
||||
MG_PHYREG_ID1 = 2,
|
||||
MG_PHYREG_ID2 = 3
|
||||
};
|
||||
|
||||
// fastest is 3 cycles (SUB + BNE) on a 3-stage pipeline or equivalent
|
||||
static inline void raspin(volatile uint32_t count) {
|
||||
while (count--) (void) 0;
|
||||
@ -14792,20 +14848,14 @@ static uint16_t smi_rd(uint16_t header) {
|
||||
return data;
|
||||
}
|
||||
|
||||
static uint16_t raeth_phy_read(uint8_t addr, uint8_t reg) {
|
||||
static uint16_t raeth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
return smi_rd((1 << 14) | (2 << 12) | (addr << 7) | (reg << 2) | (2 << 0));
|
||||
}
|
||||
|
||||
static void raeth_phy_write(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
static void raeth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
smi_wr((1 << 14) | (1 << 12) | (addr << 7) | (reg << 2) | (2 << 0), val);
|
||||
}
|
||||
|
||||
static uint32_t raeth_phy_id(uint8_t addr) {
|
||||
uint16_t phy_id1 = raeth_phy_read(addr, MG_PHYREG_ID1);
|
||||
uint16_t phy_id2 = raeth_phy_read(addr, MG_PHYREG_ID2);
|
||||
return (uint32_t) phy_id1 << 16 | phy_id2;
|
||||
}
|
||||
|
||||
// MDC clock is generated manually; as per 802.3, it must not exceed 2.5MHz
|
||||
static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_ra_data *d =
|
||||
@ -14839,27 +14889,8 @@ static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) {
|
||||
EDMAC->EDMR = MG_BIT(6); // Initialize, little-endian (27.2.1)
|
||||
|
||||
MG_DEBUG(("PHY addr: %d, smispin: %d", d->phy_addr, s_smispin));
|
||||
raeth_phy_write(d->phy_addr, MG_PHYREG_BCR, MG_BIT(15)); // Reset PHY
|
||||
raeth_phy_write(d->phy_addr, MG_PHYREG_BCR,
|
||||
MG_BIT(12)); // Set autonegotiation
|
||||
|
||||
// PHY: Enable ref clock (preserve defaults)
|
||||
uint32_t id = raeth_phy_id(d->phy_addr);
|
||||
MG_INFO(("PHY ID: %#04x %#04x", (uint16_t) (id >> 16), (uint16_t) id));
|
||||
// 2000 a140 - TI DP83825I
|
||||
// 0007 c0fx - LAN8720
|
||||
// 0022 156x - KSZ8081RNB/KSZ8091RNB
|
||||
|
||||
if ((id & 0xffff0000) == 0x220000) { // KSZ8091RNB, like EK-RA6Mx boards
|
||||
// 25 MHz xtal at XI/XO (default)
|
||||
raeth_phy_write(d->phy_addr, 31, MG_BIT(15) | MG_BIT(8)); // PC2R
|
||||
} else if ((id & 0xffff0000) == 0x20000000) { // DP83825I, like ???
|
||||
// 50 MHz external at XI ???
|
||||
raeth_phy_write(d->phy_addr, 23, 0x81); // 50MHz clock input
|
||||
raeth_phy_write(d->phy_addr, 24, 0x280); // LED status, active high
|
||||
} else { // Default to LAN8720
|
||||
MG_INFO(("Defaulting to LAN8720 PHY...")); // TODO()
|
||||
}
|
||||
struct mg_phy phy = {raeth_read_phy, raeth_write_phy};
|
||||
mg_phy_init(&phy, d->phy_addr, 0); // MAC clocks PHY
|
||||
|
||||
// Select RMII mode,
|
||||
ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC
|
||||
@ -14908,27 +14939,17 @@ static size_t mg_tcpip_driver_ra_tx(const void *buf, size_t len,
|
||||
static bool mg_tcpip_driver_ra_up(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_ra_data *d =
|
||||
(struct mg_tcpip_driver_ra_data *) ifp->driver_data;
|
||||
uint32_t bsr = raeth_phy_read(d->phy_addr, MG_PHYREG_BSR);
|
||||
bool up = bsr & MG_BIT(2) ? 1 : 0;
|
||||
uint8_t speed = MG_PHY_SPEED_10M;
|
||||
bool up = false, full_duplex = false;
|
||||
struct mg_phy phy = {raeth_read_phy, raeth_write_phy};
|
||||
up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed);
|
||||
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
|
||||
// tmp = reg with flags set to the most likely situation: 100M full-duplex
|
||||
// if(link is slow or half) set flags otherwise
|
||||
// reg = tmp
|
||||
uint32_t ecmr = ETHERC->ECMR | MG_BIT(2) | MG_BIT(1); // 100M Full-duplex
|
||||
uint32_t phy_id = raeth_phy_id(d->phy_addr);
|
||||
if ((phy_id & 0xffff0000) == 0x220000) { // KSZ8091RNB
|
||||
uint16_t pc1r = raeth_phy_read(d->phy_addr, 30); // Read PC1R
|
||||
if ((pc1r & 3) == 1) ecmr &= ~MG_BIT(2); // 10M
|
||||
if ((pc1r & MG_BIT(2)) == 0) ecmr &= ~MG_BIT(1); // Half-duplex
|
||||
} else if ((phy_id & 0xffff0000) == 0x20000000) { // DP83825I
|
||||
uint16_t physts = raeth_phy_read(d->phy_addr, 16); // Read PHYSTS
|
||||
if (physts & MG_BIT(1)) ecmr &= ~MG_BIT(2); // 10M
|
||||
if ((physts & MG_BIT(2)) == 0) ecmr &= ~MG_BIT(1); // Half-duplex
|
||||
} else { // Default to LAN8720
|
||||
uint16_t scsr = raeth_phy_read(d->phy_addr, 31); // Read CSCR
|
||||
if ((scsr & MG_BIT(3)) == 0) ecmr &= ~MG_BIT(2); // 10M
|
||||
if ((scsr & MG_BIT(4)) == 0) ecmr &= ~MG_BIT(1); // Half-duplex
|
||||
}
|
||||
if (speed == MG_PHY_SPEED_10M) ecmr &= ~MG_BIT(2); // 10M
|
||||
if (full_duplex == false) ecmr &= ~MG_BIT(1); // Half-duplex
|
||||
ETHERC->ECMR = ecmr; // IRQ handler does not fiddle with these registers
|
||||
MG_DEBUG(("Link is %uM %s-duplex", ecmr & MG_BIT(2) ? 100 : 10,
|
||||
ecmr & MG_BIT(1) ? "full" : "half"));
|
||||
@ -15220,23 +15241,16 @@ static uint8_t s_txno; // Current TX descriptor
|
||||
static uint8_t s_rxno; // Current RX descriptor
|
||||
|
||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||
enum {
|
||||
MG_PHYREG_BCR = 0,
|
||||
MG_PHYREG_BSR = 1,
|
||||
MG_PHYREG_ID1 = 2,
|
||||
MG_PHYREG_ID2 = 3,
|
||||
MG_PHYREG_CSCR = 31
|
||||
};
|
||||
|
||||
static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
ETH->MACMIIAR &= (7 << 2);
|
||||
ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6);
|
||||
ETH->MACMIIAR |= MG_BIT(0);
|
||||
while (ETH->MACMIIAR & MG_BIT(0)) (void) 0;
|
||||
return ETH->MACMIIDR;
|
||||
return ETH->MACMIIDR & 0xffff;
|
||||
}
|
||||
|
||||
static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
|
||||
static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
ETH->MACMIIDR = val;
|
||||
ETH->MACMIIAR &= (7 << 2);
|
||||
ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | MG_BIT(1);
|
||||
@ -15334,19 +15348,16 @@ static bool mg_tcpip_driver_stm32f_init(struct mg_tcpip_if *ifp) {
|
||||
ETH->MACIMR = MG_BIT(3) | MG_BIT(9); // Mask timestamp & PMT IT
|
||||
ETH->MACFCR = MG_BIT(7); // Disable zero quarta pause
|
||||
// ETH->MACFFR = MG_BIT(31); // Receive all
|
||||
eth_write_phy(phy_addr, MG_PHYREG_BCR, MG_BIT(15)); // Reset PHY
|
||||
eth_write_phy(phy_addr, MG_PHYREG_BCR, MG_BIT(12)); // Set autonegotiation
|
||||
ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
|
||||
ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors
|
||||
ETH->DMAIER = MG_BIT(6) | MG_BIT(16); // RIE, NISE
|
||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||
mg_phy_init(&phy, phy_addr, MG_PHY_CLOCKS_MAC);
|
||||
ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
|
||||
ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors
|
||||
ETH->DMAIER = MG_BIT(6) | MG_BIT(16); // RIE, NISE
|
||||
ETH->MACCR =
|
||||
MG_BIT(2) | MG_BIT(3) | MG_BIT(11) | MG_BIT(14); // RE, TE, Duplex, Fast
|
||||
ETH->DMAOMR =
|
||||
MG_BIT(1) | MG_BIT(13) | MG_BIT(21) | MG_BIT(25); // SR, ST, TSF, RSF
|
||||
|
||||
MG_DEBUG(("PHY ID: %#04hx %#04hx", eth_read_phy(phy_addr, MG_PHYREG_ID1),
|
||||
eth_read_phy(phy_addr, MG_PHYREG_ID2)));
|
||||
|
||||
// MAC address filtering
|
||||
ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
|
||||
ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) |
|
||||
@ -15382,16 +15393,17 @@ static bool mg_tcpip_driver_stm32f_up(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_stm32f_data *d =
|
||||
(struct mg_tcpip_driver_stm32f_data *) ifp->driver_data;
|
||||
uint8_t phy_addr = d == NULL ? 0 : d->phy_addr;
|
||||
uint32_t bsr = eth_read_phy(phy_addr, MG_PHYREG_BSR);
|
||||
bool up = bsr & MG_BIT(2) ? 1 : 0;
|
||||
uint8_t speed = MG_PHY_SPEED_10M;
|
||||
bool up = false, full_duplex = false;
|
||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||
up = mg_phy_up(&phy, phy_addr, &full_duplex, &speed);
|
||||
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
|
||||
uint32_t scsr = eth_read_phy(phy_addr, MG_PHYREG_CSCR);
|
||||
// tmp = reg with flags set to the most likely situation: 100M full-duplex
|
||||
// if(link is slow or half) set flags otherwise
|
||||
// reg = tmp
|
||||
uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(11); // 100M, Full-duplex
|
||||
if ((scsr & MG_BIT(3)) == 0) maccr &= ~MG_BIT(14); // 10M
|
||||
if ((scsr & MG_BIT(4)) == 0) maccr &= ~MG_BIT(11); // Half-duplex
|
||||
if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M
|
||||
if (full_duplex == false) maccr &= ~MG_BIT(11); // Half-duplex
|
||||
ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
|
||||
MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10,
|
||||
maccr & MG_BIT(11) ? "full" : "half"));
|
||||
@ -15481,22 +15493,16 @@ static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
|
||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
|
||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||
enum {
|
||||
MG_PHY_ADDR = 0,
|
||||
MG_PHYREG_BCR = 0,
|
||||
MG_PHYREG_BSR = 1,
|
||||
MG_PHYREG_CSCR = 31
|
||||
}; // PHY constants
|
||||
|
||||
static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
ETH->MACMDIOAR &= (0xF << 8);
|
||||
ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 3 << 2;
|
||||
ETH->MACMDIOAR |= MG_BIT(0);
|
||||
while (ETH->MACMDIOAR & MG_BIT(0)) (void) 0;
|
||||
return ETH->MACMDIODR;
|
||||
return (uint16_t) ETH->MACMDIODR;
|
||||
}
|
||||
|
||||
static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
|
||||
static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
ETH->MACMDIODR = val;
|
||||
ETH->MACMDIOAR &= (0xF << 8);
|
||||
ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 1 << 2;
|
||||
@ -15584,6 +15590,8 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_stm32h_data *d =
|
||||
(struct mg_tcpip_driver_stm32h_data *) ifp->driver_data;
|
||||
s_ifp = ifp;
|
||||
uint8_t phy_addr = d == NULL ? 0 : d->phy_addr;
|
||||
uint8_t phy_conf = d == NULL ? MG_PHY_CLOCKS_MAC : d->phy_conf;
|
||||
|
||||
// Init RX descriptors
|
||||
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
||||
@ -15610,9 +15618,8 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
||||
ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
|
||||
ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause
|
||||
// ETH->MACPFR = MG_BIT(31); // Receive all
|
||||
eth_write_phy(MG_PHY_ADDR, MG_PHYREG_BCR, MG_BIT(15)); // Reset PHY
|
||||
eth_write_phy(MG_PHY_ADDR, MG_PHYREG_BCR,
|
||||
MG_BIT(12)); // Set autonegotiation
|
||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||
mg_phy_init(&phy, phy_addr, phy_conf);
|
||||
ETH->DMACRDLAR =
|
||||
(uint32_t) (uintptr_t) s_rxdesc; // RX descriptors start address
|
||||
ETH->DMACRDRLR = ETH_DESC_CNT - 1; // ring length
|
||||
@ -15667,16 +15674,20 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
|
||||
}
|
||||
|
||||
static bool mg_tcpip_driver_stm32h_up(struct mg_tcpip_if *ifp) {
|
||||
uint32_t bsr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_BSR);
|
||||
bool up = bsr & MG_BIT(2) ? 1 : 0;
|
||||
struct mg_tcpip_driver_stm32h_data *d =
|
||||
(struct mg_tcpip_driver_stm32h_data *) ifp->driver_data;
|
||||
uint8_t phy_addr = d == NULL ? 0 : d->phy_addr;
|
||||
uint8_t speed = MG_PHY_SPEED_10M;
|
||||
bool up = false, full_duplex = false;
|
||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||
up = mg_phy_up(&phy, phy_addr, &full_duplex, &speed);
|
||||
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
|
||||
uint32_t scsr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_CSCR);
|
||||
// tmp = reg with flags set to the most likely situation: 100M full-duplex
|
||||
// if(link is slow or half) set flags otherwise
|
||||
// reg = tmp
|
||||
uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex
|
||||
if ((scsr & MG_BIT(3)) == 0) maccr &= ~MG_BIT(14); // 10M
|
||||
if ((scsr & MG_BIT(4)) == 0) maccr &= ~MG_BIT(13); // Half-duplex
|
||||
if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M
|
||||
if (full_duplex == false) maccr &= ~MG_BIT(13); // Half-duplex
|
||||
ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
|
||||
MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10,
|
||||
maccr & MG_BIT(13) ? "full" : "half"));
|
||||
|
40
mongoose.h
40
mongoose.h
@ -2937,6 +2937,28 @@ struct mg_tcpip_driver_imxrt_data {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RA) && MG_ENABLE_DRIVER_RA
|
||||
|
||||
struct mg_tcpip_driver_ra_data {
|
||||
@ -3037,7 +3059,7 @@ struct mg_tcpip_driver_stm32f_data {
|
||||
|
||||
#define MG_TCPIP_DRIVER_DATA \
|
||||
static struct mg_tcpip_driver_stm32f_data driver_data = { \
|
||||
.mdc_cr = MG_DRIVER_MDC_CR, \
|
||||
.mdc_cr = MG_DRIVER_MDC_CR, \
|
||||
.phy_addr = MG_TCPIP_PHY_ADDR, \
|
||||
};
|
||||
|
||||
@ -3059,23 +3081,31 @@ struct mg_tcpip_driver_stm32h_data {
|
||||
// 100-150 MHz HCLK/62 1
|
||||
// 20-35 MHz HCLK/16 2
|
||||
// 35-60 MHz HCLK/26 3
|
||||
// 150-250 MHz HCLK/102 4 <-- value for Nucleo-H* on max speed driven by HSI
|
||||
// 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on max speed driven by CSI
|
||||
// 110, 111 Reserved
|
||||
// 150-250 MHz HCLK/102 4 <-- value for Nucleo-H* on max speed
|
||||
// driven by HSI 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on
|
||||
// max speed driven by CSI 110, 111 Reserved
|
||||
int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
|
||||
|
||||
uint8_t phy_addr; // PHY address
|
||||
uint8_t phy_conf; // PHY config
|
||||
};
|
||||
|
||||
#ifndef MG_MAC_ADDRESS
|
||||
#define MG_MAC_ADDRESS MG_MAC_ADDRESS_RANDOM
|
||||
#endif
|
||||
|
||||
#ifndef MG_TCPIP_PHY_ADDR
|
||||
#define MG_TCPIP_PHY_ADDR 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_DRIVER_MDC_CR
|
||||
#define MG_DRIVER_MDC_CR 4
|
||||
#endif
|
||||
|
||||
#define MG_TCPIP_DRIVER_DATA \
|
||||
static struct mg_tcpip_driver_stm32h_data driver_data = { \
|
||||
.mdc_cr = MG_DRIVER_MDC_CR, \
|
||||
.mdc_cr = MG_DRIVER_MDC_CR, \
|
||||
.phy_addr = MG_TCPIP_PHY_ADDR, \
|
||||
};
|
||||
|
||||
#define MG_TCPIP_DRIVER_CODE &mg_tcpip_driver_stm32h
|
||||
|
@ -48,33 +48,20 @@ static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED;
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_64BYTE_ALIGNED;
|
||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||
|
||||
enum {
|
||||
MG_PHYREG_BCR = 0,
|
||||
MG_PHYREG_BSR = 1,
|
||||
MG_PHYREG_ID1 = 2,
|
||||
MG_PHYREG_ID2 = 3
|
||||
};
|
||||
|
||||
static uint16_t enet_phy_read(uint8_t addr, uint8_t reg) {
|
||||
static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) {
|
||||
ENET->EIR |= MG_BIT(23); // MII interrupt clear
|
||||
ENET->MMFR = (1 << 30) | (2 << 28) | (addr << 23) | (reg << 18) | (2 << 16);
|
||||
while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0;
|
||||
return ENET->MMFR & 0xffff;
|
||||
}
|
||||
|
||||
static void enet_phy_write(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
static void enet_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
ENET->EIR |= MG_BIT(23); // MII interrupt clear
|
||||
ENET->MMFR =
|
||||
(1 << 30) | (1 << 28) | (addr << 23) | (reg << 18) | (2 << 16) | val;
|
||||
while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0;
|
||||
}
|
||||
|
||||
static uint32_t enet_phy_id(uint8_t addr) {
|
||||
uint16_t phy_id1 = enet_phy_read(addr, MG_PHYREG_ID1);
|
||||
uint16_t phy_id2 = enet_phy_read(addr, MG_PHYREG_ID2);
|
||||
return (uint32_t) phy_id1 << 16 | phy_id2;
|
||||
}
|
||||
|
||||
// MDC clock is generated from IPS Bus clock (ipg_clk); as per 802.3,
|
||||
// it must not exceed 2.5MHz
|
||||
// The PHY receives the PLL6-generated 50MHz clock
|
||||
@ -104,28 +91,8 @@ static bool mg_tcpip_driver_imxrt_init(struct mg_tcpip_if *ifp) {
|
||||
// TODO(): Otherwise, guess (currently assuming max freq)
|
||||
int cr = (d == NULL || d->mdc_cr < 0) ? 24 : d->mdc_cr;
|
||||
ENET->MSCR = (1 << 8) | ((cr & 0x3f) << 1); // HOLDTIME 2 clks
|
||||
|
||||
enet_phy_write(d->phy_addr, MG_PHYREG_BCR, MG_BIT(15)); // Reset PHY
|
||||
enet_phy_write(d->phy_addr, MG_PHYREG_BCR,
|
||||
MG_BIT(12)); // Set autonegotiation
|
||||
|
||||
// PHY: Enable 50 MHz external ref clock at XI (preserve defaults)
|
||||
uint32_t id = enet_phy_id(d->phy_addr);
|
||||
MG_INFO(("PHY ID: %#04x %#04x", (uint16_t) (id >> 16), (uint16_t) id));
|
||||
// 2000 a140 - TI DP83825I
|
||||
// 0007 c0fx - LAN8720
|
||||
// 0022 1561 - KSZ8081RNB
|
||||
|
||||
if ((id & 0xffff0000) == 0x220000) { // KSZ8081RNB, like EVK-RTxxxx boards
|
||||
enet_phy_write(d->phy_addr, 31,
|
||||
MG_BIT(15) | MG_BIT(8) | MG_BIT(7)); // PC2R
|
||||
} else if ((id & 0xffff0000) == 0x20000000) { // DP83825I, like Teensy4.1
|
||||
enet_phy_write(d->phy_addr, 23, 0x81); // 50MHz clock input
|
||||
enet_phy_write(d->phy_addr, 24, 0x280); // LED status, active high
|
||||
} else { // Default to LAN8720
|
||||
MG_INFO(("Defaulting to LAN8720 PHY...")); // TODO()
|
||||
}
|
||||
|
||||
struct mg_phy phy = {enet_read_phy, enet_write_phy};
|
||||
mg_phy_init(&phy, d->phy_addr, MG_PHY_LEDS_ACTIVE_HIGH); // MAC clocks PHY
|
||||
// Select RMII mode, 100M, keep CRC, set max rx length, disable loop
|
||||
ENET->RCR = (1518 << 16) | MG_BIT(8) | MG_BIT(2);
|
||||
// ENET->RCR |= MG_BIT(3); // Receive all
|
||||
@ -173,28 +140,18 @@ static size_t mg_tcpip_driver_imxrt_tx(const void *buf, size_t len,
|
||||
static bool mg_tcpip_driver_imxrt_up(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_imxrt_data *d =
|
||||
(struct mg_tcpip_driver_imxrt_data *) ifp->driver_data;
|
||||
uint32_t bsr = enet_phy_read(d->phy_addr, MG_PHYREG_BSR);
|
||||
bool up = bsr & MG_BIT(2) ? 1 : 0;
|
||||
uint8_t speed = MG_PHY_SPEED_10M;
|
||||
bool up = false, full_duplex = false;
|
||||
struct mg_phy phy = {enet_read_phy, enet_write_phy};
|
||||
up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed);
|
||||
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
|
||||
// tmp = reg with flags set to the most likely situation: 100M full-duplex
|
||||
// if(link is slow or half) set flags otherwise
|
||||
// reg = tmp
|
||||
uint32_t tcr = ENET->TCR | MG_BIT(2); // Full-duplex
|
||||
uint32_t rcr = ENET->RCR & ~MG_BIT(9); // 100M
|
||||
uint32_t phy_id = enet_phy_id(d->phy_addr);
|
||||
if ((phy_id & 0xffff0000) == 0x220000) { // KSZ8081RNB
|
||||
uint16_t pc1r = enet_phy_read(d->phy_addr, 30); // Read PC1R
|
||||
if ((pc1r & 3) == 1) rcr |= MG_BIT(9); // 10M
|
||||
if ((pc1r & MG_BIT(2)) == 0) tcr &= ~MG_BIT(2); // Half-duplex
|
||||
} else if ((phy_id & 0xffff0000) == 0x20000000) { // DP83825I
|
||||
uint16_t physts = enet_phy_read(d->phy_addr, 16); // Read PHYSTS
|
||||
if (physts & MG_BIT(1)) rcr |= MG_BIT(9); // 10M
|
||||
if ((physts & MG_BIT(2)) == 0) tcr &= ~MG_BIT(2); // Half-duplex
|
||||
} else { // Default to LAN8720
|
||||
uint16_t scsr = enet_phy_read(d->phy_addr, 31); // Read CSCR
|
||||
if ((scsr & MG_BIT(3)) == 0) rcr |= MG_BIT(9); // 10M
|
||||
if ((scsr & MG_BIT(4)) == 0) tcr &= ~MG_BIT(2); // Half-duplex
|
||||
}
|
||||
uint32_t tcr = ENET->TCR | MG_BIT(2); // Full-duplex
|
||||
uint32_t rcr = ENET->RCR & ~MG_BIT(9); // 100M
|
||||
if (speed == MG_PHY_SPEED_10M) rcr |= MG_BIT(9); // 10M
|
||||
if (full_duplex == false) tcr &= ~MG_BIT(2); // Half-duplex
|
||||
ENET->TCR = tcr; // IRQ handler does not fiddle with these registers
|
||||
ENET->RCR = rcr;
|
||||
MG_DEBUG(("Link is %uM %s-duplex", rcr & MG_BIT(9) ? 10 : 100,
|
||||
|
102
src/drivers/phy.c
Normal file
102
src/drivers/phy.c
Normal file
@ -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;
|
||||
}
|
22
src/drivers/phy.h
Normal file
22
src/drivers/phy.h
Normal file
@ -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);
|
@ -41,13 +41,6 @@ static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED;
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_32BYTE_ALIGNED;
|
||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||
|
||||
enum {
|
||||
MG_PHYREG_BCR = 0,
|
||||
MG_PHYREG_BSR = 1,
|
||||
MG_PHYREG_ID1 = 2,
|
||||
MG_PHYREG_ID2 = 3
|
||||
};
|
||||
|
||||
// fastest is 3 cycles (SUB + BNE) on a 3-stage pipeline or equivalent
|
||||
static inline void raspin(volatile uint32_t count) {
|
||||
while (count--) (void) 0;
|
||||
@ -117,20 +110,14 @@ static uint16_t smi_rd(uint16_t header) {
|
||||
return data;
|
||||
}
|
||||
|
||||
static uint16_t raeth_phy_read(uint8_t addr, uint8_t reg) {
|
||||
static uint16_t raeth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
return smi_rd((1 << 14) | (2 << 12) | (addr << 7) | (reg << 2) | (2 << 0));
|
||||
}
|
||||
|
||||
static void raeth_phy_write(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
static void raeth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
smi_wr((1 << 14) | (1 << 12) | (addr << 7) | (reg << 2) | (2 << 0), val);
|
||||
}
|
||||
|
||||
static uint32_t raeth_phy_id(uint8_t addr) {
|
||||
uint16_t phy_id1 = raeth_phy_read(addr, MG_PHYREG_ID1);
|
||||
uint16_t phy_id2 = raeth_phy_read(addr, MG_PHYREG_ID2);
|
||||
return (uint32_t) phy_id1 << 16 | phy_id2;
|
||||
}
|
||||
|
||||
// MDC clock is generated manually; as per 802.3, it must not exceed 2.5MHz
|
||||
static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_ra_data *d =
|
||||
@ -164,27 +151,8 @@ static bool mg_tcpip_driver_ra_init(struct mg_tcpip_if *ifp) {
|
||||
EDMAC->EDMR = MG_BIT(6); // Initialize, little-endian (27.2.1)
|
||||
|
||||
MG_DEBUG(("PHY addr: %d, smispin: %d", d->phy_addr, s_smispin));
|
||||
raeth_phy_write(d->phy_addr, MG_PHYREG_BCR, MG_BIT(15)); // Reset PHY
|
||||
raeth_phy_write(d->phy_addr, MG_PHYREG_BCR,
|
||||
MG_BIT(12)); // Set autonegotiation
|
||||
|
||||
// PHY: Enable ref clock (preserve defaults)
|
||||
uint32_t id = raeth_phy_id(d->phy_addr);
|
||||
MG_INFO(("PHY ID: %#04x %#04x", (uint16_t) (id >> 16), (uint16_t) id));
|
||||
// 2000 a140 - TI DP83825I
|
||||
// 0007 c0fx - LAN8720
|
||||
// 0022 156x - KSZ8081RNB/KSZ8091RNB
|
||||
|
||||
if ((id & 0xffff0000) == 0x220000) { // KSZ8091RNB, like EK-RA6Mx boards
|
||||
// 25 MHz xtal at XI/XO (default)
|
||||
raeth_phy_write(d->phy_addr, 31, MG_BIT(15) | MG_BIT(8)); // PC2R
|
||||
} else if ((id & 0xffff0000) == 0x20000000) { // DP83825I, like ???
|
||||
// 50 MHz external at XI ???
|
||||
raeth_phy_write(d->phy_addr, 23, 0x81); // 50MHz clock input
|
||||
raeth_phy_write(d->phy_addr, 24, 0x280); // LED status, active high
|
||||
} else { // Default to LAN8720
|
||||
MG_INFO(("Defaulting to LAN8720 PHY...")); // TODO()
|
||||
}
|
||||
struct mg_phy phy = {raeth_read_phy, raeth_write_phy};
|
||||
mg_phy_init(&phy, d->phy_addr, 0); // MAC clocks PHY
|
||||
|
||||
// Select RMII mode,
|
||||
ETHERC->ECMR = MG_BIT(2) | MG_BIT(1); // 100M, Full-duplex, CRC
|
||||
@ -233,27 +201,17 @@ static size_t mg_tcpip_driver_ra_tx(const void *buf, size_t len,
|
||||
static bool mg_tcpip_driver_ra_up(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_ra_data *d =
|
||||
(struct mg_tcpip_driver_ra_data *) ifp->driver_data;
|
||||
uint32_t bsr = raeth_phy_read(d->phy_addr, MG_PHYREG_BSR);
|
||||
bool up = bsr & MG_BIT(2) ? 1 : 0;
|
||||
uint8_t speed = MG_PHY_SPEED_10M;
|
||||
bool up = false, full_duplex = false;
|
||||
struct mg_phy phy = {raeth_read_phy, raeth_write_phy};
|
||||
up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed);
|
||||
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
|
||||
// tmp = reg with flags set to the most likely situation: 100M full-duplex
|
||||
// if(link is slow or half) set flags otherwise
|
||||
// reg = tmp
|
||||
uint32_t ecmr = ETHERC->ECMR | MG_BIT(2) | MG_BIT(1); // 100M Full-duplex
|
||||
uint32_t phy_id = raeth_phy_id(d->phy_addr);
|
||||
if ((phy_id & 0xffff0000) == 0x220000) { // KSZ8091RNB
|
||||
uint16_t pc1r = raeth_phy_read(d->phy_addr, 30); // Read PC1R
|
||||
if ((pc1r & 3) == 1) ecmr &= ~MG_BIT(2); // 10M
|
||||
if ((pc1r & MG_BIT(2)) == 0) ecmr &= ~MG_BIT(1); // Half-duplex
|
||||
} else if ((phy_id & 0xffff0000) == 0x20000000) { // DP83825I
|
||||
uint16_t physts = raeth_phy_read(d->phy_addr, 16); // Read PHYSTS
|
||||
if (physts & MG_BIT(1)) ecmr &= ~MG_BIT(2); // 10M
|
||||
if ((physts & MG_BIT(2)) == 0) ecmr &= ~MG_BIT(1); // Half-duplex
|
||||
} else { // Default to LAN8720
|
||||
uint16_t scsr = raeth_phy_read(d->phy_addr, 31); // Read CSCR
|
||||
if ((scsr & MG_BIT(3)) == 0) ecmr &= ~MG_BIT(2); // 10M
|
||||
if ((scsr & MG_BIT(4)) == 0) ecmr &= ~MG_BIT(1); // Half-duplex
|
||||
}
|
||||
if (speed == MG_PHY_SPEED_10M) ecmr &= ~MG_BIT(2); // 10M
|
||||
if (full_duplex == false) ecmr &= ~MG_BIT(1); // Half-duplex
|
||||
ETHERC->ECMR = ecmr; // IRQ handler does not fiddle with these registers
|
||||
MG_DEBUG(("Link is %uM %s-duplex", ecmr & MG_BIT(2) ? 100 : 10,
|
||||
ecmr & MG_BIT(1) ? "full" : "half"));
|
||||
|
@ -30,23 +30,16 @@ static uint8_t s_txno; // Current TX descriptor
|
||||
static uint8_t s_rxno; // Current RX descriptor
|
||||
|
||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||
enum {
|
||||
MG_PHYREG_BCR = 0,
|
||||
MG_PHYREG_BSR = 1,
|
||||
MG_PHYREG_ID1 = 2,
|
||||
MG_PHYREG_ID2 = 3,
|
||||
MG_PHYREG_CSCR = 31
|
||||
};
|
||||
|
||||
static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
ETH->MACMIIAR &= (7 << 2);
|
||||
ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6);
|
||||
ETH->MACMIIAR |= MG_BIT(0);
|
||||
while (ETH->MACMIIAR & MG_BIT(0)) (void) 0;
|
||||
return ETH->MACMIIDR;
|
||||
return ETH->MACMIIDR & 0xffff;
|
||||
}
|
||||
|
||||
static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
|
||||
static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
ETH->MACMIIDR = val;
|
||||
ETH->MACMIIAR &= (7 << 2);
|
||||
ETH->MACMIIAR |= ((uint32_t) addr << 11) | ((uint32_t) reg << 6) | MG_BIT(1);
|
||||
@ -144,19 +137,16 @@ static bool mg_tcpip_driver_stm32f_init(struct mg_tcpip_if *ifp) {
|
||||
ETH->MACIMR = MG_BIT(3) | MG_BIT(9); // Mask timestamp & PMT IT
|
||||
ETH->MACFCR = MG_BIT(7); // Disable zero quarta pause
|
||||
// ETH->MACFFR = MG_BIT(31); // Receive all
|
||||
eth_write_phy(phy_addr, MG_PHYREG_BCR, MG_BIT(15)); // Reset PHY
|
||||
eth_write_phy(phy_addr, MG_PHYREG_BCR, MG_BIT(12)); // Set autonegotiation
|
||||
ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
|
||||
ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors
|
||||
ETH->DMAIER = MG_BIT(6) | MG_BIT(16); // RIE, NISE
|
||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||
mg_phy_init(&phy, phy_addr, MG_PHY_CLOCKS_MAC);
|
||||
ETH->DMARDLAR = (uint32_t) (uintptr_t) s_rxdesc; // RX descriptors
|
||||
ETH->DMATDLAR = (uint32_t) (uintptr_t) s_txdesc; // RX descriptors
|
||||
ETH->DMAIER = MG_BIT(6) | MG_BIT(16); // RIE, NISE
|
||||
ETH->MACCR =
|
||||
MG_BIT(2) | MG_BIT(3) | MG_BIT(11) | MG_BIT(14); // RE, TE, Duplex, Fast
|
||||
ETH->DMAOMR =
|
||||
MG_BIT(1) | MG_BIT(13) | MG_BIT(21) | MG_BIT(25); // SR, ST, TSF, RSF
|
||||
|
||||
MG_DEBUG(("PHY ID: %#04hx %#04hx", eth_read_phy(phy_addr, MG_PHYREG_ID1),
|
||||
eth_read_phy(phy_addr, MG_PHYREG_ID2)));
|
||||
|
||||
// MAC address filtering
|
||||
ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4];
|
||||
ETH->MACA0LR = (uint32_t) (ifp->mac[3] << 24) |
|
||||
@ -192,16 +182,17 @@ static bool mg_tcpip_driver_stm32f_up(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_stm32f_data *d =
|
||||
(struct mg_tcpip_driver_stm32f_data *) ifp->driver_data;
|
||||
uint8_t phy_addr = d == NULL ? 0 : d->phy_addr;
|
||||
uint32_t bsr = eth_read_phy(phy_addr, MG_PHYREG_BSR);
|
||||
bool up = bsr & MG_BIT(2) ? 1 : 0;
|
||||
uint8_t speed = MG_PHY_SPEED_10M;
|
||||
bool up = false, full_duplex = false;
|
||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||
up = mg_phy_up(&phy, phy_addr, &full_duplex, &speed);
|
||||
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
|
||||
uint32_t scsr = eth_read_phy(phy_addr, MG_PHYREG_CSCR);
|
||||
// tmp = reg with flags set to the most likely situation: 100M full-duplex
|
||||
// if(link is slow or half) set flags otherwise
|
||||
// reg = tmp
|
||||
uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(11); // 100M, Full-duplex
|
||||
if ((scsr & MG_BIT(3)) == 0) maccr &= ~MG_BIT(14); // 10M
|
||||
if ((scsr & MG_BIT(4)) == 0) maccr &= ~MG_BIT(11); // Half-duplex
|
||||
if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M
|
||||
if (full_duplex == false) maccr &= ~MG_BIT(11); // Half-duplex
|
||||
ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
|
||||
MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10,
|
||||
maccr & MG_BIT(11) ? "full" : "half"));
|
||||
|
@ -34,7 +34,7 @@ struct mg_tcpip_driver_stm32f_data {
|
||||
|
||||
#define MG_TCPIP_DRIVER_DATA \
|
||||
static struct mg_tcpip_driver_stm32f_data driver_data = { \
|
||||
.mdc_cr = MG_DRIVER_MDC_CR, \
|
||||
.mdc_cr = MG_DRIVER_MDC_CR, \
|
||||
.phy_addr = MG_TCPIP_PHY_ADDR, \
|
||||
};
|
||||
|
||||
|
@ -45,22 +45,16 @@ static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]; // TX descriptors
|
||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // RX ethernet buffers
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]; // TX ethernet buffers
|
||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||
enum {
|
||||
MG_PHY_ADDR = 0,
|
||||
MG_PHYREG_BCR = 0,
|
||||
MG_PHYREG_BSR = 1,
|
||||
MG_PHYREG_CSCR = 31
|
||||
}; // PHY constants
|
||||
|
||||
static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
ETH->MACMDIOAR &= (0xF << 8);
|
||||
ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 3 << 2;
|
||||
ETH->MACMDIOAR |= MG_BIT(0);
|
||||
while (ETH->MACMDIOAR & MG_BIT(0)) (void) 0;
|
||||
return ETH->MACMDIODR;
|
||||
return (uint16_t) ETH->MACMDIODR;
|
||||
}
|
||||
|
||||
static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
|
||||
static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) {
|
||||
ETH->MACMDIODR = val;
|
||||
ETH->MACMDIOAR &= (0xF << 8);
|
||||
ETH->MACMDIOAR |= ((uint32_t) addr << 21) | ((uint32_t) reg << 16) | 1 << 2;
|
||||
@ -148,6 +142,8 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_stm32h_data *d =
|
||||
(struct mg_tcpip_driver_stm32h_data *) ifp->driver_data;
|
||||
s_ifp = ifp;
|
||||
uint8_t phy_addr = d == NULL ? 0 : d->phy_addr;
|
||||
uint8_t phy_conf = d == NULL ? MG_PHY_CLOCKS_MAC : d->phy_conf;
|
||||
|
||||
// Init RX descriptors
|
||||
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
||||
@ -174,9 +170,8 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
||||
ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
|
||||
ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause
|
||||
// ETH->MACPFR = MG_BIT(31); // Receive all
|
||||
eth_write_phy(MG_PHY_ADDR, MG_PHYREG_BCR, MG_BIT(15)); // Reset PHY
|
||||
eth_write_phy(MG_PHY_ADDR, MG_PHYREG_BCR,
|
||||
MG_BIT(12)); // Set autonegotiation
|
||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||
mg_phy_init(&phy, phy_addr, phy_conf);
|
||||
ETH->DMACRDLAR =
|
||||
(uint32_t) (uintptr_t) s_rxdesc; // RX descriptors start address
|
||||
ETH->DMACRDRLR = ETH_DESC_CNT - 1; // ring length
|
||||
@ -231,16 +226,20 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
|
||||
}
|
||||
|
||||
static bool mg_tcpip_driver_stm32h_up(struct mg_tcpip_if *ifp) {
|
||||
uint32_t bsr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_BSR);
|
||||
bool up = bsr & MG_BIT(2) ? 1 : 0;
|
||||
struct mg_tcpip_driver_stm32h_data *d =
|
||||
(struct mg_tcpip_driver_stm32h_data *) ifp->driver_data;
|
||||
uint8_t phy_addr = d == NULL ? 0 : d->phy_addr;
|
||||
uint8_t speed = MG_PHY_SPEED_10M;
|
||||
bool up = false, full_duplex = false;
|
||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||
up = mg_phy_up(&phy, phy_addr, &full_duplex, &speed);
|
||||
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
|
||||
uint32_t scsr = eth_read_phy(MG_PHY_ADDR, MG_PHYREG_CSCR);
|
||||
// tmp = reg with flags set to the most likely situation: 100M full-duplex
|
||||
// if(link is slow or half) set flags otherwise
|
||||
// reg = tmp
|
||||
uint32_t maccr = ETH->MACCR | MG_BIT(14) | MG_BIT(13); // 100M, Full-duplex
|
||||
if ((scsr & MG_BIT(3)) == 0) maccr &= ~MG_BIT(14); // 10M
|
||||
if ((scsr & MG_BIT(4)) == 0) maccr &= ~MG_BIT(13); // Half-duplex
|
||||
if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M
|
||||
if (full_duplex == false) maccr &= ~MG_BIT(13); // Half-duplex
|
||||
ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
|
||||
MG_DEBUG(("Link is %uM %s-duplex", maccr & MG_BIT(14) ? 100 : 10,
|
||||
maccr & MG_BIT(13) ? "full" : "half"));
|
||||
|
@ -12,23 +12,31 @@ struct mg_tcpip_driver_stm32h_data {
|
||||
// 100-150 MHz HCLK/62 1
|
||||
// 20-35 MHz HCLK/16 2
|
||||
// 35-60 MHz HCLK/26 3
|
||||
// 150-250 MHz HCLK/102 4 <-- value for Nucleo-H* on max speed driven by HSI
|
||||
// 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on max speed driven by CSI
|
||||
// 110, 111 Reserved
|
||||
// 150-250 MHz HCLK/102 4 <-- value for Nucleo-H* on max speed
|
||||
// driven by HSI 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on
|
||||
// max speed driven by CSI 110, 111 Reserved
|
||||
int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
|
||||
|
||||
uint8_t phy_addr; // PHY address
|
||||
uint8_t phy_conf; // PHY config
|
||||
};
|
||||
|
||||
#ifndef MG_MAC_ADDRESS
|
||||
#define MG_MAC_ADDRESS MG_MAC_ADDRESS_RANDOM
|
||||
#endif
|
||||
|
||||
#ifndef MG_TCPIP_PHY_ADDR
|
||||
#define MG_TCPIP_PHY_ADDR 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_DRIVER_MDC_CR
|
||||
#define MG_DRIVER_MDC_CR 4
|
||||
#endif
|
||||
|
||||
#define MG_TCPIP_DRIVER_DATA \
|
||||
static struct mg_tcpip_driver_stm32h_data driver_data = { \
|
||||
.mdc_cr = MG_DRIVER_MDC_CR, \
|
||||
.mdc_cr = MG_DRIVER_MDC_CR, \
|
||||
.phy_addr = MG_TCPIP_PHY_ADDR, \
|
||||
};
|
||||
|
||||
#define MG_TCPIP_DRIVER_CODE &mg_tcpip_driver_stm32h
|
||||
|
Loading…
x
Reference in New Issue
Block a user