* Alchemy: Support for RMI Alchemy Au1300 and DBAu1300
@ 2009-03-06 16:19 Kevin Hickey
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
0 siblings, 1 reply; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:19 UTC (permalink / raw)
To: ralf, linux-mips
This patch series introduces support for the RMI Alchemy Au1300 series of SOCs
and the DBAu1300 (or DB1300) development board. With this set the basic CPU
and board are supported, as well as a few of the system peripherals. USB, LCD,
UART, MMC/SD and ethernet drivers are included. Other drivers are currently in
development and will be released in a later patch set. All included code has
been tested and verified working on a DB1300 board.
Though some of the new code added here could be useful for other boards (the
DB1200 in particular), I did my best to limit this patch set to additions only.
It should not disturb any other boards. To verify this I built and tested the
updated directory for an on a DB1200 board. A future patch set may include
some integration of this new code into the DB1200 configuration.
arch/mips/Kconfig | 1 +
arch/mips/Makefile | 6 +
arch/mips/alchemy/Kconfig | 22 +
arch/mips/alchemy/common/Makefile | 4 +-
arch/mips/alchemy/common/au13xx_res.c | 104 +
arch/mips/alchemy/common/dbdma.c | 46 +-
arch/mips/alchemy/common/gpio_int.c | 268 +
arch/mips/alchemy/common/irq.c | 3 +
arch/mips/alchemy/common/platform.c | 76 +-
arch/mips/alchemy/common/time.c | 16 +
arch/mips/alchemy/devboards/Makefile | 6 +
arch/mips/alchemy/devboards/cascade_irq.c | 142 +
arch/mips/alchemy/devboards/db1300/Makefile | 6 +
arch/mips/alchemy/devboards/db1300/board_setup.c | 123 +
arch/mips/alchemy/devboards/db1300/mmc.c | 154 +
arch/mips/alchemy/devboards/leds.c | 58 +
arch/mips/configs/db1300_defconfig | 1216 ++++
arch/mips/include/asm/cpu.h | 10 +-
arch/mips/include/asm/mach-au1x00/au1000.h | 49 +
arch/mips/include/asm/mach-au1x00/au13xx.h | 207 +
arch/mips/include/asm/mach-au1x00/au1xxx.h | 3 +
arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h | 33 +
arch/mips/include/asm/mach-au1x00/dev_boards.h | 44 +
arch/mips/include/asm/mach-au1x00/gpio_int.h | 239 +
arch/mips/include/asm/mach-au1x00/irq.h | 34 +
arch/mips/include/asm/mips-boards/db1300.h | 120 +
arch/mips/kernel/cpu-probe.c | 20 +
arch/mips/mm/c-r4k.c | 1 +
arch/mips/mm/tlbex.c | 1 +
drivers/mmc/host/Kconfig | 2 +-
drivers/mmc/host/au1xmmc.c | 18 +-
drivers/net/Kconfig | 6 +
drivers/net/Makefile | 3 +
drivers/net/smsc9210/Makefile | 9 +
drivers/net/smsc9210/ioctl_118.h | 298 +
drivers/net/smsc9210/platform_alchemy.c | 88 +
drivers/net/smsc9210/platform_alchemy.h | 117 +
drivers/net/smsc9210/smsc9210.h | 23 +
drivers/net/smsc9210/smsc9210_main.c | 7189 ++++++++++++++++++++++
drivers/usb/Kconfig | 1 +
drivers/usb/host/ehci-au13xx.c | 213 +
drivers/usb/host/ehci-hcd.c | 5 +
drivers/video/Kconfig | 2 +-
43 files changed, 10969 insertions(+), 17 deletions(-)
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH 01/10] Initial Au1300 and DBAu1300 support
2009-03-06 16:19 Alchemy: Support for RMI Alchemy Au1300 and DBAu1300 Kevin Hickey
@ 2009-03-06 16:20 ` Kevin Hickey
2009-03-06 16:20 ` [PATCH 02/10] Alchemy: Au1300 new interrupt controller Kevin Hickey
` (9 more replies)
0 siblings, 10 replies; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:20 UTC (permalink / raw)
To: ralf, linux-mips; +Cc: Kevin Hickey
This patch introduces the new RMI Alchemy Au1300 series SOC to the kernel, as
well as its first development board, the DBAu1300 (or DB1300). This patch is
just the basic CPU identification and some resouce constants.
Also included are some new Alchemy IO functions and macros, named to match with
the current kernel standard. They include au_iowrite32, au_ioread32, etc.
These are used heavily in the Au1300/DB1300 code so they need to be included
here.
Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
---
arch/mips/Makefile | 6 +
arch/mips/alchemy/Kconfig | 18 ++
arch/mips/alchemy/common/platform.c | 2 +
arch/mips/alchemy/devboards/Makefile | 1 +
arch/mips/alchemy/devboards/db1300/Makefile | 6 +
arch/mips/alchemy/devboards/db1300/board_setup.c | 123 +++++++++++++
arch/mips/include/asm/cpu.h | 10 +-
arch/mips/include/asm/mach-au1x00/au1000.h | 44 +++++
arch/mips/include/asm/mach-au1x00/au13xx.h | 207 ++++++++++++++++++++++
arch/mips/include/asm/mach-au1x00/au1xxx.h | 3 +
arch/mips/include/asm/mach-au1x00/dev_boards.h | 44 +++++
arch/mips/include/asm/mips-boards/db1300.h | 120 +++++++++++++
arch/mips/kernel/cpu-probe.c | 20 ++
arch/mips/mm/c-r4k.c | 1 +
arch/mips/mm/tlbex.c | 1 +
15 files changed, 603 insertions(+), 3 deletions(-)
create mode 100644 arch/mips/alchemy/devboards/db1300/Makefile
create mode 100644 arch/mips/alchemy/devboards/db1300/board_setup.c
create mode 100644 arch/mips/include/asm/mach-au1x00/au13xx.h
create mode 100644 arch/mips/include/asm/mach-au1x00/dev_boards.h
create mode 100644 arch/mips/include/asm/mips-boards/db1300.h
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 21b00e9..15e1577 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -255,6 +255,12 @@ core-$(CONFIG_MIPS_DB1200) += arch/mips/alchemy/devboards/
cflags-$(CONFIG_MIPS_DB1200) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
load-$(CONFIG_MIPS_DB1200) += 0xffffffff80100000
+# RMI Alchemy DBAu1300 development board
+#
+core-$(CONFIG_MIPS_DB1300) += arch/mips/alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1300) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1300) += 0xffffffff80100000
+
#
# AMD Alchemy Bosporus eval board
#
diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig
index 7f8ef13..7198a88 100644
--- a/arch/mips/alchemy/Kconfig
+++ b/arch/mips/alchemy/Kconfig
@@ -53,6 +53,12 @@ config MIPS_DB1550
select MIPS_DISABLE_OBSOLETE_IDE
select SYS_SUPPORTS_LITTLE_ENDIAN
+config MIPS_DB1300
+ bool "Alchemy DBAu1300 Development Board"
+ select SOC_AU13XX
+ select DMA_COHERENT
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
config MIPS_MIRAGE
bool "Alchemy Mirage board"
select DMA_NONCOHERENT
@@ -124,6 +130,12 @@ config SOC_AU1550
config SOC_AU1200
bool
select SOC_AU1X00
+ select AU_INT_CNTLR
+
+config SOC_AU13XX
+ bool
+ select SOC_AU1X00
+ select AU_GPIO_INT_CNTLR
config SOC_AU1X00
bool
@@ -135,3 +147,9 @@ config SOC_AU1X00
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_APM_EMULATION
select GENERIC_HARDIRQS_NO__DO_IRQ
+
+config AU_INT_CNTLR
+ bool
+
+config AU_GPIO_INT_CNTLR
+ bool
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 5c76c64..fd096d1 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -65,6 +65,7 @@ static struct platform_device au1xx0_uart_device = {
},
};
+#ifndef CONFIG_SOC_AU13XX
/* OHCI (USB full speed host controller) */
static struct resource au1xxx_usb_ohci_resources[] = {
[0] = {
@@ -92,6 +93,7 @@ static struct platform_device au1xxx_usb_ohci_device = {
.num_resources = ARRAY_SIZE(au1xxx_usb_ohci_resources),
.resource = au1xxx_usb_ohci_resources,
};
+#endif
/*** AU1100 LCD controller ***/
diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index 730f9f2..0d2d224 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_MIPS_PB1550) += pb1550/
obj-$(CONFIG_MIPS_DB1000) += db1x00/
obj-$(CONFIG_MIPS_DB1100) += db1x00/
obj-$(CONFIG_MIPS_DB1200) += pb1200/
+obj-$(CONFIG_MIPS_DB1300) += db1300/
obj-$(CONFIG_MIPS_DB1500) += db1x00/
obj-$(CONFIG_MIPS_DB1550) += db1x00/
obj-$(CONFIG_MIPS_BOSPORUS) += db1x00/
diff --git a/arch/mips/alchemy/devboards/db1300/Makefile b/arch/mips/alchemy/devboards/db1300/Makefile
new file mode 100644
index 0000000..edaff49
--- /dev/null
+++ b/arch/mips/alchemy/devboards/db1300/Makefile
@@ -0,0 +1,6 @@
+#
+# Copyright 2008 RMI Corporation. All rights reserved.
+# Author: Kevin Hickey <khickey@rmicorp.com>
+#
+
+obj-y := board_setup.o mmc.o
diff --git a/arch/mips/alchemy/devboards/db1300/board_setup.c b/arch/mips/alchemy/devboards/db1300/board_setup.c
new file mode 100644
index 0000000..118b15c
--- /dev/null
+++ b/arch/mips/alchemy/devboards/db1300/board_setup.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2003-2008 RMI Corporation. All rights reserved.
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h> /* for printk */
+
+#include <prom.h>
+#include <au1xxx.h>
+#include <asm/mach-au1x00/dev_boards.h>
+
+#define DB1300_SYSTEM_TYPE_STRING "RMI DBAu1300 Development Board"
+
+volatile struct bcsr_regs *const bcsr =
+ (struct bcsr_regs *)(DB1300_BCSR_REGS_PHYS_ADDR + KSEG1_OFFSET);
+
+void __init board_setup(void)
+{
+ char *argptr = NULL;
+
+ printk(KERN_INFO DB1300_SYSTEM_TYPE_STRING "\n");
+
+ /*
+ * Add some text to the command line to point the au1200fb driver to
+ * the board switch.
+ */
+ argptr = prom_getcmdline();
+ strcat(argptr, "console=ttyS0,115200 video=au1200fb:panel:bs");
+
+ /*
+ * Enable VBUS to the USB Host port
+ */
+ AU_SET_BITS_16(BCSR_RESETS_USB_HOST, &bcsr->resets);
+}
+
+void board_reset(void)
+{
+ /* KH: TODO - write board_reset() */
+}
+
+const char *get_system_type(void)
+{
+ return DB1300_SYSTEM_TYPE_STRING;
+}
+
+#if 0
+void __init prom_init(void)
+{
+ unsigned char *memsize_str;
+ unsigned long memsize;
+
+ prom_argc = (int)fw_arg0;
+ prom_argv = (char **)fw_arg1;
+ prom_envp = (char **)fw_arg2;
+
+ prom_init_cmdline();
+ memsize_str = prom_getenv("memsize");
+ /* KH: TODO - Change back to 128 MB when the second DDR channel is working. */
+ if (!memsize_str)
+ memsize = 0x04000000;
+ else
+ strict_strtol(memsize_str, 0, &memsize);
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+#endif
+
+/*
+ * Called by plat_irq_dispatch to do board-specific things (i.e. display the
+ * interrupt on a hex output). This should *not* be used for board-specific
+ * interrupt handling; for that register a new interrupt handler as a device
+ * driver would do.
+ */
+void board_irq_dispatch(unsigned int irq)
+{
+ db_set_hex((u8)irq);
+}
+
+/*
+ * Board specific functions for the Au1200 Framebuffer driver
+ */
+
+int board_au1200fb_panel(void)
+{
+ u16 switches = (au_ioread16(&db_bcsr->switches) & 0x0f00 ) >> 8;
+
+ printk("Returning LCD switch setting %d\n", switches);
+ return switches;
+}
+
+int board_au1200fb_panel_init(void)
+{
+ /* Apply power */
+ AU_SET_BITS_16(0x7, &db_bcsr->board);
+ return 0;
+}
+
+int board_au1200fb_panel_shutdown(void)
+{
+ /* Remove power */
+ AU_CLEAR_BITS_16(0x7, &db_bcsr->board);
+ return 0;
+}
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index c018727..e3528a7 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -33,9 +33,9 @@
#define PRID_COMP_TOSHIBA 0x070000
#define PRID_COMP_LSI 0x080000
#define PRID_COMP_LEXRA 0x0b0000
+#define PRID_COMP_RMI 0x0c0000
#define PRID_COMP_CAVIUM 0x0d0000
-
/*
* Assigned values for the product ID register. In order to detect a
* certain CPU type exactly eventually additional registers may need to
@@ -115,9 +115,13 @@
#define PRID_IMP_BCM3302 0x9000
/*
- * These are the PRID's for when 23:16 == PRID_COMP_CAVIUM
+ * These are the PRID's for when 23:16 == PRID_COMP_RMI
*/
+#define PRID_IMP_AU13XX 0x8000
+/*
+ * These are the PRID's for when 23:16 == PRID_COMP_CAVIUM
+ */
#define PRID_IMP_CAVIUM_CN38XX 0x0000
#define PRID_IMP_CAVIUM_CN31XX 0x0100
#define PRID_IMP_CAVIUM_CN30XX 0x0200
@@ -210,7 +214,7 @@ enum cpu_type_enum {
*/
CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
CPU_AU1000, CPU_AU1100, CPU_AU1200, CPU_AU1210, CPU_AU1250, CPU_AU1500,
- CPU_AU1550, CPU_PR4450, CPU_BCM3302, CPU_BCM4710,
+ CPU_AU1550, CPU_AU13XX, CPU_PR4450, CPU_BCM3302, CPU_BCM4710,
/*
* MIPS64 class processors
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 62f91f5..ddebb84 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -6,6 +6,9 @@
* Copyright 2000-2001, 2006-2008 MontaVista Software Inc.
* Author: MontaVista Software, Inc. <source@mvista.com>
*
+ * Copyright 2008 RMI Corporation
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
* 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
@@ -43,6 +46,8 @@
#include <linux/io.h>
#include <linux/irq.h>
+#include <au13xx.h>
+
/* cpu pipeline flush */
void static inline au_sync(void)
{
@@ -91,6 +96,10 @@ static inline u32 au_readl(unsigned long reg)
return *(volatile u32 *)reg;
}
+void static inline au_iowrite16(u16 val, volatile u16 *reg)
+{
+ *reg = val;
+}
/* Early Au1000 have a write-only SYS_CPUPLL register. */
static inline int au1xxx_cpu_has_pll_wo(void)
{
@@ -103,6 +112,11 @@ static inline int au1xxx_cpu_has_pll_wo(void)
return 0;
}
+static inline u16 au_ioread16(volatile u16 *reg)
+{
+ return *reg;
+}
+
/* does CPU need CONFIG[OD] set to fix tons of errata? */
static inline int au1xxx_cpu_needs_config_od(void)
{
@@ -130,6 +144,36 @@ static inline int au1xxx_cpu_needs_config_od(void)
return 0;
}
+void static inline au_iowrite32(u32 val, volatile u32 *reg)
+{
+ *reg = val;
+}
+
+static inline u32 au_ioread32(volatile u32 *reg)
+{
+ return *reg;
+}
+
+#define AU_SET_BITS_16(mask, reg) \
+do { \
+ au_iowrite16((au_ioread16(reg) | mask ), reg); \
+} while(0)
+
+#define AU_CLEAR_BITS_16(mask, reg) \
+do { \
+ au_iowrite16((au_ioread16(reg) & ~mask ), reg); \
+} while(0)
+
+#define AU_SET_BITS_32(mask, reg) \
+do { \
+ au_iowrite32((au_ioread32(reg) | mask), reg); \
+} while(0)
+
+#define AU_CLEAR_BITS_32(mask, reg) \
+do { \
+ au_iowrite32((au_ioread32(reg) & ~mask), reg); \
+} while(0)
+
/* arch/mips/au1000/common/clocks.c */
extern void set_au1x00_speed(unsigned int new_freq);
extern unsigned int get_au1x00_speed(void);
diff --git a/arch/mips/include/asm/mach-au1x00/au13xx.h b/arch/mips/include/asm/mach-au1x00/au13xx.h
new file mode 100644
index 0000000..e868176
--- /dev/null
+++ b/arch/mips/include/asm/mach-au1x00/au13xx.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2008 RMI Corporation
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _AU13XX_H
+#define _AU13XX_H
+
+#ifdef CONFIG_SOC_AU13XX
+
+#define NR_INTS 255
+
+#define UART0_ADDR 0xB0100000
+#define UART1_ADDR 0xB0101000
+#define UART2_ADDR 0xB0102000
+#define UART3_ADDR 0xB0103000
+
+#define KSEG1_OFFSET 0xA0000000
+#define GPIO_INT_CTRLR_BASE 0x10200000
+/*
+ * Linux uses IRQ 0-7 for the 8 causes. That means that all of our channel
+ * bits need to be offset by 8 either when passed to do_IRQ or when received
+ * through the irq_chip calls
+ *
+ * KH: TODO - This is duplicated from gpio_int.h Is that the right thing to do?
+ */
+#define GPINT_LINUX_IRQ_OFFSET 8
+
+#define AU1300_IRQ_UART1 17
+#define AU1300_IRQ_UART2 25
+#define AU1300_IRQ_UART3 27
+#define AU1300_IRQ_SD1 32
+#define AU1300_IRQ_SD2 38
+#define AU1300_IRQ_PSC0 48
+#define AU1300_IRQ_PSC1 52
+#define AU1300_IRQ_PSC2 56
+#define AU1300_IRQ_PSC3 60
+#define AU1300_IRQ_NAND 62
+#define AU1300_IRQ_DDMA 75
+#define AU1300_IRQ_GPU 78
+#define AU1300_IRQ_MPU 77
+#define AU1300_IRQ_MMU 76
+#define AU1300_IRQ_UDMA 79
+#define AU1300_IRQ_TOY_TICK 80
+#define AU1300_IRQ_TOYMATCH_0 81
+#define AU1300_IRQ_TOYMATCH_1 82
+#define AU1300_IRQ_TOYMATCH_2 83
+#define AU1300_IRQ_RTC_TICK 84
+#define AU1300_IRQ_RTCMATCH_0 85
+#define AU1300_IRQ_RTCMATCH_1 86
+#define AU1300_IRQ_RTCMATCH_2 87
+#define AU1300_IRQ_UART0 88
+#define AU1300_IRQ_SD0 89
+#define AU1300_IRQ_USB 90
+#define AU1300_IRQ_LCD 91
+#define AU1300_IRQ_BSA 94
+#define AU1300_IRQ_MPE 93
+#define AU1300_IRQ_ITE 92
+#define AU1300_IRQ_AES 95
+#define AU1300_IRQ_CIM 96
+
+#define LCD_PHYS_ADDR 0x15000000
+
+#define AU1200_LCD_INT (GPINT_LINUX_IRQ_OFFSET + AU1300_IRQ_LCD)
+#define AU1000_RTC_MATCH2_INT (GPINT_LINUX_IRQ_OFFSET + AU1300_IRQ_RTCMATCH_2)
+
+#define SD0_PHYS_ADDR 0x10600000
+#define SD1_PHYS_ADDR 0x10601000
+
+
+#define USB_BASE_PHYS_ADDR 0x14021000
+#define USB_EHCI_BASE 0x14020000
+#define USB_EHCI_LEN 0x400
+#define USB_OHCI_BASE 0x14020800
+#define USB_OHCI_LEN 0x400
+#define USB_UOC_BASE 0x14022000
+#define USB_UOC_LEN 0x20
+#define USB_UDC_BASE 0x14022000
+#define USB_UDC_LEN 0x2000
+
+#if !defined(ASSEMBLER)
+typedef volatile struct
+{
+ // setup registers
+ u32 dwc_ctrl1; //0x0000
+ u32 dwc_ctrl2; //0x0004
+ u32 reserved0[2]; //0x08 - 0x0C
+
+ u32 vbus_timer; //0x0010
+ u32 sbus_ctrl; //0x0014
+ u32 msr_err; //0x0018
+ u32 dwc_ctrl3; //0x001C
+
+ u32 dwc_ctrl4; //0x0020
+ u32 reserved1; //0x0024
+ u32 otg_status; //0x0028
+ u32 dwc_ctrl5; //0x002C
+
+ u32 dwc_ctrl6; //0x0030
+ u32 dwc_ctrl7; //0x0034
+
+ u32 reserved2[(0xC0-0x38)/4]; // 0x0038 -- 0x00C0
+
+ u32 phy_status; //0x00C0
+ u32 intr_status; //0x00C4
+ u32 intr_enable; //0x00C8
+
+} AU13XX_USB;
+#endif // ASSEMBLER
+
+#define USB_DWC_CTRL1_OTGD (1<<2)
+#define USB_DWC_CTRL1_HSTRS (1<<1)
+#define USB_DWC_CTRL1_DCRS (1<<0)
+
+#define USB_DWC_CTRL2_HTBSE1 (1<<11)
+#define USB_DWC_CTRL2_HTBSE0 (1<<10)
+#define USB_DWC_CTRL2_LTBSE1 (1<<9)
+#define USB_DWC_CTRL2_LTBSE0 (1<<8)
+#define USB_DWC_CTRL2_LPBKE1 (1<<5)
+#define USB_DWC_CTRL2_LPBKE0 (1<<4)
+#define USB_DWC_CTRL2_VBUSD (1<<3)
+#define USB_DWC_CTRL2_PH1RS (1<<2)
+#define USB_DWC_CTRL2_PHY0RS (1<<1)
+#define USB_DWC_CTRL2_PHYRS (1<<0)
+
+#define USB_VBUS_TIMER(n) (n)
+
+#define USB_SBUS_CTRL_SBCA (1<<2)
+#define USB_SBUS_CTRL_HWSZ (1<<1)
+#define USB_SBUS_CTRL_BSZ (1<<0)
+
+#define USB_MSR_ERR_ILLBM (1<<18)
+#define USB_MSR_ERR_ILLBRST (1<<17)
+#define USB_MSR_ERR_UADDRSTS (1<<16)
+#define USB_MSR_ERR_BMMSK (1<<2)
+#define USB_MSR_ERR_BRSTMSK (1<<1)
+#define USB_MSR_ERR_UADMK (1<<0)
+
+#define USB_DWC_CTRL3_VATEST_EN (1<<20)
+#define USB_DWC_CTRL3_OHC1_CLKEN (1<<19)
+#define USB_DWC_CTRL3_OHC0_CLKEN (1<<18)
+#define USB_DWC_CTRL3_EHC_CLKEN (1<<17)
+#define USB_DWC_CTRL3_OTG_CLKEN (1<<16)
+#define USB_DWC_CTRL3_OHCI_SUSP (1<<3)
+#define USB_DWC_CTRL3_VBUS_VALID_PORT1 (1<<2)
+#define USB_DWC_CTRL3_VBUS_VALID_PORT0 (1<<1)
+#define USB_DWC_CTRL3_VBUS_VALID_SEL (1<<0)
+
+#define USB_DWC_CTRL4_USB_MODE (1<<16)
+#define USB_DWC_CTRL4_AHB_CLKDIV(n) ((n&0xF)<<0)
+
+#define USB_OTG_STATUS_IDPULLUP (1<<8)
+#define USB_OTG_STATUS_IDDIG (1<<7)
+#define USB_OTG_STATUS_DISCHRGVBUS (1<<6)
+#define USB_OTG_STATUS_CHRGVBUS (1<<5)
+#define USB_OTG_STATUS_DRVVBUS (1<<4)
+#define USB_OTG_STATUS_SESSIONEND (1<<3)
+#define USB_OTG_STATUS_VBUSVALID (1<<2)
+#define USB_OTG_STATUS_BVALID (1<<1)
+#define USB_OTG_STATUS_AVALID (1<<0)
+
+#define USB_DWC_CTRL5_REFCLK_DIV(n) ((n&3)<<18)
+#define USB_DWC_CTRL5_REFCLK_EN(n) ((n&3)<<16)
+#define USB_DWC_CTRL5_SIDDQ (1<<1)
+#define USB_DWC_CTRL5_COMMONONN (1<<0)
+
+#define USB_DWC_CTRL6_DMPULLDOWN_PORT1 (1<<3)
+#define USB_DWC_CTRL6_DPPULLDOWN_PORT1 (1<<2)
+#define USB_DWC_CTRL6_DMPULLDOWN_PORT2 (1<<1)
+#define USB_DWC_CTRL6_DPPULLDOWN_PORT2 (1<<0)
+
+#define USB_DWC_CTRL7_OHC_STARTCLK (1<<0)
+
+#define USB_PHY_STATUS_VBUS (1<<0)
+
+// Bit defines used for status and enable registers
+#define USB_INTR_S2A (1<<6)
+#define USB_INTR_FORCE (1<<5)
+#define USB_INTR_PHY (1<<4)
+#define USB_INTR_DEVICE (1<<3)
+#define USB_INTR_EHCI (1<<2)
+#define USB_INTR_OHCI1 (1<<1)
+#define USB_INTR_OHCI0 (1<<0)
+
+
+#endif /* CONFIG_SOC_AU13XX */
+#endif /* _AU13XX_H */
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx.h b/arch/mips/include/asm/mach-au1x00/au1xxx.h
index 1b36550..9a6d9f1 100644
--- a/arch/mips/include/asm/mach-au1x00/au1xxx.h
+++ b/arch/mips/include/asm/mach-au1x00/au1xxx.h
@@ -38,6 +38,9 @@
#elif defined(CONFIG_MIPS_DB1200)
#include <asm/mach-db1x00/db1200.h>
+#elif defined(CONFIG_MIPS_DB1300)
+#include <asm/mips-boards/db1300.h>
+
#endif
#endif /* _AU1XXX_H_ */
diff --git a/arch/mips/include/asm/mach-au1x00/dev_boards.h b/arch/mips/include/asm/mach-au1x00/dev_boards.h
new file mode 100644
index 0000000..27bca17
--- /dev/null
+++ b/arch/mips/include/asm/mach-au1x00/dev_boards.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2003-2008 RMI Corporation. All rights reserved.
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _AU_DEV_BOARDS_H
+#define _AU_DEV_BOARDS_H
+
+#ifdef CONFIG_MIPS_DB1300
+#include <asm/mips-boards/db1300.h>
+#endif
+
+#ifdef CONFIG_MIPS_DB1200
+#include <asm/mach-db1x00/db1200.h>
+#endif
+
+void db_set_hex(u8 val);
+
+/*
+ * 2 dots use 2 bits
+ */
+void db_set_hex_dots(u8 val);
+
+#endif /* _AU_DEV_BOARDS_H */
diff --git a/arch/mips/include/asm/mips-boards/db1300.h b/arch/mips/include/asm/mips-boards/db1300.h
new file mode 100644
index 0000000..5d7ce9d
--- /dev/null
+++ b/arch/mips/include/asm/mips-boards/db1300.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2003-2008 RMI Corporation. All rights reserved.
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef ASM_DB1300_H
+#define ASM_DB1300_H
+#ifdef CONFIG_MIPS_DB1300
+#include <asm/mach-au1x00/au13xx.h> /* For KSEG1_OFFSET */
+
+struct db1300_hex_regs {
+ u16 hex; /* Write 8-bit value here */
+ u16 reserved;
+ u16 blank; /* Write 11b to blank */
+};
+
+
+#define DB1300_HEX_REGS_PHYS_ADDR 0x19C00000
+
+/* For alchemy/dev_boards/leds.c */
+typedef struct db1300_hex_regs hex_regs;
+#define HEX_REGS_KSEG1_ADDR DB1300_HEX_REGS_PHYS_ADDR + KSEG1_OFFSET
+
+struct bcsr_regs {
+ /*00*/ u16 whoami;
+ u16 reserved0;
+ /*04*/ u16 status;
+ u16 reserved1;
+ /*08*/ u16 switches;
+ u16 reserved2;
+ /*0C*/ u16 resets;
+ u16 reserved3;
+
+ /*10*/ u16 pcmcia;
+ u16 reserved4;
+ /*14*/ u16 board;
+ u16 reserved5;
+ /*18*/ u16 disk_leds;
+ u16 reserved6;
+ /*1C*/ u16 system;
+ u16 reserved7;
+
+ /*20*/ u16 intclr;
+ u16 reserved8;
+ /*24*/ u16 intset;
+ u16 reserved9;
+ /*28*/ u16 intclr_mask;
+ u16 reserved10;
+ /*2C*/ u16 intset_mask;
+ u16 reserved11;
+
+ /*30*/ u16 sig_status;
+ u16 reserved12;
+ /*34*/ u16 int_status;
+ u16 reserved13;
+ /*38*/ u16 reserved14;
+ u16 reserved15;
+ /*3C*/ u16 reserved16;
+ u16 reserved17;
+};
+
+#define DB1300_BCSR_REGS_PHYS_ADDR 0x19800000
+#define BCSR_REGS_KSEG1_ADDR (KSEG1_OFFSET + DB1300_BCSR_REGS_PHYS_ADDR)
+
+static volatile struct bcsr_regs *const db_bcsr =
+ (struct bcsr_regs *)(DB1300_BCSR_REGS_PHYS_ADDR + KSEG1_OFFSET);
+
+#define BCSR_STATUS_SD1_WP (1<<10)
+#define BCSR_INT_SD1_INSERT (1<<12)
+
+#define BCSR_RESETS_USB_OTG 0x4000
+#define BCSR_RESETS_USB_HOST 0x8000
+
+#define CASCADE_IRQ_MIN 129
+
+enum db1300_cascade_irqs {
+ DB1300_IDE_IRQ = CASCADE_IRQ_MIN,
+ DB1300_ETHERNET_IRQ,
+ DB1300_AC97_IRQ,
+ DB1300_AC97_PEN_IRQ,
+};
+
+#define CASCADE_IRQ_MAX DB1300_AC97_PEN_IRQ
+
+#define CASCADE_IRQ (5 + GPINT_LINUX_IRQ_OFFSET)
+#define CASCADE_IRQ_TYPE_STRING "DB1300 Cascade"
+
+/*
+ * Defines for au1xxx-ide
+ * See the CPLD/BCSR datasheet for details
+ */
+#define IDE_PHYS_ADDR 0x18800000
+#define IDE_REG_SHIFT 5
+#define IDE_INT DB1300_IDE_IRQ
+#define IDE_DDMA_REQ DSCR_CMD0_DMA_REQ1
+#define IDE_RQSIZE 128
+#define IDE_PHYS_LEN (16 << IDE_REG_SHIFT)
+
+
+#endif /* CONFIG_MIPS_DB1300 */
+#endif /* ASM_DB1300_H */
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index a7162a4..03e0ae7 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -189,6 +189,7 @@ void __init check_wait(void)
case CPU_AU1200:
case CPU_AU1210:
case CPU_AU1250:
+ case CPU_AU13XX:
cpu_wait = au1k_wait;
break;
case CPU_20KC:
@@ -819,6 +820,20 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
}
}
+static inline void cpu_probe_rmi(struct cpuinfo_mips *c, unsigned int cpu)
+{
+ decode_configs(c);
+ switch(c->processor_id & 0xff00) {
+ case PRID_IMP_AU13XX:
+ c->cputype = CPU_AU13XX;
+ __cpu_name[cpu] = "Au13xx";
+ break;
+ default:
+ panic("Unknown RMI Core!\n");
+ break;
+ }
+}
+
static inline void cpu_probe_sibyte(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
@@ -936,6 +951,11 @@ __cpuinit void cpu_probe(void)
case PRID_COMP_CAVIUM:
cpu_probe_cavium(c, cpu);
break;
+ case PRID_COMP_RMI:
+ cpu_probe_rmi(c, cpu);
+ break;
+ default:
+ c->cputype = CPU_UNKNOWN;
}
BUG_ON(!__cpu_name[cpu]);
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index c43f4b2..2b4736a 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1033,6 +1033,7 @@ static void __cpuinit probe_pcache(void)
case CPU_AU1200:
case CPU_AU1210:
case CPU_AU1250:
+ case CPU_AU13XX:
c->icache.flags |= MIPS_CACHE_IC_F_DC;
break;
}
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 4294203..ee5e2de 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -299,6 +299,7 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
case CPU_AU1200:
case CPU_AU1210:
case CPU_AU1250:
+ case CPU_AU13XX:
case CPU_PR4450:
uasm_i_nop(p);
tlbw(p);
--
1.5.4.3
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH 02/10] Alchemy: Au1300 new interrupt controller
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
@ 2009-03-06 16:20 ` Kevin Hickey
2009-03-07 9:49 ` Manuel Lauss
2009-03-06 16:20 ` [PATCH 03/10] Alchemy: Au1300/DB1300 UART support Kevin Hickey
` (8 subsequent siblings)
9 siblings, 1 reply; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:20 UTC (permalink / raw)
To: ralf, linux-mips; +Cc: Kevin Hickey
The Au1300 has a new interrupt controller (relative to the rest of the Alchemy
line). The differences were great enough to justify adding a whole new module.
Included in this patch is the new interrupt controller, a new implementation of
the cascade interrupt controller on the DB1300 board and some code to drive
LEDs on the DB1300 that is used by the interrupt controller.
A small change was made to the existing interrupt controller; it is "ifdef'd
out" for Au1300.
Since the cascade interrupt controller is virtually indentical (with the
exception of some constants) between the DB1300 and DB1200, a future
optimization may be to use the same code for both boards.
Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
---
arch/mips/alchemy/Kconfig | 4 +
arch/mips/alchemy/common/Makefile | 4 +-
arch/mips/alchemy/common/gpio_int.c | 268 ++++++++++++++++++++++++++
arch/mips/alchemy/common/irq.c | 3 +
arch/mips/alchemy/devboards/Makefile | 5 +
arch/mips/alchemy/devboards/cascade_irq.c | 142 ++++++++++++++
arch/mips/alchemy/devboards/leds.c | 58 ++++++
arch/mips/include/asm/mach-au1x00/gpio_int.h | 239 +++++++++++++++++++++++
arch/mips/include/asm/mach-au1x00/irq.h | 34 ++++
9 files changed, 756 insertions(+), 1 deletions(-)
create mode 100644 arch/mips/alchemy/common/gpio_int.c
create mode 100644 arch/mips/alchemy/devboards/cascade_irq.c
create mode 100644 arch/mips/alchemy/devboards/leds.c
create mode 100644 arch/mips/include/asm/mach-au1x00/gpio_int.h
create mode 100644 arch/mips/include/asm/mach-au1x00/irq.h
diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig
index 7198a88..2e189c2 100644
--- a/arch/mips/alchemy/Kconfig
+++ b/arch/mips/alchemy/Kconfig
@@ -114,18 +114,22 @@ endchoice
config SOC_AU1000
bool
select SOC_AU1X00
+ select AU_INT_CNTLR
config SOC_AU1100
bool
select SOC_AU1X00
+ select AU_INT_CNTLR
config SOC_AU1500
bool
select SOC_AU1X00
+ select AU_INT_CNTLR
config SOC_AU1550
bool
select SOC_AU1X00
+ select AU_INT_CNTLR
config SOC_AU1200
bool
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
index d50d476..85ffa2e 100644
--- a/arch/mips/alchemy/common/Makefile
+++ b/arch/mips/alchemy/common/Makefile
@@ -7,7 +7,9 @@
obj-y += prom.o irq.o puts.o time.o reset.o \
clocks.o platform.o power.o setup.o \
- sleeper.o dma.o dbdma.o gpio.o
+ sleeper.o dma.o dbdma.o gpio.o gpio_int.o
+
+obj-$(CONFIG_SOC_AU13XX) += au13xx_res.o
obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/mips/alchemy/common/gpio_int.c b/arch/mips/alchemy/common/gpio_int.c
new file mode 100644
index 0000000..c09b793
--- /dev/null
+++ b/arch/mips/alchemy/common/gpio_int.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2008 RMI Corporation
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef CONFIG_AU_GPIO_INT_CNTLR
+
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/interrupt.h> /* For functions called by do_IRQ */
+#include <asm/irq_cpu.h>
+
+#include <asm/mach-au1x00/gpio_int.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#include <dev_boards.h>
+
+volatile struct gpio_int_regs *const gpio_int =
+ (struct gpio_int_regs *)(GPIO_INT_CTRLR_BASE + KSEG1_OFFSET);
+
+static struct gpio_int_cfg __initdata basic_irqs[];
+
+#ifdef CONFIG_SOC_AU13XX
+static struct gpio_int_cfg __initdata basic_irqs[] = {
+ { AU1300_IRQ_DDMA, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+
+ { AU1300_IRQ_RTC_TICK, 1, RISING, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_TOY_TICK, 1, RISING, HW_INT_1, DEV_CTRL },
+
+ { AU1300_IRQ_LCD, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+
+ { AU1300_IRQ_UART1, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_UART1, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_UART2, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_UART3, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+
+ { AU1300_IRQ_SD1, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_SD2, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+
+ { AU1300_IRQ_USB, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+
+ { AU1300_IRQ_BSA, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_MPE, 1, RISING, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_ITE, 1, LEVEL_HIGH, HW_INT_1, DEV_CTRL },
+
+ { AU1300_IRQ_RTCMATCH_1, 1, RISING, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_RTCMATCH_1, 1, RISING, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_RTCMATCH_2, 0, RISING, HW_INT_0, DEV_CTRL },
+
+ { AU1300_IRQ_TOYMATCH_1, 1, RISING, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_TOYMATCH_1, 1, RISING, HW_INT_1, DEV_CTRL },
+ { AU1300_IRQ_TOYMATCH_2, 1, RISING, HW_INT_1, DEV_CTRL },
+
+
+ // KH: TODO - Move this to the board file.
+ { 5, 0, LEVEL_HIGH, HW_INT_0, GPIO_IN },
+};
+
+/*
+ * KH: TODO - Consider moving to board specific location...
+ */
+static struct gpio_int_cfg __initdata basic_gpios[] = {
+ { 32, 0, DISABLED, HW_INT_0, DEV_CTRL },
+ { 33, 0, DISABLED, HW_INT_0, DEV_CTRL },
+ { 34, 0, DISABLED, HW_INT_0, DEV_CTRL },
+ { 35, 0, DISABLED, HW_INT_0, DEV_CTRL },
+ { 36, 0, DISABLED, HW_INT_0, DEV_CTRL },
+ { 37, 0, DISABLED, HW_INT_0, DEV_CTRL },
+};
+#endif
+
+int __initdata nr_basic_irqs = ARRAY_SIZE(basic_irqs);
+
+/*
+ ****************************************************************************
+ * Functions and delcaration for irq_chip
+ ****************************************************************************
+ */
+void gpio_int_ack(unsigned int irq)
+{
+ u32 intr = irq - GPINT_LINUX_IRQ_OFFSET;
+ u32 bank = GPINT_BANK_FROM_INT(intr);
+ u32 bit = GPINT_BIT_FROM_INT(bank, intr);
+
+ au_iowrite32(bit, &gpio_int->int_pend[bank]);
+}
+
+void gpio_int_mask(unsigned int irq)
+{
+ u32 intr = irq - GPINT_LINUX_IRQ_OFFSET;
+ u32 bank = GPINT_BANK_FROM_INT(intr);
+ u32 bit = GPINT_BIT_FROM_INT(bank, intr);
+
+ au_iowrite32(bit, &gpio_int->int_maskclr[bank]);
+}
+
+void gpio_int_unmask(unsigned int irq)
+{
+ u32 intr = irq - GPINT_LINUX_IRQ_OFFSET;
+ u32 bank = GPINT_BANK_FROM_INT(intr);
+ u32 bit = GPINT_BIT_FROM_INT(bank, intr);
+
+ au_iowrite32(bit, &gpio_int->int_mask[bank]);
+}
+
+void gpio_int_mask_ack(unsigned int irq)
+{
+ u32 intr = irq - GPINT_LINUX_IRQ_OFFSET;
+ u32 bank = GPINT_BANK_FROM_INT(intr);
+ u32 bit = GPINT_BIT_FROM_INT(bank, intr);
+
+ au_iowrite32(bit, &gpio_int->int_maskclr[bank]);
+ au_iowrite32(bit, &gpio_int->int_pend[bank]);
+}
+
+static struct irq_chip gpio_int_irq_type = {
+ .name = "Au GPIO/INT",
+ .ack = gpio_int_ack,
+ .mask = gpio_int_mask,
+ .unmask = gpio_int_unmask,
+ .mask_ack = gpio_int_mask_ack
+};
+/*****************************************************************************/
+
+void set_pin_cfg(const struct gpio_int_cfg *cfg)
+{
+ u32 tmp;
+ tmp = GPINT_PINCTL_N(cfg->pinctl);
+ tmp |= GPINT_INTLINE_N(cfg->intline);
+ tmp |= GPINT_INTCFG_N(cfg->intcfg);
+ tmp |= cfg->intwake ? GPINT_INTWAKE_ENABLE : 0;
+ au_iowrite32(tmp, &gpio_int->gp_int[cfg->number]);
+}
+
+void set_gpio(u8 gpio, u8 value)
+{
+ u32 bank = GPINT_BANK_FROM_GPIO(gpio);
+ u32 bit = GPINT_BIT_FROM_GPIO(bank, gpio);
+
+ if (value == 0)
+ au_iowrite32(1 << bit, &gpio_int->pin_valclr[bank]);
+ else
+ au_iowrite32(1 << bit, &gpio_int->pin_val[bank]);
+}
+
+u8 get_gpio(u8 gpio)
+{
+ u32 bank = GPINT_BANK_FROM_GPIO(gpio);
+ u32 bit = GPINT_BIT_FROM_GPIO(bank, gpio);
+ u32 tmp;
+
+ tmp = au_ioread32(&gpio_int->pin_val[bank]);
+ return tmp >> bit;
+}
+
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ /*
+ * Initialize the basic MIPS interrupt components.
+ */
+ mips_cpu_irq_init();
+
+ for (i = 0; i < GPINT_NUM_BANKS; ++i)
+ gpio_int->int_maskclr[i] = ~0UL;
+
+
+ for (i = 0; i < ARRAY_SIZE(basic_gpios); ++i) {
+ set_pin_cfg(&basic_gpios[i]);
+ }
+
+ for (i = 0; i < nr_basic_irqs; ++i) {
+ printk("Initializing IRQ %d\n", basic_irqs[i].number);
+ set_pin_cfg(&basic_irqs[i]);
+ if (basic_irqs[i].intcfg == LEVEL_LOW)
+ set_irq_chip_and_handler_name(
+ basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET,
+ &gpio_int_irq_type,
+ handle_level_irq,
+ "lowlevel");
+ else if (basic_irqs[i].intcfg == LEVEL_HIGH)
+ set_irq_chip_and_handler_name(
+ basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET,
+ &gpio_int_irq_type,
+ handle_level_irq,
+ "highlevel");
+ else if (basic_irqs[i].intcfg == FALLING)
+ set_irq_chip_and_handler_name(
+ basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET,
+ &gpio_int_irq_type,
+ handle_edge_irq,
+ "fallingedge");
+ else if (basic_irqs[i].intcfg == RISING)
+ set_irq_chip_and_handler_name(
+ basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET,
+ &gpio_int_irq_type,
+ handle_edge_irq,
+ "risingedge");
+ else if (basic_irqs[i].intcfg == ANY_CHANGE)
+ set_irq_chip_and_handler_name(
+ basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET,
+ &gpio_int_irq_type,
+ handle_edge_irq,
+ "bothedge");
+ else
+ set_irq_chip(
+ basic_irqs[i].number + GPINT_LINUX_IRQ_OFFSET,
+ &gpio_int_irq_type);
+ }
+
+ set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
+
+ board_init_irq();
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ unsigned int intr;
+ u32 bank;
+ u32 reg_msk;
+ unsigned int pending = read_c0_status() & read_c0_cause();
+ /*
+ * C0 timer tick
+ */
+ if (pending & CAUSEF_IP7)
+ do_IRQ(MIPS_CPU_IRQ_BASE + 7);
+ else if (pending & (CAUSEF_IP2 | CAUSEF_IP3)) {
+ intr = au_ioread32(&gpio_int->pri_enc);
+ bank = GPINT_BANK_FROM_INT(intr);
+ reg_msk = GPINT_BIT_FROM_INT(bank, intr);
+
+ if (intr != 127) {
+ if (pending & CAUSEF_IP3)
+ board_irq_dispatch(intr);
+
+ do_IRQ(GPINT_LINUX_IRQ_OFFSET + intr);
+ }
+ } else {
+ printk(KERN_WARNING
+ "ALCHEMY GPIO_INT: Unexpected cause was set. %08x\n",
+ pending);
+ }
+
+}
+
+#endif
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index c88c821..f8742dd 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -24,6 +24,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#ifdef CONFIG_AU_INT_CNTLR
#include <linux/bitops.h>
#include <linux/init.h>
@@ -609,3 +610,5 @@ void __init arch_init_irq(void)
set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
}
+
+#endif
diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index 0d2d224..8cce4d0 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -17,3 +17,8 @@ obj-$(CONFIG_MIPS_DB1500) += db1x00/
obj-$(CONFIG_MIPS_DB1550) += db1x00/
obj-$(CONFIG_MIPS_BOSPORUS) += db1x00/
obj-$(CONFIG_MIPS_MIRAGE) += db1x00/
+
+# These two files are used only by DB1300 today but will be used by DB1200 and
+# possibly others in the future.
+obj-$(CONFIG_MIPS_DB1300) += cascade_irq.o
+obj-$(CONFIG_MIPS_DB1300) += leds.o
diff --git a/arch/mips/alchemy/devboards/cascade_irq.c b/arch/mips/alchemy/devboards/cascade_irq.c
new file mode 100644
index 0000000..6d0a965
--- /dev/null
+++ b/arch/mips/alchemy/devboards/cascade_irq.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2003-2008 RMI Corporation. All rights reserved.
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/semaphore.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mips-boards/db1300.h>
+
+#include <asm/mach-au1x00/dev_boards.h>
+
+/*
+ * The following must be declared/defined in an included file:
+ * - volatile struct bcsr_regs (declared)
+ * (which much include fields int_status, intset_mask, intclr_mask, intset,
+ * and intclr)
+ * - volatile struct bcsr_regs *const bcsr (defined)
+ * - CASCADE_IRQ_MIN
+ * - CASCADE_IRQ_MAX
+ * - CASCADE_IRQ_TYPE_STRING
+ * - CASCADE_IRQ (System IRQ to which the cascade is connected)
+ */
+
+void __init board_init_irq(void);
+
+irqreturn_t cascade_handler(int irq, void *dev_id)
+{
+ u16 int_status = au_ioread16(&db_bcsr->int_status);
+ int irq_in_service;
+
+ au_iowrite16(int_status, &db_bcsr->int_status);
+ for ( ; int_status; int_status &= int_status - 1) {
+ irq_in_service = CASCADE_IRQ_MIN + __ffs(int_status);
+ db_set_hex((u8)(irq_in_service));
+ do_IRQ(irq_in_service);
+ }
+
+ return IRQ_RETVAL(1);
+}
+
+DEFINE_MUTEX(cascade_use_count_mutex);
+static int cascade_use_count = 0;
+
+static void cascade_mask(unsigned int irq)
+{
+ au_iowrite16(1 << (irq - CASCADE_IRQ_MIN), &db_bcsr->intclr_mask);
+}
+
+static void cascade_unmask(unsigned int irq)
+{
+ au_iowrite16(1 << (irq - CASCADE_IRQ_MIN), &db_bcsr->intset_mask);
+}
+
+static void cascade_enable(unsigned int irq)
+{
+ au_iowrite16(1 << (irq - CASCADE_IRQ_MIN), &db_bcsr->intset);
+ cascade_unmask(irq);
+}
+
+static void cascade_disable(unsigned int irq)
+{
+ au_iowrite16(1 << (irq - CASCADE_IRQ_MIN), &db_bcsr->intclr);
+ cascade_mask(irq);
+}
+
+
+static unsigned int cascade_startup(unsigned int irq)
+{
+ int retval = 0;
+
+ mutex_lock(&cascade_use_count_mutex);
+ ++cascade_use_count;
+ if (cascade_use_count == 1)
+ retval = request_irq(CASCADE_IRQ,
+ &cascade_handler, 0, "Cascade",
+ &cascade_handler);
+ mutex_unlock(&cascade_use_count_mutex);
+
+ cascade_enable(irq);
+ cascade_unmask(irq);
+
+ return retval;
+}
+
+static void cascade_shutdown(unsigned int irq)
+{
+ cascade_mask(irq);
+ cascade_disable(irq);
+
+ mutex_lock(&cascade_use_count_mutex);
+ --cascade_use_count;
+ if (cascade_use_count == 0)
+ free_irq(CASCADE_IRQ, &cascade_handler);
+ mutex_unlock(&cascade_use_count_mutex);
+}
+
+static struct irq_chip cascade_irq_type = {
+ .name = CASCADE_IRQ_TYPE_STRING,
+ .startup = cascade_startup,
+ .shutdown = cascade_shutdown,
+ .mask = cascade_mask,
+ .enable = cascade_enable,
+ .disable = cascade_disable,
+ .unmask = cascade_unmask,
+ .mask_ack = cascade_mask
+};
+
+void __init board_init_irq(void)
+{
+ int irq;
+
+ for (irq = CASCADE_IRQ_MIN;
+ irq < CASCADE_IRQ_MAX; ++irq ) {
+ printk("Initializing IRQ %d\n", irq);
+ set_irq_chip_and_handler(irq, &cascade_irq_type,
+ handle_level_irq);
+ cascade_disable(irq);
+ }
+}
diff --git a/arch/mips/alchemy/devboards/leds.c b/arch/mips/alchemy/devboards/leds.c
new file mode 100644
index 0000000..75be345
--- /dev/null
+++ b/arch/mips/alchemy/devboards/leds.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2003-2008 RMI Corporation. All rights reserved.
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/dev_boards.h>
+
+/*
+ * Requires the following to be defined in the board-specifc .h file:
+ * - HEX_REGS_KSEG1_ADDR
+ * - struct hex_regs with members:
+ * - hex (set the hex value)
+ * - BCSR_REGS_KSEG1_ADDR
+ * - struct bcsr_regs
+ */
+
+static volatile hex_regs *const hex = (hex_regs *)(HEX_REGS_KSEG1_ADDR);
+
+/*
+ * Takes a u8 because though the register is 16 bits, only 8 appear
+ */
+void db_set_hex(u8 val)
+{
+ au_iowrite16((u16)val, &hex->hex);
+}
+
+/*
+ * 2 dots use the least significant 2 bits
+ * Setting a bit lights the LED (opposite of the register)
+ */
+void db_set_hex_dots(u8 val)
+{
+ u16 leds = au_ioread16(&db_bcsr->disk_leds);
+ leds |= 0x3;
+ leds &= (~(val & 0x3));
+ au_iowrite16(leds, &db_bcsr->disk_leds);
+}
diff --git a/arch/mips/include/asm/mach-au1x00/gpio_int.h b/arch/mips/include/asm/mach-au1x00/gpio_int.h
new file mode 100644
index 0000000..85df296
--- /dev/null
+++ b/arch/mips/include/asm/mach-au1x00/gpio_int.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2008 RMI Corporation
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * Defines and macros for the GPIO and Interrupt controller for Alchemy,
+ * introduced in the Au13xx series.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _GPIO_INT_H
+#define _GPIO_INT_H
+
+#include <linux/types.h>
+
+/*
+ * There are a total 128 'channels' defined by the Au13xx databook. However,
+ * this requires 4 sperate 32bit registers for programming. Each register is
+ * called a 'bank' for ease of use.
+ */
+#define GPINT_BANK0 0
+#define GPINT_BANK1 1
+#define GPINT_BANK2 2
+#define GPINT_BANK3 3
+
+#define GPINT_NUM_BANKS 4 /* 0-3 */
+#define GPINT_MAX_BANK (GPINT_BANK3)
+
+#define GPINT_GPIO_PER_BANK 32
+#define GPINT_INTS_PER_BANK GPINT_GPIO_PER_BANK
+
+/* Total number of interrupts our architecture allows */
+#define GPINT_MAX_INTS (GPINT_NUM_BANKS*GPINT_INTS_PER_BANK)
+
+/* Current maximum supported GPIO/INTERRUPTs */
+#define GPINT_NUM_GPIO GPINT_MAX_INTS
+#define GPINT_NUM_INTERRUPTS GPINT_MAX_INTS
+
+/* Starting GPIO/INTERRUPT for each bank */
+#define GPINT_BANK0_START 0
+#define GPINT_BANK1_START 32
+#define GPINT_BANK2_START 64
+#define GPINT_BANK3_START 96
+
+/* divide by 32 to get bank */
+#define GPINT_BANK_FROM_GPIO(n) (n>>5)
+#define GPINT_BANK_FROM_INT(n) GPINT_BANK_FROM_GPIO(n)
+/* multiply by 32 to get base */
+#define GPINT_BIT_FROM_GPIO(b, n) (1<<(n-(b<<5)))
+#define GPINT_BIT_FROM_INT(b, n) GPINT_BIT_FROM_GPIO(b, n)
+
+struct gpio_int_regs {
+ /* R/W1S */
+ /* u32 pin_val0; 0x00 */
+ /* u32 pin_val1; 0x04 */
+ /* u32 pin_val2; 0x08 */
+ /* u32 pin_val3; 0x0C */
+ u32 pin_val[GPINT_NUM_BANKS];
+
+ /* W1C */
+ /* u32 pin_valclr0 0x10 */
+ /* u32 pin_valclr1; 0x14 */
+ /* u32 pin_valclr2; 0x18 */
+ /* u32 pin_valclr3; 0x1C */
+ u32 pin_valclr[GPINT_NUM_BANKS];
+
+ /* R/W1C */
+ /* u32 int_pend0; 0x20 */
+ /* u32 int_pend1; 0x24 */
+ /* u32 int_pend2; 0x28 */
+ /* u32 int_pend3; 0x2c */
+ u32 int_pend[GPINT_NUM_BANKS];
+
+ u32 pri_enc; /* 0x30 */
+ u32 _resvd0[3]; /* 0x34-0x3c */
+
+ /* R/W1S */
+ /* u32 int_mask0; 0x40 */
+ /* u32 int_mask1; 0x44 */
+ /* u32 int_mask2; 0x48 */
+ /* u32 int_mask3; 0x4c */
+ u32 int_mask[GPINT_NUM_BANKS];
+
+ /* W1C */
+ /* u32 int_maskclr0; 0x50 */
+ /* u32 int_maskclr1; 0x54 */
+ /* u32 int_maskclr2; 0x58 */
+ /* u32 int_maskclr3; 0x5C */
+ u32 int_maskclr[GPINT_NUM_BANKS];
+
+ /* R/W */
+ u32 dma_sel; /* 0x60 */
+ u32 _resvd1[(0x80-0x64)/4]; /* 0x64-0x7C */
+
+ /* W */
+ /* u32 dev_sel0; 0x80 */
+ /* u32 dev_sel1; 0x84 */
+ /* u32 dev_sel2; 0x88 */
+ /* u32 dev_sel3; 0x8C */
+ u32 dev_sel[GPINT_NUM_BANKS];
+
+ /* W */
+ /* u32 dev_selclr0; 0x90 */
+ /* u32 dev_selclr1; 0x94 */
+ /* u32 dev_selclr2; 0x98 */
+ /* u32 dev_selclr3; 0x9C */
+ u32 dev_selclr[GPINT_NUM_BANKS];
+
+ /* R */
+ /* u32 reset_val0; 0xA0 */
+ /* u32 reset_val1; 0xA4 */
+ /* u32 reset_val2; 0xA8 */
+ /* u32 reset_val3; 0xAC */
+ u32 reset_val[GPINT_NUM_BANKS];
+
+ /* 0xB0 - 0xFFC */
+ u32 _resvd2[(0x1000-0xB0)/4];
+
+ /* R/W -- when interrupt mask is clear */
+ /* R -- when interrupt mask is set */
+ /* u32 gp_int0; 0x1000 */
+ /* u32 gp_int1; 0x1004 */
+ /* u32 gp_int2; 0x1008 */
+ /* u32 gp_int2; 0x100C */
+ /* u32 gp_intN; 0x1000 + (N*4) */
+ u32 gp_int[GPINT_MAX_INTS];
+};
+
+extern volatile struct gpio_int_regs *const gpio_int;
+
+#define GPINT_DMASEL_DMA0 (0)
+#define GPINT_DMASEL_DMA0_N(n) (((n)&0xFF)<<GPINT_DMASEL_DMA0)
+#define GPINT_DMASEL_DMA1 (8)
+#define GPINT_DMASEL_DMA1_N(n) (((n)&0xFF)<<GPINT_DMASEL_DMA1)
+
+#define GPINT_PINCTL (0)
+#define GPINT_PINCTL_N(n) (((n)&0x3)<<GPINT_PINCTL)
+#define GPINT_PINCTL_GPIOINPUT GPINT_PINCTL_N(0)
+#define GPINT_PINCTL_INTERRUPT GPINT_PINCTL_N(1)
+#define GPINT_PINCTL_GPIOOUT_0 GPINT_PINCTL_N(2)
+#define GPINT_PINCTL_GPIOOUT_1 GPINT_PINCTL_N(3)
+
+#define GPINT_INTLINE (2)
+#define GPINT_INTLINE_N(n) (((n)&0x3)<<GPINT_INTLINE)
+#define GPINT_INTLINE_CPUINT_0 GPINT_INTLINE_N(0)
+#define GPINT_INTLINE_CPUINT_1 GPINT_INTLINE_N(1)
+#define GPINT_INTLINE_CPUINT_2 GPINT_INTLINE_N(2)
+#define GPINT_INTLINE_CPUINT_3 GPINT_INTLINE_N(3)
+
+#define GPINT_INTCFG (4)
+#define GPINT_INTCFG_N(n) (((n)&0x7)<<GPINT_INTCFG)
+#define GPINT_INTCFG_DISABLE GPINT_INTCFG_N(0)
+#define GPINT_INTCFG_LL GPINT_INTCFG_N(1)
+#define GPINT_INTCFG_HL GPINT_INTCFG_N(2)
+#define GPINT_INTCFG_FE GPINT_INTCFG_N(5)
+#define GPINT_INTCFG_RE GPINT_INTCFG_N(6)
+#define GPINT_INTCFG_CHANGE GPINT_INTCFG_N(7)
+
+#define GPINT_INTWAKE (7)
+#define GPINT_INTWAKE_ENABLE ((1)<<GPINT_INTWAKE)
+
+/* GPIO */
+#define GPIO_N(N) (1 << (N))
+
+/*
+ * Take caution when reordering or changing values; used directly in pin
+ * configuration register
+ */
+enum intcfg_vals { DISABLED = 0, LEVEL_LOW, LEVEL_HIGH,
+ FALLING = 5, RISING, ANY_CHANGE };
+enum intline_vals { HW_INT_0 = 0, HW_INT_1, HW_INT_2, HW_INT_3 };
+enum pinctl_vals { GPIO_IN = 0, DEV_CTRL, GPIO_OUT_0, GPIO_OUT_1 };
+
+/*
+ * Defines the settings for a given interrupt "channel"
+ */
+struct gpio_int_cfg {
+ int number;
+ bool intwake;
+ enum intcfg_vals intcfg;
+ enum intline_vals intline;
+ enum pinctl_vals pinctl;
+};
+
+/*
+ * Linux uses IRQ 0-7 for the 8 causes. That means that all of our channel
+ * bits need to be offset by 8 either when passed to do_IRQ or when received
+ * through the irq_chip calls
+ */
+#define GPINT_LINUX_IRQ_OFFSET 8
+
+void board_irq_dispatch(unsigned int irq);
+
+/*
+ * Configure a GPIO/Interrupt pin. Many of the defined interrupt pins as
+ * decribed in the Au1300 data book are configured during platform
+ * initialization, however drivers may wish to repurpose those or other GPIO
+ * pins later.
+ *
+ * Changing the behavior of an interrupt pin after a handler has been
+ * installed is ill advised and should be avoided.
+ */
+void set_pin_cfg(const struct gpio_int_cfg *cfg);
+
+/*
+ * Set the GPIO to the specified value. The value must be 0 or 1. Any other
+ * value results in a no-op.
+ *
+ * This call will implicitly reconfigure the pin to be a GPIO if it is
+ * configured as a device pin.
+ */
+void set_gpio(u8 gpio, u8 value);
+
+/*
+ * Get the value of any GPIO pin (including those controlled by devices).
+ *
+ * This will not change the pin configuration
+ */
+u8 get_gpio(u8 gpio);
+
+#endif /* _GPIO_INT_H */
+
diff --git a/arch/mips/include/asm/mach-au1x00/irq.h b/arch/mips/include/asm/mach-au1x00/irq.h
new file mode 100644
index 0000000..91d06a5
--- /dev/null
+++ b/arch/mips/include/asm/mach-au1x00/irq.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008 RMI Corporation
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * Defines and macros for the GPIO and Interrupt controller for Alchemy,
+ * introduced in the Au13xx series.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _MACH_AU1X00_INT_H
+#define _MACH_AU1X00_INT_H
+
+#define NR_IRQS 255
+#define MIPS_CPU_IRQ_BASE 0
+
+#endif /* _MACH_AU1X00_INT_H */
--
1.5.4.3
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH 03/10] Alchemy: Au1300/DB1300 UART support
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
2009-03-06 16:20 ` [PATCH 02/10] Alchemy: Au1300 new interrupt controller Kevin Hickey
@ 2009-03-06 16:20 ` Kevin Hickey
2009-03-06 16:20 ` [PATCH 04/10] Alchemy: Au1300/DB1300 peripheral resource declarations Kevin Hickey
` (7 subsequent siblings)
9 siblings, 0 replies; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:20 UTC (permalink / raw)
To: ralf, linux-mips; +Cc: Kevin Hickey
Adds support for the UART on the Au1300 SOC and the DB1300 board. This
includes enabling EARLY_PRINTK for Alchemy.
Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
---
arch/mips/Kconfig | 1 +
arch/mips/alchemy/common/platform.c | 5 +++++
arch/mips/include/asm/mach-au1x00/au1000.h | 5 +++++
3 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index e61465a..b030770 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -21,6 +21,7 @@ choice
config MACH_ALCHEMY
bool "Alchemy processor based machines"
+ select SYS_HAS_EARLY_PRINTK
config BASLER_EXCITE
bool "Basler eXcite smart camera"
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index fd096d1..d53d3a0 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -52,6 +52,11 @@ static struct plat_serial8250_port au1x00_uart_data[] = {
#elif defined(CONFIG_SOC_AU1200)
PORT(UART0_ADDR, AU1200_UART0_INT),
PORT(UART1_ADDR, AU1200_UART1_INT),
+#elif defined(CONFIG_SOC_AU13XX)
+ PORT(UART2_ADDR, AU1300_IRQ_UART2 + GPINT_LINUX_IRQ_OFFSET),
+ PORT(UART0_ADDR, AU1300_IRQ_UART0 + GPINT_LINUX_IRQ_OFFSET),
+ PORT(UART1_ADDR, AU1300_IRQ_UART1 + GPINT_LINUX_IRQ_OFFSET),
+ PORT(UART3_ADDR, AU1300_IRQ_UART3 + GPINT_LINUX_IRQ_OFFSET),
#endif
#endif /* CONFIG_SERIAL_8250_AU1X00 */
{ },
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index ddebb84..debf896 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -1276,7 +1276,12 @@ enum soc_au1200_ints {
#define MAC_RX_BUFF3_ADDR 0x34
/* UARTS 0-3 */
+#ifdef CONFIG_SOC_AU13XX
+#define UART_BASE UART2_ADDR
+#else
#define UART_BASE UART0_ADDR
+#endif
+
#ifdef CONFIG_SOC_AU1200
#define UART_DEBUG_BASE UART1_ADDR
#else
--
1.5.4.3
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH 04/10] Alchemy: Au1300/DB1300 peripheral resource declarations
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
2009-03-06 16:20 ` [PATCH 02/10] Alchemy: Au1300 new interrupt controller Kevin Hickey
2009-03-06 16:20 ` [PATCH 03/10] Alchemy: Au1300/DB1300 UART support Kevin Hickey
@ 2009-03-06 16:20 ` Kevin Hickey
2009-03-06 16:20 ` [PATCH 05/10] Alchemy: Au1300/DB1300 MMC support Kevin Hickey
` (6 subsequent siblings)
9 siblings, 0 replies; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:20 UTC (permalink / raw)
To: ralf, linux-mips; +Cc: Kevin Hickey
This adds some declarations for peripheral resouces for the first few supported
peripherals. This includes USB, LCD, IDE and MMC.
Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
---
arch/mips/alchemy/common/au13xx_res.c | 104 ++++++++++++++++++++++
arch/mips/alchemy/common/dbdma.c | 46 +++++++++-
arch/mips/alchemy/common/platform.c | 69 ++++++++++++++-
arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h | 33 +++++++
4 files changed, 250 insertions(+), 2 deletions(-)
create mode 100644 arch/mips/alchemy/common/au13xx_res.c
diff --git a/arch/mips/alchemy/common/au13xx_res.c b/arch/mips/alchemy/common/au13xx_res.c
new file mode 100644
index 0000000..206c2f8
--- /dev/null
+++ b/arch/mips/alchemy/common/au13xx_res.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2003-2008 RMI Corporation. All rights reserved.
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+#ifdef CONFIG_SOC_AU13XX
+/*
+ * USB Resources for Au13xx
+ */
+static struct resource au13xx_usb_ehci_resources[] = {
+ [0] = {
+ .start = USB_EHCI_BASE,
+ .end = USB_EHCI_BASE + USB_EHCI_LEN - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AU1300_IRQ_USB + GPINT_LINUX_IRQ_OFFSET,
+ .end = AU1300_IRQ_USB + GPINT_LINUX_IRQ_OFFSET,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 ehci_dmamask = DMA_32BIT_MASK;
+
+static struct platform_device au13xx_usb_ehci_device = {
+ .name = "au13xx-ehci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ehci_dmamask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ },
+ .num_resources = ARRAY_SIZE(au13xx_usb_ehci_resources),
+ .resource = au13xx_usb_ehci_resources,
+};
+
+/* OHCI (USB full speed host controller) */
+static struct resource au13xx_usb_ohci_resources[] = {
+ [0] = {
+ .start = USB_OHCI_BASE,
+ .end = USB_OHCI_BASE + USB_OHCI_LEN - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AU1300_IRQ_USB + GPINT_LINUX_IRQ_OFFSET,
+ .end = AU1300_IRQ_USB + GPINT_LINUX_IRQ_OFFSET,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = DMA_32BIT_MASK;
+
+static struct platform_device au13xx_usb_ohci_device = {
+ .name = "au1xxx-ohci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ },
+ .num_resources = ARRAY_SIZE(au13xx_usb_ohci_resources),
+ .resource = au13xx_usb_ohci_resources,
+};
+
+
+static struct platform_device *au13xx_platform_devices[] __initdata = {
+ &au13xx_usb_ehci_device,
+ &au13xx_usb_ohci_device,
+};
+
+static int __init au13xx_add_devices(void)
+{
+ return platform_add_devices(au13xx_platform_devices,
+ ARRAY_SIZE(au13xx_platform_devices));
+}
+
+arch_initcall(au13xx_add_devices);
+
+#endif /* CONFIG_SOC_AU13XX */
diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c
index 3ab6d80..7fda56b 100644
--- a/arch/mips/alchemy/common/dbdma.c
+++ b/arch/mips/alchemy/common/dbdma.c
@@ -38,7 +38,8 @@
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) || \
+ defined(CONFIG_SOC_AU13XX)
/*
* The Descriptor Based DMA supports up to 16 channels.
@@ -150,6 +151,47 @@ static dbdev_tab_t dbdev_tab[] = {
#endif /* CONFIG_SOC_AU1200 */
+#ifdef CONFIG_SOC_AU13XX
+ { DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x10100004, 0, 0 },
+ { DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x10100000, 0, 0 },
+ { DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8, 0x01011004, 0, 0 },
+ { DSCR_CMD0_UART1_RX, DEV_FLAGS_IN, 0, 8, 0x10101000, 0, 0 },
+ { DSCR_CMD0_UART2_TX, DEV_FLAGS_OUT, 0, 8, 0x01012004, 0, 0 },
+ { DSCR_CMD0_UART2_RX, DEV_FLAGS_IN, 0, 8, 0x10102000, 0, 0 },
+ { DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8, 0x01013004, 0, 0 },
+ { DSCR_CMD0_UART3_RX, DEV_FLAGS_IN, 0, 8, 0x10103000, 0, 0 },
+
+ { DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 },
+ { DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 },
+ { DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 8, 8, 0x10601000, 0, 0 },
+ { DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 8, 8, 0x10601004, 0, 0 },
+
+ { DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 },
+ { DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 },
+
+ { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 16, 0x10a0001c, 0, 0 },
+ { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 16, 0x10a0001c, 0, 0 },
+ { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 16, 0x10a0101c, 0, 0 },
+ { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 16, 0x10a0101c, 0, 0 },
+ { DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT, 0, 16, 0x10a0201c, 0, 0 },
+ { DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN, 0, 16, 0x10a0201c, 0, 0 },
+ { DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT, 0, 16, 0x10a0301c, 0, 0 },
+ { DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN, 0, 16, 0x10a0301c, 0, 0 },
+
+ { DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+ { DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+
+ { DSCR_CMD0_SDMS_TX2, DEV_FLAGS_OUT, 4, 8, 0x10602000, 0, 0 },
+ { DSCR_CMD0_SDMS_RX2, DEV_FLAGS_IN, 4, 8, 0x10602004, 0, 0 },
+
+ { DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+ { DSCR_CMD0_UDMA, DEV_FLAGS_ANYUSE, 0, 32, 0x14001810, 0, 0 },
+
+ { DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 },
+ { DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 },
+#endif /* CONFIG_SOC_AU13XX */
+
{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
{ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
@@ -881,6 +923,8 @@ static void au1xxx_dbdma_init(void)
irq_nr = AU1550_DDMA_INT;
#elif defined(CONFIG_SOC_AU1200)
irq_nr = AU1200_DDMA_INT;
+#elif defined(CONFIG_SOC_AU13XX)
+ irq_nr = AU1300_IRQ_DDMA + GPINT_LINUX_IRQ_OFFSET;
#else
#error Unknown Au1x00 SOC
#endif
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index d53d3a0..d1b370d 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -338,14 +338,81 @@ static struct platform_device pbdb_smbus_device = {
};
#endif
+#ifdef CONFIG_SOC_AU13XX
+static struct resource au1200_lcd_resources[] = {
+ [0] = {
+ .start = LCD_PHYS_ADDR,
+ .end = LCD_PHYS_ADDR + 0x800 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AU1300_IRQ_LCD + 8,
+ .end = AU1300_IRQ_LCD + 8,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 au1200_lcd_dmamask = DMA_32BIT_MASK;
+
+static struct platform_device au1200_lcd_device = {
+ .name = "au1200-lcd",
+ .id = 0,
+ .dev = {
+ .dma_mask = &au1200_lcd_dmamask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ },
+ .num_resources = ARRAY_SIZE(au1200_lcd_resources),
+ .resource = au1200_lcd_resources,
+};
+
+extern struct platform_device au13xx_mmc0_device;
+extern struct platform_device au13xx_mmc1_device;
+
+
+extern struct au1xmmc_platform_data au1xmmc_platdata[2];
+static struct resource ide_resources[] = {
+ [0] = {
+ .start = IDE_PHYS_ADDR,
+ .end = IDE_PHYS_ADDR + IDE_PHYS_LEN - 1,
+ .flags = IORESOURCE_MEM
+ },
+ [1] = {
+ .start = IDE_INT,
+ .end = IDE_INT,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static u64 ide_dmamask = DMA_32BIT_MASK;
+
+static struct platform_device ide_device = {
+ .name = "au1200-ide",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ide_dmamask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ },
+ .num_resources = ARRAY_SIZE(ide_resources),
+ .resource = ide_resources
+};
+
+#endif
+
+
static struct platform_device *au1xxx_platform_devices[] __initdata = {
&au1xx0_uart_device,
- &au1xxx_usb_ohci_device,
+#ifdef CONFIG_SOC_AU13XX
+ &au1200_lcd_device,
+ &ide_device,
+ //&au13xx_mmc0_device,
+ &au13xx_mmc1_device,
+#endif
&au1x00_pcmcia_device,
#ifdef CONFIG_FB_AU1100
&au1100_lcd_device,
#endif
#ifdef CONFIG_SOC_AU1200
+ &au1xxx_usb_ohci_device,
&au1xxx_usb_ehci_device,
&au1xxx_usb_gdt_device,
&au1xxx_usb_otg_device,
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
index 06f68f4..1c36b9f 100644
--- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
+++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
@@ -195,6 +195,39 @@ typedef volatile struct au1xxx_ddma_desc {
#define DSCR_CMD0_CIM_SYNC 26
#endif /* CONFIG_SOC_AU1200 */
+#ifdef CONFIG_SOC_AU13XX
+#define DSCR_CMD0_UART0_TX 0
+#define DSCR_CMD0_UART0_RX 1
+#define DSCR_CMD0_UART1_TX 2
+#define DSCR_CMD0_UART1_RX 3
+#define DSCR_CMD0_UART2_TX 4
+#define DSCR_CMD0_UART2_RX 5
+#define DSCR_CMD0_UART3_TX 6
+#define DSCR_CMD0_UART3_RX 7
+#define DSCR_CMD0_SDMS_TX0 8
+#define DSCR_CMD0_SDMS_RX0 9
+#define DSCR_CMD0_SDMS_TX1 10
+#define DSCR_CMD0_SDMS_RX1 11
+#define DSCR_CMD0_AES_TX 12
+#define DSCR_CMD0_AES_RX 13
+#define DSCR_CMD0_PSC0_TX 14
+#define DSCR_CMD0_PSC0_RX 15
+#define DSCR_CMD0_PSC1_TX 16
+#define DSCR_CMD0_PSC1_RX 17
+#define DSCR_CMD0_PSC2_TX 18
+#define DSCR_CMD0_PSC2_RX 19
+#define DSCR_CMD0_PSC3_TX 20
+#define DSCR_CMD0_PSC3_RX 21
+#define DSCR_CMD0_LCD 22
+#define DSCR_CMD0_NAND_FLASH 23
+#define DSCR_CMD0_SDMS_TX2 24
+#define DSCR_CMD0_SDMS_RX2 25
+#define DSCR_CMD0_CIM_SYNC 26
+#define DSCR_CMD0_UDMA 27
+#define DSCR_CMD0_DMA_REQ0 28
+#define DSCR_CMD0_DMA_REQ1 29
+#endif /* CONFIG_SOC_AU13XX */
+
#define DSCR_CMD0_THROTTLE 30
#define DSCR_CMD0_ALWAYS 31
#define DSCR_NDEV_IDS 32
--
1.5.4.3
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH 05/10] Alchemy: Au1300/DB1300 MMC support
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
` (2 preceding siblings ...)
2009-03-06 16:20 ` [PATCH 04/10] Alchemy: Au1300/DB1300 peripheral resource declarations Kevin Hickey
@ 2009-03-06 16:20 ` Kevin Hickey
2009-03-06 16:20 ` [PATCH 06/10] Alchemy: Au1300 USB support Kevin Hickey
` (5 subsequent siblings)
9 siblings, 0 replies; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:20 UTC (permalink / raw)
To: ralf, linux-mips; +Cc: Kevin Hickey
Supports the MMC/SD controller on Au1300 and the single slot on the DB1300
board.
Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
---
arch/mips/alchemy/devboards/db1300/mmc.c | 154 ++++++++++++++++++++++++++++++
drivers/mmc/host/Kconfig | 2 +-
drivers/mmc/host/au1xmmc.c | 18 ++--
3 files changed, 164 insertions(+), 10 deletions(-)
create mode 100644 arch/mips/alchemy/devboards/db1300/mmc.c
diff --git a/arch/mips/alchemy/devboards/db1300/mmc.c b/arch/mips/alchemy/devboards/db1300/mmc.c
new file mode 100644
index 0000000..821658c
--- /dev/null
+++ b/arch/mips/alchemy/devboards/db1300/mmc.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2003-2008 RMI Corporation. All rights reserved.
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <asm/mips-boards/db1300.h>
+#include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <linux/dma-mapping.h>
+
+static volatile struct bcsr_regs *const bcsr =
+ (struct bcsr_regs *)(DB1300_BCSR_REGS_PHYS_ADDR + KSEG1_OFFSET);
+
+static int mmc_activity;
+static u64 au1xxx_mmc_dmamask = DMA_32BIT_MASK;
+
+
+static void db1300_mmcled_set(struct led_classdev *led,
+ enum led_brightness brightness)
+{
+ if (brightness != LED_OFF) {
+ if (++mmc_activity == 1)
+ bcsr->disk_leds &= ~(1 << 8);
+ } else {
+ if (--mmc_activity == 0)
+ bcsr->disk_leds |= (1 << 8);
+ }
+}
+
+static struct led_classdev db1300mmc_led = {
+ .brightness_set = db1300_mmcled_set,
+};
+
+
+static int db1300mmc1_card_readonly(void *mmc_host)
+{
+ return (bcsr->status & BCSR_STATUS_SD1_WP) ? 1 : 0;
+}
+
+static int db1300mmc1_card_inserted(void *mmc_host)
+{
+ int retval;
+ retval = (bcsr->sig_status & BCSR_INT_SD1_INSERT) ? 1 : 0;
+ return retval;
+}
+
+struct au1xmmc_platform_data au1xmmc_platdata[2] = {
+ [0] = {
+ .set_power = NULL,
+ .card_inserted = NULL,
+ .card_readonly = NULL,
+ .cd_setup = NULL, /* use poll-timer in driver */
+ .led = &db1300mmc_led,
+ },
+ [1] = {
+ .set_power = NULL,
+ .card_inserted = db1300mmc1_card_inserted,
+ .card_readonly = db1300mmc1_card_readonly,
+ .cd_setup = NULL, /* use poll-timer in driver */
+ .led = &db1300mmc_led,
+ },
+};
+
+static struct resource au13xx_mmc0_resources[] = {
+ [0] = {
+ .start = SD0_PHYS_ADDR,
+ .end = SD0_PHYS_ADDR + 0x7ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AU1300_IRQ_SD0 + GPINT_LINUX_IRQ_OFFSET,
+ .end = AU1300_IRQ_SD0 + GPINT_LINUX_IRQ_OFFSET,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = DSCR_CMD0_SDMS_TX0,
+ .end = DSCR_CMD0_SDMS_TX0,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .start = DSCR_CMD0_SDMS_RX0,
+ .end = DSCR_CMD0_SDMS_RX0,
+ .flags = IORESOURCE_DMA,
+ }
+};
+
+struct platform_device au13xx_mmc0_device = {
+ .name = "au1xxx-mmc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &au1xxx_mmc_dmamask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ .platform_data = &au1xmmc_platdata[0],
+ },
+ .num_resources = ARRAY_SIZE(au13xx_mmc0_resources),
+ .resource = au13xx_mmc0_resources,
+};
+
+static struct resource au13xx_mmc1_resources[] = {
+ [0] = {
+ .start = SD1_PHYS_ADDR,
+ .end = SD1_PHYS_ADDR + 0x7ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AU1300_IRQ_SD1 + GPINT_LINUX_IRQ_OFFSET,
+ .end = AU1300_IRQ_SD1 + GPINT_LINUX_IRQ_OFFSET,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = DSCR_CMD0_SDMS_TX1,
+ .end = DSCR_CMD0_SDMS_TX1,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .start = DSCR_CMD0_SDMS_RX1,
+ .end = DSCR_CMD0_SDMS_RX1,
+ .flags = IORESOURCE_DMA,
+ }
+};
+
+struct platform_device au13xx_mmc1_device = {
+ .name = "au1xxx-mmc",
+ .id = 1,
+ .dev = {
+ .dma_mask = &au1xxx_mmc_dmamask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ .platform_data = &au1xmmc_platdata[1],
+ },
+ .num_resources = ARRAY_SIZE(au13xx_mmc1_resources),
+ .resource = au13xx_mmc1_resources,
+};
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 99d4b28..a37bfee 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -99,7 +99,7 @@ config MMC_WBSD
config MMC_AU1X
tristate "Alchemy AU1XX0 MMC Card Interface support"
- depends on SOC_AU1200
+ depends on (SOC_AU1200 || SOC_AU13XX)
help
This selects the AMD Alchemy(R) Multimedia card interface.
If you have a Alchemy platform with a MMC slot, say Y or M here.
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index d3f5561..a3b8ac7 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -353,7 +353,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
if (!data->error) {
if (host->flags & HOST_F_DMA) {
-#ifdef CONFIG_SOC_AU1200 /* DBDMA */
+#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) /* DBDMA */
u32 chan = DMA_CHANNEL(host);
chan_tab_t *c = *((chan_tab_t **)chan);
@@ -570,7 +570,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
host->status = HOST_S_DATA;
if (host->flags & HOST_F_DMA) {
-#ifdef CONFIG_SOC_AU1200 /* DBDMA */
+#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) /* DBDMA */
u32 channel = DMA_CHANNEL(host);
/* Start the DMA as soon as the buffer gets something in it */
@@ -633,7 +633,7 @@ static int au1xmmc_prepare_data(struct au1xmmc_host *host,
au_writel(data->blksz - 1, HOST_BLKSIZE(host));
if (host->flags & HOST_F_DMA) {
-#ifdef CONFIG_SOC_AU1200 /* DBDMA */
+#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) /* DBDMA */
int i;
u32 channel = DMA_CHANNEL(host);
@@ -837,7 +837,7 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-#ifdef CONFIG_SOC_AU1200
+#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX)
/* 8bit memory DMA device */
static dbdev_tab_t au1xmmc_mem_dbdev = {
.dev_id = DSCR_CMD0_ALWAYS,
@@ -1023,7 +1023,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
(unsigned long)host);
-#ifdef CONFIG_SOC_AU1200
+#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX)
ret = au1xmmc_dbdma_init(host);
if (ret)
printk(KERN_INFO DRIVER_NAME ": DBDMA init failed; using PIO\n");
@@ -1068,7 +1068,7 @@ out5:
au_writel(0, HOST_CONFIG2(host));
au_sync();
-#ifdef CONFIG_SOC_AU1200
+#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX)
au1xmmc_dbdma_shutdown(host);
#endif
@@ -1115,7 +1115,7 @@ static int __devexit au1xmmc_remove(struct platform_device *pdev)
tasklet_kill(&host->data_task);
tasklet_kill(&host->finish_task);
-#ifdef CONFIG_SOC_AU1200
+#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX)
au1xmmc_dbdma_shutdown(host);
#endif
au1xmmc_set_power(host, 0);
@@ -1176,7 +1176,7 @@ static struct platform_driver au1xmmc_driver = {
static int __init au1xmmc_init(void)
{
-#ifdef CONFIG_SOC_AU1200
+#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX)
/* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
* of 8 bits. And since devices are shared, we need to create
* our own to avoid freaking out other devices.
@@ -1190,7 +1190,7 @@ static int __init au1xmmc_init(void)
static void __exit au1xmmc_exit(void)
{
-#ifdef CONFIG_SOC_AU1200
+#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX)
if (memid)
au1xxx_ddma_del_device(memid);
#endif
--
1.5.4.3
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH 06/10] Alchemy: Au1300 USB support
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
` (3 preceding siblings ...)
2009-03-06 16:20 ` [PATCH 05/10] Alchemy: Au1300/DB1300 MMC support Kevin Hickey
@ 2009-03-06 16:20 ` Kevin Hickey
2009-03-07 10:01 ` Sergei Shtylyov
2009-03-06 16:20 ` [PATCH 07/10] Alchemy: SMSC 9210 Ethernet support Kevin Hickey
` (4 subsequent siblings)
9 siblings, 1 reply; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:20 UTC (permalink / raw)
To: ralf, linux-mips; +Cc: Kevin Hickey
Adds support for USB 2.0 on the Au1300 SOC.
Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
---
drivers/usb/Kconfig | 1 +
drivers/usb/host/ehci-au13xx.c | 213 ++++++++++++++++++++++++++++++++++++++++
drivers/usb/host/ehci-hcd.c | 5 +
3 files changed, 219 insertions(+), 0 deletions(-)
create mode 100644 drivers/usb/host/ehci-au13xx.c
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 83babb0..a50d053 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -55,6 +55,7 @@ config USB_ARCH_HAS_EHCI
boolean
default y if PPC_83xx
default y if SOC_AU1200
+ default y if SOC_AU13XX
default y if ARCH_IXP4XX
default PCI
diff --git a/drivers/usb/host/ehci-au13xx.c b/drivers/usb/host/ehci-au13xx.c
new file mode 100644
index 0000000..fe03667
--- /dev/null
+++ b/drivers/usb/host/ehci-au13xx.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2008 RMI Corporation
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Based on ehci-au1xxx.c.
+ */
+
+#include <linux/platform_device.h>
+#include <asm/mach-au1x00/au1000.h>
+
+
+extern int usb_disabled(void);
+
+static void au13xx_start_ehc(void)
+{
+ AU13XX_USB* au13xx_usb = (AU13XX_USB*)(KSEG1 | USB_BASE_PHYS_ADDR);
+ /*
+ * Enable clocks.
+ */
+ AU_SET_BITS_32(USB_DWC_CTRL3_EHC_CLKEN, &au13xx_usb->dwc_ctrl3);
+
+ /*
+ * Take the host controller block out of reset
+ */
+ AU_SET_BITS_32(USB_DWC_CTRL1_HSTRS, &au13xx_usb->dwc_ctrl1);
+
+ /*
+ * Enable all of the PHYs
+ */
+ AU_SET_BITS_32(USB_DWC_CTRL2_PHYRS | USB_DWC_CTRL2_PHY0RS | USB_DWC_CTRL2_PH1RS,
+ &au13xx_usb->dwc_ctrl2);
+
+ /*
+ * Enable interrupts
+ */
+ AU_SET_BITS_32(USB_INTR_EHCI, &au13xx_usb->intr_enable);
+
+ /*
+ * This bit enables coherent DMA.
+ */
+ AU_SET_BITS_32(USB_SBUS_CTRL_SBCA, &au13xx_usb->sbus_ctrl);
+ asm("sync");
+}
+
+static void au13xx_stop_ehc(void)
+{
+ AU13XX_USB* au13xx_usb = (AU13XX_USB*)(KSEG1 | USB_BASE_PHYS_ADDR);
+ /*
+ * Disable the EHCI interrupt
+ */
+ AU_CLEAR_BITS_32(USB_INTR_EHCI, &au13xx_usb->intr_enable);
+
+ /*
+ * Disable the clock to the EHCI block
+ */
+ AU_CLEAR_BITS_32(USB_DWC_CTRL3_EHC_CLKEN, &au13xx_usb->dwc_ctrl3);
+
+ /*
+ * Note: we're not disabling the PHY here because the OHCI and EHCI
+ * drivers share a PHY and the OHCI driver may still be active.
+ */
+}
+
+static const struct hc_driver ehci_au13xx_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Au13xx EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_init,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+};
+
+static int ehci_hcd_au13xx_drv_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (pdev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug("resource[1] is not IORESOURCE_IRQ");
+ return -ENOMEM;
+ }
+ hcd = usb_create_hcd(&ehci_au13xx_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = pdev->resource[0].start;
+ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug("request_mem_region failed");
+ ret = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug("ioremap failed");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ au13xx_start_ehc();
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ printk("ehci->regs = %p\n", ehci->regs);
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+ ret = usb_add_hcd(hcd, pdev->resource[1].start,
+ IRQF_DISABLED | IRQF_SHARED);
+ if (ret == 0) {
+ platform_set_drvdata(pdev, hcd);
+ return ret;
+ }
+
+ au13xx_stop_ehc();
+ iounmap(hcd->regs);
+err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ehci_hcd_au13xx_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ au13xx_stop_ehc();
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ehci_hcd_au13xx_driver = {
+ .probe = ehci_hcd_au13xx_drv_probe,
+ .remove = ehci_hcd_au13xx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .suspend = NULL,
+ .resume = NULL,
+ .driver = {
+ .name = "au13xx-ehci",
+ .owner = THIS_MODULE,
+ }
+};
+
+MODULE_ALIAS("platform:au13xx-ehci");
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index e551bb3..1e4ca7e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1016,6 +1016,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
+#ifdef CONFIG_SOC_AU13XX
+#include "ehci-au13xx.c"
+#define PLATFORM_DRIVER ehci_hcd_au13xx_driver
+#endif
+
#ifdef CONFIG_PPC_PS3
#include "ehci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
--
1.5.4.3
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH 07/10] Alchemy: SMSC 9210 Ethernet support
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
` (4 preceding siblings ...)
2009-03-06 16:20 ` [PATCH 06/10] Alchemy: Au1300 USB support Kevin Hickey
@ 2009-03-06 16:20 ` Kevin Hickey
2009-03-07 9:35 ` Manuel Lauss
2009-03-06 16:20 ` [PATCH 08/10] Alchemy: DB1300 blink leds on timer tick Kevin Hickey
` (3 subsequent siblings)
9 siblings, 1 reply; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:20 UTC (permalink / raw)
To: ralf, linux-mips; +Cc: Kevin Hickey
This patch adds support for the SMSC 9210 Ethernet chip, specialized for
Alchemy platforms (including the DB1300). The ethernet driver code was
provided by SMSC; the platform shim by RMI.
Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
---
drivers/net/Kconfig | 6 +
drivers/net/Makefile | 3 +
drivers/net/smsc9210/Makefile | 9 +
drivers/net/smsc9210/ioctl_118.h | 298 ++
drivers/net/smsc9210/platform_alchemy.c | 88 +
drivers/net/smsc9210/platform_alchemy.h | 117 +
drivers/net/smsc9210/smsc9210.h | 23 +
drivers/net/smsc9210/smsc9210_main.c | 7189 +++++++++++++++++++++++++++++++
8 files changed, 7733 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/smsc9210/Makefile
create mode 100644 drivers/net/smsc9210/ioctl_118.h
create mode 100644 drivers/net/smsc9210/platform_alchemy.c
create mode 100644 drivers/net/smsc9210/platform_alchemy.h
create mode 100644 drivers/net/smsc9210/smsc9210.h
create mode 100644 drivers/net/smsc9210/smsc9210_main.c
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 8b13c5d..791735e 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -907,6 +907,12 @@ config SMC91X
inserted in and removed from the running kernel whenever you want).
The module will be called smc91x. If you want to compile it as a
module, say M here and read <file:Documentation/kbuild/modules.txt>.
+
+config SMSC9210
+ tristate "SMSC 9210 support"
+ depends on SOC_AU1X00
+ help
+ TODO
config NET_NETX
tristate "NetX Ethernet support"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 3c627d0..7c4052f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -222,6 +222,9 @@ obj-$(CONFIG_IBMVETH) += ibmveth.o
obj-$(CONFIG_S2IO) += s2io.o
obj-$(CONFIG_MYRI10GE) += myri10ge/
obj-$(CONFIG_SMC91X) += smc91x.o
+
+obj-$(CONFIG_SMSC9210) += smsc9210/
+
obj-$(CONFIG_SMC911X) += smc911x.o
obj-$(CONFIG_SMSC911X) += smsc911x.o
obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
diff --git a/drivers/net/smsc9210/Makefile b/drivers/net/smsc9210/Makefile
new file mode 100644
index 0000000..76a1217
--- /dev/null
+++ b/drivers/net/smsc9210/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright 2008 RMI Corporation. All rights reserved.
+# Author: Kevin Hickey <khickey@rmicorp.com>
+#
+
+obj-$(CONFIG_SMSC9210) += smsc9210.o
+
+smsc9210-objs := smsc9210_main.o platform_alchemy.o
+
diff --git a/drivers/net/smsc9210/ioctl_118.h b/drivers/net/smsc9210/ioctl_118.h
new file mode 100644
index 0000000..07187d7
--- /dev/null
+++ b/drivers/net/smsc9210/ioctl_118.h
@@ -0,0 +1,298 @@
+/***************************************************************************
+
+ *
+
+ * Copyright (C) 2004-2005 SMSC
+
+ *
+
+ * 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.
+
+ *
+
+ * This program is distributed in the hope that it will be useful,
+
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+
+ * GNU General Public License for more details.
+
+ *
+
+ * You should have received a copy of the GNU General Public License
+
+ * along with this program; if not, write to the Free Software
+
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ *
+
+ ***************************************************************************
+
+ * File: ioctl_118.h
+
+ */
+
+
+
+#ifndef IOCTL_118_H
+
+#define IOCTL_118_H
+
+
+
+#define DRIVER_VERSION (0x00000155UL)
+
+
+
+#define SMSC9118_DRIVER_SIGNATURE (0x82745BACUL+DRIVER_VERSION)
+
+#define SMSC9118_APP_SIGNATURE (0x987BEF28UL+DRIVER_VERSION)
+
+
+
+#define SMSC9118_IOCTL (SIOCDEVPRIVATE + 0xB)
+
+
+
+#define COMMAND_BASE (0x974FB832UL)
+
+
+
+#define COMMAND_GET_SIGNATURE (COMMAND_BASE+0)
+
+
+
+#define COMMAND_LAN_GET_REG (COMMAND_BASE+1)
+
+#define COMMAND_LAN_SET_REG (COMMAND_BASE+2)
+
+
+
+#define COMMAND_MAC_GET_REG (COMMAND_BASE+3)
+
+#define COMMAND_MAC_SET_REG (COMMAND_BASE+4)
+
+
+
+#define COMMAND_PHY_GET_REG (COMMAND_BASE+5)
+
+#define COMMAND_PHY_SET_REG (COMMAND_BASE+6)
+
+
+
+#define COMMAND_DUMP_LAN_REGS (COMMAND_BASE+7)
+
+#define LAN_REG_ID_REV (0)
+
+#define LAN_REG_INT_CFG (1)
+
+#define LAN_REG_INT_STS (2)
+
+#define LAN_REG_INT_EN (3)
+
+#define LAN_REG_BYTE_TEST (4)
+
+#define LAN_REG_FIFO_INT (5)
+
+#define LAN_REG_RX_CFG (6)
+
+#define LAN_REG_TX_CFG (7)
+
+#define LAN_REG_HW_CFG (8)
+
+#define LAN_REG_RX_DP_CTRL (9)
+
+#define LAN_REG_RX_FIFO_INF (10)
+
+#define LAN_REG_TX_FIFO_INF (11)
+
+#define LAN_REG_PMT_CTRL (12)
+
+#define LAN_REG_GPIO_CFG (13)
+
+#define LAN_REG_GPT_CFG (14)
+
+#define LAN_REG_GPT_CNT (15)
+
+#define LAN_REG_FPGA_REV (16)
+
+#define LAN_REG_WORD_SWAP (17)
+
+#define LAN_REG_FREE_RUN (18)
+
+#define LAN_REG_RX_DROP (19)
+
+#define LAN_REG_MAC_CSR_CMD (21)
+
+#define LAN_REG_MAC_CSR_DATA (22)
+
+#define LAN_REG_AFC_CFG (23)
+
+#define LAN_REG_E2P_CMD (24)
+
+#define LAN_REG_E2P_DATA (25)
+
+
+
+#define COMMAND_DUMP_MAC_REGS (COMMAND_BASE+8)
+
+#define MAC_REG_MAC_CR (0)
+
+#define MAC_REG_ADDRH (1)
+
+#define MAC_REG_ADDRL (2)
+
+#define MAC_REG_HASHH (3)
+
+#define MAC_REG_HASHL (4)
+
+#define MAC_REG_MII_ACC (5)
+
+#define MAC_REG_MII_DATA (6)
+
+#define MAC_REG_FLOW (7)
+
+#define MAC_REG_VLAN1 (8)
+
+#define MAC_REG_VLAN2 (9)
+
+#define MAC_REG_WUFF (10)
+
+#define MAC_REG_WUCSR (11)
+
+
+
+#define COMMAND_DUMP_PHY_REGS (COMMAND_BASE+9)
+
+#define PHY_REG_0 (0)
+
+#define PHY_REG_1 (1)
+
+#define PHY_REG_2 (2)
+
+#define PHY_REG_3 (3)
+
+#define PHY_REG_4 (4)
+
+#define PHY_REG_5 (5)
+
+#define PHY_REG_6 (6)
+
+#define PHY_REG_16 (7)
+
+#define PHY_REG_17 (8)
+
+#define PHY_REG_18 (9)
+
+#define PHY_REG_20 (10)
+
+#define PHY_REG_21 (11)
+
+#define PHY_REG_22 (12)
+
+#define PHY_REG_23 (13)
+
+#define PHY_REG_27 (14)
+
+#define PHY_REG_28 (15)
+
+#define PHY_REG_29 (16)
+
+#define PHY_REG_30 (17)
+
+#define PHY_REG_31 (18)
+
+
+
+#define COMMAND_DUMP_EEPROM (COMMAND_BASE+10)
+
+
+
+#define COMMAND_GET_MAC_ADDRESS (COMMAND_BASE+11)
+
+#define COMMAND_SET_MAC_ADDRESS (COMMAND_BASE+12)
+
+#define COMMAND_LOAD_MAC_ADDRESS (COMMAND_BASE+13)
+
+#define COMMAND_SAVE_MAC_ADDRESS (COMMAND_BASE+14)
+
+#define COMMAND_SET_DEBUG_MODE (COMMAND_BASE+15)
+
+
+
+#define COMMAND_SET_POWER_MODE (COMMAND_BASE+16)
+
+#define COMMAND_GET_POWER_MODE (COMMAND_BASE+17)
+
+
+
+#define COMMAND_SET_LINK_MODE (COMMAND_BASE+18)
+
+#define COMMAND_GET_LINK_MODE (COMMAND_BASE+19)
+
+#define COMMAND_GET_CONFIGURATION (COMMAND_BASE+20)
+
+#define COMMAND_DUMP_TEMP (COMMAND_BASE+21)
+
+#define COMMAND_READ_BYTE (COMMAND_BASE+22)
+
+#define COMMAND_READ_WORD (COMMAND_BASE+23)
+
+#define COMMAND_READ_DWORD (COMMAND_BASE+24)
+
+#define COMMAND_WRITE_BYTE (COMMAND_BASE+25)
+
+#define COMMAND_WRITE_WORD (COMMAND_BASE+26)
+
+#define COMMAND_WRITE_DWORD (COMMAND_BASE+27)
+
+#define COMMAND_CHECK_LINK (COMMAND_BASE+28)
+
+
+
+//the following codes are intended for cmd9118 only
+
+// they are not intended to have any use in the driver
+
+#define COMMAND_RUN_SERVER (COMMAND_BASE+29)
+
+#define COMMAND_RUN_TUNER (COMMAND_BASE+30)
+
+
+
+#define COMMAND_GET_FLOW_PARAMS (COMMAND_BASE+31)
+
+#define COMMAND_SET_FLOW_PARAMS (COMMAND_BASE+32)
+
+#define COMMAND_SET_AMDIX_STS (COMMAND_BASE+33)
+
+#define COMMAND_GET_AMDIX_STS (COMMAND_BASE+34)
+
+typedef struct _SMSC9118_IOCTL_DATA {
+
+ unsigned long dwSignature;
+
+ unsigned long dwCommand;
+
+ unsigned long Data[0x60];
+
+ char Strng1[30];
+
+ char Strng2[10];
+
+} SMSC9118_IOCTL_DATA, *PSMSC9118_IOCTL_DATA;
+
+
+
+#endif
+
+
+
diff --git a/drivers/net/smsc9210/platform_alchemy.c b/drivers/net/smsc9210/platform_alchemy.c
new file mode 100644
index 0000000..1da19a6
--- /dev/null
+++ b/drivers/net/smsc9210/platform_alchemy.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2003-2008 RMI Corporation. All rights reserved.
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/interrupt.h>
+#include "platform_alchemy.h"
+
+u32 Platform_Initialize(PPLATFORM_DATA pd, u32 lan_base, u32 bus_width)
+{
+ return BASE_ADDRESS;
+}
+
+
+/*
+ * Ignores the passed in irq in favor of the one we know to be correct...
+ */
+bool Platform_RequestIRQ(PPLATFORM_DATA pd,
+ u32 irq,
+ irqreturn_t (*pIsr)(int irq,void *dev_id),
+ void* dev_id )
+{
+ int retval = request_irq(PLATFORM_IRQ, pIsr, 0, "SMSC 9210 Ethernet", dev_id);
+ pd->irq_dev_id = dev_id;
+
+ return retval == 0 ? true : false;
+}
+
+void Platform_FreeIRQ(PPLATFORM_DATA pd)
+{
+ free_irq(PLATFORM_IRQ, pd->irq_dev_id);
+}
+
+void Platform_WriteFifo(u32 lan_base, u32 *buf, u32 count)
+{
+ int i;
+ for(i = 0; i < count; ++i)
+ {
+ au_iowrite32(*buf, (u32*)(lan_base+0x20));
+ ++buf;
+ }
+}
+
+void Platform_ReadFifo(u32 lan_base, u32 *buf, u32 count)
+{
+ int i;
+ for(i = 0; i < count; ++i)
+ {
+ *buf = au_ioread32((u32*)lan_base);
+ ++buf;
+ }
+
+}
+
+void Platform_GetFlowControlParameters(PPLATFORM_DATA pd, PFLOW_CONTROL_PARAMETERS fcp, bool useDma)
+{
+ /*
+ * Borrowed from xscale_linux.c in the 16-bit PIO 8210 section
+ */
+ memset(fcp,0,sizeof(FLOW_CONTROL_PARAMETERS));
+ fcp->BurstPeriod=100;
+ fcp->IntDeas=0;
+ fcp->MaxThroughput=0x74378UL;
+ fcp->MaxPacketCount=0x13AUL;
+ fcp->PacketCost=0x02UL;
+ fcp->BurstPeriod=0x76UL;
+ fcp->IntDeas=0x18UL;
+}
diff --git a/drivers/net/smsc9210/platform_alchemy.h b/drivers/net/smsc9210/platform_alchemy.h
new file mode 100644
index 0000000..17f42e3
--- /dev/null
+++ b/drivers/net/smsc9210/platform_alchemy.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2003-2008 RMI Corporation. All rights reserved.
+ * Author: Kevin Hickey <khickey@rmicorp.com>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef PLATFORM_ALCHEMY_H
+#define PLATFORM_ALCHEMY_H
+
+#include <asm/mach-au1x00/au1000.h>
+#include <linux/types.h>
+
+#if defined(CONFIG_MIPS_DB1200)
+#include <asm/mach-db1x00/db1200.h>
+#define PLATFORM_IRQ DB1200_DC_INT
+#elif defined(CONFIG_MIPS_HMP10)
+#include <asm/mips-boards/hmp10.h>
+#define PLATFORM_IRQ HMP10_ETH_IRQ
+#elif defined(CONFIG_MIPS_DB1300)
+#include <asm/mips-boards/db1300.h>
+#define PLATFORM_IRQ DB1300_ETHERNET_IRQ
+#endif
+
+#include "smsc9210.h"
+/*
+ * Make the IRQ a push-pull; on DB1300 there is no pull up so open-drain will
+ * always be low.
+ */
+#define PLATFORM_IRQ_POL 0
+#define PLATFORM_IRQ_TYPE 1
+#define PLATFORM_CACHE_LINE_BYTES 0
+#define PLATFORM_RX_DMA TRANSFER_PIO
+#define PLATFORM_TX_DMA TRANSFER_PIO
+#define PLATFORM_DMA_THRESHOLD 0
+#define PLATFORM_NAME "Alchemy"
+
+#ifdef CONFIG_MIPS_DB1200
+#define BASE_ADDRESS 0xBA000000
+#else
+#define BASE_ADDRESS 0xB9000000
+#endif
+
+typedef struct {
+ void *irq_dev_id;
+} PLATFORM_DATA, *PPLATFORM_DATA;
+
+u32 Platform_Initialize(PPLATFORM_DATA pd, u32 lan_base, u32 bus_width);
+
+static void Platform_CleanUp(PPLATFORM_DATA pd) { }
+static u32 Platform_CurrentIRQ(PPLATFORM_DATA pd)
+{
+ return PLATFORM_IRQ;
+}
+
+static inline void Platform_SetRegDW(u32 lan_base, u32 offset, u32 val)
+{
+ au_writel(val, (lan_base + offset));
+}
+
+static inline u32 Platform_GetRegDW(u32 lan_base, u32 offset)
+{
+ return au_readl(lan_base + offset);
+}
+
+bool Platform_RequestIRQ(PPLATFORM_DATA pd,
+ u32 irq,
+ irqreturn_t (*pIsr)(int irq, void *dev_id),
+ void* dev_id );
+
+void Platform_FreeIRQ(PPLATFORM_DATA pd);
+void Platform_GetFlowControlParameters(PPLATFORM_DATA pd, PFLOW_CONTROL_PARAMETERS fcp, bool useDma);
+void Platform_WriteFifo(u32 lan_base, u32 *buf, u32 count);
+void Platform_ReadFifo(u32 lan_base, u32 *buf, u32 count);
+
+/* * We're not supporting DMA at this time, so degenerate all functions to return
+ * errors.
+ */
+static inline bool Platform_IsValidDmaChannel(u32 chan) { return false; }
+static inline bool Platform_DmaInitialize(PPLATFORM_DATA pd, u32 chan) { return false; }
+static inline bool Platform_DmaDisable(PPLATFORM_DATA pd, u32 chan) { return false; }
+static inline void Platform_CacheInvalidate(PPLATFORM_DATA pd, const void *const sa,
+ const u32 len) { }
+static inline void Platform_CachePurge(PPLATFORM_DATA pd, const void *const sa,
+ const u32 len) { }
+static inline u32 Platform_RequestDmaChannel(PPLATFORM_DATA pd) { return TRANSFER_PIO; }
+static inline void Platform_ReleaseDmaChannel(PPLATFORM_DATA pd, u32 chan) { }
+static inline bool Platform_DmaStartXfer(PPLATFORM_DATA pd, const DMA_XFER * const pDmaXfer)
+{
+ return false;
+}
+static inline u32 Platform_DmaGetDwCnt(PPLATFORM_DATA platformData, const u32 dwDmaCh)
+{
+ return 0;
+}
+static inline void Platform_DmaComplete(PPLATFORM_DATA platformData, const u32 dwDmaCh) { }
+
+
+#endif /* PLATFORM_ALCHEMY_H */
diff --git a/drivers/net/smsc9210/smsc9210.h b/drivers/net/smsc9210/smsc9210.h
new file mode 100644
index 0000000..903b156
--- /dev/null
+++ b/drivers/net/smsc9210/smsc9210.h
@@ -0,0 +1,23 @@
+#ifndef SMSC9210_H
+#define SMSC9210_H
+
+#define TRANSFER_PIO (256UL)
+
+typedef struct _DMA_XFER
+{
+ u32 dwLanReg;
+ u32 *pdwBuf;
+ u32 dwDmaCh;
+ u32 dwDwCnt;
+ bool fMemWr;
+} DMA_XFER;
+
+typedef struct _FLOW_CONTROL_PARAMETERS
+{
+ u32 MaxThroughput;
+ u32 MaxPacketCount;
+ u32 PacketCost;
+ u32 BurstPeriod;
+ u32 IntDeas;
+} FLOW_CONTROL_PARAMETERS, *PFLOW_CONTROL_PARAMETERS;
+#endif /* SMSC9210_H */
diff --git a/drivers/net/smsc9210/smsc9210_main.c b/drivers/net/smsc9210/smsc9210_main.c
new file mode 100644
index 0000000..15fbf7f
--- /dev/null
+++ b/drivers/net/smsc9210/smsc9210_main.c
@@ -0,0 +1,7189 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2004-2005 SMSC
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ***************************************************************************
+ * File: smsc9118.c
+ * see readme.txt for programmers guide
+ */
+
+
+//#define UseScatterGather
+//#define UseTxCsum
+//#define UseRxCsum
+
+#define USE_DEBUG
+
+#ifndef __KERNEL__
+# define __KERNEL__
+#endif
+
+#ifdef USING_LINT
+#include "lint.h"
+#else //not USING_LINT
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <linux/timer.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/version.h>
+
+#include <asm/mach-au1x00/prom.h>
+#include "smsc9210.h"
+
+#endif //not USING_LINT
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+typedef void irqreturn_t;
+#define IRQ_NONE
+#define IRQ_HANDLED
+#define IRQ_RETVAL(x)
+#else
+#define LINUX_2_6_OR_NEWER
+#endif
+
+#ifdef USE_DEBUG
+static u32 debug_mode=0x7UL;
+#else
+static u32 debug_mode=0x0UL;
+#endif
+
+#ifdef USE_DEBUG
+//select debug modes
+#define USE_WARNING
+#define USE_TRACE
+#define USE_ASSERT
+#endif //USE_DEBUG
+
+#define USE_LED1_WORK_AROUND // 10/100 LED link-state inversion
+#define USE_PHY_WORK_AROUND // output polarity inversion
+
+typedef long TIME_SPAN;
+#define MAX_TIME_SPAN ((TIME_SPAN)(0x7FFFFFFFUL))
+typedef unsigned short WORD;
+typedef unsigned char BYTE;
+//typedef unsigned char bool;
+#define true ((bool)1)
+#define false ((bool)0)
+
+//unsigned char testbuff[1600]={0};
+//u32 * p= NULL;
+
+
+#define HIBYTE(word) ((BYTE)(((WORD)(word))>>8))
+#define LOBYTE(word) ((BYTE)(((WORD)(word))&0x00FFU))
+#define HIWORD(dWord) ((WORD)(((u32)(dWord))>>16))
+#define LOWORD(dWord) ((WORD)(((u32)(dWord))&0x0000FFFFUL))
+
+#define TRANSFER_PIO (256UL)
+#define TRANSFER_REQUEST_DMA (255UL)
+//these are values that can be assigned to
+//PLATFORM_RX_DMA
+//PLATFORM_TX_DMA
+// in addition to any specific dma channel
+
+/*******************************************************
+ * Macro: SMSC_TRACE
+ * Description:
+ * This macro is used like printf.
+ * It can be used anywhere you want to display information
+ * For any release version it should not be left in
+ * performance sensitive Tx and Rx code paths.
+ * To use this macro define USE_TRACE and set bit 0 of debug_mode
+ *******************************************************/
+#ifdef USING_LINT
+extern void SMSC_TRACE(const char * a, ...);
+#else //not USING_LINT
+#ifdef USE_TRACE
+#ifndef USE_WARNING
+#define USE_WARNING
+#endif
+# define SMSC_TRACE(msg,args...) \
+ if(debug_mode&0x01UL) { \
+ printk("SMSC: " msg "\n", ## args); \
+ }
+#else
+# define SMSC_TRACE(msg,args...)
+#endif
+#endif //not USING_LINT
+
+/*******************************************************
+ * Macro: SMSC_WARNING
+ * Description:
+ * This macro is used like printf.
+ * It can be used anywhere you want to display warning information
+ * For any release version it should not be left in
+ * performance sensitive Tx and Rx code paths.
+ * To use this macro define USE_TRACE or
+ * USE_WARNING and set bit 1 of debug_mode
+ *******************************************************/
+
+
+#ifdef USING_LINT
+extern void SMSC_WARNING(const char * a, ...);
+#else //not USING_LINT
+#ifdef USE_WARNING
+#ifndef USE_ASSERT
+#define USE_ASSERT
+#endif
+# define SMSC_WARNING(msg, args...) \
+ if(debug_mode&0x02UL) { \
+ printk("SMSC_WARNING: " msg "\n",## args); \
+ }
+#else
+# define SMSC_WARNING(msg, args...)
+#endif
+#endif //not USING_LINT
+
+
+/*******************************************************
+ * Macro: SMSC_ASSERT
+ * Description:
+ * This macro is used to test assumptions made when coding.
+ * It can be used anywhere, but is intended only for situations
+ * where a failure is fatal.
+ * If code execution where allowed to continue it is assumed that
+ * only further unrecoverable errors would occur and so this macro
+ * includes an infinite loop to prevent further corruption.
+ * Assertions are only intended for use during developement to
+ * insure consistency of logic through out the driver.
+ * A driver should not be released if assertion failures are
+ * still occuring.
+ * To use this macro define USE_TRACE or USE_WARNING or
+ * USE_ASSERT
+ *******************************************************/
+#ifdef USING_LINT
+extern void SMSC_ASSERT(bool condition);
+#else //not USING_LINT
+#ifdef USE_ASSERT
+# define SMSC_ASSERT(condition) \
+ if(!(condition)) { \
+ printk("SMSC_ASSERTION_FAILURE: File=" __FILE__ ", Line=%d\n",__LINE__); \
+ while(1); \
+ }
+#else
+# define SMSC_ASSERT(condition)
+#endif
+#endif //not USING_LINT
+
+//Below are the register offsets and bit definitions
+// of the Lan9118 memory space
+#define RX_DATA_FIFO (0x00UL)
+#define TX_DATA_FIFO (0x20UL)
+#define TX_CMD_A_INT_ON_COMP_ (0x80000000UL)
+#define TX_CMD_A_INT_BUF_END_ALGN_ (0x03000000UL)
+#define TX_CMD_A_INT_4_BYTE_ALGN_ (0x00000000UL)
+#define TX_CMD_A_INT_16_BYTE_ALGN_ (0x01000000UL)
+#define TX_CMD_A_INT_32_BYTE_ALGN_ (0x02000000UL)
+#define TX_CMD_A_INT_DATA_OFFSET_ (0x001F0000UL)
+#define TX_CMD_A_INT_FIRST_SEG_ (0x00002000UL)
+#define TX_CMD_A_INT_LAST_SEG_ (0x00001000UL)
+#define TX_CMD_A_BUF_SIZE_ (0x000007FFUL)
+#define TX_CMD_B_PKT_TAG_ (0xFFFF0000UL)
+#define TX_CMD_B_CSUM_ENABLE (0x00004000UL)
+#define TX_CMD_B_ADD_CRC_DISABLE_ (0x00002000UL)
+#define TX_CMD_B_DISABLE_PADDING_ (0x00001000UL)
+#define TX_CMD_B_PKT_BYTE_LENGTH_ (0x000007FFUL)
+
+#define RX_STATUS_FIFO (0x40UL)
+#define RX_STS_ES_ (0x00008000UL)
+#define RX_STS_MCAST_ (0x00000400UL)
+#define RX_STATUS_FIFO_PEEK (0x44UL)
+#define TX_STATUS_FIFO (0x48UL)
+#define TX_STATUS_FIFO_PEEK (0x4CUL)
+#define ID_REV (0x50UL)
+#define ID_REV_CHIP_ID_ (0xFFFF0000UL) // RO
+#define ID_REV_REV_ID_ (0x0000FFFFUL) // RO
+
+#define INT_CFG (0x54UL)
+#define INT_CFG_INT_DEAS_ (0xFF000000UL) // R/W
+#define INT_CFG_IRQ_INT_ (0x00001000UL) // RO
+#define INT_CFG_IRQ_EN_ (0x00000100UL) // R/W
+#define INT_CFG_IRQ_POL_ (0x00000010UL) // R/W Not Affected by SW Reset
+#define INT_CFG_IRQ_TYPE_ (0x00000001UL) // R/W Not Affected by SW Reset
+
+#define INT_STS (0x58UL)
+#define INT_STS_SW_INT_ (0x80000000UL) // R/WC
+#define INT_STS_TXSTOP_INT_ (0x02000000UL) // R/WC
+#define INT_STS_RXSTOP_INT_ (0x01000000UL) // R/WC
+#define INT_STS_RXDFH_INT_ (0x00800000UL) // R/WC
+#define INT_STS_RXDF_INT_ (0x00400000UL) // R/WC
+#define INT_STS_TX_IOC_ (0x00200000UL) // R/WC
+#define INT_STS_RXD_INT_ (0x00100000UL) // R/WC
+#define INT_STS_GPT_INT_ (0x00080000UL) // R/WC
+#define INT_STS_PHY_INT_ (0x00040000UL) // RO
+#define INT_STS_PME_INT_ (0x00020000UL) // R/WC
+#define INT_STS_TXSO_ (0x00010000UL) // R/WC
+#define INT_STS_RWT_ (0x00008000UL) // R/WC
+#define INT_STS_RXE_ (0x00004000UL) // R/WC
+#define INT_STS_TXE_ (0x00002000UL) // R/WC
+#define INT_STS_ERX_ (0x00001000UL) // R/WC
+#define INT_STS_TDFU_ (0x00000800UL) // R/WC
+#define INT_STS_TDFO_ (0x00000400UL) // R/WC
+#define INT_STS_TDFA_ (0x00000200UL) // R/WC
+#define INT_STS_TSFF_ (0x00000100UL) // R/WC
+#define INT_STS_TSFL_ (0x00000080UL) // R/WC
+#define INT_STS_RDFO_ (0x00000040UL) // R/WC
+#define INT_STS_RDFL_ (0x00000020UL) // R/WC
+#define INT_STS_RSFF_ (0x00000010UL) // R/WC
+#define INT_STS_RSFL_ (0x00000008UL) // R/WC
+#define INT_STS_GPIO2_INT_ (0x00000004UL) // R/WC
+#define INT_STS_GPIO1_INT_ (0x00000002UL) // R/WC
+#define INT_STS_GPIO0_INT_ (0x00000001UL) // R/WC
+
+#define INT_EN (0x5CUL)
+#define INT_EN_SW_INT_EN_ (0x80000000UL) // R/W
+#define INT_EN_TXSTOP_INT_EN_ (0x02000000UL) // R/W
+#define INT_EN_RXSTOP_INT_EN_ (0x01000000UL) // R/W
+#define INT_EN_RXDFH_INT_EN_ (0x00800000UL) // R/W
+#define INT_EN_RXDF_INT_EN_ (0x00400000UL) // R/W
+#define INT_EN_TIOC_INT_EN_ (0x00200000UL) // R/W
+#define INT_EN_RXD_INT_EN_ (0x00100000UL) // R/W
+#define INT_EN_GPT_INT_EN_ (0x00080000UL) // R/W
+#define INT_EN_PHY_INT_EN_ (0x00040000UL) // R/W
+#define INT_EN_PME_INT_EN_ (0x00020000UL) // R/W
+#define INT_EN_TXSO_EN_ (0x00010000UL) // R/W
+#define INT_EN_RWT_EN_ (0x00008000UL) // R/W
+#define INT_EN_RXE_EN_ (0x00004000UL) // R/W
+#define INT_EN_TXE_EN_ (0x00002000UL) // R/W
+#define INT_EN_ERX_EN_ (0x00001000UL) // R/W
+#define INT_EN_TDFU_EN_ (0x00000800UL) // R/W
+#define INT_EN_TDFO_EN_ (0x00000400UL) // R/W
+#define INT_EN_TDFA_EN_ (0x00000200UL) // R/W
+#define INT_EN_TSFF_EN_ (0x00000100UL) // R/W
+#define INT_EN_TSFL_EN_ (0x00000080UL) // R/W
+#define INT_EN_RDFO_EN_ (0x00000040UL) // R/W
+#define INT_EN_RDFL_EN_ (0x00000020UL) // R/W
+#define INT_EN_RSFF_EN_ (0x00000010UL) // R/W
+#define INT_EN_RSFL_EN_ (0x00000008UL) // R/W
+#define INT_EN_GPIO2_INT_ (0x00000004UL) // R/W
+#define INT_EN_GPIO1_INT_ (0x00000002UL) // R/W
+#define INT_EN_GPIO0_INT_ (0x00000001UL) // R/W
+
+#define BYTE_TEST (0x64UL)
+#define FIFO_INT (0x68UL)
+#define FIFO_INT_TX_AVAIL_LEVEL_ (0xFF000000UL) // R/W
+#define FIFO_INT_TX_STS_LEVEL_ (0x00FF0000UL) // R/W
+#define FIFO_INT_RX_AVAIL_LEVEL_ (0x0000FF00UL) // R/W
+#define FIFO_INT_RX_STS_LEVEL_ (0x000000FFUL) // R/W
+
+#define RX_CFG (0x6CUL)
+#define RX_CFG_RX_END_ALGN_ (0xC0000000UL) // R/W
+#define RX_CFG_RX_END_ALGN4_ (0x00000000UL) // R/W
+#define RX_CFG_RX_END_ALGN16_ (0x40000000UL) // R/W
+#define RX_CFG_RX_END_ALGN32_ (0x80000000UL) // R/W
+#define RX_CFG_RX_DMA_CNT_ (0x0FFF0000UL) // R/W
+#define RX_CFG_RX_DUMP_ (0x00008000UL) // R/W
+#define RX_CFG_RXDOFF_ (0x00001F00UL) // R/W
+#define RX_CFG_RXDOFF_2_ (0x00000200UL) //Rx data offset is 2
+#define RX_CFG_RXDOFF_18_ (0x00001200UL) //Rx data offset is 0x12
+#define RX_CFG_RXBAD_ (0x00000001UL) // R/W
+
+#define TX_CFG (0x70UL)
+#define TX_CFG_TX_DMA_LVL_ (0xE0000000UL) // R/W
+#define TX_CFG_TX_DMA_CNT_ (0x0FFF0000UL) // R/W Self Clearing
+#define TX_CFG_TXS_DUMP_ (0x00008000UL) // Self Clearing
+#define TX_CFG_TXD_DUMP_ (0x00004000UL) // Self Clearing
+#define TX_CFG_TXSAO_ (0x00000004UL) // R/W
+#define TX_CFG_TX_ON_ (0x00000002UL) // R/W
+#define TX_CFG_STOP_TX_ (0x00000001UL) // Self Clearing
+
+#define HW_CFG (0x74UL)
+#define HW_CFG_AMDIX_EN_STRAP_STS_ (0x01000000UL)
+#define HW_CFG_TTM_ (0x00200000UL) // R/W
+#define HW_CFG_SF_ (0x00100000UL) // R/W
+#define HW_CFG_TX_FIF_SZ_ (0x000F0000UL) // R/W
+#define HW_CFG_TR_ (0x00003000UL) // R/W
+#define HW_CFG_PHY_CLK_SEL_ (0x00000060UL) // R/W
+#define HW_CFG_PHY_CLK_SEL_INT_PHY_ (0x00000000UL) // R/W
+#define HW_CFG_PHY_CLK_SEL_EXT_PHY_ (0x00000020UL) // R/W
+#define HW_CFG_PHY_CLK_SEL_CLK_DIS_ (0x00000040UL) // R/W
+#define HW_CFG_SMI_SEL_ (0x00000010UL) // R/W
+#define HW_CFG_EXT_PHY_DET_ (0x00000008UL) // RO
+#define HW_CFG_EXT_PHY_EN_ (0x00000004UL) // R/W
+#define HW_CFG_32_16_BIT_MODE_ (0x00000004UL) // RO
+#define HW_CFG_SRST_TO_ (0x00000002UL) // RO
+#define HW_CFG_SRST_ (0x00000001UL) // Self Clearing
+
+#define RX_DP_CTRL (0x78UL)
+#define RX_DP_CTRL_RX_FFWD_ (0x00000FFFUL) // R/W
+#define RX_DP_CTRL_FFWD_BUSY_ (0x80000000UL) // RO
+
+#define RX_FIFO_INF (0x7CUL)
+#define RX_FIFO_INF_RXSUSED_ (0x00FF0000UL) // RO
+#define RX_FIFO_INF_RXDUSED_ (0x0000FFFFUL) // RO
+
+#define TX_FIFO_INF (0x80UL)
+#define TX_FIFO_INF_TSUSED_ (0x00FF0000UL) // RO
+#define TX_FIFO_INF_TSFREE_ (0x00FF0000UL) // RO
+#define TX_FIFO_INF_TDFREE_ (0x0000FFFFUL) // RO
+
+#define PMT_CTRL (0x84UL)
+#define PMT_CTRL_PM_MODE_ (0x00018000UL) // Self Clearing
+#define PMT_CTRL_PHY_RST_ (0x00000400UL) // Self Clearing
+#define PMT_CTRL_WOL_EN_ (0x00000200UL) // R/W
+#define PMT_CTRL_ED_EN_ (0x00000100UL) // R/W
+#define PMT_CTRL_PME_TYPE_ (0x00000040UL) // R/W Not Affected by SW Reset
+#define PMT_CTRL_WUPS_ (0x00000030UL) // R/WC
+#define PMT_CTRL_WUPS_NOWAKE_ (0x00000000UL) // R/WC
+#define PMT_CTRL_WUPS_ED_ (0x00000010UL) // R/WC
+#define PMT_CTRL_WUPS_WOL_ (0x00000020UL) // R/WC
+#define PMT_CTRL_WUPS_MULTI_ (0x00000030UL) // R/WC
+#define PMT_CTRL_PME_IND_ (0x00000008UL) // R/W
+#define PMT_CTRL_PME_POL_ (0x00000004UL) // R/W
+#define PMT_CTRL_PME_EN_ (0x00000002UL) // R/W Not Affected by SW Reset
+#define PMT_CTRL_READY_ (0x00000001UL) // RO
+
+#define GPIO_CFG (0x88UL)
+#define GPIO_CFG_LED3_EN_ (0x40000000UL) // R/W
+#define GPIO_CFG_LED2_EN_ (0x20000000UL) // R/W
+#define GPIO_CFG_LED1_EN_ (0x10000000UL) // R/W
+#define GPIO_CFG_GPIO2_INT_POL_ (0x04000000UL) // R/W
+#define GPIO_CFG_GPIO1_INT_POL_ (0x02000000UL) // R/W
+#define GPIO_CFG_GPIO0_INT_POL_ (0x01000000UL) // R/W
+#define GPIO_CFG_EEPR_EN_ (0x00E00000UL) // R/W
+#define GPIO_CFG_GPIOBUF2_ (0x00040000UL) // R/W
+#define GPIO_CFG_GPIOBUF1_ (0x00020000UL) // R/W
+#define GPIO_CFG_GPIOBUF0_ (0x00010000UL) // R/W
+#define GPIO_CFG_GPIODIR2_ (0x00000400UL) // R/W
+#define GPIO_CFG_GPIODIR1_ (0x00000200UL) // R/W
+#define GPIO_CFG_GPIODIR0_ (0x00000100UL) // R/W
+#define GPIO_CFG_GPIOD4_ (0x00000020UL) // R/W
+#define GPIO_CFG_GPIOD3_ (0x00000010UL) // R/W
+#define GPIO_CFG_GPIOD2_ (0x00000004UL) // R/W
+#define GPIO_CFG_GPIOD1_ (0x00000002UL) // R/W
+#define GPIO_CFG_GPIOD0_ (0x00000001UL) // R/W
+
+#define GPT_CFG (0x8CUL)
+#define GPT_CFG_TIMER_EN_ (0x20000000UL) // R/W
+#define GPT_CFG_GPT_LOAD_ (0x0000FFFFUL) // R/W
+
+#define GPT_CNT (0x90UL)
+#define GPT_CNT_GPT_CNT_ (0x0000FFFFUL) // RO
+
+#define FPGA_REV (0x94UL)
+#define FPGA_REV_FPGA_REV_ (0x0000FFFFUL) // RO
+
+#define WORD_SWAP (0x98UL)
+#define FREE_RUN (0x9CUL)
+#define RX_DROP (0xA0UL)
+#define MAC_CSR_CMD (0xA4UL)
+#define MAC_CSR_CMD_CSR_BUSY_ (0x80000000UL) // Self Clearing
+#define MAC_CSR_CMD_R_NOT_W_ (0x40000000UL) // R/W
+#define MAC_CSR_CMD_CSR_ADDR_ (0x000000FFUL) // R/W
+
+#define MAC_CSR_DATA (0xA8UL)
+#define AFC_CFG (0xACUL)
+#define AFC_CFG_AFC_HI_ (0x00FF0000UL) // R/W
+#define AFC_CFG_AFC_LO_ (0x0000FF00UL) // R/W
+#define AFC_CFG_BACK_DUR_ (0x000000F0UL) // R/W
+#define AFC_CFG_FCMULT_ (0x00000008UL) // R/W
+#define AFC_CFG_FCBRD_ (0x00000004UL) // R/W
+#define AFC_CFG_FCADD_ (0x00000002UL) // R/W
+#define AFC_CFG_FCANY_ (0x00000001UL) // R/W
+
+#define E2P_CMD (0xB0UL)
+#define E2P_CMD_EPC_BUSY_ (0x80000000UL) // Self Clearing
+#define E2P_CMD_EPC_CMD_ (0x70000000UL) // R/W
+#define E2P_CMD_EPC_CMD_READ_ (0x00000000UL) // R/W
+#define E2P_CMD_EPC_CMD_EWDS_ (0x10000000UL) // R/W
+#define E2P_CMD_EPC_CMD_EWEN_ (0x20000000UL) // R/W
+#define E2P_CMD_EPC_CMD_WRITE_ (0x30000000UL) // R/W
+#define E2P_CMD_EPC_CMD_WRAL_ (0x40000000UL) // R/W
+#define E2P_CMD_EPC_CMD_ERASE_ (0x50000000UL) // R/W
+#define E2P_CMD_EPC_CMD_ERAL_ (0x60000000UL) // R/W
+#define E2P_CMD_EPC_CMD_RELOAD_ (0x70000000UL) // R/W
+#define E2P_CMD_EPC_TIMEOUT_ (0x00000200UL) // R
+#define E2P_CMD_MAC_ADDR_LOADED_ (0x00000100UL) // RO
+#define E2P_CMD_EPC_ADDR_ (0x000000FFUL) // R/W
+
+#define E2P_DATA (0xB4UL)
+#define E2P_DATA_EEPROM_DATA_ (0x000000FFUL) // R/W
+//end of lan register offsets and bit definitions
+
+#define LAN_REGISTER_EXTENT (0x00002000UL)
+
+//The following describes the synchronization policies used in this driver.
+//Register Name Policy
+//RX_DATA_FIFO Only used by the Rx Thread, Rx_ProcessPackets
+//TX_DATA_FIFO Only used by the Tx Thread, Tx_SendSkb
+//RX_STATUS_FIFO Only used by the Rx Thread, Rx_ProcessPackets
+//RX_STATUS_FIFO_PEEK Not used.
+//TX_STATUS_FIFO Used in Tx_CompleteTx in Tx_UpdateTxCounters.
+// protected by TxCounterLock
+//TX_STATUS_FIFO_PEEK Not used.
+//ID_REV Read only
+//INT_CFG Set in Lan_Initialize,
+// protected by IntEnableLock
+//INT_STS Sharable,
+//INT_EN Initialized at startup,
+// Used in Rx_ProcessPackets
+// otherwise protected by IntEnableLock
+//BYTE_TEST Read Only
+//FIFO_INT Initialized at startup,
+// During run time only accessed by
+// Tx_HandleInterrupt, and Tx_SendSkb and done in a safe manner
+//RX_CFG Used during initialization
+// During runtime only used by Rx Thread
+//TX_CFG Only used during initialization
+//HW_CFG Only used during initialization
+//RX_DP_CTRL Only used in Rx Thread, in Rx_FastForward
+//RX_FIFO_INF Read Only, Only used in Rx Thread, in Rx_PopRxStatus
+//TX_FIFO_INF Read Only, Only used in Tx Thread, in Tx_GetTxStatusCount, Tx_SendSkb, Tx_CompleteTx
+//PMT_CTRL Not Used
+//GPIO_CFG used during initialization, in Lan_Initialize
+// used for debugging
+// used during EEPROM access.
+// safe enough to not require a lock
+//GPT_CFG protected by GpTimerLock
+//GPT_CNT Not Used
+//WORD_SWAP Not Used
+//FREE_RUN Read only
+//RX_DROP Used in Rx Interrupt Handler,
+// and get_stats.
+// safe enough to not require a lock.
+//MAC_CSR_CMD Protected by MacPhyLock
+//MAC_CSR_DATA Protected by MacPhyLock
+// Because the two previous MAC_CSR_ registers are protected
+// All MAC, and PHY registers are protected as well.
+//AFC_CFG Used during initialization, in Lan_Initialize
+// During run time, used in timer call back, in Phy_UpdateLinkMode
+//E2P_CMD Used during initialization, in Lan_Initialize
+// Used in EEPROM functions
+//E2P_DATA Used in EEPROM functions
+
+#include "platform_alchemy.h"
+
+#define Lan_GetRegDW(dwOffset) \
+ Platform_GetRegDW(privateData->dwLanBase,dwOffset)
+
+#define Lan_SetRegDW(dwOffset,dwVal) \
+ Platform_SetRegDW(privateData->dwLanBase,dwOffset,dwVal)
+
+#define Lan_ClrBitsDW(dwOffset,dwBits) \
+ Platform_SetRegDW(privateData->dwLanBase, \
+ dwOffset,Platform_GetRegDW(privateData->dwLanBase, \
+ dwOffset)&(~dwBits))
+
+#define Lan_SetBitsDW(dwOffset,dwBits) \
+ Platform_SetRegDW(privateData->dwLanBase, \
+ dwOffset,Platform_GetRegDW(privateData->dwLanBase, \
+ dwOffset)|dwBits);
+
+#define LINK_OFF (0x00UL)
+#define LINK_SPEED_10HD (0x01UL)
+#define LINK_SPEED_10FD (0x02UL)
+#define LINK_SPEED_100HD (0x04UL)
+#define LINK_SPEED_100FD (0x08UL)
+#define LINK_SYMMETRIC_PAUSE (0x10UL)
+#define LINK_ASYMMETRIC_PAUSE (0x20UL)
+#define LINK_AUTO_NEGOTIATE (0x40UL)
+
+typedef unsigned long VL_KEY;
+typedef struct _VERIFIABLE_LOCK {
+ spinlock_t Lock;
+ VL_KEY KeyCode;
+} VERIFIABLE_LOCK, * PVERIFIABLE_LOCK;
+
+void Vl_InitLock(PVERIFIABLE_LOCK pVl);
+bool Vl_CheckLock(PVERIFIABLE_LOCK pVl,VL_KEY keyCode);
+VL_KEY Vl_WaitForLock(PVERIFIABLE_LOCK pVl,unsigned long *pdwIntFlags);
+void Vl_ReleaseLock(PVERIFIABLE_LOCK pVl,VL_KEY keyCode,unsigned long *pdwIntFlags);
+
+typedef struct _PRIVATE_DATA {
+ u32 dwLanBase;
+ u32 dwIdRev;
+ u32 dwFpgaRev;
+ struct net_device *dev;
+ u32 dwGeneration;//used to decide which workarounds apply
+ bool UseScatterGather;
+ bool UseTxCsum;
+ bool UseRxCsum;
+
+
+ spinlock_t IntEnableLock;
+ bool LanInitialized;
+ VERIFIABLE_LOCK MacPhyLock;
+ bool ExtPhy; //
+
+ u32 dwTxDmaCh;
+ bool TxDmaChReserved;
+ DMA_XFER TxDmaXfer;
+ u32 dwTxDmaThreshold;
+ u32 dwTxQueueDisableMask;
+ struct sk_buff *TxSkb;
+ spinlock_t TxSkbLock;
+ spinlock_t TxQueueLock;
+ spinlock_t TxCounterLock;
+ bool TxInitialized;
+
+
+
+ // BYTE bCoalesceBuf[1600];
+
+
+
+ // struct sk_buff *TxSkbPending;
+
+
+ u32 dwRxDmaCh;
+ struct sk_buff *RxSkb;
+ bool RxDmaChReserved;
+ u32 dwRxDmaThreshold;
+ bool RxCongested;
+ u32 dwRxOffCount;
+ bool RxOverrun;
+ u32 RxOverrunCount;
+ u32 RxStatusDWReadCount;
+ u32 RxDataDWReadCount;
+ u32 RxPacketReadCount;
+ u32 RxFastForwardCount;
+ u32 RxPioReadCount;
+ u32 RxDmaReadCount;
+ u32 RxCongestedCount;
+ u32 RxDumpCount;
+ u32 LastReasonForReleasingCPU;
+ u32 LastRxStatus1;
+ u32 LastRxStatus2;
+ u32 LastRxStatus3;
+ u32 LastIntStatus1;
+ u32 LastIntStatus2;
+ u32 LastIntStatus3;
+ u32 RxUnloadProgress;
+ u32 RxUnloadPacketProgress;
+ u32 RxMaxDataFifoSize;
+ // bool RxVLanPkt;
+
+ //NAPI
+ int RxWorkLimit;
+ int RxPacketsReceived;
+ // bool RxDone;
+
+
+ u32 RxFlowCurrentThroughput;
+ u32 RxFlowCurrentPacketCount;
+ u32 RxFlowCurrentWorkLoad;
+ bool MeasuringRxThroughput;
+ u32 RxFlowMeasuredMaxThroughput;
+ u32 RxFlowMeasuredMaxPacketCount;
+
+ //RX_FLOW_ACTIVATION specifies the percentage that RxFlowCurrentWorkLoad must exceed
+ // RxFlowMaxWorkLoad in order to activate flow control
+#define RX_FLOW_ACTIVATION (4UL)
+
+ //RX_FLOW_DEACTIVATION specifies the percentage that RxFlowCurrentWorkLoad must reduce
+ // from RxFlowMaxWorkLoad in order to deactivate flow control
+#define RX_FLOW_DEACTIVATION (25UL)
+ u32 RxFlowMaxWorkLoad;
+
+ FLOW_CONTROL_PARAMETERS RxFlowParameters;
+
+ u32 RxFlowBurstWorkLoad;
+ u32 RxFlowBurstMaxWorkLoad;
+ bool RxFlowControlActive;
+ bool RxFlowBurstActive;
+ u32 RxInterrupts;
+
+#define GPT_SCHEDULE_DEPTH (3)
+ void *GptFunction[GPT_SCHEDULE_DEPTH];
+ u32 GptCallTime[GPT_SCHEDULE_DEPTH];
+ u32 Gpt_scheduled_slot_index;
+ spinlock_t GpTimerLock;
+
+ bool Running;
+ struct net_device_stats stats;
+
+ u32 dwPhyAddress;
+ u32 dwPhyId;
+#ifdef USE_LED1_WORK_AROUND
+ u32 NotUsingExtPhy;
+#endif
+ BYTE bPhyModel;
+ BYTE bPhyRev;
+ u32 dwLinkSpeed;
+ u32 dwLinkSettings;
+ u32 dwRemoteFaultCount;
+ struct timer_list LinkPollingTimer;
+ bool StopLinkPolling;
+ WORD wLastADV;
+ WORD wLastADVatRestart;
+#ifdef USE_PHY_WORK_AROUND
+#define MIN_PACKET_SIZE (64)
+ u32 dwTxStartMargen;
+ BYTE LoopBackTxPacket[MIN_PACKET_SIZE];
+ u32 dwTxEndMargen;
+ u32 dwRxStartMargen;
+ BYTE LoopBackRxPacket[MIN_PACKET_SIZE];
+ u32 dwRxEndMargen;
+ u32 dwResetCount;
+#endif
+
+ bool SoftwareInterruptSignal;
+
+ PLATFORM_DATA PlatformData;
+
+#define SMSC_IF_NAME_SIZE (10)
+ char ifName[SMSC_IF_NAME_SIZE];
+
+ /* for Rx Multicast work around */
+ volatile u32 HashLo;
+ volatile u32 HashHi;
+ volatile bool MulticastUpdatePending;
+ volatile u32 set_bits_mask;
+ volatile u32 clear_bits_mask;
+
+} PRIVATE_DATA, *PPRIVATE_DATA;
+
+
+/*
+ ****************************************************************************
+ ****************************************************************************
+ * MAC Control and Status Register (Indirect Address)
+ * Offset (through the MAC_CSR CMD and DATA port)
+ ****************************************************************************
+ ****************************************************************************
+ *
+ */
+#define MAC_CR (0x01UL) // R/W
+
+/* MAC_CR - MAC Control Register */
+#define MAC_CR_RXALL_ (0x80000000UL)
+#define MAC_CR_HBDIS_ (0x10000000UL)
+#define MAC_CR_RCVOWN_ (0x00800000UL)
+#define MAC_CR_LOOPBK_ (0x00200000UL)
+#define MAC_CR_FDPX_ (0x00100000UL)
+#define MAC_CR_MCPAS_ (0x00080000UL)
+#define MAC_CR_PRMS_ (0x00040000UL)
+#define MAC_CR_INVFILT_ (0x00020000UL)
+#define MAC_CR_PASSBAD_ (0x00010000UL)
+#define MAC_CR_HFILT_ (0x00008000UL)
+#define MAC_CR_HPFILT_ (0x00002000UL)
+#define MAC_CR_LCOLL_ (0x00001000UL)
+#define MAC_CR_BCAST_ (0x00000800UL)
+#define MAC_CR_DISRTY_ (0x00000400UL)
+#define MAC_CR_PADSTR_ (0x00000100UL)
+#define MAC_CR_BOLMT_MASK_ (0x000000C0UL)
+#define MAC_CR_DFCHK_ (0x00000020UL)
+#define MAC_CR_TXEN_ (0x00000008UL)
+#define MAC_CR_RXEN_ (0x00000004UL)
+
+#define ADDRH (0x02UL) // R/W mask 0x0000FFFFUL
+#define ADDRL (0x03UL) // R/W mask 0xFFFFFFFFUL
+#define HASHH (0x04UL) // R/W
+#define HASHL (0x05UL) // R/W
+
+#define MII_ACC (0x06UL) // R/W
+#define MII_ACC_PHY_ADDR_ (0x0000F800UL)
+#define MII_ACC_MIIRINDA_ (0x000007C0UL)
+#define MII_ACC_MII_WRITE_ (0x00000002UL)
+#define MII_ACC_MII_BUSY_ (0x00000001UL)
+
+#define MII_DATA (0x07UL) // R/W mask 0x0000FFFFUL
+
+#define FLOW (0x08UL) // R/W
+#define FLOW_FCPT_ (0xFFFF0000UL)
+#define FLOW_FCPASS_ (0x00000004UL)
+#define FLOW_FCEN_ (0x00000002UL)
+#define FLOW_FCBSY_ (0x00000001UL)
+
+#define VLAN1 (0x09UL) // R/W mask 0x0000FFFFUL
+#define VLAN2 (0x0AUL) // R/W mask 0x0000FFFFUL
+
+#define WUFF (0x0BUL) // WO
+
+#define WUCSR (0x0CUL) // R/W
+#define WUCSR_GUE_ (0x00000200UL)
+#define WUCSR_WUFR_ (0x00000040UL)
+#define WUCSR_MPR_ (0x00000020UL)
+#define WUCSR_WAKE_EN_ (0x00000004UL)
+#define WUCSR_MPEN_ (0x00000002UL)
+
+#define COE_CR 0xDUL
+#define TX_COE_EN 0x00010000UL
+#define RX_COE_MODE 0x00000002UL
+#define RX_COE_EN 0x00000001UL
+
+
+bool Mac_Initialize(PPRIVATE_DATA privateData);
+static bool MacNotBusy(PPRIVATE_DATA privateData,VL_KEY keyCode);
+u32 Mac_GetRegDW(PPRIVATE_DATA privateData,u32 dwRegOffset,VL_KEY keyCode);
+void Mac_SetRegDW(PPRIVATE_DATA privateData,u32 dwRegOffset,u32 dwVal,VL_KEY keyCode);
+
+/*
+ ****************************************************************************
+ * Chip Specific MII Defines
+ ****************************************************************************
+ *
+ * Phy register offsets and bit definitions
+ *
+ */
+#define LAN9118_PHY_ID (0x00C0001C)
+
+#define PHY_BCR ((u32)0U)
+#define PHY_BCR_RESET_ ((WORD)0x8000U)
+#define PHY_BCR_LOOPBACK_ ((WORD)0x4000U)
+#define PHY_BCR_SPEED_SELECT_ ((WORD)0x2000U)
+#define PHY_BCR_AUTO_NEG_ENABLE_ ((WORD)0x1000U)
+#define PHY_BCR_RESTART_AUTO_NEG_ ((WORD)0x0200U)
+#define PHY_BCR_DUPLEX_MODE_ ((WORD)0x0100U)
+
+#define PHY_BSR ((u32)1U)
+#define PHY_BSR_LINK_STATUS_ ((WORD)0x0004U)
+#define PHY_BSR_REMOTE_FAULT_ ((WORD)0x0010U)
+#define PHY_BSR_AUTO_NEG_COMP_ ((WORD)0x0020U)
+
+#define PHY_ID_1 ((u32)2U)
+#define PHY_ID_2 ((u32)3U)
+
+#define PHY_ANEG_ADV ((u32)4U)
+#define PHY_ANEG_ADV_PAUSE_ ((WORD)0x0C00)
+#define PHY_ANEG_ADV_ASYMP_ ((WORD)0x0800)
+#define PHY_ANEG_ADV_SYMP_ ((WORD)0x0400)
+#define PHY_ANEG_ADV_10H_ ((WORD)0x20)
+#define PHY_ANEG_ADV_10F_ ((WORD)0x40)
+#define PHY_ANEG_ADV_100H_ ((WORD)0x80)
+#define PHY_ANEG_ADV_100F_ ((WORD)0x100)
+#define PHY_ANEG_ADV_SPEED_ ((WORD)0x1E0)
+
+#define PHY_ANEG_LPA ((u32)5U)
+#define PHY_ANEG_LPA_ASYMP_ ((WORD)0x0800)
+#define PHY_ANEG_LPA_SYMP_ ((WORD)0x0400)
+#define PHY_ANEG_LPA_100FDX_ ((WORD)0x0100)
+#define PHY_ANEG_LPA_100HDX_ ((WORD)0x0080)
+#define PHY_ANEG_LPA_10FDX_ ((WORD)0x0040)
+#define PHY_ANEG_LPA_10HDX_ ((WORD)0x0020)
+
+#define PHY_MODE_CTRL_STS ((u32)17) // Mode Control/Status Register
+#define MODE_CTRL_STS_FASTRIP_ ((WORD)0x4000U)
+#define MODE_CTRL_STS_EDPWRDOWN_ ((WORD)0x2000U)
+#define MODE_CTRL_STS_LOWSQEN_ ((WORD)0x0800U)
+#define MODE_CTRL_STS_MDPREBP_ ((WORD)0x0400U)
+#define MODE_CTRL_STS_FARLOOPBACK_ ((WORD)0x0200U)
+#define MODE_CTRL_STS_FASTEST_ ((WORD)0x0100U)
+#define MODE_CTRL_STS_REFCLKEN_ ((WORD)0x0010U)
+#define MODE_CTRL_STS_PHYADBP_ ((WORD)0x0008U)
+#define MODE_CTRL_STS_FORCE_G_LINK_ ((WORD)0x0004U)
+#define MODE_CTRL_STS_ENERGYON_ ((WORD)0x0002U)
+
+#define SPECIAL_CTRL_STS ((u32)27)
+#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ ((WORD)0x8000U)
+#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ ((WORD)0x4000U)
+#define SPECIAL_CTRL_STS_AMDIX_STATE_ ((WORD)0x2000U)
+
+#define PHY_INT_SRC ((u32)29)
+#define PHY_INT_SRC_ENERGY_ON_ ((WORD)0x0080U)
+#define PHY_INT_SRC_ANEG_COMP_ ((WORD)0x0040U)
+#define PHY_INT_SRC_REMOTE_FAULT_ ((WORD)0x0020U)
+#define PHY_INT_SRC_LINK_DOWN_ ((WORD)0x0010U)
+
+#define PHY_INT_MASK ((u32)30)
+#define PHY_INT_MASK_ENERGY_ON_ ((WORD)0x0080U)
+#define PHY_INT_MASK_ANEG_COMP_ ((WORD)0x0040U)
+#define PHY_INT_MASK_REMOTE_FAULT_ ((WORD)0x0020U)
+#define PHY_INT_MASK_LINK_DOWN_ ((WORD)0x0010U)
+
+#define PHY_SPECIAL ((u32)31)
+#define PHY_SPECIAL_SPD_ ((WORD)0x001CU)
+#define PHY_SPECIAL_SPD_10HALF_ ((WORD)0x0004U)
+#define PHY_SPECIAL_SPD_10FULL_ ((WORD)0x0014U)
+#define PHY_SPECIAL_SPD_100HALF_ ((WORD)0x0008U)
+#define PHY_SPECIAL_SPD_100FULL_ ((WORD)0x0018U)
+
+#define AMDIX_DISABLE_STRAIGHT ((WORD)0x0U)
+#define AMDIX_DISABLE_CROSSOVER ((WORD)0x01U)
+#define AMDIX_ENABLE ((WORD)0x02U)
+
+bool Phy_Initialize(
+ PPRIVATE_DATA privateData,
+ u32 dwPhyAddress,
+ u32 dwLinkMode);
+void Phy_SetLink(PPRIVATE_DATA privateData,
+ u32 dwLinkRequest);
+WORD Phy_GetRegW(
+ PPRIVATE_DATA privateData,
+ u32 dwRegIndex,
+ VL_KEY keyCode);
+void Phy_SetRegW(
+ PPRIVATE_DATA privateData,
+ u32 dwRegIndex,
+ WORD wVal,
+ VL_KEY keyCode);
+void Phy_UpdateLinkMode(
+ PPRIVATE_DATA privateData);
+void Phy_GetLinkMode(
+ PPRIVATE_DATA privateData,
+ VL_KEY keyCode);
+void Phy_CheckLink(unsigned long ptr);
+void Phy_SetAutoMdixSts(PPRIVATE_DATA privateData,
+ WORD wAutoMdixSts);
+void Phy_GetAutoMdixSts(PPRIVATE_DATA privateData);
+
+
+
+
+
+TIME_SPAN Gpt_FreeRunCompare(u32 time1,u32 time2);
+void Gpt_ScheduleInterrupt(PPRIVATE_DATA privateData,TIME_SPAN timeSpan);
+void Gpt_CancelInterrupt(PPRIVATE_DATA privateData);
+void Gpt_CancelCallBack(
+ PPRIVATE_DATA privateData,
+ void (*callBackFunction)(PPRIVATE_DATA privateData));
+void Gpt_ScheduleCallBack(
+ PPRIVATE_DATA privateData,
+ void (*callBackFunction)(PPRIVATE_DATA privateData),
+ u32 callBackTime);//100uS units relative to now
+bool Gpt_HandleInterrupt(
+ PPRIVATE_DATA privateData,u32 dwIntSts);
+void GptCB_RxCompleteMulticast(PPRIVATE_DATA privateData);
+void GptCB_RestartBurst(PPRIVATE_DATA privateData);
+void GptCB_MeasureRxThroughput(PPRIVATE_DATA privateData);
+
+void Tx_Initialize(
+ PPRIVATE_DATA privateData,
+ u32 dwTxDmaCh,
+ u32 dwTxDmaThreshold);
+void Tx_SendSkb(
+ PPRIVATE_DATA privateData,
+ struct sk_buff *skb);
+bool Tx_HandleInterrupt(
+ PPRIVATE_DATA privateData,u32 dwIntSts);
+
+void Tx_StopQueue(
+ PPRIVATE_DATA privateData,u32 dwSource);
+void Tx_WakeQueue(
+ PPRIVATE_DATA privateData,u32 dwSource);
+
+static u32 Tx_GetTxStatusCount(
+ PPRIVATE_DATA privateData);
+static u32 Tx_CompleteTx(
+ PPRIVATE_DATA privateData);
+void Tx_UpdateTxCounters(
+ PPRIVATE_DATA privateData);
+
+void Tx_CompleteDma(
+ PPRIVATE_DATA privateData);
+
+void CalculateTxChecksumOffset(
+ struct sk_buff *skb,
+ int *csum_start_offset);
+
+void rkdump(unsigned char *p, unsigned short len);
+
+void Rx_Initialize(
+ PPRIVATE_DATA privateData,
+ u32 dwRxDmaCh,
+ u32 dwDmaThreshold);
+
+void Rx_CompleteMulticastUpdate (PPRIVATE_DATA privateData);
+static void Rx_HandleOverrun(PPRIVATE_DATA privateData);
+static void Rx_HandOffSkb(
+ PPRIVATE_DATA privateData,
+ struct sk_buff *skb);
+static u32 Rx_PopRxStatus(
+ PPRIVATE_DATA privateData);
+void Rx_CountErrors(PPRIVATE_DATA privateData,u32 dwRxStatus);
+void Rx_FastForward(PPRIVATE_DATA privateData,u32 dwDwordCount);
+void Rx_ProcessPackets(PPRIVATE_DATA privateData);
+void Rx_BeginMulticastUpdate (PPRIVATE_DATA privateData);
+
+unsigned long Rx_TaskletParameter=0;
+
+void Rx_ProcessPacketsTasklet(unsigned long data);
+DECLARE_TASKLET(Rx_Tasklet,Rx_ProcessPacketsTasklet,0);
+
+#ifdef LINUX_2_6_OR_NEWER
+int Smsc9118_rx_poll(struct net_device *dev,int * budget);
+#endif
+
+bool RxStop_HandleInterrupt(
+ PPRIVATE_DATA privateData,
+ u32 dwIntSts);
+bool Rx_HandleInterrupt(
+ PPRIVATE_DATA privateData,
+ u32 dwIntSts);
+static u32 Rx_Hash(BYTE addr[6]);
+
+void Rx_SetMulticastList(
+ struct net_device *dev);
+void Rx_ReceiverOff(
+ PPRIVATE_DATA privateData);
+void Rx_ReceiverOn(
+ PPRIVATE_DATA privateData, VL_KEY callerKeyCode);
+
+
+void Eeprom_EnableAccess(PPRIVATE_DATA privateData);
+void Eeprom_DisableAccess(PPRIVATE_DATA privateData);
+
+bool Eeprom_IsMacAddressLoaded(PPRIVATE_DATA privateData);
+bool Eeprom_IsBusy(PPRIVATE_DATA privateData);
+bool Eeprom_Timeout(PPRIVATE_DATA privateData);
+
+bool Eeprom_ReadLocation(
+ PPRIVATE_DATA privateData,BYTE address, BYTE * data);
+bool Eeprom_EnableEraseAndWrite(
+ PPRIVATE_DATA privateData);
+bool Eeprom_DisableEraseAndWrite(
+ PPRIVATE_DATA privateData);
+bool Eeprom_WriteLocation(
+ PPRIVATE_DATA privateData,BYTE address,BYTE data);
+bool Eeprom_EraseAll(
+ PPRIVATE_DATA privateData);
+bool Eeprom_Reload(
+ PPRIVATE_DATA privateData);
+
+bool Eeprom_SaveMacAddress(
+ PPRIVATE_DATA privateData,
+ u32 dwHi16,u32 dwLo32);
+
+
+#define OLD_REGISTERS(privData) (((privData->dwIdRev)==0x01180000UL)&& \
+ ((privData->dwFpgaRev)>=0x01)&& \
+ ((privData->dwFpgaRev)<=0x25))
+
+extern volatile u32 g_GpioSetting;
+#define GP_0 (0x01UL)
+#define GP_1 (0x02UL)
+#define GP_2 (0x04UL)
+#define GP_3 (0x08UL)
+#define GP_4 (0x10UL)
+#define GP_OFF (0x00UL)
+#define GP_ISR GP_OFF
+#define GP_RX GP_OFF
+#define GP_TX GP_OFF
+#define GP_BEGIN_MULTICAST_UPDATE GP_OFF
+#define GP_COMPLETE_MULTICAST_UPDATE GP_OFF
+
+#define SET_GPIO(gpioBit) \
+ if(debug_mode&0x04UL) { \
+ g_GpioSetting|=gpioBit; \
+ Lan_SetRegDW(GPIO_CFG,g_GpioSetting); \
+ }
+
+#define CLEAR_GPIO(gpioBit) \
+ if(debug_mode&0x04UL) { \
+ g_GpioSetting&=(~gpioBit); \
+ Lan_SetRegDW(GPIO_CFG,g_GpioSetting); \
+ }
+
+#define PULSE_GPIO(gpioBit,count) \
+ if(debug_mode&0x04UL) { \
+ u32 pulseNum=0; \
+ /*make first pulse longer */ \
+ SET_GPIO(gpioBit); \
+ while(pulseNum<count) { \
+ SET_GPIO(gpioBit); \
+ CLEAR_GPIO(gpioBit); \
+ pulseNum++; \
+ } \
+ }
+#ifdef USE_LED1_WORK_AROUND
+volatile u32 g_GpioSettingOriginal;
+#endif
+
+bool Lan_Initialize(
+ PPRIVATE_DATA privateData,u32 dwIntCfg,
+ u32 dwTxFifSz,u32 dwAfcCfg);
+void Lan_EnableInterrupt(PPRIVATE_DATA privateData,u32 dwIntEnMask);
+void Lan_DisableInterrupt(PPRIVATE_DATA privateData,u32 dwIntEnMask);
+void Lan_EnableIRQ(PPRIVATE_DATA privateData);
+void Lan_DisableIRQ(PPRIVATE_DATA privateData);
+void Lan_SetIntDeas(PPRIVATE_DATA privateData,u32 dwIntDeas);
+void Lan_SetTDFL(PPRIVATE_DATA privateData,BYTE level);
+void Lan_SetTSFL(PPRIVATE_DATA privateData,BYTE level);
+void Lan_SetRDFL(PPRIVATE_DATA privateData,BYTE level);
+void Lan_SetRSFL(PPRIVATE_DATA privateData,BYTE level);
+
+void Lan_SignalSoftwareInterrupt(PPRIVATE_DATA privateData);
+bool Lan_HandleSoftwareInterrupt(PPRIVATE_DATA privateData,u32 dwIntSts);
+
+void Lan_ShowRegs(PPRIVATE_DATA privateData);
+
+#include "ioctl_118.h"
+
+static u32 lan_base=0x0UL;
+module_param(lan_base, int, S_IRUGO);
+MODULE_PARM_DESC(lan_base,"Base Address of LAN9118, (default: choosen by platform code)");
+
+static u32 bus_width=0UL;
+module_param(bus_width, int, S_IRUGO);
+MODULE_PARM_DESC(bus_width,"Force bus width of 16 or 32 bits, default: autodetect");
+
+static u32 link_mode=0x7FUL;
+module_param(link_mode, int, S_IRUGO);
+MODULE_PARM_DESC(link_mode,"Set Link speed and Duplex, 1=10HD,2=10FD,4=100HD,8=100FD,default=0xF");
+
+static u32 AutoMdix=0x3U;
+module_param(AutoMdix, int, S_IRUGO);
+MODULE_PARM_DESC(AutoMdix,"Set Auto-MDIX state, 0=StraightCable,1=CrossOver,2=Enable AMDIX,3=controlled by Strap");
+
+static u32 irq=PLATFORM_IRQ;
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq,"Force use of specific IRQ, (default: choosen by platform code)");
+
+static u32 int_deas=0xFFFFFFFFUL;
+module_param(int_deas, int, S_IRUGO);
+MODULE_PARM_DESC(int_deas,"Interrupt Deassertion Interval in 10uS units");
+
+static u32 irq_pol=PLATFORM_IRQ_POL;
+module_param(irq_pol, int, S_IRUGO);
+MODULE_PARM_DESC(irq_pol,"IRQ Polarity bit, see definition of INT_CFG register");
+
+static u32 irq_type=PLATFORM_IRQ_TYPE;
+module_param(irq_type, int, S_IRUGO);
+MODULE_PARM_DESC(irq_type,"IRQ Buffer Type bit, see definition of INT_CFG register");
+
+static u32 rx_dma=PLATFORM_RX_DMA;
+module_param(rx_dma, int, S_IRUGO);
+MODULE_PARM_DESC(rx_dma,"Receiver DMA Channel, 255=find available channel, 256=use PIO");
+
+static u32 tx_dma=PLATFORM_TX_DMA;
+module_param(tx_dma, int, S_IRUGO);
+MODULE_PARM_DESC(tx_dma,"Transmitter DMA Channel, 255=find available channel, 256=use PIO");
+
+static u32 dma_threshold=PLATFORM_DMA_THRESHOLD;
+module_param(dma_threshold, int, S_IRUGO);
+MODULE_PARM_DESC(dma_threshold,"Specifies the minimum packet size for DMA to be used.");
+
+static u32 mac_addr_hi16=0xFFFFFFFF;
+module_param(mac_addr_hi16, int, S_IRUGO);
+MODULE_PARM_DESC(mac_addr_hi16,"Specifies the high 16 bits of the mac address");
+
+static u32 mac_addr_lo32=0xFFFFFFFF;
+module_param(mac_addr_lo32, int, S_IRUGO);
+MODULE_PARM_DESC(mac_addr_lo32,"Specifies the low 32 bits of the mac address");
+
+module_param(debug_mode, int, S_IRUGO);
+MODULE_PARM_DESC(debug_mode,"bit 0 enables trace points, bit 1 enables warning points, bit 2 enables gpios");
+
+static u32 tx_fif_sz=0x00050000UL;
+module_param(tx_fif_sz, int, S_IRUGO);
+MODULE_PARM_DESC(tx_fif_sz,"Specifies TX_FIF_SZ of the HW_CFG register");
+
+static u32 afc_cfg=0xFFFFFFFFUL;
+module_param(afc_cfg, int, S_IRUGO);
+MODULE_PARM_DESC(afc_cfg,"Specifies the setting for the AFC_CFG register");
+
+//static u32 tasklets=1UL;
+//module_param(tasklets, int, S_IRUGO);
+//MODULE_PARM_DESC(tasklets,"non-zero== use tasklets for receiving packets, zero==receive packets in ISR");
+
+#define PROCESSING_MODE_IDLE (0UL)
+#define PROCESSING_MODE_TASKLET (1UL)
+#define PROCESSING_MODE_NAPI (2UL)
+
+
+static u32 rx_mode=PROCESSING_MODE_TASKLET;
+module_param(rx_mode, int, S_IRUGO);
+MODULE_PARM_DESC(rx_mode,"0==use ISR, 1==use Rx Tasklet, 2==use NAPI");
+
+#ifdef LINUX_2_6_OR_NEWER
+static u32 napi_weight=4UL;
+module_param(napi_weight, int, S_IRUGO);
+MODULE_PARM_DESC(napi_weight,"The weight value to use if NAPI is used");
+#endif
+
+
+
+static u32 phy_addr=0xFFFFFFFFUL;
+module_param(phy_addr, int, S_IRUGO);
+MODULE_PARM_DESC(phy_addr,"phy_addr, 0xFFFFFFFF=use interal phy, 0-31=use external phy with specified address, else autodetect external phy addr");
+
+static u32 max_throughput=0xFFFFFFFFUL;
+module_param(max_throughput, int, S_IRUGO);
+MODULE_PARM_DESC(max_throughput,"See readme.txt");
+
+static u32 max_packet_count=0xFFFFFFFFUL;
+module_param(max_packet_count, int, S_IRUGO);
+MODULE_PARM_DESC(max_packet_count,"See Readme.txt");
+
+static u32 packet_cost=0xFFFFFFFFUL;
+module_param(packet_cost, int, S_IRUGO);
+MODULE_PARM_DESC(packet_cost,"See Readme.txt");
+
+static u32 burst_period=0xFFFFFFFFUL;
+module_param(burst_period, int, S_IRUGO);
+MODULE_PARM_DESC(burst_period,"See Readme.txt");
+
+static u32 max_work_load=0xFFFFFFFFUL;
+module_param(max_work_load, int, S_IRUGO);
+MODULE_PARM_DESC(max_work_load,"See Readme.txt");
+
+static int Scatter_gather=false;
+module_param(Scatter_gather, bool, S_IRUGO);
+MODULE_PARM_DESC(Scatter_gather,"Enable Scatter Gather");
+
+static int tx_Csum=false;
+module_param(tx_Csum, bool, S_IRUGO);
+MODULE_PARM_DESC(tx_Csum,"Enable Tx Hardware Checksum Offload");
+
+static int rx_Csum=false;
+module_param(rx_Csum, bool, S_IRUGO);
+MODULE_PARM_DESC(rx_Csum,"Enable Rx Hardware Checksum Offload");
+
+/* The three parameters below are used for the new unkonw chip before we formally add them in the driver
+ So that in the future we can just immediately support chips with new IDs by passing the new id and timing at load time.
+ But we still need to add the supported new Chip id and the flow control parameters formally later.
+ */
+static u32 id_reg=0x0UL;
+module_param(id_reg, int, S_IRUGO);
+MODULE_PARM_DESC(id_reg,"Chip Id");
+
+static u32 bus_timing=0UL;
+module_param(bus_timing, int, S_IRUGO);
+MODULE_PARM_DESC(bus_timing,"bus timing");
+
+
+static int Csum_Support=false;
+module_param(Csum_Support, int, S_IRUGO);
+MODULE_PARM_DESC(Csum_Support,"The chip has the ability of Checksum offload");
+
+
+MODULE_LICENSE("GPL");
+
+int Smsc9118_init_module(void);
+void Smsc9118_cleanup_module(void);
+void Smsc9118_init(struct net_device *dev);
+int Smsc9118_open(struct net_device *dev);
+int Smsc9118_stop(struct net_device *dev);
+int Smsc9118_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
+struct net_device_stats * Smsc9118_get_stats(struct net_device *dev);
+void Smsc9118_set_multicast_list(struct net_device *dev);
+int Smsc9118_private_ioctl(PPRIVATE_DATA privateData,void *useraddr);
+int Smsc9118_ethtool_ioctl(PPRIVATE_DATA privateData, void * userAddr);
+int Smsc9118_do_ioctl(struct net_device *dev, struct ifreq *ifr,int cmd);
+irqreturn_t Smsc9118_ISR(int irq,void *dev_id);
+
+#ifdef USING_LINT
+//struct net_device SMSC9118;
+#else //not USING_LINT
+/* KH: Don't initialize here. */
+/* struct net_device SMSC9118 = {init: Smsc9118_init,}; */
+struct net_device *SMSC9118;
+#endif //not USING_LINT
+
+int Smsc9118_init_module(void)
+{
+ int result=0;
+ int device_present=0;
+
+ SMSC_TRACE("--> init_module()");
+ SMSC_TRACE("Compiled: %s, %s",__DATE__,__TIME__);
+ SMSC_TRACE("Platform: %s",PLATFORM_NAME);
+ SMSC_TRACE("Driver Parameters");
+
+ if(lan_base==0UL) {
+ SMSC_TRACE(" lan_base = 0x%08X, driver will decide",lan_base);
+ } else {
+ SMSC_TRACE(" lan_base = 0x%08X",lan_base);
+ }
+ if((bus_width==16UL)||(bus_width==32UL)) {
+ SMSC_TRACE(" bus_width = %d",bus_width);
+ } else {
+ SMSC_TRACE(" bus_width = %d, driver will autodetect",bus_width);
+ }
+ if(link_mode>0x7FUL) {
+ SMSC_WARNING(" link_mode = %d, Unknown",link_mode);
+ link_mode=0x7FUL;
+ SMSC_WARNING(" resetting link_mode to %d, 100FD,100HD,10FD,10HD,ASYMP,SYMP,ANEG",link_mode);
+ } else if(link_mode==0UL) {
+ SMSC_TRACE(" link_mode = %d, LINK_OFF",link_mode);
+ } else {
+ SMSC_TRACE(" link_mode = 0x%X, %s,%s,%s,%s,%s,%s,%s",
+ link_mode,
+ (link_mode&LINK_SPEED_10HD)?"10HD":"",
+ (link_mode&LINK_SPEED_10FD)?"10FD":"",
+ (link_mode&LINK_SPEED_100HD)?"100HD":"",
+ (link_mode&LINK_SPEED_100FD)?"100FD":"",
+ (link_mode&LINK_ASYMMETRIC_PAUSE)?"ASYMP":"",
+ (link_mode&LINK_SYMMETRIC_PAUSE)?"SYMP":"",
+ (link_mode&LINK_AUTO_NEGOTIATE)?"ANEG":"");
+ }
+ SMSC_TRACE( " irq = %d",irq);
+ if(int_deas!=0xFFFFFFFFUL) {
+ if(int_deas>0xFFUL) {
+ SMSC_WARNING(" int_deas = %d, too high",int_deas);
+ int_deas=0xFFFFFFFFUL;
+ SMSC_WARNING(" resetting int_deas to %d",int_deas);
+ }
+ }
+ if(int_deas==0xFFFFFFFFUL) {
+ SMSC_TRACE( " int_deas = 0x%08X, use platform default",int_deas);
+ } else {
+ SMSC_TRACE( " int_deas = %d, %duS",int_deas,(unsigned int)(10UL*int_deas));
+ }
+ if(irq_pol) {
+ SMSC_TRACE(" irq_pol = %d, IRQ output is active high",irq_pol);
+ } else {
+ SMSC_TRACE(" irq_pol = %d, IRQ output is active low",irq_pol);
+ }
+ if(irq_type) {
+ SMSC_TRACE(" irq_type = %d, IRQ output is Push-Pull driver",irq_type);
+ } else {
+ SMSC_TRACE(" irq_type = %d, IRQ output is Open-Drain buffer",irq_type);
+ }
+ if(rx_dma<TRANSFER_REQUEST_DMA) {
+ if(Platform_IsValidDmaChannel(rx_dma)) {
+ SMSC_TRACE(
+ " rx_dma = %d, DMA Channel %d",rx_dma,rx_dma);
+ } else {
+ SMSC_WARNING(" rx_dma = %d, Invalid Dma Channel",rx_dma);
+ rx_dma=TRANSFER_PIO;
+ SMSC_WARNING(" resetting rx_dma to %d, RX will use PIO",rx_dma);
+ }
+ } else if(rx_dma==TRANSFER_REQUEST_DMA) {
+ SMSC_TRACE(" rx_dma = %d, RX will try to find available channel",rx_dma);
+ } else {
+ SMSC_TRACE(" rx_dma = %d, RX will use PIO",rx_dma);
+ }
+ if(tx_dma<TRANSFER_REQUEST_DMA) {
+ if(Platform_IsValidDmaChannel(tx_dma)) {
+ if(tx_dma!=rx_dma) {
+ SMSC_TRACE(
+ " tx_dma = %d, DMA Channel %d",tx_dma,tx_dma);
+ } else {
+ SMSC_WARNING(" tx_dma == rx_dma");
+ tx_dma=TRANSFER_PIO;
+ SMSC_WARNING(" resetting tx_dma to %d, TX will use PIO",tx_dma);
+ }
+ } else {
+ SMSC_WARNING(" tx_dma = %d, Invalid Dma Channel",tx_dma);
+ tx_dma=TRANSFER_PIO;
+ SMSC_WARNING(" resetting tx_dma to %d, TX will use PIO",tx_dma);
+ }
+ } else if(tx_dma==TRANSFER_REQUEST_DMA) {
+ SMSC_TRACE(" tx_dma = %d, TX will try to find available channel",tx_dma);
+ } else {
+ SMSC_TRACE(" tx_dma = %d, TX will use PIO",tx_dma);
+ }
+ SMSC_TRACE( " dma_threshold = %d",dma_threshold);
+
+ if(mac_addr_hi16==0xFFFFFFFFUL) {
+ SMSC_TRACE(" mac_addr_hi16 = 0x%08X, will attempt to read from LAN9118",mac_addr_hi16);
+ SMSC_TRACE(" mac_addr_lo32 = 0x%08X, will attempt to read from LAN9118",mac_addr_lo32);
+ } else {
+ if(mac_addr_hi16&0xFFFF0000UL) {
+ //The high word is reserved
+ SMSC_WARNING(" mac_addr_hi16 = 0x%08X, reserved bits are high.",mac_addr_hi16);
+ mac_addr_hi16&=0x0000FFFFUL;
+ SMSC_WARNING(" reseting to mac_addr_hi16 = 0x%08X",mac_addr_hi16);
+ }
+ if(mac_addr_lo32&0x00000001UL) {
+ //bit 0 is the I/G bit
+ SMSC_WARNING(" mac_addr_lo32 = 0x%08X, I/G bit is set.",mac_addr_lo32);
+ mac_addr_lo32&=0xFFFFFFFEUL;
+ SMSC_WARNING(" reseting to mac_addr_lo32 = 0x%08X",mac_addr_lo32);
+ }
+ SMSC_TRACE(" mac_addr_hi16 = 0x%08X",mac_addr_hi16);
+ SMSC_TRACE(" mac_addr_lo32 = 0x%08X",mac_addr_lo32);
+ }
+ SMSC_TRACE( " debug_mode = 0x%08X",debug_mode);
+ if(tx_fif_sz&(~HW_CFG_TX_FIF_SZ_)) {
+ SMSC_WARNING("tx_fif_sz = 0x%08X is invalid",tx_fif_sz);
+ tx_fif_sz&=HW_CFG_TX_FIF_SZ_;
+ SMSC_WARNING(" resetting tx_fif_sz to 0x%08X",tx_fif_sz);
+ }
+ if(tx_fif_sz>0x000E0000UL) {
+ SMSC_WARNING("tx_fif_sz = 0x%08X is too high",tx_fif_sz);
+ tx_fif_sz=0x000E0000UL;
+ SMSC_WARNING(" resetting tx_fif_sz to 0x%08X",tx_fif_sz);
+ }
+ if(tx_fif_sz<0x00020000UL) {
+ SMSC_WARNING("tx_fif_sz = 0x%08X is too low",tx_fif_sz);
+ tx_fif_sz=0x00020000UL;
+ SMSC_WARNING(" resetting tx_fif_sz to 0x%08X",tx_fif_sz);
+ }
+ SMSC_TRACE( " tx_fif_sz = 0x%08X",tx_fif_sz);
+ if(afc_cfg==0xFFFFFFFFUL) {
+ SMSC_TRACE(" afc_cfg = 0x%08X, driver will decide",afc_cfg);
+ } else {
+ if(afc_cfg&0xFF000000UL) {
+ SMSC_WARNING("afc_cfg = 0x%08X is invalid",afc_cfg);
+ afc_cfg&=0xFFFFFFFFUL;
+ SMSC_WARNING(" resetting to afc_cfg = 0x%08X, driver will decide",afc_cfg);
+ } else {
+ SMSC_TRACE(
+ " afc_cfg = 0x%08X",afc_cfg);
+ }
+ }
+ if(rx_mode==PROCESSING_MODE_TASKLET) {
+ SMSC_TRACE(" rx_mode = 0x%08X, Tasklets enabled",rx_mode);
+ } else if(rx_mode==PROCESSING_MODE_NAPI) {
+#ifndef LINUX_2_6_OR_NEWER
+ SMSC_WARNING(" rx_mode = 0x%08X requires Linux 2.6 or newer", rx_mode);
+ rx_mode=PROCESSING_MODE_TASKLET;
+ SMSC_WARNING(" resetting to rx_mode = 0x%08X, Tasklets enabled", rx_mode);
+#else
+ SMSC_TRACE(" rx_mode = 0x%08X, NAPI enabled",rx_mode);
+#endif
+ } else {
+ SMSC_TRACE(" rx_mode = 0, use ISR");
+ }
+
+ if(phy_addr==0xFFFFFFFFUL) {
+ SMSC_TRACE(" phy_addr = 0xFFFFFFFF, Use internal phy");
+ } else if(phy_addr<=31UL) {
+ SMSC_TRACE(" phy_addr = 0x%08X, use this address for external phy",phy_addr);
+ } else {
+ SMSC_TRACE(" phy_addr = 0x%08X, auto detect external phy",phy_addr);
+ }
+ if(max_throughput) {
+ SMSC_TRACE(" max_throughput = 0x%08X, Use platform default",max_throughput);
+ } else {
+ SMSC_TRACE(" max_throughput = 0x%08X",max_throughput);
+ }
+ if(max_packet_count) {
+ SMSC_TRACE(" max_packet_count = 0x%08X, Use platform default",max_packet_count);
+ } else {
+ SMSC_TRACE(" max_packet_count = 0x%08X",max_packet_count);
+ }
+ if(packet_cost) {
+ SMSC_TRACE(" packet_cost = 0x%08X, Use platform default",packet_cost);
+ } else {
+ SMSC_TRACE(" packet_cost = 0x%08X",packet_cost);
+ }
+ if(burst_period) {
+ SMSC_TRACE(" burst_period = 0x%08X, Use platform default",burst_period);
+ } else {
+ SMSC_TRACE(" burst_period = 0x%08X",burst_period);
+ }
+ if(max_work_load) {
+ SMSC_TRACE(" max_work_load = 0x%08X, Use platform default",max_work_load);
+ } else {
+ SMSC_TRACE(" max_work_load = 0x%08X",max_work_load);
+ }
+
+ SMSC9118 = alloc_netdev_mq(0, "eth%d", Smsc9118_init, 1);
+ SMSC_TRACE(" alloc_netdev complete. SMSC9118 = 0x%08X\n", (u32)SMSC9118);
+ result=register_netdev(SMSC9118);
+ if(result) {
+ SMSC_WARNING("error %i registering device",result);
+ } else {
+ device_present=1;
+ SMSC_TRACE(" Interface Name = \"%s\"",SMSC9118->name);
+ }
+ result=result;//make lint happy
+ SMSC_TRACE("<-- init_module()");
+ return device_present ? 0 : -ENODEV;
+}
+
+void Smsc9118_cleanup_module(void)
+{
+ SMSC_TRACE("--> cleanup_module()");
+ if(SMSC9118->ml_priv!=NULL) {
+ PPRIVATE_DATA privateData=(PPRIVATE_DATA)SMSC9118->ml_priv;
+ PPLATFORM_DATA platformData=(PPLATFORM_DATA)&(privateData->PlatformData);
+ Platform_CleanUp(platformData);
+ kfree(SMSC9118->ml_priv);
+ SMSC9118->ml_priv=NULL;
+ }
+ unregister_netdev(SMSC9118);
+ SMSC_TRACE("<-- cleanup_module()");
+}
+
+void Smsc9118_init(struct net_device *dev)
+{
+ u32 dwLanBase=0UL;
+ u32 dwIdRev=0UL;
+ u32 dwFpgaRev=0UL;
+ // WORD SpecialCtrlSts=0U;
+ PPRIVATE_DATA privateData=NULL;
+ PPLATFORM_DATA platformData=NULL;
+ bool platformInitialized=false;
+ int result=-ENODEV;
+
+ int i;
+ bool acquired_mem_region=false;
+ bool acquired_isr=false;
+
+ SMSC_TRACE("-->Smsc9118_init(dev=0x%08X)",(u32)dev);
+
+ if(dev==NULL) {
+ SMSC_WARNING("Smsc9118_init(dev==NULL)");
+ result=-EFAULT;
+ goto DONE;
+ }
+
+ if(dev->ml_priv!=NULL) {
+ SMSC_WARNING("dev->ml_priv!=NULL, going to overwrite pointer");
+ }
+ dev->ml_priv=kmalloc(sizeof(PRIVATE_DATA),GFP_KERNEL);
+ if(dev->ml_priv==NULL) {
+ SMSC_WARNING("Unable to allocate PRIVATE_DATA");
+ result=-ENOMEM;
+ goto DONE;
+ }
+ memset(dev->ml_priv,0,sizeof(PRIVATE_DATA));
+ privateData=(PPRIVATE_DATA)(dev->ml_priv);
+ platformData=&(privateData->PlatformData);
+
+ dwLanBase=Platform_Initialize(
+ platformData,
+ lan_base,bus_width);
+
+ if(dwLanBase==0UL) {
+ SMSC_WARNING("dwLanBase==0x00000000");
+ result=-ENODEV;
+ goto DONE;
+ }
+ platformInitialized=true;
+ SMSC_TRACE("dwLanBase=0x%08X",dwLanBase);
+
+ if(check_mem_region(dwLanBase,LAN_REGISTER_EXTENT)!=0) {
+ SMSC_WARNING(" Memory Region specified (0x%08X to 0x%08X) is not available.",
+ dwLanBase,(u32)(dwLanBase+LAN_REGISTER_EXTENT-1UL));
+ result=-ENOMEM;
+ goto DONE;
+ }
+
+ privateData->dwLanBase=dwLanBase;
+ dwIdRev=Lan_GetRegDW(ID_REV);
+ if(HIWORD(dwIdRev)==LOWORD(dwIdRev)) {
+ //this may mean the chip is set for 32 bit
+ // while the bus is reading as 16 bit
+UNKNOWN_CHIP:
+ SMSC_WARNING(" LAN9118 Family NOT Identified, dwIdRev==0x%08X",dwIdRev);
+ result=-ENODEV;
+ goto DONE;
+ }
+ switch(dwIdRev&0xFFFF0000UL) {
+
+ case 0x93120000UL:
+ if (Scatter_gather | tx_Csum | rx_Csum)
+ SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
+ privateData->UseScatterGather=false;
+ privateData->UseTxCsum=false;
+ privateData->UseRxCsum=false;
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 1UL:
+ SMSC_TRACE(" Hydra identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=3;
+ break;
+ default:
+ SMSC_TRACE(" Hydra identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=3;
+ break;
+ };break;
+
+
+ case 0x01180000UL:
+ if (Scatter_gather | tx_Csum | rx_Csum)
+ SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
+ privateData->UseScatterGather=false;
+ privateData->UseTxCsum=false;
+ privateData->UseRxCsum=false;
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9118 Beacon identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=0;
+ break;
+ case 1UL:
+ SMSC_TRACE(" LAN9118 Concord A0 identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=1;
+ break;
+ case 2UL:
+ SMSC_TRACE(" LAN9118 Concord A1 identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=2;
+ break;
+ default:
+ SMSC_TRACE(" LAN9118 Concord A1 identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=2;
+ break;
+ };break;
+
+ case 0x01170000UL:
+ if (Scatter_gather | tx_Csum | rx_Csum)
+ SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
+ privateData->UseScatterGather=false;
+ privateData->UseTxCsum=false;
+ privateData->UseRxCsum=false;
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9117 Beacon identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=0;
+ break;
+ case 1UL:
+ SMSC_TRACE(" LAN9117 Concord A0 identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=1;
+ break;
+ case 2UL:
+ SMSC_TRACE(" LAN9117 Concord A1 identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=2;
+ break;
+ default:
+ SMSC_TRACE(" LAN9117 Concord A1 identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=2;
+ break;
+ };break;
+
+ case 0x01160000UL:
+ if (Scatter_gather | tx_Csum | rx_Csum)
+ SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
+ privateData->UseScatterGather=false;
+ privateData->UseTxCsum=false;
+ privateData->UseRxCsum=false;
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ goto UNKNOWN_CHIP;
+ case 1UL:
+ SMSC_TRACE(" LAN9116 Concord A0 identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=1;
+ break;
+ case 2UL:
+ SMSC_TRACE(" LAN9116 Concord A1 identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=2;
+ break;
+ default:
+ SMSC_TRACE(" LAN9116 Concord A1 identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=2;
+ break;
+ };break;
+
+ case 0x01150000UL:
+ if (Scatter_gather | tx_Csum | rx_Csum)
+ SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
+ privateData->UseScatterGather=false;
+ privateData->UseTxCsum=false;
+ privateData->UseRxCsum=false;
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ goto UNKNOWN_CHIP;
+ case 1UL:
+ SMSC_TRACE(" LAN9115 Concord A0 identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=1;
+ break;
+ case 2UL:
+ SMSC_TRACE(" LAN9115 Concord A1 identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=2;
+ break;
+ default:
+ SMSC_TRACE(" LAN9115 Concord A1 identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=2;
+ break;
+ };break;
+
+ case 0x118A0000UL:
+ if (Scatter_gather | tx_Csum | rx_Csum)
+ SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
+ privateData->UseScatterGather=false;
+ privateData->UseTxCsum=false;
+ privateData->UseRxCsum=false;
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9218 Boylston identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=3;
+ break;
+ default:
+ SMSC_TRACE(" LAN9218 Boylston identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=3;
+ break;
+ };break;
+
+ case 0x117A0000UL:
+ if (Scatter_gather | tx_Csum | rx_Csum)
+ SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
+ privateData->UseScatterGather=false;
+ privateData->UseTxCsum=false;
+ privateData->UseRxCsum=false;
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9217 Boylston identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=3;
+ break;
+ default:
+ SMSC_TRACE(" LAN9217 Boylston identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=3;
+ break;
+ };break;
+
+ case 0x116A0000UL:
+ if (Scatter_gather | tx_Csum | rx_Csum)
+ SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
+ privateData->UseScatterGather=false;
+ privateData->UseTxCsum=false;
+ privateData->UseRxCsum=false;
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9216 Boylston identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=3;
+ break;
+ default:
+ SMSC_TRACE(" LAN9216 Boylston identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=3;
+ break;
+ };break;
+
+ case 0x115A0000UL:
+ if (Scatter_gather | tx_Csum | rx_Csum)
+ SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
+ privateData->UseScatterGather=false;
+ privateData->UseTxCsum=false;
+ privateData->UseRxCsum=false;
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9215 Boylston identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=3;
+ break;
+ default:
+ SMSC_TRACE(" LAN9215 Boylston identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=3;
+ break;
+ };break;
+
+
+ case 0x92100000UL:
+ privateData->UseScatterGather=Scatter_gather;
+ privateData->UseTxCsum=tx_Csum;
+ privateData->UseRxCsum=rx_Csum;
+ if (Scatter_gather)
+ SMSC_TRACE(" Tx Scatter-Gather");
+ if (tx_Csum)
+ SMSC_TRACE(" Tx HW Checksum");
+ if (rx_Csum)
+ SMSC_TRACE(" Rx HW Checksum");
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9210 Boylston Lite identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+
+ default:
+ SMSC_TRACE(" LAN9210 Boylston Lite identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+ };break;
+
+ case 0x92110000UL:
+ privateData->UseScatterGather=Scatter_gather;
+ privateData->UseTxCsum=tx_Csum;
+ privateData->UseRxCsum=rx_Csum;
+ if (Scatter_gather)
+ SMSC_TRACE(" Tx Scatter-Gather");
+ if (tx_Csum)
+ SMSC_TRACE(" Tx HW Checksum");
+ if (rx_Csum)
+ SMSC_TRACE(" Rx HW Checksum");
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9211 Boylston Lite identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+
+ default:
+ SMSC_TRACE(" LAN9211 Boylston Lite identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+ };break;
+
+ case 0x215A0000UL:
+ privateData->UseScatterGather=Scatter_gather;
+ privateData->UseTxCsum=tx_Csum;
+ privateData->UseRxCsum=rx_Csum;
+ if (Scatter_gather)
+ SMSC_TRACE(" Tx Scatter-Gather");
+ if (tx_Csum)
+ SMSC_TRACE(" Tx HW Checksum");
+ if (rx_Csum)
+ SMSC_TRACE(" Rx HW Checksum");
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9215A Boylston Auto identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+
+ default:
+ SMSC_TRACE(" LAN9215A Boylston Auto identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+ };break;
+
+ case 0x216A0000UL:
+ privateData->UseScatterGather=Scatter_gather;
+ privateData->UseTxCsum=tx_Csum;
+ privateData->UseRxCsum=rx_Csum;
+ if (Scatter_gather)
+ SMSC_TRACE(" Tx Scatter-Gather");
+ if (tx_Csum)
+ SMSC_TRACE(" Tx HW Checksum");
+ if (rx_Csum)
+ SMSC_TRACE(" Rx HW Checksum");
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9216A Boylston Auto identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+
+ default:
+ SMSC_TRACE(" LAN9216A Boylston Auto identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+ };break;
+
+ case 0x217A0000UL:
+ privateData->UseScatterGather=Scatter_gather;
+ privateData->UseTxCsum=tx_Csum;
+ privateData->UseRxCsum=rx_Csum;
+ if (Scatter_gather)
+ SMSC_TRACE(" Tx Scatter-Gather");
+ if (tx_Csum)
+ SMSC_TRACE(" Tx HW Checksum");
+ if (rx_Csum)
+ SMSC_TRACE(" Rx HW Checksum");
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9217A Boylston Auto identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+
+ default:
+ SMSC_TRACE(" LAN9217A Boylston Auto identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+ };break;
+
+
+ case 0x218A0000UL:
+ privateData->UseScatterGather=Scatter_gather;
+ privateData->UseTxCsum=tx_Csum;
+ privateData->UseRxCsum=rx_Csum;
+ if (Scatter_gather)
+ SMSC_TRACE(" Tx Scatter-Gather");
+ if (tx_Csum)
+ SMSC_TRACE(" Tx HW Checksum");
+ if (rx_Csum)
+ SMSC_TRACE(" Rx HW Checksum");
+
+ switch(dwIdRev&0x0000FFFFUL) {
+ case 0UL:
+ SMSC_TRACE(" LAN9218A Boylston Auto identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+
+ default:
+ SMSC_TRACE(" LAN9218A Boylston Auto identified (NEW), dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=4;
+ break;
+ };break;
+
+ default:
+ //This is used for the new unkonw chip before we formally add them in the driver
+ if (id_reg==dwIdRev) {
+ if (Csum_Support) {
+ privateData->UseScatterGather=Scatter_gather;
+ privateData->UseTxCsum=tx_Csum;
+ privateData->UseRxCsum=rx_Csum;
+ } else {
+ SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
+ privateData->UseScatterGather=false;
+ privateData->UseTxCsum=false;
+ privateData->UseRxCsum=false;
+ }
+
+ SMSC_TRACE(" New Chip identified, dwIdRev==0x%08X",dwIdRev);
+ privateData->dwGeneration=5;
+
+ } else {
+
+ SMSC_WARNING("unknow chip, dwIdRev==0x%08X",dwIdRev);
+
+ }; break;
+
+
+ }
+
+ //printk("dwGeneration = %d\n", privateData->dwGeneration);
+
+ dwFpgaRev=Lan_GetRegDW(FPGA_REV);
+ SMSC_TRACE(" FPGA_REV == 0x%08X",dwFpgaRev);
+
+
+ ether_setup(dev);
+ dev->open= Smsc9118_open;
+ dev->stop= Smsc9118_stop;
+ dev->hard_start_xmit= Smsc9118_hard_start_xmit;
+ dev->get_stats= Smsc9118_get_stats;
+ dev->do_ioctl= Smsc9118_do_ioctl;
+ dev->set_multicast_list=Smsc9118_set_multicast_list;
+ dev->flags|=IFF_MULTICAST;
+#ifdef LINUX_2_6_OR_NEWER
+ /*
+ if (rx_mode==PROCESSING_MODE_NAPI) {
+ dev->poll=Smsc9118_rx_poll;
+ dev->weight=napi_weight;
+ }
+ */
+#endif
+ if(privateData->UseScatterGather) {
+
+ if(privateData->UseTxCsum)
+ dev->features = (NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST);
+ else
+ dev->features = (NETIF_F_SG | NETIF_F_FRAGLIST); // Kernel will turn off SG in this case.
+ }
+
+ else {
+
+ if(privateData->UseTxCsum)
+ dev->features = (NETIF_F_HW_CSUM);
+ else
+ dev->features = 0;
+ }
+
+ if(dev==NULL) {
+ SMSC_WARNING("Smsc9118_open(dev==NULL)");
+ result=-EFAULT;
+ goto DONE;
+ }
+ privateData=(PPRIVATE_DATA)(dev->ml_priv);
+ if(privateData==NULL) {
+ SMSC_WARNING("Smsc9118_open(privateData==NULL)");
+ result=-EFAULT;
+ goto DONE;
+ }
+ platformData=&(privateData->PlatformData);
+
+ for (i = 0; i < GPT_SCHEDULE_DEPTH; i++) {
+ privateData->GptFunction [i] = NULL;
+ }
+ privateData->Gpt_scheduled_slot_index = GPT_SCHEDULE_DEPTH;
+
+ //get memory region
+ if(check_mem_region(privateData->dwLanBase,LAN_REGISTER_EXTENT)!=0)
+ {
+ SMSC_WARNING("Device memory is already in use.");
+ result=-ENOMEM;
+ goto DONE;
+ }
+ request_mem_region(privateData->dwLanBase,LAN_REGISTER_EXTENT,"SMSC_LAN9118");
+ acquired_mem_region=true;
+
+ //initialize the LAN9118
+ {
+ u32 dwIntCfg=0;
+ if(irq_pol) {
+ dwIntCfg|=INT_CFG_IRQ_POL_;
+ }
+ if(irq_type) {
+ dwIntCfg|=INT_CFG_IRQ_TYPE_;
+ }
+ if(!Lan_Initialize(privateData,dwIntCfg,tx_fif_sz,afc_cfg))
+ {
+ SMSC_WARNING("Failed Lan_Initialize");
+ result=-ENODEV;
+ goto DONE;
+ }
+ }
+
+ if(!Platform_RequestIRQ(platformData,irq,Smsc9118_ISR,privateData)) {
+ result=-ENODEV;
+ goto DONE;
+ }
+ acquired_isr=true;
+
+ //must now test the IRQ connection to the ISR
+ SMSC_TRACE("Testing ISR using IRQ %d",Platform_CurrentIRQ(platformData));
+ {
+ u32 dwTimeOut=1000000;
+ Lan_SignalSoftwareInterrupt(privateData);
+ SMSC_TRACE("privateData=%08X", (u32)privateData);
+ do {
+ udelay(10);
+ dwTimeOut--;
+ } while((dwTimeOut)&&(!(privateData->SoftwareInterruptSignal)));
+ if(!(privateData->SoftwareInterruptSignal)) {
+ SMSC_WARNING("ISR failed signaling test");
+ result=-ENODEV;
+ goto DONE;
+ }
+ }
+ SMSC_TRACE("ISR passed test using IRQ %d",Platform_CurrentIRQ(platformData));
+
+ if(!Mac_Initialize(privateData)) {
+ SMSC_WARNING("Failed Mac_Initialize");
+ result=-ENODEV;
+ goto DONE;
+ }
+ {//get mac address
+ u32 dwHigh16=0;
+ u32 dwLow32=0;
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ if(mac_addr_hi16==0xFFFFFFFF) {
+ dwHigh16=Mac_GetRegDW(privateData,ADDRH,keyCode);
+ dwLow32=Mac_GetRegDW(privateData,ADDRL,keyCode);
+ if((dwHigh16==0x0000FFFFUL)&&(dwLow32==0xFFFFFFFF))
+ {
+ dwHigh16=0x00000070UL;
+ dwLow32=0x110F8000UL;
+ Mac_SetRegDW(privateData,ADDRH,dwHigh16,keyCode);
+ Mac_SetRegDW(privateData,ADDRL,dwLow32,keyCode);
+ SMSC_TRACE("Mac Address is set by default to 0x%04X%08X",
+ dwHigh16,dwLow32);
+ } else {
+ SMSC_TRACE("Mac Address is read from LAN9118 as 0x%04X%08X",
+ dwHigh16,dwLow32);
+ }
+ } else {
+ //SMSC_ASSERT((mac_addr_hi16&0xFFFF8000UL)==0);
+ dwHigh16=mac_addr_hi16;
+ dwLow32=mac_addr_lo32;
+ Mac_SetRegDW(privateData,ADDRH,dwHigh16,keyCode);
+ Mac_SetRegDW(privateData,ADDRL,dwLow32,keyCode);
+ SMSC_TRACE("Mac Address is set by parameter to 0x%04X%08X",
+ dwHigh16,dwLow32);
+ }
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ dev->dev_addr[0]=LOBYTE(LOWORD(dwLow32));
+ dev->dev_addr[1]=HIBYTE(LOWORD(dwLow32));
+ dev->dev_addr[2]=LOBYTE(HIWORD(dwLow32));
+ dev->dev_addr[3]=HIBYTE(HIWORD(dwLow32));
+ dev->dev_addr[4]=LOBYTE(LOWORD(dwHigh16));
+ dev->dev_addr[5]=HIBYTE(LOWORD(dwHigh16));
+ }
+
+ privateData->dwIdRev=dwIdRev;
+ privateData->dwFpgaRev=dwFpgaRev&(0x000000FFUL);
+ privateData->dev=dev;
+
+ sprintf(privateData->ifName,"%s","eth1");
+ SMSC_TRACE("privateData->ifName = %s\n", privateData->ifName);
+ result=0;
+
+DONE:
+ if(result!=0) {
+ if(dev!=NULL) {
+ if(dev->ml_priv!=NULL) {
+ if(platformInitialized) {
+ Platform_CleanUp(platformData);
+ }
+ kfree(dev->ml_priv);
+ dev->ml_priv=NULL;
+ }
+ }
+ }
+ SMSC_TRACE("<--Smsc9118_init(), result=%d",result);
+}
+
+int Smsc9118_open(struct net_device *dev)
+{
+ int result=-ENODEV;
+ PPRIVATE_DATA privateData=NULL;
+ PPLATFORM_DATA platformData=NULL;
+ bool acquired_mem_region=false;
+ bool acquired_isr=false;
+ SMSC_TRACE("-->Smsc9118_open(dev=0x%08X)",(u32)dev);
+ if(dev==NULL) {
+ SMSC_WARNING("Smsc9118_open(dev==NULL)");
+ result=-EFAULT;
+ goto DONE;
+ }
+ privateData=(PPRIVATE_DATA)(dev->ml_priv);
+ if(privateData==NULL) {
+ SMSC_WARNING("Smsc9118_open(privateData==NULL)");
+ result=-EFAULT;
+ goto DONE;
+ }
+ platformData=&(privateData->PlatformData);
+
+ privateData->MulticastUpdatePending = false;
+#ifdef USE_PHY_WORK_AROUND
+ netif_carrier_off(dev);
+ if(!Phy_Initialize(
+ privateData,
+ phy_addr,
+ link_mode))
+ {
+ SMSC_WARNING("Failed to initialize Phy");
+ result=-ENODEV;
+ goto DONE;
+ }
+#endif
+
+ {
+ u32 dwRxDmaCh=rx_dma;
+ u32 dwTxDmaCh=tx_dma;
+ privateData->RxDmaChReserved=false;
+
+
+ if(rx_dma==TRANSFER_REQUEST_DMA) {
+ dwRxDmaCh=Platform_RequestDmaChannel(&(privateData->PlatformData));
+ SMSC_ASSERT(dwRxDmaCh!=TRANSFER_REQUEST_DMA);
+ if(dwRxDmaCh<TRANSFER_REQUEST_DMA) {
+ privateData->RxDmaChReserved=true;
+ }
+ }
+ privateData->TxDmaChReserved=false;
+ if(tx_dma==TRANSFER_REQUEST_DMA) {
+ dwTxDmaCh=Platform_RequestDmaChannel(&(privateData->PlatformData));
+ SMSC_ASSERT(dwTxDmaCh!=TRANSFER_REQUEST_DMA);
+ if(dwTxDmaCh<TRANSFER_REQUEST_DMA) {
+ privateData->TxDmaChReserved=true;
+ }
+ }
+ Tx_Initialize(privateData,dwTxDmaCh,dma_threshold);
+ Rx_Initialize(privateData,dwRxDmaCh,dma_threshold);
+
+ }
+
+#ifndef LINUX_2_6_OR_NEWER
+ MOD_INC_USE_COUNT;
+#endif
+ privateData->Running=true;
+ netif_start_queue(dev);
+ Tx_StopQueue(privateData,0x01UL);
+
+
+ spin_lock_init(&(privateData->GpTimerLock));
+ Lan_EnableInterrupt(privateData,INT_EN_GPT_INT_EN_);
+
+#ifndef USE_PHY_WORK_AROUND
+ netif_carrier_off(dev);
+ if(!Phy_Initialize(
+ privateData,
+ phy_addr,
+ link_mode))
+ {
+ SMSC_WARNING("Failed to initialize Phy");
+ result=-ENODEV;
+ goto DONE;
+ }
+#endif
+
+ result=0;
+
+DONE:
+ if(result!=0) {
+#ifndef LINUX_2_6_OR_NEWER
+ MOD_DEC_USE_COUNT;
+#endif
+ if(privateData!=NULL) {
+ if(privateData->TxDmaChReserved) {
+ Platform_ReleaseDmaChannel(platformData,
+ privateData->dwTxDmaCh);
+ privateData->TxDmaChReserved=false;
+ }
+ if(privateData->RxDmaChReserved) {
+ Platform_ReleaseDmaChannel(platformData,
+ privateData->dwRxDmaCh);
+ privateData->RxDmaChReserved=false;
+ }
+ if(acquired_isr) {
+ Platform_FreeIRQ(platformData);
+ }
+ if(acquired_mem_region) {
+ release_mem_region(
+ privateData->dwLanBase,
+ LAN_REGISTER_EXTENT);
+ }
+ }
+ }
+ SMSC_TRACE("<--Smsc9118_open, result=%d",result);
+ return result;
+}
+
+int Smsc9118_stop(struct net_device *dev)
+{
+ int result=0;
+ PPRIVATE_DATA privateData=NULL;
+ SMSC_TRACE("-->Smsc9118_stop(dev=0x%08X)",(u32)dev);
+ if(dev==NULL) {
+ SMSC_WARNING("Smsc9118_stop(dev==NULL)");
+ result=-EFAULT;
+ goto DONE;
+ }
+ privateData=(PPRIVATE_DATA)(dev->ml_priv);
+ if(privateData==NULL) {
+ SMSC_WARNING("Smsc9118_stop(privateData==NULL)");
+ result=-EFAULT;
+ goto DONE;
+ }
+
+ privateData->StopLinkPolling=true;
+ del_timer_sync(&(privateData->LinkPollingTimer));
+
+ Lan_DisableInterrupt(privateData,INT_EN_GPT_INT_EN_);
+
+ Tx_UpdateTxCounters(privateData);
+ privateData->Running=false;
+ Lan_DisableIRQ(privateData);
+
+ Tx_CompleteDma(privateData);
+
+ Tx_StopQueue(privateData,0x01UL);
+
+#ifndef LINUX_2_6_OR_NEWER
+ MOD_DEC_USE_COUNT;
+#endif
+
+ if(privateData->TxDmaChReserved) {
+ Platform_ReleaseDmaChannel(
+ &(privateData->PlatformData),
+ privateData->dwTxDmaCh);
+ privateData->TxDmaChReserved=false;
+ }
+ if(privateData->RxDmaChReserved) {
+ Platform_ReleaseDmaChannel(
+ &(privateData->PlatformData),
+ privateData->dwRxDmaCh);
+ privateData->RxDmaChReserved=false;
+ }
+
+ Platform_FreeIRQ(&(privateData->PlatformData));
+ release_mem_region(privateData->dwLanBase,LAN_REGISTER_EXTENT);
+
+ {
+ const u32 dwLanBase=privateData->dwLanBase;
+ const u32 dwIdRev=privateData->dwIdRev;
+ const u32 dwFpgaRev=privateData->dwFpgaRev;
+ struct net_device * const tempDev=privateData->dev;
+ char ifName[SMSC_IF_NAME_SIZE];
+ PLATFORM_DATA platformDataBackup;
+ memcpy(ifName,privateData->ifName,SMSC_IF_NAME_SIZE);
+ memcpy(&platformDataBackup,&(privateData->PlatformData),sizeof(PLATFORM_DATA));
+
+ memset(privateData,0,sizeof(PRIVATE_DATA));
+
+ privateData->dwLanBase=dwLanBase;
+ privateData->dwIdRev=dwIdRev;
+ privateData->dwFpgaRev=dwFpgaRev;
+ privateData->dev=tempDev;
+ memcpy(privateData->ifName,ifName,SMSC_IF_NAME_SIZE);
+ memcpy(&(privateData->PlatformData),&platformDataBackup,sizeof(PLATFORM_DATA));
+ }
+
+DONE:
+ SMSC_TRACE("<--Smsc9118_stop, result=%d",result);
+ return result;
+}
+
+int Smsc9118_hard_start_xmit(
+ struct sk_buff *skb, struct net_device * const dev)
+{
+ int result=0;
+ PPRIVATE_DATA privateData=NULL;
+ //SMSC_TRACE("-->Smsc9118_hard_start_xmit(skb=0x%08X,dev=0x%08X)",(u32)skb,(u32)dev);
+ if(skb==NULL) {
+ SMSC_WARNING("Smsc9118_hard_start_xmit(skb==NULL)");
+ result=-EFAULT;
+ goto DONE;
+ }
+ if(dev==NULL) {
+ SMSC_WARNING("Smsc9118_hard_start_xmit(dev==NULL)");
+ result=-EFAULT;
+ goto DONE;
+ }
+ if(dev->ml_priv==NULL) {
+ SMSC_WARNING("Smsc9118_hard_start_xmit(dev->ml_priv==NULL)");
+ result=-EFAULT;
+ goto DONE;
+ }
+ privateData=(PPRIVATE_DATA)(dev->ml_priv);
+ // SET_GPIO(GP_TX);
+
+ Tx_SendSkb(privateData,skb);
+
+ // CLEAR_GPIO(GP_TX);
+DONE:
+ //SMSC_TRACE("<--Smsc9118_hard_start_xmit, result=%d",result);
+ return result;
+}
+
+struct net_device_stats * Smsc9118_get_stats(struct net_device * const dev)
+{
+ PPRIVATE_DATA privateData=NULL;
+ if(dev==NULL) {
+ SMSC_WARNING("Smsc9118_get_stats(dev==NULL)");
+ return NULL;
+ }
+ if(dev->ml_priv==NULL) {
+ // SMSC_WARNING("Smsc9118_get_stats(dev->ml_priv==NULL)");
+ return NULL;
+ }
+
+ privateData=(PPRIVATE_DATA)(dev->ml_priv);
+ if(privateData->Running) {
+ privateData->stats.rx_dropped+=Lan_GetRegDW(RX_DROP);
+ Tx_UpdateTxCounters(privateData);
+ }
+ return &(privateData->stats);
+}
+
+void Smsc9118_set_multicast_list(struct net_device *dev)
+{
+ SMSC_ASSERT(dev!=NULL);
+ Rx_SetMulticastList(dev);
+}
+
+
+int Smsc9118_do_ioctl(
+ struct net_device *dev,
+ struct ifreq *ifr,
+ int cmd)
+{
+ int result=0;
+ PPRIVATE_DATA privateData=NULL;
+ void *userAddr=NULL;
+
+ // bool success=false;
+
+ SMSC_TRACE("-->Smsc9118_do_ioctl");
+ SMSC_TRACE("cmd=%d,SIOCGMIIPHY=%d,SIOCDEVPRIVATE=%d",
+ cmd,SIOCGMIIPHY,SIOCDEVPRIVATE);
+
+
+ if(dev==NULL) {
+ SMSC_WARNING("dev==NULL");
+ result=-EFAULT;
+ goto DONE;
+ }
+ if(dev->ml_priv==NULL) {
+ SMSC_WARNING("dev->ml_priv==NULL");
+ result=-EFAULT;
+ goto DONE;
+ }
+ privateData=((PPRIVATE_DATA)dev->ml_priv);
+ if(ifr==NULL) {
+ SMSC_WARNING("ifr==NULL");
+ result=-EFAULT;
+ goto DONE;
+ }
+ userAddr=ifr->ifr_data;
+
+
+ if(privateData->LanInitialized) {
+ // standard MII IOC's
+ struct mii_ioctl_data * const data=
+ (struct mii_ioctl_data *) & ifr->ifr_data;
+ switch(cmd) {
+ case SIOCGMIIPHY:
+
+ case SIOCDEVPRIVATE:
+ data->phy_id=1;
+ SMSC_TRACE("SIOCGMIIPHY: phy_id set to 0x%04X",data->phy_id);
+ break;
+ case SIOCGMIIREG:
+ case SIOCDEVPRIVATE+1:
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ data->val_out=Phy_GetRegW(
+ privateData,data->reg_num,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ }
+ SMSC_TRACE("SIOCGMIIREG: phy_id=0x%04X, reg_num=0x%04X, val_out set to 0x%04X",
+ data->phy_id,data->reg_num,data->val_out);
+ break;
+ case SIOCSMIIREG:
+ case SIOCDEVPRIVATE+2:
+ SMSC_TRACE("SIOCSMIIREG: phy_id=0x%04X, reg_num=0x%04X, val_in=0x%04X",
+ data->phy_id,data->reg_num,data->val_in);
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ Phy_SetRegW(
+ privateData,data->reg_num,((WORD)(data->val_in)),keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ }
+ break;
+
+ case SIOCETHTOOL:
+ result=Smsc9118_ethtool_ioctl(privateData,userAddr);
+ break;
+ case SMSC9118_IOCTL:
+ result=Smsc9118_private_ioctl(privateData,userAddr);
+ break;
+
+ default:
+ result=-EOPNOTSUPP;
+ break;//make lint happy
+ }
+ }
+
+DONE:
+
+ return result;
+}
+
+
+
+int Smsc9118_private_ioctl(PPRIVATE_DATA privateData,void *useraddr)
+{
+
+
+ bool success=false;
+ int result=-EFAULT;
+ SMSC9118_IOCTL_DATA ioctlData;
+
+ if(useraddr==NULL) {
+ SMSC_WARNING("useraddr==NULL");
+ result=-EFAULT;
+ goto DONE;
+ }
+
+ if(copy_from_user(&ioctlData,useraddr,sizeof(ioctlData))) {
+ SMSC_WARNING("copy_from_user failed");
+ result=-EFAULT;
+ goto DONE;
+ }
+
+ if(ioctlData.dwSignature!=SMSC9118_APP_SIGNATURE) {
+ SMSC_WARNING("invalid application signature");
+ result=-EFAULT;
+ goto DONE;
+ }
+
+ switch(ioctlData.dwCommand) {
+ case COMMAND_GET_SIGNATURE:
+ success=true;
+ break;
+ case COMMAND_GET_FLOW_PARAMS:
+ ioctlData.Data[0]=privateData->RxFlowMeasuredMaxThroughput;
+ ioctlData.Data[1]=privateData->RxFlowMeasuredMaxPacketCount;
+ ioctlData.Data[2]=privateData->RxFlowParameters.MaxThroughput;
+ ioctlData.Data[3]=privateData->RxFlowParameters.MaxPacketCount;
+ ioctlData.Data[4]=privateData->RxFlowParameters.PacketCost;
+ ioctlData.Data[5]=privateData->RxFlowParameters.BurstPeriod;
+ ioctlData.Data[6]=privateData->RxFlowMaxWorkLoad;
+ ioctlData.Data[7]=Lan_GetRegDW(INT_CFG)>>24;
+ privateData->RxFlowMeasuredMaxThroughput=0;
+ privateData->RxFlowMeasuredMaxPacketCount=0;
+ success=true;
+ break;
+ case COMMAND_SET_FLOW_PARAMS:
+ if(!(privateData->RxFlowControlActive)) {
+ privateData->RxFlowParameters.MaxThroughput=ioctlData.Data[2];
+ privateData->RxFlowParameters.MaxPacketCount=ioctlData.Data[3];
+ privateData->RxFlowParameters.PacketCost=ioctlData.Data[4];
+ privateData->RxFlowParameters.BurstPeriod=ioctlData.Data[5];
+ if(ioctlData.Data[6]==0xFFFFFFFFUL) {
+ privateData->RxFlowMaxWorkLoad=
+ privateData->RxFlowParameters.MaxThroughput+
+ (privateData->RxFlowParameters.MaxPacketCount*
+ privateData->RxFlowParameters.PacketCost);
+ } else {
+ privateData->RxFlowMaxWorkLoad=ioctlData.Data[6];
+ }
+ Lan_SetIntDeas(privateData,ioctlData.Data[7]);
+ privateData->RxFlowBurstMaxWorkLoad=
+ (privateData->RxFlowMaxWorkLoad*
+ privateData->RxFlowParameters.BurstPeriod)/1000;
+ success=true;
+ };break;
+ case COMMAND_GET_CONFIGURATION:
+ ioctlData.Data[0]=DRIVER_VERSION;
+ ioctlData.Data[1]=lan_base;
+ ioctlData.Data[2]=bus_width;
+ ioctlData.Data[3]=link_mode;
+ ioctlData.Data[4]=irq;
+ ioctlData.Data[5]=int_deas;
+ ioctlData.Data[6]=irq_pol;
+ ioctlData.Data[7]=irq_type;
+ ioctlData.Data[8]=rx_dma;
+ ioctlData.Data[9]=tx_dma;
+ ioctlData.Data[10]=dma_threshold;
+ ioctlData.Data[11]=mac_addr_hi16;
+ ioctlData.Data[12]=mac_addr_lo32;
+ ioctlData.Data[13]=debug_mode;
+ ioctlData.Data[14]=tx_fif_sz;
+ ioctlData.Data[15]=afc_cfg;
+ ioctlData.Data[16]=rx_mode;
+ ioctlData.Data[17]=max_throughput;
+ ioctlData.Data[18]=max_packet_count;
+ ioctlData.Data[19]=packet_cost;
+ ioctlData.Data[20]=burst_period;
+ ioctlData.Data[21]=max_work_load;
+ ioctlData.Data[22]=privateData->dwIdRev;
+ ioctlData.Data[23]=privateData->dwFpgaRev;
+ ioctlData.Data[24]=1;
+ ioctlData.Data[25]=privateData->dwPhyId;
+ ioctlData.Data[26]=privateData->bPhyModel;
+ ioctlData.Data[27]=privateData->bPhyRev;
+ ioctlData.Data[28]=privateData->dwLinkSpeed;
+ ioctlData.Data[29]=privateData->RxFlowMeasuredMaxThroughput;
+ ioctlData.Data[30]=privateData->RxFlowMeasuredMaxPacketCount;
+ ioctlData.Data[31]=privateData->RxFlowParameters.MaxThroughput;
+ ioctlData.Data[32]=privateData->RxFlowParameters.MaxPacketCount;
+ ioctlData.Data[33]=privateData->RxFlowParameters.PacketCost;
+ ioctlData.Data[34]=privateData->RxFlowParameters.BurstPeriod;
+ ioctlData.Data[35]=privateData->RxFlowMaxWorkLoad;
+ sprintf(ioctlData.Strng1,"%s, %s",__DATE__,__TIME__);
+ sprintf(ioctlData.Strng2,"%s",privateData->ifName);
+ privateData->RxFlowMeasuredMaxThroughput=0;
+ privateData->RxFlowMeasuredMaxPacketCount=0;
+ success=true;
+ break;
+ case COMMAND_LAN_GET_REG:
+ if((ioctlData.Data[0]<LAN_REGISTER_EXTENT)&&
+ ((ioctlData.Data[0]&0x3UL)==0))
+ {
+ ioctlData.Data[1]=
+ (*((volatile u32 *)(privateData->dwLanBase+
+ ioctlData.Data[0])));
+ success=true;
+ } else {
+ SMSC_WARNING("Reading LAN9118 Mem Map Failed");
+ goto MEM_MAP_ACCESS_FAILED;
+ }
+ break;
+ case COMMAND_LAN_SET_REG:
+ if((ioctlData.Data[0]<LAN_REGISTER_EXTENT)&&
+ ((ioctlData.Data[0]&0x3UL)==0))
+ {
+ (*((volatile u32 *)(privateData->dwLanBase+
+ ioctlData.Data[0])))=ioctlData.Data[1];
+ success=true;
+ } else {
+ SMSC_WARNING("Reading LAN9118 Mem Map Failed");
+MEM_MAP_ACCESS_FAILED:
+ SMSC_WARNING(" Invalid offset == 0x%08X",(u32)(ioctlData.Data[0]));
+ if(ioctlData.Data[0]>=LAN_REGISTER_EXTENT) {
+ SMSC_WARNING(" Out of range");
+ }
+ if(ioctlData.Data[0]&0x3UL) {
+ SMSC_WARNING(" Not u32 aligned");
+ }
+ }
+ break;
+ case COMMAND_MAC_GET_REG:
+ if((ioctlData.Data[0]<=0xC)&&(privateData->LanInitialized)) {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ ioctlData.Data[1]=
+ Mac_GetRegDW(privateData,ioctlData.Data[0],keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ success=true;
+ } else {
+ SMSC_WARNING("Reading Mac Register Failed");
+ goto MAC_ACCESS_FAILURE;
+ }
+ break;
+ case COMMAND_MAC_SET_REG:
+ if((ioctlData.Data[0]<=0xC)&&(privateData->LanInitialized)) {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ Mac_SetRegDW(
+ privateData,
+ ioctlData.Data[0],
+ ioctlData.Data[1],
+ keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ success=true;
+ } else {
+ SMSC_WARNING("Writing Mac Register Failed");
+MAC_ACCESS_FAILURE:
+ if(!(privateData->LanInitialized)) {
+
+ SMSC_WARNING(" LAN Not Initialized,");
+ SMSC_WARNING(" Use ifconfig to bring interface UP");
+ }
+ if(!(ioctlData.Data[0]<=0xC)) {
+ SMSC_WARNING(" Invalid index == 0x%08X",(u32)(ioctlData.Data[0]));
+ }
+ }
+ break;
+ case COMMAND_PHY_GET_REG:
+ if((ioctlData.Data[0]<32)&&(privateData->LanInitialized)) {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ ioctlData.Data[1]=((u32)
+ Phy_GetRegW(privateData,ioctlData.Data[0],keyCode));
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ success=true;
+ } else {
+ SMSC_WARNING("Reading Phy Register Failed");
+ goto PHY_ACCESS_FAILURE;
+ }
+ break;
+ case COMMAND_PHY_SET_REG:
+ if((ioctlData.Data[0]<32)&&(privateData->LanInitialized)) {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ Phy_SetRegW(
+ privateData,
+ ioctlData.Data[0],
+ ((WORD)(ioctlData.Data[1])),
+ keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ success=true;
+ } else {
+ SMSC_WARNING("Writing Phy Register Failed");
+PHY_ACCESS_FAILURE:
+ if(!(privateData->LanInitialized)) {
+ SMSC_WARNING(" Lan Not Initialized,");
+ SMSC_WARNING(" Use ifconfig to bring interface UP");
+ }
+ if(!(ioctlData.Data[0]<32)) {
+ SMSC_WARNING(" Invalid index == 0x%d",(u32)(ioctlData.Data[0]));
+ }
+ }
+ break;
+ // case COMMAND_DUMP_TEMP:
+ // {
+ // u32 c=0;
+ // for(c=0;c<0x40;c++)
+ // ioctlData.Data[c]=privateData->temp[c];
+ // }
+ // success=true;
+ // break;
+ case COMMAND_DUMP_LAN_REGS:
+ ioctlData.Data[LAN_REG_ID_REV]=Lan_GetRegDW(ID_REV);
+ ioctlData.Data[LAN_REG_INT_CFG]=Lan_GetRegDW(INT_CFG);
+ ioctlData.Data[LAN_REG_INT_STS]=Lan_GetRegDW(INT_STS);
+ ioctlData.Data[LAN_REG_INT_EN]=Lan_GetRegDW(INT_EN);
+ ioctlData.Data[LAN_REG_BYTE_TEST]=Lan_GetRegDW(BYTE_TEST);
+ ioctlData.Data[LAN_REG_FIFO_INT]=Lan_GetRegDW(FIFO_INT);
+ ioctlData.Data[LAN_REG_RX_CFG]=Lan_GetRegDW(RX_CFG);
+ ioctlData.Data[LAN_REG_TX_CFG]=Lan_GetRegDW(TX_CFG);
+ ioctlData.Data[LAN_REG_HW_CFG]=Lan_GetRegDW(HW_CFG);
+ ioctlData.Data[LAN_REG_RX_DP_CTRL]=Lan_GetRegDW(RX_DP_CTRL);
+ ioctlData.Data[LAN_REG_RX_FIFO_INF]=Lan_GetRegDW(RX_FIFO_INF);
+ ioctlData.Data[LAN_REG_TX_FIFO_INF]=Lan_GetRegDW(TX_FIFO_INF);
+ ioctlData.Data[LAN_REG_PMT_CTRL]=Lan_GetRegDW(PMT_CTRL);
+ ioctlData.Data[LAN_REG_GPIO_CFG]=Lan_GetRegDW(GPIO_CFG);
+ ioctlData.Data[LAN_REG_GPT_CFG]=Lan_GetRegDW(GPT_CFG);
+ ioctlData.Data[LAN_REG_GPT_CNT]=Lan_GetRegDW(GPT_CNT);
+ ioctlData.Data[LAN_REG_FPGA_REV]=Lan_GetRegDW(FPGA_REV);
+ ioctlData.Data[LAN_REG_WORD_SWAP]=Lan_GetRegDW(WORD_SWAP);
+ ioctlData.Data[LAN_REG_FREE_RUN]=Lan_GetRegDW(FREE_RUN);
+ ioctlData.Data[LAN_REG_RX_DROP]=Lan_GetRegDW(RX_DROP);
+ if(privateData->LanInitialized) {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ ioctlData.Data[LAN_REG_MAC_CSR_CMD]=Lan_GetRegDW(MAC_CSR_CMD);
+ ioctlData.Data[LAN_REG_MAC_CSR_DATA]=Lan_GetRegDW(MAC_CSR_DATA);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ } else {
+ ioctlData.Data[LAN_REG_MAC_CSR_CMD]=Lan_GetRegDW(MAC_CSR_CMD);
+ ioctlData.Data[LAN_REG_MAC_CSR_DATA]=Lan_GetRegDW(MAC_CSR_DATA);
+ }
+ ioctlData.Data[LAN_REG_AFC_CFG]=Lan_GetRegDW(AFC_CFG);
+ ioctlData.Data[LAN_REG_E2P_CMD]=Lan_GetRegDW(E2P_CMD);
+ ioctlData.Data[LAN_REG_E2P_DATA]=Lan_GetRegDW(E2P_DATA);
+ success=true;
+ break;
+ case COMMAND_DUMP_MAC_REGS:
+ if(privateData->LanInitialized) {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ ioctlData.Data[MAC_REG_MAC_CR]=Mac_GetRegDW(privateData,MAC_CR,keyCode);
+ ioctlData.Data[MAC_REG_ADDRH]=Mac_GetRegDW(privateData,ADDRH,keyCode);
+ ioctlData.Data[MAC_REG_ADDRL]=Mac_GetRegDW(privateData,ADDRL,keyCode);
+ ioctlData.Data[MAC_REG_HASHH]=Mac_GetRegDW(privateData,HASHH,keyCode);
+ ioctlData.Data[MAC_REG_HASHL]=Mac_GetRegDW(privateData,HASHL,keyCode);
+ ioctlData.Data[MAC_REG_MII_ACC]=Mac_GetRegDW(privateData,MII_ACC,keyCode);
+ ioctlData.Data[MAC_REG_MII_DATA]=Mac_GetRegDW(privateData,MII_DATA,keyCode);
+ ioctlData.Data[MAC_REG_FLOW]=Mac_GetRegDW(privateData,FLOW,keyCode);
+ ioctlData.Data[MAC_REG_VLAN1]=Mac_GetRegDW(privateData,VLAN1,keyCode);
+ ioctlData.Data[MAC_REG_VLAN2]=Mac_GetRegDW(privateData,VLAN2,keyCode);
+ ioctlData.Data[MAC_REG_WUFF]=Mac_GetRegDW(privateData,WUFF,keyCode);
+ ioctlData.Data[MAC_REG_WUCSR]=Mac_GetRegDW(privateData,WUCSR,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ success=true;
+ } else {
+ SMSC_WARNING("Mac Not Initialized,");
+ SMSC_WARNING(" Use ifconfig to bring interface UP");
+ }
+ break;
+ case COMMAND_DUMP_PHY_REGS:
+ if(privateData->LanInitialized) {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ ioctlData.Data[PHY_REG_0]=Phy_GetRegW(privateData,0,keyCode);
+ ioctlData.Data[PHY_REG_1]=Phy_GetRegW(privateData,1,keyCode);
+ ioctlData.Data[PHY_REG_2]=Phy_GetRegW(privateData,2,keyCode);
+ ioctlData.Data[PHY_REG_3]=Phy_GetRegW(privateData,3,keyCode);
+ ioctlData.Data[PHY_REG_4]=Phy_GetRegW(privateData,4,keyCode);
+ ioctlData.Data[PHY_REG_5]=Phy_GetRegW(privateData,5,keyCode);
+ ioctlData.Data[PHY_REG_6]=Phy_GetRegW(privateData,6,keyCode);
+ ioctlData.Data[PHY_REG_16]=Phy_GetRegW(privateData,16,keyCode);
+ ioctlData.Data[PHY_REG_17]=Phy_GetRegW(privateData,17,keyCode);
+ ioctlData.Data[PHY_REG_18]=Phy_GetRegW(privateData,18,keyCode);
+ ioctlData.Data[PHY_REG_20]=Phy_GetRegW(privateData,20,keyCode);
+ ioctlData.Data[PHY_REG_21]=Phy_GetRegW(privateData,21,keyCode);
+ ioctlData.Data[PHY_REG_22]=Phy_GetRegW(privateData,22,keyCode);
+ ioctlData.Data[PHY_REG_23]=Phy_GetRegW(privateData,23,keyCode);
+ ioctlData.Data[PHY_REG_27]=Phy_GetRegW(privateData,27,keyCode);
+ ioctlData.Data[PHY_REG_28]=Phy_GetRegW(privateData,28,keyCode);
+ ioctlData.Data[PHY_REG_29]=Phy_GetRegW(privateData,29,keyCode);
+ ioctlData.Data[PHY_REG_30]=Phy_GetRegW(privateData,30,keyCode);
+ ioctlData.Data[PHY_REG_31]=Phy_GetRegW(privateData,31,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ success=true;
+ } else {
+ SMSC_WARNING("Phy Not Initialized,");
+ SMSC_WARNING(" Use ifconfig to bring interface UP");
+ }
+ break;
+ case COMMAND_DUMP_EEPROM:
+ {
+ BYTE data=0;
+ BYTE index=0;
+ Eeprom_EnableAccess(privateData);
+ success=true;
+ for(index=0;index<8;index++) {
+ if(Eeprom_ReadLocation(privateData,index,&data)) {
+ ioctlData.Data[index]=(u32)data;
+ } else {
+ success=false;
+ break;
+ }
+ }
+ Eeprom_DisableAccess(privateData);
+ };break;
+ case COMMAND_GET_MAC_ADDRESS:
+ if(privateData->LanInitialized) {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ ioctlData.Data[0]=Mac_GetRegDW(privateData,ADDRH,keyCode);
+ ioctlData.Data[1]=Mac_GetRegDW(privateData,ADDRL,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ success=true;
+ } else {
+ SMSC_WARNING("Lan Not Initialized,");
+ SMSC_WARNING(" Use ifconfig to bring interface UP");
+ }
+ break;
+
+ case COMMAND_SET_MAC_ADDRESS:
+ if(privateData->LanInitialized)
+ {
+ u32 dwLow32=ioctlData.Data[1];
+ u32 dwHigh16=ioctlData.Data[0];
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ Mac_SetRegDW(privateData,ADDRH,dwHigh16,keyCode);
+ Mac_SetRegDW(privateData,ADDRL,dwLow32,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ success=true;
+ } else {
+ SMSC_WARNING("Lan Not Initialized,");
+ SMSC_WARNING(" Use ifconfig to bring interface UP");
+ };break;
+ case COMMAND_LOAD_MAC_ADDRESS:
+ if(privateData->LanInitialized) {
+ Eeprom_EnableAccess(privateData);
+ if(Eeprom_Reload(privateData)) {
+ if(Eeprom_IsMacAddressLoaded(privateData)) {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ ioctlData.Data[0]=Mac_GetRegDW(privateData,ADDRH,keyCode);
+ ioctlData.Data[1]=Mac_GetRegDW(privateData,ADDRL,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ success=true;
+ } else {
+ SMSC_WARNING("Failed to Load Mac Address(1)");
+ }
+ } else {
+ SMSC_WARNING("Failed to Load Mac Address(2)");
+ }
+ Eeprom_DisableAccess(privateData);
+ } else {
+ SMSC_WARNING("Lan Not Initialized,");
+ SMSC_WARNING(" Use ifconfig to bring interface UP");
+ };break;
+ case COMMAND_SAVE_MAC_ADDRESS:
+ if(privateData->LanInitialized) {
+ if(Eeprom_SaveMacAddress(privateData,
+ ioctlData.Data[0],ioctlData.Data[1])) {
+ success=true;
+ }
+ } else {
+ SMSC_WARNING("Lan Not Initialized,");
+ SMSC_WARNING(" Use ifconfig to bring interface UP");
+ };break;
+ case COMMAND_SET_DEBUG_MODE:
+ debug_mode=ioctlData.Data[0];
+ if(debug_mode&0x04UL) {
+ if(OLD_REGISTERS(privateData))
+ {
+ g_GpioSetting=0x00270700UL;
+ } else {
+ g_GpioSetting=0x00670700UL;
+ }
+ Lan_SetRegDW(GPIO_CFG,g_GpioSetting);
+ } else {
+ Lan_SetRegDW(GPIO_CFG,0x70070000);
+ }
+ success=true;
+ break;
+ case COMMAND_SET_LINK_MODE:
+ link_mode=(ioctlData.Data[0]&0x7FUL);
+ if(privateData->LanInitialized) {
+ Phy_SetLink(privateData,link_mode);
+ }
+ success=true;
+ break;
+ case COMMAND_GET_LINK_MODE:
+ ioctlData.Data[0]=link_mode;
+ success=true;
+ break;
+ case COMMAND_CHECK_LINK:
+ Phy_UpdateLinkMode(privateData);
+ success=true;
+ break;
+ case COMMAND_READ_BYTE:
+ ioctlData.Data[1]=(*((volatile BYTE *)(ioctlData.Data[0])));
+ success=true;
+ break;
+ case COMMAND_READ_WORD:
+ ioctlData.Data[1]=(*((volatile WORD *)(ioctlData.Data[0])));
+ success=true;
+ break;
+ case COMMAND_READ_DWORD:
+ ioctlData.Data[1]=(*((volatile u32 *)(ioctlData.Data[0])));
+ success=true;
+ break;
+ case COMMAND_WRITE_BYTE:
+ (*((volatile BYTE *)(ioctlData.Data[0])))=
+ ((BYTE)(ioctlData.Data[1]));
+ success=true;
+ break;
+ case COMMAND_WRITE_WORD:
+ (*((volatile WORD *)(ioctlData.Data[0])))=
+ ((WORD)(ioctlData.Data[1]));
+ success=true;
+ break;
+ case COMMAND_WRITE_DWORD:
+ (*((volatile u32 *)(ioctlData.Data[0])))=
+ ((u32)(ioctlData.Data[1]));
+ success=true;
+ break;
+ case COMMAND_SET_AMDIX_STS:
+ AutoMdix=(ioctlData.Data[0]);
+ if(privateData->LanInitialized) {
+ Phy_SetAutoMdixSts(privateData,AutoMdix);
+ }
+ success=true;
+ break;
+ case COMMAND_GET_AMDIX_STS:
+ ioctlData.Data[0]=AutoMdix;
+ if(privateData->LanInitialized) {
+ Phy_GetAutoMdixSts(privateData);
+ }
+ success=true;
+ break;
+
+ default:return -EOPNOTSUPP;
+ }
+
+DONE:
+ if(success) {
+ ioctlData.dwSignature=SMSC9118_DRIVER_SIGNATURE;
+ if(copy_to_user(useraddr, &ioctlData, sizeof(ioctlData))) {
+ SMSC_WARNING("copy_to_user failed");
+ result=-EFAULT;
+ }
+ result=0;
+ }
+ // SMSC_TRACE("<--Smsc9118_do_ioctl");
+ return result;
+
+}
+
+
+
+int Smsc9118_ethtool_ioctl(PPRIVATE_DATA privateData, void * userAddr)
+{
+ int result=-EFAULT;
+ u32 ethcmd=0;
+ if(copy_from_user(ðcmd,userAddr,sizeof(ethcmd)))
+ {
+ result=-EFAULT;
+ goto DONE;
+ }
+ switch(ethcmd) {
+ case ETHTOOL_GSET:// Get settings.
+ // SMSC_TRACE("ETHTOOL_GSET");
+ {
+ struct ethtool_cmd settings={ETHTOOL_GSET};
+ settings.supported=
+ SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_MII;
+ settings.advertising=ADVERTISED_MII;
+ if(privateData->dwLinkSettings & LINK_SPEED_10HD)
+ settings.advertising|=ADVERTISED_10baseT_Half;
+ if(privateData->dwLinkSettings & LINK_SPEED_10FD)
+ settings.advertising|=ADVERTISED_10baseT_Full;
+ if(privateData->dwLinkSettings & LINK_SPEED_100HD)
+ settings.advertising|=ADVERTISED_100baseT_Half;
+ if(privateData->dwLinkSettings & LINK_SPEED_100FD)
+ settings.advertising|=ADVERTISED_100baseT_Full;
+ if(privateData->dwLinkSettings & LINK_AUTO_NEGOTIATE) {
+ settings.advertising|=ADVERTISED_Autoneg;
+ settings.autoneg=AUTONEG_ENABLE;
+ } else settings.autoneg=AUTONEG_DISABLE;
+ if(privateData->dwLinkSpeed & (LINK_SPEED_100HD|LINK_SPEED_100FD))
+ settings.speed=SPEED_100;
+ else settings.speed=SPEED_10;
+ if(privateData->dwLinkSpeed & (LINK_SPEED_10FD|LINK_SPEED_100FD))
+ settings.duplex=DUPLEX_FULL;
+ else settings.duplex=DUPLEX_HALF;
+ settings.port=PORT_MII;
+ settings.phy_address=(u8)privateData->dwPhyAddress;
+ settings.transceiver=XCVR_INTERNAL;
+ settings.maxtxpkt=0;
+ settings.maxrxpkt=0;
+ if(copy_to_user(userAddr,&settings,sizeof(settings))) {
+ result=-EFAULT;
+ } else {
+ result=0;
+ }
+ }
+ break;
+ case ETHTOOL_SSET:// Set settings.
+ // SMSC_TRACE("ETHTOOL_SSET");
+ {
+ struct ethtool_cmd settings;
+ u16 speed=0;
+ u8 duplex=0;
+ u8 autoneg=0;
+ if(copy_from_user(&settings,userAddr,sizeof(settings))) {
+ result=-EFAULT;
+ goto DONE;
+ }
+ if(privateData->dwLinkSettings&LINK_AUTO_NEGOTIATE) {
+ autoneg=AUTONEG_ENABLE;
+ } else {
+ autoneg=AUTONEG_DISABLE;
+ }
+ if(privateData->dwLinkSpeed&(LINK_SPEED_100HD|LINK_SPEED_100FD))
+ {
+ speed=SPEED_100;
+ } else {
+ speed=SPEED_10;
+ }
+ if(privateData->dwLinkSpeed&(LINK_SPEED_10FD|LINK_SPEED_100FD))
+ {
+ duplex=DUPLEX_FULL;
+ } else {
+ duplex=DUPLEX_HALF;
+ }
+ if((settings.speed!=100)&&(settings.speed!=10)) {
+ result=-EOPNOTSUPP;
+ goto DONE;
+ }
+ if((settings.duplex!=DUPLEX_FULL)&&(settings.duplex!=DUPLEX_HALF)) {
+ result=-EOPNOTSUPP;
+ goto DONE;
+ }
+ if((settings.autoneg!=AUTONEG_ENABLE)&&(settings.autoneg!=AUTONEG_DISABLE)) {
+ result=-EOPNOTSUPP;
+ goto DONE;
+ }
+ if((settings.autoneg!=autoneg)||
+ (settings.speed!=speed)||
+ (settings.duplex!=duplex))
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ if(settings.autoneg==AUTONEG_ENABLE) {
+
+
+
+ WORD wAdvertisement=Phy_GetRegW(privateData,PHY_ANEG_ADV,keyCode);
+ wAdvertisement&=(~PHY_ANEG_ADV_SPEED_);
+ if(settings.speed==SPEED_100) {
+ if(settings.duplex==DUPLEX_FULL) {
+ wAdvertisement|=PHY_ANEG_ADV_100F_;
+ } else {
+ wAdvertisement|=PHY_ANEG_ADV_100H_;
+ }
+ } else {
+ if(settings.duplex==DUPLEX_FULL) {
+ wAdvertisement|=PHY_ANEG_ADV_10F_;
+ } else {
+ wAdvertisement|=PHY_ANEG_ADV_10H_;
+ }
+ }
+
+
+
+ Phy_SetRegW(privateData,PHY_ANEG_ADV,wAdvertisement,keyCode);
+ Phy_SetRegW(privateData,PHY_BCR,
+ (PHY_BCR_AUTO_NEG_ENABLE_|PHY_BCR_RESTART_AUTO_NEG_),keyCode);
+
+
+ } else {
+ WORD wBcr=Phy_GetRegW(privateData,PHY_BCR,keyCode);
+ if(settings.speed==SPEED_100) {
+ wBcr|=PHY_BCR_SPEED_SELECT_;
+ } else {
+ wBcr&=(~PHY_BCR_SPEED_SELECT_);
+ }
+ if(settings.duplex==DUPLEX_FULL) {
+ wBcr|=PHY_BCR_DUPLEX_MODE_;
+ } else {
+ wBcr&=(~PHY_BCR_DUPLEX_MODE_);
+ }
+ Phy_SetRegW(privateData,PHY_BCR,wBcr,keyCode);
+ }
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+
+ }
+ result=0;
+ }
+ break;
+ case ETHTOOL_GDRVINFO:// Get driver info.
+ // SMSC_TRACE("ETHTOOL_GDRVINFO");
+ {
+ struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+ strcpy(info.driver,"Smsc9131_eth");
+ memset(&info.version,0,sizeof(info.version));
+ memset(&info.fw_version,0,sizeof(info.fw_version));
+ sprintf(info.fw_version,"%u",(privateData->dwIdRev)&0xFFFF);
+ memset(&info.bus_info,0,sizeof(info.bus_info));
+ memset(&info.reserved1,0,sizeof(info.reserved1));
+ memset(&info.reserved2,0,sizeof(info.reserved2));
+#ifdef LINUX_2_6_OR_NEWER
+ info.n_stats=0;
+ info.testinfo_len=0;
+#endif
+ info.eedump_len=0;
+ info.regdump_len=0;
+ if(copy_to_user(userAddr,&info,sizeof(info))) {
+ result=-EFAULT;
+ } else {
+ result=0;
+ }
+ }
+ break;
+ case ETHTOOL_GREGS:// Get NIC registers.
+ // SMSC_TRACE("ETHTOOL_GREGS");
+ result=-EOPNOTSUPP;
+ break;
+ /*
+ case ETHTOOL_GWOL:// Get wake-on-lan options.
+ SMSC_TRACE("ETHTOOL_GWOL");
+ {
+ struct ethtool_wolinfo wol_info={ETHTOOL_GWOL};
+ //wol_info.supported=true;
+ wol_info.supported=(WAKE_PHY | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_MAGIC);
+ wol_info.wolopts= privateData->WolWakeupOpts;
+ memset(&wol_info.sopass,0,sizeof(wol_info.sopass));
+ if(copy_to_user(userAddr,&wol_info,sizeof(wol_info))) {
+ result=-EFAULT;
+ } else {
+ result=0;
+ }
+ }
+ break;
+ case ETHTOOL_SWOL:// Set wake-on-lan options.
+ SMSC_TRACE("ETHTOOL_SWOL");
+ {
+ unsigned long dwIntFlags=0;
+ struct ethtool_wolinfo wol_info;
+ if(copy_from_user(&wol_info,userAddr,sizeof(wol_info)))
+ {
+ result=-EFAULT;
+ } else {
+ SMSC_TRACE(DBG_IOCTL,"WOL OPTS = 0x%x", wol_info.wolopts);
+ spin_lock_irqsave(&(privateData->PhyLock),dwIntFlags);
+ privateData->WolWakeupOpts = wol_info.wolopts;
+ spin_unlock_irqrestore(&(privateData->PhyLock),dwIntFlags);
+ result=0;
+ }
+ }
+ break;
+ */
+ case ETHTOOL_GMSGLVL:// Get driver message level
+ // SMSC_TRACE("ETHTOOL_GMSGLVL");
+ {
+ struct ethtool_value msgLevel={ETHTOOL_GMSGLVL};
+ msgLevel.data=debug_mode;
+ if(copy_to_user(userAddr, &msgLevel,sizeof(msgLevel))) {
+ result=-EFAULT;
+ } else {
+ result=0;
+ }
+ }
+ break;
+ case ETHTOOL_SMSGLVL:// Set driver msg level.
+ // SMSC_TRACE("ETHTOOL_SMSGLVL");
+ {
+ struct ethtool_value msgLevel;
+ if(copy_from_user(&msgLevel,userAddr,sizeof(msgLevel)))
+ {
+ result=-EFAULT;
+ } else {
+ debug_mode=msgLevel.data;
+ result=0;
+ }
+ }
+ break;
+ case ETHTOOL_NWAY_RST:// Restart autonegotiation.
+ // SMSC_TRACE("ETHTOOL_NWAY_RST");
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ Phy_SetRegW(privateData,PHY_BCR,
+ (PHY_BCR_AUTO_NEG_ENABLE_|PHY_BCR_RESTART_AUTO_NEG_),keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ result=0;
+ }
+ break;
+ case ETHTOOL_GLINK:// Get link status (ethtool_value)
+ // SMSC_TRACE("ETHTOOL_GLINK");
+ {
+ struct ethtool_value linkStatus={ETHTOOL_GLINK};
+ if(privateData->dwLinkSpeed!=LINK_OFF) {
+ linkStatus.data=1;
+ } else {
+ linkStatus.data=0;
+ }
+ if(copy_to_user(userAddr,&linkStatus,sizeof(linkStatus)))
+ {
+ result=-EFAULT;
+ } else {
+ result=0;
+ }
+ }
+ break;
+ case ETHTOOL_GEEPROM:// Get EEPROM data
+ // SMSC_TRACE("ETHTOOL_GEEPROM");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_SEEPROM:// Set EEPROM data.
+ // SMSC_TRACE("ETHTOOL_SEEPROM");
+ result=-EOPNOTSUPP;
+ break;
+
+#ifdef LINUX_2_6_OR_NEWER
+
+ case ETHTOOL_GCOALESCE:// Get coalesce config
+ // SMSC_TRACE("ETHTOOL_GCOALESCE");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_SCOALESCE:// Set coalesce config.
+ // SMSC_TRACE("ETHTOOL_SCOALESCE");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_GRINGPARAM:// Get ring parameters
+ // SMSC_TRACE("ETHTOOL_GRINGPARAM");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_SRINGPARAM:// Set ring parameters.
+ // SMSC_TRACE("ETHTOOL_SRINGPARAM");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_GPAUSEPARAM:// Get pause parameters
+ // SMSC_TRACE("ETHTOOL_GPAUSEPARAM");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_SPAUSEPARAM:// Set pause parameters.
+ // SMSC_TRACE("ETHTOOL_SPAUSEPARAM");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_GRXCSUM:// Get RX hw csum enable (ethtool_value)
+ // SMSC_TRACE("ETHTOOL_GRXCSUM");
+ {
+ struct ethtool_value rxCsum={ETHTOOL_GRXCSUM};
+ rxCsum.data=0;
+ if(copy_to_user(userAddr,&rxCsum,sizeof(rxCsum))) {
+ result=-EFAULT;
+ } else {
+ result=0;
+ }
+ }
+ break;
+ case ETHTOOL_SRXCSUM:// Set RX hw csum enable (ethtool_value)
+ // SMSC_TRACE("ETHTOOL_SRXCSUM");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_GTXCSUM:// Get TX hw csum enable (ethtool_value)
+ // SMSC_TRACE("ETHTOOL_GTXCSUM");
+ {
+ struct ethtool_value txCsum={ETHTOOL_GTXCSUM};
+ txCsum.data=0;
+ if(copy_to_user(userAddr,&txCsum,sizeof(txCsum))) {
+ result=-EFAULT;
+ } else {
+ result=0;
+ }
+ }
+ break;
+ case ETHTOOL_STXCSUM:// Set TX hw csum enable (ethtool_value)
+ // SMSC_TRACE("ETHTOOL_STXCSUM");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_GSG:// Get scatter-gather enable (ethtool_value)
+ // SMSC_TRACE("ETHTOOL_GSG");
+ {
+ struct ethtool_value sg={ETHTOOL_GSG};
+ sg.data=0;
+ if(copy_to_user(userAddr,&sg,sizeof(sg))) {
+ result=-EFAULT;
+ } else {
+ result=0;
+ }
+ }
+ break;
+ case ETHTOOL_SSG:// Set scatter-gather enable (ethtool_value).
+ // SMSC_TRACE("ETHTOOL_SSG");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_TEST:// execute NIC self-test.
+ // SMSC_TRACE("ETHTOOL_TEST");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_GSTRINGS:// get specified string set
+ // SMSC_TRACE("ETHTOOL_GSTRINGS");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_PHYS_ID:// identify the NIC
+ // SMSC_TRACE("ETHTOOL_PHYS_ID");
+ result=-EOPNOTSUPP;
+ break;
+ case ETHTOOL_GSTATS:// get NIC-specific statistics
+ // SMSC_TRACE("ETHTOOL_GSTATS");
+ result=-EOPNOTSUPP;
+ break;
+
+ case ETHTOOL_GTSO:// Get TSO enable (ethtool_value)
+ // SMSC_TRACE("ETHTOOL_GTSO");
+ {
+ struct ethtool_value tso={ETHTOOL_GTSO};
+ tso.data=0;
+ if(copy_to_user(userAddr,&tso,sizeof(tso))) {
+ result=-EFAULT;
+ } else {
+ result=0;
+ }
+ }
+ break;
+ case ETHTOOL_STSO:// Set TSO enable (ethtool_value)
+ // SMSC_TRACE("ETHTOOL_STS0");
+ result=-EOPNOTSUPP;
+ break;
+#endif
+ default:
+ // SMSC_WARNING("unknown ethcmd=0x%08X",ethcmd);
+ result=-EOPNOTSUPP;
+ break;
+ }
+DONE:
+ return result;
+}
+
+
+//returns time1-time2;
+TIME_SPAN Gpt_FreeRunCompare(u32 time1,u32 time2)
+{
+ return ((TIME_SPAN)(time1-time2));
+}
+void Gpt_ScheduleInterrupt(PPRIVATE_DATA privateData,TIME_SPAN timeSpan)
+{
+ u32 timerValue=0;
+ if(timeSpan<0) timeSpan=0;
+ timerValue=(u32)timeSpan;
+ if((timerValue%2500)>=1250) {
+ timerValue=(timerValue/2500)+1;
+ } else {
+ timerValue=(timerValue/2500);
+ }
+ if(timerValue>0x0000FFFFUL) {
+ timerValue=0x0000FFFF;
+ }
+ Lan_SetRegDW(GPT_CFG,(timerValue|GPT_CFG_TIMER_EN_));
+ Lan_SetRegDW(INT_STS,INT_STS_GPT_INT_);
+}
+
+void Gpt_CancelInterrupt(PPRIVATE_DATA privateData)
+{
+ Lan_SetRegDW(GPT_CFG,0UL);
+ Lan_SetRegDW(INT_STS,INT_STS_GPT_INT_);
+}
+
+void Gpt_ScheduleCallBack(
+ PPRIVATE_DATA privateData,
+ void (*callBackFunction)(PPRIVATE_DATA privateData),
+ u32 callBackTime)
+{
+ u32 slot_index=GPT_SCHEDULE_DEPTH;
+ bool result=false;
+ if((callBackFunction!=NULL)&&(callBackTime!=0)) {
+ unsigned long dwIntFlags=0;
+ SMSC_ASSERT(privateData!=NULL);
+ spin_lock_irqsave(&privateData->GpTimerLock,dwIntFlags);
+ {
+ u32 index=0;
+ u32 currentTime=Lan_GetRegDW(FREE_RUN);
+ TIME_SPAN nextCallTime=MAX_TIME_SPAN;
+ TIME_SPAN timeSpan=MAX_TIME_SPAN;
+ bool rescheduleRequired=false;
+ for(index=0;index<GPT_SCHEDULE_DEPTH;index++) {
+ if(privateData->GptFunction[index]==NULL) {
+ if(!result) {
+ result=true;
+ //lint -save
+ //lint -e611 //suspicious cast
+ privateData->GptFunction[index]=(void *)callBackFunction;
+ //lint -restore_
+ privateData->GptCallTime[index]=currentTime+(2500*callBackTime);
+ timeSpan=Gpt_FreeRunCompare(privateData->GptCallTime[index],currentTime);
+ if(nextCallTime>timeSpan) {
+ nextCallTime=timeSpan;
+ rescheduleRequired=true;
+ slot_index = index;
+ }
+ }
+ } else {
+ timeSpan=Gpt_FreeRunCompare(privateData->GptCallTime[index],currentTime);
+ if(nextCallTime>=timeSpan) {
+ nextCallTime=timeSpan;
+ rescheduleRequired=false;
+ }
+ }
+ }
+ if(rescheduleRequired) {
+ privateData->Gpt_scheduled_slot_index = slot_index;
+ Gpt_ScheduleInterrupt(privateData,nextCallTime);
+ }
+ }
+ spin_unlock_irqrestore(&(privateData->GpTimerLock),dwIntFlags);
+ }
+ if(!result) {
+ SMSC_WARNING("Gpt_ScheduleCallBack: Failed");
+ }
+}
+
+void Gpt_CancelCallBack(
+ PPRIVATE_DATA privateData,
+ void (*callBackFunction)(PPRIVATE_DATA privateData))
+{
+ bool result=false;
+ if(callBackFunction!=NULL) {
+ unsigned long dwIntFlags=0;
+ SMSC_ASSERT(privateData!=NULL);
+ spin_lock_irqsave(&(privateData->GpTimerLock),dwIntFlags);
+ {
+ u32 index=0;
+ u32 currentTime=Lan_GetRegDW(FREE_RUN);
+ TIME_SPAN nextCallTime=MAX_TIME_SPAN;
+ TIME_SPAN timeSpan=MAX_TIME_SPAN;
+ bool rescheduleRequired=false;
+ for(index=0;index<GPT_SCHEDULE_DEPTH;index++) {
+ if(privateData->GptFunction[index]==callBackFunction) {
+ result=true;
+ //lint -save
+ //lint -e611 //suspicious cast
+ privateData->GptFunction[index]=(void *)NULL;
+ // cancelled time will not need a
+ // re-scheduled
+
+ // re-scheduled is done at other
+ // non-null slots
+ }
+ else if(privateData->GptFunction[index]!=NULL) {
+ timeSpan=Gpt_FreeRunCompare(privateData->GptCallTime[index],currentTime);
+ // if this scheduled time is earlier
+ // than current scheduled time
+ // AND not a duplicated one
+ if(nextCallTime>=timeSpan && privateData->Gpt_scheduled_slot_index != index) {
+ nextCallTime=timeSpan;
+ rescheduleRequired=true;
+ privateData->Gpt_scheduled_slot_index = index;
+ }
+ }
+ }
+ if(rescheduleRequired) {
+ Gpt_ScheduleInterrupt(privateData,nextCallTime);
+ }
+ else if (privateData->Gpt_scheduled_slot_index==GPT_SCHEDULE_DEPTH) {
+ Gpt_CancelInterrupt(privateData);
+ }
+ }
+ spin_unlock_irqrestore(&(privateData->GpTimerLock),dwIntFlags);
+ }
+ if(!result) {
+ SMSC_WARNING("Gpt_CancelCallBack: Failed");
+ }
+}
+
+bool Gpt_HandleInterrupt(
+ PPRIVATE_DATA privateData,u32 dwIntSts)
+{
+ SMSC_ASSERT(privateData!=NULL);
+ if(dwIntSts&INT_STS_GPT_INT_)
+ {
+ unsigned long dwIntFlags=0;
+ Lan_SetRegDW(INT_STS,INT_STS_GPT_INT_);
+ spin_lock_irqsave(&(privateData->GpTimerLock),dwIntFlags);
+ {
+ u32 index=0;
+ u32 currentTime=Lan_GetRegDW(FREE_RUN);
+ TIME_SPAN timeSpan=MAX_TIME_SPAN;
+ TIME_SPAN nextCallTime=MAX_TIME_SPAN;
+ bool rescheduleRequired=false;
+ for(index=0;index<GPT_SCHEDULE_DEPTH;index++) {
+ if(privateData->GptFunction[index]!=NULL) {
+ timeSpan=Gpt_FreeRunCompare(privateData->GptCallTime[index],currentTime);
+ if(timeSpan<1250) {
+ void (*callBackFunction)(PPRIVATE_DATA privateData);
+ callBackFunction=privateData->GptFunction[index];
+ privateData->GptFunction[index]=NULL;
+ spin_unlock_irqrestore(&(privateData->GpTimerLock),dwIntFlags);
+ privateData->Gpt_scheduled_slot_index = GPT_SCHEDULE_DEPTH;
+ callBackFunction(privateData);
+ spin_lock_irqsave(&(privateData->GpTimerLock),dwIntFlags);
+ }
+ }
+ }
+ for(index=0;index<GPT_SCHEDULE_DEPTH;index++) {
+ if(privateData->GptFunction[index]!=NULL) {
+ rescheduleRequired=true;
+ timeSpan=Gpt_FreeRunCompare(privateData->GptCallTime[index],currentTime);
+ if(nextCallTime>timeSpan) {
+ nextCallTime=timeSpan;
+ privateData->Gpt_scheduled_slot_index = index;
+ }
+ }
+ }
+ if(rescheduleRequired) {
+ Gpt_ScheduleInterrupt(privateData,nextCallTime);
+ }
+ }
+ spin_unlock_irqrestore(&(privateData->GpTimerLock),dwIntFlags);
+ return true;
+ }
+ return false;
+}
+
+void GptCB_RxCompleteMulticast(PPRIVATE_DATA privateData)
+{
+ Rx_CompleteMulticastUpdate (privateData);
+}
+
+void GptCB_RestartBurst(PPRIVATE_DATA privateData)
+{
+ if(privateData->RxFlowControlActive) {
+ privateData->RxFlowBurstActive=true;
+ if(privateData->RxFlowBurstWorkLoad>privateData->RxFlowBurstMaxWorkLoad) {
+ privateData->RxFlowBurstWorkLoad-=privateData->RxFlowBurstMaxWorkLoad;
+ } else {
+ privateData->RxFlowBurstWorkLoad=0;
+ }
+ Gpt_ScheduleCallBack(privateData,GptCB_RestartBurst,
+ privateData->RxFlowParameters.BurstPeriod);
+ }
+ Lan_EnableInterrupt(privateData,privateData->RxInterrupts);
+}
+
+void GptCB_MeasureRxThroughput(PPRIVATE_DATA privateData)
+{
+ if(privateData->RxFlowMeasuredMaxThroughput<privateData->RxFlowCurrentThroughput) {
+ privateData->RxFlowMeasuredMaxThroughput=privateData->RxFlowCurrentThroughput;
+ }
+ if(privateData->RxFlowMeasuredMaxPacketCount<privateData->RxFlowCurrentPacketCount) {
+ privateData->RxFlowMeasuredMaxPacketCount=privateData->RxFlowCurrentPacketCount;
+ }
+ if(privateData->RxFlowCurrentThroughput!=0) {
+ if(privateData->RxFlowMaxWorkLoad!=0) {
+ if(!(privateData->RxFlowControlActive)) {
+ u32 activationLevel=
+ (privateData->RxFlowMaxWorkLoad*(100+RX_FLOW_ACTIVATION))/100;
+ if(privateData->RxFlowCurrentWorkLoad>=activationLevel) {
+ privateData->RxFlowControlActive=true;
+ privateData->RxFlowBurstActive=true;
+ privateData->RxFlowBurstWorkLoad=0;
+ Gpt_ScheduleCallBack(privateData,GptCB_RestartBurst,
+ privateData->RxFlowParameters.BurstPeriod);
+ //SET_GPIO(GP_TX);
+ }
+ } else {
+ u32 deactivationLevel=
+ (privateData->RxFlowMaxWorkLoad*(100-RX_FLOW_DEACTIVATION))/100;
+ if(privateData->RxFlowCurrentWorkLoad<=deactivationLevel) {
+ privateData->RxFlowControlActive=false;
+ //CLEAR_GPIO(GP_TX);
+ }
+ }
+ }
+ privateData->RxFlowCurrentThroughput=0;
+ privateData->RxFlowCurrentPacketCount=0;
+ privateData->RxFlowCurrentWorkLoad=0;
+ Gpt_ScheduleCallBack(privateData,GptCB_MeasureRxThroughput,1000);
+ } else {
+ if(privateData->RxFlowMaxWorkLoad!=0) {
+ if(privateData->RxFlowControlActive) {
+ privateData->RxFlowControlActive=false;
+ //CLEAR_GPIO(GP_TX);
+ }
+ }
+ privateData->MeasuringRxThroughput=false;
+ }
+}
+
+irqreturn_t Smsc9118_ISR(int Irq, void *dev_id)
+{
+ u32 dwIntCfg=0;
+ u32 dwIntSts=0;
+ u32 dwIntEn=0;
+ u32 dwIntBits=0;
+ PPRIVATE_DATA privateData=(PPRIVATE_DATA)dev_id;
+ bool serviced=false;
+
+ Irq=Irq;//make lint happy
+
+ if(privateData==NULL) {
+ SMSC_WARNING("Smsc9118_ISR(privateData==NULL)");
+ goto DONE;
+ }
+ if(privateData->dwLanBase==0) {
+ SMSC_WARNING("Smsc9118_ISR(dwLanBase==0)");
+ goto DONE;
+ }
+ SET_GPIO(GP_ISR);
+ dwIntCfg=Lan_GetRegDW(INT_CFG);
+ if((dwIntCfg&0x00001100)!=0x00001100) {
+ SMSC_TRACE("In ISR, not my interrupt, dwIntCfg=0x%08X",
+ dwIntCfg);
+ goto ALMOST_DONE;
+ }
+
+ {
+ /*
+ * KH: Neither is true for 9210
+ u32 reservedBits;
+ if(OLD_REGISTERS(privateData)) {
+ reservedBits=0x00FFEEEEUL;
+ } else {
+ reservedBits=0x00FFCEEEUL;
+ }
+ */
+ /*
+ reservedBits = 0x00FF8EEEUL;
+ if(dwIntCfg&reservedBits) {
+ SMSC_WARNING("In ISR, reserved bits are high.\n");
+ SMSC_TRACE("(reserved=0x%08X int=0x%08X)\n", reservedBits, dwIntCfg);
+ //this could mean surprise removal
+ goto ALMOST_DONE;
+ }
+ */
+ }
+
+ dwIntSts=Lan_GetRegDW(INT_STS);
+ dwIntEn=Lan_GetRegDW(INT_EN);
+ dwIntBits=dwIntSts&dwIntEn;
+ //SMSC_TRACE("dwIntBits= 0x%x8l \n", dwIntBits);
+ privateData->LastIntStatus3=privateData->LastIntStatus2;
+ privateData->LastIntStatus2=privateData->LastIntStatus1;
+ privateData->LastIntStatus1=dwIntBits;
+ if(Lan_HandleSoftwareInterrupt(privateData,dwIntBits)) {
+ serviced=true;
+ }
+ if(Gpt_HandleInterrupt(privateData,dwIntBits)) {
+ serviced=true;
+ }
+ if(Tx_HandleInterrupt(privateData,dwIntBits)) {
+ serviced=true;
+ }
+
+ if(RxStop_HandleInterrupt(privateData,dwIntBits)) {
+ serviced=true;
+ }
+
+
+ if(Rx_HandleInterrupt(privateData,dwIntBits)) {
+ serviced=true;
+ }
+
+ if(!serviced) {
+ SMSC_WARNING("unserviced interrupt dwIntCfg=0x%08X,dwIntSts=0x%08X,dwIntEn=0x%08X,dwIntBits=0x%08X",
+ dwIntCfg,dwIntSts,dwIntEn,dwIntBits);
+ }
+
+ALMOST_DONE:
+ CLEAR_GPIO(GP_ISR);
+DONE:
+ return IRQ_RETVAL(serviced);
+}
+
+#ifdef USE_PHY_WORK_AROUND
+bool Phy_Reset(PPRIVATE_DATA privateData,VL_KEY keyCode)
+{
+ bool result=false;
+ WORD wTemp=0;
+ u32 dwLoopCount=100000;
+ SMSC_TRACE("Performing PHY BCR Reset");
+ Phy_SetRegW(privateData,PHY_BCR,PHY_BCR_RESET_,keyCode);
+ do {
+ udelay(10);
+ wTemp=Phy_GetRegW(privateData,PHY_BCR,keyCode);
+ dwLoopCount--;
+ } while((dwLoopCount>0)&&(wTemp&PHY_BCR_RESET_));
+ if(wTemp&PHY_BCR_RESET_) {
+ SMSC_WARNING("Phy Reset failed to complete.");
+ goto DONE;
+ }
+ //extra delay required because the phy may not be completed with its reset
+ // when PHY_BCR_RESET_ is cleared.
+ // They say 256 uS is enough delay but I'm using 500 here to be safe
+ udelay(500);
+ result=true;
+DONE:
+ return result;
+}
+
+u32 Phy_LBT_GetTxStatus(PPRIVATE_DATA privateData)
+{
+ u32 result=Lan_GetRegDW(TX_FIFO_INF);
+ if(OLD_REGISTERS(privateData)) {
+ result&=TX_FIFO_INF_TSFREE_;
+ if(result!=0x00800000UL) {
+ result=Lan_GetRegDW(TX_STATUS_FIFO);
+ } else {
+ result=0;
+ }
+ } else {
+ result&=TX_FIFO_INF_TSUSED_;
+ if(result!=0x00000000UL) {
+ result=Lan_GetRegDW(TX_STATUS_FIFO);
+ } else {
+ result=0;
+ }
+ }
+ return result;
+}
+
+u32 Phy_LBT_GetRxStatus(PPRIVATE_DATA privateData)
+{
+ u32 result=Lan_GetRegDW(RX_FIFO_INF);
+ if(result&0x00FF0000UL) {
+ //Rx status is available, read it
+ result=Lan_GetRegDW(RX_STATUS_FIFO);
+ } else {
+ result=0;
+ }
+ return result;
+}
+
+bool Phy_TransmitTestPacket(PPRIVATE_DATA privateData)
+{
+ bool result=false;
+ u32 dwLoopCount=0;
+ u32 dwTxCmdA=0;
+ u32 dwTxCmdB=0;
+ u32 dwStatus=0;
+
+ //write Tx Packet to 118
+ dwTxCmdA=
+ ((((u32)(privateData->LoopBackTxPacket))&0x03UL)<<16) | //u32 alignment adjustment
+ TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ |
+ ((u32)(MIN_PACKET_SIZE));
+ dwTxCmdB=
+ (((u32)(MIN_PACKET_SIZE))<<16) |
+ ((u32)(MIN_PACKET_SIZE));
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+ Platform_WriteFifo(
+ privateData->dwLanBase,
+ (u32 *)(((u32)(privateData->LoopBackTxPacket))&0xFFFFFFFCUL),
+ (((u32)(MIN_PACKET_SIZE))+3+
+ (((u32)(privateData->LoopBackTxPacket))&0x03UL))>>2);
+
+ //wait till transmit is done
+ dwLoopCount=60;
+ while((dwLoopCount>0)&&((dwStatus=Phy_LBT_GetTxStatus(privateData))==0)) {
+ udelay(5);
+ dwLoopCount--;
+ }
+ if(dwStatus==0) {
+ SMSC_WARNING("Failed to Transmit during Packet Test");
+ goto DONE;
+ }
+ if(dwStatus&0x00008000UL) {
+ SMSC_WARNING("Transmit encountered errors during Packet Test");
+ goto DONE;
+ }
+DONE:
+ return result;
+}
+
+bool Phy_CheckLoopBackPacket(PPRIVATE_DATA privateData)
+
+{
+ bool result=false;
+ u32 tryCount=0;
+ u32 dwLoopCount=0;
+ for(tryCount=0;tryCount<10;tryCount++)
+ {
+ u32 dwTxCmdA=0;
+ u32 dwTxCmdB=0;
+ u32 dwStatus=0;
+ u32 dwPacketLength=0;
+
+ //zero-out Rx Packet memory
+ memset(privateData->LoopBackRxPacket,0,MIN_PACKET_SIZE);
+
+ //write Tx Packet to 118
+ dwTxCmdA=
+ ((((u32)(privateData->LoopBackTxPacket))&0x03UL)<<16) | //u32 alignment adjustment
+ TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ |
+ ((u32)(MIN_PACKET_SIZE));
+ dwTxCmdB=
+ (((u32)(MIN_PACKET_SIZE))<<16) |
+ ((u32)(MIN_PACKET_SIZE));
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+ Platform_WriteFifo(
+ privateData->dwLanBase,
+ (u32 *)(((u32)(privateData->LoopBackTxPacket))&0xFFFFFFFCUL),
+ (((u32)(MIN_PACKET_SIZE))+3+
+ (((u32)(privateData->LoopBackTxPacket))&0x03UL))>>2);
+
+ //wait till transmit is done
+ dwLoopCount=60;
+ while((dwLoopCount>0)&&((dwStatus=Phy_LBT_GetTxStatus(privateData))==0)) {
+ udelay(5);
+ dwLoopCount--;
+ }
+ if(dwStatus==0) {
+ SMSC_WARNING("Failed to Transmit during Loop Back Test");
+ continue;
+ }
+ if(dwStatus&0x00008000UL) {
+ SMSC_WARNING("Transmit encountered errors during Loop Back Test");
+ continue;
+ }
+
+ //wait till receive is done
+ dwLoopCount=60;
+ while((dwLoopCount>0)&&((dwStatus=Phy_LBT_GetRxStatus(privateData))==0))
+ {
+ udelay(5);
+ dwLoopCount--;
+ }
+ if(dwStatus==0) {
+ SMSC_WARNING("Failed to Receive during Loop Back Test");
+ continue;
+ }
+ if(dwStatus&RX_STS_ES_)
+ {
+ SMSC_WARNING("Receive encountered errors during Loop Back Test");
+ continue;
+ }
+
+ dwPacketLength=((dwStatus&0x3FFF0000UL)>>16);
+
+ Platform_ReadFifo(
+ privateData->dwLanBase,
+ ((u32 *)(privateData->LoopBackRxPacket)),
+ (dwPacketLength+3+(((u32)(privateData->LoopBackRxPacket))&0x03UL))>>2);
+
+ if(dwPacketLength!=(MIN_PACKET_SIZE+4)) {
+ SMSC_WARNING("Unexpected packet size during loop back test, size=%d, will retry",dwPacketLength);
+ } else {
+ u32 byteIndex=0;
+ bool foundMissMatch=false;
+ for(byteIndex=0;byteIndex<MIN_PACKET_SIZE;byteIndex++) {
+ if(privateData->LoopBackTxPacket[byteIndex]!=privateData->LoopBackRxPacket[byteIndex])
+ {
+ foundMissMatch=true;
+ break;
+ }
+ }
+ if(!foundMissMatch) {
+ SMSC_TRACE("Successfully Verified Loop Back Packet");
+ result=true;
+ goto DONE;
+ } else {
+ SMSC_WARNING("Data miss match during loop back test, will retry.");
+ }
+ }
+ }
+DONE:
+ return result;
+}
+
+bool Phy_LoopBackTest(PPRIVATE_DATA privateData)
+{
+ bool result=false;
+ u32 byteIndex=0;
+ u32 tryCount=0;
+ // u32 failed=0;
+ //Initialize Tx Packet
+ for(byteIndex=0;byteIndex<6;byteIndex++) {
+ //use broadcast destination address
+ privateData->LoopBackTxPacket[byteIndex]=(BYTE)0xFF;
+ }
+ for(byteIndex=6;byteIndex<12;byteIndex++) {
+ //use incrementing source address
+ privateData->LoopBackTxPacket[byteIndex]=(BYTE)byteIndex;
+ }
+ //Set length type field
+ privateData->LoopBackTxPacket[12]=0x00;
+ privateData->LoopBackTxPacket[13]=0x00;
+ for(byteIndex=14;byteIndex<MIN_PACKET_SIZE;byteIndex++)
+ {
+ privateData->LoopBackTxPacket[byteIndex]=(BYTE)byteIndex;
+ }
+ //TRY_AGAIN:
+ {
+ u32 dwRegVal=Lan_GetRegDW(HW_CFG);
+ dwRegVal&=(HW_CFG_TX_FIF_SZ_|0x00000FFFUL);
+ dwRegVal|=HW_CFG_SF_;
+ Lan_SetRegDW(HW_CFG,dwRegVal);
+ }
+ Lan_SetRegDW(TX_CFG,TX_CFG_TX_ON_);
+
+ Lan_SetRegDW(RX_CFG,(((u32)(privateData->LoopBackRxPacket))&0x03)<<8);
+
+ {
+
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ //Set Phy to 10/FD, no ANEG,
+ Phy_SetRegW(privateData,PHY_BCR,0x0100,keyCode);
+
+ //enable MAC Tx/Rx, FD
+ Mac_SetRegDW(privateData,MAC_CR,MAC_CR_FDPX_|MAC_CR_TXEN_|MAC_CR_RXEN_,keyCode);
+
+ // Phy_TransmitTestPacket(privateData);
+
+ //set Phy to loopback mode
+ Phy_SetRegW(privateData,PHY_BCR,0x4100,keyCode);
+
+ for(tryCount=0;tryCount<10;tryCount++) {
+ if(Phy_CheckLoopBackPacket(privateData))
+ {
+ result=true;
+ goto DONE;
+ }
+ privateData->dwResetCount++;
+ //disable MAC rx
+ Mac_SetRegDW(privateData,MAC_CR,0UL,keyCode);
+ Phy_Reset(privateData,keyCode);
+
+ //Set Phy to 10/FD, no ANEG, and Loopbackmode
+ Phy_SetRegW(privateData,PHY_BCR,0x4100,keyCode);
+
+ //enable MAC Tx/Rx, FD
+ Mac_SetRegDW(privateData,MAC_CR,MAC_CR_FDPX_|MAC_CR_TXEN_|MAC_CR_RXEN_,keyCode);
+ }
+ // if(failed<2) {
+ // if(tryCount>=10) {
+ // u32 timeOut=10000;
+ // Lan_ShowRegs(privateData);
+ // SMSC_TRACE("Performing full reset");
+ // privateData->Lan9118->HW_CFG=HW_CFG_SRST_;
+ // while((timeOut>0)&&(privateData->Lan9118->HW_CFG&HW_CFG_SRST_)) {
+ // udelay(1);
+ // timeOut--;
+ // }
+ // failed++;
+ // goto TRY_AGAIN;
+ // }
+ // }
+DONE:
+ //disable MAC
+ Mac_SetRegDW(privateData,MAC_CR,0UL,keyCode);
+ //Cancel Phy loopback mode
+ Phy_SetRegW(privateData,PHY_BCR,0U,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ }
+
+ Lan_SetRegDW(TX_CFG,0UL);
+ Lan_SetRegDW(RX_CFG,0UL);
+
+ return result;
+}
+
+#endif //USE_PHY_WORK_AROUND
+void Phy_SetLink(PPRIVATE_DATA privateData,
+ u32 dwLinkRequest)
+{
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ if(dwLinkRequest&LINK_AUTO_NEGOTIATE) {
+ WORD wTemp;
+ wTemp=Phy_GetRegW(privateData,
+ PHY_ANEG_ADV,keyCode);
+ wTemp&=~PHY_ANEG_ADV_PAUSE_;
+ if(dwLinkRequest&LINK_ASYMMETRIC_PAUSE) {
+ wTemp|=PHY_ANEG_ADV_ASYMP_;
+ }
+ if(dwLinkRequest&LINK_SYMMETRIC_PAUSE) {
+ wTemp|=PHY_ANEG_ADV_SYMP_;
+ }
+ wTemp&=~PHY_ANEG_ADV_SPEED_;
+ if(dwLinkRequest&LINK_SPEED_10HD) {
+ wTemp|=PHY_ANEG_ADV_10H_;
+ }
+ if(dwLinkRequest&LINK_SPEED_10FD) {
+ wTemp|=PHY_ANEG_ADV_10F_;
+ }
+ if(dwLinkRequest&LINK_SPEED_100HD) {
+ wTemp|=PHY_ANEG_ADV_100H_;
+ }
+ if(dwLinkRequest&LINK_SPEED_100FD) {
+ wTemp|=PHY_ANEG_ADV_100F_;
+ }
+ Phy_SetRegW(privateData,PHY_ANEG_ADV,wTemp,keyCode);
+
+ // begin to establish link
+ privateData->dwRemoteFaultCount=0;
+ Phy_SetRegW(privateData,
+ PHY_BCR,
+ PHY_BCR_AUTO_NEG_ENABLE_|
+ PHY_BCR_RESTART_AUTO_NEG_,
+ keyCode);
+ } else {
+ WORD wTemp=0;
+ if(dwLinkRequest&(LINK_SPEED_100FD)) {
+ dwLinkRequest=LINK_SPEED_100FD;
+ } else if(dwLinkRequest&(LINK_SPEED_100HD)) {
+ dwLinkRequest=LINK_SPEED_100HD;
+ } else if(dwLinkRequest&(LINK_SPEED_10FD)) {
+ dwLinkRequest=LINK_SPEED_10FD;
+ } else if(dwLinkRequest&(LINK_SPEED_10HD)) {
+ dwLinkRequest=LINK_SPEED_10HD;
+ }
+ if(dwLinkRequest&(LINK_SPEED_10FD|LINK_SPEED_100FD)) {
+ wTemp|=PHY_BCR_DUPLEX_MODE_;
+ }
+ if(dwLinkRequest&(LINK_SPEED_100HD|LINK_SPEED_100FD)) {
+ wTemp|=PHY_BCR_SPEED_SELECT_;
+ }
+ Phy_SetRegW(privateData,PHY_BCR,wTemp,keyCode);
+ }
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+}
+
+void Phy_SetAutoMdixSts(PPRIVATE_DATA privateData,
+ WORD wAutoMdixSts)
+{
+ WORD SpecialCtrlSts=0U;
+
+ if (((privateData->dwGeneration)>2) && (!(privateData->ExtPhy)))
+ {
+ if (wAutoMdixSts > 2)
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ SpecialCtrlSts=Phy_GetRegW(privateData, SPECIAL_CTRL_STS,keyCode);
+ SpecialCtrlSts = (SpecialCtrlSts&0x1FFF);
+ Phy_SetRegW(privateData, SPECIAL_CTRL_STS,SpecialCtrlSts,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+
+ if (Lan_GetRegDW(HW_CFG) & HW_CFG_AMDIX_EN_STRAP_STS_) {
+ SMSC_TRACE("Auto-MDIX Enable by default!!!");
+ }
+ else {
+ SMSC_TRACE("Auto-MDIX Disable by default!!!");
+ }
+ }
+ else
+ {
+
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ SpecialCtrlSts=Phy_GetRegW(privateData, SPECIAL_CTRL_STS,keyCode);
+ SpecialCtrlSts = (((wAutoMdixSts+4) << 13) | (SpecialCtrlSts&0x1FFF));
+ Phy_SetRegW(privateData, SPECIAL_CTRL_STS,SpecialCtrlSts,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+
+ if (wAutoMdixSts & AMDIX_ENABLE) {
+ SMSC_TRACE("Override Strap, Enable Auto-MDIX ");
+ } else if (wAutoMdixSts & AMDIX_DISABLE_CROSSOVER) {
+ SMSC_TRACE("Override Strap, Disable Auto-MDIX, CrossOver Cable");
+ } else {
+ SMSC_TRACE("Override Strap, Disable Auto-MDIX, Straight Cable");
+ }
+
+ }
+ }
+
+ else {
+ SMSC_TRACE("This chip or PHY doesn't support HP AMDIX!!!");
+ }
+
+}
+
+void Phy_GetAutoMdixSts(PPRIVATE_DATA privateData)
+{
+
+
+ WORD SpecialCtrlSts=0U;
+ unsigned long dwIntFlags=0;
+
+ if (((privateData->dwGeneration)>2) && (!(privateData->ExtPhy)))
+ {
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ SpecialCtrlSts=Phy_GetRegW(privateData, SPECIAL_CTRL_STS,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+
+ if (SpecialCtrlSts & SPECIAL_CTRL_STS_OVRRD_AMDIX_) {
+
+ if (SpecialCtrlSts & SPECIAL_CTRL_STS_AMDIX_ENABLE_) {
+ SMSC_TRACE("AutoMdix Status: Override Strap, Enable Auto Mdix");
+ }
+ else if (SpecialCtrlSts & SPECIAL_CTRL_STS_AMDIX_STATE_) {
+
+ SMSC_TRACE("AutoMdix Status: Override Strap, Disable Auto Mdix, CrossOver Cable");
+
+ } else {
+
+ SMSC_TRACE("AutoMdix Status: Override Strap, Disable Auto Mdix, Straight Cable");
+ }
+
+ }
+ else {
+ if (Lan_GetRegDW(HW_CFG) & HW_CFG_AMDIX_EN_STRAP_STS_) {
+ SMSC_TRACE("AutoMdix Status: Enable by default!!!");
+ }
+ else {
+ SMSC_TRACE("AutoMdix Status: Disable by default!!!");
+ }
+ }
+
+ }
+ else {
+ SMSC_TRACE("This chip or PHY doesn't support HP AMDIX!!!");
+ }
+
+}
+
+
+bool Phy_Initialize(
+ PPRIVATE_DATA privateData,
+ u32 dwPhyAddr,
+ u32 dwLinkRequest)
+{
+ bool result=false;
+ u32 dwTemp=0;
+ WORD wTemp=0;
+ u32 dwLoopCount=0;
+ // WORD SpecialCtrlSts=0U;
+
+ SMSC_TRACE("-->Phy_Initialize");
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->dwLanBase!=0);
+ SMSC_ASSERT(dwLinkRequest<=0x7FUL);
+ privateData->ExtPhy=false;
+
+ if(dwPhyAddr!=0xFFFFFFFFUL) {
+ switch(privateData->dwIdRev&0xFFFF0000) {
+ case 0x117A0000UL:
+ case 0x115A0000UL:
+ goto EXTERNAL_PHY_SUPPORTED;
+ case 0x01170000UL:
+ case 0x01150000UL:
+ if(privateData->dwIdRev&0x0000FFFF) {
+ u32 dwHwCfg=0;
+EXTERNAL_PHY_SUPPORTED:
+ dwHwCfg=Lan_GetRegDW(HW_CFG);
+ if(dwHwCfg&HW_CFG_EXT_PHY_DET_) {
+ //External phy is requested, supported, and detected
+ //Attempt to switch
+ //NOTE: Assuming Rx and Tx are stopped
+ // because Phy_Initialize is called before
+ // Rx_Initialize and Tx_Initialize
+ WORD wPhyId1=0;
+ WORD wPhyId2=0;
+
+ //Disable phy clocks to the mac
+ dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_);
+ dwHwCfg|= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
+ Lan_SetRegDW(HW_CFG,dwHwCfg);
+ udelay(10);//wait for clocks to acutally stop
+
+ dwHwCfg|=HW_CFG_EXT_PHY_EN_;
+ Lan_SetRegDW(HW_CFG,dwHwCfg);
+
+ dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_);
+ dwHwCfg|= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
+ Lan_SetRegDW(HW_CFG,dwHwCfg);
+ udelay(10);//wait for clocks to actually start
+
+ dwHwCfg|=HW_CFG_SMI_SEL_;
+ Lan_SetRegDW(HW_CFG,dwHwCfg);
+
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ if(dwPhyAddr<=31) {
+ //only check the phy address specified
+ privateData->dwPhyAddress=dwPhyAddr;
+ wPhyId1=Phy_GetRegW(privateData,PHY_ID_1,keyCode);
+ wPhyId2=Phy_GetRegW(privateData,PHY_ID_2,keyCode);
+ } else {
+ //auto detect phy
+ u32 address=0;
+ for(address=0;address<=31;address++) {
+ privateData->dwPhyAddress=address;
+ wPhyId1=Phy_GetRegW(privateData,PHY_ID_1,keyCode);
+ wPhyId2=Phy_GetRegW(privateData,PHY_ID_2,keyCode);
+ if((wPhyId1!=0xFFFFU)||(wPhyId2!=0xFFFFU)) {
+ SMSC_TRACE("Detected Phy at address = 0x%02X = %d",
+ address,address);
+ break;
+ }
+ }
+ if(address>=32) {
+ SMSC_WARNING("Failed to auto detect external phy");
+ }
+ }
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ }
+ if((wPhyId1==0xFFFFU)&&(wPhyId2==0xFFFFU)) {
+ SMSC_WARNING("External Phy is not accessable");
+ SMSC_WARNING(" using internal phy instead");
+ //revert back to interal phy settings.
+
+ //Disable phy clocks to the mac
+ dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_);
+ dwHwCfg|= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
+ Lan_SetRegDW(HW_CFG,dwHwCfg);
+ udelay(10);//wait for clocks to actually stop
+
+ dwHwCfg&=(~HW_CFG_EXT_PHY_EN_);
+ Lan_SetRegDW(HW_CFG,dwHwCfg);
+
+ dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_);
+ dwHwCfg|= HW_CFG_PHY_CLK_SEL_INT_PHY_;
+ Lan_SetRegDW(HW_CFG,dwHwCfg);
+ udelay(10);//wait for clocks to actually start
+
+ dwHwCfg&=(~HW_CFG_SMI_SEL_);
+ Lan_SetRegDW(HW_CFG,dwHwCfg);
+ goto USE_INTERNAL_PHY;
+ } else {
+ SMSC_TRACE("Successfully switched to external phy");
+ privateData->ExtPhy=true;
+#ifdef USE_LED1_WORK_AROUND
+ privateData->NotUsingExtPhy=0;
+#endif
+ }
+ } else {
+ SMSC_WARNING("No External Phy Detected");
+ SMSC_WARNING(" using internal phy instead");
+ goto USE_INTERNAL_PHY;
+ }
+ } else {
+ SMSC_WARNING("External Phy is not supported");
+ SMSC_WARNING(" using internal phy instead");
+ goto USE_INTERNAL_PHY;
+ };break;
+ default:
+ SMSC_WARNING("External Phy is not supported");
+ SMSC_WARNING(" using internal phy instead");
+ goto USE_INTERNAL_PHY;
+ }
+ } else {
+USE_INTERNAL_PHY:
+
+ privateData->dwPhyAddress=1;
+ privateData->ExtPhy=false;
+#ifdef USE_LED1_WORK_AROUND
+ if(privateData->dwGeneration<=2) {
+ privateData->NotUsingExtPhy=1;
+ } else {
+ //Generation 3 or higher has the LED problem fixed
+ // to disable the workaround pretend the phy is external
+ privateData->NotUsingExtPhy=0;
+ }
+#endif
+
+ Phy_SetAutoMdixSts(privateData,AutoMdix);
+ }
+
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ dwTemp=Phy_GetRegW(privateData,PHY_ID_2,keyCode);
+ privateData->bPhyRev=((BYTE)(dwTemp&(0x0FUL)));
+ privateData->bPhyModel=((BYTE)((dwTemp>>4)&(0x3FUL)));
+ privateData->dwPhyId=((dwTemp&(0xFC00UL))<<8);
+ dwTemp=Phy_GetRegW(privateData,PHY_ID_1,keyCode);
+ privateData->dwPhyId|=((dwTemp&(0x0000FFFFUL))<<2);
+
+ SMSC_TRACE("dwPhyId==0x%08X,bPhyModel==0x%02X,bPhyRev==0x%02X",
+ privateData->dwPhyId,
+ privateData->bPhyModel,
+ privateData->bPhyRev);
+
+ privateData->dwLinkSpeed=LINK_OFF;
+ privateData->dwLinkSettings=LINK_OFF;
+ //reset the PHY
+ Phy_SetRegW(privateData,PHY_BCR,PHY_BCR_RESET_,keyCode);
+ dwLoopCount=100000;
+ do {
+
+ udelay(10);
+ wTemp=Phy_GetRegW(privateData,PHY_BCR,keyCode);
+ dwLoopCount--;
+ } while((dwLoopCount>0) && (wTemp&PHY_BCR_RESET_));
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ }
+
+ if(wTemp&PHY_BCR_RESET_) {
+ SMSC_WARNING("PHY reset failed to complete.");
+ goto DONE;
+ }
+
+#ifdef USE_PHY_WORK_AROUND
+ if(privateData->dwGeneration<=2) {
+ // printk("phy_LoopBackTest\n");
+ if(!Phy_LoopBackTest(privateData)) {
+ SMSC_WARNING("Failed Loop back test");
+ goto DONE;
+ } else {
+ SMSC_TRACE("Passed Loop Back Test");
+ }
+ }
+#endif
+
+ Phy_SetLink(privateData,dwLinkRequest);
+
+ init_timer(&(privateData->LinkPollingTimer));
+ privateData->LinkPollingTimer.function=Phy_CheckLink;
+ privateData->LinkPollingTimer.data=(unsigned long)privateData;
+ privateData->LinkPollingTimer.expires=jiffies+HZ;
+ add_timer(&(privateData->LinkPollingTimer));
+
+ result=true;
+DONE:
+ SMSC_TRACE("<--Phy_Initialize, result=%s",result?"true":"false");
+ return result;
+}
+
+WORD Phy_GetRegW(
+ PPRIVATE_DATA privateData,
+ u32 dwRegIndex,
+ VL_KEY keyCode)
+{
+ u32 dwAddr=0;
+ int i=0;
+ WORD result=0xFFFFU;
+
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->LanInitialized==true);
+ SMSC_ASSERT(Vl_CheckLock(&(privateData->MacPhyLock),keyCode));
+
+ // confirm MII not busy
+ if ((Mac_GetRegDW(privateData, MII_ACC,keyCode) & MII_ACC_MII_BUSY_) != 0UL)
+ {
+ SMSC_WARNING("MII is busy in Phy_GetRegW???");
+ result=0;
+ goto DONE;
+ }
+
+ // set the address, index & direction (read from PHY)
+ dwAddr = ((privateData->dwPhyAddress&0x1FUL)<<11) | ((dwRegIndex & 0x1FUL)<<6);
+ Mac_SetRegDW(privateData, MII_ACC, dwAddr,keyCode);
+
+ // wait for read to complete w/ timeout
+ for(i=0;i<100;i++) {
+ // see if MII is finished yet
+ if ((Mac_GetRegDW(privateData, MII_ACC,keyCode) & MII_ACC_MII_BUSY_) == 0UL)
+ {
+ // get the read data from the MAC & return i
+ result=((WORD)Mac_GetRegDW(privateData, MII_DATA,keyCode));
+ goto DONE;
+ }
+ }
+ SMSC_WARNING("timeout waiting for MII write to finish");
+
+DONE:
+ return result;
+}
+
+void Phy_SetRegW(
+ PPRIVATE_DATA privateData,
+ u32 dwRegIndex,WORD wVal,
+ VL_KEY keyCode)
+{
+ u32 dwAddr=0;
+ int i=0;
+
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->LanInitialized==true);
+
+ SMSC_ASSERT(Vl_CheckLock(&(privateData->MacPhyLock),keyCode));
+
+ if(dwRegIndex==0) {
+ if((wVal&0x1200)==0x1200) {
+ privateData->wLastADVatRestart=privateData->wLastADV;
+ }
+ }
+ if(dwRegIndex==4) {
+ privateData->wLastADV=wVal;
+ }
+
+ // confirm MII not busy
+ if ((Mac_GetRegDW(privateData, MII_ACC,keyCode) & MII_ACC_MII_BUSY_) != 0UL)
+ {
+ SMSC_WARNING("MII is busy in Phy_SetRegW???");
+ goto DONE;
+ }
+
+ // put the data to write in the MAC
+ Mac_SetRegDW(privateData, MII_DATA, (u32)wVal,keyCode);
+
+ // set the address, index & direction (write to PHY)
+ dwAddr = ((privateData->dwPhyAddress&0x1FUL)<<11) | ((dwRegIndex & 0x1FUL)<<6) | MII_ACC_MII_WRITE_;
+ Mac_SetRegDW(privateData, MII_ACC, dwAddr,keyCode);
+
+ // wait for write to complete w/ timeout
+ for(i=0;i<100;i++) {
+ // see if MII is finished yet
+ if ((Mac_GetRegDW(privateData, MII_ACC,keyCode) & MII_ACC_MII_BUSY_) == 0UL)
+ {
+ goto DONE;
+ }
+ }
+ SMSC_WARNING("timeout waiting for MII write to finish");
+DONE:
+ return;
+}
+
+void Phy_UpdateLinkMode(PPRIVATE_DATA privateData)
+{
+ u32 dwOldLinkSpeed=privateData->dwLinkSpeed;
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+
+ Phy_GetLinkMode(privateData,keyCode);
+
+ if(dwOldLinkSpeed!=(privateData->dwLinkSpeed)) {
+ if(privateData->dwLinkSpeed!=LINK_OFF) {
+ u32 dwRegVal=0;
+ switch(privateData->dwLinkSpeed) {
+ case LINK_SPEED_10HD:
+ SMSC_TRACE("Link is now UP at 10Mbps HD");
+ break;
+ case LINK_SPEED_10FD:
+ SMSC_TRACE("Link is now UP at 10Mbps FD");
+ break;
+ case LINK_SPEED_100HD:
+ SMSC_TRACE("Link is now UP at 100Mbps HD");
+ break;
+ case LINK_SPEED_100FD:
+ SMSC_TRACE("Link is now UP at 100Mbps FD");
+ break;
+ default:
+ SMSC_WARNING("Link is now UP at Unknown Link Speed, dwLinkSpeed=0x%08X",
+ privateData->dwLinkSpeed);
+ break;
+ }
+
+ dwRegVal=Mac_GetRegDW(privateData,MAC_CR,keyCode);
+ dwRegVal&=~(MAC_CR_FDPX_|MAC_CR_RCVOWN_);
+ switch(privateData->dwLinkSpeed) {
+ case LINK_SPEED_10HD:
+ case LINK_SPEED_100HD:
+ dwRegVal|=MAC_CR_RCVOWN_;
+ break;
+ case LINK_SPEED_10FD:
+ case LINK_SPEED_100FD:
+ dwRegVal|=MAC_CR_FDPX_;
+ break;
+ default:break;//make lint happy
+ }
+
+ Mac_SetRegDW(privateData,
+ MAC_CR,dwRegVal,keyCode);
+
+ if(privateData->dwLinkSettings&LINK_AUTO_NEGOTIATE) {
+ WORD linkPartner=0;
+ WORD localLink=0;
+ localLink=Phy_GetRegW(privateData,4,keyCode);
+ linkPartner=Phy_GetRegW(privateData,5,keyCode);
+ switch(privateData->dwLinkSpeed) {
+ case LINK_SPEED_10FD:
+ case LINK_SPEED_100FD:
+ if(((localLink&linkPartner)&((WORD)0x0400U)) != ((WORD)0U)) {
+ //Enable PAUSE receive and transmit
+ Mac_SetRegDW(privateData,FLOW,0xFFFF0002UL,keyCode);
+ Lan_SetBitsDW(AFC_CFG,(afc_cfg&0x0000000FUL));
+ } else if(((localLink&((WORD)0x0C00U))==((WORD)0x0C00U)) &&
+ ((linkPartner&((WORD)0x0C00U))==((WORD)0x0800U)))
+ {
+ //Enable PAUSE receive, disable PAUSE transmit
+ Mac_SetRegDW(privateData,FLOW,0xFFFF0002UL,keyCode);
+ Lan_ClrBitsDW(AFC_CFG,0x0000000FUL);
+ } else {
+ //Disable PAUSE receive and transmit
+ Mac_SetRegDW(privateData,FLOW,0UL,keyCode);
+ Lan_ClrBitsDW(AFC_CFG,0x0000000FUL);
+ };break;
+ case LINK_SPEED_10HD:
+ case LINK_SPEED_100HD:
+ Mac_SetRegDW(privateData,FLOW,0UL,keyCode);
+ Lan_SetBitsDW(AFC_CFG,0x0000000FUL);
+ break;
+ default:break;//make lint happy
+ }
+ SMSC_TRACE("LAN9118: %s,%s,%s,%s,%s,%s",
+ (localLink&PHY_ANEG_ADV_ASYMP_)?"ASYMP":" ",
+ (localLink&PHY_ANEG_ADV_SYMP_)?"SYMP ":" ",
+ (localLink&PHY_ANEG_ADV_100F_)?"100FD":" ",
+ (localLink&PHY_ANEG_ADV_100H_)?"100HD":" ",
+ (localLink&PHY_ANEG_ADV_10F_)?"10FD ":" ",
+ (localLink&PHY_ANEG_ADV_10H_)?"10HD ":" ");
+
+ SMSC_TRACE("Partner: %s,%s,%s,%s,%s,%s",
+ (linkPartner&PHY_ANEG_LPA_ASYMP_)?"ASYMP":" ",
+ (linkPartner&PHY_ANEG_LPA_SYMP_)?"SYMP ":" ",
+ (linkPartner&PHY_ANEG_LPA_100FDX_)?"100FD":" ",
+ (linkPartner&PHY_ANEG_LPA_100HDX_)?"100HD":" ",
+ (linkPartner&PHY_ANEG_LPA_10FDX_)?"10FD ":" ",
+ (linkPartner&PHY_ANEG_LPA_10HDX_)?"10HD ":" ");
+ } else {
+ switch(privateData->dwLinkSpeed) {
+ case LINK_SPEED_10HD:
+ case LINK_SPEED_100HD:
+ Mac_SetRegDW(privateData,FLOW,0x0UL,keyCode);
+ Lan_SetBitsDW(AFC_CFG,0x0000000FUL);
+ break;
+ default:
+ Mac_SetRegDW(privateData,FLOW,0x0UL,keyCode);
+ Lan_ClrBitsDW(AFC_CFG,0x0000000FUL);
+ break;
+ }
+ }
+ netif_carrier_on(privateData->dev);
+ Tx_WakeQueue(privateData,0x01);
+#ifdef USE_LED1_WORK_AROUND
+ if ((g_GpioSettingOriginal & GPIO_CFG_LED1_EN_) &&
+ privateData->NotUsingExtPhy)
+ {
+ // Restore orginal GPIO configuration
+ g_GpioSetting = g_GpioSettingOriginal;
+ Lan_SetRegDW(GPIO_CFG,g_GpioSetting);
+ }
+#endif // USE_LED1_WORK_AROUND
+ } else {
+ SMSC_TRACE("Link is now DOWN");
+ Tx_StopQueue(privateData,0x01);
+ netif_carrier_off(privateData->dev);
+ Mac_SetRegDW(privateData,FLOW,0UL,keyCode);
+ Lan_ClrBitsDW(AFC_CFG,0x0000000FUL);
+#ifdef USE_LED1_WORK_AROUND
+ // Check global setting that LED1 usage is 10/100 indicator
+ // g_GpioSetting = Lan_GetRegDW(GPIO_CFG);
+ if ((g_GpioSetting & GPIO_CFG_LED1_EN_) &&
+ privateData->NotUsingExtPhy)
+ {
+ //Force 10/100 LED off, after saving orginal GPIO configuration
+ g_GpioSettingOriginal = g_GpioSetting;
+
+ g_GpioSetting &= ~GPIO_CFG_LED1_EN_;
+ g_GpioSetting |=
+ (GPIO_CFG_GPIOBUF0_|GPIO_CFG_GPIODIR0_|GPIO_CFG_GPIOD0_);
+ Lan_SetRegDW(GPIO_CFG,g_GpioSetting);
+ }
+#endif // USE_LED1_WORK_AROUND
+ }
+ }
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+}
+
+void Phy_CheckLink(unsigned long ptr)
+{
+ PPRIVATE_DATA privateData=(PPRIVATE_DATA)ptr;
+ if(privateData==NULL) {
+ SMSC_WARNING("Phy_CheckLink(ptr==0)");
+ return;
+ }
+
+ //must call this twice
+ Phy_UpdateLinkMode(privateData);
+ Phy_UpdateLinkMode(privateData);
+
+ if(!(privateData->StopLinkPolling)) {
+ privateData->LinkPollingTimer.expires=jiffies+HZ;
+ add_timer(&(privateData->LinkPollingTimer));
+ }
+}
+
+void Phy_GetLinkMode(
+ PPRIVATE_DATA privateData,
+ VL_KEY keyCode)
+{
+ u32 result=LINK_OFF;
+ WORD wRegVal=0;
+ WORD wRegBSR=Phy_GetRegW(
+ privateData,
+ PHY_BSR,keyCode);
+ privateData->dwLinkSettings=LINK_OFF;
+ if(wRegBSR&PHY_BSR_LINK_STATUS_) {
+ wRegVal=Phy_GetRegW(
+ privateData,
+ PHY_BCR,keyCode);
+ if(wRegVal&PHY_BCR_AUTO_NEG_ENABLE_) {
+ u32 linkSettings=LINK_AUTO_NEGOTIATE;
+ WORD wRegADV=privateData->wLastADVatRestart;
+ // Phy_GetRegW(
+ // privateData,
+ // PHY_ANEG_ADV,keyCode);
+ WORD wRegLPA=Phy_GetRegW(
+ privateData,
+ PHY_ANEG_LPA,keyCode);
+ if(wRegADV&PHY_ANEG_ADV_ASYMP_) {
+ linkSettings|=LINK_ASYMMETRIC_PAUSE;
+ }
+ if(wRegADV&PHY_ANEG_ADV_SYMP_) {
+ linkSettings|=LINK_SYMMETRIC_PAUSE;
+ }
+ if(wRegADV&PHY_ANEG_LPA_100FDX_) {
+ linkSettings|=LINK_SPEED_100FD;
+ }
+ if(wRegADV&PHY_ANEG_LPA_100HDX_) {
+ linkSettings|=LINK_SPEED_100HD;
+ }
+ if(wRegADV&PHY_ANEG_LPA_10FDX_) {
+ linkSettings|=LINK_SPEED_10FD;
+ }
+ if(wRegADV&PHY_ANEG_LPA_10HDX_) {
+ linkSettings|=LINK_SPEED_10HD;
+ }
+ privateData->dwLinkSettings=linkSettings;
+ wRegLPA&=wRegADV;
+ if(wRegLPA&PHY_ANEG_LPA_100FDX_) {
+ result=LINK_SPEED_100FD;
+ } else if(wRegLPA&PHY_ANEG_LPA_100HDX_) {
+ result=LINK_SPEED_100HD;
+ } else if(wRegLPA&PHY_ANEG_LPA_10FDX_) {
+ result=LINK_SPEED_10FD;
+ } else if(wRegLPA&PHY_ANEG_LPA_10HDX_) {
+ result=LINK_SPEED_10HD;
+ }
+ } else {
+ if(wRegVal&PHY_BCR_SPEED_SELECT_) {
+ if(wRegVal&PHY_BCR_DUPLEX_MODE_) {
+ privateData->dwLinkSettings=result=LINK_SPEED_100FD;
+ } else {
+ privateData->dwLinkSettings=result=LINK_SPEED_100HD;
+ }
+ } else {
+ if(wRegVal&PHY_BCR_DUPLEX_MODE_) {
+ privateData->dwLinkSettings=result=LINK_SPEED_10FD;
+ } else {
+ privateData->dwLinkSettings=result=LINK_SPEED_10HD;
+ }
+ }
+ }
+ }
+ privateData->dwLinkSpeed=result;
+}
+
+extern int smsc_prom_get_ethernet_mac_addr(char *addr);
+
+bool Mac_Initialize(PPRIVATE_DATA privateData)
+{
+ unsigned char ea[6];
+ int result;
+ u32 dwHigh16, dwLow32;
+ unsigned long dwIntFlags = 0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+
+ SMSC_ASSERT(privateData!=NULL);
+#ifdef CONFIG_MIPS_HMP10
+ result = smsc_prom_get_ethernet_mac_addr(ea);
+#else
+ result = prom_get_ethernet_addr(ea);
+#endif
+
+ if (result == 0) {
+ SMSC_TRACE("Got ethernet addr %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X from prom\n",
+ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5] );
+ dwHigh16 = (ea[5] << 8) | ea[4];
+ Mac_SetRegDW(privateData, ADDRH, dwHigh16, keyCode);
+ dwLow32 = (ea[3] << 24) | (ea[2] << 16) | (ea[1] << 8) | ea[0];
+ Mac_SetRegDW(privateData, ADDRL, dwLow32, keyCode);
+ } else {
+ SMSC_TRACE("Failed to get ethernet addr from prom\n");
+ return result;
+ }
+
+ return true;
+}
+
+static bool MacNotBusy(PPRIVATE_DATA privateData, VL_KEY keyCode)
+{
+ int i=0;
+ SMSC_ASSERT(Vl_CheckLock(&(privateData->MacPhyLock),keyCode));
+ // wait for MAC not busy, w/ timeout
+ for(i=0;i<40;i++)
+ {
+ if((Lan_GetRegDW(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY_)==(0UL)) {
+ return true;
+ }
+ }
+ SMSC_WARNING("timeout waiting for MAC not BUSY. MAC_CSR_CMD = 0x%08X",
+ Lan_GetRegDW(MAC_CSR_CMD));
+ return false;
+}
+
+u32 Mac_GetRegDW(PPRIVATE_DATA privateData,u32 dwRegOffset,VL_KEY keyCode)
+{
+ u32 result=0xFFFFFFFFUL;
+ u32 dwTemp=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->LanInitialized==true);
+ SMSC_ASSERT(Vl_CheckLock(&(privateData->MacPhyLock),keyCode));
+ SMSC_ASSERT(privateData->dwLanBase!=0);
+
+ // wait until not busy
+ if (Lan_GetRegDW(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY_)
+ {
+ SMSC_WARNING("Mac_GetRegDW() failed, MAC already busy at entry");
+ goto DONE;
+ }
+
+ // send the MAC Cmd w/ offset
+ Lan_SetRegDW(MAC_CSR_CMD,
+ ((dwRegOffset & 0x000000FFUL) |
+ MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_));
+ dwTemp=Lan_GetRegDW(BYTE_TEST);//to flush previous write
+ dwTemp=dwTemp;
+
+ // wait for the read to happen, w/ timeout
+ if (!MacNotBusy(privateData,keyCode))
+ {
+ SMSC_WARNING("Mac_GetRegDW() failed, waiting for MAC not busy after read");
+ goto DONE;
+ } else {
+ // finally, return the read data
+ result=Lan_GetRegDW(MAC_CSR_DATA);
+ }
+DONE:
+ return result;
+}
+
+void Mac_SetRegDW(PPRIVATE_DATA privateData,u32 dwRegOffset,u32 dwVal,VL_KEY keyCode)
+{
+ u32 dwTemp=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->LanInitialized==true);
+ SMSC_ASSERT(Vl_CheckLock(&(privateData->MacPhyLock),keyCode));
+ SMSC_ASSERT(privateData->dwLanBase!=0);
+
+ if (Lan_GetRegDW(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY_)
+ {
+ SMSC_WARNING("Mac_SetRegDW() failed, MAC already busy at entry");
+ goto DONE;
+ }
+
+ // send the data to write
+ Lan_SetRegDW(MAC_CSR_DATA,dwVal);
+
+ // do the actual write
+ Lan_SetRegDW(MAC_CSR_CMD,((dwRegOffset & 0x000000FFUL) | MAC_CSR_CMD_CSR_BUSY_));
+ dwTemp=Lan_GetRegDW(BYTE_TEST);//force flush of previous write
+ dwTemp=dwTemp;
+
+ // wait for the write to complete, w/ timeout
+ if (!MacNotBusy(privateData,keyCode))
+ {
+ SMSC_WARNING("Mac_SetRegDW() failed, waiting for MAC not busy after write");
+ }
+DONE:
+ return;
+}
+
+#define TX_FIFO_LOW_THRESHOLD (1600)
+//#define Tx_Max_Fragments (86) //every fragment needs 6 bytes overhead. 1514+2(alignment)+6*86=2032 < 2036
+
+void Tx_Initialize(
+ PPRIVATE_DATA privateData,
+ u32 dwTxDmaCh,
+ u32 dwDmaThreshold)
+{
+ u32 dwRegVal=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->dwLanBase!=0);
+
+ dwRegVal=Lan_GetRegDW(HW_CFG);
+ dwRegVal&=(HW_CFG_TX_FIF_SZ_|0x00000FFFUL);
+ dwRegVal|=HW_CFG_SF_;
+ Lan_SetRegDW(HW_CFG,dwRegVal);
+
+
+ if(privateData->UseTxCsum)
+
+ //Set TX COE
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ u32 dwCoeCr=Mac_GetRegDW(privateData,COE_CR,keyCode);
+ dwCoeCr|=(TX_COE_EN);
+ Mac_SetRegDW(privateData,COE_CR,dwCoeCr,keyCode);
+ //printk("COE_CR = 0x%08x\n", Mac_GetRegDW(privateData,COE_CR,keyCode));
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+
+ }
+
+
+
+ Lan_SetTDFL(privateData,0xFF);
+ Lan_EnableInterrupt(privateData,INT_EN_TDFA_EN_);
+
+ privateData->dwTxDmaThreshold=dwDmaThreshold;
+ privateData->dwTxDmaCh=dwTxDmaCh;
+ if(dwTxDmaCh>=TRANSFER_PIO) {
+ SMSC_TRACE("Tx will use PIO");
+ } else {
+ SMSC_TRACE("Tx will use DMA channel %d",dwTxDmaCh);
+ SMSC_ASSERT(Platform_IsValidDmaChannel(dwTxDmaCh));
+ if(!Platform_DmaInitialize(
+ &(privateData->PlatformData),
+ dwTxDmaCh))
+ {
+ SMSC_WARNING("Failed Platform_DmaInitialize, dwTxDmaCh=%u",dwTxDmaCh);
+ }
+ privateData->TxDmaXfer.dwLanReg=privateData->dwLanBase+TX_DATA_FIFO;
+ privateData->TxDmaXfer.pdwBuf=NULL;//this will be reset per dma request
+ privateData->TxDmaXfer.dwDmaCh=privateData->dwTxDmaCh;
+ privateData->TxDmaXfer.dwDwCnt=0;//this will be reset per dma request
+ privateData->TxDmaXfer.fMemWr=false;
+ }
+
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ u32 dwMacCr=Mac_GetRegDW(privateData,MAC_CR,keyCode);
+ dwMacCr|=(MAC_CR_TXEN_|MAC_CR_HBDIS_);
+ Mac_SetRegDW(privateData,MAC_CR,dwMacCr,keyCode);
+ Lan_SetRegDW(TX_CFG,TX_CFG_TX_ON_);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ }
+
+ privateData->TxSkb=NULL;
+ spin_lock_init(&(privateData->TxSkbLock));
+ privateData->dwTxQueueDisableMask=0;
+ spin_lock_init(&(privateData->TxQueueLock));
+ spin_lock_init(&(privateData->TxCounterLock));
+ privateData->TxInitialized=true;
+
+}
+
+bool Tx_HandleInterrupt(
+ PPRIVATE_DATA privateData,u32 dwIntSts)
+{
+ SMSC_ASSERT(privateData!=NULL);
+ if(dwIntSts&INT_STS_TDFA_)
+ {
+ Lan_SetTDFL(privateData,0xFF);
+ Lan_SetRegDW(INT_STS,INT_STS_TDFA_);
+ Tx_WakeQueue(privateData,0x02UL);
+ return true;
+ }
+ return false;
+}
+
+void Tx_StopQueue(
+ PPRIVATE_DATA privateData,u32 dwSource)
+{
+ unsigned long intFlags=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->dev!=NULL);
+ SMSC_ASSERT(privateData->TxInitialized);
+ spin_lock_irqsave(&(privateData->TxQueueLock),intFlags);
+ if(privateData->dwTxQueueDisableMask==0) {
+ netif_stop_queue(privateData->dev);
+ }
+ privateData->dwTxQueueDisableMask|=dwSource;
+ spin_unlock_irqrestore(&(privateData->TxQueueLock),intFlags);
+}
+
+void Tx_WakeQueue(
+ PPRIVATE_DATA privateData,u32 dwSource)
+{
+ unsigned long intFlags=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->dev!=NULL);
+ SMSC_ASSERT(privateData->TxInitialized);
+ spin_lock_irqsave(&(privateData->TxQueueLock),intFlags);
+ privateData->dwTxQueueDisableMask&=(~dwSource);
+ if(privateData->dwTxQueueDisableMask==0) {
+ netif_wake_queue(privateData->dev);
+ }
+ spin_unlock_irqrestore(&(privateData->TxQueueLock),intFlags);
+}
+
+static u32 Tx_GetTxStatusCount(
+ PPRIVATE_DATA privateData)
+{
+ u32 result=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->dwLanBase!=0);
+ result=Lan_GetRegDW(TX_FIFO_INF);
+ if(OLD_REGISTERS(privateData)) {
+ result&=TX_FIFO_INF_TSFREE_;
+ result>>=16;
+ if(result>0x80) {
+ SMSC_WARNING("TX_FIFO_INF_TSFREE_>0x80");
+ result=0x80;
+ }
+ result=0x80-result;
+ } else {
+ result&=TX_FIFO_INF_TSUSED_;
+ result>>=16;
+ }
+ return result;
+}
+
+
+
+void Tx_SendSkb(
+ PPRIVATE_DATA privateData,
+ struct sk_buff *skb)
+{
+ u32 dwFreeSpace=0;
+ unsigned int i=0, TxFrag=0, skbFragCnt = skb_shinfo(skb)->nr_frags + 1;
+
+ //if (skbFragCnt>1)
+ // printk("skbFrsgCnt = (%d)\n", skbFragCnt);
+
+ // if (privateData->UseTxCsum) {
+ int Chsum_start_offset=0;
+ u32 dwTxCsumPreamble=0;
+ // }
+
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->dwLanBase!=0);
+
+ if(privateData->UseTxCsum){
+
+ if(skb->ip_summed == CHECKSUM_PARTIAL)
+ {
+ //printk("ip summed!\n");
+ TxFrag = skbFragCnt + 1;
+ }
+ else
+ {
+ TxFrag = skbFragCnt;
+ }
+ }
+ else {
+ TxFrag = skbFragCnt;
+ }
+ TxFrag = skbFragCnt;
+
+
+ if (privateData->UseTxCsum) {
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ {
+ CalculateTxChecksumOffset(
+ skb,
+ &Chsum_start_offset);
+
+
+ dwTxCsumPreamble=(((WORD) (Chsum_start_offset + skb->csum)) << 16) | ((WORD) Chsum_start_offset);
+
+
+ }
+ }
+
+ //printk("Tx skb->len = 0x%08x\n", (u32) skb->len);
+
+
+
+ if(privateData->dwTxDmaCh>=TRANSFER_PIO)
+ {
+ //Use PIO only
+
+ //printk("Tx using pio only\n");
+
+ u32 dwTxCmdA=0;
+ u32 dwTxCmdB=0;
+
+
+ dwFreeSpace=Lan_GetRegDW(TX_FIFO_INF);
+ dwFreeSpace&=TX_FIFO_INF_TDFREE_;
+ if(dwFreeSpace<TX_FIFO_LOW_THRESHOLD) {
+ SMSC_WARNING("Tx Data Fifo Low, space available = %d",dwFreeSpace);
+ }
+
+
+ if(privateData->UseTxCsum) {
+ if(skb->ip_summed == CHECKSUM_PARTIAL)
+ {
+
+
+ dwTxCmdA=TX_CMD_A_INT_FIRST_SEG_ |((u32)sizeof(u32)) ;
+
+ dwTxCmdB=
+ (((u32)(skb->len+4))<<16) | TX_CMD_B_CSUM_ENABLE |
+ (((u32)(skb->len+4)&0x7FFUL));
+
+
+
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCsumPreamble);
+
+
+ }
+ }
+
+ if (skbFragCnt == 1){
+
+ if(skb->ip_summed == CHECKSUM_PARTIAL){
+
+ dwTxCmdA =((((u32)(skb->data))&0x03UL)<<16) |
+ TX_CMD_A_INT_LAST_SEG_|((u32)(skb->len));
+ dwTxCmdB=
+ (((u32)(skb->len+4))<<16) |
+ (((u32)(skb->len+4)&0x7FFUL));
+
+
+
+ }
+ else{
+ dwTxCmdA =
+ ((((u32)(skb->data))&0x03UL)<<16) | TX_CMD_A_INT_FIRST_SEG_ |
+ TX_CMD_A_INT_LAST_SEG_|((u32)(skb->len));
+
+ dwTxCmdB=
+ (((u32)(skb->len))<<16) |
+ (((u32)(skb->len)&0x7FFUL));
+
+ }
+
+ //printk("dwTxCmdA = 0x%08x\n", (u32) dwTxCmdA);
+ //printk("dwTxCmdB = 0x%08x\n", (u32) dwTxCmdB);
+
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+
+
+ // rkdump(skb->data, skb->len);
+ Platform_WriteFifo(
+ privateData->dwLanBase,
+ (u32 *)(((u32)(skb->data))&0xFFFFFFFCUL),
+ (((u32)(skb->len))+3+
+ (((u32)(skb->data))&0x03UL))>>2);
+
+ //printk("Tx skb->len2 = 0x%08x\n", (u32) skb->len);
+ dwFreeSpace-=(skb->len+32);
+ dev_kfree_skb(skb);
+
+ }
+
+ else {
+
+ if(skb->ip_summed == CHECKSUM_PARTIAL){
+ dwTxCmdA =
+ ((((u32)(skb->data))&0x03UL)<<16) | //u32 alignment adjustment
+ ((u32)((skb->len)-(skb->data_len)));
+ dwTxCmdB=
+ (((u32)(skb->len+4))<<16) |
+ (((u32)(skb->len+4)&0x7FFUL));
+
+ }
+ else{
+ dwTxCmdA =
+ ((((u32)(skb->data))&0x03UL)<<16) |TX_CMD_A_INT_FIRST_SEG_ |
+ ((u32)((skb->len)-(skb->data_len)));
+ dwTxCmdB=
+ (((u32)(skb->len))<<16) |
+ (((u32)(skb->len)&0x7FFUL));
+
+ }
+ //printk("first frag. \n");
+ //rkdump(skb->data, ((skb->len)-(skb->data_len)));
+
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+
+
+ Platform_WriteFifo(
+ privateData->dwLanBase,
+ (u32 *)(((u32)(skb->data))&0xFFFFFFFCUL),
+ (((u32)((skb->len)-(skb->data_len)))+3+
+ (((u32)(skb->data))&0x03UL))>>2);
+ // dwFreeSpace-=((skb->len-skb->data_len)+32);
+
+
+ for(i=1;i<skbFragCnt;i++)
+ {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
+ void *frag_addr = page_address(frag->page) + frag->page_offset;
+
+
+ dwTxCmdA=
+ ((((u32)(frag_addr))&0x03UL)<<16) | //u32 alignment adjustment
+ ((u32)(frag->size));
+
+
+ if (i==(skbFragCnt-1)){
+ dwTxCmdA |= TX_CMD_A_INT_LAST_SEG_ ;
+ }
+
+ if(skb->ip_summed == CHECKSUM_PARTIAL) {
+ dwTxCmdB=
+ (((u32)(skb->len+4))<<16) |
+ (((u32)(skb->len+4)&0x7FFUL));
+ }
+ else {
+ dwTxCmdB=
+ (((u32)(skb->len))<<16) |
+ (((u32)(skb->len)&0x7FFUL));
+ }
+
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+ //printk("i= %d\n", i);
+ //rkdump(frag_addr, frag->size);
+
+ Platform_WriteFifo(
+ privateData->dwLanBase,
+ (u32 *)(((u32)(frag_addr))&0xFFFFFFFCUL),
+ (((u32)(frag->size))+3+
+ (((u32)(frag_addr))&0x03UL))>>2);
+ // dwFreeSpace-=(frag->size+8);
+
+ }
+
+ dwFreeSpace-=skb->len+12*TxFrag+16;
+ dev_kfree_skb(skb);
+ }
+
+ }
+
+
+ else
+ {
+ //Use DMA and PIO
+
+ //printk("Tx using dma!!\n");
+
+ u32 dwDmaCh=privateData->dwTxDmaCh;
+ PPLATFORM_DATA platformData=&(privateData->PlatformData);
+ SMSC_ASSERT(TX_FIFO_LOW_THRESHOLD>(skb->len+32));
+
+ if(((skb->len)>=(privateData->dwTxDmaThreshold)) && (skbFragCnt == 1))
+ {
+
+ //printk("Tx using dma!!\n");
+ // if(privateData->UseTxCsum) {
+ u32 dwTxCmdA1=0;
+ u32 dwTxCmdB1=0;
+ // }
+ u32 dwTxCmdA=0;
+ u32 dwTxCmdB=0;
+
+
+ if(privateData->UseTxCsum) {
+ if(skb->ip_summed == CHECKSUM_PARTIAL)
+
+ {
+
+
+ dwTxCmdA1=
+ TX_CMD_A_INT_FIRST_SEG_ |
+ ((u32)sizeof(u32));//buffer length
+
+ dwTxCmdB1=
+ (((u32)(skb->len+4))<<16) |TX_CMD_B_CSUM_ENABLE |
+ (((u32)(skb->len+4)&0x7FFUL));
+
+
+ }
+ }
+
+ if (skbFragCnt == 1){
+
+ dwTxCmdA =
+#if (PLATFORM_CACHE_LINE_BYTES == 16)
+ (0x01UL<<24)|//16 byte end alignment
+#endif
+#if (PLATFORM_CACHE_LINE_BYTES == 32)
+ (0x02UL<<24)|//32 byte end alignment
+#endif
+ ((((u32)(skb->data))&(PLATFORM_CACHE_LINE_BYTES-1))<<16) |//16 Byte start alignment
+ TX_CMD_A_INT_LAST_SEG_ |
+ ((u32)(skb->len));//buffer length
+
+ if(skb->ip_summed != CHECKSUM_PARTIAL)
+ dwTxCmdA |= TX_CMD_A_INT_FIRST_SEG_;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL){
+ dwTxCmdB=
+ (((u32)(skb->len+4))<<16) |
+ (((u32)(skb->len+4)&0x7FFUL));
+ }
+ else{
+ dwTxCmdB=
+ (((u32)(skb->len))<<16) |
+ ((u32)(skb->len));
+ }
+
+
+
+ privateData->TxDmaXfer.pdwBuf=
+ (u32 *)(((u32)(skb->data))&
+ (~(PLATFORM_CACHE_LINE_BYTES-1)));
+ privateData->TxDmaXfer.dwDwCnt=
+ ((((u32)(skb->len))+
+ (PLATFORM_CACHE_LINE_BYTES-1)+
+ (((u32)(skb->data))&
+ (PLATFORM_CACHE_LINE_BYTES-1)))&
+ (~(PLATFORM_CACHE_LINE_BYTES-1)))>>2;
+ Platform_CachePurge(
+ platformData,
+ privateData->TxDmaXfer.pdwBuf,
+ (privateData->TxDmaXfer.dwDwCnt)<<2);
+
+ spin_lock(&(privateData->TxSkbLock));
+ {
+ if(privateData->TxSkb)
+ Platform_DmaComplete(platformData,dwDmaCh);
+
+ dwFreeSpace=Lan_GetRegDW(TX_FIFO_INF);
+ dwFreeSpace&=TX_FIFO_INF_TDFREE_;
+ if(dwFreeSpace<TX_FIFO_LOW_THRESHOLD) {
+ SMSC_WARNING("Tx DATA FIFO LOW, space available = %d",dwFreeSpace);
+ }
+
+ if (privateData->UseTxCsum) {
+ if(skb->ip_summed == CHECKSUM_PARTIAL)
+
+ {
+
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA1);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB1);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCsumPreamble);
+ }
+ }
+
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+ if(!Platform_DmaStartXfer(platformData,&(privateData->TxDmaXfer)))
+ {
+ SMSC_WARNING("Failed Platform_DmaStartXfer");
+ }
+
+ dwFreeSpace-=(skb->len+32);
+ if(privateData->TxSkb)
+ dev_kfree_skb(privateData->TxSkb);
+
+ privateData->TxSkb=skb;
+ }
+ spin_unlock(&(privateData->TxSkbLock));
+
+ }
+
+
+
+ }
+
+ else
+ {
+
+
+ //Use PIO
+
+ //printk("skb->len (%d)\n", skb->len);
+ //printk("Tx using pio\n");
+
+ u32 dwTxCmdA=0;
+ u32 dwTxCmdB=0;
+
+
+ spin_lock(&(privateData->TxSkbLock));
+ if(privateData->TxSkb) {
+ Platform_DmaComplete(platformData,dwDmaCh);
+ dev_kfree_skb(privateData->TxSkb);
+ privateData->TxSkb=NULL;
+ }
+ spin_unlock(&(privateData->TxSkbLock));
+
+
+ dwFreeSpace=Lan_GetRegDW(TX_FIFO_INF);
+ dwFreeSpace&=TX_FIFO_INF_TDFREE_;
+ if(dwFreeSpace<TX_FIFO_LOW_THRESHOLD) {
+ SMSC_WARNING("Tx Data Fifo Low, space available = %d",dwFreeSpace);
+ }
+
+ if(privateData->UseTxCsum) {
+
+ if(skb->ip_summed == CHECKSUM_PARTIAL)
+ {
+
+ dwTxCmdA=TX_CMD_A_INT_FIRST_SEG_ |((u32)sizeof(u32)) ;
+
+
+ dwTxCmdB=
+ (((u32)(skb->len+4))<<16) |TX_CMD_B_CSUM_ENABLE |
+ (((u32)(skb->len+4)&0x7FFUL));
+
+
+ //printk("dwTxCmdA = 0x%08x\n", (u32) dwTxCmdA);
+ //printk("dwTxCmdB = 0x%08x\n", (u32) dwTxCmdB);
+ //printk("dwTxCsumPreamble = 0x%08x\n", (u32) dwTxCsumPreamble);
+
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCsumPreamble);
+
+ }
+
+ }
+
+ if (skbFragCnt == 1){
+
+ if(skb->ip_summed == CHECKSUM_PARTIAL){
+ dwTxCmdA =
+ ((((u32)(skb->data))&0x03UL)<<16) | //u32 alignment adjustment
+ TX_CMD_A_INT_LAST_SEG_|((u32)(skb->len));
+ dwTxCmdB=
+ (((u32)(skb->len+4))<<16) |
+ (((u32)(skb->len+4)&0x7FFUL));
+
+ }
+ else{
+ dwTxCmdA =
+ ((((u32)(skb->data))&0x03UL)<<16) | TX_CMD_A_INT_FIRST_SEG_ |
+ TX_CMD_A_INT_LAST_SEG_|((u32)(skb->len));
+ dwTxCmdB=
+ (((u32)(skb->len))<<16) |
+ ((u32)(skb->len));
+
+ }
+
+
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+
+ Platform_WriteFifo(
+ privateData->dwLanBase,
+ (u32 *)(((u32)(skb->data))&0xFFFFFFFCUL),
+ (((u32)(skb->len))+3+
+ (((u32)(skb->data))&0x03UL))>>2);
+ dwFreeSpace-=(skb->len+32);
+ dev_kfree_skb(skb);
+ }
+
+ else {
+
+ if(skb->ip_summed == CHECKSUM_PARTIAL){
+ dwTxCmdA =
+ ((((u32)(skb->data))&0x03UL)<<16) | //u32 alignment adjustment
+ ((u32)((skb->len)-(skb->data_len)));
+
+ dwTxCmdB=
+ (((u32)(skb->len+4))<<16) |
+ (((u32)(skb->len+4)&0x7FFUL));
+ }
+ else{
+ dwTxCmdA =
+ ((((u32)(skb->data))&0x03UL)<<16) |TX_CMD_A_INT_FIRST_SEG_ | //u32 alignment adjustment
+ ((u32)((skb->len)-(skb->data_len)));
+
+ dwTxCmdB=
+ (((u32)(skb->len))<<16) |
+ (((u32)(skb->len)&0x7FFUL));
+
+ }
+
+ //printk("first frag. \n");
+ //rkdump(skb->data, ((skb->len)-(skb->data_len)));
+
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+
+ Platform_WriteFifo(
+ privateData->dwLanBase,
+ (u32 *)(((u32)(skb->data))&0xFFFFFFFCUL),
+ (((u32)((skb->len)-(skb->data_len)))+3+
+ (((u32)(skb->data))&0x03UL))>>2);
+ // dwFreeSpace-=((skb->len-skb->data_len)+32);
+
+
+ for(i=1;i<skbFragCnt;i++)
+ {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
+ void *frag_addr = page_address(frag->page) + frag->page_offset;
+
+
+ dwTxCmdA=
+ ((((u32)(frag_addr))&0x03UL)<<16) | //u32 alignment adjustment
+ ((u32)(frag->size));
+
+
+ if (i==(skbFragCnt-1)){
+ dwTxCmdA |= TX_CMD_A_INT_LAST_SEG_ ;
+ }
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL){
+ dwTxCmdB=
+ (((u32)(skb->len+4))<<16) |
+ (((u32)(skb->len+4)&0x7FFUL));
+ }
+ else{
+ dwTxCmdB=
+ (((u32)(skb->len))<<16) |
+ ((u32)(skb->len));
+ }
+
+ //printk("i= %d\n", i);
+ //rkdump(frag_addr, frag->size);
+
+
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
+ Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
+
+ Platform_WriteFifo(
+ privateData->dwLanBase,
+ (u32 *)(((u32)(frag_addr))&0xFFFFFFFCUL),
+ (((u32)(frag->size))+3+
+ (((u32)(frag_addr))&0x03UL))>>2);
+ // dwFreeSpace-=(frag->size+8);
+
+ }
+
+ dwFreeSpace-=skb->len+12*TxFrag+16;
+ dev_kfree_skb(skb);
+
+ }
+
+ }
+
+ }
+
+ //printk("finish.\n");
+
+
+ if(Tx_GetTxStatusCount(privateData)>=30)
+ {
+ Tx_UpdateTxCounters(privateData);
+ }
+
+ if(dwFreeSpace<TX_FIFO_LOW_THRESHOLD) {
+ Tx_StopQueue(privateData,0x02UL);
+ Lan_SetTDFL(privateData,0x32);
+ }
+
+
+}
+
+
+
+
+
+
+
+
+
+static u32 Tx_CompleteTx(
+ PPRIVATE_DATA privateData)
+{
+ u32 result=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->dwLanBase!=0);
+ SMSC_ASSERT(privateData->TxInitialized==true);
+ result=Lan_GetRegDW(TX_FIFO_INF);
+ if(OLD_REGISTERS(privateData)) {
+ result&=TX_FIFO_INF_TSFREE_;
+ if(result!=0x00800000UL) {
+ result=Lan_GetRegDW(TX_STATUS_FIFO);
+ } else {
+ result=0;
+ }
+ } else {
+ result&=TX_FIFO_INF_TSUSED_;
+ if(result!=0x00000000UL) {
+ result=Lan_GetRegDW(TX_STATUS_FIFO);
+ } else {
+ result=0;
+ }
+ }
+ return result;
+}
+
+void Tx_UpdateTxCounters(
+ PPRIVATE_DATA privateData)
+{
+
+ u32 dwTxStatus=0;
+ SMSC_ASSERT(privateData!=NULL);
+ spin_lock(&(privateData->TxCounterLock));
+ while((dwTxStatus=Tx_CompleteTx(privateData))!=0)
+ {
+ if(dwTxStatus&0x80000000UL) {
+ SMSC_WARNING("Packet tag reserved bit is high");
+ privateData->stats.tx_errors++;
+ } else if(dwTxStatus&0x00007080UL) {
+ SMSC_WARNING("Tx Status reserved bits are high");
+ privateData->stats.tx_errors++;
+ } else {
+ if(dwTxStatus&0x00008000UL) {
+ privateData->stats.tx_errors++;
+ } else {
+ privateData->stats.tx_packets++;
+ privateData->stats.tx_bytes+=(dwTxStatus>>16);
+ }
+ if(dwTxStatus&0x00000100UL) {
+ privateData->stats.collisions+=16;
+ privateData->stats.tx_aborted_errors+=1;
+ } else {
+ privateData->stats.collisions+=
+ ((dwTxStatus>>3)&0xFUL);
+ }
+ if(dwTxStatus&0x00000800UL) {
+ privateData->stats.tx_carrier_errors+=1;
+ }
+ if(dwTxStatus&0x00000200UL) {
+ privateData->stats.collisions++;
+ privateData->stats.tx_aborted_errors++;
+ }
+ }
+ }
+ spin_unlock(&(privateData->TxCounterLock));
+}
+
+void Tx_CompleteDma(
+ PPRIVATE_DATA privateData)
+{
+ SMSC_ASSERT(privateData!=NULL);
+
+ spin_lock(&(privateData->TxSkbLock));
+ if(privateData->TxSkb) {
+ Platform_DmaComplete(
+ &(privateData->PlatformData),
+ privateData->dwTxDmaCh);
+ dev_kfree_skb(privateData->TxSkb);
+ privateData->TxSkb=NULL;
+ }
+ spin_unlock(&(privateData->TxSkbLock));
+}
+
+
+void CalculateTxChecksumOffset(
+ struct sk_buff *skb,
+ int *csum_start_offset
+ )
+{
+ unsigned int skbFragCnt;
+
+ skbFragCnt = skb_shinfo(skb)->nr_frags + 1;
+ *csum_start_offset = skb->csum_offset;
+}
+
+
+
+
+void rkdump(unsigned char *p, unsigned short len)
+{
+ int i;
+
+ for(i=0; i<len; i++)
+ {
+ if (i%16 == 0)
+ {
+ printk("\n0x%08x: ", (u32) (p+i));
+ }
+
+ printk("%02x ", *(p+i));
+ }
+
+ printk("\n");
+}
+
+
+
+void Rx_Initialize(
+ PPRIVATE_DATA privateData,
+ u32 dwRxDmaCh,
+ u32 dwDmaThreshold)
+{
+ SMSC_ASSERT(privateData!=NULL);
+
+ privateData->dwRxDmaCh=dwRxDmaCh;
+ if(dwRxDmaCh>=TRANSFER_PIO) {
+ SMSC_TRACE("Rx will use PIO");
+ Platform_GetFlowControlParameters(
+ &(privateData->PlatformData),
+ &(privateData->RxFlowParameters),
+ false);
+ } else {
+ SMSC_TRACE("Rx will use DMA Channel %d",dwRxDmaCh);
+ SMSC_ASSERT(Platform_IsValidDmaChannel(dwRxDmaCh));
+ if(!Platform_DmaInitialize(
+ &(privateData->PlatformData),
+ dwRxDmaCh))
+ {
+ SMSC_WARNING("Failed Platform_DmaInitialize, dwRxDmaCh=%u",dwRxDmaCh);
+ }
+ Platform_GetFlowControlParameters(
+ &(privateData->PlatformData),
+ &(privateData->RxFlowParameters),
+ true);
+ }
+ if(max_throughput!=0xFFFFFFFFUL) {
+ privateData->RxFlowParameters.MaxThroughput=max_throughput;
+ }
+ if(max_packet_count!=0xFFFFFFFFUL) {
+ privateData->RxFlowParameters.MaxPacketCount=max_packet_count;
+ }
+ if(packet_cost!=0xFFFFFFFFUL) {
+ privateData->RxFlowParameters.PacketCost=packet_cost;
+ }
+ if(burst_period!=0xFFFFFFFFUL) {
+ privateData->RxFlowParameters.BurstPeriod=burst_period;
+ }
+ if(privateData->RxFlowParameters.BurstPeriod==0) {
+ SMSC_WARNING("burst_period of 0 is not allowed");
+ SMSC_WARNING(" resetting burst_period to 100");
+ privateData->RxFlowParameters.BurstPeriod=100;
+ }
+ if(max_work_load!=0xFFFFFFFFUL) {
+ privateData->RxFlowMaxWorkLoad=max_work_load;
+ } else {
+ privateData->RxFlowMaxWorkLoad=
+ privateData->RxFlowParameters.MaxThroughput+
+ (privateData->RxFlowParameters.MaxPacketCount*
+ privateData->RxFlowParameters.PacketCost);
+ }
+ privateData->RxFlowBurstMaxWorkLoad=
+ (privateData->RxFlowMaxWorkLoad*
+ privateData->RxFlowParameters.BurstPeriod)/1000;
+ if(int_deas!=0xFFFFFFFFUL) {
+ Lan_SetIntDeas(privateData,int_deas);
+ } else {
+ Lan_SetIntDeas(privateData,privateData->RxFlowParameters.IntDeas);
+ }
+
+
+ //Set RX COE
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ Mac_SetRegDW(privateData,VLAN1,ETH_P_8021Q,keyCode);
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ // privateData->RxVLanPkt=true;
+
+ }
+
+
+ if (privateData->UseRxCsum) {
+
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ u32 dwCoeCr=Mac_GetRegDW(privateData,COE_CR,keyCode);
+ dwCoeCr|=(RX_COE_EN | RX_COE_MODE);
+ Mac_SetRegDW(privateData,COE_CR,dwCoeCr,keyCode);
+ //printk("COE_CR2 = 0x%08x\n", Mac_GetRegDW(privateData,COE_CR,keyCode));
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+
+ }
+
+
+ }
+
+
+
+ //initially the receiver is off
+ // a following link up detection will turn the receiver on
+ privateData->dwRxOffCount=1;
+ Lan_SetRegDW(RX_CFG,RX_CFG_RXDOFF_2_);
+ Rx_ReceiverOn(privateData, 0);
+
+ privateData->dwRxDmaThreshold=dwDmaThreshold;
+ Lan_SetRDFL(privateData,0x01);
+ Lan_SetRSFL(privateData,0x00);
+ privateData->RxInterrupts=INT_EN_RSFL_EN_;
+ privateData->RxInterrupts|=INT_EN_RXE_EN_;
+ if(privateData->dwGeneration==0) {
+ privateData->RxInterrupts|=INT_EN_RDFL_EN_;
+ } else {
+ privateData->RxInterrupts|=INT_EN_RDFO_EN_;
+ }
+ privateData->RxInterrupts|=INT_EN_RXDFH_INT_EN_;
+ Lan_EnableInterrupt(privateData,privateData->RxInterrupts);
+
+}
+
+static void Rx_HandleOverrun(PPRIVATE_DATA privateData)
+{
+ if(privateData->dwGeneration==0) {
+ if(privateData->RxOverrun==false) {
+ Rx_ReceiverOff(privateData);
+ privateData->RxUnloadProgress=
+ (((((privateData->LastRxStatus1)&0x3FFF0000UL)>>16)+2+3)&0xFFFFFFFCUL);
+ if(privateData->dwRxDmaCh<TRANSFER_REQUEST_DMA) {
+ privateData->RxUnloadProgress+=
+ (((((privateData->LastRxStatus2)&0x3FFF0000UL)>>16)+2+3)&0xFFFFFFFCUL);
+ }
+ privateData->RxUnloadPacketProgress=0;
+ privateData->RxOverrun=true;
+ privateData->RxOverrunCount++;
+ }
+ } else {
+ privateData->RxOverrunCount++;
+ }
+}
+
+static void Rx_HandOffSkb(
+ PPRIVATE_DATA privateData,
+ struct sk_buff *skb)
+{
+ int result=0;
+
+ skb->dev=privateData->dev;
+ skb->protocol= eth_type_trans(skb,privateData->dev);
+
+ // #ifdef UseRxCsum
+ // WORD wHwCsum = 0;
+ // #endif
+
+ //printk(" Handoff skb->len = 0x%08x\n",(u32) skb->len);
+ if (privateData->UseRxCsum) {
+
+ WORD wHwCsum = *(WORD *)(skb->tail +4);
+ skb->csum = wHwCsum;
+ //printk(" HW csum = 0x%04x\n", skb->csum);
+
+ }
+
+
+ if (privateData->UseRxCsum)
+
+ skb->ip_summed = CHECKSUM_PARTIAL;
+
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+#ifdef LINUX_2_6_OR_NEWER
+ if(rx_mode==PROCESSING_MODE_NAPI) {
+ result=netif_receive_skb(skb);
+ privateData->RxWorkLimit--;
+ privateData->RxPacketsReceived++;
+ if(privateData->RxWorkLimit<=0) {
+ privateData->RxCongested=true;
+ }
+
+ } else {
+ result=netif_rx(skb);//hand off the Received packet to higher layer
+ }
+#else
+ result=netif_rx(skb);
+#endif
+
+ // result=netif_rx(skb);
+
+ switch(result)
+ {
+ case NET_RX_SUCCESS:
+ break;
+ case NET_RX_CN_LOW:
+ case NET_RX_CN_MOD:
+ case NET_RX_CN_HIGH:
+ case NET_RX_DROP:
+ privateData->RxCongested=true;
+ privateData->RxCongestedCount++;
+ break;
+ default:
+ privateData->RxCongested=true;
+ privateData->RxCongestedCount++;
+ SMSC_WARNING("Unknown return value from netif_rx, result=%d",result);
+ break;
+ }
+}
+
+void Rx_CompleteMulticastUpdate (PPRIVATE_DATA privateData)
+{
+ u32 local_MACCR;
+ VL_KEY keyCode=0;
+ unsigned long dwIntFlags=0;
+
+ keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ if (privateData->MulticastUpdatePending) {
+ SET_GPIO(GP_COMPLETE_MULTICAST_UPDATE);
+ Mac_SetRegDW(privateData,HASHH,privateData->HashHi,keyCode);
+ Mac_SetRegDW(privateData,HASHL,privateData->HashLo,keyCode);
+ local_MACCR = Mac_GetRegDW(privateData,MAC_CR,keyCode);
+ local_MACCR |= privateData->set_bits_mask;
+ local_MACCR &= ~(privateData->clear_bits_mask);
+ Mac_SetRegDW(privateData,MAC_CR,local_MACCR,keyCode);
+ Rx_ReceiverOn(privateData, keyCode);
+ privateData->MulticastUpdatePending = false;
+ CLEAR_GPIO(GP_COMPLETE_MULTICAST_UPDATE);
+ }
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+}
+
+void Rx_BeginMulticastUpdate (PPRIVATE_DATA privateData)
+{
+ u32 startTime, currentTime;
+ u32 timeout;
+ unsigned long flags;
+
+ SET_GPIO(GP_BEGIN_MULTICAST_UPDATE);
+
+ //NOTE: we can't rely on privateData->dwLinkSpeed because
+ // it updates only once per second and may be out dated.
+
+ local_irq_save(flags);
+ Rx_ReceiverOff(privateData);
+ if(privateData->dwGeneration>0) {
+ //since this is concord or later there is no
+ // overrun processing that might turn off the receiver.
+ // there for we can rely on RxStop Int.
+
+ //if the speed is 100Mb then lets poll rx stop to get the
+ // quickest response.
+ timeout = 200UL;
+ while ((timeout)&&(!(Lan_GetRegDW(INT_STS)&(INT_STS_RXSTOP_INT_)))) {
+ // wait 1 uSec
+ startTime=Lan_GetRegDW(FREE_RUN);
+ while (1) {
+ currentTime=Lan_GetRegDW(FREE_RUN);
+ if (currentTime-startTime >= 25UL)
+ break;
+ }
+ timeout--;
+ }
+ if(timeout==0) {
+ //this is probably a 10Mb link, therefore prepare
+ // interrupt for update later.
+ Lan_EnableInterrupt(privateData,INT_EN_RXSTOP_INT_EN_);
+
+ // if this is a 10Mbps half duplex connection
+ // then Rx stop is only 99.6% reliable
+ // Therefor we must schedule Gpt callback as
+ // back up
+
+ // using 18*(100uS) because we already waited 200uS
+ Gpt_ScheduleCallBack(privateData,GptCB_RxCompleteMulticast, 18UL);
+ } else {
+ //Rx is stopped
+ Lan_SetRegDW(INT_STS,INT_STS_RXSTOP_INT_);//clear interrupt signal
+ Rx_CompleteMulticastUpdate(privateData);
+ }
+ } else {
+ // for generation 0 we can't rely on Rx stop because
+ // the receiver may have already been stopped due to
+ // overflow processing
+
+ // for the same reason we can't just wait 200uS and
+ // check stopped status there for we must rely on GP timer
+ // and we must assume a worse case of 10Mb speed
+
+ Gpt_ScheduleCallBack(privateData,GptCB_RxCompleteMulticast, 20UL);
+ }
+ local_irq_restore (flags);
+ CLEAR_GPIO(GP_BEGIN_MULTICAST_UPDATE);
+}
+
+static u32 Rx_PopRxStatus(
+ PPRIVATE_DATA privateData)
+{
+ u32 result=Lan_GetRegDW(RX_FIFO_INF);
+ if((privateData->RxCongested==false)||
+ ((privateData->RxCongested==true)&&((result&0x00FF0000UL)==0UL)))
+ {
+ if(result&0x00FF0000UL) {
+ u32 dwIntSts=Lan_GetRegDW(INT_STS);
+ if(privateData->dwGeneration==0) {
+ if(dwIntSts&INT_STS_RDFL_) {
+ Lan_SetRegDW(INT_STS,INT_STS_RDFL_);
+ Rx_HandleOverrun(privateData);
+ }
+ } else {
+ if(dwIntSts&INT_STS_RDFO_) {
+ Lan_SetRegDW(INT_STS,INT_STS_RDFO_);
+ Rx_HandleOverrun(privateData);
+ }
+ }
+ if((privateData->RxFlowControlActive==false)||
+ ((privateData->RxFlowControlActive==true)&&
+ (privateData->RxFlowBurstActive==true)))
+ {
+ //Rx status is available, read it
+ result=Lan_GetRegDW(RX_STATUS_FIFO);
+ privateData->RxStatusDWReadCount++;
+ privateData->LastRxStatus3=
+ privateData->LastRxStatus2;
+ privateData->LastRxStatus2=
+ privateData->LastRxStatus1;
+ privateData->LastRxStatus1=result;
+
+ if(privateData->RxOverrun) {
+ u32 dwPacketLength=((result&0x3FFF0000UL)>>16);
+ u32 dwByteCount=((dwPacketLength+2+3)&0xFFFFFFFCUL);
+ if((privateData->RxUnloadProgress+dwByteCount)>=
+ ((privateData->RxMaxDataFifoSize)-16))
+ {
+ //This is the packet that crosses the corruption point
+ // so just ignore it and complete the overrun processing.
+ result=0;
+ goto FINISH_OVERRUN_PROCESSING;
+ }
+ privateData->RxUnloadProgress+=dwByteCount;
+ privateData->RxUnloadPacketProgress++;
+ }
+
+ privateData->RxFlowCurrentThroughput+=
+ ((((result&0x3FFF0000UL)>>16)-4UL));
+ privateData->RxFlowCurrentPacketCount++;
+ privateData->RxFlowCurrentWorkLoad+=
+ ((((result&0x3FFF0000UL)>>16)-4UL)+privateData->RxFlowParameters.PacketCost);
+ if(privateData->RxFlowControlActive) {
+ privateData->RxFlowBurstWorkLoad+=
+ ((((result&0x3FFF0000UL)>>16)-4UL)+privateData->RxFlowParameters.PacketCost);
+ if(privateData->RxFlowBurstWorkLoad>=
+ privateData->RxFlowBurstMaxWorkLoad)
+ {
+ privateData->RxFlowBurstActive=false;
+ Lan_DisableInterrupt(privateData,privateData->RxInterrupts);
+ }
+ }
+ } else {
+ result=0;
+ }
+ }
+ else
+ {
+ if(privateData->RxOverrun) {
+ u32 timeOut;
+ u32 temp;
+FINISH_OVERRUN_PROCESSING:
+ temp=0;
+ {
+ timeOut=2000;
+ while((timeOut>0)&&(!(Lan_GetRegDW(INT_STS)&(INT_STS_RXSTOP_INT_)))) {
+ udelay(1);
+ timeOut--;
+ }
+ if(timeOut==0) {
+ // privateData->RxStopTimeOutCount++;
+ // PULSE_GPIO(GP_TX,1);
+ SMSC_WARNING("Timed out waiting for Rx to Stop\n");
+ }
+ Lan_SetRegDW(INT_STS,INT_STS_RXSTOP_INT_);
+ }
+
+ if(privateData->dwRxDmaCh<TRANSFER_REQUEST_DMA) {
+ //make sure DMA has stopped before doing RX Dump
+ if(privateData->RxSkb) {
+ Platform_DmaComplete(
+ &(privateData->PlatformData),
+ privateData->dwRxDmaCh);
+
+ Rx_HandOffSkb(privateData,privateData->RxSkb);
+ privateData->RxSkb=NULL;
+ }
+ }
+
+ temp=Lan_GetRegDW(RX_CFG);
+ Lan_SetRegDW(RX_CFG,(temp&0x3FFFFFFFUL));
+ timeOut=10000000;
+ Lan_SetBitsDW(RX_CFG,RX_CFG_RX_DUMP_);
+ while((timeOut>0)&&(Lan_GetRegDW(RX_CFG)&(RX_CFG_RX_DUMP_))) {
+ udelay(1);
+ timeOut--;
+ }
+ if(timeOut==0) {
+ SMSC_WARNING("Timed out waiting for Rx Dump to complete\n");
+ }
+ Lan_SetRegDW(RX_CFG,temp);
+
+ privateData->RxDumpCount++;
+ Lan_SetRegDW(INT_STS,INT_STS_RDFL_);
+ Rx_ReceiverOn(privateData, 0);
+ privateData->RxOverrun=false;
+ }
+ result=0;
+ privateData->LastReasonForReleasingCPU=1;//Status FIFO Empty
+ }
+ } else {
+ //disable and reenable the INT_EN
+ // This will allow the deassertion interval to begin
+ u32 temp=Lan_GetRegDW(INT_EN);
+ Lan_SetRegDW(INT_EN,0);
+ Lan_SetRegDW(INT_EN,temp);
+ result=0;
+ privateData->LastReasonForReleasingCPU=2;//High Congestion
+ }
+ return result;
+}
+
+void Rx_CountErrors(PPRIVATE_DATA privateData,u32 dwRxStatus)
+{
+ bool crcError=false;
+ if(dwRxStatus&0x00008000UL) {
+ privateData->stats.rx_errors++;
+ if(dwRxStatus&0x00000002UL) {
+ privateData->stats.rx_crc_errors++;
+ crcError=true;
+ }
+ }
+ if(!crcError) {
+ if((dwRxStatus&0x00001020UL)==0x00001020UL) {
+ //Frame type indicates length, and length error is set
+ privateData->stats.rx_length_errors++;
+ }
+ if(dwRxStatus&RX_STS_MCAST_) {
+ privateData->stats.multicast++;
+ }
+ }
+}
+
+void Rx_FastForward(PPRIVATE_DATA privateData,u32 dwDwordCount)
+{
+ privateData->RxFastForwardCount++;
+ if((dwDwordCount>=4)
+ && (
+ (((privateData->dwIdRev&0x0000FFFFUL)==0x00000000UL)
+ && (privateData->dwFpgaRev>=0x36))
+ ||
+ ((privateData->dwIdRev&0x0000FFFFUL)!=0UL)
+ )
+ )
+ {
+ u32 dwTimeOut=500;
+ Lan_SetRegDW(RX_DP_CTRL,(dwDwordCount|RX_DP_CTRL_FFWD_BUSY_));
+ while((dwTimeOut)&&(Lan_GetRegDW(RX_DP_CTRL)&
+ RX_DP_CTRL_FFWD_BUSY_))
+ {
+ udelay(1);
+ dwTimeOut--;
+ }
+ if(dwTimeOut==0) {
+
+ SMSC_WARNING("timed out waiting for RX FFWD to finish, RX_DP_CTRL=0x%08X",
+ Lan_GetRegDW(RX_DP_CTRL));
+ }
+ } else {
+ while(dwDwordCount) {
+ u32 dwTemp=Lan_GetRegDW(RX_DATA_FIFO);
+ dwTemp=dwTemp;
+ dwDwordCount--;
+ }
+ }
+}
+
+//Rx_ReceiverOff, and Rx_ReceiverOn use a reference counter
+// because they are used in both the Rx code and the link management count
+void Rx_ReceiverOff(PPRIVATE_DATA privateData)
+{
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ if(privateData->dwRxOffCount==0) {
+ u32 dwMacCr=Mac_GetRegDW(privateData,MAC_CR,keyCode);
+ if(!(dwMacCr&MAC_CR_RXEN_)) {
+ SMSC_WARNING("Rx_ReceiverOff: Receiver is already Off");
+ }
+ dwMacCr&=(~MAC_CR_RXEN_);
+ Mac_SetRegDW(privateData,MAC_CR,dwMacCr,keyCode);
+ //CLEAR_GPIO(GP_RX);
+ }
+ privateData->dwRxOffCount++;
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+}
+
+//Rx_ReceiverOff, and Rx_ReceiverOn use a reference counter
+// because they are used in both the Rx code and the link management count
+void Rx_ReceiverOn(PPRIVATE_DATA privateData, VL_KEY callerKeyCode)
+{
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=0;
+
+ if (callerKeyCode == 0) {
+ keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ }
+ else {
+ SMSC_ASSERT(Vl_CheckLock(&(privateData->MacPhyLock),callerKeyCode));
+ keyCode = callerKeyCode;
+ }
+ if(privateData->dwRxOffCount>0) {
+ privateData->dwRxOffCount--;
+ if(privateData->dwRxOffCount==0) {
+ u32 dwMacCr=Mac_GetRegDW(privateData,MAC_CR,keyCode);
+ if(dwMacCr&MAC_CR_RXEN_) {
+ SMSC_WARNING("Rx_ReceiverOn: Receiver is already on");
+ }
+ dwMacCr|=MAC_CR_RXEN_;
+ Mac_SetRegDW(privateData,MAC_CR,dwMacCr,keyCode);
+ //SET_GPIO(GP_RX);
+ }
+ } else {
+ SMSC_ASSERT(false);
+ }
+ if (callerKeyCode == 0) {
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ }
+}
+
+void Rx_ProcessPackets(PPRIVATE_DATA privateData)
+{
+ u32 dwRxStatus=0;
+ PPLATFORM_DATA platformData=NULL;
+
+ /*
+#ifdef UseRxCsum
+WORD wHwCsum = 0;
+#endif
+*/
+
+ // SET_GPIO(GP_RX);
+
+ privateData->RxCongested=false;
+ platformData=&(privateData->PlatformData);
+ if(privateData->dwRxDmaCh>=TRANSFER_PIO) {
+ //Use PIO only
+
+ //WARNING: the two LSBs of RXDOFF cannot be changed with the receiver running ,
+ // however we are here re-writing the same value it already had, so it's ok"
+ Lan_SetRegDW(RX_CFG,RX_CFG_RXDOFF_2_);
+ while((dwRxStatus=Rx_PopRxStatus(privateData))!=0)
+ {
+ u32 dwPacketLength=((dwRxStatus&0x3FFF0000UL)>>16);
+
+ //printk("dwPacketLength = 0x%08x\n", (u32) dwPacketLength);
+ //printk("dwRxStatus = 0x%08x\n", (u32) dwRxStatus);
+
+ Rx_CountErrors(privateData,dwRxStatus);
+
+
+ if((dwRxStatus&RX_STS_ES_)==0)
+ //||(((dwRxStatus&0x00001080)==0x00001080)&&(privateData->RxVLanPkt==true)))
+ {
+ struct sk_buff *skb=NULL;
+ skb=dev_alloc_skb(dwPacketLength+2);
+ if(skb!=NULL) {
+ skb->data=skb->head;
+ skb->tail=skb->head;
+ skb_reserve(skb,2); // align IP on 16B boundary
+
+ if (privateData->UseRxCsum)
+ {
+ skb_put(skb,dwPacketLength-2UL-4UL);
+ }
+ else
+ {
+ skb_put(skb,dwPacketLength-4UL);
+ }
+
+
+ //update counters
+ privateData->stats.rx_packets++;
+
+
+ if (privateData->UseRxCsum)
+ {
+ privateData->stats.rx_bytes+=(dwPacketLength-4-2);
+
+ }
+ else
+ {
+ privateData->stats.rx_bytes+=(dwPacketLength-4);
+ }
+
+
+ privateData->RxPacketReadCount++;
+ privateData->RxPioReadCount++;
+ privateData->RxDataDWReadCount+=
+ (dwPacketLength+2+3)>>2;
+
+
+
+ Platform_ReadFifo(
+ privateData->dwLanBase,
+ ((u32 *)(skb->head)),
+ (dwPacketLength+2+3)>>2);
+
+
+ //printk("Rx skb->len = 0x%08x\n", (u32) skb->len);
+
+ Rx_HandOffSkb(privateData,skb);
+ continue;
+ } else {
+ SMSC_WARNING("Unable to allocate sk_buff for RX Packet, in PIO path");
+ privateData->stats.rx_dropped++;
+ }
+ }
+ //if we get here then the packet is to be read
+ // out of the fifo and discarded
+ //printk("fast forward\n");
+ dwPacketLength+=(2+3);
+ dwPacketLength>>=2;
+ Rx_FastForward(privateData,dwPacketLength);
+ }
+ }
+ else {
+
+ //Use DMA and PIO
+ u32 dwDmaCh=privateData->dwRxDmaCh;
+ //struct sk_buff *dmaSkb=NULL;//use privateData->RxDmaSkb
+ DMA_XFER dmaXfer;
+ dmaXfer.dwLanReg=privateData->dwLanBase+RX_DATA_FIFO;
+ dmaXfer.pdwBuf=NULL;// this will be reset per dma request
+ dmaXfer.dwDmaCh=dwDmaCh;
+ dmaXfer.dwDwCnt=0;// this will be reset per dma request
+ dmaXfer.fMemWr=true;
+ while((dwRxStatus=Rx_PopRxStatus(privateData))!=0)
+ {
+ u32 dwPacketLength;
+RUN_AGAIN:
+ Rx_CountErrors(privateData,dwRxStatus);
+ dwPacketLength=((dwRxStatus&0x3FFF0000UL)>>16);
+
+
+ if((dwRxStatus&RX_STS_ES_)==0)
+ {
+ struct sk_buff *skb=dev_alloc_skb(dwPacketLength+2*PLATFORM_CACHE_LINE_BYTES);
+ if(skb!=NULL)
+ {
+ skb->data=skb->head;
+ skb->tail=skb->head;
+
+ //align IP on cache line boundary
+ privateData->stats.rx_packets++;
+ privateData->stats.rx_bytes+=(dwPacketLength-4UL);
+ if(dwPacketLength>=privateData->dwRxDmaThreshold)
+ {
+ //use DMA
+ //printk("Rx using DMA\n");
+ u32 dwDwordCount;
+ skb_reserve(skb,PLATFORM_CACHE_LINE_BYTES-14);
+
+ if (privateData->UseRxCsum)
+ {
+ skb_put(skb,dwPacketLength-2UL-4UL);
+ }
+ else
+ {
+ skb_put(skb,dwPacketLength-4UL);
+ }
+
+
+
+ // skb_put(skb,dwPacketLength-4UL);
+ dwDwordCount=((dwPacketLength+
+ (PLATFORM_CACHE_LINE_BYTES-14)+
+ PLATFORM_CACHE_LINE_BYTES-1)&
+ (~(PLATFORM_CACHE_LINE_BYTES-1)))>>2;
+ Platform_CacheInvalidate(
+ platformData,
+ skb->head,dwDwordCount<<2);
+ dmaXfer.pdwBuf=(u32 *)(skb->head);
+ dmaXfer.dwDwCnt=dwDwordCount;
+ privateData->RxDataDWReadCount+=dwDwordCount;
+ privateData->RxPacketReadCount++;
+ privateData->RxDmaReadCount++;
+ if(privateData->RxSkb)
+ Platform_DmaComplete(platformData,dwDmaCh);
+
+ //set end alignment and offset
+ switch(PLATFORM_CACHE_LINE_BYTES)
+ {
+ //case 4: Lan_SetRegDW(RX_CFG,0x00000200UL);break;
+ //WARNING: the two LSBs of RXDOFF cannot be changed with the receiver running ,
+ // however we are here re-writing the same value it already had, so it's ok"
+ case 16:Lan_SetRegDW(RX_CFG, RX_CFG_RX_END_ALGN16_ |RX_CFG_RXDOFF_2_ );break;
+ case 32:Lan_SetRegDW(RX_CFG, RX_CFG_RX_END_ALGN32_ |RX_CFG_RXDOFF_18_);break;
+ default:SMSC_ASSERT(false);
+ }
+ if(!Platform_DmaStartXfer(platformData,&dmaXfer)) {
+ SMSC_WARNING("Failed Platform_DmaStartXfer");
+ }
+
+
+
+
+ if(privateData->RxSkb) {
+
+ Rx_HandOffSkb(privateData,privateData->RxSkb);
+ }
+ privateData->RxSkb=skb;
+ }
+ else
+ {
+ //use PIO
+
+ // printk("Rx using PIO\n");
+ if(privateData->RxSkb) {
+ Platform_DmaComplete(platformData,dwDmaCh);
+ Rx_HandOffSkb(privateData,privateData->RxSkb);
+ }
+
+ privateData->RxSkb=skb;
+
+ skb_reserve(skb,2);
+
+ if (privateData->UseRxCsum)
+ {
+ skb_put(skb,dwPacketLength-2UL-4UL);
+ }
+ else
+ {
+ skb_put(skb,dwPacketLength-4UL);
+ }
+
+
+
+ // skb_put(skb,dwPacketLength-4UL);
+ //set end alignment and offset
+ //WARNING: the two LSBs of RXDOFF cannot be changed with the receiver running ,
+ // however we are here re-writing the same value it already had, so it's ok"
+ Lan_SetRegDW(RX_CFG, RX_CFG_RXDOFF_2_);//4 byte end alignment
+ privateData->RxPacketReadCount++;
+ privateData->RxPioReadCount++;
+ privateData->RxDataDWReadCount+=
+ ((dwPacketLength+2+3)>>2);
+ Platform_ReadFifo(
+ privateData->dwLanBase,
+ ((u32 *)(skb->head)),
+ (dwPacketLength+2+3)>>2);
+
+
+
+ }
+ continue;
+ }
+ else
+ {
+ SMSC_WARNING("Unable to allocate sk_buff for RX Packet, in DMA path");
+ privateData->stats.rx_dropped++;
+ }
+ }
+ //if we get here then the packet is to be read
+ // out of the fifo and discarded
+ if(privateData->RxSkb) Platform_DmaComplete(platformData,dwDmaCh);
+ //delay returning the dmaSkb to OS till later
+ dwPacketLength+=(2+3);
+ dwPacketLength>>=2;
+ //WARNING: the two LSBs of RXDOFF cannot be changed with the receiver running ,
+ // however we are here re-writing the same value it already had, so it's ok"
+ Lan_SetRegDW(RX_CFG,RX_CFG_RXDOFF_2_);//4 byte end alignment
+ Rx_FastForward(privateData,dwPacketLength);
+ }
+ if(privateData->RxSkb) {
+ //while waiting for dma to complete,
+ // check if another packet arrives
+ u32 dwTimeOut=1000000;
+ while((Platform_DmaGetDwCnt(platformData,dwDmaCh))&&
+ (dwTimeOut))
+ {
+ if((dwRxStatus=Rx_PopRxStatus(privateData))!=0) {
+ goto RUN_AGAIN;
+ }
+ udelay(1);
+ dwTimeOut--;
+ }
+ if(dwTimeOut==0) {
+ SMSC_WARNING("Timed out while waiting for final Dma to complete");
+ }
+ if((dwRxStatus=Rx_PopRxStatus(privateData))!=0) {
+ goto RUN_AGAIN;
+ }
+
+
+ Rx_HandOffSkb(privateData,privateData->RxSkb);
+ privateData->RxSkb=NULL;
+
+ //check one last time for another packet.
+ if((dwRxStatus=Rx_PopRxStatus(privateData))!=0) {
+ goto RUN_AGAIN;
+ }
+ }
+ }
+ Lan_SetRegDW(INT_STS,INT_STS_RSFL_);
+ // CLEAR_GPIO(GP_RX);
+}
+
+void Rx_ProcessPacketsTasklet(unsigned long data)
+{
+ PPRIVATE_DATA privateData=(PPRIVATE_DATA)Rx_TaskletParameter;
+ data=data;//make lint happy
+ if(privateData==NULL) {
+ SMSC_WARNING("Rx_ProcessPacketsTasklet(privateData==NULL)");
+ return;
+ }
+ Rx_ProcessPackets(privateData);
+ Lan_EnableIRQ(privateData);
+}
+
+#ifdef LINUX_2_6_OR_NEWER
+/*
+int Smsc9118_rx_poll(struct net_device *dev,int * budget)
+{
+ int result=0;
+ int limit=0;
+
+ PPRIVATE_DATA privateData=NULL;
+ SMSC_ASSERT(dev!=NULL);
+ SMSC_ASSERT(budget!=NULL);
+ privateData=((PPRIVATE_DATA)(dev->ml_priv));
+ SMSC_ASSERT(privateData!=NULL);
+
+ privateData->RxWorkLimit=dev->quota;
+ if((privateData->RxWorkLimit)>(*budget)) {
+ privateData->RxWorkLimit=(*budget);
+ }
+
+ limit=privateData->RxWorkLimit;
+
+ privateData->RxPacketsReceived=0;
+ // privateData->RxDone=false;
+ Rx_ProcessPackets(privateData);
+
+ dev->quota-=privateData->RxPacketsReceived;
+ (*budget)-=privateData->RxPacketsReceived;
+
+ if(privateData->RxPacketsReceived < limit) {
+ netif_rx_complete(dev);
+ Lan_EnableIRQ(privateData);
+ } else {
+ result=1;
+ }
+
+ return result;
+}
+*/
+#endif
+
+
+
+
+
+bool Rx_HandleInterrupt(
+ PPRIVATE_DATA privateData,
+ u32 dwIntSts)
+{
+ bool result=false;
+ SMSC_ASSERT(privateData!=NULL);
+
+ privateData->LastReasonForReleasingCPU=0;
+
+ if(dwIntSts&INT_STS_RXE_) {
+ SMSC_TRACE("Rx_HandleInterrupt: RXE signalled");
+ privateData->stats.rx_errors++;
+ Lan_SetRegDW(INT_STS,INT_STS_RXE_);
+ result=true;
+ }
+
+ if(dwIntSts&INT_STS_RXDFH_INT_) {
+ privateData->stats.rx_dropped+=Lan_GetRegDW(RX_DROP);
+ Lan_SetRegDW(INT_STS,INT_STS_RXDFH_INT_);
+ result=true;
+ }
+
+ if(privateData->dwGeneration==0) {
+ if(dwIntSts&(INT_STS_RDFL_)) {
+ Lan_SetRegDW(INT_STS,INT_STS_RDFL_);
+ Rx_HandleOverrun(privateData);
+ result=true;
+ }
+ } else {
+ if(dwIntSts&(INT_STS_RDFO_)) {
+ Lan_SetRegDW(INT_STS,INT_STS_RDFO_);
+ Rx_HandleOverrun(privateData);
+ result=true;
+ }
+ }
+
+ if((!(dwIntSts&INT_STS_RSFL_))&&(privateData->RxOverrun==false)) {
+ return result;
+ }
+ result=true;
+
+ if(privateData->MeasuringRxThroughput==false) {
+ privateData->MeasuringRxThroughput=true;
+ Gpt_ScheduleCallBack(privateData,GptCB_MeasureRxThroughput,1000);
+ privateData->RxFlowCurrentThroughput=0;
+ privateData->RxFlowCurrentPacketCount=0;
+ privateData->RxFlowCurrentWorkLoad=0;
+ }
+
+
+#ifdef LINUX_2_6_OR_NEWER
+ if(rx_mode==PROCESSING_MODE_TASKLET) {
+ Lan_DisableIRQ(privateData);
+ Rx_TaskletParameter=(unsigned long)privateData;
+ tasklet_schedule(&Rx_Tasklet);
+ }else if (rx_mode==PROCESSING_MODE_NAPI) {
+ /*
+ Lan_DisableIRQ(privateData);
+ netif_rx_schedule(privateData->dev);
+ */
+ }else {
+ Rx_ProcessPackets(privateData);
+ }
+#else
+ if(rx_mode==PROCESSING_MODE_TASKLET) {
+ Lan_DisableIRQ(privateData);
+ Rx_TaskletParameter=(unsigned long)privateData;
+ tasklet_schedule(&Rx_Tasklet);
+ }else {
+ Rx_ProcessPackets(privateData);
+ }
+#endif
+
+ return result;
+}
+
+bool RxStop_HandleInterrupt(
+ PPRIVATE_DATA privateData,
+ u32 dwIntSts)
+{
+ bool result=false;
+ SMSC_ASSERT(privateData!=NULL);
+
+ if(dwIntSts&INT_STS_RXSTOP_INT_) {
+ result=true;
+ Gpt_CancelCallBack (privateData, GptCB_RxCompleteMulticast);
+ Rx_CompleteMulticastUpdate (privateData);
+ Lan_SetRegDW(INT_STS,INT_STS_RXSTOP_INT_);
+ Lan_DisableInterrupt(privateData,INT_EN_RXSTOP_INT_EN_);
+ }
+ return result;
+}
+
+//returns hash bit number for given MAC address
+//example:
+// 01 00 5E 00 00 01 -> returns bit number 31
+static u32 Rx_Hash(BYTE addr[6])
+{
+ int i;
+ u32 crc=0xFFFFFFFFUL;
+ u32 poly=0xEDB88320UL;
+ u32 result=0;
+ for(i=0;i<6;i++)
+ {
+ int bit;
+ u32 data=((u32)addr[i]);
+ for(bit=0;bit<8;bit++)
+ {
+ u32 p = (crc^((u32)data))&1UL;
+ crc >>= 1;
+ if(p!=0) crc ^= poly;
+ data >>=1;
+ }
+ }
+ result=((crc&0x01UL)<<5)|
+ ((crc&0x02UL)<<3)|
+ ((crc&0x04UL)<<1)|
+ ((crc&0x08UL)>>1)|
+ ((crc&0x10UL)>>3)|
+ ((crc&0x20UL)>>5);
+ return result;
+}
+
+void Rx_SetMulticastList(
+ struct net_device *dev)
+{
+ PPRIVATE_DATA privateData=NULL;
+ VL_KEY keyCode=0;
+ unsigned long dwIntFlags=0;
+ SMSC_ASSERT(dev!=NULL);
+
+ privateData=((PPRIVATE_DATA)(dev->ml_priv));
+ SMSC_ASSERT(privateData!=NULL);
+ keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+
+ if(dev->flags & IFF_PROMISC) {
+ // SMSC_TRACE("Promiscuous Mode Enabled");
+ privateData->set_bits_mask = MAC_CR_PRMS_;
+ privateData->clear_bits_mask = (MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+
+ privateData->HashHi = 0UL;
+ privateData->HashLo = 0UL;
+ goto PREPARE;
+ }
+
+ if(dev->flags & IFF_ALLMULTI) {
+ // SMSC_TRACE("Receive all Multicast Enabled");
+ privateData->set_bits_mask = MAC_CR_MCPAS_;
+ privateData->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_);
+
+ privateData->HashHi = 0UL;
+ privateData->HashLo = 0UL;
+ goto PREPARE;
+ }
+
+
+ if(dev->mc_count>0) {
+ u32 dwHashH=0;
+ u32 dwHashL=0;
+ u32 dwCount=0;
+ struct dev_mc_list *mc_list=dev->mc_list;
+
+ privateData->set_bits_mask = MAC_CR_HPFILT_;
+ privateData->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_);
+
+ while(mc_list!=NULL) {
+ dwCount++;
+ if((mc_list->dmi_addrlen)==6) {
+ u32 dwMask=0x01UL;
+ u32 dwBitNum=Rx_Hash(mc_list->dmi_addr);
+ // SMSC_TRACE("Multicast: enable dwBitNum=%d,addr=%02X %02X %02X %02X %02X %02X",
+ // dwBitNum,
+ // ((BYTE *)(mc_list->dmi_addr))[0],
+ // ((BYTE *)(mc_list->dmi_addr))[1],
+ // ((BYTE *)(mc_list->dmi_addr))[2],
+ // ((BYTE *)(mc_list->dmi_addr))[3],
+ // ((BYTE *)(mc_list->dmi_addr))[4],
+ // ((BYTE *)(mc_list->dmi_addr))[5]);
+ dwMask<<=(dwBitNum&0x1FUL);
+ if(dwBitNum&0x20UL) {
+ dwHashH|=dwMask;
+ } else {
+ dwHashL|=dwMask;
+ }
+ } else {
+ SMSC_WARNING("dmi_addrlen!=6");
+ }
+ mc_list=mc_list->next;
+ }
+ if(dwCount!=((u32)(dev->mc_count))) {
+ SMSC_WARNING("dwCount!=dev->mc_count");
+ }
+ // SMSC_TRACE("Multicast: HASHH=0x%08X,HASHL=0x%08X",dwHashH,dwHashL);
+ privateData->HashHi = dwHashH;
+ privateData->HashLo = dwHashL;
+ }
+ else
+ {
+ privateData->set_bits_mask = 0L;
+ privateData->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+
+ // SMSC_TRACE("Receive own packets only.");
+ privateData->HashHi = 0UL;
+ privateData->HashLo = 0UL;
+ }
+
+PREPARE:
+ if(privateData->dwGeneration<=1) {
+ if (privateData->MulticastUpdatePending == false) {
+ privateData->MulticastUpdatePending = true;
+ // prepare to signal software interrupt
+ Lan_SignalSoftwareInterrupt(privateData);
+ }
+ else {
+ // Rx_CompleteMulticastUpdate has not yet been called
+ // therefore these latest settings will be used instead
+ }
+ } else {
+ u32 local_MACCR;
+ Mac_SetRegDW(privateData,HASHH,privateData->HashHi,keyCode);
+ Mac_SetRegDW(privateData,HASHL,privateData->HashLo,keyCode);
+ local_MACCR = Mac_GetRegDW(privateData,MAC_CR,keyCode);
+ local_MACCR |= privateData->set_bits_mask;
+ local_MACCR &= ~(privateData->clear_bits_mask);
+ Mac_SetRegDW(privateData,MAC_CR,local_MACCR,keyCode);
+ }
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ return;
+}
+
+void Eeprom_EnableAccess(PPRIVATE_DATA privateData)
+{
+ SMSC_ASSERT(privateData!=NULL);
+ if(debug_mode&0x04UL) {
+ Lan_SetRegDW(GPIO_CFG,(g_GpioSetting&0xFF0FFFFFUL));
+ } else {
+ Lan_ClrBitsDW(GPIO_CFG,0x00F00000UL);
+ }
+ udelay(100);
+}
+
+void Eeprom_DisableAccess(PPRIVATE_DATA privateData)
+{
+ SMSC_ASSERT(privateData!=NULL);
+ if(debug_mode&0x04UL) {
+ Lan_SetRegDW(GPIO_CFG,g_GpioSetting);
+ }
+}
+
+bool Eeprom_IsMacAddressLoaded(PPRIVATE_DATA privateData)
+{
+ SMSC_ASSERT(privateData!=NULL);
+ return (Lan_GetRegDW(E2P_CMD)&
+ E2P_CMD_MAC_ADDR_LOADED_)?true:false;
+}
+
+bool Eeprom_IsBusy(PPRIVATE_DATA privateData)
+{
+ SMSC_ASSERT(privateData!=NULL);
+ return (Lan_GetRegDW(E2P_CMD)&
+ E2P_CMD_EPC_BUSY_)?true:false;
+}
+
+bool Eeprom_Timeout(PPRIVATE_DATA privateData)
+{
+ SMSC_ASSERT(privateData!=NULL);
+ return (Lan_GetRegDW(E2P_CMD)&
+ E2P_CMD_EPC_TIMEOUT_)?true:false;
+}
+
+bool Eeprom_ReadLocation(
+ PPRIVATE_DATA privateData,
+ BYTE address, BYTE * data)
+{
+ u32 timeout=100000;
+ u32 temp=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(data!=NULL);
+ if((temp=Lan_GetRegDW(E2P_CMD))&E2P_CMD_EPC_BUSY_) {
+ SMSC_WARNING("Eeprom_ReadLocation: Busy at start, E2P_CMD=0x%08X",temp);
+ return false;
+ }
+ Lan_SetRegDW(E2P_CMD,
+ (E2P_CMD_EPC_BUSY_|E2P_CMD_EPC_CMD_READ_|((u32)address)));
+ while((timeout>0)&&
+ (Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_))
+ {
+ udelay(10);
+ timeout--;
+ }
+ if(timeout==0) {
+ return false;
+ }
+ (*data)=(BYTE)(Lan_GetRegDW(E2P_DATA));
+ return true;
+}
+
+bool Eeprom_EnableEraseAndWrite(
+ PPRIVATE_DATA privateData)
+{
+ u32 timeout=100000;
+ SMSC_ASSERT(privateData!=NULL);
+ if(Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_) {
+ SMSC_WARNING("Eeprom_EnableEraseAndWrite: Busy at start");
+ return false;
+ }
+ Lan_SetRegDW(E2P_CMD,
+ (E2P_CMD_EPC_BUSY_|E2P_CMD_EPC_CMD_EWEN_));
+
+ while((timeout>0)&&
+ (Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_))
+ {
+ udelay(10);
+ timeout--;
+ }
+ if(timeout==0) {
+ return false;
+ }
+ return true;
+}
+
+bool Eeprom_DisableEraseAndWrite(
+ PPRIVATE_DATA privateData)
+{
+ u32 timeout=100000;
+ SMSC_ASSERT(privateData!=NULL);
+ if(Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_) {
+ SMSC_WARNING("Eeprom_DisableEraseAndWrite: Busy at start");
+ return false;
+ }
+ Lan_SetRegDW(E2P_CMD,
+ (E2P_CMD_EPC_BUSY_|E2P_CMD_EPC_CMD_EWDS_));
+
+ while((timeout>0)&&
+ (Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_))
+ {
+ udelay(10);
+ timeout--;
+ }
+ if(timeout==0) {
+ return false;
+ }
+ return true;
+}
+
+bool Eeprom_WriteLocation(
+ PPRIVATE_DATA privateData,BYTE address,BYTE data)
+{
+ u32 timeout=100000;
+ SMSC_ASSERT(privateData!=NULL);
+ if(Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_) {
+ SMSC_WARNING("Eeprom_WriteLocation: Busy at start");
+ return false;
+ }
+ Lan_SetRegDW(E2P_DATA,((u32)data));
+ Lan_SetRegDW(E2P_CMD,
+ (E2P_CMD_EPC_BUSY_|E2P_CMD_EPC_CMD_WRITE_|((u32)address)));
+
+ while((timeout>0)&&
+ (Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_))
+ {
+ udelay(10);
+ timeout--;
+ }
+ if(timeout==0) {
+ return false;
+ }
+ return true;
+}
+
+bool Eeprom_EraseAll(
+ PPRIVATE_DATA privateData)
+{
+ u32 timeout=100000;
+ SMSC_ASSERT(privateData!=NULL);
+ if(Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_) {
+ SMSC_WARNING("Eeprom_EraseAll: Busy at start");
+ return false;
+ }
+ Lan_SetRegDW(E2P_CMD,
+ (E2P_CMD_EPC_BUSY_|E2P_CMD_EPC_CMD_ERAL_));
+
+ while((timeout>0)&&
+ (Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_))
+ {
+ udelay(10);
+ timeout--;
+ }
+ if(timeout==0) {
+ return false;
+ }
+ return true;
+}
+
+bool Eeprom_Reload(
+ PPRIVATE_DATA privateData)
+{
+ u32 timeout=100000;
+ SMSC_ASSERT(privateData!=NULL);
+ if(Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_) {
+ SMSC_WARNING("Eeprom_Reload: Busy at start");
+ return false;
+ }
+ Lan_SetRegDW(E2P_CMD,
+ (E2P_CMD_EPC_BUSY_|E2P_CMD_EPC_CMD_RELOAD_));
+
+ while((timeout>0)&&
+ (Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_))
+ {
+ udelay(10);
+ timeout--;
+ }
+ if(timeout==0) {
+ return false;
+ }
+ return true;
+}
+
+bool Eeprom_SaveMacAddress(
+ PPRIVATE_DATA privateData,
+ u32 dwHi16,u32 dwLo32)
+{
+ bool result=false;
+ SMSC_ASSERT(privateData!=NULL);
+ Eeprom_EnableAccess(privateData);
+ if(!Eeprom_EnableEraseAndWrite(privateData)) goto DONE;
+ if(!Eeprom_EraseAll(privateData)) goto DONE;
+ if(privateData->dwGeneration==0) {
+ if(!Eeprom_EnableEraseAndWrite(privateData)) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,0,0xA5)) goto DONE;
+ if(!Eeprom_EnableEraseAndWrite(privateData)) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,1,LOBYTE(LOWORD(dwLo32)))) goto DONE;
+ if(!Eeprom_EnableEraseAndWrite(privateData)) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,2,HIBYTE(LOWORD(dwLo32)))) goto DONE;
+ if(!Eeprom_EnableEraseAndWrite(privateData)) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,3,LOBYTE(HIWORD(dwLo32)))) goto DONE;
+ if(!Eeprom_EnableEraseAndWrite(privateData)) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,4,HIBYTE(HIWORD(dwLo32)))) goto DONE;
+ if(!Eeprom_EnableEraseAndWrite(privateData)) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,5,LOBYTE(LOWORD(dwHi16)))) goto DONE;
+ if(!Eeprom_EnableEraseAndWrite(privateData)) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,6,HIBYTE(LOWORD(dwHi16)))) goto DONE;
+ } else {
+ if(!Eeprom_WriteLocation(privateData,0,0xA5)) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,1,LOBYTE(LOWORD(dwLo32)))) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,2,HIBYTE(LOWORD(dwLo32)))) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,3,LOBYTE(HIWORD(dwLo32)))) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,4,HIBYTE(HIWORD(dwLo32)))) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,5,LOBYTE(LOWORD(dwHi16)))) goto DONE;
+ if(!Eeprom_WriteLocation(privateData,6,HIBYTE(LOWORD(dwHi16)))) goto DONE;
+ }
+ if(!Eeprom_DisableEraseAndWrite(privateData)) goto DONE;
+
+ if(!Eeprom_Reload(privateData)) goto DONE;
+ if(!Eeprom_IsMacAddressLoaded(privateData)) goto DONE;
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ if(dwHi16!=Mac_GetRegDW(privateData,ADDRH,keyCode)) goto DONE;
+ if(dwLo32!=Mac_GetRegDW(privateData,ADDRL,keyCode)) goto DONE;
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ }
+ result=true;
+DONE:
+ Eeprom_DisableAccess(privateData);
+ return result;
+}
+
+volatile u32 g_GpioSetting=0x00000000UL;
+#ifdef USE_LED1_WORK_AROUND
+volatile u32 g_GpioSettingOriginal=0x00000000UL;
+#endif
+
+bool Lan_Initialize(
+ PPRIVATE_DATA privateData,
+ u32 dwIntCfg,
+ u32 dwTxFifSz,
+ u32 dwAfcCfg)
+{
+ bool result=false;
+ u32 dwTimeOut=0;
+ u32 dwTemp=0;
+ u32 dwResetCount=3;
+
+ SMSC_TRACE("-->Lan_Initialize(dwIntCfg=0x%08X)",dwIntCfg);
+ SMSC_ASSERT(privateData!=NULL);
+
+ //Reset the LAN9118
+ if(privateData->dwGeneration>0) {
+ dwResetCount=1;
+ }
+ while(dwResetCount>0) {
+ Lan_SetRegDW(HW_CFG,HW_CFG_SRST_);
+ dwTimeOut=1000000;
+ do {
+ udelay(10);
+ dwTemp=Lan_GetRegDW(HW_CFG);
+ dwTimeOut--;
+ } while((dwTimeOut>0)&&(dwTemp&HW_CFG_SRST_));
+ if(dwTemp&HW_CFG_SRST_) {
+ SMSC_WARNING(" Failed to complete reset.");
+ goto DONE;
+ }
+ dwResetCount--;
+ }
+
+ SMSC_ASSERT(dwTxFifSz>=0x00020000UL);
+ SMSC_ASSERT(dwTxFifSz<=0x000E0000UL);
+ SMSC_ASSERT((dwTxFifSz&(~HW_CFG_TX_FIF_SZ_))==0);
+ Lan_SetRegDW(HW_CFG,dwTxFifSz);
+ privateData->RxMaxDataFifoSize=0;
+ switch(dwTxFifSz>>16) {
+ case 2:privateData->RxMaxDataFifoSize=13440;break;
+ case 3:privateData->RxMaxDataFifoSize=12480;break;
+ case 4:privateData->RxMaxDataFifoSize=11520;break;
+ case 5:privateData->RxMaxDataFifoSize=10560;break;
+ case 6:privateData->RxMaxDataFifoSize=9600;break;
+ case 7:privateData->RxMaxDataFifoSize=8640;break;
+ case 8:privateData->RxMaxDataFifoSize=7680;break;
+ case 9:privateData->RxMaxDataFifoSize=6720;break;
+ case 10:privateData->RxMaxDataFifoSize=5760;break;
+ case 11:privateData->RxMaxDataFifoSize=4800;break;
+ case 12:privateData->RxMaxDataFifoSize=3840;break;
+ case 13:privateData->RxMaxDataFifoSize=2880;break;
+ case 14:privateData->RxMaxDataFifoSize=1920;break;
+ default:SMSC_ASSERT(false);break;
+ }
+
+ if(dwAfcCfg==0xFFFFFFFF) {
+ switch(dwTxFifSz) {
+
+ //AFC_HI is about ((Rx Data Fifo Size)*2/3)/64
+ //AFC_LO is AFC_HI/2
+ //BACK_DUR is about 5uS*(AFC_LO) rounded down
+ case 0x00020000UL://13440 Rx Data Fifo Size
+ dwAfcCfg=0x008C46AF;break;
+ case 0x00030000UL://12480 Rx Data Fifo Size
+ dwAfcCfg=0x0082419F;break;
+ case 0x00040000UL://11520 Rx Data Fifo Size
+
+ dwAfcCfg=0x00783C9F;break;
+ case 0x00050000UL://10560 Rx Data Fifo Size
+ // dwAfcCfg=0x006E378F;break;
+ dwAfcCfg=0x006E374F;break;
+ case 0x00060000UL:// 9600 Rx Data Fifo Size
+ dwAfcCfg=0x0064328F;break;
+ case 0x00070000UL:// 8640 Rx Data Fifo Size
+ dwAfcCfg=0x005A2D7F;break;
+ case 0x00080000UL:// 7680 Rx Data Fifo Size
+ dwAfcCfg=0x0050287F;break;
+ case 0x00090000UL:// 6720 Rx Data Fifo Size
+ dwAfcCfg=0x0046236F;break;
+ case 0x000A0000UL:// 5760 Rx Data Fifo Size
+ dwAfcCfg=0x003C1E6F;break;
+ case 0x000B0000UL:// 4800 Rx Data Fifo Size
+ dwAfcCfg=0x0032195F;break;
+
+ //AFC_HI is ~1520 bytes less than RX Data Fifo Size
+ //AFC_LO is AFC_HI/2
+ //BACK_DUR is about 5uS*(AFC_LO) rounded down
+ case 0x000C0000UL:// 3840 Rx Data Fifo Size
+ dwAfcCfg=0x0024124F;break;
+ case 0x000D0000UL:// 2880 Rx Data Fifo Size
+ dwAfcCfg=0x0015073F;break;
+ case 0x000E0000UL:// 1920 Rx Data Fifo Size
+ dwAfcCfg=0x0006032F;break;
+ default:SMSC_ASSERT(false);break;
+ }
+ }
+ Lan_SetRegDW(AFC_CFG,(dwAfcCfg&0xFFFFFFF0UL));
+
+ //make sure EEPROM has finished loading before setting GPIO_CFG
+ dwTimeOut=1000;
+ while((dwTimeOut>0)&&(Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_)) {
+ udelay(5);
+ dwTimeOut--;
+ }
+ if(dwTimeOut==0) {
+ SMSC_WARNING("Lan_Initialize: Timed out waiting for EEPROM busy bit to clear\n");
+ }
+
+ if(debug_mode&0x04UL) {
+ if(OLD_REGISTERS(privateData))
+ {
+ g_GpioSetting=0x00270700UL;
+ } else {
+ g_GpioSetting=0x00670700UL;
+ }
+ } else {
+ g_GpioSetting = 0x70070000UL;
+ }
+ Lan_SetRegDW(GPIO_CFG,g_GpioSetting);
+
+ //initialize interrupts
+ Lan_SetRegDW(INT_EN,0);
+ Lan_SetRegDW(INT_STS,0xFFFFFFFFUL);
+ dwIntCfg|=INT_CFG_IRQ_EN_;
+ Lan_SetRegDW(INT_CFG,dwIntCfg);
+
+ Vl_InitLock(&(privateData->MacPhyLock));
+ spin_lock_init(&(privateData->IntEnableLock));
+ privateData->LanInitialized=true;
+
+ result=true;
+
+DONE:
+ SMSC_TRACE("<--Lan_Initialize");
+ return result;
+}
+
+void Lan_EnableInterrupt(PPRIVATE_DATA privateData,u32 dwIntEnMask)
+{
+ unsigned long dwIntFlags=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->LanInitialized==true);
+ spin_lock_irqsave(&(privateData->IntEnableLock),dwIntFlags);
+ Lan_SetBitsDW(INT_EN,dwIntEnMask);
+ spin_unlock_irqrestore(&(privateData->IntEnableLock),dwIntFlags);
+}
+
+void Lan_DisableInterrupt(PPRIVATE_DATA privateData,u32 dwIntEnMask)
+{
+ unsigned long dwIntFlags=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->LanInitialized==true);
+ spin_lock_irqsave(&(privateData->IntEnableLock),dwIntFlags);
+ Lan_ClrBitsDW(INT_EN,dwIntEnMask);
+ spin_unlock_irqrestore(&(privateData->IntEnableLock),dwIntFlags);
+}
+
+//Spin locks for the following functions have been commented out
+// because at this time they are not necessary.
+//These function are
+// Lan_SetTDFL
+// Lan_SetTSFL
+// Lan_SetRDFL
+// Lan_SetRSFL
+//Both the Rx and Tx side of the driver use the FIFO_INT,
+// but the Rx side only touches is during initialization,
+// so it is sufficient that Tx side simple preserve the Rx setting
+
+void Lan_SetTDFL(PPRIVATE_DATA privateData,BYTE level) {
+ // unsigned long dwIntFlags=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->LanInitialized==true);
+ // spin_lock_irqsave(&(privateData->IntEnableLock),dwIntFlags);
+ {
+ u32 temp=Lan_GetRegDW(FIFO_INT);
+ temp&=0x00FFFFFFUL;
+ temp|=((u32)level)<<24;
+ Lan_SetRegDW(FIFO_INT,temp);
+ }
+ // spin_unlock_irqrestore(&(privateData->IntEnableLock),dwIntFlags);
+}
+
+void Lan_SetTSFL(PPRIVATE_DATA privateData,BYTE level) {
+ // unsigned long dwIntFlags=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->LanInitialized==true);
+ // spin_lock_irqsave(&(privateData->IntEnableLock),dwIntFlags);
+ {
+ u32 temp=Lan_GetRegDW(FIFO_INT);
+ temp&=0xFF00FFFFUL;
+ temp|=((u32)level)<<16;
+ Lan_SetRegDW(FIFO_INT,temp);
+ }
+ // spin_unlock_irqrestore(&(privateData->IntEnableLock),dwIntFlags);
+}
+
+void Lan_SetRDFL(PPRIVATE_DATA privateData,BYTE level) {
+ // unsigned long dwIntFlags=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->LanInitialized==true);
+ // spin_lock_irqsave(&(privateData->IntEnableLock),dwIntFlags);
+ {
+ u32 temp=Lan_GetRegDW(FIFO_INT);
+ temp&=0xFFFF00FFUL;
+ temp|=((u32)level)<<8;
+ Lan_SetRegDW(FIFO_INT,temp);
+ }
+ // spin_unlock_irqrestore(&(privateData->IntEnableLock),dwIntFlags);
+}
+
+void Lan_SetRSFL(PPRIVATE_DATA privateData,BYTE level) {
+ // unsigned long dwIntFlags=0;
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->LanInitialized==true);
+ // spin_lock_irqsave(&(privateData->IntEnableLock),dwIntFlags);
+ {
+ u32 temp=Lan_GetRegDW(FIFO_INT);
+ temp&=0xFFFFFF00UL;
+ temp|=((u32)level);
+ Lan_SetRegDW(FIFO_INT,temp);
+ }
+ // spin_unlock_irqrestore(&(privateData->IntEnableLock),dwIntFlags);
+}
+
+void Lan_EnableIRQ(PPRIVATE_DATA privateData)
+{
+ unsigned long dwIntFlags=0;
+ spin_lock_irqsave(&(privateData->IntEnableLock),dwIntFlags);
+ {
+ Lan_SetBitsDW(INT_CFG,INT_CFG_IRQ_EN_);
+ }
+ spin_unlock_irqrestore(&(privateData->IntEnableLock),dwIntFlags);
+}
+
+void Lan_DisableIRQ(PPRIVATE_DATA privateData)
+{
+ unsigned long dwIntFlags=0;
+ spin_lock_irqsave(&(privateData->IntEnableLock),dwIntFlags);
+ {
+ Lan_ClrBitsDW(INT_CFG,INT_CFG_IRQ_EN_);
+ }
+ spin_unlock_irqrestore(&(privateData->IntEnableLock),dwIntFlags);
+}
+
+void Lan_SetIntDeas(PPRIVATE_DATA privateData, u32 dwIntDeas)
+{
+ unsigned long dwIntFlags=0;
+ spin_lock_irqsave(&(privateData->IntEnableLock),dwIntFlags);
+ {
+ Lan_ClrBitsDW(INT_CFG,INT_CFG_INT_DEAS_);
+ Lan_SetBitsDW(INT_CFG,(dwIntDeas<<24));
+ }
+ spin_unlock_irqrestore(&(privateData->IntEnableLock),dwIntFlags);
+}
+
+void Lan_SignalSoftwareInterrupt(PPRIVATE_DATA privateData)
+{
+ SMSC_ASSERT(privateData!=NULL);
+ SMSC_ASSERT(privateData->dwLanBase!=0);
+ privateData->SoftwareInterruptSignal=false;
+ Lan_EnableInterrupt(privateData,INT_EN_SW_INT_EN_);
+}
+
+bool Lan_HandleSoftwareInterrupt(
+ PPRIVATE_DATA privateData,
+ u32 dwIntSts)
+{
+ if(dwIntSts&INT_STS_SW_INT_) {
+ SMSC_TRACE("Got SW Interrupt (privateData=%08X)", (u32)privateData);
+ SMSC_ASSERT(privateData!=NULL);
+ Lan_DisableInterrupt(privateData,INT_EN_SW_INT_EN_);
+ Lan_SetRegDW(INT_STS,INT_STS_SW_INT_);
+ privateData->SoftwareInterruptSignal=true;
+ if (privateData->MulticastUpdatePending) {
+ Rx_BeginMulticastUpdate (privateData);
+ }
+ return true;
+ }
+ return false;
+}
+
+typedef struct _SHOW_REG
+{
+ char szName[20];
+ u32 dwOffset;
+} SHOW_REG;
+/*
+FUNCTION: Lan_ShowRegs
+This function is used to display the registers.
+Except the phy.
+*/
+void Lan_ShowRegs(PPRIVATE_DATA privateData)
+{
+ // Make these const struct's static to keep them off the stack.
+ // Otherwise, gcc will try to use _memcpy() to initialize them,
+ // which will *NOT* work in our RunTime environment.
+ static const SHOW_REG sysCsr[] = {
+ { "ID_REV", 0x50UL },
+ { "INT_CFG", 0x54UL },
+ { "INT_STS", 0x58UL },
+ { "INT_EN", 0x5CUL },
+ { "DMA_CFG", 0x60UL },
+ { "BYTE_TEST", 0x64UL },
+ { "FIFO_INT", 0x68UL },
+ { "RX_CFG", 0x6CUL },
+ { "TX_CFG", 0x70UL },
+ { "HW_CFG", 0x74UL },
+ { "RX_DP_CTRL", 0x78UL },
+ { "RX_FIFO_INF", 0x7CUL },
+ { "TX_FIFO_INF", 0x80UL },
+ { "PMT_CTRL", 0x84UL },
+ { "GPIO_CFG", 0x88UL },
+ { "GPT_CFG", 0x8CUL },
+ { "GPT_CNT", 0x90UL },
+ { "FPGA_REV", 0x94UL },
+ { "WORD_SWAP", 0x98UL },
+ { "FREE_RUN", 0x9CUL },
+ { "RX_DROP", 0xA0UL },
+ { "MAC_CSR_CMD", 0xA4UL },
+ { "MAC_CSR_DATA", 0xA8UL },
+ { "AFC_CFG", 0xACUL },
+ { "E2P_CMD", 0xB0UL },
+ { "E2P_DATA", 0xB4UL },
+ { "TEST_REG_A", 0xC0UL }};
+
+ static const SHOW_REG macCsr[] = {
+ { "MAC_CR", MAC_CR },
+ { "ADDRH", ADDRH },
+ { "ADDRL", ADDRL },
+ { "HASHH", HASHH },
+ { "HASHL", HASHL },
+ { "MII_ACC", MII_ACC },
+ { "MII_DATA", MII_DATA },
+ { "FLOW", FLOW },
+ { "VLAN1", VLAN1 },
+ { "VLAN2", VLAN2 },
+ { "WUFF", WUFF },
+ { "WUCSR", WUCSR }};
+
+ int i, iNumSysRegs, iNumMacRegs;
+ u32 dwOldMacCmdReg, dwOldMacDataReg;
+
+ iNumSysRegs = (int)(sizeof(sysCsr) / sizeof(SHOW_REG));
+ iNumMacRegs = (int)(sizeof(macCsr) / sizeof(SHOW_REG));
+
+ // preserve MAC cmd/data reg's
+ dwOldMacCmdReg = Lan_GetRegDW(MAC_CSR_CMD);
+ dwOldMacDataReg = Lan_GetRegDW(MAC_CSR_DATA);
+
+ SMSC_TRACE("");
+ SMSC_TRACE(" LAN91C118 CSR's");
+ SMSC_TRACE(" SYS CSR's MAC CSR's");
+
+ {
+ unsigned long dwIntFlags=0;
+ VL_KEY keyCode=Vl_WaitForLock(&(privateData->MacPhyLock),&dwIntFlags);
+ for (i=0; i<iNumMacRegs; i++)
+ {
+ SMSC_TRACE(
+ "%16s (0x%02X) = 0x%08X, %8s (0x%02X) + 0x%08X",
+ sysCsr[i].szName,
+ sysCsr[i].dwOffset,
+ *((volatile u32 *)(privateData->dwLanBase+sysCsr[i].dwOffset)),
+ macCsr[i].szName,
+ macCsr[i].dwOffset,
+ Mac_GetRegDW(privateData,macCsr[i].dwOffset,keyCode));
+
+ // restore original mac cmd/data reg's after each usage
+ Lan_SetRegDW(MAC_CSR_CMD,dwOldMacCmdReg);
+ Lan_SetRegDW(MAC_CSR_DATA,dwOldMacDataReg);
+ }
+ Vl_ReleaseLock(&(privateData->MacPhyLock),keyCode,&dwIntFlags);
+ }
+ for (i=iNumMacRegs; i<iNumSysRegs; i++)
+ {
+ SMSC_TRACE("%16s (0x%02X) = 0x%08X",
+ sysCsr[i].szName,
+ sysCsr[i].dwOffset,
+ *((volatile u32 *)(privateData->dwLanBase+sysCsr[i].dwOffset)));
+ }
+}
+
+void Vl_InitLock(PVERIFIABLE_LOCK pVl)
+{
+ SMSC_ASSERT(pVl!=NULL);
+ spin_lock_init(&(pVl->Lock));
+ pVl->KeyCode=0;
+}
+
+bool Vl_CheckLock(PVERIFIABLE_LOCK pVl,VL_KEY keyCode)
+{
+ bool result=false;
+ SMSC_ASSERT(pVl!=NULL);
+ if(keyCode==pVl->KeyCode)
+ result=true;
+ return result;
+}
+
+VL_KEY Vl_WaitForLock(PVERIFIABLE_LOCK pVl,unsigned long *pdwIntFlags)
+{
+ VL_KEY result=0;
+ SMSC_ASSERT(pVl!=NULL);
+ spin_lock_irqsave(
+ &(pVl->Lock),
+ (*pdwIntFlags));
+ pVl->KeyCode++;
+ if(pVl->KeyCode>0x80000000UL) {
+ pVl->KeyCode=1;
+ }
+ result=pVl->KeyCode;
+ return result;
+}
+
+void Vl_ReleaseLock(PVERIFIABLE_LOCK pVl,VL_KEY keyCode,unsigned long *pdwIntFlags)
+{
+ SMSC_ASSERT(pVl!=NULL);
+ SMSC_ASSERT(pVl->KeyCode==keyCode);
+ spin_unlock_irqrestore(&(pVl->Lock),(*pdwIntFlags));
+}
+
+#ifndef USING_LINT
+module_init(Smsc9118_init_module);
+module_exit(Smsc9118_cleanup_module);
+#endif
--
1.5.4.3
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH 08/10] Alchemy: DB1300 blink leds on timer tick
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
` (5 preceding siblings ...)
2009-03-06 16:20 ` [PATCH 07/10] Alchemy: SMSC 9210 Ethernet support Kevin Hickey
@ 2009-03-06 16:20 ` Kevin Hickey
2009-03-07 9:37 ` Manuel Lauss
2009-03-06 16:20 ` [PATCH 09/10] Alchemy: Au1300: Add LCD framebuffer support Kevin Hickey
` (2 subsequent siblings)
9 siblings, 1 reply; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:20 UTC (permalink / raw)
To: ralf, linux-mips; +Cc: Kevin Hickey
Blinks the dots on the hex display on the DB1300 board every 1000 timer ticks.
This can help tell the difference between a soft and hard hung board.
Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
---
arch/mips/alchemy/common/time.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
index f58d4ff..2b2f6bf 100644
--- a/arch/mips/alchemy/common/time.c
+++ b/arch/mips/alchemy/common/time.c
@@ -39,6 +39,10 @@
#include <asm/time.h>
#include <asm/mach-au1x00/au1000.h>
+#ifdef CONFIG_MIPS_DB1300
+#include <dev_boards.h>
+#endif
+
/* 32kHz clock enabled and detected */
#define CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S)
@@ -60,6 +64,11 @@ static struct clocksource au1x_counter1_clocksource = {
static int au1x_rtcmatch2_set_next_event(unsigned long delta,
struct clock_event_device *cd)
{
+#ifdef CONFIG_MIPS_DB1300
+ static u8 dots = 1;
+ static u32 delayer = 0;
+#endif
+
delta += au_readl(SYS_RTCREAD);
/* wait for register access */
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M21)
@@ -67,6 +76,13 @@ static int au1x_rtcmatch2_set_next_event(unsigned long delta,
au_writel(delta, SYS_RTCMATCH2);
au_sync();
+#ifdef CONFIG_MIPS_DB1300
+ if (++delayer % 1000 == 0) {
+ db_set_hex_dots(dots++);
+ dots %= 4;
+ }
+#endif
+
return 0;
}
--
1.5.4.3
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH 09/10] Alchemy: Au1300: Add LCD framebuffer support
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
` (6 preceding siblings ...)
2009-03-06 16:20 ` [PATCH 08/10] Alchemy: DB1300 blink leds on timer tick Kevin Hickey
@ 2009-03-06 16:20 ` Kevin Hickey
2009-03-06 16:20 ` [PATCH 10/10] Alchemy: DB1300 defconfig Kevin Hickey
2009-03-09 13:40 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Ralf Baechle
9 siblings, 0 replies; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:20 UTC (permalink / raw)
To: ralf, linux-mips; +Cc: Kevin Hickey
Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
---
drivers/video/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index fb19803..9f571df 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1713,7 +1713,7 @@ config FB_AU1100
config FB_AU1200
bool "Au1200 LCD Driver"
- depends on (FB = y) && MIPS && SOC_AU1200
+ depends on (FB = y) && MIPS && (SOC_AU1200 || SOC_AU13XX)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
--
1.5.4.3
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH 10/10] Alchemy: DB1300 defconfig
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
` (7 preceding siblings ...)
2009-03-06 16:20 ` [PATCH 09/10] Alchemy: Au1300: Add LCD framebuffer support Kevin Hickey
@ 2009-03-06 16:20 ` Kevin Hickey
2009-03-09 13:40 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Ralf Baechle
9 siblings, 0 replies; 26+ messages in thread
From: Kevin Hickey @ 2009-03-06 16:20 UTC (permalink / raw)
To: ralf, linux-mips; +Cc: Kevin Hickey
This configuration enables and compiles in all currently supported features.
Anything not included in this configuration is either untested, unsupported or
known broken.
Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
---
arch/mips/configs/db1300_defconfig | 1216 ++++++++++++++++++++++++++++++++++++
1 files changed, 1216 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/configs/db1300_defconfig
diff --git a/arch/mips/configs/db1300_defconfig b/arch/mips/configs/db1300_defconfig
new file mode 100644
index 0000000..1861212
--- /dev/null
+++ b/arch/mips/configs/db1300_defconfig
@@ -0,0 +1,1216 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc7
+# Thu Mar 5 16:58:03 2009
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+CONFIG_MACH_ALCHEMY=y
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MACH_EMMA is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+CONFIG_MIPS_DB1300=y
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_XXS1500 is not set
+CONFIG_SOC_AU13XX=y
+CONFIG_SOC_AU1X00=y
+CONFIG_AU_GPIO_INT_CNTLR=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CSRC_R4K_LIB=y
+CONFIG_DMA_COHERENT=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R5500 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_CPU_CAVIUM_OCTEON is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_64BIT_PHYS_ADDR=y
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+CONFIG_HZ_1000=y
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=1000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_PCSPKR_PLATFORM=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+# CONFIG_FREEZER is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_PM is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_TCP_MD5SIG=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+# CONFIG_SCTP_HMAC_MD5 is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_IDE_GD is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_PROC_FS is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_BLK_DEV_PLATFORM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_TGT=m
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_MIPS_AU1X00_ENET is not set
+# CONFIG_SMC91X is not set
+CONFIG_SMSC9210=y
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=y
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+CONFIG_SERIAL_8250_AU1X00=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_AU1200=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_AU1X=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+CONFIG_JFS_FS=y
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=y
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+
+#
+# Tracers
+#
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_CMDLINE=""
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_RUNTIME_DEBUG is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+CONFIG_CRYPTO_XCBC=m
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
--
1.5.4.3
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH 07/10] Alchemy: SMSC 9210 Ethernet support
2009-03-06 16:20 ` [PATCH 07/10] Alchemy: SMSC 9210 Ethernet support Kevin Hickey
@ 2009-03-07 9:35 ` Manuel Lauss
2009-03-07 9:35 ` Manuel Lauss
2009-03-07 19:06 ` Kevin Hickey
0 siblings, 2 replies; 26+ messages in thread
From: Manuel Lauss @ 2009-03-07 9:35 UTC (permalink / raw)
To: Kevin Hickey; +Cc: ralf, linux-mips, Kevin Hickey
On Fri, 6 Mar 2009 10:20:06 -0600
Kevin Hickey <khickey@rmicorp.com> wrote:
> This patch adds support for the SMSC 9210 Ethernet chip, specialized for
> Alchemy platforms (including the DB1300). The ethernet driver code was
> provided by SMSC; the platform shim by RMI.
>
> Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
> ---
> drivers/net/Kconfig | 6 +
> drivers/net/Makefile | 3 +
> drivers/net/smsc9210/Makefile | 9 +
> drivers/net/smsc9210/ioctl_118.h | 298 ++
> drivers/net/smsc9210/platform_alchemy.c | 88 +
> drivers/net/smsc9210/platform_alchemy.h | 117 +
> drivers/net/smsc9210/smsc9210.h | 23 +
> drivers/net/smsc9210/smsc9210_main.c | 7189 +++++++++++++++++++++++++++++++
What's wrong with the in-kernel smsc911x.c driver? It can handle the
9210 just fine (we use it on an ARM board).
Best regards,
Manuel Lauss
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 07/10] Alchemy: SMSC 9210 Ethernet support
2009-03-07 9:35 ` Manuel Lauss
@ 2009-03-07 9:35 ` Manuel Lauss
2009-03-07 19:06 ` Kevin Hickey
1 sibling, 0 replies; 26+ messages in thread
From: Manuel Lauss @ 2009-03-07 9:35 UTC (permalink / raw)
To: Kevin Hickey; +Cc: ralf, linux-mips
On Fri, 6 Mar 2009 10:20:06 -0600
Kevin Hickey <khickey@rmicorp.com> wrote:
> This patch adds support for the SMSC 9210 Ethernet chip, specialized for
> Alchemy platforms (including the DB1300). The ethernet driver code was
> provided by SMSC; the platform shim by RMI.
>
> Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
> ---
> drivers/net/Kconfig | 6 +
> drivers/net/Makefile | 3 +
> drivers/net/smsc9210/Makefile | 9 +
> drivers/net/smsc9210/ioctl_118.h | 298 ++
> drivers/net/smsc9210/platform_alchemy.c | 88 +
> drivers/net/smsc9210/platform_alchemy.h | 117 +
> drivers/net/smsc9210/smsc9210.h | 23 +
> drivers/net/smsc9210/smsc9210_main.c | 7189 +++++++++++++++++++++++++++++++
What's wrong with the in-kernel smsc911x.c driver? It can handle the
9210 just fine (we use it on an ARM board).
Best regards,
Manuel Lauss
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 08/10] Alchemy: DB1300 blink leds on timer tick
2009-03-06 16:20 ` [PATCH 08/10] Alchemy: DB1300 blink leds on timer tick Kevin Hickey
@ 2009-03-07 9:37 ` Manuel Lauss
2009-03-07 9:37 ` Manuel Lauss
2009-03-07 19:04 ` Kevin Hickey
0 siblings, 2 replies; 26+ messages in thread
From: Manuel Lauss @ 2009-03-07 9:37 UTC (permalink / raw)
To: Kevin Hickey; +Cc: ralf, linux-mips, Kevin Hickey
On Fri, 6 Mar 2009 10:20:07 -0600
Kevin Hickey <khickey@rmicorp.com> wrote:
> Blinks the dots on the hex display on the DB1300 board every 1000 timer ticks.
> This can help tell the difference between a soft and hard hung board.
>
> Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
> ---
> arch/mips/alchemy/common/time.c | 16 ++++++++++++++++
> 1 files changed, 16 insertions(+), 0 deletions(-)
>
> diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
> index f58d4ff..2b2f6bf 100644
> --- a/arch/mips/alchemy/common/time.c
> +++ b/arch/mips/alchemy/common/time.c
> @@ -39,6 +39,10 @@
> #include <asm/time.h>
> #include <asm/mach-au1x00/au1000.h>
>
> +#ifdef CONFIG_MIPS_DB1300
> +#include <dev_boards.h>
> +#endif
> +
> /* 32kHz clock enabled and detected */
> #define CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S)
>
> @@ -60,6 +64,11 @@ static struct clocksource au1x_counter1_clocksource = {
> static int au1x_rtcmatch2_set_next_event(unsigned long delta,
> struct clock_event_device *cd)
> {
> +#ifdef CONFIG_MIPS_DB1300
> + static u8 dots = 1;
> + static u32 delayer = 0;
> +#endif
> +
> delta += au_readl(SYS_RTCREAD);
> /* wait for register access */
> while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M21)
> @@ -67,6 +76,13 @@ static int au1x_rtcmatch2_set_next_event(unsigned long delta,
> au_writel(delta, SYS_RTCMATCH2);
> au_sync();
>
> +#ifdef CONFIG_MIPS_DB1300
> + if (++delayer % 1000 == 0) {
> + db_set_hex_dots(dots++);
> + dots %= 4;
> + }
> +#endif
> +
> return 0;
> }
>
Please don't do that. I'd still like to get all devboard hackery out
of code in common/ (at least for mainline kernels; what you do to the
RMI-sources I don't care about).
(btw, I made something similar for the DB1200 a while ago:
http://mlau.at/files/au1xxx-updates/4040-Alchemy-DB1200-cpu-idle-counter.patch
)
Best regards,
Manuel Lauss
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 08/10] Alchemy: DB1300 blink leds on timer tick
2009-03-07 9:37 ` Manuel Lauss
@ 2009-03-07 9:37 ` Manuel Lauss
2009-03-07 19:04 ` Kevin Hickey
1 sibling, 0 replies; 26+ messages in thread
From: Manuel Lauss @ 2009-03-07 9:37 UTC (permalink / raw)
To: Kevin Hickey; +Cc: ralf, linux-mips
On Fri, 6 Mar 2009 10:20:07 -0600
Kevin Hickey <khickey@rmicorp.com> wrote:
> Blinks the dots on the hex display on the DB1300 board every 1000 timer ticks.
> This can help tell the difference between a soft and hard hung board.
>
> Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
> ---
> arch/mips/alchemy/common/time.c | 16 ++++++++++++++++
> 1 files changed, 16 insertions(+), 0 deletions(-)
>
> diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
> index f58d4ff..2b2f6bf 100644
> --- a/arch/mips/alchemy/common/time.c
> +++ b/arch/mips/alchemy/common/time.c
> @@ -39,6 +39,10 @@
> #include <asm/time.h>
> #include <asm/mach-au1x00/au1000.h>
>
> +#ifdef CONFIG_MIPS_DB1300
> +#include <dev_boards.h>
> +#endif
> +
> /* 32kHz clock enabled and detected */
> #define CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S)
>
> @@ -60,6 +64,11 @@ static struct clocksource au1x_counter1_clocksource = {
> static int au1x_rtcmatch2_set_next_event(unsigned long delta,
> struct clock_event_device *cd)
> {
> +#ifdef CONFIG_MIPS_DB1300
> + static u8 dots = 1;
> + static u32 delayer = 0;
> +#endif
> +
> delta += au_readl(SYS_RTCREAD);
> /* wait for register access */
> while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M21)
> @@ -67,6 +76,13 @@ static int au1x_rtcmatch2_set_next_event(unsigned long delta,
> au_writel(delta, SYS_RTCMATCH2);
> au_sync();
>
> +#ifdef CONFIG_MIPS_DB1300
> + if (++delayer % 1000 == 0) {
> + db_set_hex_dots(dots++);
> + dots %= 4;
> + }
> +#endif
> +
> return 0;
> }
>
Please don't do that. I'd still like to get all devboard hackery out
of code in common/ (at least for mainline kernels; what you do to the
RMI-sources I don't care about).
(btw, I made something similar for the DB1200 a while ago:
http://mlau.at/files/au1xxx-updates/4040-Alchemy-DB1200-cpu-idle-counter.patch
)
Best regards,
Manuel Lauss
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 02/10] Alchemy: Au1300 new interrupt controller
2009-03-06 16:20 ` [PATCH 02/10] Alchemy: Au1300 new interrupt controller Kevin Hickey
@ 2009-03-07 9:49 ` Manuel Lauss
2009-03-07 9:49 ` Manuel Lauss
2009-03-07 19:20 ` Kevin Hickey
0 siblings, 2 replies; 26+ messages in thread
From: Manuel Lauss @ 2009-03-07 9:49 UTC (permalink / raw)
To: Kevin Hickey; +Cc: ralf, linux-mips, Kevin Hickey
On Fri, 6 Mar 2009 10:20:01 -0600
Kevin Hickey <khickey@rmicorp.com> wrote:
> The Au1300 has a new interrupt controller (relative to the rest of the Alchemy
> line). The differences were great enough to justify adding a whole new module.
> Included in this patch is the new interrupt controller, a new implementation of
> the cascade interrupt controller on the DB1300 board and some code to drive
> LEDs on the DB1300 that is used by the interrupt controller.
>
> A small change was made to the existing interrupt controller; it is "ifdef'd
> out" for Au1300.
>
> Since the cascade interrupt controller is virtually indentical (with the
> exception of some constants) between the DB1300 and DB1200, a future
> optimization may be to use the same code for both boards.
> diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
> index d50d476..85ffa2e 100644
> --- a/arch/mips/alchemy/common/Makefile
> +++ b/arch/mips/alchemy/common/Makefile
> @@ -7,7 +7,9 @@
>
> obj-y += prom.o irq.o puts.o time.o reset.o \
> clocks.o platform.o power.o setup.o \
> - sleeper.o dma.o dbdma.o gpio.o
> + sleeper.o dma.o dbdma.o gpio.o gpio_int.o
> +
> +obj-$(CONFIG_SOC_AU13XX) += au13xx_res.o
belongs to another patch in the series?
> diff --git a/arch/mips/alchemy/common/gpio_int.c b/arch/mips/alchemy/common/gpio_int.c
> new file mode 100644
> index 0000000..c09b793
> --- /dev/null
> +++ b/arch/mips/alchemy/common/gpio_int.c
> @@ -0,0 +1,268 @@
> +/*
> + * Copyright 2008 RMI Corporation
> + * Author: Kevin Hickey <khickey@rmicorp.com>
> + *
> + * 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.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifdef CONFIG_AU_GPIO_INT_CNTLR
> +
> +#include <linux/irq.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h> /* For functions called by do_IRQ */
> +#include <asm/irq_cpu.h>
> +
> +#include <asm/mach-au1x00/gpio_int.h>
> +#include <asm/mach-au1x00/au1000.h>
> +
> +#include <dev_boards.h>
Please try to keep common/ free of anything not related to the chip
itself.
> +asmlinkage void plat_irq_dispatch(void)
> +{
> + unsigned int intr;
> + u32 bank;
> + u32 reg_msk;
> + unsigned int pending = read_c0_status() & read_c0_cause();
> + /*
> + * C0 timer tick
> + */
> + if (pending & CAUSEF_IP7)
> + do_IRQ(MIPS_CPU_IRQ_BASE + 7);
> + else if (pending & (CAUSEF_IP2 | CAUSEF_IP3)) {
> + intr = au_ioread32(&gpio_int->pri_enc);
> + bank = GPINT_BANK_FROM_INT(intr);
> + reg_msk = GPINT_BIT_FROM_INT(bank, intr);
> +
> + if (intr != 127) {
> + if (pending & CAUSEF_IP3)
> + board_irq_dispatch(intr);
What is this supposed to do? (missed debug code?)
> +
> + do_IRQ(GPINT_LINUX_IRQ_OFFSET + intr);
> + }
> + } else {
> + printk(KERN_WARNING
> + "ALCHEMY GPIO_INT: Unexpected cause was set. %08x\n",
> + pending);
> + }
should probably call spurious_interrupt() here.
> +
> +}
> +
> +#endif
> diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
> index c88c821..f8742dd 100644
> --- a/arch/mips/alchemy/common/irq.c
> +++ b/arch/mips/alchemy/common/irq.c
> @@ -24,6 +24,7 @@
> * with this program; if not, write to the Free Software Foundation, Inc.,
> * 675 Mass Ave, Cambridge, MA 02139, USA.
> */
> +#ifdef CONFIG_AU_INT_CNTLR
>
> #include <linux/bitops.h>
> #include <linux/init.h>
> @@ -609,3 +610,5 @@ void __init arch_init_irq(void)
>
> set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
> }
> +
> +#endif
Why not make compilation of the original irq.c file dependent on
AU_INT_CNTRL? (i.e. change the Makefile to
obj-$(CONFIG_AU_INT_CNTRL) += irq.o
for non-au1300 parts).
(FWIW, I'm working on getting rid of the explicit CPU-type config
options and instead do runtime detection and configuration of
dma/dbdma/irq/ and so on).
Best regards,
Manuel Lauss
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 02/10] Alchemy: Au1300 new interrupt controller
2009-03-07 9:49 ` Manuel Lauss
@ 2009-03-07 9:49 ` Manuel Lauss
2009-03-07 19:20 ` Kevin Hickey
1 sibling, 0 replies; 26+ messages in thread
From: Manuel Lauss @ 2009-03-07 9:49 UTC (permalink / raw)
To: Kevin Hickey; +Cc: ralf, linux-mips
On Fri, 6 Mar 2009 10:20:01 -0600
Kevin Hickey <khickey@rmicorp.com> wrote:
> The Au1300 has a new interrupt controller (relative to the rest of the Alchemy
> line). The differences were great enough to justify adding a whole new module.
> Included in this patch is the new interrupt controller, a new implementation of
> the cascade interrupt controller on the DB1300 board and some code to drive
> LEDs on the DB1300 that is used by the interrupt controller.
>
> A small change was made to the existing interrupt controller; it is "ifdef'd
> out" for Au1300.
>
> Since the cascade interrupt controller is virtually indentical (with the
> exception of some constants) between the DB1300 and DB1200, a future
> optimization may be to use the same code for both boards.
> diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
> index d50d476..85ffa2e 100644
> --- a/arch/mips/alchemy/common/Makefile
> +++ b/arch/mips/alchemy/common/Makefile
> @@ -7,7 +7,9 @@
>
> obj-y += prom.o irq.o puts.o time.o reset.o \
> clocks.o platform.o power.o setup.o \
> - sleeper.o dma.o dbdma.o gpio.o
> + sleeper.o dma.o dbdma.o gpio.o gpio_int.o
> +
> +obj-$(CONFIG_SOC_AU13XX) += au13xx_res.o
belongs to another patch in the series?
> diff --git a/arch/mips/alchemy/common/gpio_int.c b/arch/mips/alchemy/common/gpio_int.c
> new file mode 100644
> index 0000000..c09b793
> --- /dev/null
> +++ b/arch/mips/alchemy/common/gpio_int.c
> @@ -0,0 +1,268 @@
> +/*
> + * Copyright 2008 RMI Corporation
> + * Author: Kevin Hickey <khickey@rmicorp.com>
> + *
> + * 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.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifdef CONFIG_AU_GPIO_INT_CNTLR
> +
> +#include <linux/irq.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h> /* For functions called by do_IRQ */
> +#include <asm/irq_cpu.h>
> +
> +#include <asm/mach-au1x00/gpio_int.h>
> +#include <asm/mach-au1x00/au1000.h>
> +
> +#include <dev_boards.h>
Please try to keep common/ free of anything not related to the chip
itself.
> +asmlinkage void plat_irq_dispatch(void)
> +{
> + unsigned int intr;
> + u32 bank;
> + u32 reg_msk;
> + unsigned int pending = read_c0_status() & read_c0_cause();
> + /*
> + * C0 timer tick
> + */
> + if (pending & CAUSEF_IP7)
> + do_IRQ(MIPS_CPU_IRQ_BASE + 7);
> + else if (pending & (CAUSEF_IP2 | CAUSEF_IP3)) {
> + intr = au_ioread32(&gpio_int->pri_enc);
> + bank = GPINT_BANK_FROM_INT(intr);
> + reg_msk = GPINT_BIT_FROM_INT(bank, intr);
> +
> + if (intr != 127) {
> + if (pending & CAUSEF_IP3)
> + board_irq_dispatch(intr);
What is this supposed to do? (missed debug code?)
> +
> + do_IRQ(GPINT_LINUX_IRQ_OFFSET + intr);
> + }
> + } else {
> + printk(KERN_WARNING
> + "ALCHEMY GPIO_INT: Unexpected cause was set. %08x\n",
> + pending);
> + }
should probably call spurious_interrupt() here.
> +
> +}
> +
> +#endif
> diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
> index c88c821..f8742dd 100644
> --- a/arch/mips/alchemy/common/irq.c
> +++ b/arch/mips/alchemy/common/irq.c
> @@ -24,6 +24,7 @@
> * with this program; if not, write to the Free Software Foundation, Inc.,
> * 675 Mass Ave, Cambridge, MA 02139, USA.
> */
> +#ifdef CONFIG_AU_INT_CNTLR
>
> #include <linux/bitops.h>
> #include <linux/init.h>
> @@ -609,3 +610,5 @@ void __init arch_init_irq(void)
>
> set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
> }
> +
> +#endif
Why not make compilation of the original irq.c file dependent on
AU_INT_CNTRL? (i.e. change the Makefile to
obj-$(CONFIG_AU_INT_CNTRL) += irq.o
for non-au1300 parts).
(FWIW, I'm working on getting rid of the explicit CPU-type config
options and instead do runtime detection and configuration of
dma/dbdma/irq/ and so on).
Best regards,
Manuel Lauss
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 06/10] Alchemy: Au1300 USB support
2009-03-06 16:20 ` [PATCH 06/10] Alchemy: Au1300 USB support Kevin Hickey
@ 2009-03-07 10:01 ` Sergei Shtylyov
2009-03-07 19:11 ` Kevin Hickey
0 siblings, 1 reply; 26+ messages in thread
From: Sergei Shtylyov @ 2009-03-07 10:01 UTC (permalink / raw)
To: Kevin Hickey; +Cc: ralf, linux-mips
Hello.
Kevin Hickey wrote:
> Adds support for USB 2.0 on the Au1300 SOC.
>
> Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
>
[...]
> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
> index 83babb0..a50d053 100644
> --- a/drivers/usb/Kconfig
> +++ b/drivers/usb/Kconfig
> @@ -55,6 +55,7 @@ config USB_ARCH_HAS_EHCI
> boolean
> default y if PPC_83xx
> default y if SOC_AU1200
> + default y if SOC_AU13XX
>
Why not:
default y if SOC_AU1200 || SOC_AU13XX
> diff --git a/drivers/usb/host/ehci-au13xx.c b/drivers/usb/host/ehci-au13xx.c
> new file mode 100644
> index 0000000..fe03667
> --- /dev/null
> +++ b/drivers/usb/host/ehci-au13xx.c
> @@ -0,0 +1,213 @@
> +/*
> + * Copyright 2008 RMI Corporation
> + * Author: Kevin Hickey <khickey@rmicorp.com>
> + *
> + * 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.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + * Based on ehci-au1xxx.c.
> + */
> +
> +#include <linux/platform_device.h>
> +#include <asm/mach-au1x00/au1000.h>
> +
> +
> +extern int usb_disabled(void);
> +
> +static void au13xx_start_ehc(void)
> +{
> + AU13XX_USB* au13xx_usb = (AU13XX_USB*)(KSEG1 | USB_BASE_PHYS_ADDR);
>
Your coding style is not acceptable -- run your patched thru
scruipts/checkpatch.pl please.
> + /*
> + * Enable clocks.
> + */
> + AU_SET_BITS_32(USB_DWC_CTRL3_EHC_CLKEN, &au13xx_usb->dwc_ctrl3);
> +
> + /*
> + * Take the host controller block out of reset
> + */
> + AU_SET_BITS_32(USB_DWC_CTRL1_HSTRS, &au13xx_usb->dwc_ctrl1);
> +
> + /*
> + * Enable all of the PHYs
> + */
> + AU_SET_BITS_32(USB_DWC_CTRL2_PHYRS | USB_DWC_CTRL2_PHY0RS | USB_DWC_CTRL2_PH1RS,
> + &au13xx_usb->dwc_ctrl2);
> +
> + /*
> + * Enable interrupts
> + */
> + AU_SET_BITS_32(USB_INTR_EHCI, &au13xx_usb->intr_enable);
> +
> + /*
> + * This bit enables coherent DMA.
> + */
> + AU_SET_BITS_32(USB_SBUS_CTRL_SBCA, &au13xx_usb->sbus_ctrl);
> + asm("sync");
>
Don't we have au_sync()?
> +static int ehci_hcd_au13xx_drv_probe(struct platform_device *pdev)
> +{
>
[...]
> + au13xx_start_ehc();
> +
> + ehci = hcd_to_ehci(hcd);
> + ehci->caps = hcd->regs;
> + ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
> + printk("ehci->regs = %p\n", ehci->regs);
>
printk() should have KERN_* facility.
> +static struct platform_driver ehci_hcd_au13xx_driver = {
> + .probe = ehci_hcd_au13xx_drv_probe,
> + .remove = ehci_hcd_au13xx_drv_remove,
> + .shutdown = usb_hcd_platform_shutdown,
> + .suspend = NULL,
> + .resume = NULL,
>
No dire need to explicitly initializer these two...
WBR, Sergei
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 08/10] Alchemy: DB1300 blink leds on timer tick
2009-03-07 9:37 ` Manuel Lauss
2009-03-07 9:37 ` Manuel Lauss
@ 2009-03-07 19:04 ` Kevin Hickey
2009-03-08 8:37 ` Manuel Lauss
1 sibling, 1 reply; 26+ messages in thread
From: Kevin Hickey @ 2009-03-07 19:04 UTC (permalink / raw)
To: Manuel Lauss; +Cc: ralf, linux-mips
On Sat, 2009-03-07 at 10:37 +0100, Manuel Lauss wrote:
> On Fri, 6 Mar 2009 10:20:07 -0600
> Kevin Hickey <khickey@rmicorp.com> wrote:
>
> > Blinks the dots on the hex display on the DB1300 board every 1000 timer ticks.
> > This can help tell the difference between a soft and hard hung board.
> Please don't do that. I'd still like to get all devboard hackery out
> of code in common/ (at least for mainline kernels; what you do to the
> RMI-sources I don't care about).
Can you suggest an alternative? Or are you saying that this
functionality does not belong in the mainline kernel at all?
--
Kevin Hickey
Alchemy Solutions
RMI Corporation
khickey@rmicorp.com
P: 512.691.8044
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 07/10] Alchemy: SMSC 9210 Ethernet support
2009-03-07 9:35 ` Manuel Lauss
2009-03-07 9:35 ` Manuel Lauss
@ 2009-03-07 19:06 ` Kevin Hickey
1 sibling, 0 replies; 26+ messages in thread
From: Kevin Hickey @ 2009-03-07 19:06 UTC (permalink / raw)
To: Manuel Lauss; +Cc: ralf, linux-mips
On Sat, 2009-03-07 at 10:35 +0100, Manuel Lauss wrote:
> On Fri, 6 Mar 2009 10:20:06 -0600
> Kevin Hickey <khickey@rmicorp.com> wrote:
>
> > This patch adds support for the SMSC 9210 Ethernet chip, specialized for
> > Alchemy platforms (including the DB1300). The ethernet driver code was
> > provided by SMSC; the platform shim by RMI.
> What's wrong with the in-kernel smsc911x.c driver? It can handle the
> 9210 just fine (we use it on an ARM board).
I was unaware that smsc911x.c could handle 9210. I'll try it out
sometime and if it works then we can drop this one.
=Kevin
--
Kevin Hickey
Alchemy Solutions
RMI Corporation
khickey@rmicorp.com
P: 512.691.8044
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 06/10] Alchemy: Au1300 USB support
2009-03-07 10:01 ` Sergei Shtylyov
@ 2009-03-07 19:11 ` Kevin Hickey
0 siblings, 0 replies; 26+ messages in thread
From: Kevin Hickey @ 2009-03-07 19:11 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: ralf, linux-mips
On Sat, 2009-03-07 at 13:01 +0300, Sergei Shtylyov wrote:
> Hello.
>
> Kevin Hickey wrote:
>
> > Adds support for USB 2.0 on the Au1300 SOC.
> >
> > Signed-off-by: Kevin Hickey <khickey@rmicorp.com>
> >
> [...]
> > diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
> > index 83babb0..a50d053 100644
> > --- a/drivers/usb/Kconfig
> > +++ b/drivers/usb/Kconfig
> > @@ -55,6 +55,7 @@ config USB_ARCH_HAS_EHCI
> > boolean
> > default y if PPC_83xx
> > default y if SOC_AU1200
> > + default y if SOC_AU13XX
> >
>
> Why not:
>
> default y if SOC_AU1200 || SOC_AU13XX
>
I was just following the pattern... there were already two other
explicit "default y if" lines.
>
> > diff --git a/drivers/usb/host/ehci-au13xx.c b/drivers/usb/host/ehci-au13xx.c
> > new file mode 100644
> > index 0000000..fe03667
> > --- /dev/null
> > +++ b/drivers/usb/host/ehci-au13xx.c
> > @@ -0,0 +1,213 @@
> > +/*
> > + * Copyright 2008 RMI Corporation
> > + * Author: Kevin Hickey <khickey@rmicorp.com>
> > + *
> > + * 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.
> > + *
> > + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> > + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> > + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> > + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> > + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> > + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> > + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> > + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> > + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> > + *
> > + * You should have received a copy of the GNU General Public License along
> > + * with this program; if not, write to the Free Software Foundation, Inc.,
> > + * 675 Mass Ave, Cambridge, MA 02139, USA.
> > + *
> > + * Based on ehci-au1xxx.c.
> > + */
> > +
> > +#include <linux/platform_device.h>
> > +#include <asm/mach-au1x00/au1000.h>
> > +
> > +
> > +extern int usb_disabled(void);
> > +
> > +static void au13xx_start_ehc(void)
> > +{
> > + AU13XX_USB* au13xx_usb = (AU13XX_USB*)(KSEG1 | USB_BASE_PHYS_ADDR);
> >
>
> Your coding style is not acceptable -- run your patched thru
> scruipts/checkpatch.pl please.
Sorry about that.
>
> > + /*
> > + * Enable clocks.
> > + */
> > + AU_SET_BITS_32(USB_DWC_CTRL3_EHC_CLKEN, &au13xx_usb->dwc_ctrl3);
> > +
> > + /*
> > + * Take the host controller block out of reset
> > + */
> > + AU_SET_BITS_32(USB_DWC_CTRL1_HSTRS, &au13xx_usb->dwc_ctrl1);
> > +
> > + /*
> > + * Enable all of the PHYs
> > + */
> > + AU_SET_BITS_32(USB_DWC_CTRL2_PHYRS | USB_DWC_CTRL2_PHY0RS | USB_DWC_CTRL2_PH1RS,
> > + &au13xx_usb->dwc_ctrl2);
> > +
> > + /*
> > + * Enable interrupts
> > + */
> > + AU_SET_BITS_32(USB_INTR_EHCI, &au13xx_usb->intr_enable);
> > +
> > + /*
> > + * This bit enables coherent DMA.
> > + */
> > + AU_SET_BITS_32(USB_SBUS_CTRL_SBCA, &au13xx_usb->sbus_ctrl);
> > + asm("sync");
> >
>
> Don't we have au_sync()?
Yes, and I should have used it here :)
>
> > +static int ehci_hcd_au13xx_drv_probe(struct platform_device *pdev)
> > +{
> >
> [...]
> > + au13xx_start_ehc();
> > +
> > + ehci = hcd_to_ehci(hcd);
> > + ehci->caps = hcd->regs;
> > + ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
> > + printk("ehci->regs = %p\n", ehci->regs);
> >
>
> printk() should have KERN_* facility.
Agreed. In fact this is probably just leftover bringup/debug code that
should be eliminated.
>
> > +static struct platform_driver ehci_hcd_au13xx_driver = {
> > + .probe = ehci_hcd_au13xx_drv_probe,
> > + .remove = ehci_hcd_au13xx_drv_remove,
> > + .shutdown = usb_hcd_platform_shutdown,
> > + .suspend = NULL,
> > + .resume = NULL,
> >
>
> No dire need to explicitly initializer these two...
Copy-paste laziness strikes again...
>
> WBR, Sergei
>
>
--
Kevin Hickey
Alchemy Solutions
RMI Corporation
khickey@rmicorp.com
P: 512.691.8044
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 02/10] Alchemy: Au1300 new interrupt controller
2009-03-07 9:49 ` Manuel Lauss
2009-03-07 9:49 ` Manuel Lauss
@ 2009-03-07 19:20 ` Kevin Hickey
2009-03-08 8:49 ` Manuel Lauss
1 sibling, 1 reply; 26+ messages in thread
From: Kevin Hickey @ 2009-03-07 19:20 UTC (permalink / raw)
To: Manuel Lauss; +Cc: ralf, linux-mips
On Sat, 2009-03-07 at 10:49 +0100, Manuel Lauss wrote:
> On Fri, 6 Mar 2009 10:20:01 -0600
> Kevin Hickey <khickey@rmicorp.com> wrote:
>
> > The Au1300 has a new interrupt controller (relative to the rest of the Alchemy
> > line). The differences were great enough to justify adding a whole new module.
> > Included in this patch is the new interrupt controller, a new implementation of
> > the cascade interrupt controller on the DB1300 board and some code to drive
> > LEDs on the DB1300 that is used by the interrupt controller.
> >
> > A small change was made to the existing interrupt controller; it is "ifdef'd
> > out" for Au1300.
> >
> > Since the cascade interrupt controller is virtually indentical (with the
> > exception of some constants) between the DB1300 and DB1200, a future
> > optimization may be to use the same code for both boards.
>
> > diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
> > index d50d476..85ffa2e 100644
> > --- a/arch/mips/alchemy/common/Makefile
> > +++ b/arch/mips/alchemy/common/Makefile
> > @@ -7,7 +7,9 @@
> >
> > obj-y += prom.o irq.o puts.o time.o reset.o \
> > clocks.o platform.o power.o setup.o \
> > - sleeper.o dma.o dbdma.o gpio.o
> > + sleeper.o dma.o dbdma.o gpio.o gpio_int.o
> > +
> > +obj-$(CONFIG_SOC_AU13XX) += au13xx_res.o
>
> belongs to another patch in the series?
Yes, but git-add wouldn't let me split the hunk so I just left it...
figured the series would be taken as a whole anyway.
>
>
> > diff --git a/arch/mips/alchemy/common/gpio_int.c b/arch/mips/alchemy/common/gpio_int.c
> > new file mode 100644
> > index 0000000..c09b793
> > --- /dev/null
> > +++ b/arch/mips/alchemy/common/gpio_int.c
> > @@ -0,0 +1,268 @@
> > +/*
> > + * Copyright 2008 RMI Corporation
> > + * Author: Kevin Hickey <khickey@rmicorp.com>
> > + *
> > + * 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.
> > + *
> > + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> > + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> > + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> > + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> > + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> > + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> > + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> > + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> > + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> > + *
> > + * You should have received a copy of the GNU General Public License along
> > + * with this program; if not, write to the Free Software Foundation, Inc.,
> > + * 675 Mass Ave, Cambridge, MA 02139, USA.
> > + */
> > +
> > +#ifdef CONFIG_AU_GPIO_INT_CNTLR
> > +
> > +#include <linux/irq.h>
> > +#include <linux/init.h>
> > +#include <linux/interrupt.h> /* For functions called by do_IRQ */
> > +#include <asm/irq_cpu.h>
> > +
> > +#include <asm/mach-au1x00/gpio_int.h>
> > +#include <asm/mach-au1x00/au1000.h>
> > +
> > +#include <dev_boards.h>
>
> Please try to keep common/ free of anything not related to the chip
> itself.
>
I have board_irq_dispatch() in there. I should move that to some other
non-dev-board specific include.
>
>
> > +asmlinkage void plat_irq_dispatch(void)
> > +{
> > + unsigned int intr;
> > + u32 bank;
> > + u32 reg_msk;
> > + unsigned int pending = read_c0_status() & read_c0_cause();
> > + /*
> > + * C0 timer tick
> > + */
> > + if (pending & CAUSEF_IP7)
> > + do_IRQ(MIPS_CPU_IRQ_BASE + 7);
> > + else if (pending & (CAUSEF_IP2 | CAUSEF_IP3)) {
> > + intr = au_ioread32(&gpio_int->pri_enc);
> > + bank = GPINT_BANK_FROM_INT(intr);
> > + reg_msk = GPINT_BIT_FROM_INT(bank, intr);
> > +
> > + if (intr != 127) {
> > + if (pending & CAUSEF_IP3)
> > + board_irq_dispatch(intr);
>
> What is this supposed to do? (missed debug code?)
board_irq_dispatch (which as I said above should be in a non-devboard
include) is used to display the IRQ number on the hex LEDs on the DB1300
board. I tried to keep it generic so that other boards could do what
they want or leave it unimplemented and have it optimized out. The
CAUSEF_IP3 part is there to not display the timer tick (since it pretty
much floods out the other IRQ displays). I should really do that
segregation in the board_irq_dispatch call; I was pretty focused on my
board when I wrote this code.
>
> > +
> > + do_IRQ(GPINT_LINUX_IRQ_OFFSET + intr);
> > + }
> > + } else {
> > + printk(KERN_WARNING
> > + "ALCHEMY GPIO_INT: Unexpected cause was set. %08x\n",
> > + pending);
> > + }
>
> should probably call spurious_interrupt() here.
Agreed.
>
>
> > +
> > +}
> > +
> > +#endif
> > diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
> > index c88c821..f8742dd 100644
> > --- a/arch/mips/alchemy/common/irq.c
> > +++ b/arch/mips/alchemy/common/irq.c
> > @@ -24,6 +24,7 @@
> > * with this program; if not, write to the Free Software Foundation, Inc.,
> > * 675 Mass Ave, Cambridge, MA 02139, USA.
> > */
> > +#ifdef CONFIG_AU_INT_CNTLR
> >
> > #include <linux/bitops.h>
> > #include <linux/init.h>
> > @@ -609,3 +610,5 @@ void __init arch_init_irq(void)
> >
> > set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
> > }
> > +
> > +#endif
>
> Why not make compilation of the original irq.c file dependent on
> AU_INT_CNTRL? (i.e. change the Makefile to
> obj-$(CONFIG_AU_INT_CNTRL) += irq.o
> for non-au1300 parts).
Good idea. I'm still getting used to some of the build system options
so they're not always instinct.
>
> (FWIW, I'm working on getting rid of the explicit CPU-type config
> options and instead do runtime detection and configuration of
> dma/dbdma/irq/ and so on).
Why? Won't that just lead to a larger kernel binary since it will have
all of the tables in it? I would prefer to only compile in the data
that I need. Unless I'm missing what you're doing...
>
>
> Best regards,
> Manuel Lauss
--
Kevin Hickey
Alchemy Solutions
RMI Corporation
khickey@rmicorp.com
P: 512.691.8044
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 08/10] Alchemy: DB1300 blink leds on timer tick
2009-03-07 19:04 ` Kevin Hickey
@ 2009-03-08 8:37 ` Manuel Lauss
2009-03-08 8:54 ` Manuel Lauss
0 siblings, 1 reply; 26+ messages in thread
From: Manuel Lauss @ 2009-03-08 8:37 UTC (permalink / raw)
To: Kevin Hickey; +Cc: ralf, linux-mips
On Sat, 07 Mar 2009 13:04:57 -0600
Kevin Hickey <khickey@rmicorp.com> wrote:
> On Sat, 2009-03-07 at 10:37 +0100, Manuel Lauss wrote:
> > On Fri, 6 Mar 2009 10:20:07 -0600
> > Kevin Hickey <khickey@rmicorp.com> wrote:
> >
> > > Blinks the dots on the hex display on the DB1300 board every 1000 timer ticks.
> > > This can help tell the difference between a soft and hard hung board.
>
> > Please don't do that. I'd still like to get all devboard hackery out
> > of code in common/ (at least for mainline kernels; what you do to the
> > RMI-sources I don't care about).
>
> Can you suggest an alternative? Or are you saying that this
> functionality does not belong in the mainline kernel at all?
>
How about this? No ifdefery, and every board can implement its own
board_timer_set callback to blink some leds. (Note, I still don't feel
this is "right", but ultimately it's not up you anyway).
diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
index f58d4ff..ac448c2 100644
--- a/arch/mips/alchemy/common/time.c
+++ b/arch/mips/alchemy/common/time.c
@@ -44,6 +44,8 @@
extern int allow_au1k_wait; /* default off for CP0 Counter */
+void (*board_timer_set)(void) = NULL;
+
static cycle_t au1x_counter1_read(void)
{
return au_readl(SYS_RTCREAD);
@@ -67,6 +69,9 @@ static int au1x_rtcmatch2_set_next_event(unsigned long delta,
au_writel(delta, SYS_RTCMATCH2);
au_sync();
+ if (board_timer_set)
+ board_timer_set();
+
return 0;
}
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH 02/10] Alchemy: Au1300 new interrupt controller
2009-03-07 19:20 ` Kevin Hickey
@ 2009-03-08 8:49 ` Manuel Lauss
0 siblings, 0 replies; 26+ messages in thread
From: Manuel Lauss @ 2009-03-08 8:49 UTC (permalink / raw)
To: Kevin Hickey; +Cc: ralf, linux-mips
On Sat, 07 Mar 2009 13:20:08 -0600
Kevin Hickey <khickey@rmicorp.com> wrote:
> > > +asmlinkage void plat_irq_dispatch(void)
> > > +{
> > > + unsigned int intr;
> > > + u32 bank;
> > > + u32 reg_msk;
> > > + unsigned int pending = read_c0_status() & read_c0_cause();
> > > + /*
> > > + * C0 timer tick
> > > + */
> > > + if (pending & CAUSEF_IP7)
> > > + do_IRQ(MIPS_CPU_IRQ_BASE + 7);
> > > + else if (pending & (CAUSEF_IP2 | CAUSEF_IP3)) {
> > > + intr = au_ioread32(&gpio_int->pri_enc);
> > > + bank = GPINT_BANK_FROM_INT(intr);
> > > + reg_msk = GPINT_BIT_FROM_INT(bank, intr);
> > > +
> > > + if (intr != 127) {
> > > + if (pending & CAUSEF_IP3)
> > > + board_irq_dispatch(intr);
> >
> > What is this supposed to do? (missed debug code?)
> board_irq_dispatch (which as I said above should be in a non-devboard
> include) is used to display the IRQ number on the hex LEDs on the DB1300
> board. I tried to keep it generic so that other boards could do what
> they want or leave it unimplemented and have it optimized out. The
> CAUSEF_IP3 part is there to not display the timer tick (since it pretty
> much floods out the other IRQ displays). I should really do that
> segregation in the board_irq_dispatch call; I was pretty focused on my
> board when I wrote this code.
Oh okay. I was wondering about the IP3.
We should probably make a list of all (possible) hooks available into
the alchemy core code (and give them nice prefixed names ;-) )
> > (FWIW, I'm working on getting rid of the explicit CPU-type config
> > options and instead do runtime detection and configuration of
> > dma/dbdma/irq/ and so on).
>
> Why? Won't that just lead to a larger kernel binary since it will have
> all of the tables in it? I would prefer to only compile in the data
> that I need. Unless I'm missing what you're doing...
All Alchemy chips are more or less identical. Some have different
sd/ddr controller, some have different dma, and some lack peripherals
others do have; most periperhals have identical mmio addresses across
chip types.
Interestingly even the devboard designers assigned a unique 4bit value
to each board type; with a bit of work you could in theory build one
kernel binary which runs on all of them.
That's what I'm aiming at.
Best regards,
Manuel Lauss
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 08/10] Alchemy: DB1300 blink leds on timer tick
2009-03-08 8:37 ` Manuel Lauss
@ 2009-03-08 8:54 ` Manuel Lauss
0 siblings, 0 replies; 26+ messages in thread
From: Manuel Lauss @ 2009-03-08 8:54 UTC (permalink / raw)
To: Manuel Lauss; +Cc: Kevin Hickey, ralf, linux-mips
> board_timer_set callback to blink some leds. (Note, I still don't feel
> this is "right", but ultimately it's not up you anyway).
should read "but ultimately it's up to you anyway"
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH 01/10] Initial Au1300 and DBAu1300 support
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
` (8 preceding siblings ...)
2009-03-06 16:20 ` [PATCH 10/10] Alchemy: DB1300 defconfig Kevin Hickey
@ 2009-03-09 13:40 ` Ralf Baechle
9 siblings, 0 replies; 26+ messages in thread
From: Ralf Baechle @ 2009-03-09 13:40 UTC (permalink / raw)
To: Kevin Hickey; +Cc: linux-mips
On Fri, Mar 06, 2009 at 10:20:00AM -0600, Kevin Hickey wrote:
> @@ -135,3 +147,9 @@ config SOC_AU1X00
> select SYS_SUPPORTS_32BIT_KERNEL
> select SYS_SUPPORTS_APM_EMULATION
> select GENERIC_HARDIRQS_NO__DO_IRQ
> +
> +config AU_INT_CNTLR
> + bool
> +
> +config AU_GPIO_INT_CNTLR
> + bool
These two definitions should be in patch 2/10 with the code that uses it.
> diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
> index 5c76c64..fd096d1 100644
> --- a/arch/mips/alchemy/common/platform.c
> +++ b/arch/mips/alchemy/common/platform.c
> @@ -65,6 +65,7 @@ static struct platform_device au1xx0_uart_device = {
> },
> };
>
> +#ifndef CONFIG_SOC_AU13XX
> /* OHCI (USB full speed host controller) */
> static struct resource au1xxx_usb_ohci_resources[] = {
> [0] = {
> @@ -92,6 +93,7 @@ static struct platform_device au1xxx_usb_ohci_device = {
> .num_resources = ARRAY_SIZE(au1xxx_usb_ohci_resources),
> .resource = au1xxx_usb_ohci_resources,
> };
> +#endif
Try to avoid this kind of #ifdef. It'll only get more ugly in the future
when there are more members of the SOC family that don't have the USB.
> +#if 0
> +void __init prom_init(void)
> +{
> + unsigned char *memsize_str;
> + unsigned long memsize;
> +
> + prom_argc = (int)fw_arg0;
> + prom_argv = (char **)fw_arg1;
> + prom_envp = (char **)fw_arg2;
> +
> + prom_init_cmdline();
> + memsize_str = prom_getenv("memsize");
> + /* KH: TODO - Change back to 128 MB when the second DDR channel is working. */
> + if (!memsize_str)
> + memsize = 0x04000000;
> + else
> + strict_strtol(memsize_str, 0, &memsize);
> + add_memory_region(0, memsize, BOOT_MEM_RAM);
> +}
> +#endif
#if 0, so delete?
> --- a/arch/mips/include/asm/mach-au1x00/au1000.h
> +++ b/arch/mips/include/asm/mach-au1x00/au1000.h
> +void static inline au_iowrite32(u32 val, volatile u32 *reg)
> +{
> + *reg = val;
> +}
> +
> +static inline u32 au_ioread32(volatile u32 *reg)
> +{
> + return *reg;
> +}
> +
> +#define AU_SET_BITS_16(mask, reg) \
> +do { \
> + au_iowrite16((au_ioread16(reg) | mask ), reg); \
> +} while(0)
Macros should be bullet proof against side effects:
#define au_set_bits_16(mask, reg) \
do { \
volatile u16 *__r = (reg); \
\
au_iowrite16((au_ioread16(__r) | (mask)), __r); \
} while(0)
Or simply use an inline function instead.
> +#define AU_CLEAR_BITS_16(mask, reg) \
> +do { \
> + au_iowrite16((au_ioread16(reg) & ~mask ), reg); \
> +} while(0)
> +
> +#define AU_SET_BITS_32(mask, reg) \
> +do { \
> + au_iowrite32((au_ioread32(reg) | mask), reg); \
> +} while(0)
> +
> +#define AU_CLEAR_BITS_32(mask, reg) \
> +do { \
> + au_iowrite32((au_ioread32(reg) & ~mask), reg); \
> +} while(0)
> +
> /* arch/mips/au1000/common/clocks.c */
> extern void set_au1x00_speed(unsigned int new_freq);
> extern unsigned int get_au1x00_speed(void);
> --- /dev/null
> +++ b/arch/mips/include/asm/mach-au1x00/au13xx.h
> @@ -0,0 +1,207 @@
> +#ifdef CONFIG_SOC_AU13XX
> +
> +#define NR_INTS 255
Unused macro - did you mean NR_IRQS? Also keep the value of
NR_IRQS a multiple of BITS_PER_LONG or unpleasant things might happen.
> +#define UART0_ADDR 0xB0100000
> +#define UART1_ADDR 0xB0101000
> +#define UART2_ADDR 0xB0102000
> +#define UART3_ADDR 0xB0103000
> +
> +#define KSEG1_OFFSET 0xA0000000
This constant duplicates KSEG1 defined in <asm/addrspace.h>.
> +#define GPIO_INT_CTRLR_BASE 0x10200000
> +/*
> + * Linux uses IRQ 0-7 for the 8 causes. That means that all of our channel
> + * bits need to be offset by 8 either when passed to do_IRQ or when received
> + * through the irq_chip calls
> + *
> + * KH: TODO - This is duplicated from gpio_int.h Is that the right thing to do?
> + */
> +#define GPINT_LINUX_IRQ_OFFSET 8
> +
> +#define AU1300_IRQ_UART1 17
> +#define AU1300_IRQ_UART2 25
> +#define AU1300_IRQ_UART3 27
> +#define AU1300_IRQ_SD1 32
> +#define AU1300_IRQ_SD2 38
> +#define AU1300_IRQ_PSC0 48
> +#define AU1300_IRQ_PSC1 52
> +#define AU1300_IRQ_PSC2 56
> +#define AU1300_IRQ_PSC3 60
> +#define AU1300_IRQ_NAND 62
> +#define AU1300_IRQ_DDMA 75
> +#define AU1300_IRQ_GPU 78
> +#define AU1300_IRQ_MPU 77
> +#define AU1300_IRQ_MMU 76
> +#define AU1300_IRQ_UDMA 79
> +#define AU1300_IRQ_TOY_TICK 80
> +#define AU1300_IRQ_TOYMATCH_0 81
> +#define AU1300_IRQ_TOYMATCH_1 82
> +#define AU1300_IRQ_TOYMATCH_2 83
> +#define AU1300_IRQ_RTC_TICK 84
> +#define AU1300_IRQ_RTCMATCH_0 85
> +#define AU1300_IRQ_RTCMATCH_1 86
> +#define AU1300_IRQ_RTCMATCH_2 87
> +#define AU1300_IRQ_UART0 88
> +#define AU1300_IRQ_SD0 89
> +#define AU1300_IRQ_USB 90
> +#define AU1300_IRQ_LCD 91
> +#define AU1300_IRQ_BSA 94
> +#define AU1300_IRQ_MPE 93
> +#define AU1300_IRQ_ITE 92
> +#define AU1300_IRQ_AES 95
> +#define AU1300_IRQ_CIM 96
> +
> +#define LCD_PHYS_ADDR 0x15000000
> +
> +#define AU1200_LCD_INT (GPINT_LINUX_IRQ_OFFSET + AU1300_IRQ_LCD)
> +#define AU1000_RTC_MATCH2_INT (GPINT_LINUX_IRQ_OFFSET + AU1300_IRQ_RTCMATCH_2)
> +
> +#define SD0_PHYS_ADDR 0x10600000
> +#define SD1_PHYS_ADDR 0x10601000
> +
> +
> +#define USB_BASE_PHYS_ADDR 0x14021000
> +#define USB_EHCI_BASE 0x14020000
> +#define USB_EHCI_LEN 0x400
> +#define USB_OHCI_BASE 0x14020800
> +#define USB_OHCI_LEN 0x400
> +#define USB_UOC_BASE 0x14022000
> +#define USB_UOC_LEN 0x20
> +#define USB_UDC_BASE 0x14022000
> +#define USB_UDC_LEN 0x2000
> +
> +#if !defined(ASSEMBLER)
There is no ASSEMBLER macro defined by cpp. Within the kernel please use
#ifndef __ASSEMBLY__ instead. However this bug suggests you don't use this
header in assembly code at all so maybe the whole ifdef should go?
> +typedef volatile struct
See Documentation/volatile-considered-harmful.txt ...
> +{
> + // setup registers
Please use /* ... */ only within the kernel.
You did run your patches through scripts/checkpatch.pl, no?
> + u32 dwc_ctrl1; //0x0000
See Documentation/volatile-considered-harmful.txt ...
Ralf
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2009-03-09 13:40 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-06 16:19 Alchemy: Support for RMI Alchemy Au1300 and DBAu1300 Kevin Hickey
2009-03-06 16:20 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Kevin Hickey
2009-03-06 16:20 ` [PATCH 02/10] Alchemy: Au1300 new interrupt controller Kevin Hickey
2009-03-07 9:49 ` Manuel Lauss
2009-03-07 9:49 ` Manuel Lauss
2009-03-07 19:20 ` Kevin Hickey
2009-03-08 8:49 ` Manuel Lauss
2009-03-06 16:20 ` [PATCH 03/10] Alchemy: Au1300/DB1300 UART support Kevin Hickey
2009-03-06 16:20 ` [PATCH 04/10] Alchemy: Au1300/DB1300 peripheral resource declarations Kevin Hickey
2009-03-06 16:20 ` [PATCH 05/10] Alchemy: Au1300/DB1300 MMC support Kevin Hickey
2009-03-06 16:20 ` [PATCH 06/10] Alchemy: Au1300 USB support Kevin Hickey
2009-03-07 10:01 ` Sergei Shtylyov
2009-03-07 19:11 ` Kevin Hickey
2009-03-06 16:20 ` [PATCH 07/10] Alchemy: SMSC 9210 Ethernet support Kevin Hickey
2009-03-07 9:35 ` Manuel Lauss
2009-03-07 9:35 ` Manuel Lauss
2009-03-07 19:06 ` Kevin Hickey
2009-03-06 16:20 ` [PATCH 08/10] Alchemy: DB1300 blink leds on timer tick Kevin Hickey
2009-03-07 9:37 ` Manuel Lauss
2009-03-07 9:37 ` Manuel Lauss
2009-03-07 19:04 ` Kevin Hickey
2009-03-08 8:37 ` Manuel Lauss
2009-03-08 8:54 ` Manuel Lauss
2009-03-06 16:20 ` [PATCH 09/10] Alchemy: Au1300: Add LCD framebuffer support Kevin Hickey
2009-03-06 16:20 ` [PATCH 10/10] Alchemy: DB1300 defconfig Kevin Hickey
2009-03-09 13:40 ` [PATCH 01/10] Initial Au1300 and DBAu1300 support Ralf Baechle
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox