Skip to content

Commit

Permalink
Split PHY code into phy.{c,h}
Browse files Browse the repository at this point in the history
  • Loading branch information
cpq committed Mar 14, 2024
1 parent 98782e4 commit 14ad3b4
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 42 deletions.
87 changes: 70 additions & 17 deletions mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -14670,6 +14670,62 @@ 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 {
MG_PHY_KSZ8x = 0x22,
MG_PHY_DP83x = 0x2000,
MG_PHY_LAN87x = 0x7,
};

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,
};

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";
}
}

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)));

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

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
}
}

void mg_phy_status(struct mg_phy *phy, bool *up, bool *full_duplex,
uint8_t *speed) {
uint16_t bsr = phy->read_reg(phy->addr, MG_PHY_REG_BSR);
*up = bsr & MG_BIT(2);
if (*up) {
uint16_t scsr = phy->read_reg(phy->addr, MG_PHY_REG_CSCR);
*full_duplex = scsr & (1U << 4U);
*speed = scsr & MG_BIT(3) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
}
}

#ifdef MG_ENABLE_LINES
#line 1 "src/drivers/ra.c"
#endif
Expand Down Expand Up @@ -15228,15 +15284,15 @@ enum {
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);
Expand Down Expand Up @@ -15334,11 +15390,11 @@ 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 = {d->phy_addr, eth_read_phy, eth_write_phy};
mg_phy_init(&phy);
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 =
Expand Down Expand Up @@ -15381,17 +15437,14 @@ static size_t mg_tcpip_driver_stm32f_tx(const void *buf, size_t len,
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 = {d->phy_addr, eth_read_phy, eth_write_phy};
mg_phy_status(&phy, &up, &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"));
Expand Down
23 changes: 15 additions & 8 deletions mongoose.h
Original file line number Diff line number Diff line change
Expand Up @@ -2937,6 +2937,21 @@ struct mg_tcpip_driver_imxrt_data {
#endif




struct mg_phy {
uint8_t addr;
uint16_t (*read_reg)(uint8_t addr, uint8_t reg);
void (*write_reg)(uint8_t addr, uint8_t reg, uint16_t value);
};

enum { MG_PHY_SPEED_10M, MG_PHY_SPEED_100M, MG_PHY_SPEED_1000M };

void mg_phy_init(struct mg_phy *);
void mg_phy_status(struct mg_phy *, bool *up, 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 {
Expand Down Expand Up @@ -3116,14 +3131,6 @@ struct mg_tcpip_driver_tm4c_data {
#define MG_TCPIP_DRIVER_NAME "tm4c"


#endif


#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5500) && MG_ENABLE_DRIVER_W5500

#undef MG_ENABLE_TCPIP_DRIVER_INIT
#define MG_ENABLE_TCPIP_DRIVER_INIT 0

#endif

#ifdef __cplusplus
Expand Down
52 changes: 52 additions & 0 deletions src/drivers/phy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "phy.h"

enum {
MG_PHY_KSZ8x = 0x22,
MG_PHY_DP83x = 0x2000,
MG_PHY_LAN87x = 0x7,
};

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,
};

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";
}
}

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)));

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

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
}
}

void mg_phy_status(struct mg_phy *phy, bool *up, bool *full_duplex,
uint8_t *speed) {
uint16_t bsr = phy->read_reg(phy->addr, MG_PHY_REG_BSR);
*up = bsr & MG_BIT(2);
if (*up) {
uint16_t scsr = phy->read_reg(phy->addr, MG_PHY_REG_CSCR);
*full_duplex = scsr & (1U << 4U);
*speed = scsr & MG_BIT(3) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
}
}
15 changes: 15 additions & 0 deletions src/drivers/phy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "net_builtin.h"

struct mg_phy {
uint8_t addr;
uint16_t (*read_reg)(uint8_t addr, uint8_t reg);
void (*write_reg)(uint8_t addr, uint8_t reg, uint16_t value);
};

enum { MG_PHY_SPEED_10M, MG_PHY_SPEED_100M, MG_PHY_SPEED_1000M };

void mg_phy_init(struct mg_phy *);
void mg_phy_status(struct mg_phy *, bool *up, bool *full_duplex,
uint8_t *speed);
31 changes: 14 additions & 17 deletions src/drivers/stm32f.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ enum {
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);
Expand Down Expand Up @@ -144,11 +144,11 @@ 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 = {d->phy_addr, eth_read_phy, eth_write_phy};
mg_phy_init(&phy);
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 =
Expand Down Expand Up @@ -191,17 +191,14 @@ static size_t mg_tcpip_driver_stm32f_tx(const void *buf, size_t len,
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 = {d->phy_addr, eth_read_phy, eth_write_phy};
mg_phy_status(&phy, &up, &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"));
Expand Down

0 comments on commit 14ad3b4

Please sign in to comment.