📄 c5471_ethernet.c
字号:
c5471->c_bifup = FALSE; irqrestore(flags); return OK;}/**************************************************************************** * Function: c5471_txavail * * Description: * Driver callback invoked when new TX data is available. This is a * stimulus perform an out-of-cycle poll and, thereby, reduce the TX * latency. * * Parameters: * dev - Reference to the NuttX driver state structure * * Returned Value: * None * * Assumptions: * Called in normal user mode * ****************************************************************************/static int c5471_txavail(struct uip_driver_s *dev){ struct c5471_driver_s *c5471 = (struct c5471_driver_s *)dev->d_private; irqstate_t flags; ndbg("Polling\n"); flags = irqsave(); /* Ignore the notification if the interface is not yet up */ if (c5471->c_bifup) { /* Check if the ESM has let go of the RX descriptor giving us access * rights to submit another Ethernet frame. */ if ((EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0) { /* If so, then poll uIP for new XMIT data */ (void)uip_poll(&c5471->c_dev, c5471_uiptxpoll); } } irqrestore(flags); return OK;}/**************************************************************************** * Name: c5471_eimreset * * Description * The C547x docs states that a module should generally be reset according * to the following algorithm: * * 1. Put the module in reset. * 2. Switch on the module clock. * 3. Wait for eight clock cycles. * 4. Release the reset. * ****************************************************************************/static void c5471_eimreset (struct c5471_driver_s *c5471){ /* Stop the EIM module clock */ putreg32((getreg32(CLKM) | CLKM_EIM_CLK_STOP), CLKM); /* Put EIM module in reset */ putreg32((getreg32(CLKM_RESET) & ~CLKM_RESET_EIM), CLKM_RESET); /* Start the EIM module clock */ putreg32((getreg32(CLKM) & ~CLKM_EIM_CLK_STOP), CLKM); /* Assert nRESET to reset the board's PHY0/1 chips */ putreg32((CLKM_CTL_RST_EXT_RESET|CLKM_CTL_RST_LEAD_RESET), CLKM_CTL_RST); up_mdelay(2); /* Release the peripheral nRESET signal */ putreg32(CLKM_CTL_RST_LEAD_RESET, CLKM_CTL_RST); /* Release EIM module reset */ putreg32((getreg32(CLKM_RESET) | CLKM_RESET_EIM), CLKM_RESET); /* All EIM register should now be in there power-up default states */ c5471->c_lastdescstart = 0; c5471->c_lastdescend = 0;}/**************************************************************************** * Name: c5471_eimconfig * * Description * Assumes that all registers are currently in the power-up reset state. * This routine then modifies that state to provide our specific ethernet * configuration. * ****************************************************************************/static void c5471_eimconfig(struct c5471_driver_s *c5471){ volatile uint32 pbuf; volatile uint32 desc; volatile uint32 val; int i; desc = EIM_RAM_START; pbuf = EIM_RAM_START + 0x6C0; /* TX ENET 0 */ ndbg("TX ENET0 desc: %08x pbuf: %08x\n", desc, pbuf); putreg32((desc & 0x0000ffff), ENET0_TDBA); /* 16-bit offset address */ for (i = NUM_DESC_TX-1; i >= 0; i--) { if (i == 0) val = EIM_TXDESC_WRAP_NEXT; else val = EIM_TXDESC_WRAP_FIRST; val |= EIM_TXDESC_OWN_HOST|EIM_TXDESC_INTRE|EIM_TXDESC_PADCRC|EIM_PACKET_BYTES; putreg32(val, desc); desc += sizeof(uint32); putreg32(pbuf, desc); desc += sizeof(uint32); putreg32(0, pbuf); pbuf += EIM_PACKET_BYTES; putreg32(0, pbuf); pbuf += sizeof(uint32); /* Ether Module's "Buffer Usage Word" */ } /* RX ENET 0 */ ndbg("RX ENET0 desc: %08x pbuf: %08x\n", desc, pbuf); putreg32((desc & 0x0000ffff), ENET0_RDBA); /* 16-bit offset address */ for (i = NUM_DESC_RX-1; i >= 0; i--) { if (i == 0) val = EIM_RXDESC_WRAP_NEXT; else val = EIM_RXDESC_WRAP_FIRST; val |= EIM_RXDESC_OWN_ENET|EIM_RXDESC_INTRE|EIM_RXDESC_PADCRC|EIM_PACKET_BYTES; putreg32(val, desc); desc += sizeof(uint32); putreg32(pbuf, desc); desc += sizeof(uint32); putreg32(0, pbuf); pbuf += EIM_PACKET_BYTES; putreg32(0, pbuf); pbuf += sizeof(uint32); /* Ether Module's "Buffer Usage Word" */ } /* TX CPU */ ndbg("TX CPU desc: %08x pbuf: %08x\n", desc, pbuf); c5471->c_txcpudesc = desc; putreg32((desc & 0x0000ffff), EIM_CPU_TXBA); /* 16-bit offset address */ for (i = NUM_DESC_TX-1; i >= 0; i--) { /* Set words 1+2 of the TXDESC */ if (i == 0) val = EIM_TXDESC_WRAP_NEXT; else val = EIM_TXDESC_WRAP_FIRST; val |= EIM_TXDESC_OWN_HOST|EIM_TXDESC_INTRE|EIM_TXDESC_PADCRC|EIM_PACKET_BYTES; putreg32(val, desc); desc += sizeof(uint32); putreg32(pbuf, desc); desc += sizeof(uint32); putreg(0, pbuf); pbuf += EIM_PACKET_BYTES; putreg(0, pbuf); pbuf += sizeof(uint32); /* Ether Module's "Buffer Usage Word" */ } /* RX CPU */ ndbg("RX CPU desc: %08x pbuf: %08x\n", desc, pbuf); c5471->c_rxcpudesc = desc; putreg32((desc & 0x0000ffff), EIM_CPU_RXBA); /* 16-bit offset address */ for (i = NUM_DESC_RX-1; i >= 0; i--) { /* Set words 1+2 of the RXDESC */ if (i == 0) val = EIM_RXDESC_WRAP_NEXT; else val = EIM_RXDESC_WRAP_FIRST; val |= EIM_RXDESC_OWN_ENET|EIM_RXDESC_INTRE|EIM_RXDESC_PADCRC|EIM_PACKET_BYTES; putreg32(val, desc); desc += sizeof(uint32); putreg32(pbuf, desc); desc += sizeof(uint32); putreg32(0, pbuf); pbuf += EIM_PACKET_BYTES; putreg32(0, pbuf); pbuf += sizeof(uint32); /* Ether Module's "Buffer Usage Word" */ } ndbg("END desc: %08x pbuf: %08x\n", desc, pbuf); /* Save the descriptor packet size */ putreg32(EIM_PACKET_BYTES, EIM_BUFSIZE); /* Set the filter mode */#if 0 putreg32(EIM_FILTER_UNICAST, EIM_CPU_FILTER);#else// putreg32(EIM_FILTER_LOGICAL|EIM_FILTER_UNICAST|EIM_FILTER_MULTICAST|// EIM_FILTER_BROADCAST, EIM_CPU_FILTER); putreg32(EIM_FILTER_UNICAST|EIM_FILTER_MULTICAST|EIM_FILTER_BROADCAST, EIM_CPU_FILTER);#endif /* Disable all Ethernet interrupts */ putreg32(0x00000000, EIM_INTEN); /* Setup the EIM control register */#if 1 putreg32(EIM_CTRL_ENET0_EN|EIM_CTRL_RXENET0_EN|EIM_CTRL_TXENET0_EN| EIM_CTRL_RXCPU_EN|EIM_CTRL_TXCPU_EN, EIM_CTRL);#else putreg32(EIM_CTRL_ENET0_EN|EIM_CTRL_ENET0_FLW|EIM_CTRL_RXENET0_EN| EIM_CTRL_TXENET0_EN|EIM_CTRL_RXCPU_EN|EIM_CTRL_TXCPU_EN, EIM_CTRL);#endif#if 1 putreg32(0x00000000, EIM_MFVHI);#else putreg32(0x0000ff00, EIM_MFVHI);#endif putreg32(0x00000000, EIM_MFVLO); putreg32(0x00000000, EIM_MFMHI); putreg32(0x00000000, EIM_MFMLO); putreg32(0x00000018, EIM_RXTH); putreg32(0x00000000, EIM_CPU_RXREADY); /* Setup the ENET0 mode register */#if 1 putreg32(ENET_MODE_RJCT_SFE|ENET_MODE_MWIDTH|ENET_MODE_FULLDUPLEX, ENET0_MODE);#else putreg32(ENET_MODE_RJCT_SFE|ENET_MODE_MWIDTH|ENET_MODE_HALFDUPLEX, ENET0_MODE);#endif putreg32(0x00000000, ENET0_BOFFSEED); putreg32(0x00000000, ENET0_FLWPAUSE); putreg32(0x00000000, ENET0_FLWCONTROL); putreg32(0x00000000, ENET0_VTYPE);#if 0 putreg32(ENET_ADR_BROADCAST|ENET_ADR_PROMISCUOUS, ENET0_ADRMODE_EN);#else /* The CPU port is not PROMISCUOUS, it wants a no-promiscuous address * match yet the the SWITCH receives packets from the PROMISCUOUS ENET0 * which routes all packets for filter matching at the CPU port which * then allows the s/w to see the new incoming packetes that passed * the filter. Here we are setting the main SWITCH closest the ether * wire. */ putreg32(ENET_ADR_PROMISCUOUS, ENET0_ADRMODE_EN);#endif putreg32(0x00000000, ENET0_DRP); up_mdelay(500);}/**************************************************************************** * Name: c5471_reset * * Description * ****************************************************************************/static void c5471_reset(struct c5471_driver_s *c5471){#if (CONFIG_C5471_ETHERNET_PHY == ETHERNET_PHY_LU3X31T_T64) ndbg("EIM reset\n"); c5471_eimreset(c5471);#endif ndbg("PHY init\n"); c5471_phyinit(); ndbg("EIM config\n"); c5471_eimconfig(c5471);}/**************************************************************************** * Name: c5471_macassign * * Description * Set the mac address of our CPU ether port so that when the SWITCH * receives packets from the PROMISCUOUS ENET0 it will switch them to the * CPU port and cause a packet arrival event on the Switch's CPU TX queue * when an address match occurs. The CPU port is not PROMISCUOUS and wants * to see only packets specifically addressed to this device. * ****************************************************************************/static void c5471_macassign(struct c5471_driver_s *c5471){ struct uip_driver_s *dev = &c5471->c_dev; uint8 *mptr = dev->d_mac.ether_addr_octet; register uint32 tmp; ndbg("MAC: %0x:%0x:%0x:%0x:%0x:%0x\n", mptr[0], mptr[1], mptr[2], mptr[3], mptr[4], mptr[5]); /* Set CPU port MAC address. S/W will only see incoming packets that match * this destination address. */ tmp = (((uint32)mptr[0]) << 8) | ((uint32)mptr[1]); putreg32(tmp, EIM_CPU_DAHI); tmp = (((uint32)mptr[2]) << 24) | (((uint32)mptr[3]) << 16) | (((uint32)mptr[4]) << 8) | ((uint32)mptr[5]); putreg32(tmp, EIM_CPU_DALO);#if 0 /* Set the ENET MAC address */ putreg32(getreg32(EIM_CPU_DAHI), ENET0_PARHI); putreg32(getreg32(EIM_CPU_DALO), ENET0_PARLO); putreg32(getreg32(EIM_CPU_DAHI), ENET0_LARHI); putreg32(getreg32(EIM_CPU_DALO), ENET0_LARLO);#else /* ENET MAC assignment not needed for its PROMISCUOUS mode */ putreg32(0x00000000, ENET0_PARHI); putreg32(0x00000000, ENET0_PARLO); putreg32(0x00000000, ENET0_LARHI); putreg32(0x00000000, ENET0_LARLO);#endif}/**************************************************************************** * Public Functions ****************************************************************************//**************************************************************************** * Function: c5471_initialize * * Description: * Initialize the Ethernet driver * * Parameters: * None * * Returned Value: * OK on success; Negated errno on failure. * * Assumptions: * ****************************************************************************//* Initialize the DM90x0 chip and driver */void up_netinitialize(void){ /* Attach the IRQ to the driver */ if (irq_attach(C5471_IRQ_ETHER, c5471_interrupt)) { /* We could not attach the ISR to the ISR */ nlldbg("irq_attach() failed\n"); return; } /* Initialize the driver structure */ memset(g_c5471, 0, CONFIG_C5471_NET_NINTERFACES*sizeof(struct c5471_driver_s)); g_c5471[0].c_dev.d_ifup = c5471_ifup; /* I/F down callback */ g_c5471[0].c_dev.d_ifdown = c5471_ifdown; /* I/F up (new IP address) callback */ g_c5471[0].c_dev.d_txavail = c5471_txavail; /* New TX data callback */ g_c5471[0].c_dev.d_private = (void*)g_c5471; /* Used to recover private state from dev */ /* Create a watchdog for timing polling for and timing of transmisstions */ g_c5471[0].c_txpoll = wd_create(); /* Create periodic poll timer */ g_c5471[0].c_txtimeout = wd_create(); /* Create TX timeout timer */ /* Register the device with the OS so that socket IOCTLs can be performed */ (void)netdev_register(&g_c5471[0].c_dev);}#endif /* CONFIG_NET */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -