/* * This function sends a single packet on the network * and returns 0 on successful transmit or negative for error */ static int davinci_emac_send(struct eth_device *edev, void *packet, int length) { struct davinci_emac_priv *priv = edev->priv; uint64_t start; int ret_status; dev_dbg(priv->dev, "+ emac_send (length %d)\n", length); /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ if (length < EMAC_MIN_ETHERNET_PKT_SIZE) { length = EMAC_MIN_ETHERNET_PKT_SIZE; } /* Populate the TX descriptor */ writel(0, priv->emac_tx_desc + EMAC_DESC_NEXT); writel((uint8_t *) packet, priv->emac_tx_desc + EMAC_DESC_BUFFER); writel((length & 0xffff), priv->emac_tx_desc + EMAC_DESC_BUFF_OFF_LEN); writel(((length & 0xffff) | EMAC_CPPI_SOP_BIT | EMAC_CPPI_OWNERSHIP_BIT | EMAC_CPPI_EOP_BIT), priv->emac_tx_desc + EMAC_DESC_PKT_FLAG_LEN); dma_sync_single_for_device((unsigned long)packet, length, DMA_TO_DEVICE); /* Send the packet */ writel(BD_TO_HW(priv->emac_tx_desc), priv->adap_emac + EMAC_TX0HDP); /* Wait for packet to complete or link down */ start = get_time_ns(); while (1) { if (readl(priv->adap_emac + EMAC_TXINTSTATRAW) & 0x01) { /* Acknowledge the TX descriptor */ writel(BD_TO_HW(priv->emac_tx_desc), priv->adap_emac + EMAC_TX0CP); ret_status = 0; break; } if (is_timeout(start, 100 * MSECOND)) { ret_status = -ETIMEDOUT; break; } } dma_sync_single_for_cpu((unsigned long)packet, length, DMA_TO_DEVICE); dev_dbg(priv->dev, "- emac_send (ret_status %i)\n", ret_status); return ret_status; }
/* * This function sends a single packet on the network and returns * positive number (number of bytes transmitted) or negative for error */ static int davinci_eth_send_packet (struct eth_device *dev, void *packet, int length) { int ret_status = -1; int index; tx_send_loop = 0; index = get_active_phy(); if (index == -1) { printf(" WARN: emac_send_packet: No link\n"); return (ret_status); } /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ if (length < EMAC_MIN_ETHERNET_PKT_SIZE) { length = EMAC_MIN_ETHERNET_PKT_SIZE; } /* Populate the TX descriptor */ emac_tx_desc->next = 0; emac_tx_desc->buffer = (u_int8_t *) packet; emac_tx_desc->buff_off_len = (length & 0xffff); emac_tx_desc->pkt_flag_len = ((length & 0xffff) | EMAC_CPPI_SOP_BIT | EMAC_CPPI_OWNERSHIP_BIT | EMAC_CPPI_EOP_BIT); flush_dcache_range((unsigned long)packet, (unsigned long)packet + ALIGN(length, PKTALIGN)); /* Send the packet */ writel(BD_TO_HW((unsigned long)emac_tx_desc), &adap_emac->TX0HDP); /* Wait for packet to complete or link down */ while (1) { if (!phy[index].get_link_speed(active_phy_addr[index])) { davinci_eth_ch_teardown (EMAC_CH_TX); return (ret_status); } if (readl(&adap_emac->TXINTSTATRAW) & 0x01) { ret_status = length; break; } tx_send_loop++; } return (ret_status); }
/* * This function sends a single packet on the network and returns * positive number (number of bytes transmitted) or negative for error */ static int davinci_eth_send_packet (struct eth_device *dev, volatile void *packet, int length) { int ret_status = -1; tx_send_loop = 0; /* Return error if no link */ if (!phy.get_link_speed (active_phy_addr)) { printf ("WARN: emac_send_packet: No link\n"); return (ret_status); } /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ if (length < EMAC_MIN_ETHERNET_PKT_SIZE) { length = EMAC_MIN_ETHERNET_PKT_SIZE; } /* Populate the TX descriptor */ emac_tx_desc->next = 0; emac_tx_desc->buffer = (u_int8_t *) packet; emac_tx_desc->buff_off_len = (length & 0xffff); emac_tx_desc->pkt_flag_len = ((length & 0xffff) | EMAC_CPPI_SOP_BIT | EMAC_CPPI_OWNERSHIP_BIT | EMAC_CPPI_EOP_BIT); /* Send the packet */ adap_emac->TX0HDP = BD_TO_HW((unsigned int) emac_tx_desc); /* Wait for packet to complete or link down */ while (1) { if (!phy.get_link_speed (active_phy_addr)) { davinci_eth_ch_teardown (EMAC_CH_TX); return (ret_status); } if (adap_emac->TXINTSTATRAW & 0x01) { ret_status = length; break; } tx_send_loop++; } return (ret_status); }
/* * This function handles receipt of a packet from the network */ static int davinci_eth_rcv_packet (struct eth_device *dev) { volatile emac_desc *rx_curr_desc; volatile emac_desc *curr_desc; volatile emac_desc *tail_desc; int status, ret = -1; rx_curr_desc = emac_rx_active_head; if (!rx_curr_desc) return 0; status = rx_curr_desc->pkt_flag_len; if ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0) { if (status & EMAC_CPPI_RX_ERROR_FRAME) { /* Error in packet - discard it and requeue desc */ printf ("WARN: emac_rcv_pkt: Error in packet\n"); } else { unsigned long tmp = (unsigned long)rx_curr_desc->buffer; unsigned short len = rx_curr_desc->buff_off_len & 0xffff; invalidate_dcache_range(tmp, tmp + ALIGN(len, PKTALIGN)); net_process_received_packet(rx_curr_desc->buffer, len); ret = len; } /* Ack received packet descriptor */ writel(BD_TO_HW((ulong)rx_curr_desc), &adap_emac->RX0CP); curr_desc = rx_curr_desc; emac_rx_active_head = (volatile emac_desc *) (HW_TO_BD(rx_curr_desc->next)); if (status & EMAC_CPPI_EOQ_BIT) { if (emac_rx_active_head) { writel(BD_TO_HW((ulong)emac_rx_active_head), &adap_emac->RX0HDP); } else { emac_rx_queue_active = 0; printf ("INFO:emac_rcv_packet: RX Queue not active\n"); } } /* Recycle RX descriptor */ rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; rx_curr_desc->next = 0; if (emac_rx_active_head == 0) { printf ("INFO: emac_rcv_pkt: active queue head = 0\n"); emac_rx_active_head = curr_desc; emac_rx_active_tail = curr_desc; if (emac_rx_queue_active != 0) { writel(BD_TO_HW((ulong)emac_rx_active_head), &adap_emac->RX0HDP); printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); emac_rx_queue_active = 1; } } else { tail_desc = emac_rx_active_tail; emac_rx_active_tail = curr_desc; tail_desc->next = BD_TO_HW((ulong) curr_desc); status = tail_desc->pkt_flag_len; if (status & EMAC_CPPI_EOQ_BIT) { writel(BD_TO_HW((ulong)curr_desc), &adap_emac->RX0HDP); status &= ~EMAC_CPPI_EOQ_BIT; tail_desc->pkt_flag_len = status; } } return (ret); } return (0); }
/* Eth device open */ static int davinci_eth_open(struct eth_device *dev, bd_t *bis) { dv_reg_p addr; u_int32_t clkdiv, cnt, mac_control; uint16_t __maybe_unused lpa_val; volatile emac_desc *rx_desc; int index; debug_emac("+ emac_open\n"); /* Reset EMAC module and disable interrupts in wrapper */ writel(1, &adap_emac->SOFTRESET); while (readl(&adap_emac->SOFTRESET) != 0) ; #if defined(DAVINCI_EMAC_VERSION2) writel(1, &adap_ewrap->softrst); while (readl(&adap_ewrap->softrst) != 0) ; #else writel(0, &adap_ewrap->EWCTL); for (cnt = 0; cnt < 5; cnt++) { clkdiv = readl(&adap_ewrap->EWCTL); } #endif #if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ defined(CONFIG_MACH_DAVINCI_DA850_EVM) adap_ewrap->c0rxen = adap_ewrap->c1rxen = adap_ewrap->c2rxen = 0; adap_ewrap->c0txen = adap_ewrap->c1txen = adap_ewrap->c2txen = 0; adap_ewrap->c0miscen = adap_ewrap->c1miscen = adap_ewrap->c2miscen = 0; #endif rx_desc = emac_rx_desc; writel(1, &adap_emac->TXCONTROL); writel(1, &adap_emac->RXCONTROL); davinci_eth_set_mac_addr(dev); /* Set DMA 8 TX / 8 RX Head pointers to 0 */ addr = &adap_emac->TX0HDP; for (cnt = 0; cnt < 8; cnt++) writel(0, addr++); addr = &adap_emac->RX0HDP; for (cnt = 0; cnt < 8; cnt++) writel(0, addr++); /* Clear Statistics (do this before setting MacControl register) */ addr = &adap_emac->RXGOODFRAMES; for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) writel(0, addr++); /* No multicast addressing */ writel(0, &adap_emac->MACHASH1); writel(0, &adap_emac->MACHASH2); /* Create RX queue and set receive process in place */ emac_rx_active_head = emac_rx_desc; for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { rx_desc->next = BD_TO_HW((u_int32_t)(rx_desc + 1)); rx_desc->buffer = &emac_rx_buffers[cnt * EMAC_RXBUF_SIZE]; rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; rx_desc++; } /* Finalize the rx desc list */ rx_desc--; rx_desc->next = 0; emac_rx_active_tail = rx_desc; emac_rx_queue_active = 1; /* Enable TX/RX */ writel(EMAC_MAX_ETHERNET_PKT_SIZE, &adap_emac->RXMAXLEN); writel(0, &adap_emac->RXBUFFEROFFSET); /* * No fancy configs - Use this for promiscous debug * - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ writel(EMAC_RXMBPENABLE_RXBROADEN, &adap_emac->RXMBPENABLE); /* Enable ch 0 only */ writel(1, &adap_emac->RXUNICASTSET); /* Init MDIO & get link state */ clkdiv = CONFIG_SYS_EMAC_TI_CLKDIV; writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT, &adap_mdio->CONTROL); /* We need to wait for MDIO to start */ udelay(1000); index = get_active_phy(); if (index == -1) return(0); /* Enable MII interface */ mac_control = EMAC_MACCONTROL_MIIEN_ENABLE; #ifdef DAVINCI_EMAC_GIG_ENABLE davinci_eth_phy_read(active_phy_addr[index], MII_STAT1000, &lpa_val); if (lpa_val & PHY_1000BTSR_1000FD) { debug_emac("eth_open : gigabit negotiated\n"); mac_control |= EMAC_MACCONTROL_FULLDUPLEX_ENABLE; mac_control |= EMAC_MACCONTROL_GIGABIT_ENABLE; } #endif davinci_eth_phy_read(active_phy_addr[index], MII_LPA, &lpa_val); if (lpa_val & (LPA_100FULL | LPA_10FULL)) /* set EMAC for Full Duplex */ mac_control |= EMAC_MACCONTROL_FULLDUPLEX_ENABLE; #if defined(CONFIG_SOC_DA8XX) || \ (defined(CONFIG_OMAP34XX) && defined(CONFIG_DRIVER_TI_EMAC_USE_RMII)) mac_control |= EMAC_MACCONTROL_RMIISPEED_100; #endif writel(mac_control, &adap_emac->MACCONTROL); /* Start receive process */ writel(BD_TO_HW((u_int32_t)emac_rx_desc), &adap_emac->RX0HDP); debug_emac("- emac_open\n"); return(1); }
/* * This function handles receipt of a packet from the network */ static int davinci_eth_rcv_packet (struct eth_device *dev) { volatile emac_desc *rx_curr_desc; volatile emac_desc *curr_desc; volatile emac_desc *tail_desc; int status, ret = -1; rx_curr_desc = emac_rx_active_head; status = rx_curr_desc->pkt_flag_len; if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) { if (status & EMAC_CPPI_RX_ERROR_FRAME) { /* Error in packet - discard it and requeue desc */ printf ("WARN: emac_rcv_pkt: Error in packet\n"); } else { NetReceive (rx_curr_desc->buffer, (rx_curr_desc->buff_off_len & 0xffff)); ret = rx_curr_desc->buff_off_len & 0xffff; } /* Ack received packet descriptor */ adap_emac->RX0CP = BD_TO_HW((unsigned int) rx_curr_desc); curr_desc = rx_curr_desc; emac_rx_active_head = (volatile emac_desc *) (HW_TO_BD(rx_curr_desc->next)); if (status & EMAC_CPPI_EOQ_BIT) { if (emac_rx_active_head) { adap_emac->RX0HDP = BD_TO_HW((unsigned int) emac_rx_active_head); } else { emac_rx_queue_active = 0; printf ("INFO:emac_rcv_packet: RX Queue not active\n"); } } /* Recycle RX descriptor */ rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; rx_curr_desc->next = 0; if (emac_rx_active_head == 0) { printf ("INFO: emac_rcv_pkt: active queue head = 0\n"); emac_rx_active_head = curr_desc; emac_rx_active_tail = curr_desc; if (emac_rx_queue_active != 0) { adap_emac->RX0HDP = BD_TO_HW((unsigned int) emac_rx_active_head); printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); emac_rx_queue_active = 1; } } else { tail_desc = emac_rx_active_tail; emac_rx_active_tail = curr_desc; tail_desc->next = BD_TO_HW((unsigned int) curr_desc); status = tail_desc->pkt_flag_len; if (status & EMAC_CPPI_EOQ_BIT) { adap_emac->RX0HDP = BD_TO_HW((unsigned int) curr_desc); status &= ~EMAC_CPPI_EOQ_BIT; tail_desc->pkt_flag_len = status; } } return (ret); } return (0); }
/* Eth device open */ static int davinci_eth_open(struct eth_device *dev, bd_t *bis) { dv_reg_p addr; u_int32_t clkdiv, cnt; volatile emac_desc *rx_desc; u_int16_t lpa_val; debug_emac("+ emac_open\n"); /* Reset EMAC module and disable interrupts in wrapper */ adap_emac->SOFTRESET = 1; while (adap_emac->SOFTRESET != 0) {;} #if (defined(CONFIG_SOC_DM646x) || defined(CONFIG_SOC_DM365) || \ defined(CONFIG_OMAP3_AM3517EVM) || defined(CONFIG_OMAP3_AM3517CRANE)) adap_ewrap->SOFTRST = 1; while (adap_ewrap->SOFTRST != 0) {;} #else adap_ewrap->EWCTL = 0; for (cnt = 0; cnt < 5; cnt++) { clkdiv = adap_ewrap->EWCTL; } #endif rx_desc = emac_rx_desc; adap_emac->TXCONTROL = 0x01; adap_emac->RXCONTROL = 0x01; /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */ /* Using channel 0 only - other channels are disabled */ adap_emac->MACINDEX = 0; adap_emac->MACADDRHI = (davinci_eth_mac_addr[3] << 24) | (davinci_eth_mac_addr[2] << 16) | (davinci_eth_mac_addr[1] << 8) | (davinci_eth_mac_addr[0]); #if (defined(CONFIG_SOC_DM646x) || defined(CONFIG_SOC_DM365) || \ defined(CONFIG_OMAP3_AM3517EVM) || defined(CONFIG_OMAP3_AM3517CRANE)) adap_emac->MACADDRLO = (davinci_eth_mac_addr[5] << 8) | (davinci_eth_mac_addr[4]| (1 << 19) | (1 << 20)); #else adap_emac->MACADDRLO = (davinci_eth_mac_addr[5] << 8) | (davinci_eth_mac_addr[4]); #endif adap_emac->MACHASH1 = 0; adap_emac->MACHASH2 = 0; /* Set source MAC address - REQUIRED */ adap_emac->MACSRCADDRHI = (davinci_eth_mac_addr[3] << 24) | (davinci_eth_mac_addr[2] << 16) | (davinci_eth_mac_addr[1] << 8) | (davinci_eth_mac_addr[0]); adap_emac->MACSRCADDRLO = (davinci_eth_mac_addr[4] << 8) | (davinci_eth_mac_addr[5]); /* Set DMA 8 TX / 8 RX Head pointers to 0 */ addr = &adap_emac->TX0HDP; for(cnt = 0; cnt < 16; cnt++) *addr++ = 0; addr = &adap_emac->RX0HDP; for(cnt = 0; cnt < 16; cnt++) *addr++ = 0; /* Clear Statistics (do this before setting MacControl register) */ addr = &adap_emac->RXGOODFRAMES; for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) *addr++ = 0; /* No multicast addressing */ adap_emac->MACHASH1 = 0; adap_emac->MACHASH2 = 0; /* Create RX queue and set receive process in place */ emac_rx_active_head = emac_rx_desc; for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { rx_desc->next = BD_TO_HW((u_int32_t)(rx_desc + 1)); rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; rx_desc++; } /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */ rx_desc--; rx_desc->next = 0; emac_rx_active_tail = rx_desc; emac_rx_queue_active = 1; /* Enable TX/RX */ adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE; adap_emac->RXBUFFEROFFSET = 0; /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN; /* Enable ch 0 only */ adap_emac->RXUNICASTSET = 0x01; /* Init MDIO & get link state */ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT); if (!phy.auto_negotiate(active_phy_addr)) return(0); davinci_eth_phy_read(active_phy_addr,PHY_ANLPAR,&lpa_val); if (lpa_val & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD) ) { /* set EMAC for Full Duplex */ adap_emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE; }else{ /*set EMAC for Half Duplex */ adap_emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; } #ifdef CONFIG_DRIVER_TI_EMAC_USE_RMII if (lpa_val & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX) ) { adap_emac->MACCONTROL |= EMAC_MACCONTROL_RMIISPEED_100; } else { adap_emac->MACCONTROL &= ~EMAC_MACCONTROL_RMIISPEED_100; } #endif /* Start receive process */ adap_emac->RX0HDP = BD_TO_HW((u_int32_t)emac_rx_desc); debug_emac("- emac_open\n"); return(1); }
/* * This function handles receipt of a packet from the network */ static int davinci_emac_recv(struct eth_device *edev) { struct davinci_emac_priv *priv = edev->priv; void __iomem *rx_curr_desc, *curr_desc, *tail_desc; unsigned char *pkt; int status, len, ret = -1; dev_dbg(priv->dev, "+ emac_recv\n"); rx_curr_desc = priv->emac_rx_active_head; status = readl(rx_curr_desc + EMAC_DESC_PKT_FLAG_LEN); if (status & EMAC_CPPI_OWNERSHIP_BIT) { ret = 0; goto out; } if (status & EMAC_CPPI_RX_ERROR_FRAME) { /* Error in packet - discard it and requeue desc */ dev_warn(priv->dev, "WARN: emac_rcv_pkt: Error in packet\n"); } else { pkt = (unsigned char *)readl(rx_curr_desc + EMAC_DESC_BUFFER); len = readl(rx_curr_desc + EMAC_DESC_BUFF_OFF_LEN) & 0xffff; dev_dbg(priv->dev, "| emac_recv got packet (length %i)\n", len); dma_sync_single_for_cpu((unsigned long)pkt, len, DMA_FROM_DEVICE); net_receive(edev, pkt, len); dma_sync_single_for_device((unsigned long)pkt, len, DMA_FROM_DEVICE); ret = len; } /* Ack received packet descriptor */ writel(BD_TO_HW(rx_curr_desc), priv->adap_emac + EMAC_RX0CP); curr_desc = rx_curr_desc; priv->emac_rx_active_head = HW_TO_BD(readl(rx_curr_desc + EMAC_DESC_NEXT)); if (status & EMAC_CPPI_EOQ_BIT) { if (priv->emac_rx_active_head) { writel(BD_TO_HW(priv->emac_rx_active_head), priv->adap_emac + EMAC_RX0HDP); } else { priv->emac_rx_queue_active = 0; dev_info(priv->dev, "INFO:emac_rcv_packet: RX Queue not active\n"); } } /* Recycle RX descriptor */ writel(EMAC_MAX_ETHERNET_PKT_SIZE, rx_curr_desc + EMAC_DESC_BUFF_OFF_LEN); writel(EMAC_CPPI_OWNERSHIP_BIT, rx_curr_desc + EMAC_DESC_PKT_FLAG_LEN); writel(0, rx_curr_desc + EMAC_DESC_NEXT); if (priv->emac_rx_active_head == 0) { dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0\n"); priv->emac_rx_active_head = curr_desc; priv->emac_rx_active_tail = curr_desc; if (priv->emac_rx_queue_active != 0) { writel(BD_TO_HW(priv->emac_rx_active_head), priv->adap_emac + EMAC_RX0HDP); dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); priv->emac_rx_queue_active = 1; } } else { tail_desc = priv->emac_rx_active_tail; priv->emac_rx_active_tail = curr_desc; writel(BD_TO_HW(curr_desc), tail_desc + EMAC_DESC_NEXT); status = readl(tail_desc + EMAC_DESC_PKT_FLAG_LEN); if (status & EMAC_CPPI_EOQ_BIT) { writel(BD_TO_HW(curr_desc), priv->adap_emac + EMAC_RX0HDP); status &= ~EMAC_CPPI_EOQ_BIT; writel(status, tail_desc + EMAC_DESC_PKT_FLAG_LEN); } } out: dev_dbg(priv->dev, "- emac_recv\n"); return ret; }
static int davinci_emac_open(struct eth_device *edev) { struct davinci_emac_priv *priv = edev->priv; uint32_t clkdiv, cnt; void __iomem *rx_desc; unsigned long mac_hi, mac_lo; int ret; dev_dbg(priv->dev, "+ emac_open\n"); dev_dbg(priv->dev, "emac->TXIDVER: 0x%08x\n", readl(priv->adap_emac + EMAC_TXIDVER)); dev_dbg(priv->dev, "emac->RXIDVER: 0x%08x\n", readl(priv->adap_emac + EMAC_RXIDVER)); /* Reset EMAC module and disable interrupts in wrapper */ writel(1, priv->adap_emac + EMAC_SOFTRESET); while (readl(priv->adap_emac + EMAC_SOFTRESET) != 0); writel(1, priv->adap_ewrap + EMAC_EWRAP_SOFTRESET); while (readl(priv->adap_ewrap + EMAC_EWRAP_SOFTRESET) != 0); writel(0, priv->adap_ewrap + EMAC_EWRAP_C0RXEN); writel(0, priv->adap_ewrap + EMAC_EWRAP_C1RXEN); writel(0, priv->adap_ewrap + EMAC_EWRAP_C2RXEN); writel(0, priv->adap_ewrap + EMAC_EWRAP_C0TXEN); writel(0, priv->adap_ewrap + EMAC_EWRAP_C1TXEN); writel(0, priv->adap_ewrap + EMAC_EWRAP_C2TXEN); writel(0, priv->adap_ewrap + EMAC_EWRAP_C0MISCEN); writel(0, priv->adap_ewrap + EMAC_EWRAP_C1MISCEN); writel(0, priv->adap_ewrap + EMAC_EWRAP_C2MISCEN); rx_desc = priv->emac_rx_desc; /* * Set MAC Addresses & Init multicast Hash to 0 (disable any multicast * receive) * Use channel 0 only - other channels are disabled */ writel(0, priv->adap_emac + EMAC_MACINDEX); mac_hi = (priv->mac_addr[3] << 24) | (priv->mac_addr[2] << 16) | (priv->mac_addr[1] << 8) | (priv->mac_addr[0]); mac_lo = (priv->mac_addr[5] << 8) | (priv->mac_addr[4]); writel(mac_hi, priv->adap_emac + EMAC_MACADDRHI); writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH, priv->adap_emac + EMAC_MACADDRLO); /* Set source MAC address - REQUIRED */ writel(mac_hi, priv->adap_emac + EMAC_MACSRCADDRHI); writel(mac_lo, priv->adap_emac + EMAC_MACSRCADDRLO); /* Set DMA head and completion pointers to 0 */ for(cnt = 0; cnt < 8; cnt++) { writel(0, (void *)priv->adap_emac + EMAC_TX0HDP + 4 * cnt); writel(0, (void *)priv->adap_emac + EMAC_RX0HDP + 4 * cnt); writel(0, (void *)priv->adap_emac + EMAC_TX0CP + 4 * cnt); writel(0, (void *)priv->adap_emac + EMAC_RX0CP + 4 * cnt); } /* Clear Statistics (do this before setting MacControl register) */ for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) writel(0, (void *)priv->adap_emac + EMAC_RXGOODFRAMES + 4 * cnt); /* No multicast addressing */ writel(0, priv->adap_emac + EMAC_MACHASH1); writel(0, priv->adap_emac + EMAC_MACHASH2); writel(0x01, priv->adap_emac + EMAC_TXCONTROL); writel(0x01, priv->adap_emac + EMAC_RXCONTROL); /* Create RX queue and set receive process in place */ priv->emac_rx_active_head = priv->emac_rx_desc; for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { writel(BD_TO_HW(rx_desc + EMAC_DESC_SIZE), rx_desc + EMAC_DESC_NEXT); writel(&priv->emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)], rx_desc + EMAC_DESC_BUFFER); writel(EMAC_MAX_ETHERNET_PKT_SIZE, rx_desc + EMAC_DESC_BUFF_OFF_LEN); writel(EMAC_CPPI_OWNERSHIP_BIT, rx_desc + EMAC_DESC_PKT_FLAG_LEN); rx_desc += EMAC_DESC_SIZE; } /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */ rx_desc -= EMAC_DESC_SIZE; writel(0, rx_desc + EMAC_DESC_NEXT); priv->emac_rx_active_tail = rx_desc; priv->emac_rx_queue_active = 1; /* Enable TX/RX */ writel(EMAC_MAX_ETHERNET_PKT_SIZE, priv->adap_emac + EMAC_RXMAXLEN); writel(0, priv->adap_emac + EMAC_RXBUFFEROFFSET); /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ writel(EMAC_RXMBPENABLE_RXBROADEN, priv->adap_emac + EMAC_RXMBPENABLE); /* Enable ch 0 only */ writel(0x01, priv->adap_emac + EMAC_RXUNICASTSET); /* Enable MII interface and full duplex mode (using RMMI) */ writel((EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE | EMAC_MACCONTROL_RMIISPEED_100), priv->adap_emac + EMAC_MACCONTROL); /* Init MDIO & get link state */ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT, priv->adap_mdio + EMAC_MDIO_CONTROL); /* Start receive process */ writel(BD_TO_HW(priv->emac_rx_desc), priv->adap_emac + EMAC_RX0HDP); ret = phy_device_connect(edev, &priv->miibus, priv->phy_addr, NULL, priv->phy_flags, priv->interface); if (ret) return ret; dev_dbg(priv->dev, "- emac_open\n"); return 0; }