mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-15 10:29:47 +00:00
Merge pull request #3405 from cesanta/cache7
Synopsys driver handles STM32H7 and N6 DCACHE
This commit is contained in:
2 files changed
+218
-44
No files matched your search
+109
-22
@@ -25748,8 +25748,26 @@ struct mg_tcpip_driver mg_tcpip_driver_stm32f = {
|
||||
#if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || \
|
||||
MG_ENABLE_DRIVER_STM32N)
|
||||
// STM32H: vendor modded single-queue Synopsys v4.2
|
||||
// STM32N, MCXNx4x: dual-queue Synopsys v5.2 with no hash table option
|
||||
// RT1170 ENET_QOS: quad-queue Synopsys v5.1
|
||||
// STM32N: dual-queue GbE Synopsys v5.2 with no hash table option, 64-bit AXI
|
||||
// MCXNx4x: dual-queue Synopsys v5.2 with no hash table option
|
||||
// RT1170: ENET_QOS: quad-queue Synopsys v5.1
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
#define SYNOPSYS_ENET_V5 0
|
||||
#define SYNOPSYS_ENET_SINGLEQ 1
|
||||
#define SYNOPSYS_ENET_NOHASHTABLE 0
|
||||
#define SYNOPSYS_ENET_GbE 0
|
||||
#elif MG_ENABLE_DRIVER_STM32N
|
||||
#define SYNOPSYS_ENET_V5 1
|
||||
#define SYNOPSYS_ENET_SINGLEQ 0
|
||||
#define SYNOPSYS_ENET_NOHASHTABLE 1
|
||||
#define SYNOPSYS_ENET_GbE 1
|
||||
#elif MG_ENABLE_DRIVER_MCXN
|
||||
#define SYNOPSYS_ENET_V5 1
|
||||
#define SYNOPSYS_ENET_SINGLEQ 0
|
||||
#define SYNOPSYS_ENET_NOHASHTABLE 1
|
||||
#define SYNOPSYS_ENET_GbE 0
|
||||
#endif
|
||||
|
||||
struct synopsys_enet_qos {
|
||||
volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R,
|
||||
RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR,
|
||||
@@ -25782,25 +25800,84 @@ struct synopsys_enet_qos {
|
||||
};
|
||||
#undef ETH
|
||||
#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)
|
||||
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40028000UL)
|
||||
#elif MG_ENABLE_DRIVER_STM32N
|
||||
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x48036000UL)
|
||||
#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
|
||||
#define ETH_DS 4 // Descriptor size (words)
|
||||
|
||||
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM
|
||||
MG_8BYTE_ALIGNED;
|
||||
static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM
|
||||
MG_8BYTE_ALIGNED;
|
||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED;
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED;
|
||||
#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_STM32N
|
||||
#define CACHE_LINESZ 32 // must be a whole number of (d)words (see DESC_SZW)
|
||||
#ifndef SCB
|
||||
struct m7_scb {
|
||||
volatile uint32_t CPUID, RESERVED1[4], CCR, RESERVED2[145], DCIMVAC, DCISW,
|
||||
DCCMVAU, DCCMVAC, DCCSW, DCCIMVAC, DCCISW, RESERVED3[10], CACR,
|
||||
RESERVED4[3];
|
||||
};
|
||||
#define SCB ((struct m7_scb *) (uintptr_t) 0xE000ED00UL)
|
||||
#endif
|
||||
// ending ISB is not needed because we don't cache instructions in data space
|
||||
static inline void MG_CACHE_INVAL(uint8_t *addr, int32_t len) {
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7
|
||||
#endif
|
||||
if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled
|
||||
MG_DSB();
|
||||
while (len > 0) {
|
||||
SCB->DCIMVAC = (uint32_t) addr;
|
||||
addr += CACHE_LINESZ;
|
||||
len -= CACHE_LINESZ;
|
||||
}
|
||||
MG_DSB();
|
||||
}
|
||||
static inline void MG_CACHE_FLUSH(uint8_t *addr, int32_t len) {
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7
|
||||
#endif
|
||||
if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled
|
||||
MG_DSB();
|
||||
while (len > 0) {
|
||||
SCB->DCCMVAC = (uint32_t) addr;
|
||||
addr += CACHE_LINESZ;
|
||||
len -= CACHE_LINESZ;
|
||||
}
|
||||
MG_DSB();
|
||||
}
|
||||
#define ETH_RAM_ALIGNED MG_32BYTE_ALIGNED // depends on CACHE_LINESZ and ETH
|
||||
#define CACHE_ALIGN(x) \
|
||||
((((size_t) (x)) + CACHE_LINESZ - 1) & ~(CACHE_LINESZ - 1))
|
||||
#define DESC_SZ CACHE_ALIGN(4 * ETH_DS) // grow descriptors to fit a line
|
||||
#define DESC_SZW (DESC_SZ / 4)
|
||||
#define BUFF_SZ CACHE_ALIGN(ETH_PKT_SIZE) // grow buffers to fit n lines
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
#define DESC_SKIPW (DESC_SZW - ETH_DS) // tell DMA the descriptor size, words
|
||||
#else
|
||||
// MG_ENABLE_DRIVER_STM32N, DMA is AXI and specs skip in 64-bit double-words
|
||||
#define DESC_SKIPW ((DESC_SZW - ETH_DS) / 2)
|
||||
#endif
|
||||
#else
|
||||
#define MG_CACHE_FLUSH(a, b)
|
||||
#define MG_CACHE_INVAL(a, b)
|
||||
#define ETH_RAM_ALIGNED MG_8BYTE_ALIGNED // depends on ETH DMA alone
|
||||
#define DESC_SZ 0
|
||||
#define DESC_SZW ETH_DS
|
||||
#define BUFF_SZ ETH_PKT_SIZE
|
||||
#define DESC_SKIPW 0 // no need to skip, as we're not aligning to cache lines
|
||||
#endif
|
||||
|
||||
// array[rows][cols] = coldata coldata ... for all rows, keeps alignment
|
||||
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM
|
||||
ETH_RAM_ALIGNED;
|
||||
static volatile uint32_t s_txdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM
|
||||
ETH_RAM_ALIGNED;
|
||||
static uint8_t s_rxbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED;
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED;
|
||||
|
||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||
|
||||
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
@@ -25832,12 +25909,14 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
||||
s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
|
||||
s_rxdesc[i][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V
|
||||
}
|
||||
MG_CACHE_FLUSH((uint8_t *) s_rxdesc, sizeof(s_rxdesc));
|
||||
|
||||
// Init TX descriptors
|
||||
memset((char *) s_txdesc, 0, sizeof(s_txdesc)); // manual init
|
||||
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
||||
s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
|
||||
}
|
||||
MG_CACHE_FLUSH((uint8_t *) s_txdesc, sizeof(s_txdesc));
|
||||
|
||||
ETH->DMAMR |= MG_BIT(0); // Software reset
|
||||
for (int i = 0; i < 4; i++)
|
||||
@@ -25854,7 +25933,7 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
||||
ETH->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed
|
||||
ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
|
||||
ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
#if !SYNOPSYS_ENET_V5
|
||||
ETH->MACPFR = MG_BIT(10); // Perfect filtering
|
||||
#endif
|
||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||
@@ -25870,15 +25949,15 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
||||
ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length
|
||||
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
|
||||
ETH->DMACCR = DESC_SKIPW << 18; // DSL (contiguous/sparse descriptor table)
|
||||
#if SYNOPSYS_ENET_V5
|
||||
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, (10/100)/Reserved
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
#if SYNOPSYS_ENET_SINGLEQ
|
||||
ETH->MTLTQOMR |= MG_BIT(1); // TSF
|
||||
ETH->MTLRQOMR |= MG_BIT(5); // RSF
|
||||
#else
|
||||
@@ -25902,18 +25981,23 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
|
||||
struct mg_tcpip_if *ifp) {
|
||||
if (len > sizeof(s_txbuf[s_txno])) {
|
||||
MG_ERROR(("Frame too big, %ld", (long) len));
|
||||
len = 0; // Frame is too big
|
||||
} else if ((s_txdesc[s_txno][3] & MG_BIT(31))) {
|
||||
return 0; // Frame is too big
|
||||
}
|
||||
MG_CACHE_INVAL((uint8_t *) &s_txdesc[s_txno], DESC_SZ);
|
||||
if ((s_txdesc[s_txno][3] & MG_BIT(31))) {
|
||||
ifp->nerr++;
|
||||
MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno,
|
||||
s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR));
|
||||
MG_CACHE_INVAL((uint8_t *) s_txdesc, sizeof(s_txdesc));
|
||||
for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3]));
|
||||
len = 0; // All descriptors are busy, fail
|
||||
} else {
|
||||
memcpy(s_txbuf[s_txno], buf, len); // Copy data
|
||||
memcpy(s_txbuf[s_txno], buf, len); // Copy data
|
||||
MG_CACHE_FLUSH((uint8_t *) &s_txbuf[s_txno], BUFF_SZ);
|
||||
s_txdesc[s_txno][2] = (uint32_t) len; // Set data len
|
||||
s_txdesc[s_txno][3] = MG_BIT(28) | MG_BIT(29); // FD, LD
|
||||
s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over
|
||||
MG_CACHE_FLUSH((uint8_t *) &s_txdesc[s_txno], DESC_SZ);
|
||||
if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
|
||||
}
|
||||
ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS
|
||||
@@ -25923,7 +26007,7 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
|
||||
}
|
||||
|
||||
static void mg_tcpip_driver_stm32h_update_hash_table(struct mg_tcpip_if *ifp) {
|
||||
#if MG_ENABLE_DRIVER_MCXN || MG_ENABLE_DRIVER_STM32N
|
||||
#if SYNOPSYS_ENET_NOHASHTABLE
|
||||
ETH->MACPFR = MG_BIT(4); // Pass Multicast (pass all multicast frames)
|
||||
#else
|
||||
// TODO(): read database, rebuild hash table
|
||||
@@ -25955,7 +26039,7 @@ static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||
// 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 MG_ENABLE_DRIVER_STM32N
|
||||
#if SYNOPSYS_ENET_GbE
|
||||
if (speed == MG_PHY_SPEED_1000M) maccr &= ~MG_BIT(15); // 1000M
|
||||
#endif
|
||||
if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M
|
||||
@@ -25981,6 +26065,7 @@ void ETH1_IRQHandler(void) {
|
||||
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
|
||||
MG_CACHE_INVAL((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ);
|
||||
if (s_rxdesc[s_rxno][3] & MG_BIT(31)) break; // exit when done
|
||||
if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) ==
|
||||
(MG_BIT(28) | MG_BIT(29))) &&
|
||||
@@ -25988,10 +26073,12 @@ void ETH1_IRQHandler(void) {
|
||||
uint32_t len = s_rxdesc[s_rxno][3] & (MG_BIT(15) - 1);
|
||||
// MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3],
|
||||
// ETH->DMACSR));
|
||||
MG_CACHE_INVAL((uint8_t *) &s_rxbuf[s_rxno], BUFF_SZ);
|
||||
mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
|
||||
}
|
||||
s_rxdesc[s_rxno][3] =
|
||||
MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V
|
||||
MG_CACHE_FLUSH((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ);
|
||||
if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+109
-22
@@ -3,8 +3,26 @@
|
||||
#if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || \
|
||||
MG_ENABLE_DRIVER_STM32N)
|
||||
// STM32H: vendor modded single-queue Synopsys v4.2
|
||||
// STM32N, MCXNx4x: dual-queue Synopsys v5.2 with no hash table option
|
||||
// RT1170 ENET_QOS: quad-queue Synopsys v5.1
|
||||
// STM32N: dual-queue GbE Synopsys v5.2 with no hash table option, 64-bit AXI
|
||||
// MCXNx4x: dual-queue Synopsys v5.2 with no hash table option
|
||||
// RT1170: ENET_QOS: quad-queue Synopsys v5.1
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
#define SYNOPSYS_ENET_V5 0
|
||||
#define SYNOPSYS_ENET_SINGLEQ 1
|
||||
#define SYNOPSYS_ENET_NOHASHTABLE 0
|
||||
#define SYNOPSYS_ENET_GbE 0
|
||||
#elif MG_ENABLE_DRIVER_STM32N
|
||||
#define SYNOPSYS_ENET_V5 1
|
||||
#define SYNOPSYS_ENET_SINGLEQ 0
|
||||
#define SYNOPSYS_ENET_NOHASHTABLE 1
|
||||
#define SYNOPSYS_ENET_GbE 1
|
||||
#elif MG_ENABLE_DRIVER_MCXN
|
||||
#define SYNOPSYS_ENET_V5 1
|
||||
#define SYNOPSYS_ENET_SINGLEQ 0
|
||||
#define SYNOPSYS_ENET_NOHASHTABLE 1
|
||||
#define SYNOPSYS_ENET_GbE 0
|
||||
#endif
|
||||
|
||||
struct synopsys_enet_qos {
|
||||
volatile uint32_t MACCR, MACECR, MACPFR, MACWTR, MACHT0R, MACHT1R,
|
||||
RESERVED1[14], MACVTR, RESERVED2, MACVHTR, RESERVED3, MACVIR, MACIVIR,
|
||||
@@ -37,25 +55,84 @@ struct synopsys_enet_qos {
|
||||
};
|
||||
#undef ETH
|
||||
#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)
|
||||
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x40028000UL)
|
||||
#elif MG_ENABLE_DRIVER_STM32N
|
||||
#define ETH ((struct synopsys_enet_qos *) (uintptr_t) 0x48036000UL)
|
||||
#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
|
||||
#define ETH_DS 4 // Descriptor size (words)
|
||||
|
||||
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM
|
||||
MG_8BYTE_ALIGNED;
|
||||
static volatile uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_ETH_RAM
|
||||
MG_8BYTE_ALIGNED;
|
||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED;
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM MG_8BYTE_ALIGNED;
|
||||
#if MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_STM32N
|
||||
#define CACHE_LINESZ 32 // must be a whole number of (d)words (see DESC_SZW)
|
||||
#ifndef SCB
|
||||
struct m7_scb {
|
||||
volatile uint32_t CPUID, RESERVED1[4], CCR, RESERVED2[145], DCIMVAC, DCISW,
|
||||
DCCMVAU, DCCMVAC, DCCSW, DCCIMVAC, DCCISW, RESERVED3[10], CACR,
|
||||
RESERVED4[3];
|
||||
};
|
||||
#define SCB ((struct m7_scb *) (uintptr_t) 0xE000ED00UL)
|
||||
#endif
|
||||
// ending ISB is not needed because we don't cache instructions in data space
|
||||
static inline void MG_CACHE_INVAL(uint8_t *addr, int32_t len) {
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7
|
||||
#endif
|
||||
if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled
|
||||
MG_DSB();
|
||||
while (len > 0) {
|
||||
SCB->DCIMVAC = (uint32_t) addr;
|
||||
addr += CACHE_LINESZ;
|
||||
len -= CACHE_LINESZ;
|
||||
}
|
||||
MG_DSB();
|
||||
}
|
||||
static inline void MG_CACHE_FLUSH(uint8_t *addr, int32_t len) {
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
if ((SCB->CPUID & 0xfff0) != 0xc270) return; // not a Cortex-M7 => not an H7
|
||||
#endif
|
||||
if ((SCB->CCR & MG_BIT(16)) == 0) return; // cache not enabled
|
||||
MG_DSB();
|
||||
while (len > 0) {
|
||||
SCB->DCCMVAC = (uint32_t) addr;
|
||||
addr += CACHE_LINESZ;
|
||||
len -= CACHE_LINESZ;
|
||||
}
|
||||
MG_DSB();
|
||||
}
|
||||
#define ETH_RAM_ALIGNED MG_32BYTE_ALIGNED // depends on CACHE_LINESZ and ETH
|
||||
#define CACHE_ALIGN(x) \
|
||||
((((size_t) (x)) + CACHE_LINESZ - 1) & ~(CACHE_LINESZ - 1))
|
||||
#define DESC_SZ CACHE_ALIGN(4 * ETH_DS) // grow descriptors to fit a line
|
||||
#define DESC_SZW (DESC_SZ / 4)
|
||||
#define BUFF_SZ CACHE_ALIGN(ETH_PKT_SIZE) // grow buffers to fit n lines
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
#define DESC_SKIPW (DESC_SZW - ETH_DS) // tell DMA the descriptor size, words
|
||||
#else
|
||||
// MG_ENABLE_DRIVER_STM32N, DMA is AXI and specs skip in 64-bit double-words
|
||||
#define DESC_SKIPW ((DESC_SZW - ETH_DS) / 2)
|
||||
#endif
|
||||
#else
|
||||
#define MG_CACHE_FLUSH(a, b)
|
||||
#define MG_CACHE_INVAL(a, b)
|
||||
#define ETH_RAM_ALIGNED MG_8BYTE_ALIGNED // depends on ETH DMA alone
|
||||
#define DESC_SZ 0
|
||||
#define DESC_SZW ETH_DS
|
||||
#define BUFF_SZ ETH_PKT_SIZE
|
||||
#define DESC_SKIPW 0 // no need to skip, as we're not aligning to cache lines
|
||||
#endif
|
||||
|
||||
// array[rows][cols] = coldata coldata ... for all rows, keeps alignment
|
||||
static volatile uint32_t s_rxdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM
|
||||
ETH_RAM_ALIGNED;
|
||||
static volatile uint32_t s_txdesc[ETH_DESC_CNT][DESC_SZW] MG_ETH_RAM
|
||||
ETH_RAM_ALIGNED;
|
||||
static uint8_t s_rxbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED;
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][BUFF_SZ] MG_ETH_RAM ETH_RAM_ALIGNED;
|
||||
|
||||
static struct mg_tcpip_if *s_ifp; // MIP interface
|
||||
|
||||
static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) {
|
||||
@@ -87,12 +164,14 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
||||
s_rxdesc[i][0] = (uint32_t) (uintptr_t) s_rxbuf[i]; // Point to data buffer
|
||||
s_rxdesc[i][3] = MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V
|
||||
}
|
||||
MG_CACHE_FLUSH((uint8_t *) s_rxdesc, sizeof(s_rxdesc));
|
||||
|
||||
// Init TX descriptors
|
||||
memset((char *) s_txdesc, 0, sizeof(s_txdesc)); // manual init
|
||||
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
||||
s_txdesc[i][0] = (uint32_t) (uintptr_t) s_txbuf[i]; // Buf pointer
|
||||
}
|
||||
MG_CACHE_FLUSH((uint8_t *) s_txdesc, sizeof(s_txdesc));
|
||||
|
||||
ETH->DMAMR |= MG_BIT(0); // Software reset
|
||||
for (int i = 0; i < 4; i++)
|
||||
@@ -109,7 +188,7 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
||||
ETH->DMASBMR |= MG_BIT(12); // AAL NOTE(scaprile): is this actually needed
|
||||
ETH->MACIER = 0; // Do not enable additional irq sources (reset value)
|
||||
ETH->MACTFCR = MG_BIT(7); // Disable zero-quanta pause
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
#if !SYNOPSYS_ENET_V5
|
||||
ETH->MACPFR = MG_BIT(10); // Perfect filtering
|
||||
#endif
|
||||
struct mg_phy phy = {eth_read_phy, eth_write_phy};
|
||||
@@ -125,15 +204,15 @@ static bool mg_tcpip_driver_stm32h_init(struct mg_tcpip_if *ifp) {
|
||||
ETH->DMACTDRLR = ETH_DESC_CNT - 1; // ring length
|
||||
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
|
||||
ETH->DMACCR = DESC_SKIPW << 18; // DSL (contiguous/sparse descriptor table)
|
||||
#if SYNOPSYS_ENET_V5
|
||||
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, (10/100)/Reserved
|
||||
#if MG_ENABLE_DRIVER_STM32H
|
||||
#if SYNOPSYS_ENET_SINGLEQ
|
||||
ETH->MTLTQOMR |= MG_BIT(1); // TSF
|
||||
ETH->MTLRQOMR |= MG_BIT(5); // RSF
|
||||
#else
|
||||
@@ -157,18 +236,23 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
|
||||
struct mg_tcpip_if *ifp) {
|
||||
if (len > sizeof(s_txbuf[s_txno])) {
|
||||
MG_ERROR(("Frame too big, %ld", (long) len));
|
||||
len = 0; // Frame is too big
|
||||
} else if ((s_txdesc[s_txno][3] & MG_BIT(31))) {
|
||||
return 0; // Frame is too big
|
||||
}
|
||||
MG_CACHE_INVAL((uint8_t *) &s_txdesc[s_txno], DESC_SZ);
|
||||
if ((s_txdesc[s_txno][3] & MG_BIT(31))) {
|
||||
ifp->nerr++;
|
||||
MG_ERROR(("No free descriptors: %u %08X %08X %08X", s_txno,
|
||||
s_txdesc[s_txno][3], ETH->DMACSR, ETH->DMACTCR));
|
||||
MG_CACHE_INVAL((uint8_t *) s_txdesc, sizeof(s_txdesc));
|
||||
for (int i = 0; i < ETH_DESC_CNT; i++) MG_ERROR(("%08X", s_txdesc[i][3]));
|
||||
len = 0; // All descriptors are busy, fail
|
||||
} else {
|
||||
memcpy(s_txbuf[s_txno], buf, len); // Copy data
|
||||
memcpy(s_txbuf[s_txno], buf, len); // Copy data
|
||||
MG_CACHE_FLUSH((uint8_t *) &s_txbuf[s_txno], BUFF_SZ);
|
||||
s_txdesc[s_txno][2] = (uint32_t) len; // Set data len
|
||||
s_txdesc[s_txno][3] = MG_BIT(28) | MG_BIT(29); // FD, LD
|
||||
s_txdesc[s_txno][3] |= MG_BIT(31); // Set OWN bit - let DMA take over
|
||||
MG_CACHE_FLUSH((uint8_t *) &s_txdesc[s_txno], DESC_SZ);
|
||||
if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
|
||||
}
|
||||
ETH->DMACSR |= MG_BIT(2) | MG_BIT(1); // Clear any prior TBU, TPS
|
||||
@@ -178,7 +262,7 @@ static size_t mg_tcpip_driver_stm32h_tx(const void *buf, size_t len,
|
||||
}
|
||||
|
||||
static void mg_tcpip_driver_stm32h_update_hash_table(struct mg_tcpip_if *ifp) {
|
||||
#if MG_ENABLE_DRIVER_MCXN || MG_ENABLE_DRIVER_STM32N
|
||||
#if SYNOPSYS_ENET_NOHASHTABLE
|
||||
ETH->MACPFR = MG_BIT(4); // Pass Multicast (pass all multicast frames)
|
||||
#else
|
||||
// TODO(): read database, rebuild hash table
|
||||
@@ -210,7 +294,7 @@ static bool mg_tcpip_driver_stm32h_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||
// 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 MG_ENABLE_DRIVER_STM32N
|
||||
#if SYNOPSYS_ENET_GbE
|
||||
if (speed == MG_PHY_SPEED_1000M) maccr &= ~MG_BIT(15); // 1000M
|
||||
#endif
|
||||
if (speed == MG_PHY_SPEED_10M) maccr &= ~MG_BIT(14); // 10M
|
||||
@@ -236,6 +320,7 @@ void ETH1_IRQHandler(void) {
|
||||
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
|
||||
MG_CACHE_INVAL((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ);
|
||||
if (s_rxdesc[s_rxno][3] & MG_BIT(31)) break; // exit when done
|
||||
if (((s_rxdesc[s_rxno][3] & (MG_BIT(28) | MG_BIT(29))) ==
|
||||
(MG_BIT(28) | MG_BIT(29))) &&
|
||||
@@ -243,10 +328,12 @@ void ETH1_IRQHandler(void) {
|
||||
uint32_t len = s_rxdesc[s_rxno][3] & (MG_BIT(15) - 1);
|
||||
// MG_DEBUG(("%lx %lu %lx %08lx", s_rxno, len, s_rxdesc[s_rxno][3],
|
||||
// ETH->DMACSR));
|
||||
MG_CACHE_INVAL((uint8_t *) &s_rxbuf[s_rxno], BUFF_SZ);
|
||||
mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
|
||||
}
|
||||
s_rxdesc[s_rxno][3] =
|
||||
MG_BIT(31) | MG_BIT(30) | MG_BIT(24); // OWN, IOC, BUF1V
|
||||
MG_CACHE_FLUSH((uint8_t *) &s_rxdesc[s_rxno], DESC_SZ);
|
||||
if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user