1/*
2 * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
3 *
4 * Copyright (c) 2003 Intracom S.A.
5 *  by Pantelis Antoniou <panto@intracom.gr>
6 *
7 * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
8 * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
9 *
10 * Released under the GPL
11 */
12
13#include <linux/module.h>
14#include <linux/types.h>
15#include <linux/kernel.h>
16#include <linux/string.h>
17#include <linux/ptrace.h>
18#include <linux/errno.h>
19#include <linux/ioport.h>
20#include <linux/slab.h>
21#include <linux/interrupt.h>
22#include <linux/init.h>
23#include <linux/delay.h>
24#include <linux/netdevice.h>
25#include <linux/etherdevice.h>
26#include <linux/skbuff.h>
27#include <linux/spinlock.h>
28#include <linux/mii.h>
29#include <linux/ethtool.h>
30#include <linux/bitops.h>
31
32#include <asm/8xx_immap.h>
33#include <asm/pgtable.h>
34#include <asm/mpc8xx.h>
35#include <asm/irq.h>
36#include <asm/uaccess.h>
37#include <asm/commproc.h>
38
39/*************************************************/
40
41#include "fec_8xx.h"
42
43/*************************************************/
44
45/* Make MII read/write commands for the FEC.
46*/
47#define mk_mii_read(REG)	(0x60020000 | ((REG & 0x1f) << 18))
48#define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
49#define mk_mii_end		0
50
51/*************************************************/
52
53static DEFINE_SPINLOCK(fec_mii_lock);
54
55#define FEC_MII_LOOPS	10000
56
57int fec_mii_read(struct net_device *dev, int phy_id, int location)
58{
59	struct fec_enet_private *fep = netdev_priv(dev);
60	fec_t *fecp;
61	int i, ret = -1;
62	unsigned long flags;
63
64	fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec;
65
66	spin_lock_irqsave(&fec_mii_lock, flags);
67
68	if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) {
69		FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */
70		FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
71		FW(fecp, ievent, FEC_ENET_MII);
72	}
73
74	/* Add PHY address to register command.  */
75	FW(fecp, mii_speed, fep->fec_phy_speed);
76	FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location));
77
78	for (i = 0; i < FEC_MII_LOOPS; i++)
79		if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
80			break;
81
82	if (i < FEC_MII_LOOPS) {
83		FW(fecp, ievent, FEC_ENET_MII);
84		ret = FR(fecp, mii_data) & 0xffff;
85	}
86
87	spin_unlock_irqrestore(&fec_mii_lock, flags);
88
89	return ret;
90}
91
92void fec_mii_write(struct net_device *dev, int phy_id, int location, int value)
93{
94	struct fec_enet_private *fep = netdev_priv(dev);
95	fec_t *fecp;
96	unsigned long flags;
97	int i;
98
99	fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec;
100
101	spin_lock_irqsave(&fec_mii_lock, flags);
102
103	if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) {
104		FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */
105		FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
106		FW(fecp, ievent, FEC_ENET_MII);
107	}
108
109	/* Add PHY address to register command.  */
110	FW(fecp, mii_speed, fep->fec_phy_speed);	/* always adapt mii speed */
111	FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value));
112
113	for (i = 0; i < FEC_MII_LOOPS; i++)
114		if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
115			break;
116
117	if (i < FEC_MII_LOOPS)
118		FW(fecp, ievent, FEC_ENET_MII);
119
120	spin_unlock_irqrestore(&fec_mii_lock, flags);
121}
122
123/*************************************************/
124
125#ifdef CONFIG_FEC_8XX_GENERIC_PHY
126
127/*
128 * Generic PHY support.
129 * Should work for all PHYs, but link change is detected by polling
130 */
131
132static void generic_timer_callback(unsigned long data)
133{
134	struct net_device *dev = (struct net_device *)data;
135	struct fec_enet_private *fep = netdev_priv(dev);
136
137	fep->phy_timer_list.expires = jiffies + HZ / 2;
138
139	add_timer(&fep->phy_timer_list);
140
141	fec_mii_link_status_change_check(dev, 0);
142}
143
144static void generic_startup(struct net_device *dev)
145{
146	struct fec_enet_private *fep = netdev_priv(dev);
147
148	fep->phy_timer_list.expires = jiffies + HZ / 2;	/* every 500ms */
149	fep->phy_timer_list.data = (unsigned long)dev;
150	fep->phy_timer_list.function = generic_timer_callback;
151	add_timer(&fep->phy_timer_list);
152}
153
154static void generic_shutdown(struct net_device *dev)
155{
156	struct fec_enet_private *fep = netdev_priv(dev);
157
158	del_timer_sync(&fep->phy_timer_list);
159}
160
161#endif
162
163#ifdef CONFIG_FEC_8XX_DM9161_PHY
164
165/* ------------------------------------------------------------------------- */
166/* The Davicom DM9161 is used on the NETTA board			     */
167
168/* register definitions */
169
170#define MII_DM9161_ACR		16	/* Aux. Config Register         */
171#define MII_DM9161_ACSR		17	/* Aux. Config/Status Register  */
172#define MII_DM9161_10TCSR	18	/* 10BaseT Config/Status Reg.   */
173#define MII_DM9161_INTR		21	/* Interrupt Register           */
174#define MII_DM9161_RECR		22	/* Receive Error Counter Reg.   */
175#define MII_DM9161_DISCR	23	/* Disconnect Counter Register  */
176
177static void dm9161_startup(struct net_device *dev)
178{
179	struct fec_enet_private *fep = netdev_priv(dev);
180
181	fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000);
182}
183
184static void dm9161_ack_int(struct net_device *dev)
185{
186	struct fec_enet_private *fep = netdev_priv(dev);
187
188	fec_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR);
189}
190
191static void dm9161_shutdown(struct net_device *dev)
192{
193	struct fec_enet_private *fep = netdev_priv(dev);
194
195	fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00);
196}
197
198#endif
199
200#ifdef CONFIG_FEC_8XX_LXT971_PHY
201
202/* Support for LXT971/972 PHY */
203
204#define MII_LXT971_PCR		16 /* Port Control Register */
205#define MII_LXT971_SR2		17 /* Status Register 2 */
206#define MII_LXT971_IER		18 /* Interrupt Enable Register */
207#define MII_LXT971_ISR		19 /* Interrupt Status Register */
208#define MII_LXT971_LCR		20 /* LED Control Register */
209#define MII_LXT971_TCR		30 /* Transmit Control Register */
210
211static void lxt971_startup(struct net_device *dev)
212{
213	struct fec_enet_private *fep = netdev_priv(dev);
214
215	fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x00F2);
216}
217
218static void lxt971_ack_int(struct net_device *dev)
219{
220	struct fec_enet_private *fep = netdev_priv(dev);
221
222	fec_mii_read(dev, fep->mii_if.phy_id, MII_LXT971_ISR);
223}
224
225static void lxt971_shutdown(struct net_device *dev)
226{
227	struct fec_enet_private *fep = netdev_priv(dev);
228
229	fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x0000);
230}
231#endif
232
233/**********************************************************************************/
234
235static const struct phy_info phy_info[] = {
236#ifdef CONFIG_FEC_8XX_DM9161_PHY
237	{
238	 .id = 0x00181b88,
239	 .name = "DM9161",
240	 .startup = dm9161_startup,
241	 .ack_int = dm9161_ack_int,
242	 .shutdown = dm9161_shutdown,
243	 },
244#endif
245#ifdef CONFIG_FEC_8XX_LXT971_PHY
246	{
247	 .id = 0x0001378e,
248	 .name = "LXT971/972",
249	 .startup = lxt971_startup,
250	 .ack_int = lxt971_ack_int,
251	 .shutdown = lxt971_shutdown,
252	},
253#endif
254#ifdef CONFIG_FEC_8XX_GENERIC_PHY
255	{
256	 .id = 0,
257	 .name = "GENERIC",
258	 .startup = generic_startup,
259	 .shutdown = generic_shutdown,
260	 },
261#endif
262};
263
264/**********************************************************************************/
265
266int fec_mii_phy_id_detect(struct net_device *dev)
267{
268	struct fec_enet_private *fep = netdev_priv(dev);
269	const struct fec_platform_info *fpi = fep->fpi;
270	int i, r, start, end, phytype, physubtype;
271	const struct phy_info *phy;
272	int phy_hwid, phy_id;
273
274	/* if no MDIO */
275	if (fpi->use_mdio == 0)
276		return -1;
277
278	phy_hwid = -1;
279	fep->phy = NULL;
280
281	/* auto-detect? */
282	if (fpi->phy_addr == -1) {
283		start = 0;
284		end = 32;
285	} else {		/* direct */
286		start = fpi->phy_addr;
287		end = start + 1;
288	}
289
290	for (phy_id = start; phy_id < end; phy_id++) {
291		r = fec_mii_read(dev, phy_id, MII_PHYSID1);
292		if (r == -1 || (phytype = (r & 0xffff)) == 0xffff)
293			continue;
294		r = fec_mii_read(dev, phy_id, MII_PHYSID2);
295		if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)
296			continue;
297		phy_hwid = (phytype << 16) | physubtype;
298		if (phy_hwid != -1)
299			break;
300	}
301
302	if (phy_hwid == -1) {
303		printk(KERN_ERR DRV_MODULE_NAME
304		       ": %s No PHY detected!\n", dev->name);
305		return -1;
306	}
307
308	for (i = 0, phy = phy_info; i < sizeof(phy_info) / sizeof(phy_info[0]);
309	     i++, phy++)
310		if (phy->id == (phy_hwid >> 4) || phy->id == 0)
311			break;
312
313	if (i >= sizeof(phy_info) / sizeof(phy_info[0])) {
314		printk(KERN_ERR DRV_MODULE_NAME
315		       ": %s PHY id 0x%08x is not supported!\n",
316		       dev->name, phy_hwid);
317		return -1;
318	}
319
320	fep->phy = phy;
321
322	printk(KERN_INFO DRV_MODULE_NAME
323	       ": %s Phy @ 0x%x, type %s (0x%08x)\n",
324	       dev->name, phy_id, fep->phy->name, phy_hwid);
325
326	return phy_id;
327}
328
329void fec_mii_startup(struct net_device *dev)
330{
331	struct fec_enet_private *fep = netdev_priv(dev);
332	const struct fec_platform_info *fpi = fep->fpi;
333
334	if (!fpi->use_mdio || fep->phy == NULL)
335		return;
336
337	if (fep->phy->startup == NULL)
338		return;
339
340	(*fep->phy->startup) (dev);
341}
342
343void fec_mii_shutdown(struct net_device *dev)
344{
345	struct fec_enet_private *fep = netdev_priv(dev);
346	const struct fec_platform_info *fpi = fep->fpi;
347
348	if (!fpi->use_mdio || fep->phy == NULL)
349		return;
350
351	if (fep->phy->shutdown == NULL)
352		return;
353
354	(*fep->phy->shutdown) (dev);
355}
356
357void fec_mii_ack_int(struct net_device *dev)
358{
359	struct fec_enet_private *fep = netdev_priv(dev);
360	const struct fec_platform_info *fpi = fep->fpi;
361
362	if (!fpi->use_mdio || fep->phy == NULL)
363		return;
364
365	if (fep->phy->ack_int == NULL)
366		return;
367
368	(*fep->phy->ack_int) (dev);
369}
370
371/* helper function */
372static int mii_negotiated(struct mii_if_info *mii)
373{
374	int advert, lpa, val;
375
376	if (!mii_link_ok(mii))
377		return 0;
378
379	val = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_BMSR);
380	if ((val & BMSR_ANEGCOMPLETE) == 0)
381		return 0;
382
383	advert = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_ADVERTISE);
384	lpa = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_LPA);
385
386	return mii_nway_result(advert & lpa);
387}
388
389void fec_mii_link_status_change_check(struct net_device *dev, int init_media)
390{
391	struct fec_enet_private *fep = netdev_priv(dev);
392	unsigned int media;
393	unsigned long flags;
394
395	if (mii_check_media(&fep->mii_if, netif_msg_link(fep), init_media) == 0)
396		return;
397
398	media = mii_negotiated(&fep->mii_if);
399
400	if (netif_carrier_ok(dev)) {
401		spin_lock_irqsave(&fep->lock, flags);
402		fec_restart(dev, !!(media & ADVERTISE_FULL),
403			    (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) ?
404			    100 : 10);
405		spin_unlock_irqrestore(&fep->lock, flags);
406
407		netif_start_queue(dev);
408	} else {
409		netif_stop_queue(dev);
410
411		spin_lock_irqsave(&fep->lock, flags);
412		fec_stop(dev);
413		spin_unlock_irqrestore(&fep->lock, flags);
414
415	}
416}
417