diff options
author | Domen Puncer <domen.puncer@telargo.com> | 2007-10-26 12:07:49 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-29 05:59:10 -0400 |
commit | 5d031e9e7e9ad5aa6516646f955c6262478e1acd (patch) | |
tree | 6cfe45ad29278e80f239cac39f52249d1bcbc851 /drivers/net | |
parent | af0900537f90b58fcfb7a7c821c661be8301fc9b (diff) |
FEC - fast ethernet controller for mpc52xx
Driver for ethernet on mpc5200/mpc5200b SoCs (FEC).
Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
Acked-by: Dale Farnsworth <dale@farnsworth.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Kconfig | 24 | ||||
-rw-r--r-- | drivers/net/Makefile | 4 | ||||
-rw-r--r-- | drivers/net/fec_mpc52xx.c | 1112 | ||||
-rw-r--r-- | drivers/net/fec_mpc52xx.h | 313 | ||||
-rw-r--r-- | drivers/net/fec_mpc52xx_phy.c | 198 |
5 files changed, 1651 insertions, 0 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 72d3447fb99b..867cb7345b5f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -1881,6 +1881,30 @@ config FEC2 | |||
1881 | Say Y here if you want to use the second built-in 10/100 Fast | 1881 | Say Y here if you want to use the second built-in 10/100 Fast |
1882 | ethernet controller on some Motorola ColdFire processors. | 1882 | ethernet controller on some Motorola ColdFire processors. |
1883 | 1883 | ||
1884 | config FEC_MPC52xx | ||
1885 | tristate "MPC52xx FEC driver" | ||
1886 | depends on PPC_MPC52xx | ||
1887 | select PPC_BESTCOMM | ||
1888 | select PPC_BESTCOMM_FEC | ||
1889 | select CRC32 | ||
1890 | select PHYLIB | ||
1891 | ---help--- | ||
1892 | This option enables support for the MPC5200's on-chip | ||
1893 | Fast Ethernet Controller | ||
1894 | If compiled as module, it will be called 'fec_mpc52xx.ko'. | ||
1895 | |||
1896 | config FEC_MPC52xx_MDIO | ||
1897 | bool "MPC52xx FEC MDIO bus driver" | ||
1898 | depends on FEC_MPC52xx | ||
1899 | default y | ||
1900 | ---help--- | ||
1901 | The MPC5200's FEC can connect to the Ethernet either with | ||
1902 | an external MII PHY chip or 10 Mbps 7-wire interface | ||
1903 | (Motorola? industry standard). | ||
1904 | If your board uses an external PHY connected to FEC, enable this. | ||
1905 | If not sure, enable. | ||
1906 | If compiled as module, it will be called 'fec_mpc52xx_phy.ko'. | ||
1907 | |||
1884 | config NE_H8300 | 1908 | config NE_H8300 |
1885 | tristate "NE2000 compatible support for H8/300" | 1909 | tristate "NE2000 compatible support for H8/300" |
1886 | depends on H8300 | 1910 | depends on H8300 |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 593262065c9b..0e5fde4a1b2c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -96,6 +96,10 @@ obj-$(CONFIG_SHAPER) += shaper.o | |||
96 | obj-$(CONFIG_HP100) += hp100.o | 96 | obj-$(CONFIG_HP100) += hp100.o |
97 | obj-$(CONFIG_SMC9194) += smc9194.o | 97 | obj-$(CONFIG_SMC9194) += smc9194.o |
98 | obj-$(CONFIG_FEC) += fec.o | 98 | obj-$(CONFIG_FEC) += fec.o |
99 | obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o | ||
100 | ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) | ||
101 | obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o | ||
102 | endif | ||
99 | obj-$(CONFIG_68360_ENET) += 68360enet.o | 103 | obj-$(CONFIG_68360_ENET) += 68360enet.o |
100 | obj-$(CONFIG_WD80x3) += wd.o 8390.o | 104 | obj-$(CONFIG_WD80x3) += wd.o 8390.o |
101 | obj-$(CONFIG_EL2) += 3c503.o 8390.o | 105 | obj-$(CONFIG_EL2) += 3c503.o 8390.o |
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c new file mode 100644 index 000000000000..fc1cf0b742b0 --- /dev/null +++ b/drivers/net/fec_mpc52xx.c | |||
@@ -0,0 +1,1112 @@ | |||
1 | /* | ||
2 | * Driver for the MPC5200 Fast Ethernet Controller | ||
3 | * | ||
4 | * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> and | ||
5 | * now maintained by Sylvain Munaut <tnt@246tNt.com> | ||
6 | * | ||
7 | * Copyright (C) 2007 Domen Puncer, Telargo, Inc. | ||
8 | * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com> | ||
9 | * Copyright (C) 2003-2004 MontaVista, Software, Inc. | ||
10 | * | ||
11 | * This file is licensed under the terms of the GNU General Public License | ||
12 | * version 2. This program is licensed "as is" without any warranty of any | ||
13 | * kind, whether express or implied. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/spinlock.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/crc32.h> | ||
25 | #include <linux/hardirq.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/of_device.h> | ||
28 | #include <linux/of_platform.h> | ||
29 | |||
30 | #include <linux/netdevice.h> | ||
31 | #include <linux/etherdevice.h> | ||
32 | #include <linux/ethtool.h> | ||
33 | #include <linux/skbuff.h> | ||
34 | |||
35 | #include <asm/io.h> | ||
36 | #include <asm/delay.h> | ||
37 | #include <asm/mpc52xx.h> | ||
38 | |||
39 | #include <sysdev/bestcomm/bestcomm.h> | ||
40 | #include <sysdev/bestcomm/fec.h> | ||
41 | |||
42 | #include "fec_mpc52xx.h" | ||
43 | |||
44 | #define DRIVER_NAME "mpc52xx-fec" | ||
45 | |||
46 | static irqreturn_t mpc52xx_fec_interrupt(int, void *); | ||
47 | static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *); | ||
48 | static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *); | ||
49 | static void mpc52xx_fec_stop(struct net_device *dev); | ||
50 | static void mpc52xx_fec_start(struct net_device *dev); | ||
51 | static void mpc52xx_fec_reset(struct net_device *dev); | ||
52 | |||
53 | static u8 mpc52xx_fec_mac_addr[6]; | ||
54 | module_param_array_named(mac, mpc52xx_fec_mac_addr, byte, NULL, 0); | ||
55 | MODULE_PARM_DESC(mac, "six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe"); | ||
56 | |||
57 | #define MPC52xx_MESSAGES_DEFAULT ( NETIF_MSG_DRV | NETIF_MSG_PROBE | \ | ||
58 | NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFDOWN ) | ||
59 | static int debug = -1; /* the above default */ | ||
60 | module_param(debug, int, 0); | ||
61 | MODULE_PARM_DESC(debug, "debugging messages level"); | ||
62 | |||
63 | static void mpc52xx_fec_tx_timeout(struct net_device *dev) | ||
64 | { | ||
65 | dev_warn(&dev->dev, "transmit timed out\n"); | ||
66 | |||
67 | mpc52xx_fec_reset(dev); | ||
68 | |||
69 | dev->stats.tx_errors++; | ||
70 | |||
71 | netif_wake_queue(dev); | ||
72 | } | ||
73 | |||
74 | static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac) | ||
75 | { | ||
76 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
77 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
78 | |||
79 | out_be32(&fec->paddr1, *(u32 *)(&mac[0])); | ||
80 | out_be32(&fec->paddr2, (*(u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE); | ||
81 | } | ||
82 | |||
83 | static void mpc52xx_fec_get_paddr(struct net_device *dev, u8 *mac) | ||
84 | { | ||
85 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
86 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
87 | |||
88 | *(u32 *)(&mac[0]) = in_be32(&fec->paddr1); | ||
89 | *(u16 *)(&mac[4]) = in_be32(&fec->paddr2) >> 16; | ||
90 | } | ||
91 | |||
92 | static int mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr) | ||
93 | { | ||
94 | struct sockaddr *sock = addr; | ||
95 | |||
96 | memcpy(dev->dev_addr, sock->sa_data, dev->addr_len); | ||
97 | |||
98 | mpc52xx_fec_set_paddr(dev, sock->sa_data); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static void mpc52xx_fec_free_rx_buffers(struct net_device *dev, struct bcom_task *s) | ||
103 | { | ||
104 | while (!bcom_queue_empty(s)) { | ||
105 | struct bcom_fec_bd *bd; | ||
106 | struct sk_buff *skb; | ||
107 | |||
108 | skb = bcom_retrieve_buffer(s, NULL, (struct bcom_bd **)&bd); | ||
109 | dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_FROM_DEVICE); | ||
110 | kfree_skb(skb); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | static int mpc52xx_fec_alloc_rx_buffers(struct net_device *dev, struct bcom_task *rxtsk) | ||
115 | { | ||
116 | while (!bcom_queue_full(rxtsk)) { | ||
117 | struct sk_buff *skb; | ||
118 | struct bcom_fec_bd *bd; | ||
119 | |||
120 | skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE); | ||
121 | if (skb == NULL) | ||
122 | return -EAGAIN; | ||
123 | |||
124 | /* zero out the initial receive buffers to aid debugging */ | ||
125 | memset(skb->data, 0, FEC_RX_BUFFER_SIZE); | ||
126 | |||
127 | bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk); | ||
128 | |||
129 | bd->status = FEC_RX_BUFFER_SIZE; | ||
130 | bd->skb_pa = dma_map_single(&dev->dev, skb->data, | ||
131 | FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE); | ||
132 | |||
133 | bcom_submit_next_buffer(rxtsk, skb); | ||
134 | } | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* based on generic_adjust_link from fs_enet-main.c */ | ||
140 | static void mpc52xx_fec_adjust_link(struct net_device *dev) | ||
141 | { | ||
142 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
143 | struct phy_device *phydev = priv->phydev; | ||
144 | int new_state = 0; | ||
145 | |||
146 | if (phydev->link != PHY_DOWN) { | ||
147 | if (phydev->duplex != priv->duplex) { | ||
148 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
149 | u32 rcntrl; | ||
150 | u32 tcntrl; | ||
151 | |||
152 | new_state = 1; | ||
153 | priv->duplex = phydev->duplex; | ||
154 | |||
155 | rcntrl = in_be32(&fec->r_cntrl); | ||
156 | tcntrl = in_be32(&fec->x_cntrl); | ||
157 | |||
158 | rcntrl &= ~FEC_RCNTRL_DRT; | ||
159 | tcntrl &= ~FEC_TCNTRL_FDEN; | ||
160 | if (phydev->duplex == DUPLEX_FULL) | ||
161 | tcntrl |= FEC_TCNTRL_FDEN; /* FD enable */ | ||
162 | else | ||
163 | rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */ | ||
164 | |||
165 | out_be32(&fec->r_cntrl, rcntrl); | ||
166 | out_be32(&fec->x_cntrl, tcntrl); | ||
167 | } | ||
168 | |||
169 | if (phydev->speed != priv->speed) { | ||
170 | new_state = 1; | ||
171 | priv->speed = phydev->speed; | ||
172 | } | ||
173 | |||
174 | if (priv->link == PHY_DOWN) { | ||
175 | new_state = 1; | ||
176 | priv->link = phydev->link; | ||
177 | netif_schedule(dev); | ||
178 | netif_carrier_on(dev); | ||
179 | netif_start_queue(dev); | ||
180 | } | ||
181 | |||
182 | } else if (priv->link) { | ||
183 | new_state = 1; | ||
184 | priv->link = PHY_DOWN; | ||
185 | priv->speed = 0; | ||
186 | priv->duplex = -1; | ||
187 | netif_stop_queue(dev); | ||
188 | netif_carrier_off(dev); | ||
189 | } | ||
190 | |||
191 | if (new_state && netif_msg_link(priv)) | ||
192 | phy_print_status(phydev); | ||
193 | } | ||
194 | |||
195 | static int mpc52xx_fec_init_phy(struct net_device *dev) | ||
196 | { | ||
197 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
198 | struct phy_device *phydev; | ||
199 | char phy_id[BUS_ID_SIZE]; | ||
200 | |||
201 | snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, | ||
202 | (unsigned int)dev->base_addr, priv->phy_addr); | ||
203 | |||
204 | priv->link = PHY_DOWN; | ||
205 | priv->speed = 0; | ||
206 | priv->duplex = -1; | ||
207 | |||
208 | phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII); | ||
209 | if (IS_ERR(phydev)) { | ||
210 | dev_err(&dev->dev, "phy_connect failed\n"); | ||
211 | return PTR_ERR(phydev); | ||
212 | } | ||
213 | dev_info(&dev->dev, "attached phy %i to driver %s\n", | ||
214 | phydev->addr, phydev->drv->name); | ||
215 | |||
216 | priv->phydev = phydev; | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int mpc52xx_fec_phy_start(struct net_device *dev) | ||
222 | { | ||
223 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
224 | int err; | ||
225 | |||
226 | if (!priv->has_phy) | ||
227 | return 0; | ||
228 | |||
229 | err = mpc52xx_fec_init_phy(dev); | ||
230 | if (err) { | ||
231 | dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n"); | ||
232 | return err; | ||
233 | } | ||
234 | |||
235 | /* reset phy - this also wakes it from PDOWN */ | ||
236 | phy_write(priv->phydev, MII_BMCR, BMCR_RESET); | ||
237 | phy_start(priv->phydev); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void mpc52xx_fec_phy_stop(struct net_device *dev) | ||
243 | { | ||
244 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
245 | |||
246 | if (!priv->has_phy) | ||
247 | return; | ||
248 | |||
249 | phy_disconnect(priv->phydev); | ||
250 | /* power down phy */ | ||
251 | phy_stop(priv->phydev); | ||
252 | phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN); | ||
253 | } | ||
254 | |||
255 | static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv, | ||
256 | struct mii_ioctl_data *mii_data, int cmd) | ||
257 | { | ||
258 | if (!priv->has_phy) | ||
259 | return -ENOTSUPP; | ||
260 | |||
261 | return phy_mii_ioctl(priv->phydev, mii_data, cmd); | ||
262 | } | ||
263 | |||
264 | static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv) | ||
265 | { | ||
266 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
267 | |||
268 | if (!priv->has_phy) | ||
269 | return; | ||
270 | |||
271 | out_be32(&fec->mii_speed, priv->phy_speed); | ||
272 | } | ||
273 | |||
274 | static int mpc52xx_fec_open(struct net_device *dev) | ||
275 | { | ||
276 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
277 | int err = -EBUSY; | ||
278 | |||
279 | if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED, | ||
280 | DRIVER_NAME "_ctrl", dev)) { | ||
281 | dev_err(&dev->dev, "ctrl interrupt request failed\n"); | ||
282 | goto out; | ||
283 | } | ||
284 | if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0, | ||
285 | DRIVER_NAME "_rx", dev)) { | ||
286 | dev_err(&dev->dev, "rx interrupt request failed\n"); | ||
287 | goto free_ctrl_irq; | ||
288 | } | ||
289 | if (request_irq(priv->t_irq, &mpc52xx_fec_tx_interrupt, 0, | ||
290 | DRIVER_NAME "_tx", dev)) { | ||
291 | dev_err(&dev->dev, "tx interrupt request failed\n"); | ||
292 | goto free_2irqs; | ||
293 | } | ||
294 | |||
295 | bcom_fec_rx_reset(priv->rx_dmatsk); | ||
296 | bcom_fec_tx_reset(priv->tx_dmatsk); | ||
297 | |||
298 | err = mpc52xx_fec_alloc_rx_buffers(dev, priv->rx_dmatsk); | ||
299 | if (err) { | ||
300 | dev_err(&dev->dev, "mpc52xx_fec_alloc_rx_buffers failed\n"); | ||
301 | goto free_irqs; | ||
302 | } | ||
303 | |||
304 | err = mpc52xx_fec_phy_start(dev); | ||
305 | if (err) | ||
306 | goto free_skbs; | ||
307 | |||
308 | bcom_enable(priv->rx_dmatsk); | ||
309 | bcom_enable(priv->tx_dmatsk); | ||
310 | |||
311 | mpc52xx_fec_start(dev); | ||
312 | |||
313 | netif_start_queue(dev); | ||
314 | |||
315 | return 0; | ||
316 | |||
317 | free_skbs: | ||
318 | mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk); | ||
319 | |||
320 | free_irqs: | ||
321 | free_irq(priv->t_irq, dev); | ||
322 | free_2irqs: | ||
323 | free_irq(priv->r_irq, dev); | ||
324 | free_ctrl_irq: | ||
325 | free_irq(dev->irq, dev); | ||
326 | out: | ||
327 | |||
328 | return err; | ||
329 | } | ||
330 | |||
331 | static int mpc52xx_fec_close(struct net_device *dev) | ||
332 | { | ||
333 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
334 | |||
335 | netif_stop_queue(dev); | ||
336 | |||
337 | mpc52xx_fec_stop(dev); | ||
338 | |||
339 | mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk); | ||
340 | |||
341 | free_irq(dev->irq, dev); | ||
342 | free_irq(priv->r_irq, dev); | ||
343 | free_irq(priv->t_irq, dev); | ||
344 | |||
345 | mpc52xx_fec_phy_stop(dev); | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | /* This will only be invoked if your driver is _not_ in XOFF state. | ||
351 | * What this means is that you need not check it, and that this | ||
352 | * invariant will hold if you make sure that the netif_*_queue() | ||
353 | * calls are done at the proper times. | ||
354 | */ | ||
355 | static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
356 | { | ||
357 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
358 | struct bcom_fec_bd *bd; | ||
359 | |||
360 | if (bcom_queue_full(priv->tx_dmatsk)) { | ||
361 | if (net_ratelimit()) | ||
362 | dev_err(&dev->dev, "transmit queue overrun\n"); | ||
363 | return 1; | ||
364 | } | ||
365 | |||
366 | spin_lock_irq(&priv->lock); | ||
367 | dev->trans_start = jiffies; | ||
368 | |||
369 | bd = (struct bcom_fec_bd *) | ||
370 | bcom_prepare_next_buffer(priv->tx_dmatsk); | ||
371 | |||
372 | bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_TC; | ||
373 | bd->skb_pa = dma_map_single(&dev->dev, skb->data, skb->len, DMA_TO_DEVICE); | ||
374 | |||
375 | bcom_submit_next_buffer(priv->tx_dmatsk, skb); | ||
376 | |||
377 | if (bcom_queue_full(priv->tx_dmatsk)) { | ||
378 | netif_stop_queue(dev); | ||
379 | } | ||
380 | |||
381 | spin_unlock_irq(&priv->lock); | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | /* This handles BestComm transmit task interrupts | ||
387 | */ | ||
388 | static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id) | ||
389 | { | ||
390 | struct net_device *dev = dev_id; | ||
391 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
392 | |||
393 | spin_lock(&priv->lock); | ||
394 | |||
395 | while (bcom_buffer_done(priv->tx_dmatsk)) { | ||
396 | struct sk_buff *skb; | ||
397 | struct bcom_fec_bd *bd; | ||
398 | skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL, | ||
399 | (struct bcom_bd **)&bd); | ||
400 | dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_TO_DEVICE); | ||
401 | |||
402 | dev_kfree_skb_irq(skb); | ||
403 | } | ||
404 | |||
405 | netif_wake_queue(dev); | ||
406 | |||
407 | spin_unlock(&priv->lock); | ||
408 | |||
409 | return IRQ_HANDLED; | ||
410 | } | ||
411 | |||
412 | static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) | ||
413 | { | ||
414 | struct net_device *dev = dev_id; | ||
415 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
416 | |||
417 | while (bcom_buffer_done(priv->rx_dmatsk)) { | ||
418 | struct sk_buff *skb; | ||
419 | struct sk_buff *rskb; | ||
420 | struct bcom_fec_bd *bd; | ||
421 | u32 status; | ||
422 | |||
423 | rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status, | ||
424 | (struct bcom_bd **)&bd); | ||
425 | dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_FROM_DEVICE); | ||
426 | |||
427 | /* Test for errors in received frame */ | ||
428 | if (status & BCOM_FEC_RX_BD_ERRORS) { | ||
429 | /* Drop packet and reuse the buffer */ | ||
430 | bd = (struct bcom_fec_bd *) | ||
431 | bcom_prepare_next_buffer(priv->rx_dmatsk); | ||
432 | |||
433 | bd->status = FEC_RX_BUFFER_SIZE; | ||
434 | bd->skb_pa = dma_map_single(&dev->dev, rskb->data, | ||
435 | FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE); | ||
436 | |||
437 | bcom_submit_next_buffer(priv->rx_dmatsk, rskb); | ||
438 | |||
439 | dev->stats.rx_dropped++; | ||
440 | |||
441 | continue; | ||
442 | } | ||
443 | |||
444 | /* skbs are allocated on open, so now we allocate a new one, | ||
445 | * and remove the old (with the packet) */ | ||
446 | skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE); | ||
447 | if (skb) { | ||
448 | /* Process the received skb */ | ||
449 | int length = status & BCOM_FEC_RX_BD_LEN_MASK; | ||
450 | |||
451 | skb_put(rskb, length - 4); /* length without CRC32 */ | ||
452 | |||
453 | rskb->dev = dev; | ||
454 | rskb->protocol = eth_type_trans(rskb, dev); | ||
455 | |||
456 | netif_rx(rskb); | ||
457 | dev->last_rx = jiffies; | ||
458 | } else { | ||
459 | /* Can't get a new one : reuse the same & drop pkt */ | ||
460 | dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n"); | ||
461 | dev->stats.rx_dropped++; | ||
462 | |||
463 | skb = rskb; | ||
464 | } | ||
465 | |||
466 | bd = (struct bcom_fec_bd *) | ||
467 | bcom_prepare_next_buffer(priv->rx_dmatsk); | ||
468 | |||
469 | bd->status = FEC_RX_BUFFER_SIZE; | ||
470 | bd->skb_pa = dma_map_single(&dev->dev, rskb->data, | ||
471 | FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE); | ||
472 | |||
473 | bcom_submit_next_buffer(priv->rx_dmatsk, skb); | ||
474 | } | ||
475 | |||
476 | return IRQ_HANDLED; | ||
477 | } | ||
478 | |||
479 | static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id) | ||
480 | { | ||
481 | struct net_device *dev = dev_id; | ||
482 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
483 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
484 | u32 ievent; | ||
485 | |||
486 | ievent = in_be32(&fec->ievent); | ||
487 | |||
488 | ievent &= ~FEC_IEVENT_MII; /* mii is handled separately */ | ||
489 | if (!ievent) | ||
490 | return IRQ_NONE; | ||
491 | |||
492 | out_be32(&fec->ievent, ievent); /* clear pending events */ | ||
493 | |||
494 | if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) { | ||
495 | if (ievent & ~FEC_IEVENT_TFINT) | ||
496 | dev_dbg(&dev->dev, "ievent: %08x\n", ievent); | ||
497 | return IRQ_HANDLED; | ||
498 | } | ||
499 | |||
500 | if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR)) | ||
501 | dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n"); | ||
502 | if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR)) | ||
503 | dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n"); | ||
504 | |||
505 | mpc52xx_fec_reset(dev); | ||
506 | |||
507 | netif_wake_queue(dev); | ||
508 | return IRQ_HANDLED; | ||
509 | } | ||
510 | |||
511 | /* | ||
512 | * Get the current statistics. | ||
513 | * This may be called with the card open or closed. | ||
514 | */ | ||
515 | static struct net_device_stats *mpc52xx_fec_get_stats(struct net_device *dev) | ||
516 | { | ||
517 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
518 | struct net_device_stats *stats = &dev->stats; | ||
519 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
520 | |||
521 | stats->rx_bytes = in_be32(&fec->rmon_r_octets); | ||
522 | stats->rx_packets = in_be32(&fec->rmon_r_packets); | ||
523 | stats->rx_errors = in_be32(&fec->rmon_r_crc_align) + | ||
524 | in_be32(&fec->rmon_r_undersize) + | ||
525 | in_be32(&fec->rmon_r_oversize) + | ||
526 | in_be32(&fec->rmon_r_frag) + | ||
527 | in_be32(&fec->rmon_r_jab); | ||
528 | |||
529 | stats->tx_bytes = in_be32(&fec->rmon_t_octets); | ||
530 | stats->tx_packets = in_be32(&fec->rmon_t_packets); | ||
531 | stats->tx_errors = in_be32(&fec->rmon_t_crc_align) + | ||
532 | in_be32(&fec->rmon_t_undersize) + | ||
533 | in_be32(&fec->rmon_t_oversize) + | ||
534 | in_be32(&fec->rmon_t_frag) + | ||
535 | in_be32(&fec->rmon_t_jab); | ||
536 | |||
537 | stats->multicast = in_be32(&fec->rmon_r_mc_pkt); | ||
538 | stats->collisions = in_be32(&fec->rmon_t_col); | ||
539 | |||
540 | /* detailed rx_errors: */ | ||
541 | stats->rx_length_errors = in_be32(&fec->rmon_r_undersize) | ||
542 | + in_be32(&fec->rmon_r_oversize) | ||
543 | + in_be32(&fec->rmon_r_frag) | ||
544 | + in_be32(&fec->rmon_r_jab); | ||
545 | stats->rx_over_errors = in_be32(&fec->r_macerr); | ||
546 | stats->rx_crc_errors = in_be32(&fec->ieee_r_crc); | ||
547 | stats->rx_frame_errors = in_be32(&fec->ieee_r_align); | ||
548 | stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop); | ||
549 | stats->rx_missed_errors = in_be32(&fec->rmon_r_drop); | ||
550 | |||
551 | /* detailed tx_errors: */ | ||
552 | stats->tx_aborted_errors = 0; | ||
553 | stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr); | ||
554 | stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop); | ||
555 | stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe); | ||
556 | stats->tx_window_errors = in_be32(&fec->ieee_t_lcol); | ||
557 | |||
558 | return stats; | ||
559 | } | ||
560 | |||
561 | /* | ||
562 | * Read MIB counters in order to reset them, | ||
563 | * then zero all the stats fields in memory | ||
564 | */ | ||
565 | static void mpc52xx_fec_reset_stats(struct net_device *dev) | ||
566 | { | ||
567 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
568 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
569 | |||
570 | out_be32(&fec->mib_control, FEC_MIB_DISABLE); | ||
571 | memset_io(&fec->rmon_t_drop, 0, (__force u32)&fec->reserved10 - | ||
572 | (__force u32)&fec->rmon_t_drop); | ||
573 | out_be32(&fec->mib_control, 0); | ||
574 | |||
575 | memset(&dev->stats, 0, sizeof(dev->stats)); | ||
576 | } | ||
577 | |||
578 | /* | ||
579 | * Set or clear the multicast filter for this adaptor. | ||
580 | */ | ||
581 | static void mpc52xx_fec_set_multicast_list(struct net_device *dev) | ||
582 | { | ||
583 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
584 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
585 | u32 rx_control; | ||
586 | |||
587 | rx_control = in_be32(&fec->r_cntrl); | ||
588 | |||
589 | if (dev->flags & IFF_PROMISC) { | ||
590 | rx_control |= FEC_RCNTRL_PROM; | ||
591 | out_be32(&fec->r_cntrl, rx_control); | ||
592 | } else { | ||
593 | rx_control &= ~FEC_RCNTRL_PROM; | ||
594 | out_be32(&fec->r_cntrl, rx_control); | ||
595 | |||
596 | if (dev->flags & IFF_ALLMULTI) { | ||
597 | out_be32(&fec->gaddr1, 0xffffffff); | ||
598 | out_be32(&fec->gaddr2, 0xffffffff); | ||
599 | } else { | ||
600 | u32 crc; | ||
601 | int i; | ||
602 | struct dev_mc_list *dmi; | ||
603 | u32 gaddr1 = 0x00000000; | ||
604 | u32 gaddr2 = 0x00000000; | ||
605 | |||
606 | dmi = dev->mc_list; | ||
607 | for (i=0; i<dev->mc_count; i++) { | ||
608 | crc = ether_crc_le(6, dmi->dmi_addr) >> 26; | ||
609 | if (crc >= 32) | ||
610 | gaddr1 |= 1 << (crc-32); | ||
611 | else | ||
612 | gaddr2 |= 1 << crc; | ||
613 | dmi = dmi->next; | ||
614 | } | ||
615 | out_be32(&fec->gaddr1, gaddr1); | ||
616 | out_be32(&fec->gaddr2, gaddr2); | ||
617 | } | ||
618 | } | ||
619 | } | ||
620 | |||
621 | /** | ||
622 | * mpc52xx_fec_hw_init | ||
623 | * @dev: network device | ||
624 | * | ||
625 | * Setup various hardware setting, only needed once on start | ||
626 | */ | ||
627 | static void mpc52xx_fec_hw_init(struct net_device *dev) | ||
628 | { | ||
629 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
630 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
631 | int i; | ||
632 | |||
633 | /* Whack a reset. We should wait for this. */ | ||
634 | out_be32(&fec->ecntrl, FEC_ECNTRL_RESET); | ||
635 | for (i = 0; i < FEC_RESET_DELAY; ++i) { | ||
636 | if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0) | ||
637 | break; | ||
638 | udelay(1); | ||
639 | } | ||
640 | if (i == FEC_RESET_DELAY) | ||
641 | dev_err(&dev->dev, "FEC Reset timeout!\n"); | ||
642 | |||
643 | /* set pause to 0x20 frames */ | ||
644 | out_be32(&fec->op_pause, FEC_OP_PAUSE_OPCODE | 0x20); | ||
645 | |||
646 | /* high service request will be deasserted when there's < 7 bytes in fifo | ||
647 | * low service request will be deasserted when there's < 4*7 bytes in fifo | ||
648 | */ | ||
649 | out_be32(&fec->rfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7); | ||
650 | out_be32(&fec->tfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7); | ||
651 | |||
652 | /* alarm when <= x bytes in FIFO */ | ||
653 | out_be32(&fec->rfifo_alarm, 0x0000030c); | ||
654 | out_be32(&fec->tfifo_alarm, 0x00000100); | ||
655 | |||
656 | /* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */ | ||
657 | out_be32(&fec->x_wmrk, FEC_FIFO_WMRK_256B); | ||
658 | |||
659 | /* enable crc generation */ | ||
660 | out_be32(&fec->xmit_fsm, FEC_XMIT_FSM_APPEND_CRC | FEC_XMIT_FSM_ENABLE_CRC); | ||
661 | out_be32(&fec->iaddr1, 0x00000000); /* No individual filter */ | ||
662 | out_be32(&fec->iaddr2, 0x00000000); /* No individual filter */ | ||
663 | |||
664 | /* set phy speed. | ||
665 | * this can't be done in phy driver, since it needs to be called | ||
666 | * before fec stuff (even on resume) */ | ||
667 | mpc52xx_fec_phy_hw_init(priv); | ||
668 | } | ||
669 | |||
670 | /** | ||
671 | * mpc52xx_fec_start | ||
672 | * @dev: network device | ||
673 | * | ||
674 | * This function is called to start or restart the FEC during a link | ||
675 | * change. This happens on fifo errors or when switching between half | ||
676 | * and full duplex. | ||
677 | */ | ||
678 | static void mpc52xx_fec_start(struct net_device *dev) | ||
679 | { | ||
680 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
681 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
682 | u32 rcntrl; | ||
683 | u32 tcntrl; | ||
684 | u32 tmp; | ||
685 | |||
686 | /* clear sticky error bits */ | ||
687 | tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF; | ||
688 | out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp); | ||
689 | out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp); | ||
690 | |||
691 | /* FIFOs will reset on mpc52xx_fec_enable */ | ||
692 | out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET); | ||
693 | |||
694 | /* Set station address. */ | ||
695 | mpc52xx_fec_set_paddr(dev, dev->dev_addr); | ||
696 | |||
697 | mpc52xx_fec_set_multicast_list(dev); | ||
698 | |||
699 | /* set max frame len, enable flow control, select mii mode */ | ||
700 | rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */ | ||
701 | rcntrl |= FEC_RCNTRL_FCE; | ||
702 | |||
703 | if (priv->has_phy) | ||
704 | rcntrl |= FEC_RCNTRL_MII_MODE; | ||
705 | |||
706 | if (priv->duplex == DUPLEX_FULL) | ||
707 | tcntrl = FEC_TCNTRL_FDEN; /* FD enable */ | ||
708 | else { | ||
709 | rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */ | ||
710 | tcntrl = 0; | ||
711 | } | ||
712 | out_be32(&fec->r_cntrl, rcntrl); | ||
713 | out_be32(&fec->x_cntrl, tcntrl); | ||
714 | |||
715 | /* Clear any outstanding interrupt. */ | ||
716 | out_be32(&fec->ievent, 0xffffffff); | ||
717 | |||
718 | /* Enable interrupts we wish to service. */ | ||
719 | out_be32(&fec->imask, FEC_IMASK_ENABLE); | ||
720 | |||
721 | /* And last, enable the transmit and receive processing. */ | ||
722 | out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN); | ||
723 | out_be32(&fec->r_des_active, 0x01000000); | ||
724 | } | ||
725 | |||
726 | /** | ||
727 | * mpc52xx_fec_stop | ||
728 | * @dev: network device | ||
729 | * | ||
730 | * stop all activity on fec and empty dma buffers | ||
731 | */ | ||
732 | static void mpc52xx_fec_stop(struct net_device *dev) | ||
733 | { | ||
734 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
735 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
736 | unsigned long timeout; | ||
737 | |||
738 | /* disable all interrupts */ | ||
739 | out_be32(&fec->imask, 0); | ||
740 | |||
741 | /* Disable the rx task. */ | ||
742 | bcom_disable(priv->rx_dmatsk); | ||
743 | |||
744 | /* Wait for tx queue to drain, but only if we're in process context */ | ||
745 | if (!in_interrupt()) { | ||
746 | timeout = jiffies + msecs_to_jiffies(2000); | ||
747 | while (time_before(jiffies, timeout) && | ||
748 | !bcom_queue_empty(priv->tx_dmatsk)) | ||
749 | msleep(100); | ||
750 | |||
751 | if (time_after_eq(jiffies, timeout)) | ||
752 | dev_err(&dev->dev, "queues didn't drain\n"); | ||
753 | #if 1 | ||
754 | if (time_after_eq(jiffies, timeout)) { | ||
755 | dev_err(&dev->dev, " tx: index: %i, outdex: %i\n", | ||
756 | priv->tx_dmatsk->index, | ||
757 | priv->tx_dmatsk->outdex); | ||
758 | dev_err(&dev->dev, " rx: index: %i, outdex: %i\n", | ||
759 | priv->rx_dmatsk->index, | ||
760 | priv->rx_dmatsk->outdex); | ||
761 | } | ||
762 | #endif | ||
763 | } | ||
764 | |||
765 | bcom_disable(priv->tx_dmatsk); | ||
766 | |||
767 | /* Stop FEC */ | ||
768 | out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN); | ||
769 | |||
770 | return; | ||
771 | } | ||
772 | |||
773 | /* reset fec and bestcomm tasks */ | ||
774 | static void mpc52xx_fec_reset(struct net_device *dev) | ||
775 | { | ||
776 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
777 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
778 | |||
779 | mpc52xx_fec_stop(dev); | ||
780 | |||
781 | out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status)); | ||
782 | out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_RESET_FIFO); | ||
783 | |||
784 | mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk); | ||
785 | |||
786 | mpc52xx_fec_hw_init(dev); | ||
787 | |||
788 | phy_stop(priv->phydev); | ||
789 | phy_write(priv->phydev, MII_BMCR, BMCR_RESET); | ||
790 | phy_start(priv->phydev); | ||
791 | |||
792 | bcom_fec_rx_reset(priv->rx_dmatsk); | ||
793 | bcom_fec_tx_reset(priv->tx_dmatsk); | ||
794 | |||
795 | mpc52xx_fec_alloc_rx_buffers(dev, priv->rx_dmatsk); | ||
796 | |||
797 | bcom_enable(priv->rx_dmatsk); | ||
798 | bcom_enable(priv->tx_dmatsk); | ||
799 | |||
800 | mpc52xx_fec_start(dev); | ||
801 | } | ||
802 | |||
803 | |||
804 | /* ethtool interface */ | ||
805 | static void mpc52xx_fec_get_drvinfo(struct net_device *dev, | ||
806 | struct ethtool_drvinfo *info) | ||
807 | { | ||
808 | strcpy(info->driver, DRIVER_NAME); | ||
809 | } | ||
810 | |||
811 | static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
812 | { | ||
813 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
814 | return phy_ethtool_gset(priv->phydev, cmd); | ||
815 | } | ||
816 | |||
817 | static int mpc52xx_fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
818 | { | ||
819 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
820 | return phy_ethtool_sset(priv->phydev, cmd); | ||
821 | } | ||
822 | |||
823 | static u32 mpc52xx_fec_get_msglevel(struct net_device *dev) | ||
824 | { | ||
825 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
826 | return priv->msg_enable; | ||
827 | } | ||
828 | |||
829 | static void mpc52xx_fec_set_msglevel(struct net_device *dev, u32 level) | ||
830 | { | ||
831 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
832 | priv->msg_enable = level; | ||
833 | } | ||
834 | |||
835 | static const struct ethtool_ops mpc52xx_fec_ethtool_ops = { | ||
836 | .get_drvinfo = mpc52xx_fec_get_drvinfo, | ||
837 | .get_settings = mpc52xx_fec_get_settings, | ||
838 | .set_settings = mpc52xx_fec_set_settings, | ||
839 | .get_link = ethtool_op_get_link, | ||
840 | .get_msglevel = mpc52xx_fec_get_msglevel, | ||
841 | .set_msglevel = mpc52xx_fec_set_msglevel, | ||
842 | }; | ||
843 | |||
844 | |||
845 | static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
846 | { | ||
847 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
848 | |||
849 | return mpc52xx_fec_phy_mii_ioctl(priv, if_mii(rq), cmd); | ||
850 | } | ||
851 | |||
852 | /* ======================================================================== */ | ||
853 | /* OF Driver */ | ||
854 | /* ======================================================================== */ | ||
855 | |||
856 | static int __devinit | ||
857 | mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) | ||
858 | { | ||
859 | int rv; | ||
860 | struct net_device *ndev; | ||
861 | struct mpc52xx_fec_priv *priv = NULL; | ||
862 | struct resource mem; | ||
863 | const phandle *ph; | ||
864 | |||
865 | phys_addr_t rx_fifo; | ||
866 | phys_addr_t tx_fifo; | ||
867 | |||
868 | /* Get the ether ndev & it's private zone */ | ||
869 | ndev = alloc_etherdev(sizeof(struct mpc52xx_fec_priv)); | ||
870 | if (!ndev) | ||
871 | return -ENOMEM; | ||
872 | |||
873 | priv = netdev_priv(ndev); | ||
874 | |||
875 | /* Reserve FEC control zone */ | ||
876 | rv = of_address_to_resource(op->node, 0, &mem); | ||
877 | if (rv) { | ||
878 | printk(KERN_ERR DRIVER_NAME ": " | ||
879 | "Error while parsing device node resource\n" ); | ||
880 | return rv; | ||
881 | } | ||
882 | if ((mem.end - mem.start + 1) != sizeof(struct mpc52xx_fec)) { | ||
883 | printk(KERN_ERR DRIVER_NAME | ||
884 | " - invalid resource size (%lx != %x), check mpc52xx_devices.c\n", | ||
885 | (unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec)); | ||
886 | return -EINVAL; | ||
887 | } | ||
888 | |||
889 | if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), DRIVER_NAME)) | ||
890 | return -EBUSY; | ||
891 | |||
892 | /* Init ether ndev with what we have */ | ||
893 | ndev->open = mpc52xx_fec_open; | ||
894 | ndev->stop = mpc52xx_fec_close; | ||
895 | ndev->hard_start_xmit = mpc52xx_fec_hard_start_xmit; | ||
896 | ndev->do_ioctl = mpc52xx_fec_ioctl; | ||
897 | ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops; | ||
898 | ndev->get_stats = mpc52xx_fec_get_stats; | ||
899 | ndev->set_mac_address = mpc52xx_fec_set_mac_address; | ||
900 | ndev->set_multicast_list = mpc52xx_fec_set_multicast_list; | ||
901 | ndev->tx_timeout = mpc52xx_fec_tx_timeout; | ||
902 | ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT; | ||
903 | ndev->base_addr = mem.start; | ||
904 | |||
905 | priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */ | ||
906 | |||
907 | spin_lock_init(&priv->lock); | ||
908 | |||
909 | /* ioremap the zones */ | ||
910 | priv->fec = ioremap(mem.start, sizeof(struct mpc52xx_fec)); | ||
911 | |||
912 | if (!priv->fec) { | ||
913 | rv = -ENOMEM; | ||
914 | goto probe_error; | ||
915 | } | ||
916 | |||
917 | /* Bestcomm init */ | ||
918 | rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, rfifo_data); | ||
919 | tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, tfifo_data); | ||
920 | |||
921 | priv->rx_dmatsk = bcom_fec_rx_init(FEC_RX_NUM_BD, rx_fifo, FEC_RX_BUFFER_SIZE); | ||
922 | priv->tx_dmatsk = bcom_fec_tx_init(FEC_TX_NUM_BD, tx_fifo); | ||
923 | |||
924 | if (!priv->rx_dmatsk || !priv->tx_dmatsk) { | ||
925 | printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" ); | ||
926 | rv = -ENOMEM; | ||
927 | goto probe_error; | ||
928 | } | ||
929 | |||
930 | /* Get the IRQ we need one by one */ | ||
931 | /* Control */ | ||
932 | ndev->irq = irq_of_parse_and_map(op->node, 0); | ||
933 | |||
934 | /* RX */ | ||
935 | priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk); | ||
936 | |||
937 | /* TX */ | ||
938 | priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk); | ||
939 | |||
940 | /* MAC address init */ | ||
941 | if (!is_zero_ether_addr(mpc52xx_fec_mac_addr)) | ||
942 | memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6); | ||
943 | else | ||
944 | mpc52xx_fec_get_paddr(ndev, ndev->dev_addr); | ||
945 | |||
946 | priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT); | ||
947 | priv->duplex = DUPLEX_FULL; | ||
948 | |||
949 | /* is the phy present in device tree? */ | ||
950 | ph = of_get_property(op->node, "phy-handle", NULL); | ||
951 | if (ph) { | ||
952 | const unsigned int *prop; | ||
953 | struct device_node *phy_dn; | ||
954 | priv->has_phy = 1; | ||
955 | |||
956 | phy_dn = of_find_node_by_phandle(*ph); | ||
957 | prop = of_get_property(phy_dn, "reg", NULL); | ||
958 | priv->phy_addr = *prop; | ||
959 | |||
960 | of_node_put(phy_dn); | ||
961 | |||
962 | /* Phy speed */ | ||
963 | priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1; | ||
964 | } else { | ||
965 | dev_info(&ndev->dev, "can't find \"phy-handle\" in device" | ||
966 | " tree, using 7-wire mode\n"); | ||
967 | } | ||
968 | |||
969 | /* Hardware init */ | ||
970 | mpc52xx_fec_hw_init(ndev); | ||
971 | |||
972 | mpc52xx_fec_reset_stats(ndev); | ||
973 | |||
974 | /* Register the new network device */ | ||
975 | rv = register_netdev(ndev); | ||
976 | if (rv < 0) | ||
977 | goto probe_error; | ||
978 | |||
979 | /* We're done ! */ | ||
980 | dev_set_drvdata(&op->dev, ndev); | ||
981 | |||
982 | return 0; | ||
983 | |||
984 | |||
985 | /* Error handling - free everything that might be allocated */ | ||
986 | probe_error: | ||
987 | |||
988 | irq_dispose_mapping(ndev->irq); | ||
989 | |||
990 | if (priv->rx_dmatsk) | ||
991 | bcom_fec_rx_release(priv->rx_dmatsk); | ||
992 | if (priv->tx_dmatsk) | ||
993 | bcom_fec_tx_release(priv->tx_dmatsk); | ||
994 | |||
995 | if (priv->fec) | ||
996 | iounmap(priv->fec); | ||
997 | |||
998 | release_mem_region(mem.start, sizeof(struct mpc52xx_fec)); | ||
999 | |||
1000 | free_netdev(ndev); | ||
1001 | |||
1002 | return rv; | ||
1003 | } | ||
1004 | |||
1005 | static int | ||
1006 | mpc52xx_fec_remove(struct of_device *op) | ||
1007 | { | ||
1008 | struct net_device *ndev; | ||
1009 | struct mpc52xx_fec_priv *priv; | ||
1010 | |||
1011 | ndev = dev_get_drvdata(&op->dev); | ||
1012 | priv = netdev_priv(ndev); | ||
1013 | |||
1014 | unregister_netdev(ndev); | ||
1015 | |||
1016 | irq_dispose_mapping(ndev->irq); | ||
1017 | |||
1018 | bcom_fec_rx_release(priv->rx_dmatsk); | ||
1019 | bcom_fec_tx_release(priv->tx_dmatsk); | ||
1020 | |||
1021 | iounmap(priv->fec); | ||
1022 | |||
1023 | release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec)); | ||
1024 | |||
1025 | free_netdev(ndev); | ||
1026 | |||
1027 | dev_set_drvdata(&op->dev, NULL); | ||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | #ifdef CONFIG_PM | ||
1032 | static int mpc52xx_fec_of_suspend(struct of_device *op, pm_message_t state) | ||
1033 | { | ||
1034 | struct net_device *dev = dev_get_drvdata(&op->dev); | ||
1035 | |||
1036 | if (netif_running(dev)) | ||
1037 | mpc52xx_fec_close(dev); | ||
1038 | |||
1039 | return 0; | ||
1040 | } | ||
1041 | |||
1042 | static int mpc52xx_fec_of_resume(struct of_device *op) | ||
1043 | { | ||
1044 | struct net_device *dev = dev_get_drvdata(&op->dev); | ||
1045 | |||
1046 | mpc52xx_fec_hw_init(dev); | ||
1047 | mpc52xx_fec_reset_stats(dev); | ||
1048 | |||
1049 | if (netif_running(dev)) | ||
1050 | mpc52xx_fec_open(dev); | ||
1051 | |||
1052 | return 0; | ||
1053 | } | ||
1054 | #endif | ||
1055 | |||
1056 | static struct of_device_id mpc52xx_fec_match[] = { | ||
1057 | { | ||
1058 | .type = "network", | ||
1059 | .compatible = "mpc5200-fec", | ||
1060 | }, | ||
1061 | { } | ||
1062 | }; | ||
1063 | |||
1064 | MODULE_DEVICE_TABLE(of, mpc52xx_fec_match); | ||
1065 | |||
1066 | static struct of_platform_driver mpc52xx_fec_driver = { | ||
1067 | .owner = THIS_MODULE, | ||
1068 | .name = DRIVER_NAME, | ||
1069 | .match_table = mpc52xx_fec_match, | ||
1070 | .probe = mpc52xx_fec_probe, | ||
1071 | .remove = mpc52xx_fec_remove, | ||
1072 | #ifdef CONFIG_PM | ||
1073 | .suspend = mpc52xx_fec_of_suspend, | ||
1074 | .resume = mpc52xx_fec_of_resume, | ||
1075 | #endif | ||
1076 | }; | ||
1077 | |||
1078 | |||
1079 | /* ======================================================================== */ | ||
1080 | /* Module */ | ||
1081 | /* ======================================================================== */ | ||
1082 | |||
1083 | static int __init | ||
1084 | mpc52xx_fec_init(void) | ||
1085 | { | ||
1086 | #ifdef CONFIG_FEC_MPC52xx_MDIO | ||
1087 | int ret; | ||
1088 | ret = of_register_platform_driver(&mpc52xx_fec_mdio_driver); | ||
1089 | if (ret) { | ||
1090 | printk(KERN_ERR DRIVER_NAME ": failed to register mdio driver\n"); | ||
1091 | return ret; | ||
1092 | } | ||
1093 | #endif | ||
1094 | return of_register_platform_driver(&mpc52xx_fec_driver); | ||
1095 | } | ||
1096 | |||
1097 | static void __exit | ||
1098 | mpc52xx_fec_exit(void) | ||
1099 | { | ||
1100 | of_unregister_platform_driver(&mpc52xx_fec_driver); | ||
1101 | #ifdef CONFIG_FEC_MPC52xx_MDIO | ||
1102 | of_unregister_platform_driver(&mpc52xx_fec_mdio_driver); | ||
1103 | #endif | ||
1104 | } | ||
1105 | |||
1106 | |||
1107 | module_init(mpc52xx_fec_init); | ||
1108 | module_exit(mpc52xx_fec_exit); | ||
1109 | |||
1110 | MODULE_LICENSE("GPL"); | ||
1111 | MODULE_AUTHOR("Dale Farnsworth"); | ||
1112 | MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC"); | ||
diff --git a/drivers/net/fec_mpc52xx.h b/drivers/net/fec_mpc52xx.h new file mode 100644 index 000000000000..8b1f75397b9a --- /dev/null +++ b/drivers/net/fec_mpc52xx.h | |||
@@ -0,0 +1,313 @@ | |||
1 | /* | ||
2 | * drivers/drivers/net/fec_mpc52xx/fec.h | ||
3 | * | ||
4 | * Driver for the MPC5200 Fast Ethernet Controller | ||
5 | * | ||
6 | * Author: Dale Farnsworth <dfarnsworth@mvista.com> | ||
7 | * | ||
8 | * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under | ||
9 | * the terms of the GNU General Public License version 2. This program | ||
10 | * is licensed "as is" without any warranty of any kind, whether express | ||
11 | * or implied. | ||
12 | */ | ||
13 | |||
14 | #ifndef __DRIVERS_NET_MPC52XX_FEC_H__ | ||
15 | #define __DRIVERS_NET_MPC52XX_FEC_H__ | ||
16 | |||
17 | #include <linux/phy.h> | ||
18 | |||
19 | /* Tunable constant */ | ||
20 | /* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */ | ||
21 | #define FEC_RX_BUFFER_SIZE 1522 /* max receive packet size */ | ||
22 | #define FEC_RX_NUM_BD 256 | ||
23 | #define FEC_TX_NUM_BD 64 | ||
24 | |||
25 | #define FEC_RESET_DELAY 50 /* uS */ | ||
26 | |||
27 | #define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000) | ||
28 | |||
29 | struct mpc52xx_fec_priv { | ||
30 | int duplex; | ||
31 | int r_irq; | ||
32 | int t_irq; | ||
33 | struct mpc52xx_fec __iomem *fec; | ||
34 | struct bcom_task *rx_dmatsk; | ||
35 | struct bcom_task *tx_dmatsk; | ||
36 | spinlock_t lock; | ||
37 | int msg_enable; | ||
38 | |||
39 | int has_phy; | ||
40 | unsigned int phy_speed; | ||
41 | unsigned int phy_addr; | ||
42 | struct phy_device *phydev; | ||
43 | enum phy_state link; | ||
44 | int speed; | ||
45 | }; | ||
46 | |||
47 | |||
48 | /* ======================================================================== */ | ||
49 | /* Hardware register sets & bits */ | ||
50 | /* ======================================================================== */ | ||
51 | |||
52 | struct mpc52xx_fec { | ||
53 | u32 fec_id; /* FEC + 0x000 */ | ||
54 | u32 ievent; /* FEC + 0x004 */ | ||
55 | u32 imask; /* FEC + 0x008 */ | ||
56 | |||
57 | u32 reserved0[1]; /* FEC + 0x00C */ | ||
58 | u32 r_des_active; /* FEC + 0x010 */ | ||
59 | u32 x_des_active; /* FEC + 0x014 */ | ||
60 | u32 r_des_active_cl; /* FEC + 0x018 */ | ||
61 | u32 x_des_active_cl; /* FEC + 0x01C */ | ||
62 | u32 ivent_set; /* FEC + 0x020 */ | ||
63 | u32 ecntrl; /* FEC + 0x024 */ | ||
64 | |||
65 | u32 reserved1[6]; /* FEC + 0x028-03C */ | ||
66 | u32 mii_data; /* FEC + 0x040 */ | ||
67 | u32 mii_speed; /* FEC + 0x044 */ | ||
68 | u32 mii_status; /* FEC + 0x048 */ | ||
69 | |||
70 | u32 reserved2[5]; /* FEC + 0x04C-05C */ | ||
71 | u32 mib_data; /* FEC + 0x060 */ | ||
72 | u32 mib_control; /* FEC + 0x064 */ | ||
73 | |||
74 | u32 reserved3[6]; /* FEC + 0x068-7C */ | ||
75 | u32 r_activate; /* FEC + 0x080 */ | ||
76 | u32 r_cntrl; /* FEC + 0x084 */ | ||
77 | u32 r_hash; /* FEC + 0x088 */ | ||
78 | u32 r_data; /* FEC + 0x08C */ | ||
79 | u32 ar_done; /* FEC + 0x090 */ | ||
80 | u32 r_test; /* FEC + 0x094 */ | ||
81 | u32 r_mib; /* FEC + 0x098 */ | ||
82 | u32 r_da_low; /* FEC + 0x09C */ | ||
83 | u32 r_da_high; /* FEC + 0x0A0 */ | ||
84 | |||
85 | u32 reserved4[7]; /* FEC + 0x0A4-0BC */ | ||
86 | u32 x_activate; /* FEC + 0x0C0 */ | ||
87 | u32 x_cntrl; /* FEC + 0x0C4 */ | ||
88 | u32 backoff; /* FEC + 0x0C8 */ | ||
89 | u32 x_data; /* FEC + 0x0CC */ | ||
90 | u32 x_status; /* FEC + 0x0D0 */ | ||
91 | u32 x_mib; /* FEC + 0x0D4 */ | ||
92 | u32 x_test; /* FEC + 0x0D8 */ | ||
93 | u32 fdxfc_da1; /* FEC + 0x0DC */ | ||
94 | u32 fdxfc_da2; /* FEC + 0x0E0 */ | ||
95 | u32 paddr1; /* FEC + 0x0E4 */ | ||
96 | u32 paddr2; /* FEC + 0x0E8 */ | ||
97 | u32 op_pause; /* FEC + 0x0EC */ | ||
98 | |||
99 | u32 reserved5[4]; /* FEC + 0x0F0-0FC */ | ||
100 | u32 instr_reg; /* FEC + 0x100 */ | ||
101 | u32 context_reg; /* FEC + 0x104 */ | ||
102 | u32 test_cntrl; /* FEC + 0x108 */ | ||
103 | u32 acc_reg; /* FEC + 0x10C */ | ||
104 | u32 ones; /* FEC + 0x110 */ | ||
105 | u32 zeros; /* FEC + 0x114 */ | ||
106 | u32 iaddr1; /* FEC + 0x118 */ | ||
107 | u32 iaddr2; /* FEC + 0x11C */ | ||
108 | u32 gaddr1; /* FEC + 0x120 */ | ||
109 | u32 gaddr2; /* FEC + 0x124 */ | ||
110 | u32 random; /* FEC + 0x128 */ | ||
111 | u32 rand1; /* FEC + 0x12C */ | ||
112 | u32 tmp; /* FEC + 0x130 */ | ||
113 | |||
114 | u32 reserved6[3]; /* FEC + 0x134-13C */ | ||
115 | u32 fifo_id; /* FEC + 0x140 */ | ||
116 | u32 x_wmrk; /* FEC + 0x144 */ | ||
117 | u32 fcntrl; /* FEC + 0x148 */ | ||
118 | u32 r_bound; /* FEC + 0x14C */ | ||
119 | u32 r_fstart; /* FEC + 0x150 */ | ||
120 | u32 r_count; /* FEC + 0x154 */ | ||
121 | u32 r_lag; /* FEC + 0x158 */ | ||
122 | u32 r_read; /* FEC + 0x15C */ | ||
123 | u32 r_write; /* FEC + 0x160 */ | ||
124 | u32 x_count; /* FEC + 0x164 */ | ||
125 | u32 x_lag; /* FEC + 0x168 */ | ||
126 | u32 x_retry; /* FEC + 0x16C */ | ||
127 | u32 x_write; /* FEC + 0x170 */ | ||
128 | u32 x_read; /* FEC + 0x174 */ | ||
129 | |||
130 | u32 reserved7[2]; /* FEC + 0x178-17C */ | ||
131 | u32 fm_cntrl; /* FEC + 0x180 */ | ||
132 | u32 rfifo_data; /* FEC + 0x184 */ | ||
133 | u32 rfifo_status; /* FEC + 0x188 */ | ||
134 | u32 rfifo_cntrl; /* FEC + 0x18C */ | ||
135 | u32 rfifo_lrf_ptr; /* FEC + 0x190 */ | ||
136 | u32 rfifo_lwf_ptr; /* FEC + 0x194 */ | ||
137 | u32 rfifo_alarm; /* FEC + 0x198 */ | ||
138 | u32 rfifo_rdptr; /* FEC + 0x19C */ | ||
139 | u32 rfifo_wrptr; /* FEC + 0x1A0 */ | ||
140 | u32 tfifo_data; /* FEC + 0x1A4 */ | ||
141 | u32 tfifo_status; /* FEC + 0x1A8 */ | ||
142 | u32 tfifo_cntrl; /* FEC + 0x1AC */ | ||
143 | u32 tfifo_lrf_ptr; /* FEC + 0x1B0 */ | ||
144 | u32 tfifo_lwf_ptr; /* FEC + 0x1B4 */ | ||
145 | u32 tfifo_alarm; /* FEC + 0x1B8 */ | ||
146 | u32 tfifo_rdptr; /* FEC + 0x1BC */ | ||
147 | u32 tfifo_wrptr; /* FEC + 0x1C0 */ | ||
148 | |||
149 | u32 reset_cntrl; /* FEC + 0x1C4 */ | ||
150 | u32 xmit_fsm; /* FEC + 0x1C8 */ | ||
151 | |||
152 | u32 reserved8[3]; /* FEC + 0x1CC-1D4 */ | ||
153 | u32 rdes_data0; /* FEC + 0x1D8 */ | ||
154 | u32 rdes_data1; /* FEC + 0x1DC */ | ||
155 | u32 r_length; /* FEC + 0x1E0 */ | ||
156 | u32 x_length; /* FEC + 0x1E4 */ | ||
157 | u32 x_addr; /* FEC + 0x1E8 */ | ||
158 | u32 cdes_data; /* FEC + 0x1EC */ | ||
159 | u32 status; /* FEC + 0x1F0 */ | ||
160 | u32 dma_control; /* FEC + 0x1F4 */ | ||
161 | u32 des_cmnd; /* FEC + 0x1F8 */ | ||
162 | u32 data; /* FEC + 0x1FC */ | ||
163 | |||
164 | u32 rmon_t_drop; /* FEC + 0x200 */ | ||
165 | u32 rmon_t_packets; /* FEC + 0x204 */ | ||
166 | u32 rmon_t_bc_pkt; /* FEC + 0x208 */ | ||
167 | u32 rmon_t_mc_pkt; /* FEC + 0x20C */ | ||
168 | u32 rmon_t_crc_align; /* FEC + 0x210 */ | ||
169 | u32 rmon_t_undersize; /* FEC + 0x214 */ | ||
170 | u32 rmon_t_oversize; /* FEC + 0x218 */ | ||
171 | u32 rmon_t_frag; /* FEC + 0x21C */ | ||
172 | u32 rmon_t_jab; /* FEC + 0x220 */ | ||
173 | u32 rmon_t_col; /* FEC + 0x224 */ | ||
174 | u32 rmon_t_p64; /* FEC + 0x228 */ | ||
175 | u32 rmon_t_p65to127; /* FEC + 0x22C */ | ||
176 | u32 rmon_t_p128to255; /* FEC + 0x230 */ | ||
177 | u32 rmon_t_p256to511; /* FEC + 0x234 */ | ||
178 | u32 rmon_t_p512to1023; /* FEC + 0x238 */ | ||
179 | u32 rmon_t_p1024to2047; /* FEC + 0x23C */ | ||
180 | u32 rmon_t_p_gte2048; /* FEC + 0x240 */ | ||
181 | u32 rmon_t_octets; /* FEC + 0x244 */ | ||
182 | u32 ieee_t_drop; /* FEC + 0x248 */ | ||
183 | u32 ieee_t_frame_ok; /* FEC + 0x24C */ | ||
184 | u32 ieee_t_1col; /* FEC + 0x250 */ | ||
185 | u32 ieee_t_mcol; /* FEC + 0x254 */ | ||
186 | u32 ieee_t_def; /* FEC + 0x258 */ | ||
187 | u32 ieee_t_lcol; /* FEC + 0x25C */ | ||
188 | u32 ieee_t_excol; /* FEC + 0x260 */ | ||
189 | u32 ieee_t_macerr; /* FEC + 0x264 */ | ||
190 | u32 ieee_t_cserr; /* FEC + 0x268 */ | ||
191 | u32 ieee_t_sqe; /* FEC + 0x26C */ | ||
192 | u32 t_fdxfc; /* FEC + 0x270 */ | ||
193 | u32 ieee_t_octets_ok; /* FEC + 0x274 */ | ||
194 | |||
195 | u32 reserved9[2]; /* FEC + 0x278-27C */ | ||
196 | u32 rmon_r_drop; /* FEC + 0x280 */ | ||
197 | u32 rmon_r_packets; /* FEC + 0x284 */ | ||
198 | u32 rmon_r_bc_pkt; /* FEC + 0x288 */ | ||
199 | u32 rmon_r_mc_pkt; /* FEC + 0x28C */ | ||
200 | u32 rmon_r_crc_align; /* FEC + 0x290 */ | ||
201 | u32 rmon_r_undersize; /* FEC + 0x294 */ | ||
202 | u32 rmon_r_oversize; /* FEC + 0x298 */ | ||
203 | u32 rmon_r_frag; /* FEC + 0x29C */ | ||
204 | u32 rmon_r_jab; /* FEC + 0x2A0 */ | ||
205 | |||
206 | u32 rmon_r_resvd_0; /* FEC + 0x2A4 */ | ||
207 | |||
208 | u32 rmon_r_p64; /* FEC + 0x2A8 */ | ||
209 | u32 rmon_r_p65to127; /* FEC + 0x2AC */ | ||
210 | u32 rmon_r_p128to255; /* FEC + 0x2B0 */ | ||
211 | u32 rmon_r_p256to511; /* FEC + 0x2B4 */ | ||
212 | u32 rmon_r_p512to1023; /* FEC + 0x2B8 */ | ||
213 | u32 rmon_r_p1024to2047; /* FEC + 0x2BC */ | ||
214 | u32 rmon_r_p_gte2048; /* FEC + 0x2C0 */ | ||
215 | u32 rmon_r_octets; /* FEC + 0x2C4 */ | ||
216 | u32 ieee_r_drop; /* FEC + 0x2C8 */ | ||
217 | u32 ieee_r_frame_ok; /* FEC + 0x2CC */ | ||
218 | u32 ieee_r_crc; /* FEC + 0x2D0 */ | ||
219 | u32 ieee_r_align; /* FEC + 0x2D4 */ | ||
220 | u32 r_macerr; /* FEC + 0x2D8 */ | ||
221 | u32 r_fdxfc; /* FEC + 0x2DC */ | ||
222 | u32 ieee_r_octets_ok; /* FEC + 0x2E0 */ | ||
223 | |||
224 | u32 reserved10[7]; /* FEC + 0x2E4-2FC */ | ||
225 | |||
226 | u32 reserved11[64]; /* FEC + 0x300-3FF */ | ||
227 | }; | ||
228 | |||
229 | #define FEC_MIB_DISABLE 0x80000000 | ||
230 | |||
231 | #define FEC_IEVENT_HBERR 0x80000000 | ||
232 | #define FEC_IEVENT_BABR 0x40000000 | ||
233 | #define FEC_IEVENT_BABT 0x20000000 | ||
234 | #define FEC_IEVENT_GRA 0x10000000 | ||
235 | #define FEC_IEVENT_TFINT 0x08000000 | ||
236 | #define FEC_IEVENT_MII 0x00800000 | ||
237 | #define FEC_IEVENT_LATE_COL 0x00200000 | ||
238 | #define FEC_IEVENT_COL_RETRY_LIM 0x00100000 | ||
239 | #define FEC_IEVENT_XFIFO_UN 0x00080000 | ||
240 | #define FEC_IEVENT_XFIFO_ERROR 0x00040000 | ||
241 | #define FEC_IEVENT_RFIFO_ERROR 0x00020000 | ||
242 | |||
243 | #define FEC_IMASK_HBERR 0x80000000 | ||
244 | #define FEC_IMASK_BABR 0x40000000 | ||
245 | #define FEC_IMASK_BABT 0x20000000 | ||
246 | #define FEC_IMASK_GRA 0x10000000 | ||
247 | #define FEC_IMASK_MII 0x00800000 | ||
248 | #define FEC_IMASK_LATE_COL 0x00200000 | ||
249 | #define FEC_IMASK_COL_RETRY_LIM 0x00100000 | ||
250 | #define FEC_IMASK_XFIFO_UN 0x00080000 | ||
251 | #define FEC_IMASK_XFIFO_ERROR 0x00040000 | ||
252 | #define FEC_IMASK_RFIFO_ERROR 0x00020000 | ||
253 | |||
254 | /* all but MII, which is enabled separately */ | ||
255 | #define FEC_IMASK_ENABLE (FEC_IMASK_HBERR | FEC_IMASK_BABR | \ | ||
256 | FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_LATE_COL | \ | ||
257 | FEC_IMASK_COL_RETRY_LIM | FEC_IMASK_XFIFO_UN | \ | ||
258 | FEC_IMASK_XFIFO_ERROR | FEC_IMASK_RFIFO_ERROR) | ||
259 | |||
260 | #define FEC_RCNTRL_MAX_FL_SHIFT 16 | ||
261 | #define FEC_RCNTRL_LOOP 0x01 | ||
262 | #define FEC_RCNTRL_DRT 0x02 | ||
263 | #define FEC_RCNTRL_MII_MODE 0x04 | ||
264 | #define FEC_RCNTRL_PROM 0x08 | ||
265 | #define FEC_RCNTRL_BC_REJ 0x10 | ||
266 | #define FEC_RCNTRL_FCE 0x20 | ||
267 | |||
268 | #define FEC_TCNTRL_GTS 0x00000001 | ||
269 | #define FEC_TCNTRL_HBC 0x00000002 | ||
270 | #define FEC_TCNTRL_FDEN 0x00000004 | ||
271 | #define FEC_TCNTRL_TFC_PAUSE 0x00000008 | ||
272 | #define FEC_TCNTRL_RFC_PAUSE 0x00000010 | ||
273 | |||
274 | #define FEC_ECNTRL_RESET 0x00000001 | ||
275 | #define FEC_ECNTRL_ETHER_EN 0x00000002 | ||
276 | |||
277 | #define FEC_MII_DATA_ST 0x40000000 /* Start frame */ | ||
278 | #define FEC_MII_DATA_OP_RD 0x20000000 /* Perform read */ | ||
279 | #define FEC_MII_DATA_OP_WR 0x10000000 /* Perform write */ | ||
280 | #define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address mask */ | ||
281 | #define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register mask */ | ||
282 | #define FEC_MII_DATA_TA 0x00020000 /* Turnaround */ | ||
283 | #define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data mask */ | ||
284 | |||
285 | #define FEC_MII_READ_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA) | ||
286 | #define FEC_MII_WRITE_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA) | ||
287 | |||
288 | #define FEC_MII_DATA_RA_SHIFT 0x12 /* MII reg addr bits */ | ||
289 | #define FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY addr bits */ | ||
290 | |||
291 | #define FEC_PADDR2_TYPE 0x8808 | ||
292 | |||
293 | #define FEC_OP_PAUSE_OPCODE 0x00010000 | ||
294 | |||
295 | #define FEC_FIFO_WMRK_256B 0x3 | ||
296 | |||
297 | #define FEC_FIFO_STATUS_ERR 0x00400000 | ||
298 | #define FEC_FIFO_STATUS_UF 0x00200000 | ||
299 | #define FEC_FIFO_STATUS_OF 0x00100000 | ||
300 | |||
301 | #define FEC_FIFO_CNTRL_FRAME 0x08000000 | ||
302 | #define FEC_FIFO_CNTRL_LTG_7 0x07000000 | ||
303 | |||
304 | #define FEC_RESET_CNTRL_RESET_FIFO 0x02000000 | ||
305 | #define FEC_RESET_CNTRL_ENABLE_IS_RESET 0x01000000 | ||
306 | |||
307 | #define FEC_XMIT_FSM_APPEND_CRC 0x02000000 | ||
308 | #define FEC_XMIT_FSM_ENABLE_CRC 0x01000000 | ||
309 | |||
310 | |||
311 | extern struct of_platform_driver mpc52xx_fec_mdio_driver; | ||
312 | |||
313 | #endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */ | ||
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c new file mode 100644 index 000000000000..ba6e8b218e0a --- /dev/null +++ b/drivers/net/fec_mpc52xx_phy.c | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * Driver for the MPC5200 Fast Ethernet Controller - MDIO bus driver | ||
3 | * | ||
4 | * Copyright (C) 2007 Domen Puncer, Telargo, Inc. | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public License | ||
7 | * version 2. This program is licensed "as is" without any warranty of any | ||
8 | * kind, whether express or implied. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/netdevice.h> | ||
14 | #include <linux/phy.h> | ||
15 | #include <linux/of_platform.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/mpc52xx.h> | ||
18 | #include "fec_mpc52xx.h" | ||
19 | |||
20 | struct mpc52xx_fec_mdio_priv { | ||
21 | struct mpc52xx_fec __iomem *regs; | ||
22 | }; | ||
23 | |||
24 | static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg) | ||
25 | { | ||
26 | struct mpc52xx_fec_mdio_priv *priv = bus->priv; | ||
27 | struct mpc52xx_fec __iomem *fec; | ||
28 | int tries = 100; | ||
29 | u32 request = FEC_MII_READ_FRAME; | ||
30 | |||
31 | fec = priv->regs; | ||
32 | out_be32(&fec->ievent, FEC_IEVENT_MII); | ||
33 | |||
34 | request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK; | ||
35 | request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK; | ||
36 | |||
37 | out_be32(&priv->regs->mii_data, request); | ||
38 | |||
39 | /* wait for it to finish, this takes about 23 us on lite5200b */ | ||
40 | while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries) | ||
41 | udelay(5); | ||
42 | |||
43 | if (tries == 0) | ||
44 | return -ETIMEDOUT; | ||
45 | |||
46 | return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK; | ||
47 | } | ||
48 | |||
49 | static int mpc52xx_fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data) | ||
50 | { | ||
51 | struct mpc52xx_fec_mdio_priv *priv = bus->priv; | ||
52 | struct mpc52xx_fec __iomem *fec; | ||
53 | u32 value = data; | ||
54 | int tries = 100; | ||
55 | |||
56 | fec = priv->regs; | ||
57 | out_be32(&fec->ievent, FEC_IEVENT_MII); | ||
58 | |||
59 | value |= FEC_MII_WRITE_FRAME; | ||
60 | value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK; | ||
61 | value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK; | ||
62 | |||
63 | out_be32(&priv->regs->mii_data, value); | ||
64 | |||
65 | /* wait for request to finish */ | ||
66 | while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries) | ||
67 | udelay(5); | ||
68 | |||
69 | if (tries == 0) | ||
70 | return -ETIMEDOUT; | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_id *match) | ||
76 | { | ||
77 | struct device *dev = &of->dev; | ||
78 | struct device_node *np = of->node; | ||
79 | struct device_node *child = NULL; | ||
80 | struct mii_bus *bus; | ||
81 | struct mpc52xx_fec_mdio_priv *priv; | ||
82 | struct resource res = {}; | ||
83 | int err; | ||
84 | int i; | ||
85 | |||
86 | bus = kzalloc(sizeof(*bus), GFP_KERNEL); | ||
87 | if (bus == NULL) | ||
88 | return -ENOMEM; | ||
89 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
90 | if (priv == NULL) { | ||
91 | err = -ENOMEM; | ||
92 | goto out_free; | ||
93 | } | ||
94 | |||
95 | bus->name = "mpc52xx MII bus"; | ||
96 | bus->read = mpc52xx_fec_mdio_read; | ||
97 | bus->write = mpc52xx_fec_mdio_write; | ||
98 | |||
99 | /* setup irqs */ | ||
100 | bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL); | ||
101 | if (bus->irq == NULL) { | ||
102 | err = -ENOMEM; | ||
103 | goto out_free; | ||
104 | } | ||
105 | for (i=0; i<PHY_MAX_ADDR; i++) | ||
106 | bus->irq[i] = PHY_POLL; | ||
107 | |||
108 | while ((child = of_get_next_child(np, child)) != NULL) { | ||
109 | int irq = irq_of_parse_and_map(child, 0); | ||
110 | if (irq != NO_IRQ) { | ||
111 | const u32 *id = of_get_property(child, "reg", NULL); | ||
112 | bus->irq[*id] = irq; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /* setup registers */ | ||
117 | err = of_address_to_resource(np, 0, &res); | ||
118 | if (err) | ||
119 | goto out_free; | ||
120 | priv->regs = ioremap(res.start, res.end - res.start + 1); | ||
121 | if (priv->regs == NULL) { | ||
122 | err = -ENOMEM; | ||
123 | goto out_free; | ||
124 | } | ||
125 | |||
126 | bus->id = res.start; | ||
127 | bus->priv = priv; | ||
128 | |||
129 | bus->dev = dev; | ||
130 | dev_set_drvdata(dev, bus); | ||
131 | |||
132 | /* set MII speed */ | ||
133 | out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1); | ||
134 | |||
135 | /* enable MII interrupt */ | ||
136 | out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII); | ||
137 | |||
138 | err = mdiobus_register(bus); | ||
139 | if (err) | ||
140 | goto out_unmap; | ||
141 | |||
142 | return 0; | ||
143 | |||
144 | out_unmap: | ||
145 | iounmap(priv->regs); | ||
146 | out_free: | ||
147 | for (i=0; i<PHY_MAX_ADDR; i++) | ||
148 | if (bus->irq[i] != PHY_POLL) | ||
149 | irq_dispose_mapping(bus->irq[i]); | ||
150 | kfree(bus->irq); | ||
151 | kfree(priv); | ||
152 | kfree(bus); | ||
153 | |||
154 | return err; | ||
155 | } | ||
156 | |||
157 | static int mpc52xx_fec_mdio_remove(struct of_device *of) | ||
158 | { | ||
159 | struct device *dev = &of->dev; | ||
160 | struct mii_bus *bus = dev_get_drvdata(dev); | ||
161 | struct mpc52xx_fec_mdio_priv *priv = bus->priv; | ||
162 | int i; | ||
163 | |||
164 | mdiobus_unregister(bus); | ||
165 | dev_set_drvdata(dev, NULL); | ||
166 | |||
167 | iounmap(priv->regs); | ||
168 | for (i=0; i<PHY_MAX_ADDR; i++) | ||
169 | if (bus->irq[i]) | ||
170 | irq_dispose_mapping(bus->irq[i]); | ||
171 | kfree(priv); | ||
172 | kfree(bus->irq); | ||
173 | kfree(bus); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | |||
179 | static struct of_device_id mpc52xx_fec_mdio_match[] = { | ||
180 | { | ||
181 | .type = "mdio", | ||
182 | .compatible = "mpc5200b-fec-phy", | ||
183 | }, | ||
184 | {}, | ||
185 | }; | ||
186 | |||
187 | struct of_platform_driver mpc52xx_fec_mdio_driver = { | ||
188 | .name = "mpc5200b-fec-phy", | ||
189 | .probe = mpc52xx_fec_mdio_probe, | ||
190 | .remove = mpc52xx_fec_mdio_remove, | ||
191 | .match_table = mpc52xx_fec_mdio_match, | ||
192 | }; | ||
193 | |||
194 | /* let fec driver call it, since this has to be registered before it */ | ||
195 | EXPORT_SYMBOL_GPL(mpc52xx_fec_mdio_driver); | ||
196 | |||
197 | |||
198 | MODULE_LICENSE("Dual BSD/GPL"); | ||