brintos

brintos / linux-shallow public Read only

0
0
Text · 14.7 KiB · d413d76 Raw
554 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*******************************************************************************3  This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.4  DWC Ether MAC 10/100/1000 Universal version 3.41a  has been used for5  developing this code.6 7  This only implements the mac core functions for this chip.8 9  Copyright (C) 2007-2009  STMicroelectronics Ltd10 11 12  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>13*******************************************************************************/14 15#include <linux/crc32.h>16#include <linux/slab.h>17#include <linux/ethtool.h>18#include <linux/io.h>19#include "stmmac.h"20#include "stmmac_pcs.h"21#include "dwmac1000.h"22 23static void dwmac1000_core_init(struct mac_device_info *hw,24				struct net_device *dev)25{26	void __iomem *ioaddr = hw->pcsr;27	u32 value = readl(ioaddr + GMAC_CONTROL);28	int mtu = dev->mtu;29 30	/* Configure GMAC core */31	value |= GMAC_CORE_INIT;32 33	if (mtu > 1500)34		value |= GMAC_CONTROL_2K;35	if (mtu > 2000)36		value |= GMAC_CONTROL_JE;37 38	if (hw->ps) {39		value |= GMAC_CONTROL_TE;40 41		value &= ~hw->link.speed_mask;42		switch (hw->ps) {43		case SPEED_1000:44			value |= hw->link.speed1000;45			break;46		case SPEED_100:47			value |= hw->link.speed100;48			break;49		case SPEED_10:50			value |= hw->link.speed10;51			break;52		}53	}54 55	writel(value, ioaddr + GMAC_CONTROL);56 57	/* Mask GMAC interrupts */58	value = GMAC_INT_DEFAULT_MASK;59 60	if (hw->pcs)61		value &= ~GMAC_INT_DISABLE_PCS;62 63	writel(value, ioaddr + GMAC_INT_MASK);64 65#ifdef STMMAC_VLAN_TAG_USED66	/* Tag detection without filtering */67	writel(0x0, ioaddr + GMAC_VLAN_TAG);68#endif69}70 71static int dwmac1000_rx_ipc_enable(struct mac_device_info *hw)72{73	void __iomem *ioaddr = hw->pcsr;74	u32 value = readl(ioaddr + GMAC_CONTROL);75 76	if (hw->rx_csum)77		value |= GMAC_CONTROL_IPC;78	else79		value &= ~GMAC_CONTROL_IPC;80 81	writel(value, ioaddr + GMAC_CONTROL);82 83	value = readl(ioaddr + GMAC_CONTROL);84 85	return !!(value & GMAC_CONTROL_IPC);86}87 88static void dwmac1000_dump_regs(struct mac_device_info *hw, u32 *reg_space)89{90	void __iomem *ioaddr = hw->pcsr;91	int i;92 93	for (i = 0; i < 55; i++)94		reg_space[i] = readl(ioaddr + i * 4);95}96 97static void dwmac1000_set_umac_addr(struct mac_device_info *hw,98				    const unsigned char *addr,99				    unsigned int reg_n)100{101	void __iomem *ioaddr = hw->pcsr;102	stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),103			    GMAC_ADDR_LOW(reg_n));104}105 106static void dwmac1000_get_umac_addr(struct mac_device_info *hw,107				    unsigned char *addr,108				    unsigned int reg_n)109{110	void __iomem *ioaddr = hw->pcsr;111	stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),112			    GMAC_ADDR_LOW(reg_n));113}114 115static void dwmac1000_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,116				 int mcbitslog2)117{118	int numhashregs, regs;119 120	switch (mcbitslog2) {121	case 6:122		writel(mcfilterbits[0], ioaddr + GMAC_HASH_LOW);123		writel(mcfilterbits[1], ioaddr + GMAC_HASH_HIGH);124		return;125	case 7:126		numhashregs = 4;127		break;128	case 8:129		numhashregs = 8;130		break;131	default:132		pr_debug("STMMAC: err in setting multicast filter\n");133		return;134	}135	for (regs = 0; regs < numhashregs; regs++)136		writel(mcfilterbits[regs],137		       ioaddr + GMAC_EXTHASH_BASE + regs * 4);138}139 140static void dwmac1000_set_filter(struct mac_device_info *hw,141				 struct net_device *dev)142{143	void __iomem *ioaddr = (void __iomem *)dev->base_addr;144	unsigned int value = 0;145	unsigned int perfect_addr_number = hw->unicast_filter_entries;146	u32 mc_filter[8];147	int mcbitslog2 = hw->mcast_bits_log2;148 149	pr_debug("%s: # mcasts %d, # unicast %d\n", __func__,150		 netdev_mc_count(dev), netdev_uc_count(dev));151 152	memset(mc_filter, 0, sizeof(mc_filter));153 154	if (dev->flags & IFF_PROMISC) {155		value = GMAC_FRAME_FILTER_PR | GMAC_FRAME_FILTER_PCF;156	} else if (dev->flags & IFF_ALLMULTI) {157		value = GMAC_FRAME_FILTER_PM;	/* pass all multi */158	} else if (!netdev_mc_empty(dev) && (mcbitslog2 == 0)) {159		/* Fall back to all multicast if we've no filter */160		value = GMAC_FRAME_FILTER_PM;161	} else if (!netdev_mc_empty(dev)) {162		struct netdev_hw_addr *ha;163 164		/* Hash filter for multicast */165		value = GMAC_FRAME_FILTER_HMC;166 167		netdev_for_each_mc_addr(ha, dev) {168			/* The upper n bits of the calculated CRC are used to169			 * index the contents of the hash table. The number of170			 * bits used depends on the hardware configuration171			 * selected at core configuration time.172			 */173			int bit_nr = bitrev32(~crc32_le(~0, ha->addr,174					      ETH_ALEN)) >>175					      (32 - mcbitslog2);176			/* The most significant bit determines the register to177			 * use (H/L) while the other 5 bits determine the bit178			 * within the register.179			 */180			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);181		}182	}183 184	value |= GMAC_FRAME_FILTER_HPF;185	dwmac1000_set_mchash(ioaddr, mc_filter, mcbitslog2);186 187	/* Handle multiple unicast addresses (perfect filtering) */188	if (netdev_uc_count(dev) > perfect_addr_number)189		/* Switch to promiscuous mode if more than unicast190		 * addresses are requested than supported by hardware.191		 */192		value |= GMAC_FRAME_FILTER_PR;193	else {194		int reg = 1;195		struct netdev_hw_addr *ha;196 197		netdev_for_each_uc_addr(ha, dev) {198			stmmac_set_mac_addr(ioaddr, ha->addr,199					    GMAC_ADDR_HIGH(reg),200					    GMAC_ADDR_LOW(reg));201			reg++;202		}203 204		while (reg < perfect_addr_number) {205			writel(0, ioaddr + GMAC_ADDR_HIGH(reg));206			writel(0, ioaddr + GMAC_ADDR_LOW(reg));207			reg++;208		}209	}210 211#ifdef FRAME_FILTER_DEBUG212	/* Enable Receive all mode (to debug filtering_fail errors) */213	value |= GMAC_FRAME_FILTER_RA;214#endif215	writel(value, ioaddr + GMAC_FRAME_FILTER);216}217 218 219static void dwmac1000_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,220				unsigned int fc, unsigned int pause_time,221				u32 tx_cnt)222{223	void __iomem *ioaddr = hw->pcsr;224	/* Set flow such that DZPQ in Mac Register 6 is 0,225	 * and unicast pause detect is enabled.226	 */227	unsigned int flow = GMAC_FLOW_CTRL_UP;228 229	pr_debug("GMAC Flow-Control:\n");230	if (fc & FLOW_RX) {231		pr_debug("\tReceive Flow-Control ON\n");232		flow |= GMAC_FLOW_CTRL_RFE;233	}234	if (fc & FLOW_TX) {235		pr_debug("\tTransmit Flow-Control ON\n");236		flow |= GMAC_FLOW_CTRL_TFE;237	}238 239	if (duplex) {240		pr_debug("\tduplex mode: PAUSE %d\n", pause_time);241		flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);242	}243 244	writel(flow, ioaddr + GMAC_FLOW_CTRL);245}246 247static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode)248{249	void __iomem *ioaddr = hw->pcsr;250	unsigned int pmt = 0;251 252	if (mode & WAKE_MAGIC) {253		pr_debug("GMAC: WOL Magic frame\n");254		pmt |= power_down | magic_pkt_en;255	}256	if (mode & WAKE_UCAST) {257		pr_debug("GMAC: WOL on global unicast\n");258		pmt |= power_down | global_unicast | wake_up_frame_en;259	}260 261	writel(pmt, ioaddr + GMAC_PMT);262}263 264/* RGMII or SMII interface */265static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x)266{267	u32 status;268 269	status = readl(ioaddr + GMAC_RGSMIIIS);270	x->irq_rgmii_n++;271 272	/* Check the link status */273	if (status & GMAC_RGSMIIIS_LNKSTS) {274		int speed_value;275 276		x->pcs_link = 1;277 278		speed_value = ((status & GMAC_RGSMIIIS_SPEED) >>279			       GMAC_RGSMIIIS_SPEED_SHIFT);280		if (speed_value == GMAC_RGSMIIIS_SPEED_125)281			x->pcs_speed = SPEED_1000;282		else if (speed_value == GMAC_RGSMIIIS_SPEED_25)283			x->pcs_speed = SPEED_100;284		else285			x->pcs_speed = SPEED_10;286 287		x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK);288 289		pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,290			x->pcs_duplex ? "Full" : "Half");291	} else {292		x->pcs_link = 0;293		pr_info("Link is Down\n");294	}295}296 297static int dwmac1000_irq_status(struct mac_device_info *hw,298				struct stmmac_extra_stats *x)299{300	void __iomem *ioaddr = hw->pcsr;301	u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);302	u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);303	int ret = 0;304 305	/* Discard masked bits */306	intr_status &= ~intr_mask;307 308	/* Not used events (e.g. MMC interrupts) are not handled. */309	if ((intr_status & GMAC_INT_STATUS_MMCTIS))310		x->mmc_tx_irq_n++;311	if (unlikely(intr_status & GMAC_INT_STATUS_MMCRIS))312		x->mmc_rx_irq_n++;313	if (unlikely(intr_status & GMAC_INT_STATUS_MMCCSUM))314		x->mmc_rx_csum_offload_irq_n++;315	if (unlikely(intr_status & GMAC_INT_DISABLE_PMT)) {316		/* clear the PMT bits 5 and 6 by reading the PMT status reg */317		readl(ioaddr + GMAC_PMT);318		x->irq_receive_pmt_irq_n++;319	}320 321	/* MAC tx/rx EEE LPI entry/exit interrupts */322	if (intr_status & GMAC_INT_STATUS_LPIIS) {323		/* Clean LPI interrupt by reading the Reg 12 */324		ret = readl(ioaddr + LPI_CTRL_STATUS);325 326		if (ret & LPI_CTRL_STATUS_TLPIEN)327			x->irq_tx_path_in_lpi_mode_n++;328		if (ret & LPI_CTRL_STATUS_TLPIEX)329			x->irq_tx_path_exit_lpi_mode_n++;330		if (ret & LPI_CTRL_STATUS_RLPIEN)331			x->irq_rx_path_in_lpi_mode_n++;332		if (ret & LPI_CTRL_STATUS_RLPIEX)333			x->irq_rx_path_exit_lpi_mode_n++;334	}335 336	dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);337 338	if (intr_status & PCS_RGSMIIIS_IRQ)339		dwmac1000_rgsmii(ioaddr, x);340 341	return ret;342}343 344static void dwmac1000_set_eee_mode(struct mac_device_info *hw,345				   bool en_tx_lpi_clockgating)346{347	void __iomem *ioaddr = hw->pcsr;348	u32 value;349 350	/*TODO - en_tx_lpi_clockgating treatment */351 352	/* Enable the link status receive on RGMII, SGMII ore SMII353	 * receive path and instruct the transmit to enter in LPI354	 * state.355	 */356	value = readl(ioaddr + LPI_CTRL_STATUS);357	value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;358	writel(value, ioaddr + LPI_CTRL_STATUS);359}360 361static void dwmac1000_reset_eee_mode(struct mac_device_info *hw)362{363	void __iomem *ioaddr = hw->pcsr;364	u32 value;365 366	value = readl(ioaddr + LPI_CTRL_STATUS);367	value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);368	writel(value, ioaddr + LPI_CTRL_STATUS);369}370 371static void dwmac1000_set_eee_pls(struct mac_device_info *hw, int link)372{373	void __iomem *ioaddr = hw->pcsr;374	u32 value;375 376	value = readl(ioaddr + LPI_CTRL_STATUS);377 378	if (link)379		value |= LPI_CTRL_STATUS_PLS;380	else381		value &= ~LPI_CTRL_STATUS_PLS;382 383	writel(value, ioaddr + LPI_CTRL_STATUS);384}385 386static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw)387{388	void __iomem *ioaddr = hw->pcsr;389	int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);390 391	/* Program the timers in the LPI timer control register:392	 * LS: minimum time (ms) for which the link393	 *  status from PHY should be ok before transmitting394	 *  the LPI pattern.395	 * TW: minimum time (us) for which the core waits396	 *  after it has stopped transmitting the LPI pattern.397	 */398	writel(value, ioaddr + LPI_TIMER_CTRL);399}400 401static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral,402			       bool loopback)403{404	dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback);405}406 407static void dwmac1000_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv)408{409	dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv);410}411 412static void dwmac1000_debug(struct stmmac_priv *priv, void __iomem *ioaddr,413			    struct stmmac_extra_stats *x,414			    u32 rx_queues, u32 tx_queues)415{416	u32 value = readl(ioaddr + GMAC_DEBUG);417 418	if (value & GMAC_DEBUG_TXSTSFSTS)419		x->mtl_tx_status_fifo_full++;420	if (value & GMAC_DEBUG_TXFSTS)421		x->mtl_tx_fifo_not_empty++;422	if (value & GMAC_DEBUG_TWCSTS)423		x->mmtl_fifo_ctrl++;424	if (value & GMAC_DEBUG_TRCSTS_MASK) {425		u32 trcsts = (value & GMAC_DEBUG_TRCSTS_MASK)426			     >> GMAC_DEBUG_TRCSTS_SHIFT;427		if (trcsts == GMAC_DEBUG_TRCSTS_WRITE)428			x->mtl_tx_fifo_read_ctrl_write++;429		else if (trcsts == GMAC_DEBUG_TRCSTS_TXW)430			x->mtl_tx_fifo_read_ctrl_wait++;431		else if (trcsts == GMAC_DEBUG_TRCSTS_READ)432			x->mtl_tx_fifo_read_ctrl_read++;433		else434			x->mtl_tx_fifo_read_ctrl_idle++;435	}436	if (value & GMAC_DEBUG_TXPAUSED)437		x->mac_tx_in_pause++;438	if (value & GMAC_DEBUG_TFCSTS_MASK) {439		u32 tfcsts = (value & GMAC_DEBUG_TFCSTS_MASK)440			      >> GMAC_DEBUG_TFCSTS_SHIFT;441 442		if (tfcsts == GMAC_DEBUG_TFCSTS_XFER)443			x->mac_tx_frame_ctrl_xfer++;444		else if (tfcsts == GMAC_DEBUG_TFCSTS_GEN_PAUSE)445			x->mac_tx_frame_ctrl_pause++;446		else if (tfcsts == GMAC_DEBUG_TFCSTS_WAIT)447			x->mac_tx_frame_ctrl_wait++;448		else449			x->mac_tx_frame_ctrl_idle++;450	}451	if (value & GMAC_DEBUG_TPESTS)452		x->mac_gmii_tx_proto_engine++;453	if (value & GMAC_DEBUG_RXFSTS_MASK) {454		u32 rxfsts = (value & GMAC_DEBUG_RXFSTS_MASK)455			     >> GMAC_DEBUG_RRCSTS_SHIFT;456 457		if (rxfsts == GMAC_DEBUG_RXFSTS_FULL)458			x->mtl_rx_fifo_fill_level_full++;459		else if (rxfsts == GMAC_DEBUG_RXFSTS_AT)460			x->mtl_rx_fifo_fill_above_thresh++;461		else if (rxfsts == GMAC_DEBUG_RXFSTS_BT)462			x->mtl_rx_fifo_fill_below_thresh++;463		else464			x->mtl_rx_fifo_fill_level_empty++;465	}466	if (value & GMAC_DEBUG_RRCSTS_MASK) {467		u32 rrcsts = (value & GMAC_DEBUG_RRCSTS_MASK) >>468			     GMAC_DEBUG_RRCSTS_SHIFT;469 470		if (rrcsts == GMAC_DEBUG_RRCSTS_FLUSH)471			x->mtl_rx_fifo_read_ctrl_flush++;472		else if (rrcsts == GMAC_DEBUG_RRCSTS_RSTAT)473			x->mtl_rx_fifo_read_ctrl_read_data++;474		else if (rrcsts == GMAC_DEBUG_RRCSTS_RDATA)475			x->mtl_rx_fifo_read_ctrl_status++;476		else477			x->mtl_rx_fifo_read_ctrl_idle++;478	}479	if (value & GMAC_DEBUG_RWCSTS)480		x->mtl_rx_fifo_ctrl_active++;481	if (value & GMAC_DEBUG_RFCFCSTS_MASK)482		x->mac_rx_frame_ctrl_fifo = (value & GMAC_DEBUG_RFCFCSTS_MASK)483					    >> GMAC_DEBUG_RFCFCSTS_SHIFT;484	if (value & GMAC_DEBUG_RPESTS)485		x->mac_gmii_rx_proto_engine++;486}487 488static void dwmac1000_set_mac_loopback(void __iomem *ioaddr, bool enable)489{490	u32 value = readl(ioaddr + GMAC_CONTROL);491 492	if (enable)493		value |= GMAC_CONTROL_LM;494	else495		value &= ~GMAC_CONTROL_LM;496 497	writel(value, ioaddr + GMAC_CONTROL);498}499 500const struct stmmac_ops dwmac1000_ops = {501	.core_init = dwmac1000_core_init,502	.set_mac = stmmac_set_mac,503	.rx_ipc = dwmac1000_rx_ipc_enable,504	.dump_regs = dwmac1000_dump_regs,505	.host_irq_status = dwmac1000_irq_status,506	.set_filter = dwmac1000_set_filter,507	.flow_ctrl = dwmac1000_flow_ctrl,508	.pmt = dwmac1000_pmt,509	.set_umac_addr = dwmac1000_set_umac_addr,510	.get_umac_addr = dwmac1000_get_umac_addr,511	.set_eee_mode = dwmac1000_set_eee_mode,512	.reset_eee_mode = dwmac1000_reset_eee_mode,513	.set_eee_timer = dwmac1000_set_eee_timer,514	.set_eee_pls = dwmac1000_set_eee_pls,515	.debug = dwmac1000_debug,516	.pcs_ctrl_ane = dwmac1000_ctrl_ane,517	.pcs_get_adv_lp = dwmac1000_get_adv_lp,518	.set_mac_loopback = dwmac1000_set_mac_loopback,519};520 521int dwmac1000_setup(struct stmmac_priv *priv)522{523	struct mac_device_info *mac = priv->hw;524 525	dev_info(priv->device, "\tDWMAC1000\n");526 527	priv->dev->priv_flags |= IFF_UNICAST_FLT;528	mac->pcsr = priv->ioaddr;529	mac->multicast_filter_bins = priv->plat->multicast_filter_bins;530	mac->unicast_filter_entries = priv->plat->unicast_filter_entries;531	mac->mcast_bits_log2 = 0;532 533	if (mac->multicast_filter_bins)534		mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);535 536	mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |537			 MAC_10 | MAC_100 | MAC_1000;538	mac->link.duplex = GMAC_CONTROL_DM;539	mac->link.speed10 = GMAC_CONTROL_PS;540	mac->link.speed100 = GMAC_CONTROL_PS | GMAC_CONTROL_FES;541	mac->link.speed1000 = 0;542	mac->link.speed_mask = GMAC_CONTROL_PS | GMAC_CONTROL_FES;543	mac->mii.addr = GMAC_MII_ADDR;544	mac->mii.data = GMAC_MII_DATA;545	mac->mii.addr_shift = 11;546	mac->mii.addr_mask = 0x0000F800;547	mac->mii.reg_shift = 6;548	mac->mii.reg_mask = 0x000007C0;549	mac->mii.clk_csr_shift = 2;550	mac->mii.clk_csr_mask = GENMASK(5, 2);551 552	return 0;553}554