4xx_enet.c
来自「最新版的u-boot,2008-10-18发布」· C语言 代码 · 共 2,136 行 · 第 1/5 页
C
2,136 行
rgmii_channel = devnum - 2; else rgmii_channel = devnum; if (speed == 1000) reg = (RGMII_SSR_SP_1000MBPS << RGMII_SSR_V(rgmii_channel)); else if (speed == 100) reg = (RGMII_SSR_SP_100MBPS << RGMII_SSR_V(rgmii_channel)); else if (speed == 10) reg = (RGMII_SSR_SP_10MBPS << RGMII_SSR_V(rgmii_channel)); else { printf("Error in RGMII Speed\n"); return -1; } out_be32((void *)RGMII_SSR, reg);#if defined(CONFIG_460GT) if ((devnum == 2) || (devnum == 3)) out_be32((void *)RGMII_SSR + RGMII1_BASE_OFFSET, reg);#endif#endif /* set the Mal configuration reg */#if defined(CONFIG_440GX) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX) mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT | MAL_CR_EOPIE | 0x00330000);#else mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT); /* Errata 1.12: MAL_1 -- Disable MAL bursting */ if (get_pvr() == PVR_440GP_RB) { mtdcr (malmcr, mfdcr(malmcr) & ~MAL_CR_PLBB); }#endif /* * Malloc MAL buffer desciptors, make sure they are * aligned on cache line boundary size * (401/403/IOP480 = 16, 405 = 32) * and doesn't cross cache block boundaries. */ if (hw_p->first_init == 0) { debug("*** Allocating descriptor memory ***\n"); bd_cached = (u32)malloc_aligned(MAL_ALLOC_SIZE, 4096); if (!bd_cached) { printf("%s: Error allocating MAL descriptor buffers!\n", __func__); return -1; }#ifdef CONFIG_4xx_DCACHE flush_dcache_range(bd_cached, bd_cached + MAL_ALLOC_SIZE); if (!last_used_ea)#if defined(CFG_MEM_TOP_HIDE) bd_uncached = bis->bi_memsize + CFG_MEM_TOP_HIDE;#else bd_uncached = bis->bi_memsize;#endif else bd_uncached = last_used_ea + MAL_ALLOC_SIZE; last_used_ea = bd_uncached; program_tlb(bd_cached, bd_uncached, MAL_ALLOC_SIZE, TLB_WORD2_I_ENABLE);#else bd_uncached = bd_cached;#endif hw_p->tx_phys = bd_cached; hw_p->rx_phys = bd_cached + MAL_TX_DESC_SIZE; hw_p->tx = (mal_desc_t *)(bd_uncached); hw_p->rx = (mal_desc_t *)(bd_uncached + MAL_TX_DESC_SIZE); debug("hw_p->tx=%08x, hw_p->rx=%08x\n", hw_p->tx, hw_p->rx); } for (i = 0; i < NUM_TX_BUFF; i++) { hw_p->tx[i].ctrl = 0; hw_p->tx[i].data_len = 0; if (hw_p->first_init == 0) hw_p->txbuf_ptr = malloc_aligned(MAL_ALLOC_SIZE, L1_CACHE_BYTES); hw_p->tx[i].data_ptr = hw_p->txbuf_ptr; if ((NUM_TX_BUFF - 1) == i) hw_p->tx[i].ctrl |= MAL_TX_CTRL_WRAP; hw_p->tx_run[i] = -1; debug("TX_BUFF %d @ 0x%08lx\n", i, (u32)hw_p->tx[i].data_ptr); } for (i = 0; i < NUM_RX_BUFF; i++) { hw_p->rx[i].ctrl = 0; hw_p->rx[i].data_len = 0; hw_p->rx[i].data_ptr = (char *)NetRxPackets[i]; if ((NUM_RX_BUFF - 1) == i) hw_p->rx[i].ctrl |= MAL_RX_CTRL_WRAP; hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR; hw_p->rx_ready[i] = -1; debug("RX_BUFF %d @ 0x%08lx\n", i, (u32)hw_p->rx[i].data_ptr); } reg = 0x00000000; reg |= dev->enetaddr[0]; /* set high address */ reg = reg << 8; reg |= dev->enetaddr[1]; out_be32((void *)EMAC_IAH + hw_p->hw_addr, reg); reg = 0x00000000; reg |= dev->enetaddr[2]; /* set low address */ reg = reg << 8; reg |= dev->enetaddr[3]; reg = reg << 8; reg |= dev->enetaddr[4]; reg = reg << 8; reg |= dev->enetaddr[5]; out_be32((void *)EMAC_IAL + hw_p->hw_addr, reg); switch (devnum) { case 1: /* setup MAL tx & rx channel pointers */#if defined (CONFIG_405EP) || defined (CONFIG_440EP) || defined (CONFIG_440GR) mtdcr (maltxctp2r, hw_p->tx_phys);#else mtdcr (maltxctp1r, hw_p->tx_phys);#endif#if defined(CONFIG_440) mtdcr (maltxbattr, 0x0); mtdcr (malrxbattr, 0x0);#endif#if defined(CONFIG_460EX) || defined(CONFIG_460GT) mtdcr (malrxctp8r, hw_p->rx_phys); /* set RX buffer size */ mtdcr (malrcbs8, ENET_MAX_MTU_ALIGNED / 16);#else mtdcr (malrxctp1r, hw_p->rx_phys); /* set RX buffer size */ mtdcr (malrcbs1, ENET_MAX_MTU_ALIGNED / 16);#endif break;#if defined (CONFIG_440GX) case 2: /* setup MAL tx & rx channel pointers */ mtdcr (maltxbattr, 0x0); mtdcr (malrxbattr, 0x0); mtdcr (maltxctp2r, hw_p->tx_phys); mtdcr (malrxctp2r, hw_p->rx_phys); /* set RX buffer size */ mtdcr (malrcbs2, ENET_MAX_MTU_ALIGNED / 16); break; case 3: /* setup MAL tx & rx channel pointers */ mtdcr (maltxbattr, 0x0); mtdcr (maltxctp3r, hw_p->tx_phys); mtdcr (malrxbattr, 0x0); mtdcr (malrxctp3r, hw_p->rx_phys); /* set RX buffer size */ mtdcr (malrcbs3, ENET_MAX_MTU_ALIGNED / 16); break;#endif /* CONFIG_440GX */#if defined (CONFIG_460GT) case 2: /* setup MAL tx & rx channel pointers */ mtdcr (maltxbattr, 0x0); mtdcr (malrxbattr, 0x0); mtdcr (maltxctp2r, hw_p->tx_phys); mtdcr (malrxctp16r, hw_p->rx_phys); /* set RX buffer size */ mtdcr (malrcbs16, ENET_MAX_MTU_ALIGNED / 16); break; case 3: /* setup MAL tx & rx channel pointers */ mtdcr (maltxbattr, 0x0); mtdcr (malrxbattr, 0x0); mtdcr (maltxctp3r, hw_p->tx_phys); mtdcr (malrxctp24r, hw_p->rx_phys); /* set RX buffer size */ mtdcr (malrcbs24, ENET_MAX_MTU_ALIGNED / 16); break;#endif /* CONFIG_460GT */ case 0: default: /* setup MAL tx & rx channel pointers */#if defined(CONFIG_440) mtdcr (maltxbattr, 0x0); mtdcr (malrxbattr, 0x0);#endif mtdcr (maltxctp0r, hw_p->tx_phys); mtdcr (malrxctp0r, hw_p->rx_phys); /* set RX buffer size */ mtdcr (malrcbs0, ENET_MAX_MTU_ALIGNED / 16); break; } /* Enable MAL transmit and receive channels */#if defined(CONFIG_405EP) || defined(CONFIG_440EP) || defined(CONFIG_440GR) mtdcr (maltxcasr, (MAL_TXRX_CASR >> (hw_p->devnum*2)));#else mtdcr (maltxcasr, (MAL_TXRX_CASR >> hw_p->devnum));#endif mtdcr (malrxcasr, (MAL_TXRX_CASR >> hw_p->devnum)); /* set transmit enable & receive enable */ out_be32((void *)EMAC_M0 + hw_p->hw_addr, EMAC_M0_TXE | EMAC_M0_RXE); mode_reg = in_be32((void *)EMAC_M1 + hw_p->hw_addr); /* set rx-/tx-fifo size */ mode_reg = (mode_reg & ~EMAC_MR1_FIFO_MASK) | EMAC_MR1_FIFO_SIZE; /* set speed */ if (speed == _1000BASET) {#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_440SP) || defined(CONFIG_440SPE) unsigned long pfc1; mfsdr (sdr_pfc1, pfc1); pfc1 |= SDR0_PFC1_EM_1000; mtsdr (sdr_pfc1, pfc1);#endif mode_reg = mode_reg | EMAC_M1_MF_1000MBPS | EMAC_M1_IST; } else if (speed == _100BASET) mode_reg = mode_reg | EMAC_M1_MF_100MBPS | EMAC_M1_IST; else mode_reg = mode_reg & ~0x00C00000; /* 10 MBPS */ if (duplex == FULL) mode_reg = mode_reg | 0x80000000 | EMAC_M1_IST; out_be32((void *)EMAC_M1 + hw_p->hw_addr, mode_reg); /* Enable broadcast and indvidual address */ /* TBS: enabling runts as some misbehaved nics will send runts */ out_be32((void *)EMAC_RXM + hw_p->hw_addr, EMAC_RMR_BAE | EMAC_RMR_IAE); /* we probably need to set the tx mode1 reg? maybe at tx time */ /* set transmit request threshold register */ out_be32((void *)EMAC_TRTR + hw_p->hw_addr, 0x18000000); /* 256 byte threshold */ /* set receive low/high water mark register */#if defined(CONFIG_440) /* 440s has a 64 byte burst length */ out_be32((void *)EMAC_RX_HI_LO_WMARK + hw_p->hw_addr, 0x80009000);#else /* 405s have a 16 byte burst length */ out_be32((void *)EMAC_RX_HI_LO_WMARK + hw_p->hw_addr, 0x0f002000);#endif /* defined(CONFIG_440) */ out_be32((void *)EMAC_TXM1 + hw_p->hw_addr, 0xf8640000); /* Set fifo limit entry in tx mode 0 */ out_be32((void *)EMAC_TXM0 + hw_p->hw_addr, 0x00000003); /* Frame gap set */ out_be32((void *)EMAC_I_FRAME_GAP_REG + hw_p->hw_addr, 0x00000008); /* Set EMAC IER */ hw_p->emac_ier = EMAC_ISR_PTLE | EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE; if (speed == _100BASET) hw_p->emac_ier = hw_p->emac_ier | EMAC_ISR_SYE; out_be32((void *)EMAC_ISR + hw_p->hw_addr, 0xffffffff); /* clear pending interrupts */ out_be32((void *)EMAC_IER + hw_p->hw_addr, hw_p->emac_ier); if (hw_p->first_init == 0) { /* * Connect interrupt service routines */ irq_install_handler(ETH_IRQ_NUM(hw_p->devnum), (interrupt_handler_t *) enetInt, dev); } mtmsr (msr); /* enable interrupts again */ hw_p->bis = bis; hw_p->first_init = 1; return 0;}static int ppc_4xx_eth_send (struct eth_device *dev, volatile void *ptr, int len){ struct enet_frame *ef_ptr; ulong time_start, time_now; unsigned long temp_txm0; EMAC_4XX_HW_PST hw_p = dev->priv; ef_ptr = (struct enet_frame *) ptr; /*-----------------------------------------------------------------------+ * Copy in our address into the frame. *-----------------------------------------------------------------------*/ (void) memcpy (ef_ptr->source_addr, dev->enetaddr, ENET_ADDR_LENGTH); /*-----------------------------------------------------------------------+ * If frame is too long or too short, modify length. *-----------------------------------------------------------------------*/ /* TBS: where does the fragment go???? */ if (len > ENET_MAX_MTU) len = ENET_MAX_MTU; /* memcpy ((void *) &tx_buff[tx_slot], (const void *) ptr, len); */ memcpy ((void *) hw_p->txbuf_ptr, (const void *) ptr, len); flush_dcache_range((u32)hw_p->txbuf_ptr, (u32)hw_p->txbuf_ptr + len); /*-----------------------------------------------------------------------+ * set TX Buffer busy, and send it *-----------------------------------------------------------------------*/ hw_p->tx[hw_p->tx_slot].ctrl = (MAL_TX_CTRL_LAST | EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP) & ~(EMAC_TX_CTRL_ISA | EMAC_TX_CTRL_RSA); if ((NUM_TX_BUFF - 1) == hw_p->tx_slot) hw_p->tx[hw_p->tx_slot].ctrl |= MAL_TX_CTRL_WRAP; hw_p->tx[hw_p->tx_slot].data_len = (short) len; hw_p->tx[hw_p->tx_slot].ctrl |= MAL_TX_CTRL_READY; sync(); out_be32((void *)EMAC_TXM0 + hw_p->hw_addr, in_be32((void *)EMAC_TXM0 + hw_p->hw_addr) | EMAC_TXM0_GNP0);#ifdef INFO_4XX_ENET hw_p->stats.pkts_tx++;#endif /*-----------------------------------------------------------------------+ * poll unitl the packet is sent and then make sure it is OK *-----------------------------------------------------------------------*/ time_start = get_timer (0); while (1) { temp_txm0 = in_be32((void *)EMAC_TXM0 + hw_p->hw_addr); /* loop until either TINT turns on or 3 seconds elapse */ if ((temp_txm0 & EMAC_TXM0_GNP0) != 0) { /* transmit is done, so now check for errors * If there is an error, an interrupt should * happen when we return */ time_now = get_timer (0); if ((time_now - time_start) > 3000) { return (-1); } } else { return (len); } }}int enetInt (struct eth_device *dev){ int serviced; int rc = -1; /* default to not us */ u32 mal_isr; u32 emac_isr = 0; u32 mal_eob; u32 uic_mal; u32 uic_mal_err; u32 uic_emac; u32 uic_emac_b; EMAC_4XX_HW_PST hw_p; /* * Because the mal is generic, we need to get the current * eth device */#if defined(CONFIG_NET_MULTI) dev = eth_get_dev();#else dev = emac0_dev;#endif hw_p = dev->priv; /* enter loop that stays in interrupt code until nothing to service */ do { serviced = 0; uic_mal = mfdcr(UIC_BASE_MAL + UIC_MSR); uic_mal_err = mfdcr(UIC_BASE_MAL_ERR + UIC_MSR); uic_emac = mfdcr(UIC_BASE_EMAC + UIC_MSR); uic_emac_b = mfdcr(UIC_BASE_EMAC_B + UIC_MSR); if (!(uic_mal & (UIC_MAL_RXEOB | UIC_MAL_TXEOB)) && !(uic_mal_err & (UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)) && !(uic_emac & UIC_ETHx) && !(uic_emac_b & UIC_ETHxB)) { /* not for us */ return (rc); } /* get and clear controller status interrupts */ /* look at MAL and EMAC error interrupts */ if (uic_mal_err & (UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)) { /* we have a MAL error interrupt */ mal_isr = mfdcr(malesr); mal_err(dev, mal_isr, uic_mal_err, MAL_UIC_DEF, MAL_UIC_ERR); /* clear MAL error interrupt status bits */ mtdcr(UIC_BASE_MAL_ERR + UIC_SR, UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE); return -1; } /* look for EMAC errors */ if ((uic_emac & UIC_ETHx) || (uic_emac_b & UIC_ETHxB)) { emac_isr = in_be32((void *)EMAC_ISR + hw_p->hw_addr); emac_err(dev, emac_isr); /* clear EMAC error interrupt status bits */ mtdcr(UIC_BASE_EMAC + UIC_SR, UIC_ETHx); mtdcr(UIC_BASE_EMAC_B + UIC_SR, UIC_ETHxB); return -1; } /* handle MAX TX EOB interrupt from a tx */ if (uic_mal & UIC_MAL_TXEOB) { /* clear MAL interrupt status bits */ mal_eob = mfdcr(maltxeobisr); mtdcr(maltxeobisr, mal_eob); mtdcr(UIC_BASE_MAL + UIC_SR, UIC_MAL_TXEOB); /* indicate that we serviced an interrupt */ serviced = 1; rc = 0; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?