diff --git a/mongoose.c b/mongoose.c index 34966698..9e478a1b 100644 --- a/mongoose.c +++ b/mongoose.c @@ -16511,9 +16511,11 @@ struct mg_tcpip_driver mg_tcpip_driver_stm32f = { #endif -#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \ - MG_ENABLE_DRIVER_STM32H -struct stm32h_eth { +#if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN) +// STM32H: vendor modded single-queue Synopsys v4.2 +// MCXNx4x: dual-queue Synopsys v5.2 +// RT1170 ENET_QOS: quad-queue Synopsys v5.1 +struct synopsys_enet_qos { volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R, RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR, RESERVED4[2], MACTFCR, RESERVED5[7], MACRFCR, RESERVED6[7], MACISR, @@ -16544,8 +16546,13 @@ struct stm32h_eth { DMACMFCR; }; #undef ETH -#define ETH \ - ((struct stm32h_eth *) (uintptr_t) (0x40000000UL + 0x00020000UL + 0x8000UL)) +#if MG_ENABLE_DRIVER_STM32H +#define ETH \ + ((struct synopsys_enet_qos *) (uintptr_t) (0x40000000UL + 0x00020000UL + \ + 0x8000UL)) +#elif MG_ENABLE_DRIVER_MCXN +#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL) +#endif #define ETH_PKT_SIZE 1540 // Max frame size #define ETH_DESC_CNT 4 // Descriptors count @@ -16573,82 +16580,6 @@ static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { while (ETH->MACMDIOAR & MG_BIT(0)) (void) 0; } -static uint32_t get_hclk(void) { - struct rcc { - volatile uint32_t CR, HSICFGR, CRRCR, CSICFGR, CFGR, RESERVED1, D1CFGR, - D2CFGR, D3CFGR, RESERVED2, PLLCKSELR, PLLCFGR, PLL1DIVR, PLL1FRACR, - PLL2DIVR, PLL2FRACR, PLL3DIVR, PLL3FRACR, RESERVED3, D1CCIPR, D2CCIP1R, - D2CCIP2R, D3CCIPR, RESERVED4, CIER, CIFR, CICR, RESERVED5, BDCR, CSR, - RESERVED6, AHB3RSTR, AHB1RSTR, AHB2RSTR, AHB4RSTR, APB3RSTR, APB1LRSTR, - APB1HRSTR, APB2RSTR, APB4RSTR, GCR, RESERVED8, D3AMR, RESERVED11[9], - RSR, AHB3ENR, AHB1ENR, AHB2ENR, AHB4ENR, APB3ENR, APB1LENR, APB1HENR, - APB2ENR, APB4ENR, RESERVED12, AHB3LPENR, AHB1LPENR, AHB2LPENR, - AHB4LPENR, APB3LPENR, APB1LLPENR, APB1HLPENR, APB2LPENR, APB4LPENR, - RESERVED13[4]; - } *rcc = ((struct rcc *) (0x40000000 + 0x18020000 + 0x4400)); - uint32_t clk = 0, hsi = 64000000 /* 64 MHz */, hse = 8000000 /* 8MHz */, - csi = 4000000 /* 4MHz */; - unsigned int sel = (rcc->CFGR & (7 << 3)) >> 3; - - if (sel == 1) { - clk = csi; - } else if (sel == 2) { - clk = hse; - } else if (sel == 3) { - uint32_t vco, m, n, p; - unsigned int src = (rcc->PLLCKSELR & (3 << 0)) >> 0; - m = ((rcc->PLLCKSELR & (0x3F << 4)) >> 4); - n = ((rcc->PLL1DIVR & (0x1FF << 0)) >> 0) + 1 + - ((rcc->PLLCFGR & MG_BIT(0)) ? 1 : 0); // round-up in fractional mode - p = ((rcc->PLL1DIVR & (0x7F << 9)) >> 9) + 1; - if (src == 1) { - clk = csi; - } else if (src == 2) { - clk = hse; - } else { - clk = hsi; - clk >>= ((rcc->CR & 3) >> 3); - } - vco = (uint32_t) ((uint64_t) clk * n / m); - clk = vco / p; - } else { - clk = hsi; - clk >>= ((rcc->CR & 3) >> 3); - } - const uint8_t cptab[12] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div) - uint32_t d1cpre = (rcc->D1CFGR & (0x0F << 8)) >> 8; - if (d1cpre >= 8) clk >>= cptab[d1cpre - 8]; - MG_DEBUG(("D1 CLK: %u", clk)); - uint32_t hpre = (rcc->D1CFGR & (0x0F << 0)) >> 0; - if (hpre < 8) return clk; - return ((uint32_t) clk) >> cptab[hpre - 8]; -} - -// Guess CR from AHB1 clock. MDC clock is generated from the ETH peripheral -// clock (AHB1); as per 802.3, it must not exceed 2. As the AHB clock can -// be derived from HSI or CSI (internal RC) clocks, and those can go above -// specs, the datasheets specify a range of frequencies and activate one of a -// series of dividers to keep the MDC clock safely below 2.5MHz. We guess a -// divider setting based on HCLK with some drift. If the user uses a different -// clock from our defaults, needs to set the macros on top. Valid for -// STM32H74xxx/75xxx (58.11.4)(4.5% worst case drift)(CSI clock has a 7.5 % -// worst case drift @ max temp) -static int guess_mdc_cr(void) { - const uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMDIOAR::CR values - const uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers - uint32_t hclk = get_hclk(); // Guess system HCLK - int result = -1; // Invalid CR value - for (int i = 0; i < 6; i++) { - if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { - result = crs[i]; - break; - } - } - if (result < 0) MG_ERROR(("HCLK too high")); - MG_DEBUG(("HCLK: %u, CR: %d", hclk, result)); - return result; -} - 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; @@ -16667,11 +16598,13 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer } - ETH->DMAMR |= MG_BIT(0); // Software reset + ETH->DMAMR |= MG_BIT(0); // Software reset + for (int i = 0; i < 4; i++) + (void) 0; // wait at least 4 clocks before reading while ((ETH->DMAMR & MG_BIT(0)) != 0) (void) 0; // Wait until done - // Set MDC clock divider. If user told us the value, use it. Otherwise, guess - int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr; + // Set MDC clock divider. Get user value, else, assume max freq + int cr = (d == NULL || d->mdc_cr < 0) ? 7 : d->mdc_cr; ETH->MACMDIOAR = ((uint32_t) cr & 0xF) << 8; // NOTE(scaprile): We do not use timing facilities so the DMA engine does not @@ -16695,13 +16628,23 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { ETH->DMACTDTPR = (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value) +#if !MG_ENABLE_DRIVER_STM32H + MG_SET_BITS(ETH->DMACTCR, 0x3F << 16, MG_BIT(16)); + MG_SET_BITS(ETH->DMACRCR, 0x3F << 16, MG_BIT(16)); +#endif ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) | - MG_BIT(15); // RE, TE, Duplex, Fast, Reserved + MG_BIT(15); // RE, TE, Duplex, Fast, Reserved +#if MG_ENABLE_DRIVER_STM32H ETH->MTLTQOMR |= MG_BIT(1); // TSF ETH->MTLRQOMR |= MG_BIT(5); // RSF - ETH->DMACTCR |= MG_BIT(0); // ST - ETH->DMACRCR |= MG_BIT(0); // SR +#else + ETH->MTLTQOMR |= (7 << 16) | MG_BIT(3) | MG_BIT(1); // 2KB Q0, TSF + ETH->MTLRQOMR |= (7 << 20) | MG_BIT(5); // 2KB Q, RSF + MG_SET_BITS(ETH->RESERVED6[3], 3, 2); // Enable RxQ0 (MAC_RXQ_CTRL0) +#endif + ETH->DMACTCR |= MG_BIT(0); // ST + ETH->DMACRCR |= MG_BIT(0); // SR // MAC address filtering ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; @@ -16758,9 +16701,14 @@ static bool mg_tcpip_driver_stm32h_up(struct mg_tcpip_if *ifp) { return up; } -void ETH_IRQHandler(void); static uint32_t s_rxno; +#if MG_ENABLE_DRIVER_MCXN +void ETHERNET_IRQHandler(void); +void ETHERNET_IRQHandler(void) { +#else +void ETH_IRQHandler(void); void ETH_IRQHandler(void) { +#endif if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever diff --git a/mongoose.h b/mongoose.h index 3a439a6e..10f04be5 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2848,8 +2848,14 @@ struct mg_tcpip_driver_stm32f_data { #endif -#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \ - MG_ENABLE_DRIVER_STM32H +#if MG_ENABLE_TCPIP +#if !defined(MG_ENABLE_DRIVER_STM32H) +#define MG_ENABLE_DRIVER_STM32H 0 +#endif +#if !defined(MG_ENABLE_DRIVER_MCXN) +#define MG_ENABLE_DRIVER_MCXN 0 +#endif +#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN struct mg_tcpip_driver_stm32h_data { // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz @@ -2862,7 +2868,8 @@ struct mg_tcpip_driver_stm32h_data { // 35-60 MHz HCLK/26 3 // 150-250 MHz HCLK/102 4 <-- value for max speed HSI // 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on CSI - // 110, 111 Reserved + // 300-500 MHz HCLK/204 6 + // 500-800 MHz HCLK/324 7 int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 uint8_t phy_addr; // PHY address @@ -2894,6 +2901,7 @@ struct mg_tcpip_driver_stm32h_data { } while (0) #endif +#endif #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_TM4C) && MG_ENABLE_DRIVER_TM4C diff --git a/src/drivers/stm32h.c b/src/drivers/stm32h.c index 7a7e8445..0840bf7c 100644 --- a/src/drivers/stm32h.c +++ b/src/drivers/stm32h.c @@ -1,8 +1,10 @@ #include "net_builtin.h" -#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \ - MG_ENABLE_DRIVER_STM32H -struct stm32h_eth { +#if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN) +// STM32H: vendor modded single-queue Synopsys v4.2 +// MCXNx4x: dual-queue Synopsys v5.2 +// RT1170 ENET_QOS: quad-queue Synopsys v5.1 +struct synopsys_enet_qos { volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R, RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR, RESERVED4[2], MACTFCR, RESERVED5[7], MACRFCR, RESERVED6[7], MACISR, @@ -33,8 +35,13 @@ struct stm32h_eth { DMACMFCR; }; #undef ETH -#define ETH \ - ((struct stm32h_eth *) (uintptr_t) (0x40000000UL + 0x00020000UL + 0x8000UL)) +#if MG_ENABLE_DRIVER_STM32H +#define ETH \ + ((struct synopsys_enet_qos *) (uintptr_t) (0x40000000UL + 0x00020000UL + \ + 0x8000UL)) +#elif MG_ENABLE_DRIVER_MCXN +#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40100000UL) +#endif #define ETH_PKT_SIZE 1540 // Max frame size #define ETH_DESC_CNT 4 // Descriptors count @@ -62,82 +69,6 @@ static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { while (ETH->MACMDIOAR & MG_BIT(0)) (void) 0; } -static uint32_t get_hclk(void) { - struct rcc { - volatile uint32_t CR, HSICFGR, CRRCR, CSICFGR, CFGR, RESERVED1, D1CFGR, - D2CFGR, D3CFGR, RESERVED2, PLLCKSELR, PLLCFGR, PLL1DIVR, PLL1FRACR, - PLL2DIVR, PLL2FRACR, PLL3DIVR, PLL3FRACR, RESERVED3, D1CCIPR, D2CCIP1R, - D2CCIP2R, D3CCIPR, RESERVED4, CIER, CIFR, CICR, RESERVED5, BDCR, CSR, - RESERVED6, AHB3RSTR, AHB1RSTR, AHB2RSTR, AHB4RSTR, APB3RSTR, APB1LRSTR, - APB1HRSTR, APB2RSTR, APB4RSTR, GCR, RESERVED8, D3AMR, RESERVED11[9], - RSR, AHB3ENR, AHB1ENR, AHB2ENR, AHB4ENR, APB3ENR, APB1LENR, APB1HENR, - APB2ENR, APB4ENR, RESERVED12, AHB3LPENR, AHB1LPENR, AHB2LPENR, - AHB4LPENR, APB3LPENR, APB1LLPENR, APB1HLPENR, APB2LPENR, APB4LPENR, - RESERVED13[4]; - } *rcc = ((struct rcc *) (0x40000000 + 0x18020000 + 0x4400)); - uint32_t clk = 0, hsi = 64000000 /* 64 MHz */, hse = 8000000 /* 8MHz */, - csi = 4000000 /* 4MHz */; - unsigned int sel = (rcc->CFGR & (7 << 3)) >> 3; - - if (sel == 1) { - clk = csi; - } else if (sel == 2) { - clk = hse; - } else if (sel == 3) { - uint32_t vco, m, n, p; - unsigned int src = (rcc->PLLCKSELR & (3 << 0)) >> 0; - m = ((rcc->PLLCKSELR & (0x3F << 4)) >> 4); - n = ((rcc->PLL1DIVR & (0x1FF << 0)) >> 0) + 1 + - ((rcc->PLLCFGR & MG_BIT(0)) ? 1 : 0); // round-up in fractional mode - p = ((rcc->PLL1DIVR & (0x7F << 9)) >> 9) + 1; - if (src == 1) { - clk = csi; - } else if (src == 2) { - clk = hse; - } else { - clk = hsi; - clk >>= ((rcc->CR & 3) >> 3); - } - vco = (uint32_t) ((uint64_t) clk * n / m); - clk = vco / p; - } else { - clk = hsi; - clk >>= ((rcc->CR & 3) >> 3); - } - const uint8_t cptab[12] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div) - uint32_t d1cpre = (rcc->D1CFGR & (0x0F << 8)) >> 8; - if (d1cpre >= 8) clk >>= cptab[d1cpre - 8]; - MG_DEBUG(("D1 CLK: %u", clk)); - uint32_t hpre = (rcc->D1CFGR & (0x0F << 0)) >> 0; - if (hpre < 8) return clk; - return ((uint32_t) clk) >> cptab[hpre - 8]; -} - -// Guess CR from AHB1 clock. MDC clock is generated from the ETH peripheral -// clock (AHB1); as per 802.3, it must not exceed 2. As the AHB clock can -// be derived from HSI or CSI (internal RC) clocks, and those can go above -// specs, the datasheets specify a range of frequencies and activate one of a -// series of dividers to keep the MDC clock safely below 2.5MHz. We guess a -// divider setting based on HCLK with some drift. If the user uses a different -// clock from our defaults, needs to set the macros on top. Valid for -// STM32H74xxx/75xxx (58.11.4)(4.5% worst case drift)(CSI clock has a 7.5 % -// worst case drift @ max temp) -static int guess_mdc_cr(void) { - const uint8_t crs[] = {2, 3, 0, 1, 4, 5}; // ETH->MACMDIOAR::CR values - const uint8_t div[] = {16, 26, 42, 62, 102, 124}; // Respective HCLK dividers - uint32_t hclk = get_hclk(); // Guess system HCLK - int result = -1; // Invalid CR value - for (int i = 0; i < 6; i++) { - if (hclk / div[i] <= 2375000UL /* 2.5MHz - 5% */) { - result = crs[i]; - break; - } - } - if (result < 0) MG_ERROR(("HCLK too high")); - MG_DEBUG(("HCLK: %u, CR: %d", hclk, result)); - return result; -} - 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; @@ -156,11 +87,13 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer } - ETH->DMAMR |= MG_BIT(0); // Software reset + ETH->DMAMR |= MG_BIT(0); // Software reset + for (int i = 0; i < 4; i++) + (void) 0; // wait at least 4 clocks before reading while ((ETH->DMAMR & MG_BIT(0)) != 0) (void) 0; // Wait until done - // Set MDC clock divider. If user told us the value, use it. Otherwise, guess - int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr; + // Set MDC clock divider. Get user value, else, assume max freq + int cr = (d == NULL || d->mdc_cr < 0) ? 7 : d->mdc_cr; ETH->MACMDIOAR = ((uint32_t) cr & 0xF) << 8; // NOTE(scaprile): We do not use timing facilities so the DMA engine does not @@ -184,13 +117,23 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) { ETH->DMACTDTPR = (uint32_t) (uintptr_t) s_txdesc; // first available descriptor address ETH->DMACCR = 0; // DSL = 0 (contiguous descriptor table) (reset value) +#if !MG_ENABLE_DRIVER_STM32H + MG_SET_BITS(ETH->DMACTCR, 0x3F << 16, MG_BIT(16)); + MG_SET_BITS(ETH->DMACRCR, 0x3F << 16, MG_BIT(16)); +#endif ETH->DMACIER = MG_BIT(6) | MG_BIT(15); // RIE, NIE ETH->MACCR = MG_BIT(0) | MG_BIT(1) | MG_BIT(13) | MG_BIT(14) | - MG_BIT(15); // RE, TE, Duplex, Fast, Reserved + MG_BIT(15); // RE, TE, Duplex, Fast, Reserved +#if MG_ENABLE_DRIVER_STM32H ETH->MTLTQOMR |= MG_BIT(1); // TSF ETH->MTLRQOMR |= MG_BIT(5); // RSF - ETH->DMACTCR |= MG_BIT(0); // ST - ETH->DMACRCR |= MG_BIT(0); // SR +#else + ETH->MTLTQOMR |= (7 << 16) | MG_BIT(3) | MG_BIT(1); // 2KB Q0, TSF + ETH->MTLRQOMR |= (7 << 20) | MG_BIT(5); // 2KB Q, RSF + MG_SET_BITS(ETH->RESERVED6[3], 3, 2); // Enable RxQ0 (MAC_RXQ_CTRL0) +#endif + ETH->DMACTCR |= MG_BIT(0); // ST + ETH->DMACRCR |= MG_BIT(0); // SR // MAC address filtering ETH->MACA0HR = ((uint32_t) ifp->mac[5] << 8U) | ifp->mac[4]; @@ -247,9 +190,14 @@ static bool mg_tcpip_driver_stm32h_up(struct mg_tcpip_if *ifp) { return up; } -void ETH_IRQHandler(void); static uint32_t s_rxno; +#if MG_ENABLE_DRIVER_MCXN +void ETHERNET_IRQHandler(void); +void ETHERNET_IRQHandler(void) { +#else +void ETH_IRQHandler(void); void ETH_IRQHandler(void) { +#endif if (ETH->DMACSR & MG_BIT(6)) { // Frame received, loop ETH->DMACSR = MG_BIT(15) | MG_BIT(6); // Clear flag for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever diff --git a/src/drivers/stm32h.h b/src/drivers/stm32h.h index e02c1db3..6fa3285c 100644 --- a/src/drivers/stm32h.h +++ b/src/drivers/stm32h.h @@ -1,7 +1,13 @@ #pragma once -#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_STM32H) && \ - MG_ENABLE_DRIVER_STM32H +#if MG_ENABLE_TCPIP +#if !defined(MG_ENABLE_DRIVER_STM32H) +#define MG_ENABLE_DRIVER_STM32H 0 +#endif +#if !defined(MG_ENABLE_DRIVER_MCXN) +#define MG_ENABLE_DRIVER_MCXN 0 +#endif +#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN struct mg_tcpip_driver_stm32h_data { // MDC clock divider. MDC clock is derived from HCLK, must not exceed 2.5MHz @@ -14,7 +20,8 @@ struct mg_tcpip_driver_stm32h_data { // 35-60 MHz HCLK/26 3 // 150-250 MHz HCLK/102 4 <-- value for max speed HSI // 250-300 MHz HCLK/124 5 <-- value for Nucleo-H* on CSI - // 110, 111 Reserved + // 300-500 MHz HCLK/204 6 + // 500-800 MHz HCLK/324 7 int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 uint8_t phy_addr; // PHY address @@ -46,3 +53,4 @@ struct mg_tcpip_driver_stm32h_data { } while (0) #endif +#endif