// SPDX-License-Identifier: GPL-2.0-only /******************************************************************************* This is the driver for the GMAC on-chip Ethernet controller for ST SoCs. DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for developing this code.
This only implements the mac core functions for this chip.
Copyright (C) 2007-2009 STMicroelectronics Ltd
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
staticvoid dwmac1000_core_init(struct mac_device_info *hw, struct net_device *dev)
{ void __iomem *ioaddr = hw->pcsr;
u32 value = readl(ioaddr + GMAC_CONTROL); int mtu = dev->mtu;
/* Configure GMAC core */
value |= GMAC_CORE_INIT;
if (mtu > 1500)
value |= GMAC_CONTROL_2K; if (mtu > 2000)
value |= GMAC_CONTROL_JE;
if (hw->ps) {
value |= GMAC_CONTROL_TE;
value &= ~hw->link.speed_mask; switch (hw->ps) { case SPEED_1000:
value |= hw->link.speed1000; break; case SPEED_100:
value |= hw->link.speed100; break; case SPEED_10:
value |= hw->link.speed10; break;
}
}
writel(value, ioaddr + GMAC_CONTROL);
/* Mask GMAC interrupts */
value = GMAC_INT_DEFAULT_MASK;
if (hw->pcs)
value &= ~GMAC_INT_DISABLE_PCS;
writel(value, ioaddr + GMAC_INT_MASK);
#ifdef STMMAC_VLAN_TAG_USED /* Tag detection without filtering */
writel(0x0, ioaddr + GMAC_VLAN_TAG); #endif
}
if (dev->flags & IFF_PROMISC) {
value = GMAC_FRAME_FILTER_PR | GMAC_FRAME_FILTER_PCF;
} elseif (dev->flags & IFF_ALLMULTI) {
value = GMAC_FRAME_FILTER_PM; /* pass all multi */
} elseif (!netdev_mc_empty(dev) && (mcbitslog2 == 0)) { /* Fall back to all multicast if we've no filter */
value = GMAC_FRAME_FILTER_PM;
} elseif (!netdev_mc_empty(dev)) { struct netdev_hw_addr *ha;
/* Hash filter for multicast */
value = GMAC_FRAME_FILTER_HMC;
netdev_for_each_mc_addr(ha, dev) { /* The upper n bits of the calculated CRC are used to * index the contents of the hash table. The number of * bits used depends on the hardware configuration * selected at core configuration time.
*/ int bit_nr = bitrev32(~crc32_le(~0, ha->addr,
ETH_ALEN)) >>
(32 - mcbitslog2); /* The most significant bit determines the register to * use (H/L) while the other 5 bits determine the bit * within the register.
*/
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
}
}
value |= GMAC_FRAME_FILTER_HPF;
dwmac1000_set_mchash(ioaddr, mc_filter, mcbitslog2);
/* Handle multiple unicast addresses (perfect filtering) */ if (netdev_uc_count(dev) > perfect_addr_number) /* Switch to promiscuous mode if more than unicast * addresses are requested than supported by hardware.
*/
value |= GMAC_FRAME_FILTER_PR; else { int reg = 1; struct netdev_hw_addr *ha;
/* Not used events (e.g. MMC interrupts) are not handled. */ if ((intr_status & GMAC_INT_STATUS_MMCTIS))
x->mmc_tx_irq_n++; if (unlikely(intr_status & GMAC_INT_STATUS_MMCRIS))
x->mmc_rx_irq_n++; if (unlikely(intr_status & GMAC_INT_STATUS_MMCCSUM))
x->mmc_rx_csum_offload_irq_n++; if (unlikely(intr_status & GMAC_INT_DISABLE_PMT)) { /* clear the PMT bits 5 and 6 by reading the PMT status reg */
readl(ioaddr + GMAC_PMT);
x->irq_receive_pmt_irq_n++;
}
/* MAC tx/rx EEE LPI entry/exit interrupts */ if (intr_status & GMAC_INT_STATUS_LPIIS) { /* Clean LPI interrupt by reading the Reg 12 */
ret = readl(ioaddr + LPI_CTRL_STATUS);
if (ret & LPI_CTRL_STATUS_TLPIEN)
x->irq_tx_path_in_lpi_mode_n++; if (ret & LPI_CTRL_STATUS_TLPIEX)
x->irq_tx_path_exit_lpi_mode_n++; if (ret & LPI_CTRL_STATUS_RLPIEN)
x->irq_rx_path_in_lpi_mode_n++; if (ret & LPI_CTRL_STATUS_RLPIEX)
x->irq_rx_path_exit_lpi_mode_n++;
}
if (link)
value |= LPI_CTRL_STATUS_PLS; else
value &= ~LPI_CTRL_STATUS_PLS;
writel(value, ioaddr + LPI_CTRL_STATUS);
}
staticvoid dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
{ void __iomem *ioaddr = hw->pcsr; int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
/* Program the timers in the LPI timer control register: * LS: minimum time (ms) for which the link * status from PHY should be ok before transmitting * the LPI pattern. * TW: minimum time (us) for which the core waits * after it has stopped transmitting the LPI pattern.
*/
writel(value, ioaddr + LPI_TIMER_CTRL);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.