Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1/*******************************************************************************
  2  This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
  3  DWC Ether MAC 10/100/1000 Universal version 3.41a  has been used for
  4  developing this code.
  5
  6  This only implements the mac core functions for this chip.
  7
  8  Copyright (C) 2007-2009  STMicroelectronics Ltd
  9
 10  This program is free software; you can redistribute it and/or modify it
 11  under the terms and conditions of the GNU General Public License,
 12  version 2, as published by the Free Software Foundation.
 13
 14  This program is distributed in the hope it will be useful, but WITHOUT
 15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 16  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 17  more details.
 18
 19  You should have received a copy of the GNU General Public License along with
 20  this program; if not, write to the Free Software Foundation, Inc.,
 21  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 22
 23  The full GNU General Public License is included in this distribution in
 24  the file called "COPYING".
 25
 26  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 27*******************************************************************************/
 28
 29#include <linux/crc32.h>
 30#include <linux/slab.h>
 31#include <asm/io.h>
 32#include "dwmac1000.h"
 33
 34static void dwmac1000_core_init(void __iomem *ioaddr)
 35{
 36	u32 value = readl(ioaddr + GMAC_CONTROL);
 37	value |= GMAC_CORE_INIT;
 38	writel(value, ioaddr + GMAC_CONTROL);
 39
 40	/* STBus Bridge Configuration */
 41	/*writel(0xc5608, ioaddr + 0x00007000);*/
 42
 43	/* Freeze MMC counters */
 44	writel(0x8, ioaddr + GMAC_MMC_CTRL);
 45	/* Mask GMAC interrupts */
 46	writel(0x207, ioaddr + GMAC_INT_MASK);
 47
 48#ifdef STMMAC_VLAN_TAG_USED
 49	/* Tag detection without filtering */
 50	writel(0x0, ioaddr + GMAC_VLAN_TAG);
 51#endif
 52}
 53
 54static int dwmac1000_rx_coe_supported(void __iomem *ioaddr)
 55{
 56	u32 value = readl(ioaddr + GMAC_CONTROL);
 57
 58	value |= GMAC_CONTROL_IPC;
 59	writel(value, ioaddr + GMAC_CONTROL);
 60
 61	value = readl(ioaddr + GMAC_CONTROL);
 62
 63	return !!(value & GMAC_CONTROL_IPC);
 64}
 65
 66static void dwmac1000_dump_regs(void __iomem *ioaddr)
 67{
 68	int i;
 69	pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr);
 70
 71	for (i = 0; i < 55; i++) {
 72		int offset = i * 4;
 73		pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
 74			offset, readl(ioaddr + offset));
 75	}
 76}
 77
 78static void dwmac1000_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
 79				unsigned int reg_n)
 80{
 81	stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
 82				GMAC_ADDR_LOW(reg_n));
 83}
 84
 85static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
 86				unsigned int reg_n)
 87{
 88	stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
 89				GMAC_ADDR_LOW(reg_n));
 90}
 91
 92static void dwmac1000_set_filter(struct net_device *dev)
 93{
 94	void __iomem *ioaddr = (void __iomem *) dev->base_addr;
 95	unsigned int value = 0;
 96
 97	CHIP_DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
 98		 __func__, netdev_mc_count(dev), netdev_uc_count(dev));
 99
