From e3ca006265aa7f1dc0e355818bd3184cb9ba38ec Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Thu, 2 Feb 2023 12:00:41 -0300 Subject: [PATCH] Add support for 10M and half-duplex in STM32 and TM4C drivers --- mip/driver_stm32.c | 31 +++++++++++++++++++------ mip/driver_tm4c.c | 26 +++++++++++++++++---- mongoose.c | 57 ++++++++++++++++++++++++++++++++++++---------- 3 files changed, 90 insertions(+), 24 deletions(-) diff --git a/mip/driver_stm32.c b/mip/driver_stm32.c index 73d5d288..f722d498 100644 --- a/mip/driver_stm32.c +++ b/mip/driver_stm32.c @@ -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 diff --git a/mip/driver_tm4c.c b/mip/driver_tm4c.c index cf2eec99..1b06bbd2 100644 --- a/mip/driver_tm4c.c +++ b/mip/driver_tm4c.c @@ -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); diff --git a/mongoose.c b/mongoose.c index 392b2acc..f7d21e28 100644 --- a/mongoose.c +++ b/mongoose.c @@ -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);