diff --git a/mongoose.c b/mongoose.c index b9170641..9f16cc9f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -20537,6 +20537,191 @@ struct mg_tcpip_driver mg_tcpip_driver_ra = {mg_tcpip_driver_ra_init, #endif +#ifdef MG_ENABLE_LINES +#line 1 "src/drivers/rw612.c" +#endif + + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RW612) && MG_ENABLE_DRIVER_RW612 + +struct ENET_Type { + volatile uint32_t RESERVED_0[1], EIR, EIMR, RESERVED_1[1], RDAR, TDAR, + RESERVED_2[3], ECR, RESERVED_3[6], MMFR, MSCR, RESERVED_4[7], MIBC, + RESERVED_5[7], RCR, RESERVED_6[15], TCR, RESERVED_7[7], PALR, PAUR, OPD, + TXIC[1], RESERVED_8[3], RXIC[1], RESERVED_9[5], IAUR, IALR, GAUR, GALR, + RESERVED_10[7], TFWR, RESERVED_11[14], RDSR, TDSR, MRBR, RESERVED_12[1], + RSFL, RSEM, RAEM, RAFL, TSEM, TAEM, TAFL, TIPG, FTRL, RESERVED_13[3], + TACC, RACC, RESERVED_14[15], RMON_T_PACKETS, RMON_T_BC_PKT, RMON_T_MC_PKT, + RMON_T_CRC_ALIGN, RMON_T_UNDERSIZE, RMON_T_OVERSIZE, RMON_T_FRAG, + RMON_T_JAB, RMON_T_COL, RMON_T_P64, RMON_T_P65TO127, RMON_T_P128TO255, + RMON_T_P256TO511, RMON_T_P512TO1023, RMON_T_P1024TO2047, RMON_T_P_GTE2048, + RMON_T_OCTETS, IEEE_T_DROP, IEEE_T_FRAME_OK, IEEE_T_1COL, IEEE_T_MCOL, + IEEE_T_DEF, IEEE_T_LCOL, IEEE_T_EXCOL, IEEE_T_MACERR, IEEE_T_CSERR, + IEEE_T_SQE, IEEE_T_FDXFC, IEEE_T_OCTETS_OK, RESERVED_15[3], + RMON_R_PACKETS, RMON_R_BC_PKT, RMON_R_MC_PKT, RMON_R_CRC_ALIGN, + RMON_R_UNDERSIZE, RMON_R_OVERSIZE, RMON_R_FRAG, RMON_R_JAB, + RESERVED_16[1], RMON_R_P64, RMON_R_P65TO127, RMON_R_P128TO255, + RMON_R_P256TO511, RMON_R_P512TO1023, RMON_R_P1024TO2047, RMON_R_P_GTE2048, + RMON_R_OCTETS, IEEE_R_DROP, IEEE_R_FRAME_OK, IEEE_R_CRC, IEEE_R_ALIGN, + IEEE_R_MACERR, IEEE_R_FDXFC, IEEE_R_OCTETS_OK, RESERVED_17[71], ATCR, + ATVR, ATOFF, ATPER, ATCOR, ATINC, ATSTMP, RESERVED_18[122], TGSR, + CHANNEL_TCSR[4], CHANNEL_TCCR[4]; +}; + +#define ENET ((struct ENET_Type *) 0x40138000) + +#define ETH_PKT_SIZE 1536 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 2 // Descriptor size (words) + +#define MG_8BYTE_ALIGNED __attribute__((aligned((8U)))) +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED; +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED; +static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED; +static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED; +static uint8_t s_txno; // Current TX descriptor +static uint8_t s_rxno; // Current RX descriptor + +static struct mg_tcpip_if *s_ifp; // MIP interface + +static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { + ENET->MMFR = MG_BIT(30) | // Start of frame delimiter + MG_BIT(29) | // Opcode + ((addr & 0x1f) << 23) | ((reg & 0x1f) << 18) | MG_BIT(17); + while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0; + ENET->EIR |= MG_BIT(23); + return ENET->MMFR & 0xffff; +} + +static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { + ENET->MMFR = MG_BIT(30) | // Start of frame delimiter + MG_BIT(28) | // Opcode + ((addr & 0x1f) << 23) | ((reg & 0x1f) << 18) | MG_BIT(17) | val; + while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0; + ENET->EIR |= MG_BIT(23); +} + +static bool mg_tcpip_driver_rw612_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_rw612_data *d = + (struct mg_tcpip_driver_rw612_data *) ifp->driver_data; + s_ifp = ifp; + ENET->MSCR = ((d->mdc_cr & 0x3f) << 1) | ((d->mdc_holdtime & 7) << 8); + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + mg_phy_init(&phy, d->phy_addr, 0); + ENET->ECR |= MG_BIT(0); // reset ETH + + // initialize descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][1] = (uint32_t) s_rxbuf[i]; + s_rxdesc[i][0] = MG_BIT(31); // OWN + if (i == ETH_DESC_CNT - 1) { + s_rxdesc[i][0] |= MG_BIT(29); // mark last descriptor + } + s_txdesc[i][1] = (uint32_t) s_txbuf[i]; + if (i == ETH_DESC_CNT - 1) { + s_txdesc[i][0] |= MG_BIT(29); // mark last descriptor + } + } + + ENET->RCR = (ENET->RCR & (0xffff << 16)) | MG_BIT(14) | MG_BIT(8) | MG_BIT(2); + ENET->TCR = MG_BIT(2); // full duplex + ENET->TDSR = (uint32_t) &s_txdesc[0][0]; + ENET->RDSR = (uint32_t) &s_rxdesc[0][0]; + ENET->MRBR = ETH_PKT_SIZE; + ENET->PALR = + ifp->mac[0] << 24 | ifp->mac[1] << 16 | ifp->mac[2] << 8 | ifp->mac[3]; + ENET->PAUR |= (ifp->mac[4] << 24 | ifp->mac[5] << 16); + ENET->MSCR = ((d->mdc_cr & 0x3f) << 1) | ((d->mdc_holdtime & 7) << 8); + ENET->EIMR = MG_BIT(25); // Enable RX interrupt + ENET->ECR |= MG_BIT(8) | MG_BIT(1); // DBSWP, Enable + ENET->RDAR = 0; // activate RX descriptors ring + return true; +} + +static size_t mg_tcpip_driver_rw612_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][0] & MG_BIT(31)) != 0)) { + ifp->nerr++; + MG_ERROR(("No free descriptors")); + len = 0; // All descriptors are busy, fail + } else { + memcpy(s_txbuf[s_txno], buf, len); + s_txdesc[s_txno][0] = len | MG_BIT(27) | MG_BIT(26); // last buffer, crc + if (s_txno == ETH_DESC_CNT - 1) { + s_txdesc[s_txno][0] |= MG_BIT(29); // wrap + } + s_txdesc[s_txno][0] |= MG_BIT(31); // release ownership + MG_DSB(); + ENET->TDAR = 0; + // MG_INFO(("s_txdesc[%d][0]: 0x%x", s_txno, s_txdesc[s_txno][0])); + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; + } + + return len; +} + +static bool mg_tcpip_driver_rw612_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_rw612_data *d = + (struct mg_tcpip_driver_rw612_data *) ifp->driver_data; + uint8_t speed = MG_PHY_SPEED_10M; + bool up = false, full_duplex = false; + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + // tmp = reg with flags set to the most likely situation: 100M full-duplex + // if(link is slow or half) set flags otherwise + // reg = tmp + if (speed == MG_PHY_SPEED_100M && (ENET->RCR & MG_BIT(9))) { + ENET->RCR &= ~MG_BIT(9); + } else if (speed == MG_PHY_SPEED_10M && (ENET->RCR & MG_BIT(9)) == 0) { + ENET->RCR |= MG_BIT(9); + } + if (full_duplex && (ENET->TCR & MG_BIT(2)) == 0) { + ENET->ECR &= ~MG_BIT(1); + ENET->TCR |= MG_BIT(2); + ENET->ECR |= MG_BIT(1); + } else if (!full_duplex && (ENET->TCR & MG_BIT(2))) { + ENET->ECR &= ~MG_BIT(1); + ENET->TCR &= ~MG_BIT(2); + ENET->ECR |= MG_BIT(1); + } + MG_INFO(("Link is %uM %s-duplex", + speed == MG_PHY_SPEED_10M + ? 10 + : (speed == MG_PHY_SPEED_100M ? 100 : 1000), + full_duplex ? "full" : "half")); + } + return up; +} + +void ENET_IRQHandler(void) { + if (ENET->EIR & MG_BIT(25)) { + ENET->EIR = MG_BIT(25); // Ack RX + for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever + if ((s_rxdesc[s_rxno][0] & MG_BIT(31)) != 0) break; // exit when done + // skip partial/errored frames + if ((s_rxdesc[s_rxno][0] & MG_BIT(27)) && + !(s_rxdesc[s_rxno][0] & + (MG_BIT(21) | MG_BIT(20) | MG_BIT(18) | MG_BIT(17) | MG_BIT(16)))) { + size_t len = s_rxdesc[s_rxno][0] & 0xffff; + mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); + s_rxdesc[s_rxno][0] |= MG_BIT(31); // OWN bit: handle control to DMA + MG_DSB(); + ENET->RDAR = 0; + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; + } + } + } +} + +struct mg_tcpip_driver mg_tcpip_driver_rw612 = {mg_tcpip_driver_rw612_init, + mg_tcpip_driver_rw612_tx, NULL, + mg_tcpip_driver_rw612_up}; +#endif + #ifdef MG_ENABLE_LINES #line 1 "src/drivers/same54.c" #endif diff --git a/mongoose.h b/mongoose.h index f598d0bf..5f06db22 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2815,6 +2815,7 @@ extern struct mg_tcpip_driver mg_tcpip_driver_xmc; extern struct mg_tcpip_driver mg_tcpip_driver_xmc7; extern struct mg_tcpip_driver mg_tcpip_driver_ppp; extern struct mg_tcpip_driver mg_tcpip_driver_pico_w; +extern struct mg_tcpip_driver mg_tcpip_driver_rw612; // Drivers that require SPI, can use this SPI abstraction struct mg_tcpip_spi { @@ -3029,6 +3030,52 @@ struct mg_tcpip_driver_ra_data { #endif +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RW612) && MG_ENABLE_DRIVER_RW612 + +struct mg_tcpip_driver_rw612_data { + // 38.1.8 MII Speed Control Register (MSCR) + // MDC clock frequency must not exceed 2.5 MHz and is calculated as follows: + // MDC_freq = P_clock / ((mdc_cr + 1) * 2), where P_clock is the + // peripheral bus clock. + // IEEE802.3 clause 22 defines a minimum of 10 ns for the hold time on the + // MDIO output. Depending on the host bus frequency, the setting may need + // to be increased. + int mdc_cr; + int mdc_holdtime; // Valid values: [0-7] + uint8_t phy_addr; +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 2 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 51 +#endif + +#ifndef MG_DRIVER_MDC_HOLDTIME +#define MG_DRIVER_MDC_HOLDTIME 3 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_rw612_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_rw612; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: rw612, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + + #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && MG_ENABLE_DRIVER_SAME54 struct mg_tcpip_driver_same54_data { diff --git a/src/drivers/rw612.c b/src/drivers/rw612.c new file mode 100644 index 00000000..8f0e6e20 --- /dev/null +++ b/src/drivers/rw612.c @@ -0,0 +1,181 @@ +#include "net_builtin.h" + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RW612) && MG_ENABLE_DRIVER_RW612 + +struct ENET_Type { + volatile uint32_t RESERVED_0[1], EIR, EIMR, RESERVED_1[1], RDAR, TDAR, + RESERVED_2[3], ECR, RESERVED_3[6], MMFR, MSCR, RESERVED_4[7], MIBC, + RESERVED_5[7], RCR, RESERVED_6[15], TCR, RESERVED_7[7], PALR, PAUR, OPD, + TXIC[1], RESERVED_8[3], RXIC[1], RESERVED_9[5], IAUR, IALR, GAUR, GALR, + RESERVED_10[7], TFWR, RESERVED_11[14], RDSR, TDSR, MRBR, RESERVED_12[1], + RSFL, RSEM, RAEM, RAFL, TSEM, TAEM, TAFL, TIPG, FTRL, RESERVED_13[3], + TACC, RACC, RESERVED_14[15], RMON_T_PACKETS, RMON_T_BC_PKT, RMON_T_MC_PKT, + RMON_T_CRC_ALIGN, RMON_T_UNDERSIZE, RMON_T_OVERSIZE, RMON_T_FRAG, + RMON_T_JAB, RMON_T_COL, RMON_T_P64, RMON_T_P65TO127, RMON_T_P128TO255, + RMON_T_P256TO511, RMON_T_P512TO1023, RMON_T_P1024TO2047, RMON_T_P_GTE2048, + RMON_T_OCTETS, IEEE_T_DROP, IEEE_T_FRAME_OK, IEEE_T_1COL, IEEE_T_MCOL, + IEEE_T_DEF, IEEE_T_LCOL, IEEE_T_EXCOL, IEEE_T_MACERR, IEEE_T_CSERR, + IEEE_T_SQE, IEEE_T_FDXFC, IEEE_T_OCTETS_OK, RESERVED_15[3], + RMON_R_PACKETS, RMON_R_BC_PKT, RMON_R_MC_PKT, RMON_R_CRC_ALIGN, + RMON_R_UNDERSIZE, RMON_R_OVERSIZE, RMON_R_FRAG, RMON_R_JAB, + RESERVED_16[1], RMON_R_P64, RMON_R_P65TO127, RMON_R_P128TO255, + RMON_R_P256TO511, RMON_R_P512TO1023, RMON_R_P1024TO2047, RMON_R_P_GTE2048, + RMON_R_OCTETS, IEEE_R_DROP, IEEE_R_FRAME_OK, IEEE_R_CRC, IEEE_R_ALIGN, + IEEE_R_MACERR, IEEE_R_FDXFC, IEEE_R_OCTETS_OK, RESERVED_17[71], ATCR, + ATVR, ATOFF, ATPER, ATCOR, ATINC, ATSTMP, RESERVED_18[122], TGSR, + CHANNEL_TCSR[4], CHANNEL_TCCR[4]; +}; + +#define ENET ((struct ENET_Type *) 0x40138000) + +#define ETH_PKT_SIZE 1536 // Max frame size +#define ETH_DESC_CNT 4 // Descriptors count +#define ETH_DS 2 // Descriptor size (words) + +#define MG_8BYTE_ALIGNED __attribute__((aligned((8U)))) +static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED; +static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_8BYTE_ALIGNED; +static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED; +static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS] MG_8BYTE_ALIGNED; +static uint8_t s_txno; // Current TX descriptor +static uint8_t s_rxno; // Current RX descriptor + +static struct mg_tcpip_if *s_ifp; // MIP interface + +static uint16_t eth_read_phy(uint8_t addr, uint8_t reg) { + ENET->MMFR = MG_BIT(30) | // Start of frame delimiter + MG_BIT(29) | // Opcode + ((addr & 0x1f) << 23) | ((reg & 0x1f) << 18) | MG_BIT(17); + while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0; + ENET->EIR |= MG_BIT(23); + return ENET->MMFR & 0xffff; +} + +static void eth_write_phy(uint8_t addr, uint8_t reg, uint16_t val) { + ENET->MMFR = MG_BIT(30) | // Start of frame delimiter + MG_BIT(28) | // Opcode + ((addr & 0x1f) << 23) | ((reg & 0x1f) << 18) | MG_BIT(17) | val; + while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0; + ENET->EIR |= MG_BIT(23); +} + +static bool mg_tcpip_driver_rw612_init(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_rw612_data *d = + (struct mg_tcpip_driver_rw612_data *) ifp->driver_data; + s_ifp = ifp; + ENET->MSCR = ((d->mdc_cr & 0x3f) << 1) | ((d->mdc_holdtime & 7) << 8); + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + mg_phy_init(&phy, d->phy_addr, 0); + ENET->ECR |= MG_BIT(0); // reset ETH + + // initialize descriptors + for (int i = 0; i < ETH_DESC_CNT; i++) { + s_rxdesc[i][1] = (uint32_t) s_rxbuf[i]; + s_rxdesc[i][0] = MG_BIT(31); // OWN + if (i == ETH_DESC_CNT - 1) { + s_rxdesc[i][0] |= MG_BIT(29); // mark last descriptor + } + s_txdesc[i][1] = (uint32_t) s_txbuf[i]; + if (i == ETH_DESC_CNT - 1) { + s_txdesc[i][0] |= MG_BIT(29); // mark last descriptor + } + } + + ENET->RCR = (ENET->RCR & (0xffff << 16)) | MG_BIT(14) | MG_BIT(8) | MG_BIT(2); + ENET->TCR = MG_BIT(2); // full duplex + ENET->TDSR = (uint32_t) &s_txdesc[0][0]; + ENET->RDSR = (uint32_t) &s_rxdesc[0][0]; + ENET->MRBR = ETH_PKT_SIZE; + ENET->PALR = + ifp->mac[0] << 24 | ifp->mac[1] << 16 | ifp->mac[2] << 8 | ifp->mac[3]; + ENET->PAUR |= (ifp->mac[4] << 24 | ifp->mac[5] << 16); + ENET->MSCR = ((d->mdc_cr & 0x3f) << 1) | ((d->mdc_holdtime & 7) << 8); + ENET->EIMR = MG_BIT(25); // Enable RX interrupt + ENET->ECR |= MG_BIT(8) | MG_BIT(1); // DBSWP, Enable + ENET->RDAR = 0; // activate RX descriptors ring + return true; +} + +static size_t mg_tcpip_driver_rw612_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][0] & MG_BIT(31)) != 0)) { + ifp->nerr++; + MG_ERROR(("No free descriptors")); + len = 0; // All descriptors are busy, fail + } else { + memcpy(s_txbuf[s_txno], buf, len); + s_txdesc[s_txno][0] = len | MG_BIT(27) | MG_BIT(26); // last buffer, crc + if (s_txno == ETH_DESC_CNT - 1) { + s_txdesc[s_txno][0] |= MG_BIT(29); // wrap + } + s_txdesc[s_txno][0] |= MG_BIT(31); // release ownership + MG_DSB(); + ENET->TDAR = 0; + // MG_INFO(("s_txdesc[%d][0]: 0x%x", s_txno, s_txdesc[s_txno][0])); + if (++s_txno >= ETH_DESC_CNT) s_txno = 0; + } + + return len; +} + +static bool mg_tcpip_driver_rw612_up(struct mg_tcpip_if *ifp) { + struct mg_tcpip_driver_rw612_data *d = + (struct mg_tcpip_driver_rw612_data *) ifp->driver_data; + uint8_t speed = MG_PHY_SPEED_10M; + bool up = false, full_duplex = false; + struct mg_phy phy = {eth_read_phy, eth_write_phy}; + up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed); + if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up + // tmp = reg with flags set to the most likely situation: 100M full-duplex + // if(link is slow or half) set flags otherwise + // reg = tmp + if (speed == MG_PHY_SPEED_100M && (ENET->RCR & MG_BIT(9))) { + ENET->RCR &= ~MG_BIT(9); + } else if (speed == MG_PHY_SPEED_10M && (ENET->RCR & MG_BIT(9)) == 0) { + ENET->RCR |= MG_BIT(9); + } + if (full_duplex && (ENET->TCR & MG_BIT(2)) == 0) { + ENET->ECR &= ~MG_BIT(1); + ENET->TCR |= MG_BIT(2); + ENET->ECR |= MG_BIT(1); + } else if (!full_duplex && (ENET->TCR & MG_BIT(2))) { + ENET->ECR &= ~MG_BIT(1); + ENET->TCR &= ~MG_BIT(2); + ENET->ECR |= MG_BIT(1); + } + MG_INFO(("Link is %uM %s-duplex", + speed == MG_PHY_SPEED_10M + ? 10 + : (speed == MG_PHY_SPEED_100M ? 100 : 1000), + full_duplex ? "full" : "half")); + } + return up; +} + +void ENET_IRQHandler(void) { + if (ENET->EIR & MG_BIT(25)) { + ENET->EIR = MG_BIT(25); // Ack RX + for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever + if ((s_rxdesc[s_rxno][0] & MG_BIT(31)) != 0) break; // exit when done + // skip partial/errored frames + if ((s_rxdesc[s_rxno][0] & MG_BIT(27)) && + !(s_rxdesc[s_rxno][0] & + (MG_BIT(21) | MG_BIT(20) | MG_BIT(18) | MG_BIT(17) | MG_BIT(16)))) { + size_t len = s_rxdesc[s_rxno][0] & 0xffff; + mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp); + s_rxdesc[s_rxno][0] |= MG_BIT(31); // OWN bit: handle control to DMA + MG_DSB(); + ENET->RDAR = 0; + if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0; + } + } + } +} + +struct mg_tcpip_driver mg_tcpip_driver_rw612 = {mg_tcpip_driver_rw612_init, + mg_tcpip_driver_rw612_tx, NULL, + mg_tcpip_driver_rw612_up}; +#endif diff --git a/src/drivers/rw612.h b/src/drivers/rw612.h new file mode 100644 index 00000000..568284e5 --- /dev/null +++ b/src/drivers/rw612.h @@ -0,0 +1,46 @@ +#pragma once + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RW612) && MG_ENABLE_DRIVER_RW612 + +struct mg_tcpip_driver_rw612_data { + // 38.1.8 MII Speed Control Register (MSCR) + // MDC clock frequency must not exceed 2.5 MHz and is calculated as follows: + // MDC_freq = P_clock / ((mdc_cr + 1) * 2), where P_clock is the + // peripheral bus clock. + // IEEE802.3 clause 22 defines a minimum of 10 ns for the hold time on the + // MDIO output. Depending on the host bus frequency, the setting may need + // to be increased. + int mdc_cr; + int mdc_holdtime; // Valid values: [0-7] + uint8_t phy_addr; +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 2 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 51 +#endif + +#ifndef MG_DRIVER_MDC_HOLDTIME +#define MG_DRIVER_MDC_HOLDTIME 3 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_rw612_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_rw612; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: rw612, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif diff --git a/src/net_builtin.h b/src/net_builtin.h index 31c21298..47109770 100644 --- a/src/net_builtin.h +++ b/src/net_builtin.h @@ -82,6 +82,7 @@ extern struct mg_tcpip_driver mg_tcpip_driver_xmc; extern struct mg_tcpip_driver mg_tcpip_driver_xmc7; extern struct mg_tcpip_driver mg_tcpip_driver_ppp; extern struct mg_tcpip_driver mg_tcpip_driver_pico_w; +extern struct mg_tcpip_driver mg_tcpip_driver_rw612; // Drivers that require SPI, can use this SPI abstraction struct mg_tcpip_spi {