summaryrefslogtreecommitdiff
path: root/recipes/linux/gumstix-kernel-2.6.21/smc911x-fixup.patch
blob: 7e051f9fb62ee2075cc626787abef3948966ad12 (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
Index: linux-2.6.21gum/drivers/net/smc911x.c
===================================================================
--- linux-2.6.21gum.orig/drivers/net/smc911x.c
+++ linux-2.6.21gum/drivers/net/smc911x.c
@@ -76,6 +76,7 @@ static const char version[] =
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
+#include <linux/irq.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
@@ -303,14 +304,14 @@ static void smc911x_reset(struct net_dev
 	SMC_SET_AFC_CFG(lp->afc_cfg);
 
 
-	/* Set to LED outputs */
-	SMC_SET_GPIO_CFG(0x70070000);
+	/* Set to LED outputs and configure EEPROM pins as GP outputs */
+	SMC_SET_GPIO_CFG(GPIO_CFG_LED1_EN_ | GPIO_CFG_LED2_EN_ | 1 << 20);
 
 	/*
-	 * Deassert IRQ for 1*10us for edge type interrupts
+	 * Deassert IRQ for 22*10us for edge type interrupts
 	 * and drive IRQ pin push-pull
 	 */
-	SMC_SET_IRQ_CFG( (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_ );
+	SMC_SET_IRQ_CFG( (22 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_ );
 
 	/* clear anything saved */
 	if (lp->pending_tx_skb != NULL) {
@@ -413,7 +414,7 @@ static inline void smc911x_drop_pkt(stru
 	if (fifo_count <= 4) {
 		/* Manually dump the packet data */
 		while (fifo_count--)
-			SMC_GET_RX_FIFO();
+			(void)SMC_GET_RX_FIFO();
 	} else	 {
 		/* Fast forward through the bad packet */
 		SMC_SET_RX_DP_CTRL(RX_DP_CTRL_FFWD_BUSY_);
@@ -499,7 +500,7 @@ static inline void	 smc911x_rcv(struct n
 		SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_));
 		SMC_PULL_DATA(data, pkt_len+2+3);
 
-		DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name,);
+		DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name);
 		PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64);
 		dev->last_rx = jiffies;
 		skb->dev = dev;
@@ -900,6 +901,7 @@ static void smc911x_phy_powerdown(struct
 	unsigned long ioaddr = dev->base_addr;
 	unsigned int bmcr;
 
+	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
 	/* Enter Link Disable state */
 	SMC_GET_PHY_BMCR(phy, bmcr);
 	bmcr |= BMCR_PDOWN;
@@ -925,6 +927,7 @@ static void smc911x_phy_check_media(stru
 
 	if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
 		/* duplex state has changed */
+		DBG(SMC_DEBUG_MISC, "%s: duplex state has changed\n", dev->name);
 		SMC_GET_PHY_BMCR(phyaddr, bmcr);
 		SMC_GET_MAC_CR(cr);
 		if (lp->mii.full_duplex) {
@@ -960,6 +963,7 @@ static void smc911x_phy_configure(struct
 	int my_phy_caps; /* My PHY capabilities */
 	int my_ad_caps; /* My Advertised capabilities */
 	int status;
+	int bmcr;
 	unsigned long flags;
 
 	DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __FUNCTION__);
@@ -1033,9 +1037,12 @@ static void smc911x_phy_configure(struct
 
 	DBG(SMC_DEBUG_MISC, "%s: phy caps=0x%04x\n", dev->name, my_phy_caps);
 	DBG(SMC_DEBUG_MISC, "%s: phy advertised caps=0x%04x\n", dev->name, my_ad_caps);
+	DBG(SMC_DEBUG_MISC, "%s: phy advertised readback caps=0x%04x\n", dev->name, status);
 
 	/* Restart auto-negotiation process in order to advertise my caps */
-	SMC_SET_PHY_BMCR(phyaddr, BMCR_ANENABLE | BMCR_ANRESTART);
+	SMC_GET_PHY_BMCR(phyaddr, bmcr);
+	bmcr |= BMCR_ANENABLE | BMCR_ANRESTART;
+	SMC_SET_PHY_BMCR(phyaddr, bmcr);
 
 	smc911x_phy_check_media(dev, 1);
 
@@ -1888,6 +1895,39 @@ static int __init smc911x_findirq(unsign
 	return probe_irq_off(cookie);
 }
 
+static inline unsigned int is_gumstix_oui(u8 *addr)
+{
+	return (addr[0] == 0x00 && addr[1] == 0x15 && addr[2] == 0xC9);
+}
+
+/**
+ * gen_serial_ether_addr - Generate software assigned Ethernet address
+ * based on the system_serial number
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Generate an Ethernet address (MAC) that is not multicast
+ * and has the local assigned bit set, keyed on the system_serial
+ */
+static inline void gen_serial_ether_addr(u8 *addr)
+{
+	static u8 ether_serial_digit = 0;
+	addr [0] = system_serial_high >> 8;
+	addr [1] = system_serial_high;
+	addr [2] = system_serial_low >> 24;
+	addr [3] = system_serial_low >> 16;
+	addr [4] = system_serial_low >> 8;
+	addr [5] = (system_serial_low & 0xc0) |	/* top bits are from system serial */
+		(1 << 4) |			/* 2 bits identify interface type 1=ether, 2=usb, 3&4 undef */
+		((ether_serial_digit++) & 0x0f);	/* 15 possible interfaces of each type */
+
+	if(!is_gumstix_oui(addr))
+	{
+		addr [0] &= 0xfe;		/* clear multicast bit */
+		addr [0] |= 0x02;		/* set local assignment bit (IEEE802) */
+	}
+}
+
+
 /*
  * Function: smc911x_probe(unsigned long ioaddr)
  *
@@ -2116,15 +2156,13 @@ static int __init smc911x_probe(struct n
 #endif
 		printk("\n");
 		if (!is_valid_ether_addr(dev->dev_addr)) {
-			printk("%s: Invalid ethernet MAC address. Please "
-					"set using ifconfig\n", dev->name);
-		} else {
-			/* Print the Ethernet address */
-			printk("%s: Ethernet addr: ", dev->name);
-			for (i = 0; i < 5; i++)
-				printk("%2.2x:", dev->dev_addr[i]);
-			printk("%2.2x\n", dev->dev_addr[5]);
+			gen_serial_ether_addr(dev->dev_addr);
 		}
+		/* Print the Ethernet address */
+		printk("%s: Ethernet addr: ", dev->name);
+		for (i = 0; i < 5; i++)
+			printk("%2.2x:", dev->dev_addr[i]);
+		printk("%2.2x\n", dev->dev_addr[5]);
 
 		if (lp->phy_type == 0) {
 			PRINTK("%s: No PHY found\n", dev->name);
@@ -2300,8 +2338,15 @@ static struct platform_driver smc911x_dr
 	},
 };
 
+#ifdef CONFIG_ARCH_GUMSTIX
+extern void gumstix_smc911x_load(void);
+#endif
+
 static int __init smc911x_init(void)
 {
+#ifdef CONFIG_ARCH_GUMSTIX
+	gumstix_smc911x_load();
+#endif
 	return platform_driver_register(&smc911x_driver);
 }
 
Index: linux-2.6.21gum/drivers/net/gumstix-smc911x.c
===================================================================
--- /dev/null
+++ linux-2.6.21gum/drivers/net/gumstix-smc911x.c
@@ -0,0 +1,148 @@
+/*
+ *  Gumstix SMC911x chip intialization driver
+ *
+ *  Author:     Craig Hughes
+ *  Created:    December 9, 2004
+ *  Copyright:  (C) 2004 Craig Hughes
+ *
+ * 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/module.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/delay.h>
+
+#include <asm/arch/gumstix.h>
+
+#define SMC_DEBUG               9
+#include <asm/io.h>
+#include "smc911x.h"
+
+static struct resource gumstix_smc911x0_resources[] = {
+	[0] = {
+		.name	= "smc911x-regs",
+		.start  = PXA_CS1_PHYS,
+		.end    = PXA_CS1_PHYS + 0x000fffff,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = GUMSTIX_ETH0_IRQ,
+		.end    = GUMSTIX_ETH0_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource gumstix_smc911x1_resources[] = {
+	[0] = {
+		.name	= "smc911x-regs",
+		.start	= PXA_CS2_PHYS,
+		.end	= PXA_CS2_PHYS + 0x000fffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= GUMSTIX_ETH1_IRQ,
+		.end	= GUMSTIX_ETH1_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device gumstix_smc911x0_device = {
+	.name           = "smc911x",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(gumstix_smc911x0_resources),
+	.resource       = gumstix_smc911x0_resources,
+};
+
+static struct platform_device gumstix_smc911x1_device = {
+	.name           = "smc911x",
+	.id             = 1,
+	.num_resources  = ARRAY_SIZE(gumstix_smc911x1_resources),
+	.resource       = gumstix_smc911x1_resources,
+};
+
+static struct platform_device *smc911x_devices[] = {
+	&gumstix_smc911x0_device,
+	&gumstix_smc911x1_device,
+};
+
+/* First we're going to test if there's a 2nd SMC911x, and if not, then we'll free up those resources and the GPIO lines
+ * that it would otherwise use.  We have no choice but to probe by doing:
+ * Set nCS2 to CS2 mode
+ * Set the reset line to GPIO out mode, and pull it high, then drop it low (to trigger reset)
+ * Read from the memory space to check for the sentinel sequence identifying a likely SMC911x device
+ */
+int __init gumstix_smc911x_init(void)
+{
+	unsigned int val, num_devices=ARRAY_SIZE(smc911x_devices);
+	void *ioaddr;
+
+	/* Set up nPWE */
+	pxa_gpio_mode(GPIO49_nPWE_MD);
+
+	pxa_gpio_mode(GPIO78_nCS_2_MD);
+	// If either if statement fails, then we'll drop out and turn_off_eth1,
+	// if both succeed, then we'll skip that and just proceed with 2 cards
+	if(request_mem_region(gumstix_smc911x1_resources[1].start, SMC911X_IO_EXTENT, "smc911x probe"))
+	{
+		ioaddr = ioremap(gumstix_smc911x1_resources[1].start, SMC911X_IO_EXTENT);
+		val = SMC_GET_PN();
+		iounmap(ioaddr);
+		release_mem_region(gumstix_smc911x1_resources[1].start, SMC911X_IO_EXTENT);
+		if (CHIP_9115 == val ||
+			CHIP_9116 == val ||
+			CHIP_9117 == val ||
+			CHIP_9118 == val ) {
+			goto proceed;
+		}
+	}
+
+turn_off_eth1:
+	// This is apparently not an SMC911x
+	// So, let's decrement the number of devices to request, and reset the GPIO lines to GPIO IN mode
+	num_devices--;
+	smc911x_devices[1] = NULL;
+	pxa_gpio_mode(78 | GPIO_IN);
+	
+proceed:
+	pxa_gpio_mode(GPIO15_nCS_1_MD);
+
+	if(smc911x_devices[1]) pxa_gpio_mode(GPIO_GUMSTIX_ETH1_RST_MD);
+	pxa_gpio_mode(GPIO_GUMSTIX_ETH0_RST_MD);
+
+	if(smc911x_devices[1]) GPCR(GPIO_GUMSTIX_ETH1_RST) = GPIO_bit(GPIO_GUMSTIX_ETH1_RST);
+	GPCR(GPIO_GUMSTIX_ETH0_RST) = GPIO_bit(GPIO_GUMSTIX_ETH0_RST);
+	msleep(500); // Hold RESET for at least 200µ
+
+	if(smc911x_devices[1]) GPSR(GPIO_GUMSTIX_ETH1_RST) = GPIO_bit(GPIO_GUMSTIX_ETH1_RST);
+	GPSR(GPIO_GUMSTIX_ETH0_RST) = GPIO_bit(GPIO_GUMSTIX_ETH0_RST);
+	msleep(50);
+
+	return platform_add_devices(smc911x_devices, num_devices);
+}
+
+void __exit gumstix_smc911x_exit(void)
+{
+	if(smc911x_devices[1] != NULL) platform_device_unregister(&gumstix_smc911x1_device);
+	platform_device_unregister(&gumstix_smc911x0_device);
+}
+
+void gumstix_smc911x_load(void) {}
+EXPORT_SYMBOL(gumstix_smc911x_load);
+
+module_init(gumstix_smc911x_init);
+module_exit(gumstix_smc911x_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Craig Hughes <craig@gumstix.com>");
+MODULE_DESCRIPTION("Gumstix board SMC911x chip initialization driver");
+MODULE_VERSION("1:0.1");
Index: linux-2.6.21gum/drivers/net/Kconfig
===================================================================
--- linux-2.6.21gum.orig/drivers/net/Kconfig
+++ linux-2.6.21gum/drivers/net/Kconfig
@@ -897,6 +897,13 @@ config SMC911X
 	  called smc911x.  If you want to compile it as a module, say M 
 	  here and read <file:Documentation/modules.txt>
 
+config SMC911X_GUMSTIX
+	tristate
+	default m if SMC911X=m
+	default y if SMC911X=y
+	depends on SMC911X && ARCH_GUMSTIX
+
+
 config NET_VENDOR_RACAL
 	bool "Racal-Interlan (Micom) NI cards"
 	depends on NET_ETHERNET && ISA
Index: linux-2.6.21gum/drivers/net/Makefile
===================================================================
--- linux-2.6.21gum.orig/drivers/net/Makefile
+++ linux-2.6.21gum/drivers/net/Makefile
@@ -201,6 +201,7 @@ obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
 obj-$(CONFIG_MACB) += macb.o
 
 obj-$(CONFIG_SMC91X_GUMSTIX) += gumstix-smc91x.o
+obj-$(CONFIG_SMC911X_GUMSTIX) += gumstix-smc911x.o
 obj-$(CONFIG_ARM) += arm/
 obj-$(CONFIG_DEV_APPLETALK) += appletalk/
 obj-$(CONFIG_TR) += tokenring/
Index: linux-2.6.21gum/include/asm-arm/arch-pxa/gumstix.h
===================================================================
--- linux-2.6.21gum.orig/include/asm-arm/arch-pxa/gumstix.h
+++ linux-2.6.21gum/include/asm-arm/arch-pxa/gumstix.h
@@ -52,7 +52,7 @@
 #define GPIO_GUMSTIX_ETH0_RST		80
 #define GPIO_GUMSTIX_ETH0		36
 #else
-#define GPIO_GUMSTIX_ETH0_RST		32
+#define GPIO_GUMSTIX_ETH0_RST		107
 #define GPIO_GUMSTIX_ETH0		99
 #endif
 #define GPIO_GUMSTIX_ETH1_RST		52
Index: linux-2.6.21gum/drivers/net/smc911x.h
===================================================================
--- linux-2.6.21gum.orig/drivers/net/smc911x.h
+++ linux-2.6.21gum/drivers/net/smc911x.h
@@ -33,7 +33,9 @@
  * Use the DMA feature on PXA chips
  */
 #ifdef CONFIG_ARCH_PXA
+#if !defined( CONFIG_SMC911X_GUMSTIX ) && !defined( CONFIG_SMC911X_GUMSTIX_MODULE )
   #define SMC_USE_PXA_DMA	1
+#endif
   #define SMC_USE_16BIT		0
   #define SMC_USE_32BIT		1
 #endif
@@ -46,13 +48,13 @@
 #if	SMC_USE_16BIT
 #define SMC_inb(a, r)			 readb((a) + (r))
 #define SMC_inw(a, r)			 readw((a) + (r))
-#define SMC_inl(a, r)			 ((SMC_inw(a, r) & 0xFFFF)+(SMC_inw(a+2, r)<<16))
+#define SMC_inl(a, r)			 ((SMC_inw(a, r) & 0xFFFF)+(SMC_inw((a)+2, r)<<16))
 #define SMC_outb(v, a, r)		 writeb(v, (a) + (r))
 #define SMC_outw(v, a, r)		 writew(v, (a) + (r))
 #define SMC_outl(v, a, r) 			 \
 	do{					 \
-		 writel(v & 0xFFFF, (a) + (r));	 \
-		 writel(v >> 16, (a) + (r) + 2); \
+		 writel((v) & 0xFFFF, (a) + (r));	 \
+		 writel((v) >> 16, (a) + (r) + 2); \
 	 } while (0)
 #define SMC_insl(a, r, p, l)	 readsw((short*)((a) + (r)), p, l*2)
 #define SMC_outsl(a, r, p, l)	 writesw((short*)((a) + (r)), p, l*2)