mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-21 11:30:01 +00:00
191 lines
7.7 KiB
C
191 lines
7.7 KiB
C
#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->IALR = 0;
|
|
ENET->IAUR = 0;
|
|
ENET->GALR = 0;
|
|
#if MG_TCPIP_MCAST
|
|
ENET->GAUR = MG_BIT(1); // see imxrt, it reduces to this for mDNS
|
|
#else
|
|
ENET->GAUR = 0;
|
|
#endif
|
|
|
|
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
|