aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux/sarge-at91/2.6.21-sarge-phy.patch
blob: 5cdc73b4dd40e39ca0b4ab6c7f53f2a8f8a0e712 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
diff -Nurp linux-2.6.21.4/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
--- linux-2.6.21.4/drivers/net/arm/at91_ether.c	2007-06-12 22:29:12.000000000 +0200
+++ b/drivers/net/arm/at91_ether.c	2007-06-12 03:11:16.000000000 +0200
@@ -235,6 +235,11 @@ static irqreturn_t at91ether_phy_interru
 		if (!(phy & (1 << 7)))
 			goto done;
 	}
+	else if (lp->phy_type == MII_STE100P_ID) {	
+		read_phy(lp->phy_address, MII_STE100P_XCSIIS_REG, &phy); /* ack interrupt in STE100P PHY */
+		if (!(phy & 0x007F))
+		    goto done;
+	}
 
 	update_linkspeed(dev, 0);
 
@@ -303,6 +308,11 @@ static void enable_phyirq(struct net_dev
 		dsintr = dsintr | 0x3;			/* set bits 0,1 */
 		write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
 	}
+	else if (lp->phy_type == MII_STE100P_ID) {	/* for STE100P PHY */
+		read_phy(lp->phy_address, MII_STE100P_XIE_REG, &dsintr);
+
+		dsintr |= 0x007F;
+	}
 
 	disable_mdi();
 	spin_unlock_irq(&lp->lock);
@@ -359,6 +369,11 @@ static void disable_phyirq(struct net_de
 		dsintr = dsintr & ~0x3c;			/* clear bits 2..5 */
 		write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
 	}
+	else if (lp->phy_type == MII_STE100P_ID) {	/* for STE100P PHY */
+		read_phy(lp->phy_address, MII_STE100P_XIE_REG, &dsintr);
+		dsintr &= 0xFF80;
+		write_phy(lp->phy_address, MII_STE100P_XIE_REG, dsintr);
+	}
 
 	disable_mdi();
 	spin_unlock_irq(&lp->lock);
@@ -1117,6 +1132,8 @@ static int __init at91ether_setup(unsign
 		printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name);
 	else if (phy_type == MII_LAN83C185_ID)
 		printk(KERN_INFO "%s: SMSC LAN83C185 PHY\n", dev->name);
+	else if (phy_type == MII_STE100P_ID)
+		printk(KERN_INFO "%s: STE100P PHY\n", dev->name);
 
 	return 0;
 }
@@ -1159,6 +1176,7 @@ static int __init at91ether_probe(struct
 			case MII_KS8721_ID:		/* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
 			case MII_T78Q21x3_ID:		/* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
 			case MII_LAN83C185_ID:		/* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
+ 			case MII_STE100P_ID:		/* STE100P: PHY_ID1 = 0x1C04, PHY_ID2 = 0x0000 */
 				detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
 				break;
 		}
diff -Nurp linux-2.6.21.4/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h
--- linux-2.6.21.4/drivers/net/arm/at91_ether.h	2007-06-12 22:29:12.000000000 +0200
+++ b/drivers/net/arm/at91_ether.h	2007-06-12 03:07:54.000000000 +0200
@@ -29,6 +29,15 @@
 #define MII_ISINTS_REG		19
 #define MII_LEDCTRL_REG		20
 
+/* STE100P specific registers */
+#define MII_STE100P_XCSIIS_REG  0x11
+#define MII_STE100P_XIE_REG     0x12
+#define MII_XCR_REG             0x00
+#define MII_XCR_ISOLATE      0x0400
+
+/* STE100P PHY */
+#define MII_STE100P_ID  0x1c040010
+
 /* Realtek RTL8201 PHY */
 #define MII_RTL8201_ID		0x00008200
 
diff -Nurp linux-2.6.21.4/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
--- linux-2.6.21.4/drivers/net/phy/Kconfig	2007-06-07 23:27:31.000000000 +0200
+++ b/drivers/net/phy/Kconfig	2007-06-12 03:12:16.000000000 +0200
@@ -62,6 +62,12 @@ config BROADCOM_PHY
 	---help---
 	  Currently supports the BCM5411, BCM5421 and BCM5461 PHYs.
 
