mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-15 10:29:47 +00:00
Merge pull request #3666 from cesanta/netc
Add Ethernet controller (NETC) driver for IMXRT1180
This commit is contained in:
6 files changed
+1074
-4
No files matched your search
+489
-2
@@ -28630,6 +28630,465 @@ struct mg_tcpip_driver mg_tcpip_driver_imxrt = {mg_tcpip_driver_imxrt_init,
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MG_ENABLE_LINES
|
||||
#line 1 "src/drivers/netc.c"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP && \
|
||||
defined(MG_ENABLE_DRIVER_NETC) && MG_ENABLE_DRIVER_NETC
|
||||
|
||||
// IMXRT1180 RM - Chapter 53 - Ethernet Controller (NETC)
|
||||
|
||||
#define ETH_DESC_CNT 8 // Descriptor count must be multiple of 8 (53.4.6.11.97)
|
||||
#define ETH_PKT_SIZE 1536
|
||||
|
||||
struct netc_pci_function { // 53.4.6.1.1
|
||||
volatile uint32_t DID_VID;
|
||||
volatile uint16_t CMD, STAT;
|
||||
volatile uint8_t reserved0[0x40];
|
||||
volatile uint16_t DEV_CTL, DEV_STAT;
|
||||
volatile uint8_t reserved1[0x34];
|
||||
volatile uint16_t MSIX_CAP_LIST, MSIX_MSG_CTL;
|
||||
};
|
||||
|
||||
struct netc_emdio { // 53.4.6.12
|
||||
volatile uint32_t EMDIO_CFG, EMDIO_CTL, EMDIO_DATA, EMDIO_ADDR, EMDIO_STAT;
|
||||
};
|
||||
|
||||
struct netc_enetc { // 53.4.6.6
|
||||
volatile uint32_t ECAPR0, ECAPR1, ECAPR2, reserved0, PMR;
|
||||
volatile uint8_t reserved1[0x1ec];
|
||||
volatile uint32_t PSIPMMR, PSIPVMR;
|
||||
volatile uint8_t reserved2[0x5f8];
|
||||
volatile uint32_t SMCAPR;
|
||||
volatile uint8_t reserved3[0x17fc];
|
||||
struct {
|
||||
volatile uint32_t PSIPMAR0, PSIPMAR1, PSIVLANR, reserved0, PSICFGR0,
|
||||
PSICFGR1, PSICFGR2;
|
||||
volatile uint8_t reserved1[0x64];
|
||||
} PSI[1];
|
||||
};
|
||||
|
||||
struct netc_port { // 53.4.6.8
|
||||
volatile uint32_t PCAPR, PMCAPR, PIOCAPR, reserved0, PCR;
|
||||
volatile uint8_t reserved1[0x0c];
|
||||
volatile uint32_t PMAR0, PMAR1;
|
||||
volatile uint8_t reserved2[0xd8];
|
||||
volatile uint32_t POR, PSR;
|
||||
volatile uint8_t reserved3[0x30];
|
||||
volatile uint32_t PDGSR;
|
||||
volatile uint8_t reserved4[0xc4];
|
||||
struct {
|
||||
volatile uint32_t PTGSTCSR, reserved0, PTCTMSDUR, reserved1, PTCCBSR0,
|
||||
PTCCBSR1;
|
||||
volatile uint8_t reserved2[8];
|
||||
} TCT[8];
|
||||
volatile uint8_t reserved5[0x220];
|
||||
volatile uint32_t BPSTGSR;
|
||||
};
|
||||
|
||||
struct netc_port_mac { // 53.4.6.9
|
||||
volatile uint8_t reserved0[8];
|
||||
volatile uint32_t COMMAND_CONFIG, MAC_ADDR_0, MAC_ADDR_1, MAXFRM, MINFRM;
|
||||
volatile uint8_t reserved1[0x24];
|
||||
volatile uint32_t IEVENT;
|
||||
volatile uint8_t reserved2[0x1dc];
|
||||
volatile uint64_t TFRMN;
|
||||
volatile uint8_t reserved3[0xd8];
|
||||
volatile uint32_t IF_MODE;
|
||||
volatile uint8_t reserved4[0xfc];
|
||||
};
|
||||
|
||||
struct netc_eth_link {
|
||||
struct netc_port_mac PM[2];
|
||||
};
|
||||
|
||||
struct netc_pseudo_link {
|
||||
volatile uint32_t PPMSR;
|
||||
volatile uint8_t reserved0[0x0c];
|
||||
volatile uint32_t PPMCR;
|
||||
};
|
||||
|
||||
struct netc_switch { // 53.4.6.5
|
||||
volatile uint8_t reserved0[0x400];
|
||||
volatile uint32_t MPCR;
|
||||
volatile uint8_t reserved1[0x1c0c];
|
||||
volatile uint32_t VFHTDECR0, VFHTDECR1, VFHTDECR2;
|
||||
};
|
||||
|
||||
struct netc_bdr {
|
||||
volatile uint32_t TBMR, TBSR;
|
||||
volatile uint8_t reserved0[8];
|
||||
volatile uint32_t TBBAR0, TBBAR1, TBPIR, TBCIR, TBLENR;
|
||||
volatile uint8_t reserved1[0x7c];
|
||||
volatile uint32_t TBIER, TBIDR, TBICR0, TBICR1;
|
||||
volatile uint8_t reserved2[0x50];
|
||||
volatile uint32_t RBMR, RBSR, RBBSR, RBCIR, RBBAR0, RBBAR1, RBPIR,
|
||||
reserved3, RBLENR;
|
||||
volatile uint8_t reserved4[0x5c];
|
||||
volatile uint32_t RBDCR;
|
||||
volatile uint8_t reserved5[0x1c];
|
||||
volatile uint32_t RBIER, RBIDR, RBICR0, RBICR1;
|
||||
volatile uint8_t reserved6[0x50];
|
||||
};
|
||||
|
||||
struct netc_si { // 53.4.6.11
|
||||
volatile uint32_t SIMR, SISR;
|
||||
volatile uint8_t reserved0[0x30];
|
||||
volatile uint32_t SIRBGCR;
|
||||
volatile uint8_t reserved1[0x2ec];
|
||||
volatile uint32_t SITFRM0;
|
||||
volatile uint8_t reserved2[0x6fc];
|
||||
volatile uint32_t SIRXIDR0;
|
||||
volatile uint8_t reserved3[0x154];
|
||||
volatile uint32_t SIMSIRRVR[1];
|
||||
volatile uint8_t reserved4[0x747c];
|
||||
struct netc_bdr BDR[1];
|
||||
};
|
||||
|
||||
struct netc_msix_entry { // 53.4.2.11
|
||||
volatile uint32_t MSG_ADDR, MSG_UPPER_ADDR, MSG_DATA, VECTOR_CTRL;
|
||||
};
|
||||
|
||||
struct netc_msgintr { // 54.4
|
||||
struct {
|
||||
volatile uint32_t MSIIR, MSIR;
|
||||
} MSI[3];
|
||||
};
|
||||
|
||||
#define NETC_EMDIO_PCI \
|
||||
((struct netc_pci_function *) (uintptr_t) 0x60001000U)
|
||||
#define NETC_SWITCH_PCI \
|
||||
((struct netc_pci_function *) (uintptr_t) 0x60002000U)
|
||||
#define NETC_ENETC1_PCI \
|
||||
((struct netc_pci_function *) (uintptr_t) 0x60004000U)
|
||||
#define NETC_EMDIO ((struct netc_emdio *) (uintptr_t) 0x60ba1c00U)
|
||||
|
||||
#define NETC_ENETC1 ((struct netc_enetc *) (uintptr_t) 0x60b50000U)
|
||||
#define NETC_ENETC1_PORT ((struct netc_port *) (uintptr_t) 0x60b54000U)
|
||||
#define NETC_ENETC1_PSEUDO_LINK \
|
||||
((struct netc_pseudo_link *) (uintptr_t) 0x60b55000U)
|
||||
#define NETC_ENETC1_SI0 ((struct netc_si *) (uintptr_t) 0x60b40000U)
|
||||
#define NETC_ENETC1_MSIX \
|
||||
((struct netc_msix_entry *) (uintptr_t) 0x60c00000U)
|
||||
|
||||
#define NETC_SWITCH ((struct netc_switch *) (uintptr_t) 0x60a00000U)
|
||||
#define NETC_SW0_PORT(link) \
|
||||
((struct netc_port *) (uintptr_t) (0x60a04000U + \
|
||||
(uint32_t) (link) * 0x4000U))
|
||||
#define NETC_SW0_ETH(link) \
|
||||
((struct netc_eth_link *) (uintptr_t) (0x60a05000U + \
|
||||
(uint32_t) (link) * 0x4000U))
|
||||
#define NETC_SW0_PORT4 ((struct netc_port *) (uintptr_t) 0x60a14000U)
|
||||
#define NETC_MSGINTR1 \
|
||||
((struct netc_msgintr *) (uintptr_t) 0x428a0000U)
|
||||
|
||||
enum {
|
||||
NETC_RX_MSIX_ENTRY = 0,
|
||||
NETC_RX_MSG_INDEX = 2,
|
||||
};
|
||||
|
||||
struct netc_tx_bd {
|
||||
uint64_t buffer_address;
|
||||
uint16_t buffer_length, frame_length;
|
||||
uint32_t control;
|
||||
};
|
||||
|
||||
struct netc_rx_descriptor {
|
||||
uint64_t buffer_address, reserved;
|
||||
};
|
||||
|
||||
struct netc_rx_writeback {
|
||||
uint16_t internet_checksum, parser_summary;
|
||||
uint32_t rss_hash;
|
||||
uint16_t buffer_length, vlan;
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
union netc_rx_bd {
|
||||
struct netc_rx_descriptor descriptor;
|
||||
struct netc_rx_writeback writeback;
|
||||
};
|
||||
|
||||
static volatile struct netc_tx_bd s_txdesc[ETH_DESC_CNT] MG_ETH_RAM
|
||||
__attribute__((aligned(128)));
|
||||
static volatile union netc_rx_bd s_rxdesc[ETH_DESC_CNT] MG_ETH_RAM
|
||||
__attribute__((aligned(128)));
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM
|
||||
__attribute__((aligned(64)));
|
||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM
|
||||
__attribute__((aligned(64)));
|
||||
|
||||
static uint16_t s_tx_prod;
|
||||
static uint16_t s_tx_clean;
|
||||
static uint16_t s_rx_cons;
|
||||
static struct mg_tcpip_if *s_ifp;
|
||||
|
||||
static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) {
|
||||
NETC_EMDIO->EMDIO_CFG &= ~MG_BIT(6); // ENC45: use Clause 22
|
||||
NETC_EMDIO->EMDIO_CTL = MG_BIT(15) | ((uint32_t) (addr & 0x1fU) << 5) |
|
||||
(reg & 0x1fU); // READ, PORT_ADDR, DEV_ADDR
|
||||
while (NETC_EMDIO->EMDIO_CFG & MG_BIT(31)) (void) 0; // BSY1
|
||||
return (uint16_t) (NETC_EMDIO->EMDIO_DATA & 0xffffU);
|
||||
}
|
||||
|
||||
static void enet_write_phy(uint8_t addr, uint8_t reg, uint16_t value) {
|
||||
NETC_EMDIO->EMDIO_CFG &= ~MG_BIT(6); // ENC45: use Clause 22
|
||||
NETC_EMDIO->EMDIO_CTL = ((uint32_t) (addr & 0x1fU) << 5) |
|
||||
(reg & 0x1fU); // PORT_ADDR, DEV_ADDR
|
||||
NETC_EMDIO->EMDIO_DATA = value;
|
||||
while (NETC_EMDIO->EMDIO_CFG & MG_BIT(31)) (void) 0; // BSY1
|
||||
}
|
||||
|
||||
static bool mg_tcpip_driver_netc_init(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_netc_data *d =
|
||||
(struct mg_tcpip_driver_netc_data *) ifp->driver_data;
|
||||
struct mg_phy phy = {enet_read_phy, enet_write_phy};
|
||||
struct netc_port *switch_port;
|
||||
struct netc_eth_link *eth_link;
|
||||
uint64_t tx_base = (uint64_t) (uintptr_t) s_txdesc;
|
||||
uint64_t rx_base = (uint64_t) (uintptr_t) s_rxdesc;
|
||||
uint32_t mac0 = (uint32_t) ifp->mac[0] |
|
||||
((uint32_t) ifp->mac[1] << 8) |
|
||||
((uint32_t) ifp->mac[2] << 16) |
|
||||
((uint32_t) ifp->mac[3] << 24);
|
||||
uint32_t mac1 = (uint32_t) ifp->mac[4] |
|
||||
((uint32_t) ifp->mac[5] << 8);
|
||||
uint32_t mdc_cr =
|
||||
(uint32_t) (d->mdc_cr < 0 ? MG_DRIVER_MDC_CR : d->mdc_cr);
|
||||
|
||||
switch_port = NETC_SW0_PORT(d->link);
|
||||
eth_link = NETC_SW0_ETH(d->link);
|
||||
s_ifp = ifp;
|
||||
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
||||
s_txdesc[i].buffer_address = (uint64_t) (uintptr_t) s_txbuf[i];
|
||||
s_rxdesc[i].descriptor.buffer_address =
|
||||
(uint64_t) (uintptr_t) s_rxbuf[i];
|
||||
}
|
||||
|
||||
NETC_EMDIO_PCI->DEV_CTL |= MG_BIT(15); // INIT_FLR
|
||||
while (NETC_EMDIO_PCI->DEV_CTL & MG_BIT(15)) (void) 0;
|
||||
NETC_EMDIO_PCI->CMD |= MG_BIT(2) | MG_BIT(1); // BUS_MASTER_EN, MEM_ACCESS
|
||||
NETC_EMDIO->EMDIO_CFG =
|
||||
((mdc_cr & 0x1ffU) << 7) | MG_BIT(2); // MDIO_CLK_DIV, MDIO_HOLD
|
||||
mg_phy_init(&phy, d->phy_addr, 0);
|
||||
|
||||
// Initialize ENETC1 PSI0 and port
|
||||
NETC_ENETC1_PCI->CMD |= MG_BIT(2) | MG_BIT(1); // BUS_MASTER_EN, MEM_ACCESS
|
||||
NETC_ENETC1_PCI->MSIX_MSG_CTL = MG_BIT(14); // FUNC_MASK
|
||||
NETC_ENETC1_PORT->POR |= MG_BIT(1) | MG_BIT(0); // RXDIS, TXDIS
|
||||
NETC_ENETC1_PCI->DEV_CTL |= MG_BIT(15); // INIT_FLR
|
||||
while (NETC_ENETC1_PCI->DEV_CTL & MG_BIT(15)) (void) 0;
|
||||
NETC_ENETC1_PCI->CMD |= MG_BIT(2) | MG_BIT(1); // BUS_MASTER_EN, MEM_ACCESS
|
||||
NETC_ENETC1_PCI->MSIX_MSG_CTL = MG_BIT(14); // FUNC_MASK
|
||||
NETC_ENETC1_PORT->PCR = 99U << 16; // PSPEED: 1 Gbps
|
||||
NETC_ENETC1_PORT->PMAR0 = mac0;
|
||||
NETC_ENETC1_PORT->PMAR1 = mac1;
|
||||
NETC_ENETC1_PSEUDO_LINK->PPMCR = MG_BIT(16); // TXPAD
|
||||
NETC_ENETC1->PSIPMMR &= ~(MG_BIT(16) | MG_BIT(0));
|
||||
NETC_ENETC1_SI0->SIMR &=
|
||||
~(MG_BIT(31) | MG_BIT(3) | MG_BIT(2) | MG_BIT(1));
|
||||
NETC_ENETC1_SI0->SIRBGCR = 0;
|
||||
NETC_ENETC1->PSI[0].PSICFGR0 =
|
||||
MG_BIT(16) | MG_BIT(0); // one Rx BDR, one Tx BDR
|
||||
|
||||
NETC_ENETC1->PSI[0].PSICFGR2 = 0; // NUM_MSIX: one entry
|
||||
NETC_ENETC1_MSIX[NETC_RX_MSIX_ENTRY].VECTOR_CTRL = MG_BIT(0); // MASK
|
||||
NETC_ENETC1_MSIX[NETC_RX_MSIX_ENTRY].MSG_ADDR =
|
||||
(uint32_t) (uintptr_t) &NETC_MSGINTR1->MSI[0].MSIIR;
|
||||
NETC_ENETC1_MSIX[NETC_RX_MSIX_ENTRY].MSG_UPPER_ADDR = 0;
|
||||
NETC_ENETC1_MSIX[NETC_RX_MSIX_ENTRY].MSG_DATA = NETC_RX_MSG_INDEX;
|
||||
NETC_ENETC1_SI0->SIMSIRRVR[0] = NETC_RX_MSIX_ENTRY; // Rx ring 0 -> entry 0
|
||||
|
||||
// Initialize switch function 2 to drive the selected physical port
|
||||
NETC_SWITCH_PCI->CMD |= MG_BIT(2) | MG_BIT(1);
|
||||
NETC_SWITCH_PCI->MSIX_MSG_CTL = MG_BIT(14); // FUNC_MASK
|
||||
switch_port->POR |= MG_BIT(1) | MG_BIT(0);
|
||||
eth_link->PM[0].COMMAND_CONFIG |= MG_BIT(26); // SWR
|
||||
while (eth_link->PM[0].COMMAND_CONFIG & MG_BIT(26)) (void) 0;
|
||||
eth_link->PM[1].COMMAND_CONFIG |= MG_BIT(26); // SWR
|
||||
while (eth_link->PM[1].COMMAND_CONFIG & MG_BIT(26)) (void) 0;
|
||||
NETC_SWITCH_PCI->DEV_CTL |= MG_BIT(15); // INIT_FLR
|
||||
while (NETC_SWITCH_PCI->DEV_CTL & MG_BIT(15)) (void) 0;
|
||||
NETC_SWITCH_PCI->CMD |= MG_BIT(2) | MG_BIT(1);
|
||||
NETC_SWITCH_PCI->MSIX_MSG_CTL = MG_BIT(14); // FUNC_MASK
|
||||
|
||||
// Configure switch physical port and ethernet link (ETH_X)
|
||||
switch_port->PCR = 99U << 16; // PSPEED: 1 Gbps
|
||||
switch_port->PMAR0 = mac0;
|
||||
switch_port->PMAR1 = mac1;
|
||||
switch_port->TCT[0].PTCTMSDUR = MG_BIT(24) | MG_BIT(16) | ETH_PKT_SIZE;
|
||||
eth_link->PM[0].MAXFRM = ETH_PKT_SIZE;
|
||||
eth_link->PM[0].MINFRM = 64;
|
||||
eth_link->PM[0].IF_MODE = MG_BIT(14) | 4U; // 1G RGMII
|
||||
eth_link->PM[0].COMMAND_CONFIG =
|
||||
MG_BIT(15) | MG_BIT(1) | MG_BIT(0); // TXP, RX_EN, TX_EN
|
||||
eth_link->PM[1].MAXFRM = ETH_PKT_SIZE;
|
||||
eth_link->PM[1].MINFRM = 64;
|
||||
eth_link->PM[1].IF_MODE = MG_BIT(14) | 4U;
|
||||
eth_link->PM[1].COMMAND_CONFIG =
|
||||
MG_BIT(15) | MG_BIT(1) | MG_BIT(0);
|
||||
|
||||
// Bridge the selected physical port with management port 4 (54.4.1.1)
|
||||
NETC_SWITCH->VFHTDECR0 = MG_BIT(4) | MG_BIT(d->link);
|
||||
NETC_SWITCH->VFHTDECR2 = (1UL << 27) | (1UL << 24); // MFO=1, MLO=1
|
||||
switch_port->BPSTGSR = 2U; // STG0: forwarding
|
||||
NETC_SW0_PORT4->BPSTGSR = 2U; // STG0: forwarding
|
||||
switch_port->POR &= ~(MG_BIT(1) | MG_BIT(0));
|
||||
NETC_SW0_PORT4->POR &= ~(MG_BIT(1) | MG_BIT(0));
|
||||
|
||||
// Initialize Tx BD ring 0 (direct switch enqueue)
|
||||
NETC_ENETC1_SI0->BDR[0].TBBAR0 = (uint32_t) tx_base;
|
||||
NETC_ENETC1_SI0->BDR[0].TBBAR1 = (uint32_t) (tx_base >> 32);
|
||||
NETC_ENETC1_SI0->BDR[0].TBLENR = ETH_DESC_CNT;
|
||||
|
||||
// Initialize Rx BD ring 0
|
||||
NETC_ENETC1_SI0->BDR[0].RBICR0 =
|
||||
MG_BIT(31) | MG_BIT(0); // ICEN, interrupt after one frame
|
||||
NETC_ENETC1_SI0->BDR[0].RBBAR0 = (uint32_t) rx_base;
|
||||
NETC_ENETC1_SI0->BDR[0].RBBAR1 = (uint32_t) (rx_base >> 32);
|
||||
NETC_ENETC1_SI0->BDR[0].RBBSR = ETH_PKT_SIZE;
|
||||
NETC_ENETC1_SI0->BDR[0].RBLENR = ETH_DESC_CNT;
|
||||
|
||||
// Clear stale device and MSGINTR state before the ring becomes active
|
||||
NETC_ENETC1_SI0->SIRXIDR0 = MG_BIT(0); // RX0, W1C
|
||||
(void) NETC_MSGINTR1->MSI[0].MSIR; // clear pending messages
|
||||
NETC_ENETC1_SI0->BDR[0].RBIER = MG_BIT(0); // RXTIE
|
||||
NETC_ENETC1_SI0->BDR[0].TBMR = MG_BIT(31);
|
||||
NETC_ENETC1_SI0->BDR[0].RBMR = MG_BIT(31); // EN, CRC=0: strip FCS
|
||||
NETC_ENETC1_PORT->POR &= ~(MG_BIT(1) | MG_BIT(0));
|
||||
NETC_ENETC1->PMR |= MG_BIT(16); // SI0EN
|
||||
NETC_ENETC1_SI0->SIMR |= MG_BIT(31); // EN
|
||||
MG_DSB();
|
||||
if ((NETC_ENETC1->SMCAPR & MG_BIT(0)) == 0U ||
|
||||
(NETC_SWITCH->MPCR & 0x1fU) != 4U) {
|
||||
MG_ERROR(("NETC fixed management path unavailable: SMCAPR=%08lx MPCR=%08lx",
|
||||
(unsigned long) NETC_ENETC1->SMCAPR,
|
||||
(unsigned long) NETC_SWITCH->MPCR));
|
||||
return false;
|
||||
}
|
||||
|
||||
NETC_ENETC1_PCI->MSIX_MSG_CTL =
|
||||
MG_BIT(15); // Enable RX interrupt, MSIX_EN=1, FUNC_MASK=0
|
||||
MG_DSB();
|
||||
NETC_ENETC1_MSIX[NETC_RX_MSIX_ENTRY].VECTOR_CTRL = 0; // MASK=0, last
|
||||
MG_DSB();
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t mg_tcpip_driver_netc_tx(const void *buf, size_t len,
|
||||
struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_netc_data *d =
|
||||
(struct mg_tcpip_driver_netc_data *) ifp->driver_data;
|
||||
uint16_t next;
|
||||
s_tx_clean =
|
||||
(uint16_t) (NETC_ENETC1_SI0->BDR[0].TBCIR & 0xffffU); // BDR_INDEX
|
||||
next = (uint16_t) (s_tx_prod + 1U);
|
||||
if (next >= ETH_DESC_CNT) next = 0;
|
||||
if (len > sizeof(s_txbuf[0])) {
|
||||
MG_ERROR(("Frame too big, %ld", (long) len));
|
||||
len = (size_t) -1; // fail
|
||||
} else if (next == s_tx_clean) {
|
||||
ifp->nerr++;
|
||||
MG_ERROR(("No descriptors available"));
|
||||
len = 0; // retry later
|
||||
} else {
|
||||
memcpy(s_txbuf[s_tx_prod], buf, len); // Copy data
|
||||
s_txdesc[s_tx_prod].buffer_address =
|
||||
(uint64_t) (uintptr_t) s_txbuf[s_tx_prod];
|
||||
s_txdesc[s_tx_prod].buffer_length = (uint16_t) len; // BUFF_LEN
|
||||
s_txdesc[s_tx_prod].frame_length = (uint16_t) len; // FRAME_LEN
|
||||
s_txdesc[s_tx_prod].control =
|
||||
MG_BIT(31) | (2UL << 24) | MG_BIT(23) | ((uint32_t) d->link << 16);
|
||||
// F=1, FLQ=2, SMSO=1, EGR_PORT=link, IPV=0, DR=0
|
||||
MG_DSB();
|
||||
if (++s_tx_prod >= ETH_DESC_CNT) s_tx_prod = 0;
|
||||
NETC_ENETC1_SI0->BDR[0].TBPIR = s_tx_prod; // BDR_INDEX
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool mg_tcpip_driver_netc_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||
if (!s1) return false;
|
||||
struct mg_tcpip_driver_netc_data *d =
|
||||
(struct mg_tcpip_driver_netc_data *) ifp->driver_data;
|
||||
struct netc_port *switch_port = NETC_SW0_PORT(d->link);
|
||||
struct netc_eth_link *eth_link = NETC_SW0_ETH(d->link);
|
||||
uint8_t speed = MG_PHY_SPEED_10M;
|
||||
bool up, full_duplex = false;
|
||||
struct mg_phy phy = {enet_read_phy, enet_write_phy};
|
||||
|
||||
up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed);
|
||||
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) {
|
||||
uint16_t port_speed = speed == MG_PHY_SPEED_1000M ? 99U
|
||||
: speed == MG_PHY_SPEED_100M ? 9U
|
||||
: 0U;
|
||||
uint32_t config = switch_port->PCR;
|
||||
uint32_t mode = eth_link->PM[0].IF_MODE;
|
||||
config &= ~(0x3fffU << 16); // PCR[29:16] PSPEED
|
||||
config |= (uint32_t) port_speed << 16;
|
||||
mode &= ~(MG_BIT(14) | MG_BIT(13) | MG_BIT(6)); // SSP, HD
|
||||
if (speed == MG_PHY_SPEED_1000M) {
|
||||
mode |= MG_BIT(14); // SSP: 1 Gbps, full duplex
|
||||
} else {
|
||||
if (speed == MG_PHY_SPEED_10M) mode |= MG_BIT(13); // SSP
|
||||
if (!full_duplex) mode |= MG_BIT(6); // HD
|
||||
}
|
||||
switch_port->PCR = config;
|
||||
eth_link->PM[0].IF_MODE = mode;
|
||||
eth_link->PM[1].IF_MODE = mode;
|
||||
|
||||
// TX_CSD, RX_CSD, and SPD_DUP are latched while the PHY is reset/down.
|
||||
eth_link->PM[0].IEVENT = MG_BIT(23) | MG_BIT(22) | MG_BIT(21);
|
||||
MG_DSB();
|
||||
MG_DEBUG(("Link is %uM %s-duplex",
|
||||
speed == MG_PHY_SPEED_1000M ? 1000U
|
||||
: speed == MG_PHY_SPEED_100M ? 100U
|
||||
: 10U,
|
||||
full_duplex ? "full" : "half"));
|
||||
}
|
||||
return up;
|
||||
}
|
||||
|
||||
void MSGINTR1_IRQHandler(void);
|
||||
void MSGINTR1_IRQHandler(void) {
|
||||
if (NETC_MSGINTR1->MSI[0].MSIR & MG_BIT(NETC_RX_MSG_INDEX)) {
|
||||
NETC_ENETC1_SI0->SIRXIDR0 = MG_BIT(0); // RX0, W1C
|
||||
MG_DSB();
|
||||
for (int i = 0; i < 10; i++) { // Read as they arrive but not forever
|
||||
uint32_t status;
|
||||
size_t len;
|
||||
if (s_rx_cons ==
|
||||
(uint16_t) (NETC_ENETC1_SI0->BDR[0].RBPIR & 0xffffU))
|
||||
break;
|
||||
status = s_rxdesc[s_rx_cons].writeback.status;
|
||||
if (!(status & MG_BIT(30))) break; // R: writeback is ready
|
||||
len = s_rxdesc[s_rx_cons].writeback.buffer_length;
|
||||
if ((status & (MG_BIT(31) | MG_BIT(30))) ==
|
||||
(MG_BIT(31) | MG_BIT(30)) && // F, R
|
||||
!(status & (0xffU << 16)) && // ERROR
|
||||
!(status & (0xfU << 2)) && // HR=0: regular frame
|
||||
len > 0 && len <= sizeof(s_rxbuf[0])) {
|
||||
mg_tcpip_qwrite(s_rxbuf[s_rx_cons], len, s_ifp); // FCS stripped
|
||||
}
|
||||
s_rxdesc[s_rx_cons].descriptor.buffer_address =
|
||||
(uint64_t) (uintptr_t) s_rxbuf[s_rx_cons];
|
||||
s_rxdesc[s_rx_cons].descriptor.reserved = 0;
|
||||
MG_DSB();
|
||||
if (++s_rx_cons >= ETH_DESC_CNT) s_rx_cons = 0;
|
||||
NETC_ENETC1_SI0->BDR[0].RBCIR = s_rx_cons;
|
||||
}
|
||||
}
|
||||
MG_DSB();
|
||||
}
|
||||
|
||||
struct mg_tcpip_driver mg_tcpip_driver_netc = {mg_tcpip_driver_netc_init,
|
||||
mg_tcpip_driver_netc_tx, NULL,
|
||||
mg_tcpip_driver_netc_poll};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MG_ENABLE_LINES
|
||||
#line 1 "src/drivers/nxp_wifi.c"
|
||||
#endif
|
||||
@@ -28741,7 +29200,9 @@ enum { // ID1 ID2
|
||||
MG_PHY_RTL8201 = 0xc816, // 001c c816 - RTL8201F
|
||||
MG_PHY_RTL8211 = 0xc916, // 001c c916 - RTL8211F
|
||||
MG_PHY_ICS1894x = 0x15,
|
||||
MG_PHY_ICS189432 = 0xf450 // 0015 f450 - ICS1894
|
||||
MG_PHY_ICS189432 = 0xf450, // 0015 f450 - ICS1894
|
||||
MG_PHY_YT85x = 0x4f51,
|
||||
MG_PHY_YT8531 = 0xe91a // 4f51 e91a - Motorcomm YT8531
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -28759,7 +29220,10 @@ enum {
|
||||
MG_PHY_RTL82x_REG_PAGESEL = 31,
|
||||
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7
|
||||
MG_PHY_RTL8211_REG_PHYSR = 26, // in page a43
|
||||
MG_PHY_ICS189432_REG_POLL = 17
|
||||
MG_PHY_ICS189432_REG_POLL = 17,
|
||||
MG_PHY_YT8531_REG_PHYSTS = 17,
|
||||
MG_PHY_YT8531_REG_EXT_ADDR = 30,
|
||||
MG_PHY_YT8531_REG_EXT_DATA = 31
|
||||
};
|
||||
|
||||
static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
|
||||
@@ -28790,6 +29254,8 @@ static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
|
||||
}
|
||||
case MG_PHY_ICS1894x:
|
||||
return "ICS1894x";
|
||||
case MG_PHY_YT85x:
|
||||
return id2 == MG_PHY_YT8531 ? "YT8531" : "YT85x";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
@@ -28805,6 +29271,18 @@ void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
|
||||
id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2);
|
||||
MG_INFO(("PHY ID: %#04x %#04x (%s)", id1, id2, mg_phy_id_to_str(id1, id2)));
|
||||
|
||||
if (id1 == MG_PHY_YT85x && id2 == MG_PHY_YT8531) {
|
||||
uint16_t value;
|
||||
// TODO (robertc2000): Autonegotiation remains disabled after PHY is reset
|
||||
// We temporarily force enabling autoneg, until a workaround is found.
|
||||
phy->write_reg(phy_addr, MG_PHY_REG_BCR, MG_BIT(12));
|
||||
phy->write_reg(phy_addr, MG_PHY_YT8531_REG_EXT_ADDR, 0xa003);
|
||||
value = phy->read_reg(phy_addr, MG_PHY_YT8531_REG_EXT_DATA);
|
||||
value &= (uint16_t) ~(MG_BIT(3) | MG_BIT(2) | MG_BIT(1) | MG_BIT(0));
|
||||
phy->write_reg(phy_addr, MG_PHY_YT8531_REG_EXT_DATA,
|
||||
(uint16_t) (value | MG_BIT(1))); // TXDLY: 2 * 150 ps
|
||||
}
|
||||
|
||||
if (id1 == MG_PHY_DP83x && id2 == MG_PHY_DP83867) {
|
||||
phy->write_reg(phy_addr, 0x0d, 0x1f); // write 0x10d to IO_MUX_CFG (0x0170)
|
||||
phy->write_reg(phy_addr, 0x0e, 0x170);
|
||||
@@ -28898,6 +29376,15 @@ bool mg_phy_up(struct mg_phy *phy, uint8_t phy_addr, bool *full_duplex,
|
||||
uint16_t poll_reg = phy->read_reg(phy_addr, MG_PHY_ICS189432_REG_POLL);
|
||||
*full_duplex = poll_reg & MG_BIT(14);
|
||||
*speed = (poll_reg & MG_BIT(15)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
|
||||
} else if (id1 == MG_PHY_YT85x) {
|
||||
uint16_t id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2);
|
||||
if (id2 == MG_PHY_YT8531) {
|
||||
uint16_t physts = phy->read_reg(phy_addr, MG_PHY_YT8531_REG_PHYSTS);
|
||||
*full_duplex = physts & MG_BIT(13);
|
||||
*speed = (physts & MG_BIT(15)) ? MG_PHY_SPEED_1000M
|
||||
: (physts & MG_BIT(14)) ? MG_PHY_SPEED_100M
|
||||
: MG_PHY_SPEED_10M;
|
||||
}
|
||||
}
|
||||
}
|
||||
return up;
|
||||
|
||||
+50
@@ -5111,6 +5111,7 @@ extern struct mg_tcpip_driver mg_tcpip_driver_cyw;
|
||||
extern struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi;
|
||||
extern struct mg_tcpip_driver mg_tcpip_driver_st67w6;
|
||||
extern struct mg_tcpip_driver mg_tcpip_driver_atcmd;
|
||||
extern struct mg_tcpip_driver mg_tcpip_driver_netc;
|
||||
|
||||
// SPI bus abstraction for SPI-attached network chips (e.g. W5500).
|
||||
// Populate and assign to the driver's driver_data field.
|
||||
@@ -5455,6 +5456,55 @@ struct mg_tcpip_driver_imxrt_data {
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP && \
|
||||
defined(MG_ENABLE_DRIVER_NETC) && MG_ENABLE_DRIVER_NETC
|
||||
|
||||
struct mg_tcpip_driver_netc_data {
|
||||
int mdc_cr;
|
||||
uint8_t phy_addr;
|
||||
|
||||
// Selects the physical Ethernet link (ETH0 through ETH3)
|
||||
// Its switch port is bridged to pseudo-port 4,
|
||||
// which connects internally to ENETC1
|
||||
// IMXRT1180 RM 53.4.1.1 NETC Block diagram
|
||||
uint8_t link;
|
||||
};
|
||||
|
||||
#ifndef MG_TCPIP_PHY_ADDR
|
||||
#define MG_TCPIP_PHY_ADDR 5
|
||||
#endif
|
||||
|
||||
#ifndef MG_DRIVER_MDC_CR
|
||||
#define MG_DRIVER_MDC_CR 48
|
||||
#endif
|
||||
|
||||
#ifndef MG_TCPIP_NETC_LINK
|
||||
#define MG_TCPIP_NETC_LINK 0
|
||||
#endif
|
||||
|
||||
struct mg_tcpip_driver;
|
||||
extern struct mg_tcpip_driver mg_tcpip_driver_netc;
|
||||
|
||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||
do { \
|
||||
static struct mg_tcpip_driver_netc_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; \
|
||||
driver_data_.link = MG_TCPIP_NETC_LINK; \
|
||||
mif_.ip = MG_TCPIP_IP; \
|
||||
mif_.mask = MG_TCPIP_MASK; \
|
||||
mif_.gw = MG_TCPIP_GW; \
|
||||
mif_.driver = &mg_tcpip_driver_netc; \
|
||||
mif_.driver_data = &driver_data_; \
|
||||
MG_SET_MAC_ADDRESS(mif_.mac); \
|
||||
mg_tcpip_init(mgr, &mif_); \
|
||||
MG_INFO(("Driver: netc, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if MG_ENABLE_TCPIP && \
|
||||
defined(MG_ENABLE_DRIVER_NXP_WIFI) && MG_ENABLE_DRIVER_NXP_WIFI
|
||||
|
||||
|
||||
@@ -0,0 +1,455 @@
|
||||
#include "net_builtin.h"
|
||||
|
||||
#if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP && \
|
||||
defined(MG_ENABLE_DRIVER_NETC) && MG_ENABLE_DRIVER_NETC
|
||||
|
||||
// IMXRT1180 RM - Chapter 53 - Ethernet Controller (NETC)
|
||||
|
||||
#define ETH_DESC_CNT 8 // Descriptor count must be multiple of 8 (53.4.6.11.97)
|
||||
#define ETH_PKT_SIZE 1536
|
||||
|
||||
struct netc_pci_function { // 53.4.6.1.1
|
||||
volatile uint32_t DID_VID;
|
||||
volatile uint16_t CMD, STAT;
|
||||
volatile uint8_t reserved0[0x40];
|
||||
volatile uint16_t DEV_CTL, DEV_STAT;
|
||||
volatile uint8_t reserved1[0x34];
|
||||
volatile uint16_t MSIX_CAP_LIST, MSIX_MSG_CTL;
|
||||
};
|
||||
|
||||
struct netc_emdio { // 53.4.6.12
|
||||
volatile uint32_t EMDIO_CFG, EMDIO_CTL, EMDIO_DATA, EMDIO_ADDR, EMDIO_STAT;
|
||||
};
|
||||
|
||||
struct netc_enetc { // 53.4.6.6
|
||||
volatile uint32_t ECAPR0, ECAPR1, ECAPR2, reserved0, PMR;
|
||||
volatile uint8_t reserved1[0x1ec];
|
||||
volatile uint32_t PSIPMMR, PSIPVMR;
|
||||
volatile uint8_t reserved2[0x5f8];
|
||||
volatile uint32_t SMCAPR;
|
||||
volatile uint8_t reserved3[0x17fc];
|
||||
struct {
|
||||
volatile uint32_t PSIPMAR0, PSIPMAR1, PSIVLANR, reserved0, PSICFGR0,
|
||||
PSICFGR1, PSICFGR2;
|
||||
volatile uint8_t reserved1[0x64];
|
||||
} PSI[1];
|
||||
};
|
||||
|
||||
struct netc_port { // 53.4.6.8
|
||||
volatile uint32_t PCAPR, PMCAPR, PIOCAPR, reserved0, PCR;
|
||||
volatile uint8_t reserved1[0x0c];
|
||||
volatile uint32_t PMAR0, PMAR1;
|
||||
volatile uint8_t reserved2[0xd8];
|
||||
volatile uint32_t POR, PSR;
|
||||
volatile uint8_t reserved3[0x30];
|
||||
volatile uint32_t PDGSR;
|
||||
volatile uint8_t reserved4[0xc4];
|
||||
struct {
|
||||
volatile uint32_t PTGSTCSR, reserved0, PTCTMSDUR, reserved1, PTCCBSR0,
|
||||
PTCCBSR1;
|
||||
volatile uint8_t reserved2[8];
|
||||
} TCT[8];
|
||||
volatile uint8_t reserved5[0x220];
|
||||
volatile uint32_t BPSTGSR;
|
||||
};
|
||||
|
||||
struct netc_port_mac { // 53.4.6.9
|
||||
volatile uint8_t reserved0[8];
|
||||
volatile uint32_t COMMAND_CONFIG, MAC_ADDR_0, MAC_ADDR_1, MAXFRM, MINFRM;
|
||||
volatile uint8_t reserved1[0x24];
|
||||
volatile uint32_t IEVENT;
|
||||
volatile uint8_t reserved2[0x1dc];
|
||||
volatile uint64_t TFRMN;
|
||||
volatile uint8_t reserved3[0xd8];
|
||||
volatile uint32_t IF_MODE;
|
||||
volatile uint8_t reserved4[0xfc];
|
||||
};
|
||||
|
||||
struct netc_eth_link {
|
||||
struct netc_port_mac PM[2];
|
||||
};
|
||||
|
||||
struct netc_pseudo_link {
|
||||
volatile uint32_t PPMSR;
|
||||
volatile uint8_t reserved0[0x0c];
|
||||
volatile uint32_t PPMCR;
|
||||
};
|
||||
|
||||
struct netc_switch { // 53.4.6.5
|
||||
volatile uint8_t reserved0[0x400];
|
||||
volatile uint32_t MPCR;
|
||||
volatile uint8_t reserved1[0x1c0c];
|
||||
volatile uint32_t VFHTDECR0, VFHTDECR1, VFHTDECR2;
|
||||
};
|
||||
|
||||
struct netc_bdr {
|
||||
volatile uint32_t TBMR, TBSR;
|
||||
volatile uint8_t reserved0[8];
|
||||
volatile uint32_t TBBAR0, TBBAR1, TBPIR, TBCIR, TBLENR;
|
||||
volatile uint8_t reserved1[0x7c];
|
||||
volatile uint32_t TBIER, TBIDR, TBICR0, TBICR1;
|
||||
volatile uint8_t reserved2[0x50];
|
||||
volatile uint32_t RBMR, RBSR, RBBSR, RBCIR, RBBAR0, RBBAR1, RBPIR,
|
||||
reserved3, RBLENR;
|
||||
volatile uint8_t reserved4[0x5c];
|
||||
volatile uint32_t RBDCR;
|
||||
volatile uint8_t reserved5[0x1c];
|
||||
volatile uint32_t RBIER, RBIDR, RBICR0, RBICR1;
|
||||
volatile uint8_t reserved6[0x50];
|
||||
};
|
||||
|
||||
struct netc_si { // 53.4.6.11
|
||||
volatile uint32_t SIMR, SISR;
|
||||
volatile uint8_t reserved0[0x30];
|
||||
volatile uint32_t SIRBGCR;
|
||||
volatile uint8_t reserved1[0x2ec];
|
||||
volatile uint32_t SITFRM0;
|
||||
volatile uint8_t reserved2[0x6fc];
|
||||
volatile uint32_t SIRXIDR0;
|
||||
volatile uint8_t reserved3[0x154];
|
||||
volatile uint32_t SIMSIRRVR[1];
|
||||
volatile uint8_t reserved4[0x747c];
|
||||
struct netc_bdr BDR[1];
|
||||
};
|
||||
|
||||
struct netc_msix_entry { // 53.4.2.11
|
||||
volatile uint32_t MSG_ADDR, MSG_UPPER_ADDR, MSG_DATA, VECTOR_CTRL;
|
||||
};
|
||||
|
||||
struct netc_msgintr { // 54.4
|
||||
struct {
|
||||
volatile uint32_t MSIIR, MSIR;
|
||||
} MSI[3];
|
||||
};
|
||||
|
||||
#define NETC_EMDIO_PCI \
|
||||
((struct netc_pci_function *) (uintptr_t) 0x60001000U)
|
||||
#define NETC_SWITCH_PCI \
|
||||
((struct netc_pci_function *) (uintptr_t) 0x60002000U)
|
||||
#define NETC_ENETC1_PCI \
|
||||
((struct netc_pci_function *) (uintptr_t) 0x60004000U)
|
||||
#define NETC_EMDIO ((struct netc_emdio *) (uintptr_t) 0x60ba1c00U)
|
||||
|
||||
#define NETC_ENETC1 ((struct netc_enetc *) (uintptr_t) 0x60b50000U)
|
||||
#define NETC_ENETC1_PORT ((struct netc_port *) (uintptr_t) 0x60b54000U)
|
||||
#define NETC_ENETC1_PSEUDO_LINK \
|
||||
((struct netc_pseudo_link *) (uintptr_t) 0x60b55000U)
|
||||
#define NETC_ENETC1_SI0 ((struct netc_si *) (uintptr_t) 0x60b40000U)
|
||||
#define NETC_ENETC1_MSIX \
|
||||
((struct netc_msix_entry *) (uintptr_t) 0x60c00000U)
|
||||
|
||||
#define NETC_SWITCH ((struct netc_switch *) (uintptr_t) 0x60a00000U)
|
||||
#define NETC_SW0_PORT(link) \
|
||||
((struct netc_port *) (uintptr_t) (0x60a04000U + \
|
||||
(uint32_t) (link) * 0x4000U))
|
||||
#define NETC_SW0_ETH(link) \
|
||||
((struct netc_eth_link *) (uintptr_t) (0x60a05000U + \
|
||||
(uint32_t) (link) * 0x4000U))
|
||||
#define NETC_SW0_PORT4 ((struct netc_port *) (uintptr_t) 0x60a14000U)
|
||||
#define NETC_MSGINTR1 \
|
||||
((struct netc_msgintr *) (uintptr_t) 0x428a0000U)
|
||||
|
||||
enum {
|
||||
NETC_RX_MSIX_ENTRY = 0,
|
||||
NETC_RX_MSG_INDEX = 2,
|
||||
};
|
||||
|
||||
struct netc_tx_bd {
|
||||
uint64_t buffer_address;
|
||||
uint16_t buffer_length, frame_length;
|
||||
uint32_t control;
|
||||
};
|
||||
|
||||
struct netc_rx_descriptor {
|
||||
uint64_t buffer_address, reserved;
|
||||
};
|
||||
|
||||
struct netc_rx_writeback {
|
||||
uint16_t internet_checksum, parser_summary;
|
||||
uint32_t rss_hash;
|
||||
uint16_t buffer_length, vlan;
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
union netc_rx_bd {
|
||||
struct netc_rx_descriptor descriptor;
|
||||
struct netc_rx_writeback writeback;
|
||||
};
|
||||
|
||||
static volatile struct netc_tx_bd s_txdesc[ETH_DESC_CNT] MG_ETH_RAM
|
||||
__attribute__((aligned(128)));
|
||||
static volatile union netc_rx_bd s_rxdesc[ETH_DESC_CNT] MG_ETH_RAM
|
||||
__attribute__((aligned(128)));
|
||||
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM
|
||||
__attribute__((aligned(64)));
|
||||
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE] MG_ETH_RAM
|
||||
__attribute__((aligned(64)));
|
||||
|
||||
static uint16_t s_tx_prod;
|
||||
static uint16_t s_tx_clean;
|
||||
static uint16_t s_rx_cons;
|
||||
static struct mg_tcpip_if *s_ifp;
|
||||
|
||||
static uint16_t enet_read_phy(uint8_t addr, uint8_t reg) {
|
||||
NETC_EMDIO->EMDIO_CFG &= ~MG_BIT(6); // ENC45: use Clause 22
|
||||
NETC_EMDIO->EMDIO_CTL = MG_BIT(15) | ((uint32_t) (addr & 0x1fU) << 5) |
|
||||
(reg & 0x1fU); // READ, PORT_ADDR, DEV_ADDR
|
||||
while (NETC_EMDIO->EMDIO_CFG & MG_BIT(31)) (void) 0; // BSY1
|
||||
return (uint16_t) (NETC_EMDIO->EMDIO_DATA & 0xffffU);
|
||||
}
|
||||
|
||||
static void enet_write_phy(uint8_t addr, uint8_t reg, uint16_t value) {
|
||||
NETC_EMDIO->EMDIO_CFG &= ~MG_BIT(6); // ENC45: use Clause 22
|
||||
NETC_EMDIO->EMDIO_CTL = ((uint32_t) (addr & 0x1fU) << 5) |
|
||||
(reg & 0x1fU); // PORT_ADDR, DEV_ADDR
|
||||
NETC_EMDIO->EMDIO_DATA = value;
|
||||
while (NETC_EMDIO->EMDIO_CFG & MG_BIT(31)) (void) 0; // BSY1
|
||||
}
|
||||
|
||||
static bool mg_tcpip_driver_netc_init(struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_netc_data *d =
|
||||
(struct mg_tcpip_driver_netc_data *) ifp->driver_data;
|
||||
struct mg_phy phy = {enet_read_phy, enet_write_phy};
|
||||
struct netc_port *switch_port;
|
||||
struct netc_eth_link *eth_link;
|
||||
uint64_t tx_base = (uint64_t) (uintptr_t) s_txdesc;
|
||||
uint64_t rx_base = (uint64_t) (uintptr_t) s_rxdesc;
|
||||
uint32_t mac0 = (uint32_t) ifp->mac[0] |
|
||||
((uint32_t) ifp->mac[1] << 8) |
|
||||
((uint32_t) ifp->mac[2] << 16) |
|
||||
((uint32_t) ifp->mac[3] << 24);
|
||||
uint32_t mac1 = (uint32_t) ifp->mac[4] |
|
||||
((uint32_t) ifp->mac[5] << 8);
|
||||
uint32_t mdc_cr =
|
||||
(uint32_t) (d->mdc_cr < 0 ? MG_DRIVER_MDC_CR : d->mdc_cr);
|
||||
|
||||
switch_port = NETC_SW0_PORT(d->link);
|
||||
eth_link = NETC_SW0_ETH(d->link);
|
||||
s_ifp = ifp;
|
||||
for (int i = 0; i < ETH_DESC_CNT; i++) {
|
||||
s_txdesc[i].buffer_address = (uint64_t) (uintptr_t) s_txbuf[i];
|
||||
s_rxdesc[i].descriptor.buffer_address =
|
||||
(uint64_t) (uintptr_t) s_rxbuf[i];
|
||||
}
|
||||
|
||||
NETC_EMDIO_PCI->DEV_CTL |= MG_BIT(15); // INIT_FLR
|
||||
while (NETC_EMDIO_PCI->DEV_CTL & MG_BIT(15)) (void) 0;
|
||||
NETC_EMDIO_PCI->CMD |= MG_BIT(2) | MG_BIT(1); // BUS_MASTER_EN, MEM_ACCESS
|
||||
NETC_EMDIO->EMDIO_CFG =
|
||||
((mdc_cr & 0x1ffU) << 7) | MG_BIT(2); // MDIO_CLK_DIV, MDIO_HOLD
|
||||
mg_phy_init(&phy, d->phy_addr, 0);
|
||||
|
||||
// Initialize ENETC1 PSI0 and port
|
||||
NETC_ENETC1_PCI->CMD |= MG_BIT(2) | MG_BIT(1); // BUS_MASTER_EN, MEM_ACCESS
|
||||
NETC_ENETC1_PCI->MSIX_MSG_CTL = MG_BIT(14); // FUNC_MASK
|
||||
NETC_ENETC1_PORT->POR |= MG_BIT(1) | MG_BIT(0); // RXDIS, TXDIS
|
||||
NETC_ENETC1_PCI->DEV_CTL |= MG_BIT(15); // INIT_FLR
|
||||
while (NETC_ENETC1_PCI->DEV_CTL & MG_BIT(15)) (void) 0;
|
||||
NETC_ENETC1_PCI->CMD |= MG_BIT(2) | MG_BIT(1); // BUS_MASTER_EN, MEM_ACCESS
|
||||
NETC_ENETC1_PCI->MSIX_MSG_CTL = MG_BIT(14); // FUNC_MASK
|
||||
NETC_ENETC1_PORT->PCR = 99U << 16; // PSPEED: 1 Gbps
|
||||
NETC_ENETC1_PORT->PMAR0 = mac0;
|
||||
NETC_ENETC1_PORT->PMAR1 = mac1;
|
||||
NETC_ENETC1_PSEUDO_LINK->PPMCR = MG_BIT(16); // TXPAD
|
||||
NETC_ENETC1->PSIPMMR &= ~(MG_BIT(16) | MG_BIT(0));
|
||||
NETC_ENETC1_SI0->SIMR &=
|
||||
~(MG_BIT(31) | MG_BIT(3) | MG_BIT(2) | MG_BIT(1));
|
||||
NETC_ENETC1_SI0->SIRBGCR = 0;
|
||||
NETC_ENETC1->PSI[0].PSICFGR0 =
|
||||
MG_BIT(16) | MG_BIT(0); // one Rx BDR, one Tx BDR
|
||||
|
||||
NETC_ENETC1->PSI[0].PSICFGR2 = 0; // NUM_MSIX: one entry
|
||||
NETC_ENETC1_MSIX[NETC_RX_MSIX_ENTRY].VECTOR_CTRL = MG_BIT(0); // MASK
|
||||
NETC_ENETC1_MSIX[NETC_RX_MSIX_ENTRY].MSG_ADDR =
|
||||
(uint32_t) (uintptr_t) &NETC_MSGINTR1->MSI[0].MSIIR;
|
||||
NETC_ENETC1_MSIX[NETC_RX_MSIX_ENTRY].MSG_UPPER_ADDR = 0;
|
||||
NETC_ENETC1_MSIX[NETC_RX_MSIX_ENTRY].MSG_DATA = NETC_RX_MSG_INDEX;
|
||||
NETC_ENETC1_SI0->SIMSIRRVR[0] = NETC_RX_MSIX_ENTRY; // Rx ring 0 -> entry 0
|
||||
|
||||
// Initialize switch function 2 to drive the selected physical port
|
||||
NETC_SWITCH_PCI->CMD |= MG_BIT(2) | MG_BIT(1);
|
||||
NETC_SWITCH_PCI->MSIX_MSG_CTL = MG_BIT(14); // FUNC_MASK
|
||||
switch_port->POR |= MG_BIT(1) | MG_BIT(0);
|
||||
eth_link->PM[0].COMMAND_CONFIG |= MG_BIT(26); // SWR
|
||||
while (eth_link->PM[0].COMMAND_CONFIG & MG_BIT(26)) (void) 0;
|
||||
eth_link->PM[1].COMMAND_CONFIG |= MG_BIT(26); // SWR
|
||||
while (eth_link->PM[1].COMMAND_CONFIG & MG_BIT(26)) (void) 0;
|
||||
NETC_SWITCH_PCI->DEV_CTL |= MG_BIT(15); // INIT_FLR
|
||||
while (NETC_SWITCH_PCI->DEV_CTL & MG_BIT(15)) (void) 0;
|
||||
NETC_SWITCH_PCI->CMD |= MG_BIT(2) | MG_BIT(1);
|
||||
NETC_SWITCH_PCI->MSIX_MSG_CTL = MG_BIT(14); // FUNC_MASK
|
||||
|
||||
// Configure switch physical port and ethernet link (ETH_X)
|
||||
switch_port->PCR = 99U << 16; // PSPEED: 1 Gbps
|
||||
switch_port->PMAR0 = mac0;
|
||||
switch_port->PMAR1 = mac1;
|
||||
switch_port->TCT[0].PTCTMSDUR = MG_BIT(24) | MG_BIT(16) | ETH_PKT_SIZE;
|
||||
eth_link->PM[0].MAXFRM = ETH_PKT_SIZE;
|
||||
eth_link->PM[0].MINFRM = 64;
|
||||
eth_link->PM[0].IF_MODE = MG_BIT(14) | 4U; // 1G RGMII
|
||||
eth_link->PM[0].COMMAND_CONFIG =
|
||||
MG_BIT(15) | MG_BIT(1) | MG_BIT(0); // TXP, RX_EN, TX_EN
|
||||
eth_link->PM[1].MAXFRM = ETH_PKT_SIZE;
|
||||
eth_link->PM[1].MINFRM = 64;
|
||||
eth_link->PM[1].IF_MODE = MG_BIT(14) | 4U;
|
||||
eth_link->PM[1].COMMAND_CONFIG =
|
||||
MG_BIT(15) | MG_BIT(1) | MG_BIT(0);
|
||||
|
||||
// Bridge the selected physical port with management port 4 (54.4.1.1)
|
||||
NETC_SWITCH->VFHTDECR0 = MG_BIT(4) | MG_BIT(d->link);
|
||||
NETC_SWITCH->VFHTDECR2 = (1UL << 27) | (1UL << 24); // MFO=1, MLO=1
|
||||
switch_port->BPSTGSR = 2U; // STG0: forwarding
|
||||
NETC_SW0_PORT4->BPSTGSR = 2U; // STG0: forwarding
|
||||
switch_port->POR &= ~(MG_BIT(1) | MG_BIT(0));
|
||||
NETC_SW0_PORT4->POR &= ~(MG_BIT(1) | MG_BIT(0));
|
||||
|
||||
// Initialize Tx BD ring 0 (direct switch enqueue)
|
||||
NETC_ENETC1_SI0->BDR[0].TBBAR0 = (uint32_t) tx_base;
|
||||
NETC_ENETC1_SI0->BDR[0].TBBAR1 = (uint32_t) (tx_base >> 32);
|
||||
NETC_ENETC1_SI0->BDR[0].TBLENR = ETH_DESC_CNT;
|
||||
|
||||
// Initialize Rx BD ring 0
|
||||
NETC_ENETC1_SI0->BDR[0].RBICR0 =
|
||||
MG_BIT(31) | MG_BIT(0); // ICEN, interrupt after one frame
|
||||
NETC_ENETC1_SI0->BDR[0].RBBAR0 = (uint32_t) rx_base;
|
||||
NETC_ENETC1_SI0->BDR[0].RBBAR1 = (uint32_t) (rx_base >> 32);
|
||||
NETC_ENETC1_SI0->BDR[0].RBBSR = ETH_PKT_SIZE;
|
||||
NETC_ENETC1_SI0->BDR[0].RBLENR = ETH_DESC_CNT;
|
||||
|
||||
// Clear stale device and MSGINTR state before the ring becomes active
|
||||
NETC_ENETC1_SI0->SIRXIDR0 = MG_BIT(0); // RX0, W1C
|
||||
(void) NETC_MSGINTR1->MSI[0].MSIR; // clear pending messages
|
||||
NETC_ENETC1_SI0->BDR[0].RBIER = MG_BIT(0); // RXTIE
|
||||
NETC_ENETC1_SI0->BDR[0].TBMR = MG_BIT(31);
|
||||
NETC_ENETC1_SI0->BDR[0].RBMR = MG_BIT(31); // EN, CRC=0: strip FCS
|
||||
NETC_ENETC1_PORT->POR &= ~(MG_BIT(1) | MG_BIT(0));
|
||||
NETC_ENETC1->PMR |= MG_BIT(16); // SI0EN
|
||||
NETC_ENETC1_SI0->SIMR |= MG_BIT(31); // EN
|
||||
MG_DSB();
|
||||
if ((NETC_ENETC1->SMCAPR & MG_BIT(0)) == 0U ||
|
||||
(NETC_SWITCH->MPCR & 0x1fU) != 4U) {
|
||||
MG_ERROR(("NETC fixed management path unavailable: SMCAPR=%08lx MPCR=%08lx",
|
||||
(unsigned long) NETC_ENETC1->SMCAPR,
|
||||
(unsigned long) NETC_SWITCH->MPCR));
|
||||
return false;
|
||||
}
|
||||
|
||||
NETC_ENETC1_PCI->MSIX_MSG_CTL =
|
||||
MG_BIT(15); // Enable RX interrupt, MSIX_EN=1, FUNC_MASK=0
|
||||
MG_DSB();
|
||||
NETC_ENETC1_MSIX[NETC_RX_MSIX_ENTRY].VECTOR_CTRL = 0; // MASK=0, last
|
||||
MG_DSB();
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t mg_tcpip_driver_netc_tx(const void *buf, size_t len,
|
||||
struct mg_tcpip_if *ifp) {
|
||||
struct mg_tcpip_driver_netc_data *d =
|
||||
(struct mg_tcpip_driver_netc_data *) ifp->driver_data;
|
||||
uint16_t next;
|
||||
s_tx_clean =
|
||||
(uint16_t) (NETC_ENETC1_SI0->BDR[0].TBCIR & 0xffffU); // BDR_INDEX
|
||||
next = (uint16_t) (s_tx_prod + 1U);
|
||||
if (next >= ETH_DESC_CNT) next = 0;
|
||||
if (len > sizeof(s_txbuf[0])) {
|
||||
MG_ERROR(("Frame too big, %ld", (long) len));
|
||||
len = (size_t) -1; // fail
|
||||
} else if (next == s_tx_clean) {
|
||||
ifp->nerr++;
|
||||
MG_ERROR(("No descriptors available"));
|
||||
len = 0; // retry later
|
||||
} else {
|
||||
memcpy(s_txbuf[s_tx_prod], buf, len); // Copy data
|
||||
s_txdesc[s_tx_prod].buffer_address =
|
||||
(uint64_t) (uintptr_t) s_txbuf[s_tx_prod];
|
||||
s_txdesc[s_tx_prod].buffer_length = (uint16_t) len; // BUFF_LEN
|
||||
s_txdesc[s_tx_prod].frame_length = (uint16_t) len; // FRAME_LEN
|
||||
s_txdesc[s_tx_prod].control =
|
||||
MG_BIT(31) | (2UL << 24) | MG_BIT(23) | ((uint32_t) d->link << 16);
|
||||
// F=1, FLQ=2, SMSO=1, EGR_PORT=link, IPV=0, DR=0
|
||||
MG_DSB();
|
||||
if (++s_tx_prod >= ETH_DESC_CNT) s_tx_prod = 0;
|
||||
NETC_ENETC1_SI0->BDR[0].TBPIR = s_tx_prod; // BDR_INDEX
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool mg_tcpip_driver_netc_poll(struct mg_tcpip_if *ifp, bool s1) {
|
||||
if (!s1) return false;
|
||||
struct mg_tcpip_driver_netc_data *d =
|
||||
(struct mg_tcpip_driver_netc_data *) ifp->driver_data;
|
||||
struct netc_port *switch_port = NETC_SW0_PORT(d->link);
|
||||
struct netc_eth_link *eth_link = NETC_SW0_ETH(d->link);
|
||||
uint8_t speed = MG_PHY_SPEED_10M;
|
||||
bool up, full_duplex = false;
|
||||
struct mg_phy phy = {enet_read_phy, enet_write_phy};
|
||||
|
||||
up = mg_phy_up(&phy, d->phy_addr, &full_duplex, &speed);
|
||||
if ((ifp->state == MG_TCPIP_STATE_DOWN) && up) {
|
||||
uint16_t port_speed = speed == MG_PHY_SPEED_1000M ? 99U
|
||||
: speed == MG_PHY_SPEED_100M ? 9U
|
||||
: 0U;
|
||||
uint32_t config = switch_port->PCR;
|
||||
uint32_t mode = eth_link->PM[0].IF_MODE;
|
||||
config &= ~(0x3fffU << 16); // PCR[29:16] PSPEED
|
||||
config |= (uint32_t) port_speed << 16;
|
||||
mode &= ~(MG_BIT(14) | MG_BIT(13) | MG_BIT(6)); // SSP, HD
|
||||
if (speed == MG_PHY_SPEED_1000M) {
|
||||
mode |= MG_BIT(14); // SSP: 1 Gbps, full duplex
|
||||
} else {
|
||||
if (speed == MG_PHY_SPEED_10M) mode |= MG_BIT(13); // SSP
|
||||
if (!full_duplex) mode |= MG_BIT(6); // HD
|
||||
}
|
||||
switch_port->PCR = config;
|
||||
eth_link->PM[0].IF_MODE = mode;
|
||||
eth_link->PM[1].IF_MODE = mode;
|
||||
|
||||
// TX_CSD, RX_CSD, and SPD_DUP are latched while the PHY is reset/down.
|
||||
eth_link->PM[0].IEVENT = MG_BIT(23) | MG_BIT(22) | MG_BIT(21);
|
||||
MG_DSB();
|
||||
MG_DEBUG(("Link is %uM %s-duplex",
|
||||
speed == MG_PHY_SPEED_1000M ? 1000U
|
||||
: speed == MG_PHY_SPEED_100M ? 100U
|
||||
: 10U,
|
||||
full_duplex ? "full" : "half"));
|
||||
}
|
||||
return up;
|
||||
}
|
||||
|
||||
void MSGINTR1_IRQHandler(void);
|
||||
void MSGINTR1_IRQHandler(void) {
|
||||
if (NETC_MSGINTR1->MSI[0].MSIR & MG_BIT(NETC_RX_MSG_INDEX)) {
|
||||
NETC_ENETC1_SI0->SIRXIDR0 = MG_BIT(0); // RX0, W1C
|
||||
MG_DSB();
|
||||
for (int i = 0; i < 10; i++) { // Read as they arrive but not forever
|
||||
uint32_t status;
|
||||
size_t len;
|
||||
if (s_rx_cons ==
|
||||
(uint16_t) (NETC_ENETC1_SI0->BDR[0].RBPIR & 0xffffU))
|
||||
break;
|
||||
status = s_rxdesc[s_rx_cons].writeback.status;
|
||||
if (!(status & MG_BIT(30))) break; // R: writeback is ready
|
||||
len = s_rxdesc[s_rx_cons].writeback.buffer_length;
|
||||
if ((status & (MG_BIT(31) | MG_BIT(30))) ==
|
||||
(MG_BIT(31) | MG_BIT(30)) && // F, R
|
||||
!(status & (0xffU << 16)) && // ERROR
|
||||
!(status & (0xfU << 2)) && // HR=0: regular frame
|
||||
len > 0 && len <= sizeof(s_rxbuf[0])) {
|
||||
mg_tcpip_qwrite(s_rxbuf[s_rx_cons], len, s_ifp); // FCS stripped
|
||||
}
|
||||
s_rxdesc[s_rx_cons].descriptor.buffer_address =
|
||||
(uint64_t) (uintptr_t) s_rxbuf[s_rx_cons];
|
||||
s_rxdesc[s_rx_cons].descriptor.reserved = 0;
|
||||
MG_DSB();
|
||||
if (++s_rx_cons >= ETH_DESC_CNT) s_rx_cons = 0;
|
||||
NETC_ENETC1_SI0->BDR[0].RBCIR = s_rx_cons;
|
||||
}
|
||||
}
|
||||
MG_DSB();
|
||||
}
|
||||
|
||||
struct mg_tcpip_driver mg_tcpip_driver_netc = {mg_tcpip_driver_netc_init,
|
||||
mg_tcpip_driver_netc_tx, NULL,
|
||||
mg_tcpip_driver_netc_poll};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP && \
|
||||
defined(MG_ENABLE_DRIVER_NETC) && MG_ENABLE_DRIVER_NETC
|
||||
|
||||
struct mg_tcpip_driver_netc_data {
|
||||
int mdc_cr;
|
||||
uint8_t phy_addr;
|
||||
|
||||
// Selects the physical Ethernet link (ETH0 through ETH3)
|
||||
// Its switch port is bridged to pseudo-port 4,
|
||||
// which connects internally to ENETC1
|
||||
// IMXRT1180 RM 53.4.1.1 NETC Block diagram
|
||||
uint8_t link;
|
||||
};
|
||||
|
||||
#ifndef MG_TCPIP_PHY_ADDR
|
||||
#define MG_TCPIP_PHY_ADDR 5
|
||||
#endif
|
||||
|
||||
#ifndef MG_DRIVER_MDC_CR
|
||||
#define MG_DRIVER_MDC_CR 48
|
||||
#endif
|
||||
|
||||
#ifndef MG_TCPIP_NETC_LINK
|
||||
#define MG_TCPIP_NETC_LINK 0
|
||||
#endif
|
||||
|
||||
struct mg_tcpip_driver;
|
||||
extern struct mg_tcpip_driver mg_tcpip_driver_netc;
|
||||
|
||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||
do { \
|
||||
static struct mg_tcpip_driver_netc_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; \
|
||||
driver_data_.link = MG_TCPIP_NETC_LINK; \
|
||||
mif_.ip = MG_TCPIP_IP; \
|
||||
mif_.mask = MG_TCPIP_MASK; \
|
||||
mif_.gw = MG_TCPIP_GW; \
|
||||
mif_.driver = &mg_tcpip_driver_netc; \
|
||||
mif_.driver_data = &driver_data_; \
|
||||
MG_SET_MAC_ADDRESS(mif_.mac); \
|
||||
mg_tcpip_init(mgr, &mif_); \
|
||||
MG_INFO(("Driver: netc, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
+30
-2
@@ -11,7 +11,9 @@ enum { // ID1 ID2
|
||||
MG_PHY_RTL8201 = 0xc816, // 001c c816 - RTL8201F
|
||||
MG_PHY_RTL8211 = 0xc916, // 001c c916 - RTL8211F
|
||||
MG_PHY_ICS1894x = 0x15,
|
||||
MG_PHY_ICS189432 = 0xf450 // 0015 f450 - ICS1894
|
||||
MG_PHY_ICS189432 = 0xf450, // 0015 f450 - ICS1894
|
||||
MG_PHY_YT85x = 0x4f51,
|
||||
MG_PHY_YT8531 = 0xe91a // 4f51 e91a - Motorcomm YT8531
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -29,7 +31,10 @@ enum {
|
||||
MG_PHY_RTL82x_REG_PAGESEL = 31,
|
||||
MG_PHY_RTL8201_REG_RMSR = 16, // in page 7
|
||||
MG_PHY_RTL8211_REG_PHYSR = 26, // in page a43
|
||||
MG_PHY_ICS189432_REG_POLL = 17
|
||||
MG_PHY_ICS189432_REG_POLL = 17,
|
||||
MG_PHY_YT8531_REG_PHYSTS = 17,
|
||||
MG_PHY_YT8531_REG_EXT_ADDR = 30,
|
||||
MG_PHY_YT8531_REG_EXT_DATA = 31
|
||||
};
|
||||
|
||||
static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
|
||||
@@ -60,6 +65,8 @@ static const char *mg_phy_id_to_str(uint16_t id1, uint16_t id2) {
|
||||
}
|
||||
case MG_PHY_ICS1894x:
|
||||
return "ICS1894x";
|
||||
case MG_PHY_YT85x:
|
||||
return id2 == MG_PHY_YT8531 ? "YT8531" : "YT85x";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
@@ -75,6 +82,18 @@ void mg_phy_init(struct mg_phy *phy, uint8_t phy_addr, uint8_t config) {
|
||||
id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2);
|
||||
MG_INFO(("PHY ID: %#04x %#04x (%s)", id1, id2, mg_phy_id_to_str(id1, id2)));
|
||||
|
||||
if (id1 == MG_PHY_YT85x && id2 == MG_PHY_YT8531) {
|
||||
uint16_t value;
|
||||
// TODO (robertc2000): Autonegotiation remains disabled after PHY is reset
|
||||
// We temporarily force enabling autoneg, until a workaround is found.
|
||||
phy->write_reg(phy_addr, MG_PHY_REG_BCR, MG_BIT(12));
|
||||
phy->write_reg(phy_addr, MG_PHY_YT8531_REG_EXT_ADDR, 0xa003);
|
||||
value = phy->read_reg(phy_addr, MG_PHY_YT8531_REG_EXT_DATA);
|
||||
value &= (uint16_t) ~(MG_BIT(3) | MG_BIT(2) | MG_BIT(1) | MG_BIT(0));
|
||||
phy->write_reg(phy_addr, MG_PHY_YT8531_REG_EXT_DATA,
|
||||
(uint16_t) (value | MG_BIT(1))); // TXDLY: 2 * 150 ps
|
||||
}
|
||||
|
||||
if (id1 == MG_PHY_DP83x && id2 == MG_PHY_DP83867) {
|
||||
phy->write_reg(phy_addr, 0x0d, 0x1f); // write 0x10d to IO_MUX_CFG (0x0170)
|
||||
phy->write_reg(phy_addr, 0x0e, 0x170);
|
||||
@@ -168,6 +187,15 @@ bool mg_phy_up(struct mg_phy *phy, uint8_t phy_addr, bool *full_duplex,
|
||||
uint16_t poll_reg = phy->read_reg(phy_addr, MG_PHY_ICS189432_REG_POLL);
|
||||
*full_duplex = poll_reg & MG_BIT(14);
|
||||
*speed = (poll_reg & MG_BIT(15)) ? MG_PHY_SPEED_100M : MG_PHY_SPEED_10M;
|
||||
} else if (id1 == MG_PHY_YT85x) {
|
||||
uint16_t id2 = phy->read_reg(phy_addr, MG_PHY_REG_ID2);
|
||||
if (id2 == MG_PHY_YT8531) {
|
||||
uint16_t physts = phy->read_reg(phy_addr, MG_PHY_YT8531_REG_PHYSTS);
|
||||
*full_duplex = physts & MG_BIT(13);
|
||||
*speed = (physts & MG_BIT(15)) ? MG_PHY_SPEED_1000M
|
||||
: (physts & MG_BIT(14)) ? MG_PHY_SPEED_100M
|
||||
: MG_PHY_SPEED_10M;
|
||||
}
|
||||
}
|
||||
}
|
||||
return up;
|
||||
|
||||
@@ -152,6 +152,7 @@ extern struct mg_tcpip_driver mg_tcpip_driver_cyw;
|
||||
extern struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi;
|
||||
extern struct mg_tcpip_driver mg_tcpip_driver_st67w6;
|
||||
extern struct mg_tcpip_driver mg_tcpip_driver_atcmd;
|
||||
extern struct mg_tcpip_driver mg_tcpip_driver_netc;
|
||||
|
||||
// SPI bus abstraction for SPI-attached network chips (e.g. W5500).
|
||||
// Populate and assign to the driver's driver_data field.
|
||||
|
||||
Reference in new issue
Block a user