📄 dm90x0.c
字号:
* Assumptions: * ****************************************************************************/static inline void dm9x_phymode(struct dm9x_driver_s *dm9x){ uint16 phyreg0; uint16 phyreg4;#if CONFIG_DM9X_MODE == DM9X_MODE_AUTO phyreg0 = 0x1200; /* Auto-negotiation & Restart Auto-negotiation */ phyreg4 = 0x01e1; /* Default flow control disable*/#elif CONFIG_DM9X_MODE == DM9X_MODE_10MHD phyreg4 = 0x21; phyreg0 = 0x1000;#elif CONFIG_DM9X_MODE == DM9X_MODE_10MFD phyreg4 = 0x41; phyreg0 = 0x1100;#elif CONFIG_DM9X_MODE == DM9X_MODE_100MHD phyreg4 = 0x81; phyreg0 = 0x3000;#elif CONFIG_DM9X_MODE == DM9X_MODE_100MFD phyreg4 = 0x101; phyreg0 = 0x3100;#else# error "Recognized PHY mode"#endif dm9x_phywrite(dm9x, 0, phyreg0); dm9x_phywrite(dm9x, 4, phyreg4);}/**************************************************************************** * Function: dm9x_ifup * * Description: * NuttX Callback: Bring up the DM90x0 interface when an IP address is * provided * * Parameters: * dev - Reference to the NuttX driver state structure * * Returned Value: * None * * Assumptions: * ****************************************************************************/static int dm9x_ifup(struct uip_driver_s *dev){ struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; uint8 netstatus; int i; ndbg("Bringing up: %d.%d.%d.%d\n", dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); /* Initilize DM90x0 chip */ dm9x_bringup(dm9x); /* Check link state and media speed (waiting up to 3s for link OK) */ dm9x->dm_b100M = FALSE; for (i = 0; i < 3000; i++) { netstatus = getreg(DM9X_NETS); if (netstatus & DM9X_NETS_LINKST) { /* Link OK... Wait a bit before getting the detected speed */ up_mdelay(200); netstatus = getreg(DM9X_NETS); if ((netstatus & DM9X_NETS_SPEED) == 0) { dm9x->dm_b100M = TRUE; } break; } i++; up_mdelay(1); } ndbg("delay: %dmS speed: %s\n", i, dm9x->dm_b100M ? "100M" : "10M"); /* Set and activate a timer process */ (void)wd_start(dm9x->dm_txpoll, DM6X_WDDELAY, dm9x_polltimer, 1, (uint32)dm9x); /* Enable the DM9X interrupt */ dm9x->dm_bifup = TRUE; up_enable_irq(CONFIG_DM9X_IRQ); return OK;}/**************************************************************************** * Function: dm9x_ifdown * * Description: * NuttX Callback: Stop the interface. * * Parameters: * dev - Reference to the NuttX driver state structure * * Returned Value: * None * * Assumptions: * ****************************************************************************/static int dm9x_ifdown(struct uip_driver_s *dev){ struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; irqstate_t flags; ndbg("Stopping\n"); /* Disable the DM9X interrupt */ flags = irqsave(); up_disable_irq(CONFIG_DM9X_IRQ); /* Cancel the TX poll timer and TX timeout timers */ wd_cancel(dm9x->dm_txpoll); wd_cancel(dm9x->dm_txtimeout); /* Reset the device */ dm9x_phywrite(dm9x, 0x00, 0x8000); /* PHY reset */ putreg(DM9X_GPD, 0x01); /* Power-down PHY (GEPIO0=1) */ putreg(DM9X_IMR, DM9X_IMRDISABLE); /* Disable all interrupts */ putreg(DM9X_RXC, 0x00); /* Disable RX */ putreg(DM9X_ISR, DM9X_INT_ALL); /* Clear interrupt status */ dm9x->dm_bifup = FALSE; irqrestore(flags); /* Dump statistics */ dm9x_dumpstatistics(dm9x); return OK;}/**************************************************************************** * Function: dm9x_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 dm9x_txavail(struct uip_driver_s *dev){ struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; irqstate_t flags; ndbg("Polling\n"); flags = irqsave(); /* Ignore the notification if the interface is not yet up */ if (dm9x->dm_bifup) { /* Check if there is room in the DM90x0 to hold another packet. In 100M * mode, that can be 2 packets, otherwise it is a single packet. */ if (dm9x->dm_ntxpending < 1 || (dm9x->dm_b100M && dm9x->dm_ntxpending < 2)) { /* If so, then poll uIP for new XMIT data */ (void)uip_poll(&dm9x->dm_dev, dm9x_uiptxpoll); } } irqrestore(flags); return OK;}/**************************************************************************** * Function: dm9x_bringup * * Description: * Initialize the dm90x0 chip * * Parameters: * dm9x - Reference to the driver state structure * * Returned Value: * None * * Assumptions: * ****************************************************************************/static void dm9x_bringup(struct dm9x_driver_s *dm9x){ ndbg("Initializing\n"); /* Set the internal PHY power-on, GPIOs normal, and wait 2ms */ putreg(DM9X_GPD, 0x01); /* Power-down the PHY (GEPIO0=1) */ up_udelay(500); putreg(DM9X_GPD, 0x00); /* Preactivate PHY (GPIO0=0 */ up_udelay(20); /* Wait 20us for PHY power-on ready */ /* Do a software reset and wait 20us (twice). The reset autoclears * in 10us; 20us guarantees completion of the reset */ putreg(DM9X_NETC, (DM9X_NETC_RST|DM9X_NETC_LBK1)); up_udelay(20); putreg(DM9X_NETC, (DM9X_NETC_RST|DM9X_NETC_LBK1)); up_udelay(20); /* Configure I/O mode */ switch (getreg(DM9X_ISR) & DM9X_ISR_IOMODEM) { case DM9X_ISR_IOMODE8: dm9x->dm_read = read8; dm9x->dm_write = write8; dm9x->dm_discard = discard8; break; case DM9X_ISR_IOMODE16: dm9x->dm_read = read16; dm9x->dm_write = write16; dm9x->dm_discard = discard16; break; case DM9X_ISR_IOMODE32: dm9x->dm_read = read32; dm9x->dm_write = write32; dm9x->dm_discard = discard32; break; default: break; } /* Program PHY operating mode */ dm9x_phymode(dm9x); /* Program operating mode */ putreg(DM9X_NETC, 0x00); /* Network control */ putreg(DM9X_TXC, 0x00); /* Clear TX Polling */ putreg(DM9X_BPTHRES, 0x3f); /* Less 3kb, 600us */ putreg(DM9X_SMODEC, 0x00); /* Special mode */ putreg(DM9X_NETS, (DM9X_NETS_WAKEST|DM9X_NETS_TX1END|DM9X_NETS_TX2END)); /* Clear TX status */ putreg(DM9X_ISR, DM9X_INT_ALL); /* Clear interrupt status */#if defined(CONFIG_DM9X_CHECKSUM) putreg(DM9X_TCCR, 0x07); /* TX UDP/TCP/IP checksum enable */ putreg(DM9X_RCSR, 0x02); /* Receive checksum enable */#endif#if defined(CONFIG_DM9X_ETRANS) putreg(DM9X_ETXCSR, 0x83);#endif /* Initialize statistics */ dm9x->ncrxpackets = 0; /* Number of continuous RX packets */ dm9x->dm_ntxpending = 0; /* Number of pending TX packets */ dm9x_resetstatistics(dm9x); /* Activate DM9000A/DM9010 */ putreg(DM9X_RXC, DM9X_RXCSETUP | 1); /* RX enable */ putreg(DM9X_IMR, DM9X_IMRENABLE); /* Enable TX/RX interrupts */}/**************************************************************************** * Function: dm9x_reset * * Description: * Stop, reset, re-initialize, and restart the DM90x0 chip and driver. At * present, the chip is only reset after a TX timeout. * * Parameters: * dm9x - Reference to the driver state structure * * Returned Value: * None * * Assumptions: * ****************************************************************************/static void dm9x_reset(struct dm9x_driver_s *dm9x){ uint8 save; int i; /* Cancel the TX poll timer and TX timeout timers */ wd_cancel(dm9x->dm_txpoll); wd_cancel(dm9x->dm_txtimeout); /* Save previous register address */ save = (uint8)DM9X_INDEX;#if defined(CONFIG_DM9X_STATS) dm9x->dm_nresets++;#endif dm9x_bringup(dm9x); /* Wait up to 1 second for the link to be OK */ dm9x->dm_b100M = FALSE; for (i = 0; i < 1000; i++) { if (dm9x_phyread(dm9x,0x1) & 0x4) { if (dm9x_phyread(dm9x, 0) &0x2000) { dm9x->dm_b100M = TRUE; } break; } up_mdelay(1); } /* Restore previous register address */ DM9X_INDEX = save;}/**************************************************************************** * Public Functions ****************************************************************************//**************************************************************************** * Function: dm9x_initialize * * Description: * Initialize the DM90x0 driver * * Parameters: * None * * Returned Value: * OK on success; Negated errno on failure. * * Assumptions: * ****************************************************************************//* Initialize the DM90x0 chip and driver */int dm9x_initialize(void){ uint8 *mptr; uint16 vid; uint16 pid; int i; int j; /* Get the chip vendor ID and product ID */ vid = (((uint16)getreg(DM9X_VIDH)) << 8) | (uint16)getreg(DM9X_VIDL); pid = (((uint16)getreg(DM9X_PIDH)) << 8) | (uint16)getreg(DM9X_PIDL); nlldbg("I/O base: %08x VID: %04x PID: %04x\n", CONFIG_DM9X_BASE, vid, pid); /* Check if a DM90x0 chip is recognized at this I/O base */ if (vid != DM9X_DAVICOMVID || (pid != DM9X_DM9000PID && pid != DM9X_DM9010PID)) { nlldbg("DM90x0 vender/product ID not found at this base address\n"); return -ENODEV; } /* Attach the IRQ to the driver */ if (irq_attach(CONFIG_DM9X_IRQ, dm9x_interrupt)) { /* We could not attach the ISR to the ISR */ nlldbg("irq_attach() failed\n"); return -EAGAIN; } /* Initialize the driver structure */ memset(g_dm9x, 0, CONFIG_DM9X_NINTERFACES*sizeof(struct dm9x_driver_s)); g_dm9x[0].dm_dev.d_ifup = dm9x_ifup; /* I/F down callback */ g_dm9x[0].dm_dev.d_ifdown = dm9x_ifdown; /* I/F up (new IP address) callback */ g_dm9x[0].dm_dev.d_txavail = dm9x_txavail; /* New TX data callback */ g_dm9x[0].dm_dev.d_private = (void*)g_dm9x; /* Used to recover private state from dev */ /* Create a watchdog for timing polling for and timing of transmisstions */ g_dm9x[0].dm_txpoll = wd_create(); /* Create periodic poll timer */ g_dm9x[0].dm_txtimeout = wd_create(); /* Create TX timeout timer */ /* Read the MAC address */ mptr = g_dm9x[0].dm_dev.d_mac.ether_addr_octet; for (i = 0, j = DM9X_PAB0; i < ETHER_ADDR_LEN; i++, j++) { mptr[i] = getreg(j); } nlldbg("MAC: %0x:%0x:%0x:%0x:%0x:%0x\n", mptr[0], mptr[1], mptr[2], mptr[3], mptr[4], mptr[5]); /* Register the device with the OS so that socket IOCTLs can be performed */ (void)netdev_register(&g_dm9x[0].dm_dev); return OK;}#endif /* CONFIG_NET && CONFIG_NET_DM90x0 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -