incomplete Gumstix support
[openwrt.git] / target / linux / pxa / patches-2.6.21 / 044-smc911x-fixup.patch
1 Index: linux-2.6.21gum/drivers/net/smc911x.c
2 ===================================================================
3 --- linux-2.6.21gum.orig/drivers/net/smc911x.c
4 +++ linux-2.6.21gum/drivers/net/smc911x.c
5 @@ -76,6 +76,7 @@ static const char version[] =
6  #include <linux/etherdevice.h>
7  #include <linux/skbuff.h>
8  
9 +#include <linux/irq.h>
10  #include <asm/io.h>
11  #include <asm/irq.h>
12  
13 @@ -303,14 +304,14 @@ static void smc911x_reset(struct net_dev
14         SMC_SET_AFC_CFG(lp->afc_cfg);
15  
16  
17 -       /* Set to LED outputs */
18 -       SMC_SET_GPIO_CFG(0x70070000);
19 +       /* Set to LED outputs and configure EEPROM pins as GP outputs */
20 +       SMC_SET_GPIO_CFG(GPIO_CFG_LED1_EN_ | GPIO_CFG_LED2_EN_ | 1 << 20);
21  
22         /*
23 -        * Deassert IRQ for 1*10us for edge type interrupts
24 +        * Deassert IRQ for 22*10us for edge type interrupts
25          * and drive IRQ pin push-pull
26          */
27 -       SMC_SET_IRQ_CFG( (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_ );
28 +       SMC_SET_IRQ_CFG( (22 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_ );
29  
30         /* clear anything saved */
31         if (lp->pending_tx_skb != NULL) {
32 @@ -413,7 +414,7 @@ static inline void smc911x_drop_pkt(stru
33         if (fifo_count <= 4) {
34                 /* Manually dump the packet data */
35                 while (fifo_count--)
36 -                       SMC_GET_RX_FIFO();
37 +                       (void)SMC_GET_RX_FIFO();
38         } else   {
39                 /* Fast forward through the bad packet */
40                 SMC_SET_RX_DP_CTRL(RX_DP_CTRL_FFWD_BUSY_);
41 @@ -900,6 +901,7 @@ static void smc911x_phy_powerdown(struct
42         unsigned long ioaddr = dev->base_addr;
43         unsigned int bmcr;
44  
45 +       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
46         /* Enter Link Disable state */
47         SMC_GET_PHY_BMCR(phy, bmcr);
48         bmcr |= BMCR_PDOWN;
49 @@ -925,6 +927,7 @@ static void smc911x_phy_check_media(stru
50  
51         if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
52                 /* duplex state has changed */
53 +               DBG(SMC_DEBUG_MISC, "%s: duplex state has changed\n", dev->name);
54                 SMC_GET_PHY_BMCR(phyaddr, bmcr);
55                 SMC_GET_MAC_CR(cr);
56                 if (lp->mii.full_duplex) {
57 @@ -960,6 +963,7 @@ static void smc911x_phy_configure(struct
58         int my_phy_caps; /* My PHY capabilities */
59         int my_ad_caps; /* My Advertised capabilities */
60         int status;
61 +       int bmcr;
62         unsigned long flags;
63  
64         DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __FUNCTION__);
65 @@ -1033,9 +1037,12 @@ static void smc911x_phy_configure(struct
66  
67         DBG(SMC_DEBUG_MISC, "%s: phy caps=0x%04x\n", dev->name, my_phy_caps);
68         DBG(SMC_DEBUG_MISC, "%s: phy advertised caps=0x%04x\n", dev->name, my_ad_caps);
69 +       DBG(SMC_DEBUG_MISC, "%s: phy advertised readback caps=0x%04x\n", dev->name, status);
70  
71         /* Restart auto-negotiation process in order to advertise my caps */
72 -       SMC_SET_PHY_BMCR(phyaddr, BMCR_ANENABLE | BMCR_ANRESTART);
73 +       SMC_GET_PHY_BMCR(phyaddr, bmcr);
74 +       bmcr |= BMCR_ANENABLE | BMCR_ANRESTART;
75 +       SMC_SET_PHY_BMCR(phyaddr, bmcr);
76  
77         smc911x_phy_check_media(dev, 1);
78  
79 @@ -1888,6 +1895,39 @@ static int __init smc911x_findirq(unsign
80         return probe_irq_off(cookie);
81  }
82  
83 +static inline unsigned int is_gumstix_oui(u8 *addr)
84 +{
85 +       return (addr[0] == 0x00 && addr[1] == 0x15 && addr[2] == 0xC9);
86 +}
87 +
88 +/**
89 + * gen_serial_ether_addr - Generate software assigned Ethernet address
90 + * based on the system_serial number
91 + * @addr: Pointer to a six-byte array containing the Ethernet address
92 + *
93 + * Generate an Ethernet address (MAC) that is not multicast
94 + * and has the local assigned bit set, keyed on the system_serial
95 + */
96 +static inline void gen_serial_ether_addr(u8 *addr)
97 +{
98 +       static u8 ether_serial_digit = 0;
99 +       addr [0] = system_serial_high >> 8;
100 +       addr [1] = system_serial_high;
101 +       addr [2] = system_serial_low >> 24;
102 +       addr [3] = system_serial_low >> 16;
103 +       addr [4] = system_serial_low >> 8;
104 +       addr [5] = (system_serial_low & 0xc0) | /* top bits are from system serial */
105 +               (1 << 4) |                      /* 2 bits identify interface type 1=ether, 2=usb, 3&4 undef */
106 +               ((ether_serial_digit++) & 0x0f);        /* 15 possible interfaces of each type */
107 +
108 +       if(!is_gumstix_oui(addr))
109 +       {
110 +               addr [0] &= 0xfe;               /* clear multicast bit */
111 +               addr [0] |= 0x02;               /* set local assignment bit (IEEE802) */
112 +       }
113 +}
114 +
115 +
116  /*
117   * Function: smc911x_probe(unsigned long ioaddr)
118   *
119 @@ -2116,15 +2156,13 @@ static int __init smc911x_probe(struct n
120  #endif
121                 printk("\n");
122                 if (!is_valid_ether_addr(dev->dev_addr)) {
123 -                       printk("%s: Invalid ethernet MAC address. Please "
124 -                                       "set using ifconfig\n", dev->name);
125 -               } else {
126 -                       /* Print the Ethernet address */
127 -                       printk("%s: Ethernet addr: ", dev->name);
128 -                       for (i = 0; i < 5; i++)
129 -                               printk("%2.2x:", dev->dev_addr[i]);
130 -                       printk("%2.2x\n", dev->dev_addr[5]);
131 +                       gen_serial_ether_addr(dev->dev_addr);
132                 }
133 +               /* Print the Ethernet address */
134 +               printk("%s: Ethernet addr: ", dev->name);
135 +               for (i = 0; i < 5; i++)
136 +                       printk("%2.2x:", dev->dev_addr[i]);
137 +               printk("%2.2x\n", dev->dev_addr[5]);
138  
139                 if (lp->phy_type == 0) {
140                         PRINTK("%s: No PHY found\n", dev->name);
141 @@ -2300,8 +2338,15 @@ static struct platform_driver smc911x_dr
142         },
143  };
144  
145 +#ifdef CONFIG_ARCH_GUMSTIX
146 +extern void gumstix_smc911x_load(void);
147 +#endif
148 +
149  static int __init smc911x_init(void)
150  {
151 +#ifdef CONFIG_ARCH_GUMSTIX
152 +       gumstix_smc911x_load();
153 +#endif
154         return platform_driver_register(&smc911x_driver);
155  }
156  
157 Index: linux-2.6.21gum/drivers/net/gumstix-smc911x.c
158 ===================================================================
159 --- /dev/null
160 +++ linux-2.6.21gum/drivers/net/gumstix-smc911x.c
161 @@ -0,0 +1,148 @@
162 +/*
163 + *  Gumstix SMC911x chip intialization driver
164 + *
165 + *  Author:     Craig Hughes
166 + *  Created:    December 9, 2004
167 + *  Copyright:  (C) 2004 Craig Hughes
168 + *
169 + * This program is free software; you can redistribute it and/or modify
170 + * it under the terms of the GNU General Public License as published by
171 + * the Free Software Foundation; either version 2 of the License, or
172 + * (at your option) any later version.
173 + *
174 + */
175 +
176 +#include <linux/module.h>
177 +#include <linux/ioport.h>
178 +#include <linux/device.h>
179 +#include <linux/platform_device.h>
180 +#include <linux/delay.h>
181 +
182 +#include <asm/hardware.h>
183 +#include <asm/arch/pxa-regs.h>
184 +#include <asm/delay.h>
185 +
186 +#include <asm/arch/gumstix.h>
187 +
188 +#define SMC_DEBUG               9
189 +#include <asm/io.h>
190 +#include "smc911x.h"
191 +
192 +static struct resource gumstix_smc911x0_resources[] = {
193 +       [0] = {
194 +               .name   = "smc911x-regs",
195 +               .start  = PXA_CS1_PHYS,
196 +               .end    = PXA_CS1_PHYS + 0x000fffff,
197 +               .flags  = IORESOURCE_MEM,
198 +       },
199 +       [1] = {
200 +               .start  = GUMSTIX_ETH0_IRQ,
201 +               .end    = GUMSTIX_ETH0_IRQ,
202 +               .flags  = IORESOURCE_IRQ,
203 +       },
204 +};
205 +
206 +static struct resource gumstix_smc911x1_resources[] = {
207 +       [0] = {
208 +               .name   = "smc911x-regs",
209 +               .start  = PXA_CS2_PHYS,
210 +               .end    = PXA_CS2_PHYS + 0x000fffff,
211 +               .flags  = IORESOURCE_MEM,
212 +       },
213 +       [1] = {
214 +               .start  = GUMSTIX_ETH1_IRQ,
215 +               .end    = GUMSTIX_ETH1_IRQ,
216 +               .flags  = IORESOURCE_IRQ,
217 +       },
218 +};
219 +
220 +static struct platform_device gumstix_smc911x0_device = {
221 +       .name           = "smc911x",
222 +       .id             = 0,
223 +       .num_resources  = ARRAY_SIZE(gumstix_smc911x0_resources),
224 +       .resource       = gumstix_smc911x0_resources,
225 +};
226 +
227 +static struct platform_device gumstix_smc911x1_device = {
228 +       .name           = "smc911x",
229 +       .id             = 1,
230 +       .num_resources  = ARRAY_SIZE(gumstix_smc911x1_resources),
231 +       .resource       = gumstix_smc911x1_resources,
232 +};
233 +
234 +static struct platform_device *smc911x_devices[] = {
235 +       &gumstix_smc911x0_device,
236 +       &gumstix_smc911x1_device,
237 +};
238 +
239 +/* 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
240 + * that it would otherwise use.  We have no choice but to probe by doing:
241 + * Set nCS2 to CS2 mode
242 + * Set the reset line to GPIO out mode, and pull it high, then drop it low (to trigger reset)
243 + * Read from the memory space to check for the sentinel sequence identifying a likely SMC911x device
244 + */
245 +int __init gumstix_smc911x_init(void)
246 +{
247 +       unsigned int val, num_devices=ARRAY_SIZE(smc911x_devices);
248 +       void *ioaddr;
249 +
250 +       /* Set up nPWE */
251 +       pxa_gpio_mode(GPIO49_nPWE_MD);
252 +
253 +       pxa_gpio_mode(GPIO78_nCS_2_MD);
254 +       // If either if statement fails, then we'll drop out and turn_off_eth1,
255 +       // if both succeed, then we'll skip that and just proceed with 2 cards
256 +       if(request_mem_region(gumstix_smc911x1_resources[1].start, SMC911X_IO_EXTENT, "smc911x probe"))
257 +       {
258 +               ioaddr = ioremap(gumstix_smc911x1_resources[1].start, SMC911X_IO_EXTENT);
259 +               val = SMC_GET_PN();
260 +               iounmap(ioaddr);
261 +               release_mem_region(gumstix_smc911x1_resources[1].start, SMC911X_IO_EXTENT);
262 +               if (CHIP_9115 == val ||
263 +                       CHIP_9116 == val ||
264 +                       CHIP_9117 == val ||
265 +                       CHIP_9118 == val ) {
266 +                       goto proceed;
267 +               }
268 +       }
269 +
270 +turn_off_eth1:
271 +       // This is apparently not an SMC911x
272 +       // So, let's decrement the number of devices to request, and reset the GPIO lines to GPIO IN mode
273 +       num_devices--;
274 +       smc911x_devices[1] = NULL;
275 +       pxa_gpio_mode(78 | GPIO_IN);
276 +       
277 +proceed:
278 +       pxa_gpio_mode(GPIO15_nCS_1_MD);
279 +
280 +       if(smc911x_devices[1]) pxa_gpio_mode(GPIO_GUMSTIX_ETH1_RST_MD);
281 +       pxa_gpio_mode(GPIO_GUMSTIX_ETH0_RST_MD);
282 +
283 +       if(smc911x_devices[1]) GPCR(GPIO_GUMSTIX_ETH1_RST) = GPIO_bit(GPIO_GUMSTIX_ETH1_RST);
284 +       GPCR(GPIO_GUMSTIX_ETH0_RST) = GPIO_bit(GPIO_GUMSTIX_ETH0_RST);
285 +       msleep(500); // Hold RESET for at least 200µ
286 +
287 +       if(smc911x_devices[1]) GPSR(GPIO_GUMSTIX_ETH1_RST) = GPIO_bit(GPIO_GUMSTIX_ETH1_RST);
288 +       GPSR(GPIO_GUMSTIX_ETH0_RST) = GPIO_bit(GPIO_GUMSTIX_ETH0_RST);
289 +       msleep(50);
290 +
291 +       return platform_add_devices(smc911x_devices, num_devices);
292 +}
293 +
294 +void __exit gumstix_smc911x_exit(void)
295 +{
296 +       if(smc911x_devices[1] != NULL) platform_device_unregister(&gumstix_smc911x1_device);
297 +       platform_device_unregister(&gumstix_smc911x0_device);
298 +}
299 +
300 +void gumstix_smc911x_load(void) {}
301 +EXPORT_SYMBOL(gumstix_smc911x_load);
302 +
303 +module_init(gumstix_smc911x_init);
304 +module_exit(gumstix_smc911x_exit);
305 +
306 +MODULE_LICENSE("GPL");
307 +MODULE_AUTHOR("Craig Hughes <craig@gumstix.com>");
308 +MODULE_DESCRIPTION("Gumstix board SMC911x chip initialization driver");
309 +MODULE_VERSION("1:0.1");
310 Index: linux-2.6.21gum/drivers/net/Kconfig
311 ===================================================================
312 --- linux-2.6.21gum.orig/drivers/net/Kconfig
313 +++ linux-2.6.21gum/drivers/net/Kconfig
314 @@ -897,6 +897,13 @@ config SMC911X
315           called smc911x.  If you want to compile it as a module, say M 
316           here and read <file:Documentation/modules.txt>
317  
318 +config SMC911X_GUMSTIX
319 +       tristate
320 +       default m if SMC911X=m
321 +       default y if SMC911X=y
322 +       depends on SMC911X && ARCH_GUMSTIX
323 +
324 +
325  config NET_VENDOR_RACAL
326         bool "Racal-Interlan (Micom) NI cards"
327         depends on NET_ETHERNET && ISA
328 Index: linux-2.6.21gum/drivers/net/Makefile
329 ===================================================================
330 --- linux-2.6.21gum.orig/drivers/net/Makefile
331 +++ linux-2.6.21gum/drivers/net/Makefile
332 @@ -201,6 +201,7 @@ obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
333  obj-$(CONFIG_MACB) += macb.o
334  
335  obj-$(CONFIG_SMC91X_GUMSTIX) += gumstix-smc91x.o
336 +obj-$(CONFIG_SMC911X_GUMSTIX) += gumstix-smc911x.o
337  obj-$(CONFIG_ARM) += arm/
338  obj-$(CONFIG_DEV_APPLETALK) += appletalk/
339  obj-$(CONFIG_TR) += tokenring/
340 Index: linux-2.6.21gum/include/asm-arm/arch-pxa/gumstix.h
341 ===================================================================
342 --- linux-2.6.21gum.orig/include/asm-arm/arch-pxa/gumstix.h
343 +++ linux-2.6.21gum/include/asm-arm/arch-pxa/gumstix.h
344 @@ -52,7 +52,7 @@
345  #define GPIO_GUMSTIX_ETH0_RST          80
346  #define GPIO_GUMSTIX_ETH0              36
347  #else
348 -#define GPIO_GUMSTIX_ETH0_RST          32
349 +#define GPIO_GUMSTIX_ETH0_RST          107
350  #define GPIO_GUMSTIX_ETH0              99
351  #endif
352  #define GPIO_GUMSTIX_ETH1_RST          52
353 Index: linux-2.6.21gum/drivers/net/smc911x.h
354 ===================================================================
355 --- linux-2.6.21gum.orig/drivers/net/smc911x.h
356 +++ linux-2.6.21gum/drivers/net/smc911x.h
357 @@ -33,7 +33,9 @@
358   * Use the DMA feature on PXA chips
359   */
360  #ifdef CONFIG_ARCH_PXA
361 +#if !defined( CONFIG_SMC911X_GUMSTIX ) && !defined( CONFIG_SMC911X_GUMSTIX_MODULE )
362    #define SMC_USE_PXA_DMA      1
363 +#endif
364    #define SMC_USE_16BIT                0
365    #define SMC_USE_32BIT                1
366  #endif
367 @@ -46,13 +48,13 @@
368  #if    SMC_USE_16BIT
369  #define SMC_inb(a, r)                   readb((a) + (r))
370  #define SMC_inw(a, r)                   readw((a) + (r))
371 -#define SMC_inl(a, r)                   ((SMC_inw(a, r) & 0xFFFF)+(SMC_inw(a+2, r)<<16))
372 +#define SMC_inl(a, r)                   ((SMC_inw(a, r) & 0xFFFF)+(SMC_inw((a)+2, r)<<16))
373  #define SMC_outb(v, a, r)               writeb(v, (a) + (r))
374  #define SMC_outw(v, a, r)               writew(v, (a) + (r))
375  #define SMC_outl(v, a, r)                       \
376         do{                                      \
377 -                writel(v & 0xFFFF, (a) + (r));  \
378 -                writel(v >> 16, (a) + (r) + 2); \
379 +                writel((v) & 0xFFFF, (a) + (r));        \
380 +                writel((v) >> 16, (a) + (r) + 2); \
381          } while (0)
382  #define SMC_insl(a, r, p, l)    readsw((short*)((a) + (r)), p, l*2)
383  #define SMC_outsl(a, r, p, l)   writesw((short*)((a) + (r)), p, l*2)