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