+config STE100P_PHY
+        tristate "Drivers for the STE100P PHY"
+        depends on PHYLIB
+        ---help---
+          Currently supports the ste100p
+	  
 config FIXED_PHY
 	tristate "Drivers for PHY emulation on fixed speed/link"
 	depends on PHYLIB
diff -Nurp linux-2.6.21.4/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
--- linux-2.6.21.4/drivers/net/phy/Makefile	2007-06-07 23:27:31.000000000 +0200
+++ b/drivers/net/phy/Makefile	2007-06-12 03:12:29.000000000 +0200
@@ -12,3 +12,4 @@ obj-$(CONFIG_SMSC_PHY)		+= smsc.o
 obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
 obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
 obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+obj-$(CONFIG_STE100P_PHY)       += ste100p.o
diff -Nurp linux-2.6.21.4/drivers/net/phy/ste100p.c b/drivers/net/phy/ste100p.c
--- linux-2.6.21.4/drivers/net/phy/ste100p.c	1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/net/phy/ste100p.c	2007-06-12 02:52:31.000000000 +0200
@@ -0,0 +1,297 @@
+/*
+ * drivers/net/phy/ste100p.c
+ *
+ * Driver for STE100P PHYs
+ *
+ * Author: Grzegorz Rajtar mcgregor@blackmesaeast.com.pl
+ *
+ * Copyright (c) 2007 Black Mesa East 
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* Control register and bitmasks*/
+#define MII_STE100P_XCR_REG 0x00
+#define MII_STE100P_XCR_RESET 		1 << 15
+#define MII_STE100P_XCR_LOOPBACK	1 << 14
+#define MII_STE100P_XCR_SPEED		1 << 13
+#define MII_STE100P_XCR_AN		1 << 12
+#define MII_STE100P_XCR_PWRDN		1 << 11
+#define MII_STE100P_XCR_ISOLATE		1 << 10
+#define MII_STE100P_XCR_RSTRT_AN	1 << 9
+#define MII_STE100P_XCR_FULL_DUP	1 << 8
+#define MII_STE100P_XCR_COLLEN		1 << 7
+
+
+/* Iinterrupt register and bitmasks */
+#define MII_STE100P_XIE_REG	0x12
+#define MII_STE100P_XIE_ANCE	1 << 6
+#define MII_STE100P_XIE_RFE	1 << 5
+#define MII_STE100P_XIE_LDE	1 << 4
+#define MII_STE100P_XIE_ANAE	1 << 3
+#define MII_STE100P_XIE_PDFE	1 << 2
+#define MII_STE100P_XIE_ANPE	1 << 1
+#define MII_STE100P_XIE_REFE	1
+#define MII_STE100P_XIE_ALL	\
+(MII_STE100P_XIE_ANCE | MII_STE100P_XIE_RFE | MII_STE100P_XIE_LDE | \
+ MII_STE100P_XIE_ANAE | MII_STE100P_XIE_PDFE | MII_STE100P_XIE_ANPE | MII_STE100P_XIE_REFE)
+
+/* Iinterrupt status register and bitmasks */
+#define MII_STE100P_XCSIIS_REG		0x11
+#define MII_STE100P_XCSIIS_SPEED	1 << 9
+#define MII_STE100P_XCSIIS_DUPLEX	1 << 8
+#define MII_STE100P_XCSIIS_PAUSE	1 << 7
+#define MII_STE100P_XCSIIS_ANC		1 << 6
+#define MII_STE100P_XCSIIS_RFD		1 << 5
+#define MII_STE100P_XCSIIS_LS		1 << 4
+#define MII_STE100P_XCSIIS_ANAR		1 << 3
+#define MII_STE100P_XCSIIS_PDF		1 << 2
+#define MII_STE100P_XCSIIS_ANPR		1 << 1
+#define MII_STE100P_XCSIIS_REF		1
+
+/* 100-TX register and bitmasks*/
+#define MII_STE100P_100CTR_REG		0x13
+#define MII_STE100P_100CTR_DISERR	1 << 13
+#define MII_STE100P_100CTR_ANC		1 << 12
+#define MII_STE100P_100CTR_ENRLB	1 << 9
+#define MII_STE100P_100CTR_ENDCR	1 << 8
+#define MII_STE100P_100CTR_ENRZI	1 << 7
+#define MII_STE100P_100CTR_EN4B5B	1 << 6
+#define MII_STE100P_100CTR_ISOTX	1 << 5
+#define MII_STE100P_100CTR_CMODE_MASK	0x001C
+#define MII_STE100P_100CTR_DISMLT	1 << 1
+#define MII_STE100P_100CTR_DISCRM	1
+
+/* Auto-negotiation register and bitmasks*/
+#define MII_STE100P_ANA_REG         0x04
+#define MII_STE100P_ANA_NXTPG          1 << 15 
+#define MII_STE100P_ANA_RF             1 << 13
+#define MII_STE100P_ANA_FC             1 << 10
+#define MII_STE100P_ANA_T4             1 << 9
+#define MII_STE100P_ANA_TXF            1 << 8
+#define MII_STE100P_ANA_TXH            1 << 7
+#define MII_STE100P_ANA_10F            1 << 6
+#define MII_STE100P_ANA_10H            1 << 5
+#define MII_STE100P_ANA_SF             0x0000
+#define MII_STE100P_ANA_SF_MASK        0x000F
+
+/* PHY chip ID regs */
+#define MII_STE100P_PID1_REG        0x02
+#define MII_STE100P_PID2_REG        0x03
+
+#define MII_STE100P_PHYID_VAL    0x1C040000
+#define MII_STE100P_PHYID_MASK   0xFFFF0000
+
+
+
+MODULE_DESCRIPTION("STE100P PHY driver");
+MODULE_AUTHOR("Grzegorz Rajtar <mcgregor@blackmesaeast.com.pl>");
+MODULE_LICENSE("GPL");
+
+static int ste100p_config_intr(struct phy_device *phydev)
+{
+	int temp;
+	temp = phy_read(phydev, MII_STE100P_XIE_REG);
+
+	if(PHY_INTERRUPT_ENABLED == phydev->interrupts )
+		temp |= MII_STE100P_XIE_ALL;
+	else
+	{
+		temp &= ~(MII_STE100P_XIE_ALL);
+		//clear interrupt status register
+		phy_read(phydev, MII_STE100P_XCSIIS_REG);
+	}
+
+	temp = phy_write(phydev, MII_STE100P_XIE_REG, temp);
+
+	return temp;
+}
+
+static int ste100p_config_aneg(struct phy_device *phydev)
+{
+	int err;
+
+	int temp = phy_read(phydev, MII_STE100P_XCR_REG);
+	int temp2;
+	
+	/* Isolate the PHY */
+
+	err = phy_write(phydev, MII_STE100P_XCR_REG, temp | MII_STE100P_XCR_ISOLATE);
+	
+	//read for isolate latch
+	temp = phy_read(phydev, MII_STE100P_XCR_REG);
+
+	if (err < 0)
+		return err;
+
+	/* Set the Auto_negotiation Advertisement Register */
+	/* MII advertising for Next page, 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3 */
+	err =  phy_write(phydev, MII_STE100P_ANA_REG,
+	    	MII_STE100P_ANA_NXTPG | MII_STE100P_ANA_TXF | MII_STE100P_ANA_TXH |
+		MII_STE100P_ANA_10F | MII_STE100P_ANA_10H | MII_STE100P_ANA_SF);
+
+	if (err < 0)
+	    return err;
+
+	err =  phy_write(phydev, MII_STE100P_XCR_REG, 
+		temp | MII_STE100P_XCR_AN /*| MII_STE100P_XCR_SPEED */ | MII_STE100P_XCR_FULL_DUP);
+
+	if (err < 0)
+	    return err;
+
+	/* Restart auto negotiation */
+
+	err = phy_write(phydev, MII_STE100P_XCR_REG,  
+	    (temp | MII_STE100P_XCR_AN | MII_STE100P_XCR_RSTRT_AN) & (~MII_STE100P_XCR_ISOLATE));
+
+	//read for isolate latch
+	phy_read(phydev, MII_STE100P_XCR_REG);
+
+	if (err < 0)
+		return err;
+
+	/* Configure the new settings */
+	err = genphy_config_aneg(phydev);
+
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int ste100p_config_init(struct phy_device *phydev)
+{
+	int err;
+	int temp;
+	int temp_xcr;	
+
+	/* Isolate the PHY */
+
+	temp_xcr = phy_read(phydev, MII_STE100P_XCR_REG);
+	
+	err = phy_write(phydev, MII_STE100P_XCR_REG, 
+	    ((temp_xcr |  MII_STE100P_XCR_ISOLATE) & (~MII_STE100P_XCR_AN)));
+
+	//read for isolate latch
+	temp_xcr = phy_read(phydev, MII_STE100P_XCR_REG);
+		
+	err = phy_write(phydev, MII_STE100P_XCR_REG,  
+	    temp_xcr &  (~MII_STE100P_XCR_ISOLATE));	
+
+	//read for isolate latch
+	phy_read(phydev, MII_STE100P_XCR_REG);
+	
+	if (err < 0)
+	    return err;
+
+	temp = phy_read(phydev, MII_STE100P_ANA_REG);
+	    
+	err = phy_write(phydev, MII_STE100P_ANA_REG, temp
+	    | MII_STE100P_ANA_FC | MII_STE100P_ANA_TXF 
+	    | MII_STE100P_ANA_TXH | MII_STE100P_ANA_10F | MII_STE100P_ANA_10H);
+	    
+	if (err < 0)
+	    return err;
+
+	/* Reconnect the PHY, and enable Autonegotiation */
+	err = phy_write(phydev,  MII_STE100P_XCR_REG, (temp_xcr | MII_STE100P_XCR_AN 
+		| MII_STE100P_XCR_RSTRT_AN) & (~MII_STE100P_XCR_ISOLATE));
+
+	//read for isolate latch
+	phy_read(phydev, MII_STE100P_XCR_REG);
+
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int ste100p_ack_interrupt(struct phy_device *phydev)
+{
+	int intmask = 1;
+	int rep = 0;
+
+	//clear multiple interrupts;
+	do
+	{
+	    intmask = phy_read(phydev, MII_STE100P_XCSIIS_REG);
+	    rep++;	    	    
+	} while ((intmask & MII_STE100P_XIE_ALL) != 0 && rep < 25);
+	
+	return  0;
+}
+
+
+static int ste100p_suspend(struct phy_device *phydev)
+{
+	int temp = phy_read(phydev, MII_STE100P_XCR_REG);
+	temp = phy_write(phydev, MII_STE100P_XCR_REG, temp | MII_STE100P_XCR_PWRDN);
+	//read for latch XCR REG
+	phy_read(phydev, MII_STE100P_XCR_REG);
+	return temp;
+}
+
+static int ste100p_resume(struct phy_device *phydev)
+{
+	int temp;
+	temp = phy_write(phydev, MII_STE100P_XCR_REG, temp & (~MII_STE100P_XCR_PWRDN));
+	//read for latch XCR REG	
+	phy_read(phydev, MII_STE100P_XCR_REG);
+	return temp;
+}
+
+static struct phy_driver ste100p_driver = {
+	.phy_id		= MII_STE100P_PHYID_VAL,
+	.name		= "STE100P",
+	.phy_id_mask	= MII_STE100P_PHYID_MASK,
+	.features	= PHY_BASIC_FEATURES,
+	.flags		= PHY_HAS_INTERRUPT,
+	.config_init	= &ste100p_config_init,
+	.config_intr	= &ste100p_config_intr,
+	.config_aneg	= &ste100p_config_aneg,
+	.suspend	= &ste100p_suspend,
+	.resume		= &ste100p_resume,
+	.ack_interrupt 	= &ste100p_ack_interrupt,
+	.read_status	= &genphy_read_status,
+	.driver 	= { .owner = THIS_MODULE,},
+};
+
+static int __init ste100p_init(void)
+{
+	return phy_driver_register(&ste100p_driver);
+}
+
+static void __exit ste100p_exit(void)
+{
+	phy_driver_unregister(&ste100p_driver);
+}
+
+module_init(ste100p_init);
+module_exit(ste100p_exit);