PageRenderTime 97ms CodeModel.GetById 35ms app.highlight 44ms RepoModel.GetById 9ms app.codeStats 0ms

/drivers/net/stmmac/dwmac1000_core.c

https://bitbucket.org/ndreys/linux-sunxi
C | 250 lines | 166 code | 39 blank | 45 comment | 19 complexity | 77e7f097566e87e9666c89340e07f2e9 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  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 "dwmac1000.h"
 32
 33static void dwmac1000_core_init(void __iomem *ioaddr)
 34{
 35	u32 value = readl(ioaddr + GMAC_CONTROL);
 36	value |= GMAC_CORE_INIT;
 37	writel(value, ioaddr + GMAC_CONTROL);
 38
 39	/* STBus Bridge Configuration */
 40	/*writel(0xc5608, ioaddr + 0x00007000);*/
 41
 42	/* Freeze MMC counters */
 43	writel(0x8, ioaddr + GMAC_MMC_CTRL);
 44	/* Mask GMAC interrupts */
 45	writel(0x207, ioaddr + GMAC_INT_MASK);
 46
 47#ifdef STMMAC_VLAN_TAG_USED
 48	/* Tag detection without filtering */
 49	writel(0x0, ioaddr + GMAC_VLAN_TAG);
 50#endif
 51}
 52
 53static int dwmac1000_rx_coe_supported(void __iomem *ioaddr)
 54{
 55	u32 value = readl(ioaddr + GMAC_CONTROL);
 56
 57	value |= GMAC_CONTROL_IPC;
 58	writel(value, ioaddr + GMAC_CONTROL);
 59
 60	value = readl(ioaddr + GMAC_CONTROL);
 61
 62	return !!(value & GMAC_CONTROL_IPC);
 63}
 64
 65static void dwmac1000_dump_regs(void __iomem *ioaddr)
 66{
 67	int i;
 68	pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr);
 69
 70	for (i = 0; i < 55; i++) {
 71		int offset = i * 4;
 72		pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
 73			offset, readl(ioaddr + offset));
 74	}
 75}
 76
 77static void dwmac1000_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
 78				unsigned int reg_n)
 79{
 80	stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
 81				GMAC_ADDR_LOW(reg_n));
 82}
 83
 84static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
 85				unsigned int reg_n)
 86{
 87	stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
 88				GMAC_ADDR_LOW(reg_n));
 89}
 90
 91static void dwmac1000_set_filter(struct net_device *dev)
 92{
 93	void __iomem *ioaddr = (void __iomem *) dev->base_addr;
 94	unsigned int value = 0;
 95
 96	CHIP_DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
 97		 __func__, netdev_mc_count(dev), netdev_uc_count(dev));
 98
 99	if (dev->flags & IFF_PROMISC)
