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 #include +#include #include #include @@ -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 +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define SMC_DEBUG 9 +#include +#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 "); +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 +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 +#ifndef CONFIG_SMC911X_GUMSTIX #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)