stmmac: Move the STMicroelectronics driver
[deliverable/linux.git] / drivers / net / ethernet / stmicro / stmmac / dwmac1000_core.c
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
34 static 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
54 static 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
66 static 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
78 static 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
85 static 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
92 static 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
155 static 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
178 static 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
195 static 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
217 static 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
229 struct 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 }
This page took 0.036563 seconds and 5 git commands to generate.