100	if (dev->flags & IFF_PROMISC)
101		value = GMAC_FRAME_FILTER_PR;
102	else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
103		   || (dev->flags & IFF_ALLMULTI)) {
104		value = GMAC_FRAME_FILTER_PM;	/* pass all multi */
105		writel(0xffffffff, ioaddr + GMAC_HASH_HIGH);
106		writel(0xffffffff, ioaddr + GMAC_HASH_LOW);
107	} else if (!netdev_mc_empty(dev)) {
108		u32 mc_filter[2];
109		struct netdev_hw_addr *ha;
110
111		/* Hash filter for multicast */
112		value = GMAC_FRAME_FILTER_HMC;
113
114		memset(mc_filter, 0, sizeof(mc_filter));
115		netdev_for_each_mc_addr(ha, dev) {
116			/* The upper 6 bits of the calculated CRC are used to
117			   index the contens of the hash table */
118			int bit_nr =
119			    bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26;
120			/* The most significant bit determines the register to
121			 * use (H/L) while the other 5 bits determine the bit
122			 * within the register. */
123			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
124		}
125		writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
126		writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH);
127	}
128
129	/* Handle multiple unicast addresses (perfect filtering)*/
130	if (netdev_uc_count(dev) > GMAC_MAX_UNICAST_ADDRESSES)
131		/* Switch to promiscuous mode is more than 16 addrs
132		   are required */
133		value |= GMAC_FRAME_FILTER_PR;
134	else {
135		int reg = 1;
136		struct netdev_hw_addr *ha;
137
138		netdev_for_each_uc_addr(ha, dev) {
139			dwmac1000_set_umac_addr(ioaddr, ha->addr, reg);
140			reg++;
141		}
142	}
143
144#ifdef FRAME_FILTER_DEBUG
145	/* Enable Receive all mode (to debug filtering_fail errors) */
146	value |= GMAC_FRAME_FILTER_RA;
147#endif
148	writel(value, ioaddr + GMAC_FRAME_FILTER);
149
150	CHIP_DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
151	    "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER),
152	    readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
153}
154
155static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
156			   unsigned int fc, unsigned int pause_time)
157{
158	unsigned int flow = 0;
159
160	CHIP_DBG(KERN_DEBUG "GMAC Flow-Control:\n");
161	if (fc & FLOW_RX) {
162		CHIP_DBG(KERN_DEBUG "\tReceive Flow-Control ON\n");
163		flow |= GMAC_FLOW_CTRL_RFE;
164	}
165	if (fc & FLOW_TX) {
166		CHIP_DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n");
167		flow |= GMAC_FLOW_CTRL_TFE;
168	}
169
170	if (duplex) {
171		CHIP_DBG(KERN_DEBUG "\tduplex mode: PAUSE %d\n", pause_time);
172		flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
173	}
174
175	writel(flow, ioaddr + GMAC_FLOW_CTRL);
176}
177
178static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
179{
180	unsigned int pmt = 0;
181
182	if (mode & WAKE_MAGIC) {
183		CHIP_DBG(KERN_DEBUG "GMAC: WOL Magic frame\n");
184		pmt |= power_down | magic_pkt_en;
185	}
186	if (mode & WAKE_UCAST) {
187		CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
188		pmt |= global_unicast;
189	}
190
191	writel(pmt, ioaddr + GMAC_PMT);
192}
193
194
195static void dwmac1000_irq_status(void __iomem *ioaddr)
196{
197	u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
198
199	/* Not used events (e.g. MMC interrupts) are not handled. */
200	if ((intr_status & mmc_tx_irq))
201		CHIP_DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n",
202		    readl(ioaddr + GMAC_MMC_TX_INTR));
203	if (unlikely(intr_status & mmc_rx_irq))
204		CHIP_DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n",
205		    readl(ioaddr + GMAC_MMC_RX_INTR));
206	if (unlikely(intr_status & mmc_rx_csum_offload_irq))
207		CHIP_DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n",
208		    readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
209	if (unlikely(intr_status & pmt_irq)) {
210		CHIP_DBG(KERN_DEBUG "GMAC: received Magic frame\n");
211		/* clear the PMT bits 5 and 6 by reading the PMT
212		 * status register. */
213		readl(ioaddr + GMAC_PMT);
214	}
215}
216
217static const struct stmmac_ops dwmac1000_ops = {
218	.core_init = dwmac1000_core_init,
219	.rx_coe = dwmac1000_rx_coe_supported,
220	.dump_regs = dwmac1000_dump_regs,
221	.host_irq_status = dwmac1000_irq_status,
222	.set_filter = dwmac1000_set_filter,
223	.flow_ctrl = dwmac1000_flow_ctrl,
224	.pmt = dwmac1000_pmt,
225	.set_umac_addr = dwmac1000_set_umac_addr,
226	.get_umac_addr = dwmac1000_get_umac_addr,
227};
228
229struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
230{
231	struct mac_device_info *mac;
232	u32 uid = readl(ioaddr + GMAC_VERSION);
233
234	pr_info("\tDWMAC1000 - user ID: 0x%x, Synopsys ID: 0x%x\n",
235		((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
236
237	mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
238	if (!mac)
239		return NULL;
240
241	mac->mac = &dwmac1000_ops;
242	mac->dma = &dwmac1000_dma_ops;
243
244	mac->link.port = GMAC_CONTROL_PS;
245	mac->link.duplex = GMAC_CONTROL_DM;
246	mac->link.speed = GMAC_CONTROL_FES;
247	mac->mii.addr = GMAC_MII_ADDR;
248	mac->mii.data = GMAC_MII_DATA;
249
250	return mac;
251}