Add support for 10M and half-duplex in STM32 and TM4C drivers

This commit is contained in:
Sergio R. Caprile 2023-02-02 12:00:41 -03:00
parent 961cc13948
commit e3ca006265
3 changed files with 90 additions and 24 deletions

View File

@ -29,7 +29,12 @@ static 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 mip_if *s_ifp; // MIP interface
enum { PHY_ADDR = 0, PHY_BCR = 0, PHY_BSR = 1 }; // PHY constants
enum {
PHY_ADDR = 0,
PHY_BCR = 0,
PHY_BSR = 1,
PHY_CSCR = 31
}; // PHY constants
static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
ETH->MACMIIAR &= (7 << 2);
@ -102,7 +107,8 @@ static int guess_mdc_cr(void) {
}
static bool mip_driver_stm32_init(struct mip_if *ifp) {
struct mip_driver_stm32_data *d = (struct mip_driver_stm32_data *) ifp->driver_data;
struct mip_driver_stm32_data *d =
(struct mip_driver_stm32_data *) ifp->driver_data;
s_ifp = ifp;
// Init RX descriptors
@ -152,7 +158,8 @@ static bool mip_driver_stm32_init(struct mip_if *ifp) {
}
static uint32_t s_txno;
static size_t mip_driver_stm32_tx(const void *buf, size_t len, struct mip_if *ifp) {
static size_t mip_driver_stm32_tx(const void *buf, size_t len,
struct mip_if *ifp) {
if (len > sizeof(s_txbuf[s_txno])) {
MG_ERROR(("Frame too big, %ld", (long) len));
len = 0; // Frame is too big
@ -175,8 +182,17 @@ static size_t mip_driver_stm32_tx(const void *buf, size_t len, struct mip_if *if
static bool mip_driver_stm32_up(struct mip_if *ifp) {
uint32_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
(void) ifp;
return bsr & BIT(2) ? 1 : 0;
bool up = bsr & BIT(2) ? 1 : 0;
if ((ifp->state == MIP_STATE_DOWN) && up) { // link state just went up
uint32_t scsr = eth_read_phy(PHY_ADDR, PHY_CSCR);
uint32_t maccr = ETH->MACCR | BIT(14) | BIT(11); // 100M, Full-duplex
if ((scsr & BIT(3)) == 0) maccr &= ~BIT(14); // 10M
if ((scsr & BIT(4)) == 0) maccr &= ~BIT(11); // Half-duplex
ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
MG_DEBUG(("Link is %uM %s-duplex", maccr & BIT(14) ? 100 : 10,
maccr & BIT(11) ? "full" : "half"));
}
return up;
}
void ETH_IRQHandler(void);
@ -202,6 +218,7 @@ void ETH_IRQHandler(void) {
ETH->DMARPDR = 0; // and resume RX
}
struct mip_driver mip_driver_stm32 = {
mip_driver_stm32_init, mip_driver_stm32_tx, mip_driver_rx, mip_driver_stm32_up};
struct mip_driver mip_driver_stm32 = {mip_driver_stm32_init,
mip_driver_stm32_tx, mip_driver_rx,
mip_driver_stm32_up};
#endif

View File

@ -35,7 +35,12 @@ static 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 mip_if *s_ifp; // MIP interface
enum { EPHY_ADDR = 0, EPHYBMCR = 0, EPHYBMSR = 1 }; // PHY constants
enum {
EPHY_ADDR = 0,
EPHYBMCR = 0,
EPHYBMSR = 1,
EPHYSTS = 16
}; // PHY constants
static inline void tm4cspin(volatile uint32_t count) {
while (count--) (void) 0;
@ -124,7 +129,8 @@ static int guess_mdc_cr(void) {
}
static bool mip_driver_tm4c_init(struct mip_if *ifp) {
struct mip_driver_tm4c_data *d = (struct mip_driver_tm4c_data *) ifp->driver_data;
struct mip_driver_tm4c_data *d =
(struct mip_driver_tm4c_data *) ifp->driver_data;
s_ifp = ifp;
// Init RX descriptors
@ -178,7 +184,8 @@ static bool mip_driver_tm4c_init(struct mip_if *ifp) {
}
static uint32_t s_txno;
static size_t mip_driver_tm4c_tx(const void *buf, size_t len, struct mip_if *ifp) {
static size_t mip_driver_tm4c_tx(const void *buf, size_t len,
struct mip_if *ifp) {
if (len > sizeof(s_txbuf[s_txno])) {
MG_ERROR(("Frame too big, %ld", (long) len));
len = 0; // fail
@ -203,8 +210,17 @@ static size_t mip_driver_tm4c_tx(const void *buf, size_t len, struct mip_if *ifp
static bool mip_driver_tm4c_up(struct mip_if *ifp) {
uint32_t bmsr = emac_read_phy(EPHY_ADDR, EPHYBMSR);
(void) ifp;
return (bmsr & BIT(2)) ? 1 : 0;
bool up = (bmsr & BIT(2)) ? 1 : 0;
if ((ifp->state == MIP_STATE_DOWN) && up) { // link state just went up
uint32_t sts = emac_read_phy(EPHY_ADDR, EPHYSTS);
uint32_t emaccfg = EMAC->EMACCFG | BIT(14) | BIT(11); // 100M, Full-duplex
if (sts & BIT(1)) emaccfg &= ~BIT(14); // 10M
if ((sts & BIT(2)) == 0) emaccfg &= ~BIT(11); // Half-duplex
EMAC->EMACCFG = emaccfg; // IRQ handler does not fiddle with this register
MG_DEBUG(("Link is %uM %s-duplex", emaccfg & BIT(14) ? 100 : 10,
emaccfg & BIT(11) ? "full" : "half"));
}
return up;
}
void EMAC0_IRQHandler(void);

View File

@ -5988,7 +5988,12 @@ static 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 mip_if *s_ifp; // MIP interface
enum { PHY_ADDR = 0, PHY_BCR = 0, PHY_BSR = 1 }; // PHY constants
enum {
PHY_ADDR = 0,
PHY_BCR = 0,
PHY_BSR = 1,
PHY_CSCR = 31
}; // PHY constants
static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
ETH->MACMIIAR &= (7 << 2);
@ -6061,7 +6066,8 @@ static int guess_mdc_cr(void) {
}
static bool mip_driver_stm32_init(struct mip_if *ifp) {
struct mip_driver_stm32_data *d = (struct mip_driver_stm32_data *) ifp->driver_data;
struct mip_driver_stm32_data *d =
(struct mip_driver_stm32_data *) ifp->driver_data;
s_ifp = ifp;
// Init RX descriptors
@ -6111,7 +6117,8 @@ static bool mip_driver_stm32_init(struct mip_if *ifp) {
}
static uint32_t s_txno;
static size_t mip_driver_stm32_tx(const void *buf, size_t len, struct mip_if *ifp) {
static size_t mip_driver_stm32_tx(const void *buf, size_t len,
struct mip_if *ifp) {
if (len > sizeof(s_txbuf[s_txno])) {
MG_ERROR(("Frame too big, %ld", (long) len));
len = 0; // Frame is too big
@ -6134,8 +6141,17 @@ static size_t mip_driver_stm32_tx(const void *buf, size_t len, struct mip_if *if
static bool mip_driver_stm32_up(struct mip_if *ifp) {
uint32_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
(void) ifp;
return bsr & BIT(2) ? 1 : 0;
bool up = bsr & BIT(2) ? 1 : 0;
if ((ifp->state == MIP_STATE_DOWN) && up) { // link state just went up
uint32_t scsr = eth_read_phy(PHY_ADDR, PHY_CSCR);
uint32_t maccr = ETH->MACCR | BIT(14) | BIT(11); // 100M, Full-duplex
if ((scsr & BIT(3)) == 0) maccr &= ~BIT(14); // 10M
if ((scsr & BIT(4)) == 0) maccr &= ~BIT(11); // Half-duplex
ETH->MACCR = maccr; // IRQ handler does not fiddle with this register
MG_DEBUG(("Link is %uM %s-duplex", maccr & BIT(14) ? 100 : 10,
maccr & BIT(11) ? "full" : "half"));
}
return up;
}
void ETH_IRQHandler(void);
@ -6161,8 +6177,9 @@ void ETH_IRQHandler(void) {
ETH->DMARPDR = 0; // and resume RX
}
struct mip_driver mip_driver_stm32 = {
mip_driver_stm32_init, mip_driver_stm32_tx, mip_driver_rx, mip_driver_stm32_up};
struct mip_driver mip_driver_stm32 = {mip_driver_stm32_init,
mip_driver_stm32_tx, mip_driver_rx,
mip_driver_stm32_up};
#endif
#ifdef MG_ENABLE_LINES
@ -6205,7 +6222,12 @@ static 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 mip_if *s_ifp; // MIP interface
enum { EPHY_ADDR = 0, EPHYBMCR = 0, EPHYBMSR = 1 }; // PHY constants
enum {
EPHY_ADDR = 0,
EPHYBMCR = 0,
EPHYBMSR = 1,
EPHYSTS = 16
}; // PHY constants
static inline void tm4cspin(volatile uint32_t count) {
while (count--) (void) 0;
@ -6294,7 +6316,8 @@ static int guess_mdc_cr(void) {
}
static bool mip_driver_tm4c_init(struct mip_if *ifp) {
struct mip_driver_tm4c_data *d = (struct mip_driver_tm4c_data *) ifp->driver_data;
struct mip_driver_tm4c_data *d =
(struct mip_driver_tm4c_data *) ifp->driver_data;
s_ifp = ifp;
// Init RX descriptors
@ -6348,7 +6371,8 @@ static bool mip_driver_tm4c_init(struct mip_if *ifp) {
}
static uint32_t s_txno;
static size_t mip_driver_tm4c_tx(const void *buf, size_t len, struct mip_if *ifp) {
static size_t mip_driver_tm4c_tx(const void *buf, size_t len,
struct mip_if *ifp) {
if (len > sizeof(s_txbuf[s_txno])) {
MG_ERROR(("Frame too big, %ld", (long) len));
len = 0; // fail
@ -6373,8 +6397,17 @@ static size_t mip_driver_tm4c_tx(const void *buf, size_t len, struct mip_if *ifp
static bool mip_driver_tm4c_up(struct mip_if *ifp) {
uint32_t bmsr = emac_read_phy(EPHY_ADDR, EPHYBMSR);
(void) ifp;
return (bmsr & BIT(2)) ? 1 : 0;
bool up = (bmsr & BIT(2)) ? 1 : 0;
if ((ifp->state == MIP_STATE_DOWN) && up) { // link state just went up
uint32_t sts = emac_read_phy(EPHY_ADDR, EPHYSTS);
uint32_t emaccfg = EMAC->EMACCFG | BIT(14) | BIT(11); // 100M, Full-duplex
if (sts & BIT(1)) emaccfg &= ~BIT(14); // 10M
if ((sts & BIT(2)) == 0) emaccfg &= ~BIT(11); // Half-duplex
EMAC->EMACCFG = emaccfg; // IRQ handler does not fiddle with this register
MG_DEBUG(("Link is %uM %s-duplex", emaccfg & BIT(14) ? 100 : 10,
emaccfg & BIT(11) ? "full" : "half"));
}
return up;
}
void EMAC0_IRQHandler(void);