100		value = GMAC_FRAME_FILTER_PR;
101	else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
102		   || (dev->flags & IFF_ALLMULTI)) {
103		value = GMAC_FRAME_FILTER_PM;	/* pass all multi */
104		writel(0xffffffff, ioaddr + GMAC_HASH_HIGH);
105		writel(0xffffffff, ioaddr + GMAC_HASH_LOW);
106	} else if (!netdev_mc_empty(dev)) {
107		u32 mc_filter[2];
108		struct netdev_hw_addr *ha;
109
110		/* Hash filter for multicast */
111		value = GMAC_FRAME_FILTER_HMC;
112
113		memset(mc_filter, 0, sizeof(mc_filter));
114		netdev_for_each_mc_addr(ha, dev) {
115			/* The upper 6 bits of the calculated CRC are used to
116			   index the contens of the hash table */
117			int bit_nr =
118			    bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26;
119			/* The most significant bit determines the register to
120			 * use (H/L) while the other 5 bits determine the bit
121			 * within the register. */
122			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
123		}
124		writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
125		writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH);
126	}
127
128	/* Handle multiple unicast addresses (perfect filtering)*/
129	if (netdev_uc_count(dev) > GMAC_MAX_UNICAST_ADDRESSES)
130		/* Switch to promiscuous mode is more than 16 addrs
131		   are required */
132		value |= GMAC_FRAME_FILTER_PR;
133	else {
134		int reg = 1;
135		struct netdev_hw_addr *ha;
136
137		netdev_for_each_uc_addr(ha, dev) {
138			dwmac1000_set_umac_addr(ioaddr, ha->addr, reg);
139			reg++;
140		}
141	}
142
143#ifdef FRAME_FILTER_DEBUG
144	/* Enable Receive all mode (to debug filtering_fail errors) */
145	value |= GMAC_FRAME_FILTER_RA;
146#endif
147	writel(value, ioaddr + GMAC_FRAME_FILTER);
148
149	CHIP_DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
150	    "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER),
151	    readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
152}
153
154static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
155			   unsigned int fc, unsigned int pause_time)
156{
157	unsigned int flow = 0;
158
159	CHIP_DBG(KERN_DEBUG "GMAC Flow-Control:\n");
160	if (fc & FLOW_RX) {
161		CHIP_DBG(KERN_DEBUG "\tReceive Flow-Control ON\n");
162		flow |= GMAC_FLOW_CTRL_RFE;
163	}
164	if (fc & FLOW_TX) {
165		CHIP_DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n");
166		flow |= GMAC_FLOW_CTRL_TFE;
167	}
168
169	if (duplex) {
170		CHIP_DBG(KERN_DEBUG "\tduplex mode: PAUSE %d\n", pause_time);
171		flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
172	}
173
174	writel(flow, ioaddr + GMAC_FLOW_CTRL);
175}
176
177static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
178{
179	unsigned int pmt = 0;
180
181	if (mode & WAKE_MAGIC) {
182		CHIP_DBG(KERN_DEBUG "GMAC: WOL Magic frame\n");
183		pmt |= power_down | magic_pkt_en;
184	}
185	if (mode & WAKE_UCAST) {
186		CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
187		pmt |= global_unicast;
188	}
189
190	writel(pmt, ioaddr + GMAC_PMT);
191}
192
193
194static void dwmac1000_irq_status(void __iomem *ioaddr)
195{
196	u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
197
198	/* Not used events (e.g. MMC interrupts) are not handled. */
199	if ((intr_status & mmc_tx_irq))
200		CHIP_DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n",
201		    readl(ioaddr + GMAC_MMC_TX_INTR));
202	if (unlikely(intr_status & mmc_rx_irq))
203		CHIP_DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n",
204		    readl(ioaddr + GMAC_MMC_RX_INTR));
205	if (unlikely(intr_status & mmc_rx_csum_offload_irq))
206		CHIP_DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n",
207		    readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
208	if (unlikely(intr_status & pmt_irq)) {
209		CHIP_DBG(KERN_DEBUG "GMAC: received Magic frame\n");
210		/* clear the PMT bits 5 and 6 by reading the PMT
211		 * status register. */
212		readl(ioaddr + GMAC_PMT);
213	}
214}
215
216static const struct stmmac_ops dwmac1000_ops = {
217	.core_init = dwmac1000_core_init,
218	.rx_coe = dwmac1000_rx_coe_supported,
219	.dump_regs = dwmac1000_dump_regs,
220	.host_irq_status = dwmac1000_irq_status,
221	.set_filter = dwmac1000_set_filter,
222	.flow_ctrl = dwmac1000_flow_ctrl,
223	.pmt = dwmac1000_pmt,
224	.set_umac_addr = dwmac1000_set_umac_addr,
225	.get_umac_addr = dwmac1000_get_umac_addr,
226};
227
228struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
229{
230	struct mac_device_info *mac;
231	u32 uid = readl(ioaddr + GMAC_VERSION);
232
233	pr_info("\tDWMAC1000 - user ID: 0x%x, Synopsys ID: 0x%x\n",
234		((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
235
236	mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
237	if (!mac)
238		return NULL;
239
240	mac->mac = &dwmac1000_ops;
241	mac->dma = &dwmac1000_dma_ops;
242
243	mac->link.port = GMAC_CONTROL_PS;
244	mac->link.duplex = GMAC_CONTROL_DM;
245	mac->link.speed = GMAC_CONTROL_FES;
246	mac->mii.addr = GMAC_MII_ADDR;
247	mac->mii.data = GMAC_MII_DATA;
248
249	return mac;
250}