Add teensy41 example

This commit is contained in:
cpq committed 2023-11-11 21:22:00 +00:00
1 parent a619de0508
commit b815e6bc04
20 files changed
+671 -462

No files matched your search

+76 -56
View File
@@ -27,14 +27,10 @@ struct rt1020_enet {
};
#undef ENET
#define ENET ((struct rt1020_enet *) (uintptr_t) 0x402D8000u)
#define ENET ((struct rt1020_enet *) (uintptr_t) 0x402D8000U)
#undef BIT
#define BIT(x) ((uint32_t) 1 << (x))
// Max frame size, every buffer must be 64-bit aligned (1536 = 0x600)
#define ETH_PKT_SIZE 1536
#define ETH_DESC_CNT 4 // Descriptors count
#define ETH_PKT_SIZE 1536 // Max frame size, 64-bit aligned
#define ETH_DESC_CNT 4 // Descriptors count
typedef struct {
uint16_t length; // Data length
@@ -43,29 +39,30 @@ typedef struct {
} enet_bd_t;
// TODO(): handle these in a portable compiler-independent CMSIS-friendly way
// Descriptors: in non-cached area (TODO(scaprile)), 64-bit aligned
enet_bd_t s_rxdesc[ETH_DESC_CNT] __attribute__((aligned((64U))));
enet_bd_t s_txdesc[ETH_DESC_CNT] __attribute__((aligned((64U))));
// Buffers: 64-bit aligned
uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] __attribute__((aligned((64U))));
uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] __attribute__((aligned((64U))));
#define MG_A64 __attribute__((aligned((64U))))
// Descriptors: in non-cached area (TODO(scaprile)), 64-bit aligned
// Buffers: 64-bit aligned
static volatile enet_bd_t s_rxdesc[ETH_DESC_CNT] MG_A64;
static volatile enet_bd_t s_txdesc[ETH_DESC_CNT] MG_A64;
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_A64;
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_A64;
static struct mg_tcpip_if *s_ifp; // MIP interface
enum { PHY_ADDR = 2, PHY_BCR = 0, PHY_BSR = 1, PHY_PC1R = 30, PHY_PC2R = 31 };
enum { PHY_BCR = 0, PHY_BSR = 1, PHY_ID1 = 2, PHY_ID2 = 3 };
static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
ENET->EIR |= BIT(23); // MII interrupt clear
static uint16_t rt10xx_phy_read(uint8_t addr, uint8_t reg) {
ENET->EIR |= MG_BIT(23); // MII interrupt clear
ENET->MMFR = (1 << 30) | (2 << 28) | (addr << 23) | (reg << 18) | (2 << 16);
while ((ENET->EIR & BIT(23)) == 0) (void) 0;
while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0;
return ENET->MMFR & 0xffff;
}
static void eth_write_phy(uint8_t addr, uint8_t reg, uint32_t val) {
ENET->EIR |= BIT(23); // MII interrupt clear
static void rt10xx_phy_write(uint8_t addr, uint8_t reg, uint16_t val) {
ENET->EIR |= MG_BIT(23); // MII interrupt clear
ENET->MMFR =
(1 << 30) | (1 << 28) | (addr << 23) | (reg << 18) | (2 << 16) | val;
while ((ENET->EIR & BIT(23)) == 0) (void) 0;
while ((ENET->EIR & MG_BIT(23)) == 0) (void) 0;
}
// MDC clock is generated from IPS Bus clock (ipg_clk); as per 802.3,
@@ -78,34 +75,51 @@ static bool mg_tcpip_driver_rt1020_init(struct mg_tcpip_if *ifp) {
// Init RX descriptors
for (int i = 0; i < ETH_DESC_CNT; i++) {
s_rxdesc[i].control = BIT(15); // Own (E)
s_rxdesc[i].control = MG_BIT(15); // Own (E)
s_rxdesc[i].buffer = (uint32_t *) s_rxbuf[i]; // Point to data buffer
}
s_rxdesc[ETH_DESC_CNT - 1].control |= BIT(13); // Wrap last descriptor
s_rxdesc[ETH_DESC_CNT - 1].control |= MG_BIT(13); // Wrap last descriptor
// Init TX descriptors
for (int i = 0; i < ETH_DESC_CNT; i++) {
s_txdesc[i].control = BIT(10); // Own (TC)
//s_txdesc[i].control = MG_BIT(10); // Own (TC)
s_txdesc[i].buffer = (uint32_t *) s_txbuf[i];
}
s_txdesc[ETH_DESC_CNT - 1].control |= BIT(13); // Wrap last descriptor
s_txdesc[ETH_DESC_CNT - 1].control |= MG_BIT(13); // Wrap last descriptor
ENET->ECR = BIT(0); // Software reset, disable
while ((ENET->ECR & BIT(0))) (void) 0; // Wait until done
ENET->ECR = MG_BIT(0); // Software reset, disable
while ((ENET->ECR & MG_BIT(0))) (void) 0; // Wait until done
// Set MDC clock divider. If user told us the value, use it.
// TODO(): Otherwise, guess (currently assuming max freq)
int cr = (d == NULL || d->mdc_cr < 0) ? 24 : d->mdc_cr;
ENET->MSCR = (1 << 8) | ((cr & 0x3f) << 1); // HOLDTIME 2 clks
eth_write_phy(PHY_ADDR, PHY_BCR, BIT(15)); // Reset PHY
eth_write_phy(PHY_ADDR, PHY_BCR, BIT(12)); // Set autonegotiation
rt10xx_phy_write(d->phy_addr, PHY_BCR, MG_BIT(15)); // Reset PHY
rt10xx_phy_write(d->phy_addr, PHY_BCR, MG_BIT(12)); // Set autonegotiation
// PHY: Enable 50 MHz external ref clock at XI (preserve defaults)
eth_write_phy(PHY_ADDR, PHY_PC2R, BIT(15) | BIT(8) | BIT(7));
uint16_t phy_id2 = rt10xx_phy_read(d->phy_addr, PHY_ID1);
uint16_t phy_id3 = rt10xx_phy_read(d->phy_addr, PHY_ID2);
MG_INFO(("PHY ID: %#04x %#04x", phy_id2, phy_id3));
// 2000 a140 - TI DP83825I
// 0007 c0fx - LAN8720
// 0022 1561 - KSZ8081RNB
if (phy_id2 == 0x22) { // KSZ8081RNB, like EVK-RTxxxx boards
rt10xx_phy_write(d->phy_addr, 31,
MG_BIT(15) | MG_BIT(8) | MG_BIT(7)); // PC2R
} else if (phy_id2 == 0x2000) { // DP83825I, like Teensy4.1
rt10xx_phy_write(d->phy_addr, 23, 0x81); // 50Mhz clock input
rt10xx_phy_write(d->phy_addr, 24, 0x280); // LED status, active high
} else { // Default to LAN8720
MG_INFO(("Defauling to LAN8720 PHY..."));
}
// Select RMII mode, 100M, keep CRC, set max rx length, disable loop
ENET->RCR = (1518 << 16) | BIT(8) | BIT(2);
// ENET->RCR |= BIT(3); // Receive all
ENET->TCR = BIT(2); // Full-duplex
ENET->RCR = (1518 << 16) | MG_BIT(8) | MG_BIT(2);
// ENET->RCR |= MG_BIT(3); // Receive all
ENET->TCR = MG_BIT(2); // Full-duplex
ENET->RDSR = (uint32_t) (uintptr_t) s_rxdesc;
ENET->TDSR = (uint32_t) (uintptr_t) s_txdesc;
ENET->MRBR[0] = ETH_PKT_SIZE; // Same size for RX/TX buffers
@@ -114,9 +128,9 @@ static bool mg_tcpip_driver_rt1020_init(struct mg_tcpip_if *ifp) {
ENET->PALR = (uint32_t) (ifp->mac[0] << 24U) |
((uint32_t) ifp->mac[1] << 16U) |
((uint32_t) ifp->mac[2] << 8U) | ifp->mac[3];
ENET->ECR = BIT(8) | BIT(1); // Little-endian CPU, Enable
ENET->EIMR = BIT(25); // Set interrupt mask
ENET->RDAR = BIT(24); // Receive Descriptors have changed
ENET->ECR = MG_BIT(8) | MG_BIT(1); // Little-endian CPU, Enable
ENET->EIMR = MG_BIT(25); // Set interrupt mask
ENET->RDAR = MG_BIT(24); // Receive Descriptors have changed
return true;
}
@@ -126,18 +140,20 @@ static uint32_t s_txno;
static size_t mg_tcpip_driver_rt1020_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) {
if (len > sizeof(s_txbuf[ETH_DESC_CNT])) {
MG_ERROR(("Frame too big, %ld", (long) len));
len = 0; // fail
} else if ((s_txdesc[s_txno].control & BIT(15))) {
ifp->nerr++;
MG_ERROR(("Frame too big, %ld", (long) len));
len = (size_t) -1; // fail
} else if ((s_txdesc[s_txno].control & MG_BIT(15))) {
MG_ERROR(("No descriptors available"));
len = 0; // fail
len = 0; // retry later
} else {
MG_DEBUG(("sending %lu bytes, desc %u", len, s_txno));
memcpy(s_txbuf[s_txno], buf, len); // Copy data
s_txdesc[s_txno].length = (uint16_t) len; // Set data len
// Table 37-34, R, L, TC (Ready, last, transmit CRC after frame
s_txdesc[s_txno].control |= (uint16_t) (BIT(15) | BIT(11) | BIT(10));
ENET->TDAR = BIT(24); // Descriptor ring updated
s_txdesc[s_txno].control |=
(uint16_t) (MG_BIT(15) | MG_BIT(11) | MG_BIT(10));
ENET->TDAR |= MG_BIT(24); // Descriptor ring updated
if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
}
(void) ifp;
@@ -145,18 +161,22 @@ static size_t mg_tcpip_driver_rt1020_tx(const void *buf, size_t len,
}
static bool mg_tcpip_driver_rt1020_up(struct mg_tcpip_if *ifp) {
uint32_t bsr = eth_read_phy(PHY_ADDR, PHY_BSR);
bool up = bsr & BIT(2) ? 1 : 0;
struct mg_tcpip_driver_rt1020_data *d =
(struct mg_tcpip_driver_rt1020_data *) ifp->driver_data;
uint32_t bsr = rt10xx_phy_read(d->phy_addr, PHY_BSR);
bool up = bsr & MG_BIT(2) ? 1 : 0;
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) { // link state just went up
uint32_t pc1r = eth_read_phy(PHY_ADDR, PHY_PC1R);
uint32_t tcr = ENET->TCR |= BIT(2); // Full-duplex
uint32_t rcr = ENET->RCR &= ~BIT(9); // 100M
if ((pc1r & 3) == 1) rcr |= BIT(9); // 10M
if ((pc1r & BIT(2)) == 0) tcr &= ~BIT(2); // Half-duplex
uint32_t tcr = ENET->TCR |= MG_BIT(2); // Full-duplex
uint32_t rcr = ENET->RCR &= ~MG_BIT(9); // 100M
if (rt10xx_phy_read(d->phy_addr, PHY_ID1)) { // KSZ8081RNB ?
uint32_t pc1r = rt10xx_phy_read(d->phy_addr, 30); // Read PC2R
if ((pc1r & 3) == 1) rcr |= MG_BIT(9); // 10M
if ((pc1r & MG_BIT(2)) == 0) tcr &= ~MG_BIT(2); // Half-duplex
}
ENET->TCR = tcr; // IRQ handler does not fiddle with these registers
ENET->RCR = rcr;
MG_DEBUG(("Link is %uM %s-duplex", rcr & BIT(9) ? 10 : 100,
tcr & BIT(2) ? "full" : "half"));
MG_DEBUG(("Link is %uM %s-duplex", rcr & MG_BIT(9) ? 10 : 100,
tcr & MG_BIT(2) ? "full" : "half"));
}
return up;
}
@@ -164,21 +184,21 @@ static bool mg_tcpip_driver_rt1020_up(struct mg_tcpip_if *ifp) {
void ENET_IRQHandler(void);
static uint32_t s_rxno;
void ENET_IRQHandler(void) {
ENET->EIR = BIT(25); // Ack IRQ
ENET->EIR = MG_BIT(25); // Ack IRQ
// Frame received, loop
for (uint32_t i = 0; i < 10; i++) { // read as they arrive but not forever
if (s_rxdesc[s_rxno].control & BIT(15)) break; // exit when done
if (s_rxdesc[s_rxno].control & MG_BIT(15)) break; // exit when done
// skip partial/errored frames (Table 37-32)
if ((s_rxdesc[s_rxno].control & BIT(11)) &&
if ((s_rxdesc[s_rxno].control & MG_BIT(11)) &&
!(s_rxdesc[s_rxno].control &
(BIT(5) | BIT(4) | BIT(2) | BIT(1) | BIT(0)))) {
(MG_BIT(5) | MG_BIT(4) | MG_BIT(2) | MG_BIT(1) | MG_BIT(0)))) {
uint32_t len = (s_rxdesc[s_rxno].length);
mg_tcpip_qwrite(s_rxbuf[s_rxno], len > 4 ? len - 4 : len, s_ifp);
}
s_rxdesc[s_rxno].control |= BIT(15);
s_rxdesc[s_rxno].control |= MG_BIT(15);
if (++s_rxno >= ETH_DESC_CNT) s_rxno = 0;
}
ENET->RDAR = BIT(24); // Receive Descriptors have changed
ENET->RDAR = MG_BIT(24); // Receive Descriptors have changed
// If b24 == 0, descriptors were exhausted and probably frames were dropped
}
+3 -1
View File
@@ -11,6 +11,8 @@ struct mg_tcpip_driver_rt1020_data {
// 33 MHz 6
// 40 MHz 7
// 50 MHz 9
// 66 MHz 13
// 66 MHz 13
int mdc_cr; // Valid values: -1 to 63
uint8_t phy_addr; // PHY address
};
+3 -16
View File
@@ -17,19 +17,6 @@ struct stm32_eth {
#undef ETH
#define ETH ((struct stm32_eth *) (uintptr_t) 0x40028000)
#undef DSB
#if defined(__CC_ARM)
#define DSB() __dsb(0xF)
#elif defined(__ARMCC_VERSION)
#define DSB() __builtin_arm_dsb(0xF)
#elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__)
#define DSB() asm("DSB 0xF")
#elif defined(__ICCARM__)
#define DSB() __iar_builtin_DSB()
#else
#define DSB()
#endif
#undef BIT
#define BIT(x) ((uint32_t) 1 << (x))
#define ETH_PKT_SIZE 1540 // Max frame size
@@ -177,13 +164,13 @@ static size_t mg_tcpip_driver_stm32_tx(const void *buf, size_t len,
// printf("D0 %lx SR %lx\n", (long) s_txdesc[0][0], (long) ETH->DMASR);
len = 0; // All descriptors are busy, fail
} else {
memcpy(s_txbuf[s_txno], buf, len); // Copy data
s_txdesc[s_txno][1] = (uint32_t) len; // Set data len
memcpy(s_txbuf[s_txno], buf, len); // Copy data
s_txdesc[s_txno][1] = (uint32_t) len; // Set data len
s_txdesc[s_txno][0] = BIT(20) | BIT(28) | BIT(29); // Chain,FS,LS
s_txdesc[s_txno][0] |= BIT(31); // Set OWN bit - let DMA take over
if (++s_txno >= ETH_DESC_CNT) s_txno = 0;
}
DSB(); // ensure descriptors have been written
MG_DSB(); // ensure descriptors have been written
ETH->DMASR = BIT(2) | BIT(5); // Clear any prior TBUS/TUS
ETH->DMATPDR = 0; // and resume
return len;
+18 -17
View File
@@ -172,9 +172,6 @@ static void settmout(struct mg_connection *c, uint8_t type) {
}
static size_t ether_output(struct mg_tcpip_if *ifp, size_t len) {
// size_t min = 64; // Pad short frames to 64 bytes (minimum Ethernet size)
// if (len < min) memset(ifp->tx.ptr + len, 0, min - len), len = min;
// mg_hexdump(ifp->tx.ptr, len);
size_t n = ifp->driver->tx(ifp->tx.ptr, len, ifp);
if (n == len) ifp->nsent++;
return n;
@@ -550,8 +547,8 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
static size_t trim_len(struct mg_connection *c, size_t len) {
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
size_t eth_h_len = 14, ip_max_h_len = 24, tcp_max_h_len = 60, udp_h_len = 8;
size_t max_headers_len = eth_h_len + ip_max_h_len +
(c->is_udp ? udp_h_len : tcp_max_h_len);
size_t max_headers_len =
eth_h_len + ip_max_h_len + (c->is_udp ? udp_h_len : tcp_max_h_len);
size_t min_mtu = c->is_udp ? 68 /* RFC-791 */ : max_headers_len - eth_h_len;
// If the frame exceeds the available buffer, trim the length
@@ -578,18 +575,21 @@ static size_t trim_len(struct mg_connection *c, size_t len) {
long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
struct connstate *s = (struct connstate *) (c + 1);
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
uint32_t dst_ip = *(uint32_t *) c->rem.ip;
len = trim_len(c, len);
if (c->is_udp) {
tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len);
tx_udp(ifp, s->mac, ifp->ip, c->loc.port, dst_ip, c->rem.port, buf, len);
} else {
if (tx_tcp(ifp, s->mac, rem_ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq), mg_htonl(s->ack), buf, len) > 0) {
size_t sent =
tx_tcp(ifp, s->mac, dst_ip, TH_PUSH | TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq), mg_htonl(s->ack), buf, len);
if (sent == 0) {
return MG_IO_WAIT;
} else if (sent == (size_t) -1) {
return MG_IO_ERR;
} else {
s->seq += (uint32_t) len;
if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE);
} else {
return MG_IO_ERR;
}
}
return (long) len;
@@ -744,12 +744,11 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
}
static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (pkt->ip->frag & IP_MORE_FRAGS_MSK ||
pkt->ip->frag & IP_FRAG_OFFSET_MSK) {
if (pkt->ip->frag & IP_MORE_FRAGS_MSK || pkt->ip->frag & IP_FRAG_OFFSET_MSK) {
if (pkt->ip->proto == 17) pkt->udp = (struct udp *) (pkt->ip + 1);
if (pkt->ip->proto == 6) pkt->tcp = (struct tcp *) (pkt->ip + 1);
struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
if (c) mg_error(c, "Received fragmented packet");
if (c) mg_error(c, "Received fragmented packet");
} else if (pkt->ip->proto == 1) {
pkt->icmp = (struct icmp *) (pkt->ip + 1);
if (pkt->pay.len < sizeof(*pkt->icmp)) return;
@@ -1039,7 +1038,9 @@ bool mg_open_listener(struct mg_connection *c, const char *url) {
static void write_conn(struct mg_connection *c) {
long len = c->is_tls ? mg_tls_send(c, c->send.buf, c->send.len)
: mg_io_send(c, c->send.buf, c->send.len);
if (len > 0) {
if (len == MG_IO_ERR) {
mg_error(c, "tx err");
} else if (len > 0) {
mg_iobuf_del(&c->send, 0, (size_t) len);
mg_call(c, MG_EV_WRITE, &len);
}
@@ -1100,7 +1101,7 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
mg_error(c, "net down");
} else if (c->is_udp) {
struct connstate *s = (struct connstate *) (c + 1);
len = trim_len(c, len); // Trimming length if necessary
len = trim_len(c, len); // Trimming length if necessary
tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len);
res = true;
} else {
+12
View File
@@ -47,6 +47,18 @@ uint64_t mg_now(void); // Return milliseconds since Epoch
#define MG_ARM_ENABLE_IRQ()
#endif
#if defined(__CC_ARM)
#define MG_DSB() __dsb(0xf)
#elif defined(__ARMCC_VERSION)
#define MG_DSB() __builtin_arm_dsb(0xf)
#elif defined(__GNUC__) && defined(__arm__) && defined(__thumb__)
#define MG_DSB() asm("DSB 0xf")
#elif defined(__ICCARM__)
#define MG_DSB() __iar_builtin_DSB()
#else
#define MG_DSB()
#endif
struct mg_addr;
int mg_check_ip_acl(struct mg_str acl, struct mg_addr *remote_ip);