summaryrefslogtreecommitdiff
path: root/libre/linux-libre-lts/3.14.26-8475f027b4-loongson-community.patch
diff options
context:
space:
mode:
Diffstat (limited to 'libre/linux-libre-lts/3.14.26-8475f027b4-loongson-community.patch')
-rw-r--r--libre/linux-libre-lts/3.14.26-8475f027b4-loongson-community.patch10872
1 files changed, 0 insertions, 10872 deletions
diff --git a/libre/linux-libre-lts/3.14.26-8475f027b4-loongson-community.patch b/libre/linux-libre-lts/3.14.26-8475f027b4-loongson-community.patch
deleted file mode 100644
index 20f540673..000000000
--- a/libre/linux-libre-lts/3.14.26-8475f027b4-loongson-community.patch
+++ /dev/null
@@ -1,10872 +0,0 @@
-diff --git a/Makefile b/Makefile
-index 63a5ee8..9b779e2 100644
---- a/Makefile
-+++ b/Makefile
-@@ -244,8 +244,8 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
-
- HOSTCC = gcc
- HOSTCXX = g++
--HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer
--HOSTCXXFLAGS = -O2
-+HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O3 -fomit-frame-pointer
-+HOSTCXXFLAGS = -O3
-
- # Decide whether to build built-in, modular, or both.
- # Normally, just do built-in.
-@@ -582,7 +582,7 @@ all: vmlinux
- ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
- KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,)
- else
--KBUILD_CFLAGS += -O2
-+KBUILD_CFLAGS += -O3
- endif
-
- include $(srctree)/arch/$(SRCARCH)/Makefile
-diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
-index 95fa1f1..82dc7e8 100644
---- a/arch/mips/Kconfig
-+++ b/arch/mips/Kconfig
-@@ -278,7 +278,7 @@ config LASAT
-
- config MACH_LOONGSON
- bool "Loongson family of machines"
-- select SYS_SUPPORTS_ZBOOT
-+ select SYS_SUPPORTS_ZBOOT_UART16550
- help
- This enables the support of Loongson family of machines.
-
-@@ -885,6 +885,60 @@ config CSRC_IOASIC
- config CSRC_R4K
- bool
-
-+config MIPS_USER_RDTSC
-+ bool "Emulate rdtsc instruction for MIPS"
-+ depends on CSRC_R4K && MIPS32_O32
-+ default n
-+ help
-+ This optoin enables the Emulated rdtsc support for MIPS, which allows
-+ the user-space applications read the R4k count directly. Currently,
-+ this only support the CONFIG_MIPS32_O32 and R4K, but future, we may
-+ add support for scall64-{n32,64}.S and scall32-32.S and for the count
-+ registers provided by the other MIPS variants.
-+
-+ This emulation based on the syscall instruction, by default, the
-+ syscall is encoded as 0x0000000c, except the 0xc, the other parts can
-+ be encoded as specific meaning. when a syscall instruction is issued,
-+ through checking the encoding of the instruction, when the encoding
-+ is the generic 0x000000c, we do the generic syscall work, if
-+ something other is encoded in, we can do relevant things, except for
-+ the light-weight things, such as read a register. herein, we read the
-+ count register whenever there is something encoded in the syscall
-+ instruction. In the future, we may be possible to abstract more
-+ light-weight & frequently-used operations and add a
-+ sys_call_table-like table to store the entries of some light-weight
-+ operations and encode 1,2,3... into the syscall instruction and jump
-+ to respective entry for diffrent numbers, as a result, we get
-+ fast-syscall and which may speed up the user-space applications and
-+ even be possibly improve the determinism.
-+
-+ *Example*
-+
-+ #include <stdio.h>
-+ #include <stdint.h>
-+
-+ /*
-+ * Currently, our return value is only 32bit, In the long run,
-+ * this should be uint64_t, just like clock_gettime(), but it
-+ * should has high precision/low overhead than clock_gettime()
-+ */
-+ uint32_t rdtsc(void)
-+ {
-+ /*
-+ * Linux will store the value of the count register into
-+ * the v0 register, which is just the return value of this
-+ * function, so, please ignore the compiling warning.
-+ */
-+ __asm__ __volatile__ (
-+ "syscall 1\n"
-+ :::"$2");
-+ }
-+
-+ int main(int argc, char *argv[])
-+ {
-+ return printf("cycles: %u\n", rdtsc());
-+ }
-+
- config CSRC_GIC
- bool
-
-@@ -1492,6 +1546,15 @@ config CPU_LOONGSON2
- bool
- select CPU_SUPPORTS_32BIT_KERNEL
- select CPU_SUPPORTS_64BIT_KERNEL
-+ select CPU_SUPPORTS_HIGHMEM if ! EMBEDDED
-+ select ARCH_WANT_OPTIONAL_GPIOLIB
-+
-+config CPU_LOONGSON1
-+ bool
-+ select CPU_MIPS32
-+ select CPU_MIPSR2
-+ select CPU_HAS_PREFETCH
-+ select CPU_SUPPORTS_32BIT_KERNEL
- select CPU_SUPPORTS_HIGHMEM
- select CPU_SUPPORTS_HUGEPAGES
-
-@@ -2110,7 +2173,7 @@ config SYS_SUPPORTS_MICROMIPS
-
- config ARCH_FLATMEM_ENABLE
- def_bool y
-- depends on !NUMA && !CPU_LOONGSON2
-+ depends on !NUMA && !(CPU_LOONGSON2 && HIBERNATION)
-
- config ARCH_DISCONTIGMEM_ENABLE
- bool
-diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
-index b147e70..f32dfb0 100644
---- a/arch/mips/Kconfig.debug
-+++ b/arch/mips/Kconfig.debug
-@@ -7,9 +7,9 @@ config TRACE_IRQFLAGS_SUPPORT
- source "lib/Kconfig.debug"
-
- config EARLY_PRINTK
-- bool "Early printk" if EXPERT
-+ bool "Early printk"
- depends on SYS_HAS_EARLY_PRINTK
-- default y
-+ default n
- help
- This option enables special console drivers which allow the kernel
- to print messages very early in the bootup process.
-diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
-index 61af6b6..8598044 100644
---- a/arch/mips/boot/compressed/Makefile
-+++ b/arch/mips/boot/compressed/Makefile
-@@ -30,9 +30,10 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
- targets := head.o decompress.o string.o dbg.o uart-16550.o uart-alchemy.o
-
- # decompressor objects (linked with vmlinuz)
--vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/dbg.o
-+vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o
-
- ifdef CONFIG_DEBUG_ZBOOT
-+vmlinuzobjs-y += $(obj)/dbg.o
- vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o
- vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o
- endif
-@@ -79,9 +80,18 @@ quiet_cmd_zld = LD $@
- cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@
- quiet_cmd_strip = STRIP $@
- cmd_strip = $(STRIP) -s $@
-+ifdef CONFIG_EMBEDDED
-+quiet_cmd_sstrip = SSTRIP $@
-+ cmd_sstrip = $(srctree)/scripts/sstrip.sh $@
-+endif
- vmlinuz: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr
- $(call cmd,zld)
- $(call cmd,strip)
-+ $(call cmd,sstrip)
-+
-+vmlinuz.unsstrip: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/calc_vmlinuz_load_addr
-+ $(call cmd,zld)
-+ $(call cmd,strip)
-
- #
- # Some DECstations need all possible sections of an ECOFF executable
-@@ -94,14 +104,14 @@ endif
- hostprogs-y += ../elf2ecoff
-
- ifdef CONFIG_32BIT
-- VMLINUZ = vmlinuz
-+ VMLINUZ = vmlinuz.unsstrip
- else
- VMLINUZ = vmlinuz.32
- endif
-
- quiet_cmd_32 = OBJCOPY $@
- cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
--vmlinuz.32: vmlinuz
-+vmlinuz.32: vmlinuz.unsstrip
- $(call cmd,32)
-
- quiet_cmd_ecoff = ECOFF $@
-@@ -110,11 +120,11 @@ vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ)
- $(call cmd,ecoff)
-
- OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary
--vmlinuz.bin: vmlinuz
-+vmlinuz.bin: vmlinuz.unsstrip
- $(call cmd,objcopy)
-
- OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec
--vmlinuz.srec: vmlinuz
-+vmlinuz.srec: vmlinuz.unsstrip
- $(call cmd,objcopy)
-
--clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec}
-+clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec,unsstrip}
-diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c
-index 5244cec..965734f1 100644
---- a/arch/mips/boot/compressed/decompress.c
-+++ b/arch/mips/boot/compressed/decompress.c
-@@ -28,8 +28,13 @@ unsigned long free_mem_end_ptr;
- extern unsigned char __image_begin, __image_end;
-
- /* debug interfaces */
-+#ifdef CONFIG_DEBUG_ZBOOT
- extern void puts(const char *s);
- extern void puthex(unsigned long long val);
-+#else
-+#define puts(s)
-+#define puthex(val)
-+#endif
-
- void error(char *x)
- {
-diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script
-index 5a33409..de04ac9 100644
---- a/arch/mips/boot/compressed/ld.script
-+++ b/arch/mips/boot/compressed/ld.script
-@@ -49,5 +49,6 @@ SECTIONS
- *(.reginfo)
- *(.comment)
- *(.note)
-+ *(.gnu.attributes)
- }
- }
-diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
-index 84238c5..28e0b03 100644
---- a/arch/mips/include/asm/dma-mapping.h
-+++ b/arch/mips/include/asm/dma-mapping.h
-@@ -6,9 +6,7 @@
- #include <asm/cache.h>
- #include <asm-generic/dma-coherent.h>
-
--#ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */
- #include <dma-coherence.h>
--#endif
-
- extern struct dma_map_ops *mips_dma_map_ops;
-
-diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
-index a0ee0cb..c6df1c4 100644
---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
-+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
-@@ -299,7 +299,42 @@ extern void _wrmsr(u32 msr, u32 hi, u32 lo);
-
- /****************** NATIVE ***************************/
- /* GPIO : I/O SPACE; REG : 32BITS */
--#define GPIOL_OUT_VAL 0x00
--#define GPIOL_OUT_EN 0x04
-+#define GPIOL_OUT_VAL 0x00
-+#define GPIOL_OUT_EN 0x04
-+#define GPIOL_OUT_AUX1_SEL 0x10
-+/* SMB : I/O SPACE, REG : 8BITS WIDTH */
-+#define SMB_SDA 0x00
-+#define SMB_STS 0x01
-+#define SMB_STS_SLVSTP (1 << 7)
-+#define SMB_STS_SDAST (1 << 6)
-+#define SMB_STS_BER (1 << 5)
-+#define SMB_STS_NEGACK (1 << 4)
-+#define SMB_STS_STASTR (1 << 3)
-+#define SMB_STS_NMATCH (1 << 2)
-+#define SMB_STS_MASTER (1 << 1)
-+#define SMB_STS_XMIT (1 << 0)
-+#define SMB_CTRL_STS 0x02
-+#define SMB_CSTS_TGSTL (1 << 5)
-+#define SMB_CSTS_TSDA (1 << 4)
-+#define SMB_CSTS_GCMTCH (1 << 3)
-+#define SMB_CSTS_MATCH (1 << 2)
-+#define SMB_CSTS_BB (1 << 1)
-+#define SMB_CSTS_BUSY (1 << 0)
-+#define SMB_CTRL1 0x03
-+#define SMB_CTRL1_STASTRE (1 << 7)
-+#define SMB_CTRL1_NMINTE (1 << 6)
-+#define SMB_CTRL1_GCMEN (1 << 5)
-+#define SMB_CTRL1_ACK (1 << 4)
-+#define SMB_CTRL1_RSVD (1 << 3)
-+#define SMB_CTRL1_INTEN (1 << 2)
-+#define SMB_CTRL1_STOP (1 << 1)
-+#define SMB_CTRL1_START (1 << 0)
-+#define SMB_ADDR 0x04
-+#define SMB_ADDR_SAEN (1 << 7)
-+#define SMB_CONTROLLER_ADDR (0xef << 0)
-+#define SMB_CTRL2 0x05
-+#define SMB_FREQ (0x20 << 1)
-+#define SMB_ENABLE (0x01 << 0)
-+#define SMB_CTRL3 0x06
-
- #endif /* _CS5536_H */
-diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
-index 021d017..d058e46 100644
---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
-+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
-@@ -10,26 +10,45 @@
-
- #ifdef CONFIG_CS5536_MFGPT
- extern void setup_mfgpt0_timer(void);
--extern void disable_mfgpt0_counter(void);
--extern void enable_mfgpt0_counter(void);
-+extern void disable_mfgpt_counter(void);
-+extern void enable_mfgpt_counter(void);
- #else
- static inline void __maybe_unused setup_mfgpt0_timer(void)
- {
- }
--static inline void __maybe_unused disable_mfgpt0_counter(void)
-+static inline void __maybe_unused disable_mfgpt_counter(void)
- {
- }
--static inline void __maybe_unused enable_mfgpt0_counter(void)
-+static inline void __maybe_unused enable_mfgpt_counter(void)
- {
- }
- #endif
-
--#define MFGPT_TICK_RATE 14318000
--#define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ)
-+#define MFGPT_CLK_RATE(c) ((14318000UL-32768)*c + 32768)
-+#define MFGPT_TICK_RATE(c, scale) (MFGPT_CLK_RATE(c) / (1 << scale))
-+#define MFGPT_COMPARE(c, scale) ((MFGPT_TICK_RATE(c, scale)+HZ/2)/HZ)
-
--#define MFGPT_BASE mfgpt_base
--#define MFGPT0_CMP2 (MFGPT_BASE + 2)
--#define MFGPT0_CNT (MFGPT_BASE + 4)
--#define MFGPT0_SETUP (MFGPT_BASE + 6)
-+#define MFGPT_SETUP_ENABLE (1 << 15)
-+#define MFGPT_SETUP_ACK (3 << 13)
-+#define MFGPT_SETUP_SETUP (1 << 12)
-+#define MFGPT_SETUP_CMP2EVT (3 << 8)
-+#define MFGPT_SETUP_CMP1EVT (3 << 6)
-+#define MFGPT_SETUP_CLOCK(c) (c << 4)
-+#define MFGPT_SETUP_SCALE(scale) scale
-+
-+#define MFGPT0_CMP1 mfgpt_base
-+#define MFGPT0_CMP2 (mfgpt_base + 0x02)
-+#define MFGPT0_CNT (mfgpt_base + 0x04)
-+#define MFGPT0_SETUP (mfgpt_base + 0x06)
-+
-+#define MFGPT1_CMP1 (mfgpt_base + 0x08)
-+#define MFGPT1_CMP2 (mfgpt_base + 0x0A)
-+#define MFGPT1_CNT (mfgpt_base + 0x0C)
-+#define MFGPT1_SETUP (mfgpt_base + 0x0E)
-+
-+#define MFGPT2_CMP1 (mfgpt_base + 0x10)
-+#define MFGPT2_CMP2 (mfgpt_base + 0x12)
-+#define MFGPT2_CNT (mfgpt_base + 0x14)
-+#define MFGPT2_SETUP (mfgpt_base + 0x16)
-
- #endif /*!_CS5536_MFGPT_H */
-diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h
-index 8a7ecb4..ac01334 100644
---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h
-+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h
-@@ -13,6 +13,7 @@
-
- #include <linux/types.h>
- #include <linux/pci_regs.h>
-+#include <linux/pci_ids.h>
-
- extern void cs5536_pci_conf_write4(int function, int reg, u32 value);
- extern u32 cs5536_pci_conf_read4(int function, int reg);
-diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h
-index 1f17c18..9bc368f0d 100644
---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h
-+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h
-@@ -17,15 +17,43 @@ typedef u32 (*cs5536_pci_vsm_read)(int reg);
- extern void pci_##name##_write_reg(int reg, u32 value); \
- extern u32 pci_##name##_read_reg(int reg);
-
-+#define DEFINE_CS5536_MODULE(name) \
-+static void pci_##name##_write_reg(int reg, u32 value) {} \
-+static u32 pci_##name##_read_reg(int reg) { return 0; }
-+
-+/* isa module */
-+#ifdef CONFIG_CS5536_ISA
-+DECLARE_CS5536_MODULE(isa)
-+#else
-+DEFINE_CS5536_MODULE(isa)
-+#endif
-+
- /* ide module */
-+#ifdef CONFIG_CS5536_IDE
- DECLARE_CS5536_MODULE(ide)
-+#else
-+DEFINE_CS5536_MODULE(ide)
-+#endif
-+
- /* acc module */
-+#ifdef CONFIG_CS5536_AUDIO
- DECLARE_CS5536_MODULE(acc)
-+#else
-+DEFINE_CS5536_MODULE(acc)
-+#endif
-+
- /* ohci module */
-+#ifdef CONFIG_CS5536_OHCI
- DECLARE_CS5536_MODULE(ohci)
--/* isa module */
--DECLARE_CS5536_MODULE(isa)
-+#else
-+DEFINE_CS5536_MODULE(ohci)
-+#endif
-+
- /* ehci module */
-+#ifdef CONFIG_CS5536_EHCI
- DECLARE_CS5536_MODULE(ehci)
-+#else
-+DEFINE_CS5536_MODULE(ehci)
-+#endif
-
- #endif /* _CS5536_VSM_H */
-diff --git a/arch/mips/include/asm/mach-loongson/gpio.h b/arch/mips/include/asm/mach-loongson/gpio.h
-index 211a7b7..f15db3c 100644
---- a/arch/mips/include/asm/mach-loongson/gpio.h
-+++ b/arch/mips/include/asm/mach-loongson/gpio.h
-@@ -13,12 +13,16 @@
- #ifndef __STLS2F_GPIO_H
- #define __STLS2F_GPIO_H
-
-+#ifdef CONFIG_GPIOLIB
-+#define ARCH_NR_GPIOS 4
- #include <asm-generic/gpio.h>
-
- extern void gpio_set_value(unsigned gpio, int value);
- extern int gpio_get_value(unsigned gpio);
- extern int gpio_cansleep(unsigned gpio);
-
-+#endif
-+
- /* The chip can do interrupt
- * but it has not been tested and doc not clear
- */
-diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
-index b286534..222d179 100644
---- a/arch/mips/include/asm/mach-loongson/loongson.h
-+++ b/arch/mips/include/asm/mach-loongson/loongson.h
-@@ -32,17 +32,13 @@ extern void __init prom_init_memory(void);
- extern void __init prom_init_cmdline(void);
- extern void __init prom_init_machtype(void);
- extern void __init prom_init_env(void);
--#ifdef CONFIG_LOONGSON_UART_BASE
--extern unsigned long _loongson_uart_base, loongson_uart_base;
--extern void prom_init_loongson_uart_base(void);
--#endif
-+extern void __init prom_init_uart_base(void);
-
--static inline void prom_init_uart_base(void)
--{
--#ifdef CONFIG_LOONGSON_UART_BASE
-- prom_init_loongson_uart_base();
--#endif
--}
-+/*
-+ * Copy kernel command line from arcs_cmdline
-+ */
-+#include <asm/setup.h>
-+extern char loongson_cmdline[COMMAND_LINE_SIZE];
-
- /* irq operation functions */
- extern void bonito_irqdispatch(void);
-@@ -249,6 +245,12 @@ extern struct cpufreq_frequency_table loongson2_clockmod_table[];
-
- /* Chip Config */
- #define LOONGSON_CHIPCFG0 LOONGSON_REG(LOONGSON_REGBASE + 0x80)
-+#define LOONGSON_GET_CPUFREQ() (LOONGSON_CHIPCFG0 & 7)
-+
-+#define LOONGSON_SET_CPUFREQ(level) do { \
-+ LOONGSON_CHIPCFG0 = (LOONGSON_CHIPCFG0 & (~7)) | (level); \
-+} while (0)
-+
- #endif
-
- /*
-diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h
-index 3810d5c..d219499 100644
---- a/arch/mips/include/asm/mach-loongson/machine.h
-+++ b/arch/mips/include/asm/mach-loongson/machine.h
-@@ -24,4 +24,10 @@
-
- #endif
-
-+#ifdef CONFIG_DEXXON_GDIUM
-+
-+#define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10
-+
-+#endif
-+
- #endif /* __ASM_MACH_LOONGSON_MACHINE_H */
-diff --git a/arch/mips/include/asm/mach-loongson1/clock.h b/arch/mips/include/asm/mach-loongson1/clock.h
-new file mode 100644
-index 0000000..dd1afdb
---- /dev/null
-+++ b/arch/mips/include/asm/mach-loongson1/clock.h
-@@ -0,0 +1,53 @@
-+#ifndef __ASM_MACH_LOONGSON1_CLOCK_H
-+#define __ASM_MACH_LOONGSON1_CLOCK_H
-+
-+#include <linux/kref.h>
-+#include <linux/list.h>
-+#include <linux/seq_file.h>
-+#include <linux/clk.h>
-+
-+extern void (*cpu_wait) (void);
-+
-+struct clk;
-+
-+struct clk_ops {
-+ void (*init) (struct clk *clk);
-+ void (*enable) (struct clk *clk);
-+ void (*disable) (struct clk *clk);
-+ void (*recalc) (struct clk *clk);
-+ int (*set_rate) (struct clk *clk, unsigned long rate, int algo_id);
-+ long (*round_rate) (struct clk *clk, unsigned long rate);
-+};
-+
-+struct clk {
-+ struct list_head node;
-+ const char *name;
-+ int id;
-+ struct module *owner;
-+
-+ struct clk *parent;
-+ struct clk_ops *ops;
-+
-+ struct kref kref;
-+
-+ unsigned long rate;
-+ unsigned long flags;
-+};
-+
-+#define CLK_ALWAYS_ENABLED (1 << 0)
-+#define CLK_RATE_PROPAGATES (1 << 1)
-+
-+/* Should be defined by processor-specific code */
-+void arch_init_clk_ops(struct clk_ops **, int type);
-+
-+int clk_init(void);
-+
-+int __clk_enable(struct clk *);
-+void __clk_disable(struct clk *);
-+
-+void clk_recalc_rate(struct clk *);
-+
-+int clk_register(struct clk *);
-+void clk_unregister(struct clk *);
-+
-+#endif /* __ASM_MIPS_CLOCK_H */
-diff --git a/arch/mips/include/asm/mach-loongson1/regs-intc.h b/arch/mips/include/asm/mach-loongson1/regs-intc.h
-new file mode 100644
-index 0000000..6d5db23
---- /dev/null
-+++ b/arch/mips/include/asm/mach-loongson1/regs-intc.h
-@@ -0,0 +1,25 @@
-+/*
-+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
-+ *
-+ * Loongson1 Interrupt register definitions.
-+ *
-+ * 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.
-+ */
-+
-+#ifndef __ASM_MACH_LOONGSON1_REGS_INTC_H
-+#define __ASM_MACH_LOONGSON1_REGS_INTC_H
-+
-+#define LS1X_INTC_REG(n, x) \
-+ (ioremap(LS1X_INTC_BASE + (n * 0x18) + (x), 4))
-+
-+#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0)
-+#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4)
-+#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8)
-+#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc)
-+#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10)
-+#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14)
-+
-+#endif /* __ASM_MACH_LOONGSON1_REGS_INTC_H */
-diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h
-index 44b705d..c28a782 100644
---- a/arch/mips/include/asm/module.h
-+++ b/arch/mips/include/asm/module.h
-@@ -126,6 +126,8 @@ search_module_dbetables(unsigned long addr)
- #define MODULE_PROC_FAMILY "LOONGSON1 "
- #elif defined CONFIG_CPU_LOONGSON2
- #define MODULE_PROC_FAMILY "LOONGSON2 "
-+#elif defined CONFIG_CPU_LOONGSON1
-+#define MODULE_PROC_FAMILY "LOONGSON1 "
- #elif defined CONFIG_CPU_CAVIUM_OCTEON
- #define MODULE_PROC_FAMILY "OCTEON "
- #elif defined CONFIG_CPU_XLR
-diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h
-index c542475..74fef34 100644
---- a/arch/mips/include/asm/timex.h
-+++ b/arch/mips/include/asm/timex.h
-@@ -10,6 +10,10 @@
-
- #ifdef __KERNEL__
-
-+#ifdef CONFIG_CSRC_R4K
-+#define ARCH_HAS_PREPARED_LPJ
-+#endif
-+
- #include <asm/cpu-features.h>
- #include <asm/mipsregs.h>
- #include <asm/cpu-type.h>
-diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h
-index f25181b..d243152 100644
---- a/arch/mips/include/uapi/asm/inst.h
-+++ b/arch/mips/include/uapi/asm/inst.h
-@@ -62,6 +62,8 @@ enum spec_op {
- enum spec2_op {
- madd_op, maddu_op, mul_op, spec2_3_unused_op,
- msub_op, msubu_op, /* more unused ops */
-+ loongson_madd_op = 0x18, loongson_msub_op,
-+ loongson_nmadd_op, loongson_nmsub_op,
- clz_op = 0x20, clo_op,
- dclz_op = 0x24, dclo_op,
- sdbpp_op = 0x3f
-@@ -135,7 +137,7 @@ enum cop0_com_func {
- */
- enum cop1_fmt {
- s_fmt, d_fmt, e_fmt, q_fmt,
-- w_fmt, l_fmt
-+ w_fmt, l_fmt, ps_fmt
- };
-
- /*
-@@ -164,7 +166,8 @@ enum cop1_sdw_func {
- enum cop1x_func {
- lwxc1_op = 0x00, ldxc1_op = 0x01,
- swxc1_op = 0x08, sdxc1_op = 0x09,
-- pfetch_op = 0x0f, madd_s_op = 0x20,
-+ pfetch_op = 0x0f,
-+ prefx_op = 0x17, madd_s_op = 0x20,
- madd_d_op = 0x21, madd_e_op = 0x22,
- msub_s_op = 0x28, msub_d_op = 0x29,
- msub_e_op = 0x2a, nmadd_s_op = 0x30,
-diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
-index 6788727d..0f81805 100644
---- a/arch/mips/kernel/scall64-o32.S
-+++ b/arch/mips/kernel/scall64-o32.S
-@@ -26,6 +26,18 @@
-
- .align 5
- NESTED(handle_sys, PT_SIZE, sp)
-+#ifdef CONFIG_MIPS_USER_RDTSC
-+ MFC0 k0, CP0_EPC
-+ lw k1, 0(k0)
-+ sltiu k1, k1, 0x1c
-+ bne k1, zero, 1f # Normal syscall code: 0x0c < 0x1c
-+ nop
-+ mfc0 v0, CP0_COUNT # Get TSC
-+ PTR_ADDIU k0, 4 # ret from syscall
-+ MTC0 k0, CP0_EPC
-+ eret
-+1:
-+#endif /* CONFIG_MIPS_USER_RDTSC */
- .set noat
- SAVE_SOME
- TRACE_IRQS_ON_RELOAD
-diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
-index dcb8e5d..45177bc 100644
---- a/arch/mips/kernel/time.c
-+++ b/arch/mips/kernel/time.c
-@@ -120,6 +120,11 @@ static __init int cpu_has_mfc0_count_bug(void)
-
- void __init time_init(void)
- {
-+#ifdef CONFIG_HR_SCHED_CLOCK
-+ if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug())
-+ write_c0_count(0);
-+#endif
-+
- plat_time_init();
-
- /*
-diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
-index eeddc58..d7bec00 100644
---- a/arch/mips/lib/Makefile
-+++ b/arch/mips/lib/Makefile
-@@ -2,10 +2,14 @@
- # Makefile for MIPS-specific library files..
- #
-
--lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \
-+lib-y += bitops.o csum_partial.o memcpy.o memset.o \
- mips-atomic.o strlen_user.o strncpy_user.o \
- strnlen_user.o uncached.o
-
-+ifndef CONFIG_CSRC_R4K
-+lib-y += delay.o
-+endif
-+
- obj-y += iomap.o
- obj-$(CONFIG_PCI) += iomap-pci.o
-
-diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig
-index 263beb9..d56d594 100644
---- a/arch/mips/loongson/Kconfig
-+++ b/arch/mips/loongson/Kconfig
-@@ -32,12 +32,12 @@ config LEMOTE_FULOONG2E
-
- config LEMOTE_MACH2F
- bool "Lemote Loongson 2F family machines"
-- select ARCH_SPARSEMEM_ENABLE
-+ select ARCH_SPARSEMEM_ENABLE if HIBERNATION
- select BOARD_SCACHE
- select BOOT_ELF32
- select CEVT_R4K if ! MIPS_EXTERNAL_TIMER
- select CPU_HAS_WB
-- select CS5536
-+ select CS5536 if PCI
- select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
- select DMA_NONCOHERENT
- select GENERIC_ISA_DMA_SUPPORT_BROKEN
-@@ -45,23 +45,68 @@ config LEMOTE_MACH2F
- select HW_HAS_PCI
- select I8259
- select IRQ_CPU
-- select ISA
- select SYS_HAS_CPU_LOONGSON2F
- select SYS_HAS_EARLY_PRINTK
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_64BIT_KERNEL
-- select SYS_SUPPORTS_HIGHMEM
-+ select SYS_SUPPORTS_HIGHMEM if ! EMBEDDED
- select SYS_SUPPORTS_LITTLE_ENDIAN
-- select LOONGSON_MC146818
-+ select LOONGSON_MC146818 if RTC_DRV_CMOS
- help
- Lemote Loongson 2F family machines utilize the 2F revision of
- Loongson processor and the AMD CS5536 south bridge.
-
- These family machines include fuloong2f mini PC, yeeloong2f notebook,
- LingLoong allinone PC and so forth.
-+
-+config DEXXON_GDIUM
-+ bool "Dexxon Gdium Netbook"
-+ select ARCH_SPARSEMEM_ENABLE
-+ select BOARD_SCACHE
-+ select BOOT_ELF32
-+ select CEVT_R4K if ! MIPS_EXTERNAL_TIMER
-+ select CPU_HAS_WB
-+ select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
-+ select DMA_NONCOHERENT
-+ select GENERIC_ISA_DMA_SUPPORT_BROKEN
-+ select HW_HAS_PCI
-+ select I8259
-+ select IRQ_CPU
-+ select ISA
-+ select SYS_HAS_CPU_LOONGSON2F
-+ select SYS_HAS_EARLY_PRINTK
-+ select SYS_SUPPORTS_32BIT_KERNEL
-+ select SYS_SUPPORTS_64BIT_KERNEL
-+ select SYS_SUPPORTS_HIGHMEM
-+ select SYS_SUPPORTS_LITTLE_ENDIAN
-+ select ARCH_REQUIRE_GPIOLIB
-+ select HAVE_PWM if MFD_SM501
-+ help
-+ Dexxon gdium netbook based on Loongson 2F and SM502.
- endchoice
-
- config CS5536
-+ select CS5536_IDE if (PATA_AMD || BLK_DEV_AMD74XX || PATA_CS5536)
-+ select CS5536_OHCI if USB_OHCI_HCD
-+ select CS5536_EHCI if USB_EHCI_HCD
-+ select CS5536_AUDIO if SND_CS5535AUDIO
-+ select CS5536_ISA
-+ bool
-+
-+config CS5536_ISA
-+ select ISA
-+ bool
-+
-+config CS5536_IDE
-+ bool
-+
-+config CS5536_OHCI
-+ bool
-+
-+config CS5536_EHCI
-+ bool
-+
-+config CS5536_AUDIO
- bool
-
- config CS5536_MFGPT
-@@ -81,13 +126,25 @@ config LOONGSON_SUSPEND
- default y
- depends on CPU_SUPPORTS_CPUFREQ && SUSPEND
-
--config LOONGSON_UART_BASE
-- bool
-- default y
-- depends on EARLY_PRINTK || SERIAL_8250
--
- config LOONGSON_MC146818
- bool
- default n
-
-+config GDIUM_PWM_CLOCK
-+ tristate "Gdium PWM Timer"
-+ default n
-+ depends on HAVE_PWM && EXPERIMENTAL && BROKEN
-+ select MIPS_EXTERNAL_TIMER
-+ help
-+ This options enables the experimental sm501-pwm based clock. With it,
-+ you may be possible to use the loongson2f cpufreq driver.
-+
-+config GDIUM_VERSION
-+ int "Configure Gdium Version"
-+ depends on DEXXON_GDIUM
-+ default "3"
-+ help
-+ I have no information about how to determine which version your board
-+ is, If the default config doesn't work for it, please change it to
-+ smaller ones.
- endif # MACH_LOONGSON
-diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile
-index 0dc0055..4b69866 100644
---- a/arch/mips/loongson/Makefile
-+++ b/arch/mips/loongson/Makefile
-@@ -15,3 +15,9 @@ obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/
- #
-
- obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/
-+
-+#
-+# Dexxon gdium netbook, based on loongson 2F and SM502
-+#
-+
-+obj-$(CONFIG_DEXXON_GDIUM) += gdium/
-diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform
-index 29692e5..6be5dff 100644
---- a/arch/mips/loongson/Platform
-+++ b/arch/mips/loongson/Platform
-@@ -30,3 +30,4 @@ platform-$(CONFIG_MACH_LOONGSON) += loongson/
- cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely
- load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000
- load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000
-+load-$(CONFIG_DEXXON_GDIUM) += 0xffffffff80200000
-diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile
-index 9005a8d6..73f1f9f 100644
---- a/arch/mips/loongson/common/Makefile
-+++ b/arch/mips/loongson/common/Makefile
-@@ -11,9 +11,7 @@ obj-$(CONFIG_PCI) += pci.o
- # Serial port support
- #
- obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
--loongson-serial-$(CONFIG_SERIAL_8250) := serial.o
--obj-y += $(loongson-serial-m) $(loongson-serial-y)
--obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
-+obj-$(CONFIG_SERIAL_8250) += serial.o
- obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
-
- #
-diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c
-index 72fed00..96d5919 100644
---- a/arch/mips/loongson/common/cmdline.c
-+++ b/arch/mips/loongson/common/cmdline.c
-@@ -17,10 +17,15 @@
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-+#include <linux/module.h>
- #include <asm/bootinfo.h>
-
- #include <loongson.h>
-
-+/* the kernel command line copied from arcs_cmdline */
-+char loongson_cmdline[COMMAND_LINE_SIZE];
-+EXPORT_SYMBOL(loongson_cmdline);
-+
- void __init prom_init_cmdline(void)
- {
- int prom_argc;
-@@ -45,4 +50,31 @@ void __init prom_init_cmdline(void)
- }
-
- prom_init_machtype();
-+
-+ /* append machine specific command line */
-+ switch (mips_machtype) {
-+ case MACH_LEMOTE_LL2F:
-+ if ((strstr(arcs_cmdline, "video=")) == NULL)
-+ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60");
-+ break;
-+ case MACH_LEMOTE_FL2F:
-+ if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL)
-+ strcat(arcs_cmdline, " ide_core.ignore_cable=0");
-+ break;
-+ case MACH_LEMOTE_ML2F7:
-+ /* Mengloong-2F has a 800x480 screen */
-+ if ((strstr(arcs_cmdline, "vga=")) == NULL)
-+ strcat(arcs_cmdline, " vga=0x313");
-+ break;
-+ case MACH_DEXXON_GDIUM2F10:
-+ /* gdium has a 1024x600 screen */
-+ if ((strstr(arcs_cmdline, "video=")) == NULL)
-+ strcat(arcs_cmdline, " video=sm501fb:1024x600@60");
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ /* copy arcs_cmdline into loongson_cmdline */
-+ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE);
- }
-diff --git a/arch/mips/loongson/common/cs5536/Makefile b/arch/mips/loongson/common/cs5536/Makefile
-index f12e640..70f6057 100644
---- a/arch/mips/loongson/common/cs5536/Makefile
-+++ b/arch/mips/loongson/common/cs5536/Makefile
-@@ -2,8 +2,13 @@
- # Makefile for CS5536 support.
- #
-
--obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \
-- cs5536_isa.o cs5536_ehci.o
-+obj-$(CONFIG_CS5536) += cs5536_pci.o
-+
-+obj-$(CONFIG_ISA) += cs5536_isa.o
-+obj-$(CONFIG_CS5536_IDE) += cs5536_ide.o
-+obj-$(CONFIG_CS5536_AUDIO) += cs5536_acc.o
-+obj-$(CONFIG_CS5536_OHCI) += cs5536_ohci.o
-+obj-$(CONFIG_CS5536_EHCI) += cs5536_ehci.o
-
- #
- # Enable cs5536 mfgpt Timer
-diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
-index c639b9d..a7078ae 100644
---- a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
-+++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
-@@ -7,6 +7,9 @@
- * Copyright (C) 2009 Lemote Inc.
- * Author: Wu zhangjin, wuzhangjin@gmail.com
- *
-+ * Copyright (C) 2010 Lemote Inc.
-+ * Author: Gang Liang, randomizedthinking@gmail.com
-+ *
- * Reference: AMD Geode(TM) CS5536 Companion Device Data Book
- *
- * This program is free software; you can redistribute it and/or modify it
-@@ -15,11 +18,24 @@
- * option) any later version.
- */
-
-+/*
-+ * The MFGPT base address is variable, i.e., it could change over time. In
-+ * reality, it only changes once when setting up the PCI memory mapping (occurs
-+ * about 0.2 second from boot). But because of this, we have to read in the
-+ * mfgpt base address repeatly in the beginning of various routines, most
-+ * noticeably, mfgpt1_read_cycle (for sched_clock), and mfgpt1_interrupt.
-+ *
-+ * The source of problem is that PMON and the current cs5536 set up pci
-+ * register window differently (to be further confirmed). Can we set
-+ * them the same so as to save the trouble here?
-+ *
-+ * Now an ugly hack is used to save a few CPU cycles... likely an
-+ * over-optimization. Feel free to remove it.
-+ */
-+
- #include <linux/io.h>
- #include <linux/init.h>
- #include <linux/module.h>
--#include <linux/jiffies.h>
--#include <linux/spinlock.h>
- #include <linux/interrupt.h>
- #include <linux/clockchips.h>
-
-@@ -27,108 +43,143 @@
-
- #include <cs5536/cs5536_mfgpt.h>
-
--DEFINE_SPINLOCK(mfgpt_lock);
--EXPORT_SYMBOL(mfgpt_lock);
-+static void mfgpt0_set_mode(enum clock_event_mode, struct clock_event_device*);
-+static int mfgpt0_next_event(unsigned long, struct clock_event_device*);
-+static irqreturn_t mfgpt0_interrupt(int irq, void *dev_id);
-+static void mfgpt0_start_timer(u16 delta);
-
-+static cycle_t mfgpt1_read_cycle(struct clocksource *cs);
-+
-+static enum clock_event_mode mfgpt0_mode = CLOCK_EVT_MODE_SHUTDOWN;
- static u32 mfgpt_base;
-
--/*
-- * Initialize the MFGPT timer.
-- *
-- * This is also called after resume to bring the MFGPT into operation again.
-- */
-+static struct clock_event_device mfgpt0_clockevent = {
-+ .name = "mfgpt0",
-+ .features = CLOCK_EVT_MODE_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
-+ .set_mode = mfgpt0_set_mode,
-+ .set_next_event = mfgpt0_next_event,
-+ .rating = 220,
-+ .irq = CS5536_MFGPT_INTR,
-+};
-+
-+static struct irqaction irq5 = {
-+ .handler = mfgpt0_interrupt,
-+ .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
-+ .name = "mfgpt0-timer"
-+};
-+
-+static struct clocksource mfgpt1_clocksource = {
-+ .name = "mfgpt1",
-+ .rating = 210,
-+ .read = mfgpt1_read_cycle,
-+ .mask = CLOCKSOURCE_MASK(16),
-+ .flags = CLOCK_SOURCE_IS_CONTINUOUS
-+};
-
--/* disable counter */
--void disable_mfgpt0_counter(void)
-+static inline void enable_mfgpt0_counter(void)
- {
-- outw(inw(MFGPT0_SETUP) & 0x7fff, MFGPT0_SETUP);
-+ u32 basehi;
-+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
-+
-+ /* clockevent: 14M, divisor = 8 (scale=3), CMP2 event mode */
-+ outw(MFGPT_SETUP_ACK | MFGPT_SETUP_CMP2EVT |
-+ MFGPT_SETUP_CLOCK(1) | MFGPT_SETUP_SCALE(3), MFGPT0_SETUP);
-+ outw(0, MFGPT0_CNT);
-+ outw(MFGPT_COMPARE(1, 3), MFGPT0_CMP2);
-+ outw(0xFFFF, MFGPT0_SETUP);
- }
--EXPORT_SYMBOL(disable_mfgpt0_counter);
-
--/* enable counter, comparator2 to event mode, 14.318MHz clock */
--void enable_mfgpt0_counter(void)
-+static inline void enable_mfgpt1_counter(void)
- {
-- outw(0xe310, MFGPT0_SETUP);
-+ u32 basehi;
-+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
-+
-+ /* clocksource: 32K w/ divisor = 2 (scale=1) */
-+ outw(MFGPT_SETUP_ACK | MFGPT_SETUP_CLOCK(0) |
-+ MFGPT_SETUP_SCALE(1), MFGPT1_SETUP);
-+
-+ outw(0, MFGPT1_CNT);
-+ outw(0xFFFF, MFGPT1_CMP2); /* CNT won't tick with no CMP set */
-+ outw(0xFFFF, MFGPT1_SETUP);
- }
--EXPORT_SYMBOL(enable_mfgpt0_counter);
-
--static void init_mfgpt_timer(enum clock_event_mode mode,
-- struct clock_event_device *evt)
-+void enable_mfgpt_counter(void)
- {
-- spin_lock(&mfgpt_lock);
--
-- switch (mode) {
-- case CLOCK_EVT_MODE_PERIODIC:
-- outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */
-- outw(0, MFGPT0_CNT); /* set counter to 0 */
-- enable_mfgpt0_counter();
-- break;
--
-- case CLOCK_EVT_MODE_SHUTDOWN:
-- case CLOCK_EVT_MODE_UNUSED:
-- if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
-- evt->mode == CLOCK_EVT_MODE_ONESHOT)
-- disable_mfgpt0_counter();
-- break;
--
-- case CLOCK_EVT_MODE_ONESHOT:
-- /* The oneshot mode have very high deviation, Not use it! */
-- break;
--
-- case CLOCK_EVT_MODE_RESUME:
-- /* Nothing to do here */
-- break;
-- }
-- spin_unlock(&mfgpt_lock);
-+ /* TODO: add a mfgpt system hard reset here
-+ * timers might not reset correctly when OS crashes
-+ */
-+
-+ enable_mfgpt0_counter();
-+ enable_mfgpt1_counter();
- }
-+EXPORT_SYMBOL(enable_mfgpt_counter);
-
--static struct clock_event_device mfgpt_clockevent = {
-- .name = "mfgpt",
-- .features = CLOCK_EVT_FEAT_PERIODIC,
-- .set_mode = init_mfgpt_timer,
-- .irq = CS5536_MFGPT_INTR,
--};
-+void disable_mfgpt_counter(void)
-+{
-+ outw(0x7FFF, MFGPT0_SETUP);
-+ outw(0x7FFF, MFGPT1_SETUP);
-+}
-+EXPORT_SYMBOL(disable_mfgpt_counter);
-
--static irqreturn_t timer_interrupt(int irq, void *dev_id)
-+static void mfgpt0_start_timer(u16 delta)
- {
-- u32 basehi;
-+ outw(0x7FFF, MFGPT0_SETUP);
-+ outw(0, MFGPT0_CNT);
-+ outw(delta, MFGPT0_CMP2);
-+ outw(0xFFFF, MFGPT0_SETUP);
-+}
-
-- /*
-- * get MFGPT base address
-- *
-- * NOTE: do not remove me, it's need for the value of mfgpt_base is
-- * variable
-- */
-+static void mfgpt0_set_mode(enum clock_event_mode mode,
-+ struct clock_event_device *evt)
-+{
-+ outw(0x7FFF, MFGPT0_SETUP);
-+ if (mode == CLOCK_EVT_MODE_PERIODIC)
-+ mfgpt0_start_timer(MFGPT_COMPARE(1, 3));
-+
-+ mfgpt0_mode = mode;
-+}
-+
-+static int mfgpt0_next_event(unsigned long delta,
-+ struct clock_event_device *evt)
-+{
-+ mfgpt0_start_timer(delta);
-+ return 0;
-+}
-+
-+static irqreturn_t mfgpt0_interrupt(int irq, void *dev_id)
-+{
-+ u32 basehi;
- _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
-
-- /* ack */
-- outw(inw(MFGPT0_SETUP) | 0x4000, MFGPT0_SETUP);
-+ /* stop the timer and ack the interrupt */
-+ outw(0x7FFF, MFGPT0_SETUP);
-
-- mfgpt_clockevent.event_handler(&mfgpt_clockevent);
-+ if (mfgpt0_mode == CLOCK_EVT_MODE_SHUTDOWN)
-+ return IRQ_HANDLED;
-
-+ /* restart timer for periodic mode */
-+ if (mfgpt0_mode == CLOCK_EVT_MODE_PERIODIC)
-+ outw(0xFFFF, MFGPT0_SETUP);
-+
-+ mfgpt0_clockevent.event_handler(&mfgpt0_clockevent);
- return IRQ_HANDLED;
- }
-
--static struct irqaction irq5 = {
-- .handler = timer_interrupt,
-- .flags = IRQF_NOBALANCING | IRQF_TIMER,
-- .name = "timer"
--};
--
- /*
- * Initialize the conversion factor and the min/max deltas of the clock event
- * structure and register the clock event source with the framework.
- */
- void __init setup_mfgpt0_timer(void)
- {
-- u32 basehi;
-- struct clock_event_device *cd = &mfgpt_clockevent;
-+ struct clock_event_device *cd = &mfgpt0_clockevent;
- unsigned int cpu = smp_processor_id();
--
- cd->cpumask = cpumask_of(cpu);
-- clockevent_set_clock(cd, MFGPT_TICK_RATE);
-- cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
-- cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
-+
-+ cd->shift = 22;
-+ cd->mult = div_sc(MFGPT_TICK_RATE(1, 3), NSEC_PER_SEC, cd->shift);
-+
-+ cd->min_delta_ns = clockevent_delta2ns(0xF, cd);
-+ cd->max_delta_ns = clockevent_delta2ns(0xFFFF, cd);
-
- /* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */
- _wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
-@@ -136,79 +187,24 @@ void __init setup_mfgpt0_timer(void)
- /* Enable Interrupt Gate 5 */
- _wrmsr(DIVIL_MSR_REG(PIC_ZSEL_LOW), 0, 0x50000);
-
-- /* get MFGPT base address */
-- _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
--
-+ enable_mfgpt0_counter();
- clockevents_register_device(cd);
--
- setup_irq(CS5536_MFGPT_INTR, &irq5);
- }
-
--/*
-- * Since the MFGPT overflows every tick, its not very useful
-- * to just read by itself. So use jiffies to emulate a free
-- * running counter:
-- */
--static cycle_t mfgpt_read(struct clocksource *cs)
-+static cycle_t mfgpt1_read_cycle(struct clocksource *cs)
- {
-- unsigned long flags;
-- int count;
-- u32 jifs;
-- static int old_count;
-- static u32 old_jifs;
--
-- spin_lock_irqsave(&mfgpt_lock, flags);
-- /*
-- * Although our caller may have the read side of xtime_lock,
-- * this is now a seqlock, and we are cheating in this routine
-- * by having side effects on state that we cannot undo if
-- * there is a collision on the seqlock and our caller has to
-- * retry. (Namely, old_jifs and old_count.) So we must treat
-- * jiffies as volatile despite the lock. We read jiffies
-- * before latching the timer count to guarantee that although
-- * the jiffies value might be older than the count (that is,
-- * the counter may underflow between the last point where
-- * jiffies was incremented and the point where we latch the
-- * count), it cannot be newer.
-- */
-- jifs = jiffies;
-- /* read the count */
-- count = inw(MFGPT0_CNT);
--
-- /*
-- * It's possible for count to appear to go the wrong way for this
-- * reason:
-- *
-- * The timer counter underflows, but we haven't handled the resulting
-- * interrupt and incremented jiffies yet.
-- *
-- * Previous attempts to handle these cases intelligently were buggy, so
-- * we just do the simple thing now.
-- */
-- if (count < old_count && jifs == old_jifs)
-- count = old_count;
--
-- old_count = count;
-- old_jifs = jifs;
--
-- spin_unlock_irqrestore(&mfgpt_lock, flags);
--
-- return (cycle_t) (jifs * COMPARE) + count;
-+ return inw(MFGPT1_CNT);
- }
-
--static struct clocksource clocksource_mfgpt = {
-- .name = "mfgpt",
-- .rating = 120, /* Functional for real use, but not desired */
-- .read = mfgpt_read,
-- .mask = CLOCKSOURCE_MASK(32),
--};
--
--int __init init_mfgpt_clocksource(void)
-+int __init init_mfgpt1_clocksource(void)
- {
- if (num_possible_cpus() > 1) /* MFGPT does not scale! */
- return 0;
-
-- return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
-+ enable_mfgpt1_counter();
-+
-+ return clocksource_register_hz(&mfgpt1_clocksource, MFGPT_TICK_RATE(0, 1));
- }
-
--arch_initcall(init_mfgpt_clocksource);
-+arch_initcall(init_mfgpt1_clocksource);
-diff --git a/arch/mips/loongson/common/early_printk.c b/arch/mips/loongson/common/early_printk.c
-index ced461b..89aecbf 100644
---- a/arch/mips/loongson/common/early_printk.c
-+++ b/arch/mips/loongson/common/early_printk.c
-@@ -10,9 +10,13 @@
- * option) any later version.
- */
- #include <linux/serial_reg.h>
-+#include <linux/module.h>
-+#include <asm/bootinfo.h>
-
- #include <loongson.h>
-
-+unsigned long _loongson_uart_base;
-+
- #define PORT(base, offset) (u8 *)(base + offset)
-
- static inline unsigned int serial_in(unsigned char *base, int offset)
-@@ -39,3 +43,29 @@ void prom_putchar(char c)
-
- serial_out(uart_base, UART_TX, c);
- }
-+
-+void __init prom_init_uart_base(void)
-+{
-+ unsigned long loongson_uart_base;
-+
-+ switch (mips_machtype) {
-+ case MACH_LEMOTE_FL2E:
-+ loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8;
-+ break;
-+ case MACH_LEMOTE_FL2F:
-+ case MACH_LEMOTE_LL2F:
-+ loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8;
-+ break;
-+ case MACH_LEMOTE_ML2F7:
-+ case MACH_LEMOTE_YL2F89:
-+ case MACH_DEXXON_GDIUM2F10:
-+ case MACH_LEMOTE_NAS:
-+ default:
-+ /* The CPU provided serial port */
-+ loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
-+ break;
-+ }
-+
-+ _loongson_uart_base =
-+ (unsigned long)ioremap_nocache(loongson_uart_base, 8);
-+}
-diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c
-index ae7af1f..3083978 100644
---- a/arch/mips/loongson/common/init.c
-+++ b/arch/mips/loongson/common/init.c
-@@ -30,8 +30,10 @@ void __init prom_init(void)
- prom_init_env();
- prom_init_memory();
-
-+#ifdef CONFIG_EARLY_PRINTK
- /*init the uart base address */
- prom_init_uart_base();
-+#endif
- }
-
- void __init prom_free_prom_memory(void)
-diff --git a/arch/mips/loongson/common/irq.c b/arch/mips/loongson/common/irq.c
-index 687003b..d62fa77 100644
---- a/arch/mips/loongson/common/irq.c
-+++ b/arch/mips/loongson/common/irq.c
-@@ -10,6 +10,10 @@
- #include <linux/delay.h>
- #include <linux/interrupt.h>
-
-+#include <asm/irq_cpu.h>
-+#include <asm/i8259.h>
-+#include <asm/mipsregs.h>
-+
- #include <loongson.h>
- /*
- * the first level int-handler will jump here if it is a bonito irq
-@@ -48,20 +52,32 @@ asmlinkage void plat_irq_dispatch(void)
- void __init arch_init_irq(void)
- {
- /*
-- * Clear all of the interrupts while we change the able around a bit.
-- * int-handler is not on bootstrap
-+ * The vector addresses of the generic exceptions are in the cached
-+ * address space.
- */
-- clear_c0_status(ST0_IM | ST0_BEV);
-+ clear_c0_status(ST0_BEV);
-
-- /* no steer */
-+ /* No steer */
- LOONGSON_INTSTEER = 0;
-
- /*
-- * Mask out all interrupt by writing "1" to all bit position in
-- * the interrupt reset reg.
-+ * Clear all interrupts
- */
- LOONGSON_INTENCLR = ~0;
-
-+ /*
-+ * Sets the first-level interrupt dispatcher:
-+ *
-+ * 0-15: i8259 interrupt (If CONFIG_I8259 selected)
-+ * 16-23: mips cpu interrupt
-+ * 32-63: bonito irq
-+ */
-+ mips_cpu_irq_init();
-+ bonito_irq_init();
-+#ifdef CONFIG_I8259
-+ init_i8259_irqs();
-+#endif
-+
- /* machine specific irq init */
- mach_init_irq();
- }
-diff --git a/arch/mips/loongson/common/mem.c b/arch/mips/loongson/common/mem.c
-index 8626a42..7aea259 100644
---- a/arch/mips/loongson/common/mem.c
-+++ b/arch/mips/loongson/common/mem.c
-@@ -14,39 +14,24 @@
- #include <mem.h>
- #include <pci.h>
-
-+#define MB(x) ((x) << 20)
-+
- void __init prom_init_memory(void)
- {
-- add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM);
--
-- add_memory_region(memsize << 20, LOONGSON_PCI_MEM_START - (memsize <<
-- 20), BOOT_MEM_RESERVED);
--
-+ add_memory_region(0x0, MB(memsize), BOOT_MEM_RAM);
-+ add_memory_region(MB(memsize), LOONGSON_PCI_MEM_START - MB(memsize), BOOT_MEM_RESERVED);
- #ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
-- {
-- int bit;
--
-- bit = fls(memsize + highmemsize);
-- if (bit != ffs(memsize + highmemsize))
-- bit += 20;
-- else
-- bit = bit + 20 - 1;
--
-- /* set cpu window3 to map CPU to DDR: 2G -> 2G */
-- LOONGSON_ADDRWIN_CPUTODDR(ADDRWIN_WIN3, 0x80000000ul,
-- 0x80000000ul, (1 << bit));
-- mmiowb();
-- }
--#endif /* !CONFIG_CPU_SUPPORTS_ADDRWINCFG */
-+ /* set cpu window3 to map CPU to DDR: 2G -> 0G */
-+ LOONGSON_ADDRWIN_CPUTODDR(ADDRWIN_WIN3, 0x80000000ul, 0, MB(memsize + highmemsize));
-+ mmiowb();
-+#endif
-
- #ifdef CONFIG_64BIT
- if (highmemsize > 0)
-- add_memory_region(LOONGSON_HIGHMEM_START,
-- highmemsize << 20, BOOT_MEM_RAM);
--
-+ add_memory_region(LOONGSON_HIGHMEM_START, MB(highmemsize), BOOT_MEM_RAM);
- add_memory_region(LOONGSON_PCI_MEM_END + 1, LOONGSON_HIGHMEM_START -
-- LOONGSON_PCI_MEM_END - 1, BOOT_MEM_RESERVED);
--
--#endif /* !CONFIG_64BIT */
-+ LOONGSON_PCI_MEM_END - 1, BOOT_MEM_RESERVED);
-+#endif
- }
-
- /* override of arch/mips/mm/cache.c: __uncached_access */
-diff --git a/arch/mips/loongson/common/mtd.c b/arch/mips/loongson/common/mtd.c
-new file mode 100644
-index 0000000..49a57a7
---- /dev/null
-+++ b/arch/mips/loongson/common/mtd.c
-@@ -0,0 +1,91 @@
-+/*
-+ * Driver for flushing/dumping ROM of PMON on loongson family machines
-+ *
-+ * Copyright (C) 2008-2009 Lemote Inc.
-+ * Author: Yan Hua <yanh@lemote.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.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+
-+#include <loongson.h>
-+
-+#define FLASH_PHYS_ADDR LOONGSON_BOOT_BASE
-+#define FLASH_SIZE 0x080000
-+
-+#define FLASH_PARTITION0_ADDR 0x00000000
-+#define FLASH_PARTITION0_SIZE 0x00080000
-+
-+struct map_info flash_map = {
-+ .name = "flash device",
-+ .size = FLASH_SIZE,
-+ .bankwidth = 1,
-+};
-+
-+struct mtd_partition flash_parts[] = {
-+ {
-+ .name = "Bootloader",
-+ .offset = FLASH_PARTITION0_ADDR,
-+ .size = FLASH_PARTITION0_SIZE},
-+};
-+
-+#define PARTITION_COUNT ARRAY_SIZE(flash_parts)
-+
-+static struct mtd_info *mymtd;
-+
-+int __init init_flash(void)
-+{
-+ printk(KERN_NOTICE "flash device: %x at %x\n",
-+ FLASH_SIZE, FLASH_PHYS_ADDR);
-+
-+ flash_map.phys = FLASH_PHYS_ADDR;
-+ flash_map.virt = ioremap(FLASH_PHYS_ADDR, FLASH_SIZE);
-+
-+ if (!flash_map.virt) {
-+ printk(KERN_NOTICE "Failed to ioremap\n");
-+ return -EIO;
-+ }
-+
-+ simple_map_init(&flash_map);
-+
-+ mymtd = do_map_probe("cfi_probe", &flash_map);
-+ if (mymtd) {
-+ add_mtd_partitions(mymtd, flash_parts, PARTITION_COUNT);
-+ printk(KERN_NOTICE "pmon flash device initialized\n");
-+ return 0;
-+ }
-+
-+ iounmap((void *)flash_map.virt);
-+ return -ENXIO;
-+}
-+
-+static void __exit cleanup_flash(void)
-+{
-+ if (mymtd) {
-+ del_mtd_partitions(mymtd);
-+ map_destroy(mymtd);
-+ }
-+ if (flash_map.virt) {
-+ iounmap((void *)flash_map.virt);
-+ flash_map.virt = 0;
-+ }
-+}
-+
-+module_init(init_flash);
-+module_exit(cleanup_flash);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Yanhua <yanh@lemote.com>");
-+MODULE_DESCRIPTION("MTD driver for pmon flushing/dumping");
-diff --git a/arch/mips/loongson/common/pci.c b/arch/mips/loongson/common/pci.c
-index fa77844..a992931 100644
---- a/arch/mips/loongson/common/pci.c
-+++ b/arch/mips/loongson/common/pci.c
-@@ -50,11 +50,11 @@ static void __init setup_pcimap(void)
- LOONGSON_PCIMAP_WIN(0, 0);
-
- /*
-- * PCI-DMA to local mapping: [2G,2G+256M] -> [0M,256M]
-+ * PCI-DMA to local mapping: [2G,4G] -> [0M,2G]
- */
- LOONGSON_PCIBASE0 = 0x80000000ul; /* base: 2G -> mmap: 0M */
-- /* size: 256M, burst transmission, pre-fetch enable, 64bit */
-- LOONGSON_PCI_HIT0_SEL_L = 0xc000000cul;
-+ /* size: 2G, burst transmission, pre-fetch enable, 64bit */
-+ LOONGSON_PCI_HIT0_SEL_L = 0x8000000cul;
- LOONGSON_PCI_HIT0_SEL_H = 0xfffffffful;
- LOONGSON_PCI_HIT1_SEL_L = 0x00000006ul; /* set this BAR as invalid */
- LOONGSON_PCI_HIT1_SEL_H = 0x00000000ul;
-diff --git a/arch/mips/loongson/common/serial.c b/arch/mips/loongson/common/serial.c
-index 5f2b78a..c828600 100644
---- a/arch/mips/loongson/common/serial.c
-+++ b/arch/mips/loongson/common/serial.c
-@@ -10,6 +10,7 @@
- * Author: Wu Zhangjin (wuzhangjin@gmail.com)
- */
-
-+#include <linux/module.h>
- #include <linux/io.h>
- #include <linux/init.h>
- #include <linux/serial_8250.h>
-@@ -19,58 +20,44 @@
- #include <loongson.h>
- #include <machine.h>
-
--#define PORT(int) \
-+#define PORT(int, base_baud, io_type, port) \
- { \
- .irq = int, \
-- .uartclk = 1843200, \
-- .iotype = UPIO_PORT, \
-+ .uartclk = base_baud, \
-+ .iotype = io_type, \
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
- .regshift = 0, \
-+ .iobase = port, \
- }
-
--#define PORT_M(int) \
--{ \
-- .irq = MIPS_CPU_IRQ_BASE + (int), \
-- .uartclk = 3686400, \
-- .iotype = UPIO_MEM, \
-- .membase = (void __iomem *)NULL, \
-- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
-- .regshift = 0, \
--}
--
--static struct plat_serial8250_port uart8250_data[][2] = {
-- [MACH_LOONGSON_UNKNOWN] {},
-- [MACH_LEMOTE_FL2E] {PORT(4), {} },
-- [MACH_LEMOTE_FL2F] {PORT(3), {} },
-- [MACH_LEMOTE_ML2F7] {PORT_M(3), {} },
-- [MACH_LEMOTE_YL2F89] {PORT_M(3), {} },
-- [MACH_DEXXON_GDIUM2F10] {PORT_M(3), {} },
-- [MACH_LEMOTE_NAS] {PORT_M(3), {} },
-- [MACH_LEMOTE_LL2F] {PORT(3), {} },
-- [MACH_LOONGSON_END] {},
-+static struct plat_serial8250_port uart8250_data[] = {
-+ /* ttyS0: cpu_uart0 Yeeloong, Gdium, UNAS, ... */
-+ PORT((MIPS_CPU_IRQ_BASE + 3), 3686400, UPIO_MEM, 0x3f8),
-+ /* ttyS1: sb_uart1 2E */
-+ PORT(4, 1843200, UPIO_PORT, 0x3f8),
-+ /* ttyS2: sb_uart2 fuloong2f */
-+ PORT(3, 1843200, UPIO_PORT, 0x2f8),
-+ {},
- };
-
- static struct platform_device uart8250_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
-+ .dev = {
-+ .platform_data = uart8250_data,
-+ },
- };
-
- static int __init serial_init(void)
- {
-- unsigned char iotype;
--
-- iotype = uart8250_data[mips_machtype][0].iotype;
--
-- if (UPIO_MEM == iotype)
-- uart8250_data[mips_machtype][0].membase =
-- (void __iomem *)_loongson_uart_base;
-- else if (UPIO_PORT == iotype)
-- uart8250_data[mips_machtype][0].iobase =
-- loongson_uart_base - LOONGSON_PCIIO_BASE;
--
-- uart8250_device.dev.platform_data = uart8250_data[mips_machtype];
-+ uart8250_data[0].membase = (void __iomem *)ioremap_nocache(
-+ LOONGSON_LIO1_BASE + uart8250_data[0].iobase, 8);
-
-- return platform_device_register(&uart8250_device);
-+ platform_device_register(&uart8250_device);
-+ return 0;
- }
-
- device_initcall(serial_init);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("liu shiwei <liushiwei@anheng.com.cn>");
-+MODULE_DESCRIPTION("loongson serial");
-diff --git a/arch/mips/loongson/common/time.c b/arch/mips/loongson/common/time.c
-index 262a1f6..eebbeef 100644
---- a/arch/mips/loongson/common/time.c
-+++ b/arch/mips/loongson/common/time.c
-@@ -10,6 +10,8 @@
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-+#include <linux/rtc.h>
-+
- #include <asm/mc146818-time.h>
- #include <asm/time.h>
-
-@@ -24,8 +26,81 @@ void __init plat_time_init(void)
- setup_mfgpt0_timer();
- }
-
-+#ifdef CONFIG_LOONGSON_MC146818
- void read_persistent_clock(struct timespec *ts)
- {
- ts->tv_sec = mc146818_get_cmos_time();
- ts->tv_nsec = 0;
- }
-+#else
-+
-+/* If no CMOS RTC, use the one below */
-+
-+/*
-+ * Cloned from drivers/rtc/hctosys.c
-+ *
-+ * If CONFIG_RTC_HCTOSYS=y is enabled, the system time can be set from the
-+ * hardware clock(when boot and resuming from suspend), this may be also done
-+ * (duplicately) by the timekeeper, which may need to be avoided(TODO).
-+ *
-+ * read_persistent_clock() may be useful in some places, e.g. there is not
-+ * peristent clock in the system, we can use this to recover the system time.
-+ *
-+ * Note: The device indicated by CONFIG_RTC_HCTOSYS_DEVICE must be the one
-+ * created by the RTC driver. Use Gdium as an example, We must disable the
-+ * rt_cmos driver If we want to use the rtc_m41t80 driver for
-+ * CONFIG_RTC_HCTOSYS_DEVICE is configured as /dev/rtc0, if rtc_cmos is
-+ * enabled, rtc_cmos driver will be used, but it is not supported by Gdium.
-+ * So, for Gdium, please ensure "# CONFIG_RTC_DRV_CMOS is not set"
-+ */
-+
-+#ifdef CONFIG_RTC_HCTOSYS
-+void read_persistent_clock(struct timespec *ts)
-+{
-+ int err = -ENODEV;
-+ struct rtc_time tm;
-+ struct rtc_device *rtc;
-+
-+ /* We can not access the RTC device before it is initialized ... */
-+ if (rtc_hctosys_ret != 0) {
-+ ts->tv_sec = 0;
-+ ts->tv_nsec = 0;
-+ return;
-+ }
-+
-+ rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
-+
-+ if (rtc == NULL) {
-+ pr_err("%s: unable to open rtc device (%s)\n",
-+ __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
-+ goto err_open;
-+ }
-+
-+ err = rtc_read_time(rtc, &tm);
-+ if (err) {
-+ dev_err(rtc->dev.parent,
-+ "hctosys: unable to read the hardware clock\n");
-+ goto err_read;
-+
-+ }
-+
-+ err = rtc_valid_tm(&tm);
-+ if (err) {
-+ dev_err(rtc->dev.parent,
-+ "hctosys: invalid date/time\n");
-+ goto err_invalid;
-+ }
-+
-+ ts->tv_nsec = NSEC_PER_SEC >> 1,
-+ rtc_tm_to_time(&tm, &ts->tv_sec);
-+
-+err_invalid:
-+err_read:
-+ rtc_class_close(rtc);
-+
-+err_open:
-+ rtc_hctosys_ret = err;
-+}
-+#endif /* CONFIG_RTC_HCTOSYS */
-+
-+#endif /* !CONFIG_LOONGSON_MC146818 */
-diff --git a/arch/mips/loongson/common/uart_base.c b/arch/mips/loongson/common/uart_base.c
-deleted file mode 100644
-index e192ad0..0000000
---- a/arch/mips/loongson/common/uart_base.c
-+++ /dev/null
-@@ -1,45 +0,0 @@
--/*
-- * Copyright (C) 2009 Lemote Inc.
-- * Author: Wu Zhangjin, wuzhangjin@gmail.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.
-- */
--
--#include <linux/module.h>
--#include <asm/bootinfo.h>
--
--#include <loongson.h>
--
--/* ioremapped */
--unsigned long _loongson_uart_base;
--EXPORT_SYMBOL(_loongson_uart_base);
--/* raw */
--unsigned long loongson_uart_base;
--EXPORT_SYMBOL(loongson_uart_base);
--
--void prom_init_loongson_uart_base(void)
--{
-- switch (mips_machtype) {
-- case MACH_LEMOTE_FL2E:
-- loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8;
-- break;
-- case MACH_LEMOTE_FL2F:
-- case MACH_LEMOTE_LL2F:
-- loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8;
-- break;
-- case MACH_LEMOTE_ML2F7:
-- case MACH_LEMOTE_YL2F89:
-- case MACH_DEXXON_GDIUM2F10:
-- case MACH_LEMOTE_NAS:
-- default:
-- /* The CPU provided serial port */
-- loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
-- break;
-- }
--
-- _loongson_uart_base =
-- (unsigned long)ioremap_nocache(loongson_uart_base, 8);
--}
-diff --git a/arch/mips/loongson/fuloong-2e/irq.c b/arch/mips/loongson/fuloong-2e/irq.c
-index ef5ec8f..232930e 100644
---- a/arch/mips/loongson/fuloong-2e/irq.c
-+++ b/arch/mips/loongson/fuloong-2e/irq.c
-@@ -9,7 +9,6 @@
- */
- #include <linux/interrupt.h>
-
--#include <asm/irq_cpu.h>
- #include <asm/i8259.h>
-
- #include <loongson.h>
-@@ -57,11 +56,6 @@ void __init mach_init_irq(void)
- LOONGSON_INTEDGE = LOONGSON_ICU_SYSTEMERR | LOONGSON_ICU_MASTERERR |
- LOONGSON_ICU_RETRYERR | LOONGSON_ICU_MBOXES;
-
-- /* Sets the first-level interrupt dispatcher. */
-- mips_cpu_irq_init();
-- init_i8259_irqs();
-- bonito_irq_init();
--
- /* bonito irq at IP2 */
- setup_irq(MIPS_CPU_IRQ_BASE + 2, &cascade_irqaction);
- /* 8259 irq at IP5 */
-diff --git a/arch/mips/loongson/gdium/Makefile b/arch/mips/loongson/gdium/Makefile
-new file mode 100644
-index 0000000..f3f4f51
---- /dev/null
-+++ b/arch/mips/loongson/gdium/Makefile
-@@ -0,0 +1,6 @@
-+# Makefile for gdium
-+
-+obj-y += irq.o reset.o platform.o
-+
-+obj-$(CONFIG_MFD_SM501) += sm501-pwm.o
-+obj-$(CONFIG_GDIUM_PWM_CLOCK) += gdium-clock.o
-diff --git a/arch/mips/loongson/gdium/gdium-clock.c b/arch/mips/loongson/gdium/gdium-clock.c
-new file mode 100644
-index 0000000..fdbf42a
---- /dev/null
-+++ b/arch/mips/loongson/gdium/gdium-clock.c
-@@ -0,0 +1,234 @@
-+/*
-+ * Doesn't work really well. When used, the clocksource is producing
-+ * bad timings and the clockevent can't be used (don't have one shot feature
-+ * thus can't switch on the fly and the pwm is initialised too late to be able
-+ * to use it at boot time).
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
-+#include <linux/interrupt.h>
-+#include <linux/delay.h>
-+#include <linux/pwm.h>
-+#include <linux/clocksource.h>
-+#include <linux/debugfs.h>
-+#include <asm/irq_cpu.h>
-+#include <asm/mipsregs.h>
-+#include <asm/mips-boards/bonito64.h>
-+#include <asm/time.h>
-+
-+#include <loongson.h>
-+
-+#define CLOCK_PWM 1
-+#define CLOCK_PWM_FREQ 1500000 /* Freq in Hz */
-+#define CLOCK_LATCH ((CLOCK_PWM_FREQ + HZ/2) / HZ)
-+#define CLOCK_PWM_PERIOD (1000000000/CLOCK_PWM_FREQ) /* period ns */
-+#define CLOCK_PWM_DUTY 50
-+#define CLOCK_PWM_IRQ (MIPS_CPU_IRQ_BASE + 4)
-+
-+static const char drv_name[] = "gdium-clock";
-+
-+static struct pwm_device *clock_pwm;
-+
-+static DEFINE_SPINLOCK(clock_pwm_lock);
-+static uint64_t clock_tick;
-+
-+static irqreturn_t gdium_pwm_clock_interrupt(int irq, void *dev_id)
-+{
-+ struct clock_event_device *cd = dev_id;
-+ unsigned long flag;
-+
-+ spin_lock_irqsave(&clock_pwm_lock, flag);
-+ clock_tick++;
-+ /* wait intn2 to finish */
-+ do {
-+ LOONGSON_INTENCLR = (1 << 13);
-+ } while (LOONGSON_INTISR & (1 << 13));
-+ spin_unlock_irqrestore(&clock_pwm_lock, flag);
-+
-+ if (cd && cd->event_handler)
-+ cd->event_handler(cd);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static cycle_t gdium_pwm_clock_read(struct clocksource *cs)
-+{
-+ unsigned long flag;
-+ uint32_t jifs;
-+ uint64_t ticks;
-+
-+ spin_lock_irqsave(&clock_pwm_lock, flag);
-+ jifs = jiffies;
-+ ticks = clock_tick;
-+ spin_unlock_irqrestore(&clock_pwm_lock, flag);
-+ /* return (cycle_t)ticks; */
-+ return (cycle_t)(CLOCK_LATCH * jifs);
-+}
-+
-+static struct clocksource gdium_pwm_clock_clocksource = {
-+ .name = "gdium_csrc",
-+ .read = gdium_pwm_clock_read,
-+ .mask = CLOCKSOURCE_MASK(64),
-+ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY,
-+ .shift = 20,
-+};
-+
-+/* Debug fs */
-+static int gdium_pwm_clock_show(struct seq_file *s, void *p)
-+{
-+ unsigned long flag;
-+ uint64_t ticks;
-+
-+ spin_lock_irqsave(&clock_pwm_lock, flag);
-+ ticks = clock_tick;
-+ spin_unlock_irqrestore(&clock_pwm_lock, flag);
-+ seq_printf(s, "%lld\n", ticks);
-+ return 0;
-+}
-+
-+static int gdium_pwm_clock_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, gdium_pwm_clock_show, inode->i_private);
-+}
-+
-+static const struct file_operations gdium_pwm_clock_fops = {
-+ .open = gdium_pwm_clock_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+ .owner = THIS_MODULE,
-+};
-+static struct dentry *debugfs_file;
-+
-+static void gdium_pwm_clock_set_mode(enum clock_event_mode mode,
-+ struct clock_event_device *evt)
-+{
-+ /* Nothing to do ... */
-+}
-+
-+static struct clock_event_device gdium_pwm_clock_cevt = {
-+ .name = "gdium_cevt",
-+ .features = CLOCK_EVT_FEAT_PERIODIC,
-+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
-+ .rating = 299,
-+ .irq = CLOCK_PWM_IRQ,
-+ .set_mode = gdium_pwm_clock_set_mode,
-+};
-+
-+static struct platform_device_id platform_device_ids[] = {
-+ {
-+ .name = "gdium-pwmclk",
-+ },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(platform, platform_device_ids);
-+
-+static struct platform_driver gdium_pwm_clock_driver = {
-+ .driver = {
-+ .name = drv_name,
-+ .owner = THIS_MODULE,
-+ },
-+ .id_table = platform_device_ids,
-+};
-+
-+static int gdium_pwm_clock_drvinit(void)
-+{
-+ int ret;
-+ struct clocksource *cs = &gdium_pwm_clock_clocksource;
-+ struct clock_event_device *cd = &gdium_pwm_clock_cevt;
-+ unsigned int cpu = smp_processor_id();
-+
-+ clock_tick = 0;
-+
-+ clock_pwm = pwm_request(CLOCK_PWM, drv_name);
-+ if (clock_pwm == NULL) {
-+ pr_err("unable to request PWM for Gdium clock\n");
-+ return -EBUSY;
-+ }
-+ ret = pwm_config(clock_pwm, CLOCK_PWM_DUTY, CLOCK_PWM_PERIOD);
-+ if (ret) {
-+ pr_err("unable to configure PWM for Gdium clock\n");
-+ goto err_pwm_request;
-+ }
-+ ret = pwm_enable(clock_pwm);
-+ if (ret) {
-+ pr_err("unable to enable PWM for Gdium clock\n");
-+ goto err_pwm_request;
-+ }
-+
-+ cd->cpumask = cpumask_of(cpu);
-+
-+ cd->shift = 22;
-+ cd->mult = div_sc(CLOCK_PWM_FREQ, NSEC_PER_SEC, cd->shift);
-+ cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd);
-+ cd->min_delta_ns = clockevent_delta2ns(0xF, cd);
-+ clockevents_register_device(&gdium_pwm_clock_cevt);
-+
-+ /* SM501 PWM1 connected to intn2 <->ip4 */
-+ LOONGSON_INTPOL = (1 << 13);
-+ LOONGSON_INTEDGE &= ~(1 << 13);
-+ ret = request_irq(CLOCK_PWM_IRQ, gdium_pwm_clock_interrupt, IRQF_DISABLED, drv_name, &gdium_pwm_clock_cevt);
-+ if (ret) {
-+ pr_err("Can't claim irq\n");
-+ goto err_pwm_disable;
-+ }
-+
-+ cs->rating = 200;
-+ cs->mult = clocksource_hz2mult(CLOCK_PWM_FREQ, cs->shift);
-+ ret = clocksource_register(&gdium_pwm_clock_clocksource);
-+ if (ret) {
-+ pr_err("Can't register clocksource\n");
-+ goto err_irq;
-+ }
-+ pr_info("Clocksource registered with shift %d and mult %d\n",
-+ cs->shift, cs->mult);
-+
-+ debugfs_file = debugfs_create_file(drv_name, S_IFREG | S_IRUGO,
-+ NULL, NULL, &gdium_pwm_clock_fops);
-+
-+ return 0;
-+
-+err_irq:
-+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt);
-+err_pwm_disable:
-+ pwm_disable(clock_pwm);
-+err_pwm_request:
-+ pwm_free(clock_pwm);
-+ return ret;
-+}
-+
-+static void gdium_pwm_clock_drvexit(void)
-+{
-+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt);
-+ pwm_disable(clock_pwm);
-+ pwm_free(clock_pwm);
-+}
-+
-+
-+static int __devinit gdium_pwm_clock_init(void)
-+{
-+ int ret = gdium_pwm_clock_drvinit();
-+
-+ if (ret) {
-+ pr_err("Fail to register gdium clock driver\n");
-+ return ret;
-+ }
-+
-+ return platform_driver_register(&gdium_pwm_clock_driver);
-+}
-+
-+static void __exit gdium_pwm_clock_cleanup(void)
-+{
-+ gdium_pwm_clock_drvexit();
-+ platform_driver_unregister(&gdium_pwm_clock_driver);
-+}
-+
-+module_init(gdium_pwm_clock_init);
-+module_exit(gdium_pwm_clock_cleanup);
-+
-+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
-+MODULE_DESCRIPTION("Gdium PWM clock driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:gdium-pwmclk");
-diff --git a/arch/mips/loongson/gdium/irq.c b/arch/mips/loongson/gdium/irq.c
-new file mode 100644
-index 0000000..2415d20
---- /dev/null
-+++ b/arch/mips/loongson/gdium/irq.c
-@@ -0,0 +1,55 @@
-+/*
-+ * Copyright (C) 2007 Lemote Inc.
-+ * Author: Fuxin Zhang, zhangfx@lemote.com
-+ *
-+ * Copyright (c) 2010 yajin <yajin@vm-kernel.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/interrupt.h>
-+#include <linux/module.h>
-+
-+#include <loongson.h>
-+#include <machine.h>
-+
-+#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */
-+#define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */
-+#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */
-+
-+void mach_irq_dispatch(unsigned int pending)
-+{
-+ if (pending & CAUSEF_IP7)
-+ do_IRQ(LOONGSON_TIMER_IRQ);
-+ else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */
-+ do_perfcnt_IRQ();
-+ bonito_irqdispatch();
-+ } else if (pending & CAUSEF_IP3) /* CPU UART */
-+ do_IRQ(LOONGSON_UART_IRQ);
-+#if defined(CONFIG_GDIUM_PWM_CLOCK) || defined(CONFIG_GDIUM_PWM_CLOCK_MODULE)
-+ else if (pending & CAUSEF_IP4) /* SM501 PWM clock */
-+ do_IRQ(MIPS_CPU_IRQ_BASE + 4);
-+#endif
-+ else
-+ spurious_interrupt();
-+}
-+
-+static irqreturn_t ip6_action(int cpl, void *dev_id)
-+{
-+ return IRQ_HANDLED;
-+}
-+
-+struct irqaction ip6_irqaction = {
-+ .handler = ip6_action,
-+ .name = "cascade",
-+ .flags = IRQF_SHARED,
-+};
-+
-+void __init mach_init_irq(void)
-+{
-+ /* setup north bridge irq (bonito) */
-+ setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction);
-+}
-diff --git a/arch/mips/loongson/gdium/platform.c b/arch/mips/loongson/gdium/platform.c
-new file mode 100644
-index 0000000..ffafba4
---- /dev/null
-+++ b/arch/mips/loongson/gdium/platform.c
-@@ -0,0 +1,135 @@
-+/*
-+ * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/pwm_backlight.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-gpio.h>
-+
-+#define GDIUM_GPIO_BASE 224
-+
-+static struct i2c_board_info __initdata sm502dev_i2c_devices[] = {
-+ {
-+ I2C_BOARD_INFO("lm75", 0x48),
-+ },
-+ {
-+ I2C_BOARD_INFO("m41t83", 0x68),
-+ },
-+ {
-+ I2C_BOARD_INFO("gdium-laptop", 0x40),
-+ },
-+};
-+
-+static int sm502dev_backlight_init(struct device *dev)
-+{
-+ /* Add gpio request stuff here */
-+ return 0;
-+}
-+
-+static void sm502dev_backlight_exit(struct device *dev)
-+{
-+ /* Add gpio free stuff here */
-+}
-+
-+static struct platform_pwm_backlight_data backlight_data = {
-+ .pwm_id = 0,
-+ .max_brightness = 15,
-+ .dft_brightness = 8,
-+ .pwm_period_ns = 50000, /* 20 kHz */
-+ .init = sm502dev_backlight_init,
-+ .exit = sm502dev_backlight_exit,
-+};
-+
-+static struct platform_device backlight = {
-+ .name = "pwm-backlight",
-+ .dev = {
-+ .platform_data = &backlight_data,
-+ },
-+ .id = -1,
-+};
-+
-+/*
-+ * Warning this stunt is very dangerous
-+ * as the sm501 gpio have dynamic numbers...
-+ */
-+/* bus 0 is the one for the ST7, DS75 etc... */
-+static struct i2c_gpio_platform_data i2c_gpio0_data = {
-+#if CONFIG_GDIUM_VERSION > 2
-+ .sda_pin = GDIUM_GPIO_BASE + 13,
-+ .scl_pin = GDIUM_GPIO_BASE + 6,
-+#else
-+ .sda_pin = 192+15,
-+ .scl_pin = 192+14,
-+#endif
-+ .udelay = 5,
-+ .timeout = HZ / 10,
-+ .sda_is_open_drain = 0,
-+ .scl_is_open_drain = 0,
-+};
-+
-+static struct platform_device i2c_gpio0_device = {
-+ .name = "i2c-gpio",
-+ .id = 0,
-+ .dev = { .platform_data = &i2c_gpio0_data, },
-+};
-+
-+/* bus 1 is for the CRT/VGA external screen */
-+static struct i2c_gpio_platform_data i2c_gpio1_data = {
-+ .sda_pin = GDIUM_GPIO_BASE + 10,
-+ .scl_pin = GDIUM_GPIO_BASE + 9,
-+ .udelay = 5,
-+ .timeout = HZ / 10,
-+ .sda_is_open_drain = 0,
-+ .scl_is_open_drain = 0,
-+};
-+
-+static struct platform_device i2c_gpio1_device = {
-+ .name = "i2c-gpio",
-+ .id = 1,
-+ .dev = { .platform_data = &i2c_gpio1_data, },
-+};
-+
-+static struct platform_device gdium_clock = {
-+ .name = "gdium-pwmclk",
-+ .id = -1,
-+};
-+
-+static struct platform_device *devices[] __initdata = {
-+ &i2c_gpio0_device,
-+ &i2c_gpio1_device,
-+ &backlight,
-+ &gdium_clock,
-+};
-+
-+static int __init gdium_platform_devices_setup(void)
-+{
-+ int ret;
-+
-+ pr_info("Registering gdium platform devices\n");
-+
-+ ret = i2c_register_board_info(0, sm502dev_i2c_devices,
-+ ARRAY_SIZE(sm502dev_i2c_devices));
-+
-+ if (ret != 0) {
-+ pr_info("Error while registering platform devices: %d\n", ret);
-+ return ret;
-+ }
-+
-+ platform_add_devices(devices, ARRAY_SIZE(devices));
-+
-+ return 0;
-+}
-+
-+/*
-+ * some devices are on the pwm stuff which is behind the mfd which is
-+ * behind the pci bus so arch_initcall can't work because too early
-+ */
-+late_initcall(gdium_platform_devices_setup);
-diff --git a/arch/mips/loongson/gdium/reset.c b/arch/mips/loongson/gdium/reset.c
-new file mode 100644
-index 0000000..8289f95
---- /dev/null
-+++ b/arch/mips/loongson/gdium/reset.c
-@@ -0,0 +1,22 @@
-+/* Board-specific reboot/shutdown routines
-+ *
-+ * Copyright (C) 2010 yajin <yajin@vm-kernel.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+#include <loongson.h>
-+
-+void mach_prepare_shutdown(void)
-+{
-+ LOONGSON_GPIOIE &= ~(1<<1);
-+ LOONGSON_GPIODATA |= (1<<1);
-+}
-+
-+void mach_prepare_reboot(void)
-+{
-+ LOONGSON_GPIOIE &= ~(1<<2);
-+ LOONGSON_GPIODATA &= ~(1<<2);
-+}
-diff --git a/arch/mips/loongson/gdium/sm501-pwm.c b/arch/mips/loongson/gdium/sm501-pwm.c
-new file mode 100644
-index 0000000..5af3b23
---- /dev/null
-+++ b/arch/mips/loongson/gdium/sm501-pwm.c
-@@ -0,0 +1,465 @@
-+/*
-+ * SM501 PWM clock
-+ * Copyright (C) 2009-2010 Arnaud Patard <apatard@mandriva.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.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/pwm.h>
-+#include <linux/sm501.h>
-+#include <linux/sm501-regs.h>
-+#include <linux/debugfs.h>
-+#include <linux/seq_file.h>
-+
-+static const char drv_name[] = "sm501-pwm";
-+
-+#define INPUT_CLOCK 96 /* MHz */
-+#define PWM_COUNT 3
-+
-+#define SM501PWM_HIGH_COUNTER (1<<20)
-+#define SM501PWM_LOW_COUNTER (1<<8)
-+#define SM501PWM_CLOCK_DIVIDE (1>>4)
-+#define SM501PWM_IP (1<<3)
-+#define SM501PWM_I (1<<2)
-+#define SM501PWM_E (1<<0)
-+
-+struct pwm_device {
-+ struct list_head node;
-+ struct device *dev;
-+ void __iomem *regs;
-+ int duty_ns;
-+ int period_ns;
-+ char enabled;
-+ void (*handler)(struct pwm_device *pwm);
-+
-+ const char *label;
-+ unsigned int use_count;
-+ unsigned int pwm_id;
-+};
-+
-+struct sm501pwm_info {
-+ void __iomem *regs;
-+ int irq;
-+ struct resource *res;
-+ struct device *dev;
-+ struct dentry *debugfs;
-+
-+ struct pwm_device pwm[3];
-+};
-+
-+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-+{
-+ unsigned int high, low, divider;
-+ int divider1, divider2;
-+ unsigned long long delay;
-+
-+ if (!pwm || !pwm->regs || period_ns == 0 || duty_ns > period_ns)
-+ return -EINVAL;
-+
-+ /* Get delay
-+ * We're loosing some precision but multiplying then dividing
-+ * will overflow
-+ */
-+ if (period_ns > 1000) {
-+ delay = period_ns / 1000;
-+ delay *= INPUT_CLOCK;
-+ } else {
-+ delay = period_ns * 96;
-+ delay /= 1000;
-+ }
-+
-+ /* Get the number of clock low and high */
-+ high = delay * duty_ns / period_ns;
-+ low = delay - high;
-+
-+ /* Get divider to make 'low' and 'high' fit into 12 bits */
-+ /* No need to say that the divider must be >= 0 */
-+ divider1 = fls(low)-12;
-+ divider2 = fls(high)-12;
-+
-+ if (divider1 < 0)
-+ divider1 = 0;
-+ if (divider2 < 0)
-+ divider2 = 0;
-+
-+ divider = max(divider1, divider2);
-+
-+ low >>= divider;
-+ high >>= divider;
-+
-+ pwm->duty_ns = duty_ns;
-+ pwm->period_ns = period_ns;
-+
-+ writel((high<<20)|(low<<8)|(divider<<4), pwm->regs);
-+ return 0;
-+}
-+EXPORT_SYMBOL(pwm_config);
-+
-+int pwm_enable(struct pwm_device *pwm)
-+{
-+ u32 reg;
-+
-+ if (!pwm)
-+ return -EINVAL;
-+
-+ switch (pwm->pwm_id) {
-+ case 0:
-+ sm501_configure_gpio(pwm->dev->parent, 29, 1);
-+ break;
-+ case 1:
-+ sm501_configure_gpio(pwm->dev->parent, 30, 1);
-+ break;
-+ case 2:
-+ sm501_configure_gpio(pwm->dev->parent, 31, 1);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ reg = readl(pwm->regs);
-+ reg |= (SM501PWM_IP | SM501PWM_E);
-+ writel(reg, pwm->regs);
-+ pwm->enabled = 1;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(pwm_enable);
-+
-+void pwm_disable(struct pwm_device *pwm)
-+{
-+ u32 reg;
-+
-+ if (!pwm)
-+ return;
-+
-+ reg = readl(pwm->regs);
-+ reg &= ~(SM501PWM_IP | SM501PWM_E);
-+ writel(reg, pwm->regs);
-+
-+ switch (pwm->pwm_id) {
-+ case 0:
-+ sm501_configure_gpio(pwm->dev->parent, 29, 0);
-+ break;
-+ case 1:
-+ sm501_configure_gpio(pwm->dev->parent, 30, 0);
-+ break;
-+ case 2:
-+ sm501_configure_gpio(pwm->dev->parent, 31, 0);
-+ break;
-+ default:
-+ break;
-+ }
-+ pwm->enabled = 0;
-+}
-+EXPORT_SYMBOL(pwm_disable);
-+
-+static DEFINE_MUTEX(pwm_lock);
-+static LIST_HEAD(pwm_list);
-+
-+struct pwm_device *pwm_request(int pwm_id, const char *label)
-+{
-+ struct pwm_device *pwm;
-+ int found = 0;
-+
-+ mutex_lock(&pwm_lock);
-+
-+ list_for_each_entry(pwm, &pwm_list, node) {
-+ if (pwm->pwm_id == pwm_id && pwm->use_count == 0) {
-+ pwm->use_count++;
-+ pwm->label = label;
-+ found = 1;
-+ break;
-+ }
-+ }
-+
-+ mutex_unlock(&pwm_lock);
-+
-+ return (found) ? pwm : NULL;
-+}
-+EXPORT_SYMBOL(pwm_request);
-+
-+void pwm_free(struct pwm_device *pwm)
-+{
-+ mutex_lock(&pwm_lock);
-+
-+ if (pwm->use_count) {
-+ pwm->use_count--;
-+ pwm->label = NULL;
-+ } else
-+ dev_warn(pwm->dev, "PWM device already freed\n");
-+
-+ mutex_unlock(&pwm_lock);
-+}
-+EXPORT_SYMBOL(pwm_free);
-+
-+int pwm_int_enable(struct pwm_device *pwm)
-+{
-+ unsigned long conf;
-+
-+ if (!pwm || !pwm->regs || !pwm->handler)
-+ return -EINVAL;
-+
-+ conf = readl(pwm->regs);
-+ conf |= SM501PWM_I;
-+ writel(conf, pwm->regs);
-+ return 0;
-+}
-+EXPORT_SYMBOL(pwm_int_enable);
-+
-+int pwm_int_disable(struct pwm_device *pwm)
-+{
-+ unsigned long conf;
-+
-+ if (!pwm || !pwm->regs || !pwm->handler)
-+ return -EINVAL;
-+
-+ conf = readl(pwm->regs);
-+ conf &= ~SM501PWM_I;
-+ writel(conf, pwm->regs);
-+ return 0;
-+}
-+EXPORT_SYMBOL(pwm_int_disable);
-+
-+int pwm_set_handler(struct pwm_device *pwm,
-+ void (*handler)(struct pwm_device *pwm))
-+{
-+ if (!pwm || !handler)
-+ return -EINVAL;
-+ pwm->handler = handler;
-+ return 0;
-+}
-+EXPORT_SYMBOL(pwm_set_handler);
-+
-+static irqreturn_t sm501pwm_irq(int irq, void *dev_id)
-+{
-+ unsigned long value;
-+ struct sm501pwm_info *info = (struct sm501pwm_info *)dev_id;
-+ struct pwm_device *pwm;
-+ int i;
-+
-+ value = sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 0);
-+
-+ /* Check is the interrupt is for us */
-+ if (value & (1<<22)) {
-+ for (i = 0 ; i < PWM_COUNT ; i++) {
-+ /*
-+ * Find which pwm triggered the interrupt
-+ * and ack
-+ */
-+ value = readl(info->regs + i*4);
-+ if (value & SM501PWM_IP)
-+ writel(value | SM501PWM_IP, info->regs + i*4);
-+
-+ pwm = &info->pwm[i];
-+ if (pwm->handler)
-+ pwm->handler(pwm);
-+ }
-+ return IRQ_HANDLED;
-+ }
-+
-+ return IRQ_NONE;
-+}
-+
-+static void add_pwm(int id, struct sm501pwm_info *info)
-+{
-+ struct pwm_device *pwm = &info->pwm[id];
-+
-+ pwm->use_count = 0;
-+ pwm->pwm_id = id;
-+ pwm->dev = info->dev;
-+ pwm->regs = info->regs + id * 4;
-+
-+ mutex_lock(&pwm_lock);
-+ list_add_tail(&pwm->node, &pwm_list);
-+ mutex_unlock(&pwm_lock);
-+}
-+
-+static void del_pwm(int id, struct sm501pwm_info *info)
-+{
-+ struct pwm_device *pwm = &info->pwm[id];
-+
-+ pwm->use_count = 0;
-+ pwm->pwm_id = -1;
-+ mutex_lock(&pwm_lock);
-+ list_del(&pwm->node);
-+ mutex_unlock(&pwm_lock);
-+}
-+
-+/* Debug fs */
-+static int sm501pwm_show(struct seq_file *s, void *p)
-+{
-+ struct pwm_device *pwm;
-+
-+ mutex_lock(&pwm_lock);
-+ list_for_each_entry(pwm, &pwm_list, node) {
-+ if (pwm->use_count) {
-+ seq_printf(s, "pwm-%d (%12s) %d %d %s\n",
-+ pwm->pwm_id, pwm->label,
-+ pwm->duty_ns, pwm->period_ns,
-+ pwm->enabled ? "on" : "off");
-+ seq_printf(s, " %08x\n", readl(pwm->regs));
-+ }
-+ }
-+ mutex_unlock(&pwm_lock);
-+
-+ return 0;
-+}
-+
-+static int sm501pwm_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, sm501pwm_show, inode->i_private);
-+}
-+
-+static const struct file_operations sm501pwm_fops = {
-+ .open = sm501pwm_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+ .owner = THIS_MODULE,
-+};
-+
-+static int __init sm501pwm_probe(struct platform_device *pdev)
-+{
-+ struct sm501pwm_info *info;
-+ struct device *dev = &pdev->dev;
-+ struct resource *res;
-+ int ret = 0;
-+ int res_len;
-+ int i;
-+
-+ info = kzalloc(sizeof(struct sm501pwm_info), GFP_KERNEL);
-+ if (!info) {
-+ dev_err(dev, "Allocation failure\n");
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+ info->dev = dev;
-+ platform_set_drvdata(pdev, info);
-+
-+ /* Get irq number */
-+ info->irq = platform_get_irq(pdev, 0);
-+ if (!info->irq) {
-+ dev_err(dev, "no irq found\n");
-+ ret = -ENODEV;
-+ goto err_alloc;
-+ }
-+
-+ /* Get regs address */
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (res == NULL) {
-+ dev_err(dev, "No memory resource found\n");
-+ ret = -ENODEV;
-+ goto err_alloc;
-+ }
-+ info->res = res;
-+ res_len = (res->end - res->start)+1;
-+
-+ if (!request_mem_region(res->start, res_len, drv_name)) {
-+ dev_err(dev, "Can't request iomem resource\n");
-+ ret = -EBUSY;
-+ goto err_alloc;
-+ }
-+
-+ info->regs = ioremap(res->start, res_len);
-+ if (!info->regs) {
-+ dev_err(dev, "ioremap failed\n");
-+ ret = -ENOMEM;
-+ goto err_mem;
-+ }
-+
-+ ret = request_irq(info->irq, sm501pwm_irq, IRQF_SHARED, drv_name, info);
-+ if (ret != 0) {
-+ dev_err(dev, "can't get irq\n");
-+ goto err_map;
-+ }
-+
-+
-+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 1);
-+
-+ for (i = 0; i < 3; i++)
-+ add_pwm(i, info);
-+
-+ dev_info(dev, "SM501 PWM Found at %lx irq %d\n",
-+ (unsigned long)info->res->start, info->irq);
-+
-+ info->debugfs = debugfs_create_file("pwm", S_IFREG | S_IRUGO,
-+ NULL, info, &sm501pwm_fops);
-+
-+
-+ return 0;
-+
-+err_map:
-+ iounmap(info->regs);
-+
-+err_mem:
-+ release_mem_region(res->start, res_len);
-+
-+err_alloc:
-+ kfree(info);
-+ platform_set_drvdata(pdev, NULL);
-+err:
-+ return ret;
-+}
-+
-+static int sm501pwm_remove(struct platform_device *pdev)
-+{
-+ struct sm501pwm_info *info = platform_get_drvdata(pdev);
-+ int i;
-+
-+ if (info->debugfs)
-+ debugfs_remove(info->debugfs);
-+
-+ for (i = 0; i < 3; i++) {
-+ pwm_disable(&info->pwm[i]);
-+ del_pwm(i, info);
-+ }
-+
-+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 0);
-+ sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 1<<22);
-+
-+ free_irq(info->irq, info);
-+ iounmap(info->regs);
-+ release_mem_region(info->res->start,
-+ (info->res->end - info->res->start)+1);
-+ kfree(info);
-+ platform_set_drvdata(pdev, NULL);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver sm501pwm_driver = {
-+ .probe = sm501pwm_probe,
-+ .remove = sm501pwm_remove,
-+ .driver = {
-+ .name = drv_name,
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __devinit sm501pwm_init(void)
-+{
-+ return platform_driver_register(&sm501pwm_driver);
-+}
-+
-+static void __exit sm501pwm_cleanup(void)
-+{
-+ platform_driver_unregister(&sm501pwm_driver);
-+}
-+
-+module_init(sm501pwm_init);
-+module_exit(sm501pwm_cleanup);
-+
-+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
-+MODULE_DESCRIPTION("SM501 PWM driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:sm501-pwm");
-diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile
-index 4f9eaa3..f945bd7a 100644
---- a/arch/mips/loongson/lemote-2f/Makefile
-+++ b/arch/mips/loongson/lemote-2f/Makefile
-@@ -2,7 +2,7 @@
- # Makefile for lemote loongson2f family machines
- #
-
--obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o
-+obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o platform.o
-
- #
- # Suspend Support
-diff --git a/arch/mips/loongson/lemote-2f/irq.c b/arch/mips/loongson/lemote-2f/irq.c
-index 6f8682e..2d54037 100644
---- a/arch/mips/loongson/lemote-2f/irq.c
-+++ b/arch/mips/loongson/lemote-2f/irq.c
-@@ -11,9 +11,7 @@
- #include <linux/interrupt.h>
- #include <linux/module.h>
-
--#include <asm/irq_cpu.h>
- #include <asm/i8259.h>
--#include <asm/mipsregs.h>
-
- #include <loongson.h>
- #include <machine.h>
-@@ -117,11 +115,6 @@ void __init mach_init_irq(void)
- LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1;
- LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1);
-
-- /* Sets the first-level interrupt dispatcher. */
-- mips_cpu_irq_init();
-- init_i8259_irqs();
-- bonito_irq_init();
--
- /* setup north bridge irq (bonito) */
- setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction);
- /* setup source bridge irq (i8259) */
-diff --git a/arch/mips/loongson/lemote-2f/platform.c b/arch/mips/loongson/lemote-2f/platform.c
-new file mode 100644
-index 0000000..5316360
---- /dev/null
-+++ b/arch/mips/loongson/lemote-2f/platform.c
-@@ -0,0 +1,48 @@
-+/*
-+ * Copyright (C) 2009 Lemote Inc.
-+ * Author: Wu Zhangjin, wuzhangjin@gmail.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.
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/platform_device.h>
-+
-+#include <asm/bootinfo.h>
-+
-+static struct platform_device yeeloong_pdev = {
-+ .name = "yeeloong_laptop",
-+ .id = -1,
-+};
-+
-+static struct platform_device lynloong_pdev = {
-+ .name = "lynloong_pc",
-+ .id = -1,
-+};
-+
-+static int __init lemote2f_platform_init(void)
-+{
-+ struct platform_device *pdev = NULL;
-+
-+ switch (mips_machtype) {
-+ case MACH_LEMOTE_YL2F89:
-+ pdev = &yeeloong_pdev;
-+ break;
-+ case MACH_LEMOTE_LL2F:
-+ pdev = &lynloong_pdev;
-+ break;
-+ default:
-+ break;
-+
-+ }
-+
-+ if (pdev != NULL)
-+ return platform_device_register(pdev);
-+
-+ return -ENODEV;
-+}
-+
-+arch_initcall(lemote2f_platform_init);
-diff --git a/arch/mips/loongson/lemote-2f/pm.c b/arch/mips/loongson/lemote-2f/pm.c
-index cac4d38..2b6e0ef 100644
---- a/arch/mips/loongson/lemote-2f/pm.c
-+++ b/arch/mips/loongson/lemote-2f/pm.c
-@@ -140,10 +140,10 @@ int wakeup_loongson(void)
-
- void __weak mach_suspend(void)
- {
-- disable_mfgpt0_counter();
-+ disable_mfgpt_counter();
- }
-
- void __weak mach_resume(void)
- {
-- enable_mfgpt0_counter();
-+ enable_mfgpt_counter();
- }
-diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
-index 0b4e2e3..60fad2c 100644
---- a/arch/mips/math-emu/cp1emu.c
-+++ b/arch/mips/math-emu/cp1emu.c
-@@ -7,6 +7,9 @@
- * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000 MIPS Technologies, Inc.
- *
-+ * Loongson instruction support
-+ * Copyright (C) 2011 Mark H Weaver <mhw@netris.org>
-+ *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
-@@ -58,6 +61,14 @@
- #endif
- #define __mips 4
-
-+#ifdef __loongson_fp
-+#undef __loongson_fp
-+#endif
-+#if __mips >= 4 && __mips != 32
-+/* Include support for Loongson floating point instructions */
-+#define __loongson_fp 1
-+#endif
-+
- /* Function which emulates a floating point instruction. */
-
- static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
-@@ -67,6 +78,10 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
- static int fpux_emu(struct pt_regs *,
- struct mips_fpu_struct *, mips_instruction, void *__user *);
- #endif
-+#ifdef __loongson_fp
-+static int loongson_spec2_emu(struct pt_regs *,
-+ struct mips_fpu_struct *, mips_instruction, void *__user *);
-+#endif
-
- /* Further private data for which no space exists in mips_fpu_struct */
-
-@@ -896,6 +911,14 @@ static inline int cop1_64bit(struct pt_regs *xcp)
- #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x)
- #define DPTOREG(dp, x) DITOREG((dp).bits, x)
-
-+/* Support for Loongson paired single floating-point format */
-+#define PSIFROMREG(si1, si2, x) ({ u64 di; DIFROMREG(di, x); \
-+ (si1) = (u32)di; (si2) = (u32)(di >> 32); })
-+#define PSITOREG(si1, si2, x) DITOREG((si1) | ((u64)(si2) << 32), x)
-+
-+#define PSPFROMREG(sp1, sp2, x) PSIFROMREG((sp1).bits, (sp2).bits, x)
-+#define PSPTOREG(sp1, sp2, x) PSITOREG((sp1).bits, (sp2).bits, x)
-+
- /*
- * Emulate the single floating point instruction pointed at by EPC.
- * Two instructions if the instruction is in a branch delay slot.
-@@ -1291,6 +1314,15 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- break;
- #endif
-
-+#ifdef __loongson_fp
-+ case spec2_op:{
-+ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr);
-+ if (sig)
-+ return sig;
-+ break;
-+ }
-+#endif
-+
- default:
- sigill:
- return SIGILL;
-@@ -1370,6 +1402,172 @@ DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, );
- DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
- DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
-
-+#ifdef __loongson_fp
-+static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
-+ mips_instruction ir, void *__user *fault_addr)
-+{
-+ int rfmt; /* resulting format */
-+ unsigned rcsr = 0; /* resulting csr */
-+ union {
-+ ieee754dp d;
-+ struct {
-+ ieee754sp s;
-+ ieee754sp s2;
-+ };
-+ } rv; /* resulting value */
-+
-+ /* XXX maybe add a counter for loongson spec2 fp instructions? */
-+ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */
-+
-+ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
-+ case s_fmt:{
-+ ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
-+ ieee754sp fd, fs, ft;
-+
-+ switch (MIPSInst_FUNC(ir)) {
-+ case loongson_madd_op:
-+ handler = fpemu_sp_madd;
-+ goto scoptop;
-+ case loongson_msub_op:
-+ handler = fpemu_sp_msub;
-+ goto scoptop;
-+ case loongson_nmadd_op:
-+ handler = fpemu_sp_nmadd;
-+ goto scoptop;
-+ case loongson_nmsub_op:
-+ handler = fpemu_sp_nmsub;
-+ goto scoptop;
-+
-+ scoptop:
-+ SPFROMREG(fd, MIPSInst_FD(ir));
-+ SPFROMREG(fs, MIPSInst_FS(ir));
-+ SPFROMREG(ft, MIPSInst_FT(ir));
-+ rv.s = (*handler) (fd, fs, ft);
-+
-+ copcsr:
-+ if (ieee754_cxtest(IEEE754_INEXACT))
-+ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
-+ if (ieee754_cxtest(IEEE754_UNDERFLOW))
-+ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
-+ if (ieee754_cxtest(IEEE754_OVERFLOW))
-+ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
-+ if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
-+ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
-+
-+ break;
-+
-+ default:
-+ return SIGILL;
-+ }
-+ break;
-+ }
-+
-+ case d_fmt:{
-+ ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);
-+ ieee754dp fd, fs, ft;
-+
-+ switch (MIPSInst_FUNC(ir)) {
-+ case loongson_madd_op:
-+ handler = fpemu_dp_madd;
-+ goto dcoptop;
-+ case loongson_msub_op:
-+ handler = fpemu_dp_msub;
-+ goto dcoptop;
-+ case loongson_nmadd_op:
-+ handler = fpemu_dp_nmadd;
-+ goto dcoptop;
-+ case loongson_nmsub_op:
-+ handler = fpemu_dp_nmsub;
-+ goto dcoptop;
-+
-+ dcoptop:
-+ DPFROMREG(fd, MIPSInst_FD(ir));
-+ DPFROMREG(fs, MIPSInst_FS(ir));
-+ DPFROMREG(ft, MIPSInst_FT(ir));
-+ rv.d = (*handler) (fd, fs, ft);
-+ goto copcsr;
-+
-+ default:
-+ return SIGILL;
-+ }
-+ break;
-+ }
-+
-+ case ps_fmt:{
-+ ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
-+ struct _ieee754_csr ieee754_csr_save;
-+ ieee754sp fd1, fs1, ft1;
-+ ieee754sp fd2, fs2, ft2;
-+
-+ switch (MIPSInst_FUNC(ir)) {
-+ case loongson_madd_op:
-+ handler = fpemu_sp_madd;
-+ goto pscoptop;
-+ case loongson_msub_op:
-+ handler = fpemu_sp_msub;
-+ goto pscoptop;
-+ case loongson_nmadd_op:
-+ handler = fpemu_sp_nmadd;
-+ goto pscoptop;
-+ case loongson_nmsub_op:
-+ handler = fpemu_sp_nmsub;
-+ goto pscoptop;
-+
-+ pscoptop:
-+ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir));
-+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
-+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
-+ rv.s = (*handler) (fd1, fs1, ft1);
-+ ieee754_csr_save = ieee754_csr;
-+ rv.s2 = (*handler) (fd2, fs2, ft2);
-+ ieee754_csr.cx |= ieee754_csr_save.cx;
-+ ieee754_csr.sx |= ieee754_csr_save.sx;
-+ goto copcsr;
-+
-+ default:
-+ return SIGILL;
-+ }
-+ break;
-+ }
-+
-+ default:
-+ return SIGILL;
-+ }
-+
-+ /*
-+ * Update the fpu CSR register for this operation.
-+ * If an exception is required, generate a tidy SIGFPE exception,
-+ * without updating the result register.
-+ * Note: cause exception bits do not accumulate, they are rewritten
-+ * for each op; only the flag/sticky bits accumulate.
-+ */
-+ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
-+ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
-+ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */
-+ return SIGFPE;
-+ }
-+
-+ /*
-+ * Now we can safely write the result back to the register file.
-+ */
-+ switch (rfmt) {
-+ case d_fmt:
-+ DPTOREG(rv.d, MIPSInst_FD(ir));
-+ break;
-+ case s_fmt:
-+ SPTOREG(rv.s, MIPSInst_FD(ir));
-+ break;
-+ case ps_fmt:
-+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
-+ break;
-+ default:
-+ return SIGILL;
-+ }
-+
-+ return 0;
-+}
-+#endif
-+
- static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- mips_instruction ir, void *__user *fault_addr)
- {
-@@ -1463,7 +1661,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- break;
-
- default:
-- return SIGILL;
-+ goto SIGILL_unless_prefx_op;
- }
- break;
- }
-@@ -1533,7 +1731,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- goto copcsr;
-
- default:
-- return SIGILL;
-+ goto SIGILL_unless_prefx_op;
- }
- break;
- }
-@@ -1546,6 +1744,11 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- break;
-
- default:
-+ SIGILL_unless_prefx_op:
-+ if (MIPSInst_FUNC(ir) == prefx_op) {
-+ /* ignore prefx operation */
-+ break;
-+ }
- return SIGILL;
- }
-
-@@ -1566,7 +1769,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- unsigned cond;
- union {
- ieee754dp d;
-- ieee754sp s;
-+ struct {
-+ ieee754sp s;
-+#ifdef __loongson_fp
-+ ieee754sp s2; /* for Loongson paired singles */
-+#endif
-+ };
- int w;
- #ifdef __mips64
- s64 l;
-@@ -1638,7 +1846,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- case fmov_op:
- /* an easy one */
- SPFROMREG(rv.s, MIPSInst_FS(ir));
-- goto copcsr;
-+ break;
-
- /* binary op on handler */
- scopbop:
-@@ -1825,7 +2033,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- case fmov_op:
- /* an easy one */
- DPFROMREG(rv.d, MIPSInst_FS(ir));
-- goto copcsr;
-+ break;
-
- /* binary op on handler */
- dcopbop:{
-@@ -1936,6 +2144,83 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- break;
- }
-
-+#ifdef __loongson_fp
-+ case ps_fmt:{ /* 6 */
-+ /* Support for Loongson paired single fp instructions */
-+ union {
-+ ieee754sp(*b) (ieee754sp, ieee754sp);
-+ ieee754sp(*u) (ieee754sp);
-+ } handler;
-+
-+ switch (MIPSInst_FUNC(ir)) {
-+ /* binary ops */
-+ case fadd_op:
-+ handler.b = ieee754sp_add;
-+ goto pscopbop;
-+ case fsub_op:
-+ handler.b = ieee754sp_sub;
-+ goto pscopbop;
-+ case fmul_op:
-+ handler.b = ieee754sp_mul;
-+ goto pscopbop;
-+
-+ /* unary ops */
-+ case fabs_op:
-+ handler.u = ieee754sp_abs;
-+ goto pscopuop;
-+ case fneg_op:
-+ handler.u = ieee754sp_neg;
-+ goto pscopuop;
-+ case fmov_op:
-+ /* an easy one */
-+ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir));
-+ break;
-+
-+ pscopbop: /* paired binary op handler */
-+ {
-+ struct _ieee754_csr ieee754_csr_save;
-+ ieee754sp fs1, ft1;
-+ ieee754sp fs2, ft2;
-+
-+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
-+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
-+ rv.s = (*handler.b) (fs1, ft1);
-+ ieee754_csr_save = ieee754_csr;
-+ rv.s2 = (*handler.b) (fs2, ft2);
-+ ieee754_csr.cx |= ieee754_csr_save.cx;
-+ ieee754_csr.sx |= ieee754_csr_save.sx;
-+ goto copcsr;
-+ }
-+ pscopuop: /* paired unary op handler */
-+ {
-+ struct _ieee754_csr ieee754_csr_save;
-+ ieee754sp fs1;
-+ ieee754sp fs2;
-+
-+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
-+ rv.s = (*handler.u) (fs1);
-+ ieee754_csr_save = ieee754_csr;
-+ rv.s2 = (*handler.u) (fs2);
-+ ieee754_csr.cx |= ieee754_csr_save.cx;
-+ ieee754_csr.sx |= ieee754_csr_save.sx;
-+ goto copcsr;
-+ }
-+ break;
-+
-+ default:
-+ if (MIPSInst_FUNC(ir) >= fcmp_op) {
-+ /* Loongson fp hardware handles all
-+ cases of fp compare insns, so we
-+ shouldn't have to */
-+ printk ("Loongson paired-single fp compare"
-+ " unimplemented in cp1emu.c\n");
-+ }
-+ return SIGILL;
-+ }
-+ break;
-+ }
-+#endif
-+
- case w_fmt:{
- ieee754sp fs;
-
-@@ -2025,6 +2310,11 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- DITOREG(rv.l, MIPSInst_FD(ir));
- break;
- #endif
-+#ifdef __loongson_fp
-+ case ps_fmt:
-+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
-+ break;
-+#endif
- default:
- return SIGILL;
- }
-diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c
-index 44b6dff..e782fae 100644
---- a/arch/mips/mm/dma-default.c
-+++ b/arch/mips/mm/dma-default.c
-@@ -336,7 +336,7 @@ int mips_dma_supported(struct device *dev, u64 mask)
- return plat_dma_supported(dev, mask);
- }
-
--void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-+void mips_dma_cache_sync(struct device *dev, void *vaddr, size_t size,
- enum dma_data_direction direction)
- {
- BUG_ON(direction == DMA_NONE);
-@@ -345,8 +345,6 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
- __dma_sync_virtual(vaddr, size, direction);
- }
-
--EXPORT_SYMBOL(dma_cache_sync);
--
- static struct dma_map_ops mips_default_dma_map_ops = {
- .alloc = mips_dma_alloc_coherent,
- .free = mips_dma_free_coherent,
-diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
-index 137f2a6..b9845dc 100644
---- a/arch/mips/pci/Makefile
-+++ b/arch/mips/pci/Makefile
-@@ -29,6 +29,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o
- obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o
- obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o
- obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o
-+obj-$(CONFIG_DEXXON_GDIUM) += fixup-gdium.o ops-loongson2.o
- obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o
- obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o
- obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
-diff --git a/arch/mips/pci/fixup-gdium.c b/arch/mips/pci/fixup-gdium.c
-new file mode 100644
-index 0000000..b296220
---- /dev/null
-+++ b/arch/mips/pci/fixup-gdium.c
-@@ -0,0 +1,90 @@
-+/*
-+ * Copyright (C) 2010 yajin <yajin@vm-kernel.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/pci.h>
-+
-+#include <loongson.h>
-+/*
-+ * http://www.pcidatabase.com
-+ * GDIUM has different PCI mapping
-+ * slot 13 (0x1814/0x0301) -> RaLink rt2561 Wireless-G PCI
-+ * slog 14 (0x126f/0x0501) -> sm501
-+ * slot 15 (0x1033/0x0035) -> NEC Dual OHCI controllers
-+ * plus Single EHCI controller
-+ * slot 16 (0x10ec/0x8139) -> Realtek 8139c
-+ * slot 17 (0x1033/0x00e0) -> NEC USB 2.0 Host Controller
-+ */
-+
-+#undef INT_IRQA
-+#undef INT_IRQB
-+#undef INT_IRQC
-+#undef INT_IRQD
-+#define INT_IRQA 36
-+#define INT_IRQB 37
-+#define INT_IRQC 38
-+#define INT_IRQD 39
-+
-+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-+{
-+ int irq = 0;
-+
-+ switch (slot) {
-+ case 13:
-+ irq = INT_IRQC + ((pin - 1) & 3);
-+ break;
-+ case 14:
-+ irq = INT_IRQA;
-+ break;
-+ case 15:
-+#if CONFIG_GDIUM_VERSION > 2
-+ irq = INT_IRQB;
-+#else
-+ irq = INT_IRQA + ((pin - 1) & 3);
-+#endif
-+ break;
-+ case 16:
-+ irq = INT_IRQD;
-+ break;
-+#if CONFIG_GDIUM_VERSION > 2
-+ case 17:
-+ irq = INT_IRQC;
-+ break;
-+#endif
-+ default:
-+ pr_info(" strange pci slot number %d on gdium.\n", slot);
-+ break;
-+ }
-+ return irq;
-+}
-+
-+/* Do platform specific device initialization at pci_enable_device() time */
-+int pcibios_plat_dev_init(struct pci_dev *dev)
-+{
-+ return 0;
-+}
-+
-+/* Fixups for the USB host controllers */
-+static void __init gdium_usb_host_fixup(struct pci_dev *dev)
-+{
-+ unsigned int val;
-+ pci_read_config_dword(dev, 0xe0, &val);
-+#if CONFIG_GDIUM_VERSION > 2
-+ pci_write_config_dword(dev, 0xe0, (val & ~3) | 0x3);
-+#else
-+ pci_write_config_dword(dev, 0xe0, (val & ~7) | 0x5);
-+ pci_write_config_dword(dev, 0xe4, 1<<5);
-+#endif
-+}
-+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,
-+ gdium_usb_host_fixup);
-+#if CONFIG_GDIUM_VERSION > 2
-+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_CT_65550,
-+ gdium_usb_host_fixup);
-+#endif
-diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S
-index 32a7c82..7e0277a 100644
---- a/arch/mips/power/hibernate.S
-+++ b/arch/mips/power/hibernate.S
-@@ -43,7 +43,6 @@ LEAF(swsusp_arch_resume)
- bne t1, t3, 1b
- PTR_L t0, PBE_NEXT(t0)
- bnez t0, 0b
-- jal local_flush_tlb_all /* Avoid TLB mismatch after kernel resume */
- PTR_LA t0, saved_regs
- PTR_L ra, PT_R31(t0)
- PTR_L sp, PT_R29(t0)
-diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
-index 0448860..fa7cfab 100644
---- a/drivers/ata/pata_cs5536.c
-+++ b/drivers/ata/pata_cs5536.c
-@@ -46,8 +46,6 @@ static int use_msr;
- module_param_named(msr, use_msr, int, 0644);
- MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
- #else
--#undef rdmsr /* avoid accidental MSR usage on, e.g. x86-64 */
--#undef wrmsr
- #define rdmsr(x, y, z) do { } while (0)
- #define wrmsr(x, y, z) do { } while (0)
- #define use_msr 0
-diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index f722001..5af02de 100644
---- a/drivers/hid/Kconfig
-+++ b/drivers/hid/Kconfig
-@@ -786,6 +786,13 @@ config HID_ZYDACRON
- ---help---
- Support for Zydacron remote control.
-
-+config HID_GDIUM
-+ bool "Gdium Fn keys support" if EMBEDDED
-+ depends on USB_HID && DEXXON_GDIUM
-+ default !EMBEDDED
-+ ---help---
-+ Support for Functions keys available on Gdiums.
-+
- config HID_SENSOR_HUB
- tristate "HID Sensors framework support"
- depends on HID
-diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index 30e4431..e41ca68 100644
---- a/drivers/hid/Makefile
-+++ b/drivers/hid/Makefile
-@@ -115,6 +115,7 @@ obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
- obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
- obj-$(CONFIG_HID_WACOM) += hid-wacom.o
- obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
-+obj-$(CONFIG_HID_GDIUM) += hid-gdium.o
- obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
- obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
-
-diff --git a/drivers/hid/hid-gdium.c b/drivers/hid/hid-gdium.c
-new file mode 100644
-index 0000000..67cc095
---- /dev/null
-+++ b/drivers/hid/hid-gdium.c
-@@ -0,0 +1,210 @@
-+/*
-+ * hid-gdium -- Gdium laptop function keys
-+ *
-+ * Arnaud Patard <apatard@mandriva.com>
-+ *
-+ * Based on hid-apple.c
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+
-+#include <linux/device.h>
-+#include <linux/hid.h>
-+#include <linux/module.h>
-+#include <linux/usb.h>
-+
-+#include "hid-ids.h"
-+
-+#define GDIUM_FN_ON 1
-+
-+static int fnmode = GDIUM_FN_ON;
-+module_param(fnmode, int, 0644);
-+MODULE_PARM_DESC(fnmode, "Mode of fn key on Gdium (0 = disabled, 1 = Enabled)");
-+
-+struct gdium_data {
-+ unsigned int fn_on;
-+};
-+
-+
-+struct gdium_key_translation {
-+ u16 from;
-+ u16 to;
-+};
-+
-+static struct gdium_key_translation gdium_fn_keys[] = {
-+ { KEY_F1, KEY_CAMERA },
-+ { KEY_F2, KEY_CONNECT },
-+ { KEY_F3, KEY_MUTE },
-+ { KEY_F4, KEY_VOLUMEUP},
-+ { KEY_F5, KEY_VOLUMEDOWN },
-+ { KEY_F6, KEY_SWITCHVIDEOMODE },
-+ { KEY_F7, KEY_F19 }, /* F7+12. Have to use existant keycodes */
-+ { KEY_F8, KEY_BRIGHTNESSUP },
-+ { KEY_F9, KEY_BRIGHTNESSDOWN },
-+ { KEY_F10, KEY_SLEEP },
-+ { KEY_F11, KEY_PROG1 },
-+ { KEY_F12, KEY_PROG2 },
-+ { KEY_UP, KEY_PAGEUP },
-+ { KEY_DOWN, KEY_PAGEDOWN },
-+ { KEY_INSERT, KEY_NUMLOCK },
-+ { KEY_DELETE, KEY_SCROLLLOCK },
-+ { KEY_T, KEY_STOPCD },
-+ { KEY_F, KEY_PREVIOUSSONG },
-+ { KEY_H, KEY_NEXTSONG },
-+ { KEY_G, KEY_PLAYPAUSE },
-+ { }
-+};
-+
-+static struct gdium_key_translation *gdium_find_translation(
-+ struct gdium_key_translation *table, u16 from)
-+{
-+ struct gdium_key_translation *trans;
-+
-+ /* Look for the translation */
-+ for (trans = table; trans->from; trans++)
-+ if (trans->from == from)
-+ return trans;
-+ return NULL;
-+}
-+
-+static int hidinput_gdium_event(struct hid_device *hid, struct input_dev *input,
-+ struct hid_usage *usage, __s32 value)
-+{
-+ struct gdium_data *data = hid_get_drvdata(hid);
-+ struct gdium_key_translation *trans;
-+ int do_translate;
-+
-+ if (usage->type != EV_KEY)
-+ return 0;
-+
-+ if ((usage->code == KEY_FN)) {
-+ data->fn_on = !!value;
-+ input_event(input, usage->type, usage->code, value);
-+ return 1;
-+ }
-+
-+ if (fnmode) {
-+ trans = gdium_find_translation(gdium_fn_keys, usage->code);
-+ if (trans) {
-+ do_translate = data->fn_on;
-+ if (do_translate) {
-+ input_event(input, usage->type, trans->to, value);
-+ return 1;
-+ }
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int gdium_input_event(struct hid_device *hdev, struct hid_field *field,
-+ struct hid_usage *usage, __s32 value)
-+{
-+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || !usage->type)
-+ return 0;
-+
-+ if (hidinput_gdium_event(hdev, field->hidinput->input, usage, value))
-+ return 1;
-+
-+ return 0;
-+}
-+
-+
-+static void gdium_input_setup(struct input_dev *input)
-+{
-+ struct gdium_key_translation *trans;
-+
-+ set_bit(KEY_NUMLOCK, input->keybit);
-+
-+ /* Enable all needed keys */
-+ for (trans = gdium_fn_keys; trans->from; trans++)
-+ set_bit(trans->to, input->keybit);
-+}
-+
-+static int gdium_input_mapping(struct hid_device *hdev, struct hid_input *hi,
-+ struct hid_field *field, struct hid_usage *usage,
-+ unsigned long **bit, int *max)
-+{
-+ if (((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD)
-+ && ((usage->hid & HID_USAGE) == 0x82)) {
-+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
-+ gdium_input_setup(hi->input);
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+static int gdium_input_probe(struct hid_device *hdev, const struct hid_device_id *id)
-+{
-+ struct gdium_data *data;
-+ int ret;
-+
-+ data = kzalloc(sizeof(*data), GFP_KERNEL);
-+ if (!data) {
-+ dev_err(&hdev->dev, "can't alloc gdium keyboard data\n");
-+ return -ENOMEM;
-+ }
-+
-+ hid_set_drvdata(hdev, data);
-+
-+ ret = hid_parse(hdev);
-+ if (ret) {
-+ dev_err(&hdev->dev, "parse failed\n");
-+ goto err_free;
-+ }
-+
-+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-+ if (ret) {
-+ dev_err(&hdev->dev, "hw start failed\n");
-+ goto err_free;
-+ }
-+
-+ return 0;
-+err_free:
-+ kfree(data);
-+ return ret;
-+}
-+static void gdium_input_remove(struct hid_device *hdev)
-+{
-+ hid_hw_stop(hdev);
-+ kfree(hid_get_drvdata(hdev));
-+}
-+
-+static const struct hid_device_id gdium_input_devices[] = {
-+ { HID_USB_DEVICE(USB_VENDOR_ID_GDIUM, USB_DEVICE_ID_GDIUM) },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(hid, gdium_input_devices);
-+
-+static struct hid_driver gdium_input_driver = {
-+ .name = "gdium-fnkeys",
-+ .id_table = gdium_input_devices,
-+ .probe = gdium_input_probe,
-+ .remove = gdium_input_remove,
-+ .event = gdium_input_event,
-+ .input_mapping = gdium_input_mapping,
-+};
-+
-+static int gdium_input_init(void)
-+{
-+ int ret;
-+
-+ ret = hid_register_driver(&gdium_input_driver);
-+ if (ret)
-+ pr_err("can't register gdium keyboard driver\n");
-+
-+ return ret;
-+}
-+static void gdium_input_exit(void)
-+{
-+ hid_unregister_driver(&gdium_input_driver);
-+}
-+
-+module_init(gdium_input_init);
-+module_exit(gdium_input_exit);
-+MODULE_LICENSE("GPL");
-+
-diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
-index 91bc66b..49f06b8 100644
---- a/drivers/hid/hid-ids.h
-+++ b/drivers/hid/hid-ids.h
-@@ -961,6 +961,9 @@
- #define USB_VENDOR_ID_ZYTRONIC 0x14c8
- #define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005
-
-+#define USB_VENDOR_ID_GDIUM 0x04B4
-+#define USB_DEVICE_ID_GDIUM 0xe001
-+
- #define USB_VENDOR_ID_PRIMAX 0x0461
- #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
-
-diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
-index c5eec02..9e4eb1d 100644
---- a/drivers/i2c/busses/Kconfig
-+++ b/drivers/i2c/busses/Kconfig
-@@ -1002,7 +1002,7 @@ config SCx200_I2C_SDA
-
- config SCx200_ACB
- tristate "Geode ACCESS.bus support"
-- depends on X86_32 && PCI
-+ depends on PCI
- help
- Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
- SC1100 processors and the CS5535 and CS5536 Geode companion devices.
-diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
-index 376f2dc..b576801 100644
---- a/drivers/ide/ide-iops.c
-+++ b/drivers/ide/ide-iops.c
-@@ -27,6 +27,10 @@
- #include <asm/uaccess.h>
- #include <asm/io.h>
-
-+#ifdef CONFIG_LEMOTE_MACH2F
-+#include <asm/bootinfo.h>
-+#endif
-+
- void SELECT_MASK(ide_drive_t *drive, int mask)
- {
- const struct ide_port_ops *port_ops = drive->hwif->port_ops;
-@@ -300,6 +304,11 @@ void ide_check_nien_quirk_list(ide_drive_t *drive)
- {
- const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
-
-+#ifdef CONFIG_LEMOTE_MACH2F
-+ if (mips_machtype != MACH_LEMOTE_YL2F89)
-+ return;
-+#endif
-+
- for (list = nien_quirk_list; *list != NULL; list++)
- if (strstr(m, *list) != NULL) {
- drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK;
-diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
-index e7dc441..124e8c3 100644
---- a/drivers/mfd/sm501.c
-+++ b/drivers/mfd/sm501.c
-@@ -58,7 +58,7 @@ struct sm501_gpio {
- struct sm501_gpio {
- /* no gpio support, empty definition for sm501_devdata. */
- };
--#endif
-+#endif /* CONFIG_MFD_SM501_GPIO */
-
- struct sm501_devdata {
- spinlock_t reg_lock;
-@@ -1135,6 +1135,22 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm)
- {
- return sm->gpio.registered;
- }
-+
-+void sm501_configure_gpio(struct device *dev, unsigned int gpio, unsigned
-+ char mode)
-+{
-+ unsigned long set, reg, offset = gpio;
-+
-+ if (offset >= 32) {
-+ reg = SM501_GPIO63_32_CONTROL;
-+ offset = gpio - 32;
-+ } else
-+ reg = SM501_GPIO31_0_CONTROL;
-+
-+ set = mode ? 1 << offset : 0;
-+
-+ sm501_modify_reg(dev, reg, set, 0);
-+}
- #else
- static inline int sm501_register_gpio(struct sm501_devdata *sm)
- {
-@@ -1154,7 +1170,13 @@ static inline int sm501_gpio_isregistered(struct sm501_devdata *sm)
- {
- return 0;
- }
--#endif
-+
-+void sm501_configure_gpio(struct device *dev, unsigned int gpio,
-+ unsigned char mode)
-+{
-+}
-+#endif /* CONFIG_MFD_SM501_GPIO */
-+EXPORT_SYMBOL_GPL(sm501_configure_gpio);
-
- static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm,
- struct sm501_platdata_gpio_i2c *iic)
-@@ -1209,6 +1231,20 @@ static int sm501_register_gpio_i2c(struct sm501_devdata *sm,
- return 0;
- }
-
-+/* register sm501 PWM device */
-+static int sm501_register_pwm(struct sm501_devdata *sm)
-+{
-+ struct platform_device *pdev;
-+
-+ pdev = sm501_create_subdev(sm, "sm501-pwm", 2, 0);
-+ if (!pdev)
-+ return -ENOMEM;
-+ sm501_create_subio(sm, &pdev->resource[0], 0x10020, 0xC);
-+ sm501_create_irq(sm, &pdev->resource[1]);
-+
-+ return sm501_register_device(sm, pdev);
-+}
-+
- /* sm501_dbg_regs
- *
- * Debug attribute to attach to parent device to show core registers
-@@ -1367,6 +1403,8 @@ static int sm501_init_dev(struct sm501_devdata *sm)
- sm501_register_uart(sm, idata->devices);
- if (idata->devices & SM501_USE_GPIO)
- sm501_register_gpio(sm);
-+ if (idata->devices & SM501_USE_PWM)
-+ sm501_register_pwm(sm);
- }
-
- if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
-@@ -1553,10 +1591,15 @@ static struct sm501_initdata sm501_pci_initdata = {
- .devices = SM501_USE_ALL,
-
- /* Errata AB-3 says that 72MHz is the fastest available
-- * for 33MHZ PCI with proper bus-mastering operation */
--
-+ * for 33MHZ PCI with proper bus-mastering operation
-+ * For gdium, it works under 84&112M clock freq.*/
-+#ifdef CONFIG_DEXXON_GDIUM
-+ .mclk = 84 * MHZ,
-+ .m1xclk = 112 * MHZ,
-+#else
- .mclk = 72 * MHZ,
- .m1xclk = 144 * MHZ,
-+#endif
- };
-
- static struct sm501_platdata_fbsub sm501_pdata_fbsub = {
-diff --git a/drivers/net/titan_ge.c b/drivers/net/titan_ge.c
-new file mode 100644
-index 0000000..dc137bf8
---- /dev/null
-+++ b/drivers/net/titan_ge.c
-@@ -0,0 +1,2069 @@
-+/*
-+ * drivers/net/titan_ge.c - Driver for Titan ethernet ports
-+ *
-+ * Copyright (C) 2003 PMC-Sierra Inc.
-+ * Author : Manish Lachwani (lachwani@pmc-sierra.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 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.
-+ */
-+
-+/*
-+ * The MAC unit of the Titan consists of the following:
-+ *
-+ * -> XDMA Engine to move data to from the memory to the MAC packet FIFO
-+ * -> FIFO is where the incoming and outgoing data is placed
-+ * -> TRTG is the unit that pulls the data from the FIFO for Tx and pushes
-+ * the data into the FIFO for Rx
-+ * -> TMAC is the outgoing MAC interface and RMAC is the incoming.
-+ * -> AFX is the address filtering block
-+ * -> GMII block to communicate with the PHY
-+ *
-+ * Rx will look like the following:
-+ * GMII --> RMAC --> AFX --> TRTG --> Rx FIFO --> XDMA --> CPU memory
-+ *
-+ * Tx will look like the following:
-+ * CPU memory --> XDMA --> Tx FIFO --> TRTG --> TMAC --> GMII
-+ *
-+ * The Titan driver has support for the following performance features:
-+ * -> Rx side checksumming
-+ * -> Jumbo Frames
-+ * -> Interrupt Coalscing
-+ * -> Rx NAPI
-+ * -> SKB Recycling
-+ * -> Transmit/Receive descriptors in SRAM
-+ * -> Fast routing for IP forwarding
-+ */
-+
-+#include <linux/dma-mapping.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/ioport.h>
-+#include <linux/interrupt.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+#include <linux/errno.h>
-+#include <linux/ip.h>
-+#include <linux/init.h>
-+#include <linux/in.h>
-+#include <linux/platform_device.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/mii.h>
-+#include <linux/delay.h>
-+#include <linux/skbuff.h>
-+#include <linux/prefetch.h>
-+
-+/* For MII specifc registers, titan_mdio.h should be included */
-+#include <net/ip.h>
-+
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+#include <asm/types.h>
-+#include <asm/pgtable.h>
-+#include <asm/system.h>
-+#include <asm/titan_dep.h>
-+
-+#include "titan_ge.h"
-+#include "titan_mdio.h"
-+
-+/* Static Function Declarations */
-+static int titan_ge_eth_open(struct net_device *);
-+static void titan_ge_eth_stop(struct net_device *);
-+static struct net_device_stats *titan_ge_get_stats(struct net_device *);
-+static int titan_ge_init_rx_desc_ring(titan_ge_port_info *, int, int,
-+ unsigned long, unsigned long,
-+ unsigned long);
-+static int titan_ge_init_tx_desc_ring(titan_ge_port_info *, int,
-+ unsigned long, unsigned long);
-+
-+static int titan_ge_open(struct net_device *);
-+static int titan_ge_start_xmit(struct sk_buff *, struct net_device *);
-+static int titan_ge_stop(struct net_device *);
-+
-+static unsigned long titan_ge_tx_coal(unsigned long, int);
-+
-+static void titan_ge_port_reset(unsigned int);
-+static int titan_ge_free_tx_queue(titan_ge_port_info *);
-+static int titan_ge_rx_task(struct net_device *, titan_ge_port_info *);
-+static int titan_ge_port_start(struct net_device *, titan_ge_port_info *);
-+
-+static int titan_ge_return_tx_desc(titan_ge_port_info *, int);
-+
-+/*
-+ * Some configuration for the FIFO and the XDMA channel needs
-+ * to be done only once for all the ports. This flag controls
-+ * that
-+ */
-+static unsigned long config_done;
-+
-+/*
-+ * One time out of memory flag
-+ */
-+static unsigned int oom_flag;
-+
-+static int titan_ge_poll(struct net_device *netdev, int *budget);
-+
-+static int titan_ge_receive_queue(struct net_device *, unsigned int);
-+
-+static struct platform_device *titan_ge_device[3];
-+
-+/* MAC Address */
-+extern unsigned char titan_ge_mac_addr_base[6];
-+
-+unsigned long titan_ge_base;
-+static unsigned long titan_ge_sram;
-+
-+static char titan_string[] = "titan";
-+
-+/*
-+ * The Titan GE has two alignment requirements:
-+ * -> skb->data to be cacheline aligned (32 byte)
-+ * -> IP header alignment to 16 bytes
-+ *
-+ * The latter is not implemented. So, that results in an extra copy on
-+ * the Rx. This is a big performance hog. For the former case, the
-+ * dev_alloc_skb() has been replaced with titan_ge_alloc_skb(). The size
-+ * requested is calculated:
-+ *
-+ * Ethernet Frame Size : 1518
-+ * Ethernet Header : 14
-+ * Future Titan change for IP header alignment : 2
-+ *
-+ * Hence, we allocate (1518 + 14 + 2+ 64) = 1580 bytes. For IP header
-+ * alignment, we use skb_reserve().
-+ */
-+
-+#define ALIGNED_RX_SKB_ADDR(addr) \
-+ ((((unsigned long)(addr) + (64UL - 1UL)) \
-+ & ~(64UL - 1UL)) - (unsigned long)(addr))
-+
-+#define titan_ge_alloc_skb(__length, __gfp_flags) \
-+({ struct sk_buff *__skb; \
-+ __skb = alloc_skb((__length) + 64, (__gfp_flags)); \
-+ if(__skb) { \
-+ int __offset = (int) ALIGNED_RX_SKB_ADDR(__skb->data); \
-+ if(__offset) \
-+ skb_reserve(__skb, __offset); \
-+ } \
-+ __skb; \
-+})
-+
-+/*
-+ * Configure the GMII block of the Titan based on what the PHY tells us
-+ */
-+static void titan_ge_gmii_config(int port_num)
-+{
-+ unsigned int reg_data = 0, phy_reg;
-+ int err;
-+
-+ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
-+
-+ if (err == TITAN_GE_MDIO_ERROR) {
-+ printk(KERN_ERR
-+ "Could not read PHY control register 0x11 \n");
-+ printk(KERN_ERR
-+ "Setting speed to 1000 Mbps and Duplex to Full \n");
-+
-+ return;
-+ }
-+
-+ err = titan_ge_mdio_write(port_num, TITAN_GE_MDIO_PHY_IE, 0);
-+
-+ if (phy_reg & 0x8000) {
-+ if (phy_reg & 0x2000) {
-+ /* Full Duplex and 1000 Mbps */
-+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
-+ (port_num << 12)), 0x201);
-+ } else {
-+ /* Half Duplex and 1000 Mbps */
-+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
-+ (port_num << 12)), 0x2201);
-+ }
-+ }
-+ if (phy_reg & 0x4000) {
-+ if (phy_reg & 0x2000) {
-+ /* Full Duplex and 100 Mbps */
-+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
-+ (port_num << 12)), 0x100);
-+ } else {
-+ /* Half Duplex and 100 Mbps */
-+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_MODE +
-+ (port_num << 12)), 0x2100);
-+ }
-+ }
-+ reg_data = TITAN_GE_READ(TITAN_GE_GMII_CONFIG_GENERAL +
-+ (port_num << 12));
-+ reg_data |= 0x3;
-+ TITAN_GE_WRITE((TITAN_GE_GMII_CONFIG_GENERAL +
-+ (port_num << 12)), reg_data);
-+}
-+
-+/*
-+ * Enable the TMAC if it is not
-+ */
-+static void titan_ge_enable_tx(unsigned int port_num)
-+{
-+ unsigned long reg_data;
-+
-+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12));
-+ if (!(reg_data & 0x8000)) {
-+ printk("TMAC disabled for port %d!! \n", port_num);
-+
-+ reg_data |= 0x0001; /* Enable TMAC */
-+ reg_data |= 0x4000; /* CRC Check Enable */
-+ reg_data |= 0x2000; /* Padding enable */
-+ reg_data |= 0x0800; /* CRC Add enable */
-+ reg_data |= 0x0080; /* PAUSE frame */
-+
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
-+ (port_num << 12)), reg_data);
-+ }
-+}
-+
-+/*
-+ * Tx Timeout function
-+ */
-+static void titan_ge_tx_timeout(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+
-+ printk(KERN_INFO "%s: TX timeout ", netdev->name);
-+ printk(KERN_INFO "Resetting card \n");
-+
-+ /* Do the reset outside of interrupt context */
-+ schedule_work(&titan_ge_eth->tx_timeout_task);
-+}
-+
-+/*
-+ * Update the AFX tables for UC and MC for slice 0 only
-+ */
-+static void titan_ge_update_afx(titan_ge_port_info * titan_ge_eth)
-+{
-+ int port = titan_ge_eth->port_num;
-+ unsigned int i;
-+ volatile unsigned long reg_data = 0;
-+ u8 p_addr[6];
-+
-+ memcpy(p_addr, titan_ge_eth->port_mac_addr, 6);
-+
-+ /* Set the MAC address here for TMAC and RMAC */
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port << 12)),
-+ ((p_addr[5] << 8) | p_addr[4]));
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port << 12)),
-+ ((p_addr[3] << 8) | p_addr[2]));
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port << 12)),
-+ ((p_addr[1] << 8) | p_addr[0]));
-+
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port << 12)),
-+ ((p_addr[5] << 8) | p_addr[4]));
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port << 12)),
-+ ((p_addr[3] << 8) | p_addr[2]));
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port << 12)),
-+ ((p_addr[1] << 8) | p_addr[0]));
-+
-+ TITAN_GE_WRITE((0x112c | (port << 12)), 0x1);
-+ /* Configure the eight address filters */
-+ for (i = 0; i < 8; i++) {
-+ /* Select each of the eight filters */
-+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 +
-+ (port << 12)), i);
-+
-+ /* Configure the match */
-+ reg_data = 0x9; /* Forward Enable Bit */
-+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 +
-+ (port << 12)), reg_data);
-+
-+ /* Finally, AFX Exact Match Address Registers */
-+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_LOW + (port << 12)),
-+ ((p_addr[1] << 8) | p_addr[0]));
-+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_MID + (port << 12)),
-+ ((p_addr[3] << 8) | p_addr[2]));
-+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_HIGH + (port << 12)),
-+ ((p_addr[5] << 8) | p_addr[4]));
-+
-+ /* VLAN id set to 0 */
-+ TITAN_GE_WRITE((TITAN_GE_AFX_EXACT_MATCH_VID +
-+ (port << 12)), 0);
-+ }
-+}
-+
-+/*
-+ * Actual Routine to reset the adapter when the timeout occurred
-+ */
-+static void titan_ge_tx_timeout_task(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ int port = titan_ge_eth->port_num;
-+
-+ printk("Titan GE: Transmit timed out. Resetting ... \n");
-+
-+ /* Dump debug info */
-+ printk(KERN_ERR "TRTG cause : %x \n",
-+ TITAN_GE_READ(0x100c + (port << 12)));
-+
-+ /* Fix this for the other ports */
-+ printk(KERN_ERR "FIFO cause : %x \n", TITAN_GE_READ(0x482c));
-+ printk(KERN_ERR "IE cause : %x \n", TITAN_GE_READ(0x0040));
-+ printk(KERN_ERR "XDMA GDI ERROR : %x \n",
-+ TITAN_GE_READ(0x5008 + (port << 8)));
-+ printk(KERN_ERR "CHANNEL ERROR: %x \n",
-+ TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT
-+ + (port << 8)));
-+
-+ netif_device_detach(netdev);
-+ titan_ge_port_reset(titan_ge_eth->port_num);
-+ titan_ge_port_start(netdev, titan_ge_eth);
-+ netif_device_attach(netdev);
-+}
-+
-+/*
-+ * Change the MTU of the Ethernet Device
-+ */
-+static int titan_ge_change_mtu(struct net_device *netdev, int new_mtu)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ unsigned long flags;
-+
-+ if ((new_mtu > 9500) || (new_mtu < 64))
-+ return -EINVAL;
-+
-+ spin_lock_irqsave(&titan_ge_eth->lock, flags);
-+
-+ netdev->mtu = new_mtu;
-+
-+ /* Now we have to reopen the interface so that SKBs with the new
-+ * size will be allocated */
-+
-+ if (netif_running(netdev)) {
-+ titan_ge_eth_stop(netdev);
-+
-+ if (titan_ge_eth_open(netdev) != TITAN_OK) {
-+ printk(KERN_ERR
-+ "%s: Fatal error on opening device\n",
-+ netdev->name);
-+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
-+ return -1;
-+ }
-+ }
-+
-+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
-+ return 0;
-+}
-+
-+/*
-+ * Titan Gbe Interrupt Handler. All the three ports send interrupt to one line
-+ * only. Once an interrupt is triggered, figure out the port and then check
-+ * the channel.
-+ */
-+static irqreturn_t titan_ge_int_handler(int irq, void *dev_id)
-+{
-+ struct net_device *netdev = (struct net_device *) dev_id;
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ unsigned int port_num = titan_ge_eth->port_num;
-+ unsigned int reg_data;
-+ unsigned int eth_int_cause_error = 0, is;
-+ unsigned long eth_int_cause1;
-+ int err = 0;
-+#ifdef CONFIG_SMP
-+ unsigned long eth_int_cause2;
-+#endif
-+
-+ /* Ack the CPU interrupt */
-+ switch (port_num) {
-+ case 0:
-+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS1);
-+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR1, is);
-+
-+#ifdef CONFIG_SMP
-+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS1);
-+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR1, is);
-+#endif
-+ break;
-+
-+ case 1:
-+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS0);
-+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR0, is);
-+
-+#ifdef CONFIG_SMP
-+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS0);
-+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR0, is);
-+#endif
-+ break;
-+
-+ case 2:
-+ is = OCD_READ(RM9000x2_OCD_INTP0STATUS4);
-+ OCD_WRITE(RM9000x2_OCD_INTP0CLEAR4, is);
-+
-+#ifdef CONFIG_SMP
-+ is = OCD_READ(RM9000x2_OCD_INTP1STATUS4);
-+ OCD_WRITE(RM9000x2_OCD_INTP1CLEAR4, is);
-+#endif
-+ }
-+
-+ eth_int_cause1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
-+#ifdef CONFIG_SMP
-+ eth_int_cause2 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_B);
-+#endif
-+
-+ /* Spurious interrupt */
-+#ifdef CONFIG_SMP
-+ if ( (eth_int_cause1 == 0) && (eth_int_cause2 == 0)) {
-+#else
-+ if (eth_int_cause1 == 0) {
-+#endif
-+ eth_int_cause_error = TITAN_GE_READ(TITAN_GE_CHANNEL0_INTERRUPT +
-+ (port_num << 8));
-+
-+ if (eth_int_cause_error == 0)
-+ return IRQ_NONE;
-+ }
-+
-+ /* Handle Tx first. No need to ack interrupts */
-+#ifdef CONFIG_SMP
-+ if ( (eth_int_cause1 & 0x20202) ||
-+ (eth_int_cause2 & 0x20202) )
-+#else
-+ if (eth_int_cause1 & 0x20202)
-+#endif
-+ titan_ge_free_tx_queue(titan_ge_eth);
-+
-+ /* Handle the Rx next */
-+#ifdef CONFIG_SMP
-+ if ( (eth_int_cause1 & 0x10101) ||
-+ (eth_int_cause2 & 0x10101)) {
-+#else
-+ if (eth_int_cause1 & 0x10101) {
-+#endif
-+ if (netif_rx_schedule_prep(netdev)) {
-+ unsigned int ack;
-+
-+ ack = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
-+ /* Disable Tx and Rx both */
-+ if (port_num == 0)
-+ ack &= ~(0x3);
-+ if (port_num == 1)
-+ ack &= ~(0x300);
-+
-+ if (port_num == 2)
-+ ack &= ~(0x30000);
-+
-+ /* Interrupts have been disabled */
-+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, ack);
-+
-+ __netif_rx_schedule(netdev);
-+ }
-+ }
-+
-+ /* Handle error interrupts */
-+ if (eth_int_cause_error && (eth_int_cause_error != 0x2)) {
-+ printk(KERN_ERR
-+ "XDMA Channel Error : %x on port %d\n",
-+ eth_int_cause_error, port_num);
-+
-+ printk(KERN_ERR
-+ "XDMA GDI Hardware error : %x on port %d\n",
-+ TITAN_GE_READ(0x5008 + (port_num << 8)), port_num);
-+
-+ printk(KERN_ERR
-+ "XDMA currently has %d Rx descriptors \n",
-+ TITAN_GE_READ(0x5048 + (port_num << 8)));
-+
-+ printk(KERN_ERR
-+ "XDMA currently has prefetcted %d Rx descriptors \n",
-+ TITAN_GE_READ(0x505c + (port_num << 8)));
-+
-+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT +
-+ (port_num << 8)), eth_int_cause_error);
-+ }
-+
-+ /*
-+ * PHY interrupt to inform abt the changes. Reading the
-+ * PHY Status register will clear the interrupt
-+ */
-+ if ((!(eth_int_cause1 & 0x30303)) &&
-+ (eth_int_cause_error == 0)) {
-+ err =
-+ titan_ge_mdio_read(port_num,
-+ TITAN_GE_MDIO_PHY_IS, &reg_data);
-+
-+ if (reg_data & 0x0400) {
-+ /* Link status change */
-+ titan_ge_mdio_read(port_num,
-+ TITAN_GE_MDIO_PHY_STATUS, &reg_data);
-+ if (!(reg_data & 0x0400)) {
-+ /* Link is down */
-+ netif_carrier_off(netdev);
-+ netif_stop_queue(netdev);
-+ } else {
-+ /* Link is up */
-+ netif_carrier_on(netdev);
-+ netif_wake_queue(netdev);
-+
-+ /* Enable the queue */
-+ titan_ge_enable_tx(port_num);
-+ }
-+ }
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+/*
-+ * Multicast and Promiscuous mode set. The
-+ * set_multi entry point is called whenever the
-+ * multicast address list or the network interface
-+ * flags are updated.
-+ */
-+static void titan_ge_set_multi(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ unsigned int port_num = titan_ge_eth->port_num;
-+ unsigned long reg_data;
-+
-+ reg_data = TITAN_GE_READ(TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 +
-+ (port_num << 12));
-+
-+ if (netdev->flags & IFF_PROMISC) {
-+ reg_data |= 0x2;
-+ }
-+ else if (netdev->flags & IFF_ALLMULTI) {
-+ reg_data |= 0x01;
-+ reg_data |= 0x400; /* Use the 64-bit Multicast Hash bin */
-+ }
-+ else {
-+ reg_data = 0x2;
-+ }
-+
-+ TITAN_GE_WRITE((TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 +
-+ (port_num << 12)), reg_data);
-+ if (reg_data & 0x01) {
-+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_LOW +
-+ (port_num << 12)), 0xffff);
-+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDLOW +
-+ (port_num << 12)), 0xffff);
-+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_MIDHI +
-+ (port_num << 12)), 0xffff);
-+ TITAN_GE_WRITE((TITAN_GE_AFX_MULTICAST_HASH_HI +
-+ (port_num << 12)), 0xffff);
-+ }
-+}
-+
-+/*
-+ * Open the network device
-+ */
-+static int titan_ge_open(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ unsigned int port_num = titan_ge_eth->port_num;
-+ unsigned int irq = TITAN_ETH_PORT_IRQ - port_num;
-+ int retval;
-+
-+ retval = request_irq(irq, titan_ge_int_handler,
-+ SA_INTERRUPT | SA_SAMPLE_RANDOM , netdev->name, netdev);
-+
-+ if (retval != 0) {
-+ printk(KERN_ERR "Cannot assign IRQ number to TITAN GE \n");
-+ return -1;
-+ }
-+
-+ netdev->irq = irq;
-+ printk(KERN_INFO "Assigned IRQ %d to port %d\n", irq, port_num);
-+
-+ spin_lock_irq(&(titan_ge_eth->lock));
-+
-+ if (titan_ge_eth_open(netdev) != TITAN_OK) {
-+ spin_unlock_irq(&(titan_ge_eth->lock));
-+ printk("%s: Error opening interface \n", netdev->name);
-+ free_irq(netdev->irq, netdev);
-+ return -EBUSY;
-+ }
-+
-+ spin_unlock_irq(&(titan_ge_eth->lock));
-+
-+ return 0;
-+}
-+
-+/*
-+ * Allocate the SKBs for the Rx ring. Also used
-+ * for refilling the queue
-+ */
-+static int titan_ge_rx_task(struct net_device *netdev,
-+ titan_ge_port_info *titan_ge_port)
-+{
-+ struct device *device = &titan_ge_device[titan_ge_port->port_num]->dev;
-+ volatile titan_ge_rx_desc *rx_desc;
-+ struct sk_buff *skb;
-+ int rx_used_desc;
-+ int count = 0;
-+
-+ while (titan_ge_port->rx_ring_skbs < titan_ge_port->rx_ring_size) {
-+
-+ /* First try to get the skb from the recycler */
-+#ifdef TITAN_GE_JUMBO_FRAMES
-+ skb = titan_ge_alloc_skb(TITAN_GE_JUMBO_BUFSIZE, GFP_ATOMIC);
-+#else
-+ skb = titan_ge_alloc_skb(TITAN_GE_STD_BUFSIZE, GFP_ATOMIC);
-+#endif
-+ if (unlikely(!skb)) {
-+ /* OOM, set the flag */
-+ printk("OOM \n");
-+ oom_flag = 1;
-+ break;
-+ }
-+ count++;
-+ skb->dev = netdev;
-+
-+ titan_ge_port->rx_ring_skbs++;
-+
-+ rx_used_desc = titan_ge_port->rx_used_desc_q;
-+ rx_desc = &(titan_ge_port->rx_desc_area[rx_used_desc]);
-+
-+#ifdef TITAN_GE_JUMBO_FRAMES
-+ rx_desc->buffer_addr = dma_map_single(device, skb->data,
-+ TITAN_GE_JUMBO_BUFSIZE - 2, DMA_FROM_DEVICE);
-+#else
-+ rx_desc->buffer_addr = dma_map_single(device, skb->data,
-+ TITAN_GE_STD_BUFSIZE - 2, DMA_FROM_DEVICE);
-+#endif
-+
-+ titan_ge_port->rx_skb[rx_used_desc] = skb;
-+ rx_desc->cmd_sts = TITAN_GE_RX_BUFFER_OWNED;
-+
-+ titan_ge_port->rx_used_desc_q =
-+ (rx_used_desc + 1) % TITAN_GE_RX_QUEUE;
-+ }
-+
-+ return count;
-+}
-+
-+/*
-+ * Actual init of the Tital GE port. There is one register for
-+ * the channel configuration
-+ */
-+static void titan_port_init(struct net_device *netdev,
-+ titan_ge_port_info * titan_ge_eth)
-+{
-+ unsigned long reg_data;
-+
-+ titan_ge_port_reset(titan_ge_eth->port_num);
-+
-+ /* First reset the TMAC */
-+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
-+ reg_data |= 0x80000000;
-+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
-+
-+ udelay(30);
-+
-+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
-+ reg_data &= ~(0xc0000000);
-+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
-+
-+ /* Now reset the RMAC */
-+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
-+ reg_data |= 0x00080000;
-+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
-+
-+ udelay(30);
-+
-+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG);
-+ reg_data &= ~(0x000c0000);
-+ TITAN_GE_WRITE(TITAN_GE_CHANNEL0_CONFIG, reg_data);
-+}
-+
-+/*
-+ * Start the port. All the hardware specific configuration
-+ * for the XDMA, Tx FIFO, Rx FIFO, TMAC, RMAC, TRTG and AFX
-+ * go here
-+ */
-+static int titan_ge_port_start(struct net_device *netdev,
-+ titan_ge_port_info * titan_port)
-+{
-+ volatile unsigned long reg_data, reg_data1;
-+ int port_num = titan_port->port_num;
-+ int count = 0;
-+ unsigned long reg_data_1;
-+
-+ if (config_done == 0) {
-+ reg_data = TITAN_GE_READ(0x0004);
-+ reg_data |= 0x100;
-+ TITAN_GE_WRITE(0x0004, reg_data);
-+
-+ reg_data &= ~(0x100);
-+ TITAN_GE_WRITE(0x0004, reg_data);
-+
-+ /* Turn on GMII/MII mode and turn off TBI mode */
-+ reg_data = TITAN_GE_READ(TITAN_GE_TSB_CTRL_1);
-+ reg_data |= 0x00000700;
-+ reg_data &= ~(0x00800000); /* Fencing */
-+
-+ TITAN_GE_WRITE(0x000c, 0x00001100);
-+
-+ TITAN_GE_WRITE(TITAN_GE_TSB_CTRL_1, reg_data);
-+
-+ /* Set the CPU Resource Limit register */
-+ TITAN_GE_WRITE(0x00f8, 0x8);
-+
-+ /* Be conservative when using the BIU buffers */
-+ TITAN_GE_WRITE(0x0068, 0x4);
-+ }
-+
-+ titan_port->tx_threshold = 0;
-+ titan_port->rx_threshold = 0;
-+
-+ /* We need to write the descriptors for Tx and Rx */
-+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_TX_DESC + (port_num << 8)),
-+ (unsigned long) titan_port->tx_dma);
-+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_RX_DESC + (port_num << 8)),
-+ (unsigned long) titan_port->rx_dma);
-+
-+ if (config_done == 0) {
-+ /* Step 1: XDMA config */
-+ reg_data = TITAN_GE_READ(TITAN_GE_XDMA_CONFIG);
-+ reg_data &= ~(0x80000000); /* clear reset */
-+ reg_data |= 0x1 << 29; /* sparse tx descriptor spacing */
-+ reg_data |= 0x1 << 28; /* sparse rx descriptor spacing */
-+ reg_data |= (0x1 << 23) | (0x1 << 24); /* Descriptor Coherency */
-+ reg_data |= (0x1 << 21) | (0x1 << 22); /* Data Coherency */
-+ TITAN_GE_WRITE(TITAN_GE_XDMA_CONFIG, reg_data);
-+ }
-+
-+ /* IR register for the XDMA */
-+ reg_data = TITAN_GE_READ(TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8));
-+ reg_data |= 0x80068000; /* No Rx_OOD */
-+ TITAN_GE_WRITE((TITAN_GE_GDI_INTERRUPT_ENABLE + (port_num << 8)), reg_data);
-+
-+ /* Start the Tx and Rx XDMA controller */
-+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG + (port_num << 8));
-+ reg_data &= 0x4fffffff; /* Clear tx reset */
-+ reg_data &= 0xfff4ffff; /* Clear rx reset */
-+
-+#ifdef TITAN_GE_JUMBO_FRAMES
-+ reg_data |= 0xa0 | 0x30030000;
-+#else
-+ reg_data |= 0x40 | 0x20030000;
-+#endif
-+
-+#ifndef CONFIG_SMP
-+ reg_data &= ~(0x10);
-+ reg_data |= 0x0f; /* All of the packet */
-+#endif
-+
-+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG + (port_num << 8)), reg_data);
-+
-+ /* Rx desc count */
-+ count = titan_ge_rx_task(netdev, titan_port);
-+ TITAN_GE_WRITE((0x5048 + (port_num << 8)), count);
-+ count = TITAN_GE_READ(0x5048 + (port_num << 8));
-+
-+ udelay(30);
-+
-+ /*
-+ * Step 2: Configure the SDQPF, i.e. FIFO
-+ */
-+ if (config_done == 0) {
-+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
-+ reg_data = 0x1;
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
-+ reg_data &= ~(0x1);
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
-+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_CTL);
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_CTL, reg_data);
-+
-+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
-+ reg_data = 0x1;
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
-+ reg_data &= ~(0x1);
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
-+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_CTL);
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_CTL, reg_data);
-+ }
-+ /*
-+ * Enable RX FIFO 0, 4 and 8
-+ */
-+ if (port_num == 0) {
-+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_RXFIFO_0);
-+
-+ reg_data |= 0x100000;
-+ reg_data |= (0xff << 10);
-+
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
-+ /*
-+ * BAV2,BAV and DAV settings for the Rx FIFO
-+ */
-+ reg_data1 = TITAN_GE_READ(0x4844);
-+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
-+ TITAN_GE_WRITE(0x4844, reg_data1);
-+
-+ reg_data &= ~(0x00100000);
-+ reg_data |= 0x200000;
-+
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_RXFIFO_0, reg_data);
-+
-+ reg_data = TITAN_GE_READ(TITAN_GE_SDQPF_TXFIFO_0);
-+ reg_data |= 0x100000;
-+
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
-+
-+ reg_data |= (0xff << 10);
-+
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
-+
-+ /*
-+ * BAV2, BAV and DAV settings for the Tx FIFO
-+ */
-+ reg_data1 = TITAN_GE_READ(0x4944);
-+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
-+
-+ TITAN_GE_WRITE(0x4944, reg_data1);
-+
-+ reg_data &= ~(0x00100000);
-+ reg_data |= 0x200000;
-+
-+ TITAN_GE_WRITE(TITAN_GE_SDQPF_TXFIFO_0, reg_data);
-+
-+ }
-+
-+ if (port_num == 1) {
-+ reg_data = TITAN_GE_READ(0x4870);
-+
-+ reg_data |= 0x100000;
-+ reg_data |= (0xff << 10) | (0xff + 1);
-+
-+ TITAN_GE_WRITE(0x4870, reg_data);
-+ /*
-+ * BAV2,BAV and DAV settings for the Rx FIFO
-+ */
-+ reg_data1 = TITAN_GE_READ(0x4874);
-+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
-+ TITAN_GE_WRITE(0x4874, reg_data1);
-+
-+ reg_data &= ~(0x00100000);
-+ reg_data |= 0x200000;
-+
-+ TITAN_GE_WRITE(0x4870, reg_data);
-+
-+ reg_data = TITAN_GE_READ(0x494c);
-+ reg_data |= 0x100000;
-+
-+ TITAN_GE_WRITE(0x494c, reg_data);
-+ reg_data |= (0xff << 10) | (0xff + 1);
-+ TITAN_GE_WRITE(0x494c, reg_data);
-+
-+ /*
-+ * BAV2, BAV and DAV settings for the Tx FIFO
-+ */
-+ reg_data1 = TITAN_GE_READ(0x4950);
-+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
-+
-+ TITAN_GE_WRITE(0x4950, reg_data1);
-+
-+ reg_data &= ~(0x00100000);
-+ reg_data |= 0x200000;
-+
-+ TITAN_GE_WRITE(0x494c, reg_data);
-+ }
-+
-+ /*
-+ * Titan 1.2 revision does support port #2
-+ */
-+ if (port_num == 2) {
-+ /*
-+ * Put the descriptors in the SRAM
-+ */
-+ reg_data = TITAN_GE_READ(0x48a0);
-+
-+ reg_data |= 0x100000;
-+ reg_data |= (0xff << 10) | (2*(0xff + 1));
-+
-+ TITAN_GE_WRITE(0x48a0, reg_data);
-+ /*
-+ * BAV2,BAV and DAV settings for the Rx FIFO
-+ */
-+ reg_data1 = TITAN_GE_READ(0x48a4);
-+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
-+ TITAN_GE_WRITE(0x48a4, reg_data1);
-+
-+ reg_data &= ~(0x00100000);
-+ reg_data |= 0x200000;
-+
-+ TITAN_GE_WRITE(0x48a0, reg_data);
-+
-+ reg_data = TITAN_GE_READ(0x4958);
-+ reg_data |= 0x100000;
-+
-+ TITAN_GE_WRITE(0x4958, reg_data);
-+ reg_data |= (0xff << 10) | (2*(0xff + 1));
-+ TITAN_GE_WRITE(0x4958, reg_data);
-+
-+ /*
-+ * BAV2, BAV and DAV settings for the Tx FIFO
-+ */
-+ reg_data1 = TITAN_GE_READ(0x495c);
-+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
-+
-+ TITAN_GE_WRITE(0x495c, reg_data1);
-+
-+ reg_data &= ~(0x00100000);
-+ reg_data |= 0x200000;
-+
-+ TITAN_GE_WRITE(0x4958, reg_data);
-+ }
-+
-+ if (port_num == 2) {
-+ reg_data = TITAN_GE_READ(0x48a0);
-+
-+ reg_data |= 0x100000;
-+ reg_data |= (0xff << 10) | (2*(0xff + 1));
-+
-+ TITAN_GE_WRITE(0x48a0, reg_data);
-+ /*
-+ * BAV2,BAV and DAV settings for the Rx FIFO
-+ */
-+ reg_data1 = TITAN_GE_READ(0x48a4);
-+ reg_data1 |= ( (0x10 << 20) | (0x10 << 10) | 0x1);
-+ TITAN_GE_WRITE(0x48a4, reg_data1);
-+
-+ reg_data &= ~(0x00100000);
-+ reg_data |= 0x200000;
-+
-+ TITAN_GE_WRITE(0x48a0, reg_data);
-+
-+ reg_data = TITAN_GE_READ(0x4958);
-+ reg_data |= 0x100000;
-+
-+ TITAN_GE_WRITE(0x4958, reg_data);
-+ reg_data |= (0xff << 10) | (2*(0xff + 1));
-+ TITAN_GE_WRITE(0x4958, reg_data);
-+
-+ /*
-+ * BAV2, BAV and DAV settings for the Tx FIFO
-+ */
-+ reg_data1 = TITAN_GE_READ(0x495c);
-+ reg_data1 = ( (0x1 << 20) | (0x1 << 10) | 0x10);
-+
-+ TITAN_GE_WRITE(0x495c, reg_data1);
-+
-+ reg_data &= ~(0x00100000);
-+ reg_data |= 0x200000;
-+
-+ TITAN_GE_WRITE(0x4958, reg_data);
-+ }
-+
-+ /*
-+ * Step 3: TRTG block enable
-+ */
-+ reg_data = TITAN_GE_READ(TITAN_GE_TRTG_CONFIG + (port_num << 12));
-+
-+ /*
-+ * This is the 1.2 revision of the chip. It has fix for the
-+ * IP header alignment. Now, the IP header begins at an
-+ * aligned address and this wont need an extra copy in the
-+ * driver. This performance drawback existed in the previous
-+ * versions of the silicon
-+ */
-+ reg_data_1 = TITAN_GE_READ(0x103c + (port_num << 12));
-+ reg_data_1 |= 0x40000000;
-+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
-+
-+ reg_data_1 |= 0x04000000;
-+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
-+
-+ mdelay(5);
-+
-+ reg_data_1 &= ~(0x04000000);
-+ TITAN_GE_WRITE((0x103c + (port_num << 12)), reg_data_1);
-+
-+ mdelay(5);
-+
-+ reg_data |= 0x0001;
-+ TITAN_GE_WRITE((TITAN_GE_TRTG_CONFIG + (port_num << 12)), reg_data);
-+
-+ /*
-+ * Step 4: Start the Tx activity
-+ */
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_2 + (port_num << 12)), 0xe197);
-+#ifdef TITAN_GE_JUMBO_FRAMES
-+ TITAN_GE_WRITE((0x1258 + (port_num << 12)), 0x4000);
-+#endif
-+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 + (port_num << 12));
-+ reg_data |= 0x0001; /* Enable TMAC */
-+ reg_data |= 0x6c70; /* PAUSE also set */
-+
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 + (port_num << 12)), reg_data);
-+
-+ udelay(30);
-+
-+ /* Destination Address drop bit */
-+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_2 + (port_num << 12));
-+ reg_data |= 0x218; /* DA_DROP bit and pause */
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_2 + (port_num << 12)), reg_data);
-+
-+ TITAN_GE_WRITE((0x1218 + (port_num << 12)), 0x3);
-+
-+#ifdef TITAN_GE_JUMBO_FRAMES
-+ TITAN_GE_WRITE((0x1208 + (port_num << 12)), 0x4000);
-+#endif
-+ /* Start the Rx activity */
-+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12));
-+ reg_data |= 0x0001; /* RMAC Enable */
-+ reg_data |= 0x0010; /* CRC Check enable */
-+ reg_data |= 0x0040; /* Min Frame check enable */
-+ reg_data |= 0x4400; /* Max Frame check enable */
-+
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data);
-+
-+ udelay(30);
-+
-+ /*
-+ * Enable the Interrupts for Tx and Rx
-+ */
-+ reg_data1 = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
-+
-+ if (port_num == 0) {
-+ reg_data1 |= 0x3;
-+#ifdef CONFIG_SMP
-+ TITAN_GE_WRITE(0x0038, 0x003);
-+#else
-+ TITAN_GE_WRITE(0x0038, 0x303);
-+#endif
-+ }
-+
-+ if (port_num == 1) {
-+ reg_data1 |= 0x300;
-+ }
-+
-+ if (port_num == 2)
-+ reg_data1 |= 0x30000;
-+
-+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data1);
-+ TITAN_GE_WRITE(0x003c, 0x300);
-+
-+ if (config_done == 0) {
-+ TITAN_GE_WRITE(0x0024, 0x04000024); /* IRQ vector */
-+ TITAN_GE_WRITE(0x0020, 0x000fb000); /* INTMSG base */
-+ }
-+
-+ /* Priority */
-+ reg_data = TITAN_GE_READ(0x1038 + (port_num << 12));
-+ reg_data &= ~(0x00f00000);
-+ TITAN_GE_WRITE((0x1038 + (port_num << 12)), reg_data);
-+
-+ /* Step 5: GMII config */
-+ titan_ge_gmii_config(port_num);
-+
-+ if (config_done == 0) {
-+ TITAN_GE_WRITE(0x1a80, 0);
-+ config_done = 1;
-+ }
-+
-+ return TITAN_OK;
-+}
-+
-+/*
-+ * Function to queue the packet for the Ethernet device
-+ */
-+static void titan_ge_tx_queue(titan_ge_port_info * titan_ge_eth,
-+ struct sk_buff * skb)
-+{
-+ struct device *device = &titan_ge_device[titan_ge_eth->port_num]->dev;
-+ unsigned int curr_desc = titan_ge_eth->tx_curr_desc_q;
-+ volatile titan_ge_tx_desc *tx_curr;
-+ int port_num = titan_ge_eth->port_num;
-+
-+ tx_curr = &(titan_ge_eth->tx_desc_area[curr_desc]);
-+ tx_curr->buffer_addr =
-+ dma_map_single(device, skb->data, skb_headlen(skb),
-+ DMA_TO_DEVICE);
-+
-+ titan_ge_eth->tx_skb[curr_desc] = (struct sk_buff *) skb;
-+ tx_curr->buffer_len = skb_headlen(skb);
-+
-+ /* Last descriptor enables interrupt and changes ownership */
-+ tx_curr->cmd_sts = 0x1 | (1 << 15) | (1 << 5);
-+
-+ /* Kick the XDMA to start the transfer from memory to the FIFO */
-+ TITAN_GE_WRITE((0x5044 + (port_num << 8)), 0x1);
-+
-+ /* Current descriptor updated */
-+ titan_ge_eth->tx_curr_desc_q = (curr_desc + 1) % TITAN_GE_TX_QUEUE;
-+
-+ /* Prefetch the next descriptor */
-+ prefetch((const void *)
-+ &titan_ge_eth->tx_desc_area[titan_ge_eth->tx_curr_desc_q]);
-+}
-+
-+/*
-+ * Actually does the open of the Ethernet device
-+ */
-+static int titan_ge_eth_open(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ unsigned int port_num = titan_ge_eth->port_num;
-+ struct device *device = &titan_ge_device[port_num]->dev;
-+ unsigned long reg_data;
-+ unsigned int phy_reg;
-+ int err = 0;
-+
-+ /* Stop the Rx activity */
-+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 + (port_num << 12));
-+ reg_data &= ~(0x00000001);
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 + (port_num << 12)), reg_data);
-+
-+ /* Clear the port interrupts */
-+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_INTERRUPT + (port_num << 8)), 0x0);
-+
-+ if (config_done == 0) {
-+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0);
-+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_B, 0);
-+ }
-+
-+ /* Set the MAC Address */
-+ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
-+
-+ if (config_done == 0)
-+ titan_port_init(netdev, titan_ge_eth);
-+
-+ titan_ge_update_afx(titan_ge_eth);
-+
-+ /* Allocate the Tx ring now */
-+ titan_ge_eth->tx_ring_skbs = 0;
-+ titan_ge_eth->tx_ring_size = TITAN_GE_TX_QUEUE;
-+
-+ /* Allocate space in the SRAM for the descriptors */
-+ titan_ge_eth->tx_desc_area = (titan_ge_tx_desc *)
-+ (titan_ge_sram + TITAN_TX_RING_BYTES * port_num);
-+ titan_ge_eth->tx_dma = TITAN_SRAM_BASE + TITAN_TX_RING_BYTES * port_num;
-+
-+ if (!titan_ge_eth->tx_desc_area) {
-+ printk(KERN_ERR
-+ "%s: Cannot allocate Tx Ring (size %d bytes) for port %d\n",
-+ netdev->name, TITAN_TX_RING_BYTES, port_num);
-+ return -ENOMEM;
-+ }
-+
-+ memset(titan_ge_eth->tx_desc_area, 0, titan_ge_eth->tx_desc_area_size);
-+
-+ /* Now initialize the Tx descriptor ring */
-+ titan_ge_init_tx_desc_ring(titan_ge_eth,
-+ titan_ge_eth->tx_ring_size,
-+ (unsigned long) titan_ge_eth->tx_desc_area,
-+ (unsigned long) titan_ge_eth->tx_dma);
-+
-+ /* Allocate the Rx ring now */
-+ titan_ge_eth->rx_ring_size = TITAN_GE_RX_QUEUE;
-+ titan_ge_eth->rx_ring_skbs = 0;
-+
-+ titan_ge_eth->rx_desc_area =
-+ (titan_ge_rx_desc *)(titan_ge_sram + 0x1000 + TITAN_RX_RING_BYTES * port_num);
-+
-+ titan_ge_eth->rx_dma = TITAN_SRAM_BASE + 0x1000 + TITAN_RX_RING_BYTES * port_num;
-+
-+ if (!titan_ge_eth->rx_desc_area) {
-+ printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n",
-+ netdev->name, TITAN_RX_RING_BYTES);
-+
-+ printk(KERN_ERR "%s: Freeing previously allocated TX queues...",
-+ netdev->name);
-+
-+ dma_free_coherent(device, titan_ge_eth->tx_desc_area_size,
-+ (void *) titan_ge_eth->tx_desc_area,
-+ titan_ge_eth->tx_dma);
-+
-+ return -ENOMEM;
-+ }
-+
-+ memset(titan_ge_eth->rx_desc_area, 0, titan_ge_eth->rx_desc_area_size);
-+
-+ /* Now initialize the Rx ring */
-+#ifdef TITAN_GE_JUMBO_FRAMES
-+ if ((titan_ge_init_rx_desc_ring
-+ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_JUMBO_BUFSIZE,
-+ (unsigned long) titan_ge_eth->rx_desc_area, 0,
-+ (unsigned long) titan_ge_eth->rx_dma)) == 0)
-+#else
-+ if ((titan_ge_init_rx_desc_ring
-+ (titan_ge_eth, titan_ge_eth->rx_ring_size, TITAN_GE_STD_BUFSIZE,
-+ (unsigned long) titan_ge_eth->rx_desc_area, 0,
-+ (unsigned long) titan_ge_eth->rx_dma)) == 0)
-+#endif
-+ panic("%s: Error initializing RX Ring\n", netdev->name);
-+
-+ /* Fill the Rx ring with the SKBs */
-+ titan_ge_port_start(netdev, titan_ge_eth);
-+
-+ /*
-+ * Check if Interrupt Coalscing needs to be turned on. The
-+ * values specified in the register is multiplied by
-+ * (8 x 64 nanoseconds) to determine when an interrupt should
-+ * be sent to the CPU.
-+ */
-+
-+ if (TITAN_GE_TX_COAL) {
-+ titan_ge_eth->tx_int_coal =
-+ titan_ge_tx_coal(TITAN_GE_TX_COAL, port_num);
-+ }
-+
-+ err = titan_ge_mdio_read(port_num, TITAN_GE_MDIO_PHY_STATUS, &phy_reg);
-+ if (err == TITAN_GE_MDIO_ERROR) {
-+ printk(KERN_ERR
-+ "Could not read PHY control register 0x11 \n");
-+ return TITAN_ERROR;
-+ }
-+ if (!(phy_reg & 0x0400)) {
-+ netif_carrier_off(netdev);
-+ netif_stop_queue(netdev);
-+ return TITAN_ERROR;
-+ } else {
-+ netif_carrier_on(netdev);
-+ netif_start_queue(netdev);
-+ }
-+
-+ return TITAN_OK;
-+}
-+
-+/*
-+ * Queue the packet for Tx. Currently no support for zero copy,
-+ * checksum offload and Scatter Gather. The chip does support
-+ * Scatter Gather only. But, that wont help here since zero copy
-+ * requires support for Tx checksumming also.
-+ */
-+int titan_ge_start_xmit(struct sk_buff *skb, struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ unsigned long flags;
-+ struct net_device_stats *stats;
-+//printk("titan_ge_start_xmit\n");
-+
-+ stats = &titan_ge_eth->stats;
-+ spin_lock_irqsave(&titan_ge_eth->lock, flags);
-+
-+ if ((TITAN_GE_TX_QUEUE - titan_ge_eth->tx_ring_skbs) <=
-+ (skb_shinfo(skb)->nr_frags + 1)) {
-+ netif_stop_queue(netdev);
-+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
-+ printk(KERN_ERR "Tx OOD \n");
-+ return 1;
-+ }
-+
-+ titan_ge_tx_queue(titan_ge_eth, skb);
-+ titan_ge_eth->tx_ring_skbs++;
-+
-+ if (TITAN_GE_TX_QUEUE <= (titan_ge_eth->tx_ring_skbs + 4)) {
-+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
-+ titan_ge_free_tx_queue(titan_ge_eth);
-+ spin_lock_irqsave(&titan_ge_eth->lock, flags);
-+ }
-+
-+ stats->tx_bytes += skb->len;
-+ stats->tx_packets++;
-+
-+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
-+
-+ netdev->trans_start = jiffies;
-+
-+ return 0;
-+}
-+
-+/*
-+ * Actually does the Rx. Rx side checksumming supported.
-+ */
-+static int titan_ge_rx(struct net_device *netdev, int port_num,
-+ titan_ge_port_info * titan_ge_port,
-+ titan_ge_packet * packet)
-+{
-+ int rx_curr_desc, rx_used_desc;
-+ volatile titan_ge_rx_desc *rx_desc;
-+
-+ rx_curr_desc = titan_ge_port->rx_curr_desc_q;
-+ rx_used_desc = titan_ge_port->rx_used_desc_q;
-+
-+ if (((rx_curr_desc + 1) % TITAN_GE_RX_QUEUE) == rx_used_desc)
-+ return TITAN_ERROR;
-+
-+ rx_desc = &(titan_ge_port->rx_desc_area[rx_curr_desc]);
-+
-+ if (rx_desc->cmd_sts & TITAN_GE_RX_BUFFER_OWNED)
-+ return TITAN_ERROR;
-+
-+ packet->skb = titan_ge_port->rx_skb[rx_curr_desc];
-+ packet->len = (rx_desc->cmd_sts & 0x7fff);
-+
-+ /*
-+ * At this point, we dont know if the checksumming
-+ * actually helps relieve CPU. So, keep it for
-+ * port 0 only
-+ */
-+ packet->checksum = ntohs((rx_desc->buffer & 0xffff0000) >> 16);
-+ packet->cmd_sts = rx_desc->cmd_sts;
-+
-+ titan_ge_port->rx_curr_desc_q = (rx_curr_desc + 1) % TITAN_GE_RX_QUEUE;
-+
-+ /* Prefetch the next descriptor */
-+ prefetch((const void *)
-+ &titan_ge_port->rx_desc_area[titan_ge_port->rx_curr_desc_q + 1]);
-+
-+ return TITAN_OK;
-+}
-+
-+/*
-+ * Free the Tx queue of the used SKBs
-+ */
-+static int titan_ge_free_tx_queue(titan_ge_port_info *titan_ge_eth)
-+{
-+ unsigned long flags;
-+
-+ /* Take the lock */
-+ spin_lock_irqsave(&(titan_ge_eth->lock), flags);
-+
-+ while (titan_ge_return_tx_desc(titan_ge_eth, titan_ge_eth->port_num) == 0)
-+ if (titan_ge_eth->tx_ring_skbs != 1)
-+ titan_ge_eth->tx_ring_skbs--;
-+
-+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
-+
-+ return TITAN_OK;
-+}
-+
-+/*
-+ * Threshold beyond which we do the cleaning of
-+ * Tx queue and new allocation for the Rx
-+ * queue
-+ */
-+#define TX_THRESHOLD 4
-+#define RX_THRESHOLD 10
-+
-+/*
-+ * Receive the packets and send it to the kernel.
-+ */
-+static int titan_ge_receive_queue(struct net_device *netdev, unsigned int max)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ unsigned int port_num = titan_ge_eth->port_num;
-+ titan_ge_packet packet;
-+ struct net_device_stats *stats;
-+ struct sk_buff *skb;
-+ unsigned long received_packets = 0;
-+ unsigned int ack;
-+
-+ stats = &titan_ge_eth->stats;
-+
-+ while ((--max)
-+ && (titan_ge_rx(netdev, port_num, titan_ge_eth, &packet) == TITAN_OK)) {
-+ skb = (struct sk_buff *) packet.skb;
-+
-+ titan_ge_eth->rx_ring_skbs--;
-+
-+ if (--titan_ge_eth->rx_work_limit < 0)
-+ break;
-+ received_packets++;
-+
-+ stats->rx_packets++;
-+ stats->rx_bytes += packet.len;
-+
-+ if ((packet.cmd_sts & TITAN_GE_RX_PERR) ||
-+ (packet.cmd_sts & TITAN_GE_RX_OVERFLOW_ERROR) ||
-+ (packet.cmd_sts & TITAN_GE_RX_TRUNC) ||
-+ (packet.cmd_sts & TITAN_GE_RX_CRC_ERROR)) {
-+ stats->rx_dropped++;
-+ dev_kfree_skb_any(skb);
-+
-+ continue;
-+ }
-+ /*
-+ * Either support fast path or slow path. Decision
-+ * making can really slow down the performance. The
-+ * idea is to cut down the number of checks and improve
-+ * the fastpath.
-+ */
-+
-+ skb_put(skb, packet.len - 2);
-+
-+ /*
-+ * Increment data pointer by two since thats where
-+ * the MAC starts
-+ */
-+ skb_reserve(skb, 2);
-+ skb->protocol = eth_type_trans(skb, netdev);
-+ netif_receive_skb(skb);
-+
-+ if (titan_ge_eth->rx_threshold > RX_THRESHOLD) {
-+ ack = titan_ge_rx_task(netdev, titan_ge_eth);
-+ TITAN_GE_WRITE((0x5048 + (port_num << 8)), ack);
-+ titan_ge_eth->rx_threshold = 0;
-+ } else
-+ titan_ge_eth->rx_threshold++;
-+
-+ if (titan_ge_eth->tx_threshold > TX_THRESHOLD) {
-+ titan_ge_eth->tx_threshold = 0;
-+ titan_ge_free_tx_queue(titan_ge_eth);
-+ }
-+ else
-+ titan_ge_eth->tx_threshold++;
-+
-+ }
-+ return received_packets;
-+}
-+
-+
-+/*
-+ * Enable the Rx side interrupts
-+ */
-+static void titan_ge_enable_int(unsigned int port_num,
-+ titan_ge_port_info *titan_ge_eth,
-+ struct net_device *netdev)
-+{
-+ unsigned long reg_data = TITAN_GE_READ(TITAN_GE_INTR_XDMA_IE);
-+
-+ if (port_num == 0)
-+ reg_data |= 0x3;
-+ if (port_num == 1)
-+ reg_data |= 0x300;
-+ if (port_num == 2)
-+ reg_data |= 0x30000;
-+
-+ /* Re-enable interrupts */
-+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, reg_data);
-+}
-+
-+/*
-+ * Main function to handle the polling for Rx side NAPI.
-+ * Receive interrupts have been disabled at this point.
-+ * The poll schedules the transmit followed by receive.
-+ */
-+static int titan_ge_poll(struct net_device *netdev, int *budget)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ int port_num = titan_ge_eth->port_num;
-+ int work_done = 0;
-+ unsigned long flags, status;
-+
-+ titan_ge_eth->rx_work_limit = *budget;
-+ if (titan_ge_eth->rx_work_limit > netdev->quota)
-+ titan_ge_eth->rx_work_limit = netdev->quota;
-+
-+ do {
-+ /* Do the transmit cleaning work here */
-+ titan_ge_free_tx_queue(titan_ge_eth);
-+
-+ /* Ack the Rx interrupts */
-+ if (port_num == 0)
-+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x3);
-+ if (port_num == 1)
-+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x300);
-+ if (port_num == 2)
-+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_CORE_A, 0x30000);
-+
-+ work_done += titan_ge_receive_queue(netdev, 0);
-+
-+ /* Out of quota and there is work to be done */
-+ if (titan_ge_eth->rx_work_limit < 0)
-+ goto not_done;
-+
-+ /* Receive alloc_skb could lead to OOM */
-+ if (oom_flag == 1) {
-+ oom_flag = 0;
-+ goto oom;
-+ }
-+
-+ status = TITAN_GE_READ(TITAN_GE_INTR_XDMA_CORE_A);
-+ } while (status & 0x30300);
-+
-+ /* If we are here, then no more interrupts to process */
-+ goto done;
-+
-+not_done:
-+ *budget -= work_done;
-+ netdev->quota -= work_done;
-+ return 1;
-+
-+oom:
-+ printk(KERN_ERR "OOM \n");
-+ netif_rx_complete(netdev);
-+ return 0;
-+
-+done:
-+ /*
-+ * No more packets on the poll list. Turn the interrupts
-+ * back on and we should be able to catch the new
-+ * packets in the interrupt handler
-+ */
-+ if (!work_done)
-+ work_done = 1;
-+
-+ *budget -= work_done;
-+ netdev->quota -= work_done;
-+
-+ spin_lock_irqsave(&titan_ge_eth->lock, flags);
-+
-+ /* Remove us from the poll list */
-+ netif_rx_complete(netdev);
-+
-+ /* Re-enable interrupts */
-+ titan_ge_enable_int(port_num, titan_ge_eth, netdev);
-+
-+ spin_unlock_irqrestore(&titan_ge_eth->lock, flags);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Close the network device
-+ */
-+int titan_ge_stop(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+
-+ spin_lock_irq(&(titan_ge_eth->lock));
-+ titan_ge_eth_stop(netdev);
-+ free_irq(netdev->irq, netdev);
-+ spin_unlock_irq(&titan_ge_eth->lock);
-+
-+ return TITAN_OK;
-+}
-+
-+/*
-+ * Free the Tx ring
-+ */
-+static void titan_ge_free_tx_rings(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ unsigned int port_num = titan_ge_eth->port_num;
-+ unsigned int curr;
-+ unsigned long reg_data;
-+
-+ /* Stop the Tx DMA */
-+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
-+ (port_num << 8));
-+ reg_data |= 0xc0000000;
-+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
-+ (port_num << 8)), reg_data);
-+
-+ /* Disable the TMAC */
-+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
-+ (port_num << 12));
-+ reg_data &= ~(0x00000001);
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
-+ (port_num << 12)), reg_data);
-+
-+ for (curr = 0;
-+ (titan_ge_eth->tx_ring_skbs) && (curr < TITAN_GE_TX_QUEUE);
-+ curr++) {
-+ if (titan_ge_eth->tx_skb[curr]) {
-+ dev_kfree_skb(titan_ge_eth->tx_skb[curr]);
-+ titan_ge_eth->tx_ring_skbs--;
-+ }
-+ }
-+
-+ if (titan_ge_eth->tx_ring_skbs != 0)
-+ printk
-+ ("%s: Error on Tx descriptor free - could not free %d"
-+ " descriptors\n", netdev->name,
-+ titan_ge_eth->tx_ring_skbs);
-+
-+#ifndef TITAN_RX_RING_IN_SRAM
-+ dma_free_coherent(&titan_ge_device[port_num]->dev,
-+ titan_ge_eth->tx_desc_area_size,
-+ (void *) titan_ge_eth->tx_desc_area,
-+ titan_ge_eth->tx_dma);
-+#endif
-+}
-+
-+/*
-+ * Free the Rx ring
-+ */
-+static void titan_ge_free_rx_rings(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ unsigned int port_num = titan_ge_eth->port_num;
-+ unsigned int curr;
-+ unsigned long reg_data;
-+
-+ /* Stop the Rx DMA */
-+ reg_data = TITAN_GE_READ(TITAN_GE_CHANNEL0_CONFIG +
-+ (port_num << 8));
-+ reg_data |= 0x000c0000;
-+ TITAN_GE_WRITE((TITAN_GE_CHANNEL0_CONFIG +
-+ (port_num << 8)), reg_data);
-+
-+ /* Disable the RMAC */
-+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
-+ (port_num << 12));
-+ reg_data &= ~(0x00000001);
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
-+ (port_num << 12)), reg_data);
-+
-+ for (curr = 0;
-+ titan_ge_eth->rx_ring_skbs && (curr < TITAN_GE_RX_QUEUE);
-+ curr++) {
-+ if (titan_ge_eth->rx_skb[curr]) {
-+ dev_kfree_skb(titan_ge_eth->rx_skb[curr]);
-+ titan_ge_eth->rx_ring_skbs--;
-+ }
-+ }
-+
-+ if (titan_ge_eth->rx_ring_skbs != 0)
-+ printk(KERN_ERR
-+ "%s: Error in freeing Rx Ring. %d skb's still"
-+ " stuck in RX Ring - ignoring them\n", netdev->name,
-+ titan_ge_eth->rx_ring_skbs);
-+
-+#ifndef TITAN_RX_RING_IN_SRAM
-+ dma_free_coherent(&titan_ge_device[port_num]->dev,
-+ titan_ge_eth->rx_desc_area_size,
-+ (void *) titan_ge_eth->rx_desc_area,
-+ titan_ge_eth->rx_dma);
-+#endif
-+}
-+
-+/*
-+ * Actually does the stop of the Ethernet device
-+ */
-+static void titan_ge_eth_stop(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+
-+ netif_stop_queue(netdev);
-+
-+ titan_ge_port_reset(titan_ge_eth->port_num);
-+
-+ titan_ge_free_tx_rings(netdev);
-+ titan_ge_free_rx_rings(netdev);
-+
-+ /* Disable the Tx and Rx Interrupts for all channels */
-+ TITAN_GE_WRITE(TITAN_GE_INTR_XDMA_IE, 0x0);
-+}
-+
-+/*
-+ * Update the MAC address. Note that we have to write the
-+ * address in three station registers, 16 bits each. And this
-+ * has to be done for TMAC and RMAC
-+ */
-+static void titan_ge_update_mac_address(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+ unsigned int port_num = titan_ge_eth->port_num;
-+ u8 p_addr[6];
-+
-+ memcpy(titan_ge_eth->port_mac_addr, netdev->dev_addr, 6);
-+ memcpy(p_addr, netdev->dev_addr, 6);
-+
-+ /* Update the Address Filtering Match tables */
-+ titan_ge_update_afx(titan_ge_eth);
-+
-+ printk("Station MAC : %d %d %d %d %d %d \n",
-+ p_addr[5], p_addr[4], p_addr[3],
-+ p_addr[2], p_addr[1], p_addr[0]);
-+
-+ /* Set the MAC address here for TMAC and RMAC */
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_HI + (port_num << 12)),
-+ ((p_addr[5] << 8) | p_addr[4]));
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_MID + (port_num << 12)),
-+ ((p_addr[3] << 8) | p_addr[2]));
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_STATION_LOW + (port_num << 12)),
-+ ((p_addr[1] << 8) | p_addr[0]));
-+
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_HI + (port_num << 12)),
-+ ((p_addr[5] << 8) | p_addr[4]));
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_MID + (port_num << 12)),
-+ ((p_addr[3] << 8) | p_addr[2]));
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_STATION_LOW + (port_num << 12)),
-+ ((p_addr[1] << 8) | p_addr[0]));
-+}
-+
-+/*
-+ * Set the MAC address of the Ethernet device
-+ */
-+static int titan_ge_set_mac_address(struct net_device *dev, void *addr)
-+{
-+ titan_ge_port_info *tp = netdev_priv(dev);
-+ struct sockaddr *sa = addr;
-+
-+ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
-+
-+ spin_lock_irq(&tp->lock);
-+ titan_ge_update_mac_address(dev);
-+ spin_unlock_irq(&tp->lock);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Get the Ethernet device stats
-+ */
-+static struct net_device_stats *titan_ge_get_stats(struct net_device *netdev)
-+{
-+ titan_ge_port_info *titan_ge_eth = netdev_priv(netdev);
-+
-+ return &titan_ge_eth->stats;
-+}
-+
-+/*
-+ * Initialize the Rx descriptor ring for the Titan Ge
-+ */
-+static int titan_ge_init_rx_desc_ring(titan_ge_port_info * titan_eth_port,
-+ int rx_desc_num,
-+ int rx_buff_size,
-+ unsigned long rx_desc_base_addr,
-+ unsigned long rx_buff_base_addr,
-+ unsigned long rx_dma)
-+{
-+ volatile titan_ge_rx_desc *rx_desc;
-+ unsigned long buffer_addr;
-+ int index;
-+ unsigned long titan_ge_rx_desc_bus = rx_dma;
-+
-+ buffer_addr = rx_buff_base_addr;
-+ rx_desc = (titan_ge_rx_desc *) rx_desc_base_addr;
-+
-+ /* Check alignment */
-+ if (rx_buff_base_addr & 0xF)
-+ return 0;
-+
-+ /* Check Rx buffer size */
-+ if ((rx_buff_size < 8) || (rx_buff_size > TITAN_GE_MAX_RX_BUFFER))
-+ return 0;
-+
-+ /* 64-bit alignment
-+ if ((rx_buff_base_addr + rx_buff_size) & 0x7)
-+ return 0; */
-+
-+ /* Initialize the Rx desc ring */
-+ for (index = 0; index < rx_desc_num; index++) {
-+ titan_ge_rx_desc_bus += sizeof(titan_ge_rx_desc);
-+ rx_desc[index].cmd_sts = 0;
-+ rx_desc[index].buffer_addr = buffer_addr;
-+ titan_eth_port->rx_skb[index] = NULL;
-+ buffer_addr += rx_buff_size;
-+ }
-+
-+ titan_eth_port->rx_curr_desc_q = 0;
-+ titan_eth_port->rx_used_desc_q = 0;
-+
-+ titan_eth_port->rx_desc_area = (titan_ge_rx_desc *) rx_desc_base_addr;
-+ titan_eth_port->rx_desc_area_size =
-+ rx_desc_num * sizeof(titan_ge_rx_desc);
-+
-+ titan_eth_port->rx_dma = rx_dma;
-+
-+ return TITAN_OK;
-+}
-+
-+/*
-+ * Initialize the Tx descriptor ring. Descriptors in the SRAM
-+ */
-+static int titan_ge_init_tx_desc_ring(titan_ge_port_info * titan_ge_port,
-+ int tx_desc_num,
-+ unsigned long tx_desc_base_addr,
-+ unsigned long tx_dma)
-+{
-+ titan_ge_tx_desc *tx_desc;
-+ int index;
-+ unsigned long titan_ge_tx_desc_bus = tx_dma;
-+
-+ if (tx_desc_base_addr & 0xF)
-+ return 0;
-+
-+ tx_desc = (titan_ge_tx_desc *) tx_desc_base_addr;
-+
-+ for (index = 0; index < tx_desc_num; index++) {
-+ titan_ge_port->tx_dma_array[index] =
-+ (dma_addr_t) titan_ge_tx_desc_bus;
-+ titan_ge_tx_desc_bus += sizeof(titan_ge_tx_desc);
-+ tx_desc[index].cmd_sts = 0x0000;
-+ tx_desc[index].buffer_len = 0;
-+ tx_desc[index].buffer_addr = 0x00000000;
-+ titan_ge_port->tx_skb[index] = NULL;
-+ }
-+
-+ titan_ge_port->tx_curr_desc_q = 0;
-+ titan_ge_port->tx_used_desc_q = 0;
-+
-+ titan_ge_port->tx_desc_area = (titan_ge_tx_desc *) tx_desc_base_addr;
-+ titan_ge_port->tx_desc_area_size =
-+ tx_desc_num * sizeof(titan_ge_tx_desc);
-+
-+ titan_ge_port->tx_dma = tx_dma;
-+ return TITAN_OK;
-+}
-+
-+/*
-+ * Initialize the device as an Ethernet device
-+ */
-+static int __init titan_ge_probe(struct device *device)
-+{
-+ titan_ge_port_info *titan_ge_eth;
-+ struct net_device *netdev;
-+ int port = to_platform_device(device)->id;
-+ int err;
-+
-+ netdev = alloc_etherdev(sizeof(titan_ge_port_info));
-+ if (!netdev) {
-+ err = -ENODEV;
-+ goto out;
-+ }
-+
-+ netdev->open = titan_ge_open;
-+ netdev->stop = titan_ge_stop;
-+ netdev->hard_start_xmit = titan_ge_start_xmit;
-+ netdev->get_stats = titan_ge_get_stats;
-+ netdev->set_multicast_list = titan_ge_set_multi;
-+ netdev->set_mac_address = titan_ge_set_mac_address;
-+
-+ /* Tx timeout */
-+ netdev->tx_timeout = titan_ge_tx_timeout;
-+ netdev->watchdog_timeo = 2 * HZ;
-+
-+ /* Set these to very high values */
-+ netdev->poll = titan_ge_poll;
-+ netdev->weight = 64;
-+
-+ netdev->tx_queue_len = TITAN_GE_TX_QUEUE;
-+ netif_carrier_off(netdev);
-+ netdev->base_addr = 0;
-+
-+ netdev->change_mtu = titan_ge_change_mtu;
-+
-+ titan_ge_eth = netdev_priv(netdev);
-+ /* Allocation of memory for the driver structures */
-+
-+ titan_ge_eth->port_num = port;
-+
-+ /* Configure the Tx timeout handler */
-+ INIT_WORK(&titan_ge_eth->tx_timeout_task,
-+ (void (*)(void *)) titan_ge_tx_timeout_task, netdev);
-+
-+ spin_lock_init(&titan_ge_eth->lock);
-+
-+ /* set MAC addresses */
-+ memcpy(netdev->dev_addr, titan_ge_mac_addr_base, 6);
-+ netdev->dev_addr[5] += port;
-+
-+ err = register_netdev(netdev);
-+
-+ if (err)
-+ goto out_free_netdev;
-+
-+ printk(KERN_NOTICE
-+ "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
-+ netdev->name, port, netdev->dev_addr[0],
-+ netdev->dev_addr[1], netdev->dev_addr[2],
-+ netdev->dev_addr[3], netdev->dev_addr[4],
-+ netdev->dev_addr[5]);
-+
-+ printk(KERN_NOTICE "Rx NAPI supported, Tx Coalescing ON \n");
-+
-+ return 0;
-+
-+out_free_netdev:
-+ kfree(netdev);
-+
-+out:
-+ return err;
-+}
-+
-+static void __devexit titan_device_remove(struct device *device)
-+{
-+}
-+
-+/*
-+ * Reset the Ethernet port
-+ */
-+static void titan_ge_port_reset(unsigned int port_num)
-+{
-+ unsigned int reg_data;
-+
-+ /* Stop the Tx port activity */
-+ reg_data = TITAN_GE_READ(TITAN_GE_TMAC_CONFIG_1 +
-+ (port_num << 12));
-+ reg_data &= ~(0x0001);
-+ TITAN_GE_WRITE((TITAN_GE_TMAC_CONFIG_1 +
-+ (port_num << 12)), reg_data);
-+
-+ /* Stop the Rx port activity */
-+ reg_data = TITAN_GE_READ(TITAN_GE_RMAC_CONFIG_1 +
-+ (port_num << 12));
-+ reg_data &= ~(0x0001);
-+ TITAN_GE_WRITE((TITAN_GE_RMAC_CONFIG_1 +
-+ (port_num << 12)), reg_data);
-+
-+ return;
-+}
-+
-+/*
-+ * Return the Tx desc after use by the XDMA
-+ */
-+static int titan_ge_return_tx_desc(titan_ge_port_info * titan_ge_eth, int port)
-+{
-+ int tx_desc_used;
-+ struct sk_buff *skb;
-+
-+ tx_desc_used = titan_ge_eth->tx_used_desc_q;
-+
-+ /* return right away */
-+ if (tx_desc_used == titan_ge_eth->tx_curr_desc_q)
-+ return TITAN_ERROR;
-+
-+ /* Now the critical stuff */
-+ skb = titan_ge_eth->tx_skb[tx_desc_used];
-+
-+ dev_kfree_skb_any(skb);
-+
-+ titan_ge_eth->tx_skb[tx_desc_used] = NULL;
-+ titan_ge_eth->tx_used_desc_q =
-+ (tx_desc_used + 1) % TITAN_GE_TX_QUEUE;
-+
-+ return 0;
-+}
-+
-+/*
-+ * Coalescing for the Tx path
-+ */
-+static unsigned long titan_ge_tx_coal(unsigned long delay, int port)
-+{
-+ unsigned long rx_delay;
-+
-+ rx_delay = TITAN_GE_READ(TITAN_GE_INT_COALESCING);
-+ delay = (delay << 16) | rx_delay;
-+
-+ TITAN_GE_WRITE(TITAN_GE_INT_COALESCING, delay);
-+ TITAN_GE_WRITE(0x5038, delay);
-+
-+ return delay;
-+}
-+
-+static struct device_driver titan_soc_driver = {
-+ .name = titan_string,
-+ .bus = &platform_bus_type,
-+ .probe = titan_ge_probe,
-+ .remove = __devexit_p(titan_device_remove),
-+};
-+
-+static void titan_platform_release (struct device *device)
-+{
-+ struct platform_device *pldev;
-+
-+ /* free device */
-+ pldev = to_platform_device (device);
-+ kfree (pldev);
-+}
-+
-+/*
-+ * Register the Titan GE with the kernel
-+ */
-+static int __init titan_ge_init_module(void)
-+{
-+ struct platform_device *pldev;
-+ unsigned int version, device;
-+ int i;
-+
-+ printk(KERN_NOTICE
-+ "PMC-Sierra TITAN 10/100/1000 Ethernet Driver \n");
-+
-+ titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE);
-+ if (!titan_ge_base) {
-+ printk("Mapping Titan GE failed\n");
-+ goto out;
-+ }
-+
-+ device = TITAN_GE_READ(TITAN_GE_DEVICE_ID);
-+ version = (device & 0x000f0000) >> 16;
-+ device &= 0x0000ffff;
-+
-+ printk(KERN_NOTICE "Device Id : %x, Version : %x \n", device, version);
-+
-+#ifdef TITAN_RX_RING_IN_SRAM
-+ titan_ge_sram = (unsigned long) ioremap(TITAN_SRAM_BASE,
-+ TITAN_SRAM_SIZE);
-+ if (!titan_ge_sram) {
-+ printk("Mapping Titan SRAM failed\n");
-+ goto out_unmap_ge;
-+ }
-+#endif
-+
-+ if (driver_register(&titan_soc_driver)) {
-+ printk(KERN_ERR "Driver registration failed\n");
-+ goto out_unmap_sram;
-+ }
-+
-+ for (i = 0; i < 3; i++) {
-+ titan_ge_device[i] = NULL;
-+
-+ if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL)))
-+ continue;
-+
-+ memset (pldev, 0, sizeof (*pldev));
-+ pldev->name = titan_string;
-+ pldev->id = i;
-+ pldev->dev.release = titan_platform_release;
-+ titan_ge_device[i] = pldev;
-+
-+ if (platform_device_register (pldev)) {
-+ kfree (pldev);
-+ titan_ge_device[i] = NULL;
-+ continue;
-+ }
-+
-+ if (!pldev->dev.driver) {
-+ /*
-+ * The driver was not bound to this device, there was
-+ * no hardware at this address. Unregister it, as the
-+ * release fuction will take care of freeing the
-+ * allocated structure
-+ */
-+ titan_ge_device[i] = NULL;
-+ platform_device_unregister (pldev);
-+ }
-+ }
-+
-+ return 0;
-+
-+out_unmap_sram:
-+ iounmap((void *)titan_ge_sram);
-+
-+out_unmap_ge:
-+ iounmap((void *)titan_ge_base);
-+
-+out:
-+ return -ENOMEM;
-+}
-+
-+/*
-+ * Unregister the Titan GE from the kernel
-+ */
-+static void __exit titan_ge_cleanup_module(void)
-+{
-+ int i;
-+
-+ driver_unregister(&titan_soc_driver);
-+
-+ for (i = 0; i < 3; i++) {
-+ if (titan_ge_device[i]) {
-+ platform_device_unregister (titan_ge_device[i]);
-+ titan_ge_device[i] = NULL;
-+ }
-+ }
-+
-+ iounmap((void *)titan_ge_sram);
-+ iounmap((void *)titan_ge_base);
-+}
-+
-+MODULE_AUTHOR("Manish Lachwani <lachwani@pmc-sierra.com>");
-+MODULE_DESCRIPTION("Titan GE Ethernet driver");
-+MODULE_LICENSE("GPL");
-+
-+module_init(titan_ge_init_module);
-+module_exit(titan_ge_cleanup_module);
-diff --git a/drivers/net/titan_ge.h b/drivers/net/titan_ge.h
-new file mode 100644
-index 0000000..3719f78
---- /dev/null
-+++ b/drivers/net/titan_ge.h
-@@ -0,0 +1,415 @@
-+#ifndef _TITAN_GE_H_
-+#define _TITAN_GE_H_
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/spinlock.h>
-+#include <asm/byteorder.h>
-+
-+/*
-+ * These functions should be later moved to a more generic location since there
-+ * will be others accessing it also
-+ */
-+
-+/*
-+ * This is the way it works: LKB5 Base is at 0x0128. TITAN_BASE is defined in
-+ * include/asm/titan_dep.h. TITAN_GE_BASE is the value in the TITAN_GE_LKB5
-+ * register.
-+ */
-+
-+#define TITAN_GE_BASE 0xfe000000UL
-+#define TITAN_GE_SIZE 0x10000UL
-+
-+extern unsigned long titan_ge_base;
-+
-+#define TITAN_GE_WRITE(offset, data) \
-+ *(volatile u32 *)(titan_ge_base + (offset)) = (data)
-+
-+#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset))
-+
-+#ifndef msec_delay
-+#define msec_delay(x) do { if(in_interrupt()) { \
-+ /* Don't mdelay in interrupt context! */ \
-+ BUG(); \
-+ } else { \
-+ set_current_state(TASK_UNINTERRUPTIBLE); \
-+ schedule_timeout((x * HZ)/1000); \
-+ } } while(0)
-+#endif
-+
-+#define TITAN_GE_PORT_0
-+
-+#define TITAN_SRAM_BASE ((OCD_READ(RM9000x2_OCD_LKB13) & ~1) << 4)
-+#define TITAN_SRAM_SIZE 0x2000UL
-+
-+/*
-+ * We may need these constants
-+ */
-+#define TITAN_BIT0 0x00000001
-+#define TITAN_BIT1 0x00000002
-+#define TITAN_BIT2 0x00000004
-+#define TITAN_BIT3 0x00000008
-+#define TITAN_BIT4 0x00000010
-+#define TITAN_BIT5 0x00000020
-+#define TITAN_BIT6 0x00000040
-+#define TITAN_BIT7 0x00000080
-+#define TITAN_BIT8 0x00000100
-+#define TITAN_BIT9 0x00000200
-+#define TITAN_BIT10 0x00000400
-+#define TITAN_BIT11 0x00000800
-+#define TITAN_BIT12 0x00001000
-+#define TITAN_BIT13 0x00002000
-+#define TITAN_BIT14 0x00004000
-+#define TITAN_BIT15 0x00008000
-+#define TITAN_BIT16 0x00010000
-+#define TITAN_BIT17 0x00020000
-+#define TITAN_BIT18 0x00040000
-+#define TITAN_BIT19 0x00080000
-+#define TITAN_BIT20 0x00100000
-+#define TITAN_BIT21 0x00200000
-+#define TITAN_BIT22 0x00400000
-+#define TITAN_BIT23 0x00800000
-+#define TITAN_BIT24 0x01000000
-+#define TITAN_BIT25 0x02000000
-+#define TITAN_BIT26 0x04000000
-+#define TITAN_BIT27 0x08000000
-+#define TITAN_BIT28 0x10000000
-+#define TITAN_BIT29 0x20000000
-+#define TITAN_BIT30 0x40000000
-+#define TITAN_BIT31 0x80000000
-+
-+/* Flow Control */
-+#define TITAN_GE_FC_NONE 0x0
-+#define TITAN_GE_FC_FULL 0x1
-+#define TITAN_GE_FC_TX_PAUSE 0x2
-+#define TITAN_GE_FC_RX_PAUSE 0x3
-+
-+/* Duplex Settings */
-+#define TITAN_GE_FULL_DUPLEX 0x1
-+#define TITAN_GE_HALF_DUPLEX 0x2
-+
-+/* Speed settings */
-+#define TITAN_GE_SPEED_1000 0x1
-+#define TITAN_GE_SPEED_100 0x2
-+#define TITAN_GE_SPEED_10 0x3
-+
-+/* Debugging info only */
-+#undef TITAN_DEBUG
-+
-+/* Keep the rings in the Titan's SSRAM */
-+#define TITAN_RX_RING_IN_SRAM
-+
-+#ifdef CONFIG_64BIT
-+#define TITAN_GE_IE_MASK 0xfffffffffb001b64
-+#define TITAN_GE_IE_STATUS 0xfffffffffb001b60
-+#else
-+#define TITAN_GE_IE_MASK 0xfb001b64
-+#define TITAN_GE_IE_STATUS 0xfb001b60
-+#endif
-+
-+/* Support for Jumbo Frames */
-+#undef TITAN_GE_JUMBO_FRAMES
-+
-+/* Rx buffer size */
-+#ifdef TITAN_GE_JUMBO_FRAMES
-+#define TITAN_GE_JUMBO_BUFSIZE 9080
-+#else
-+#define TITAN_GE_STD_BUFSIZE 1580
-+#endif
-+
-+/*
-+ * Tx and Rx Interrupt Coalescing parameter. These values are
-+ * for 1 Ghz processor. Rx coalescing can be taken care of
-+ * by NAPI. NAPI is adaptive and hence useful. Tx coalescing
-+ * is not adaptive. Hence, these values need to be adjusted
-+ * based on load, CPU speed etc.
-+ */
-+#define TITAN_GE_RX_COAL 150
-+#define TITAN_GE_TX_COAL 300
-+
-+#if defined(__BIG_ENDIAN)
-+
-+/* Define the Rx descriptor */
-+typedef struct eth_rx_desc {
-+ u32 reserved; /* Unused */
-+ u32 buffer_addr; /* CPU buffer address */
-+ u32 cmd_sts; /* Command and Status */
-+ u32 buffer; /* XDMA buffer address */
-+} titan_ge_rx_desc;
-+
-+/* Define the Tx descriptor */
-+typedef struct eth_tx_desc {
-+ u16 cmd_sts; /* Command, Status and Buffer count */
-+ u16 buffer_len; /* Length of the buffer */
-+ u32 buffer_addr; /* Physical address of the buffer */
-+} titan_ge_tx_desc;
-+
-+#elif defined(__LITTLE_ENDIAN)
-+
-+/* Define the Rx descriptor */
-+typedef struct eth_rx_desc {
-+ u32 buffer_addr; /* CPU buffer address */
-+ u32 reserved; /* Unused */
-+ u32 buffer; /* XDMA buffer address */
-+ u32 cmd_sts; /* Command and Status */
-+} titan_ge_rx_desc;
-+
-+/* Define the Tx descriptor */
-+typedef struct eth_tx_desc {
-+ u32 buffer_addr; /* Physical address of the buffer */
-+ u16 buffer_len; /* Length of the buffer */
-+ u16 cmd_sts; /* Command, Status and Buffer count */
-+} titan_ge_tx_desc;
-+#endif
-+
-+/* Default Tx Queue Size */
-+#define TITAN_GE_TX_QUEUE 128
-+#define TITAN_TX_RING_BYTES (TITAN_GE_TX_QUEUE * sizeof(struct eth_tx_desc))
-+
-+/* Default Rx Queue Size */
-+#define TITAN_GE_RX_QUEUE 64
-+#define TITAN_RX_RING_BYTES (TITAN_GE_RX_QUEUE * sizeof(struct eth_rx_desc))
-+
-+/* Packet Structure */
-+typedef struct _pkt_info {
-+ unsigned int len;
-+ unsigned int cmd_sts;
-+ unsigned int buffer;
-+ struct sk_buff *skb;
-+ unsigned int checksum;
-+} titan_ge_packet;
-+
-+
-+#define PHYS_CNT 3
-+
-+/* Titan Port specific data structure */
-+typedef struct _eth_port_ctrl {
-+ unsigned int port_num;
-+ u8 port_mac_addr[6];
-+
-+ /* Rx descriptor pointers */
-+ int rx_curr_desc_q, rx_used_desc_q;
-+
-+ /* Tx descriptor pointers */
-+ int tx_curr_desc_q, tx_used_desc_q;
-+
-+ /* Rx descriptor area */
-+ volatile titan_ge_rx_desc *rx_desc_area;
-+ unsigned int rx_desc_area_size;
-+ struct sk_buff* rx_skb[TITAN_GE_RX_QUEUE];
-+
-+ /* Tx Descriptor area */
-+ volatile titan_ge_tx_desc *tx_desc_area;
-+ unsigned int tx_desc_area_size;
-+ struct sk_buff* tx_skb[TITAN_GE_TX_QUEUE];
-+
-+ /* Timeout task */
-+ struct work_struct tx_timeout_task;
-+
-+ /* DMA structures and handles */
-+ dma_addr_t tx_dma;
-+ dma_addr_t rx_dma;
-+ dma_addr_t tx_dma_array[TITAN_GE_TX_QUEUE];
-+
-+ /* Device lock */
-+ spinlock_t lock;
-+
-+ unsigned int tx_ring_skbs;
-+ unsigned int rx_ring_size;
-+ unsigned int tx_ring_size;
-+ unsigned int rx_ring_skbs;
-+
-+ struct net_device_stats stats;
-+
-+ /* Tx and Rx coalescing */
-+ unsigned long rx_int_coal;
-+ unsigned long tx_int_coal;
-+
-+ /* Threshold for replenishing the Rx and Tx rings */
-+ unsigned int tx_threshold;
-+ unsigned int rx_threshold;
-+
-+ /* NAPI work limit */
-+ unsigned int rx_work_limit;
-+} titan_ge_port_info;
-+
-+/* Titan specific constants */
-+#define TITAN_ETH_PORT_IRQ 3
-+
-+/* Max Rx buffer */
-+#define TITAN_GE_MAX_RX_BUFFER 65536
-+
-+/* Tx and Rx Error */
-+#define TITAN_GE_ERROR
-+
-+/* Rx Descriptor Command and Status */
-+
-+#define TITAN_GE_RX_CRC_ERROR TITAN_BIT27 /* crc error */
-+#define TITAN_GE_RX_OVERFLOW_ERROR TITAN_BIT15 /* overflow */
-+#define TITAN_GE_RX_BUFFER_OWNED TITAN_BIT21 /* buffer ownership */
-+#define TITAN_GE_RX_STP TITAN_BIT31 /* start of packet */
-+#define TITAN_GE_RX_BAM TITAN_BIT30 /* broadcast address match */
-+#define TITAN_GE_RX_PAM TITAN_BIT28 /* physical address match */
-+#define TITAN_GE_RX_LAFM TITAN_BIT29 /* logical address filter match */
-+#define TITAN_GE_RX_VLAN TITAN_BIT26 /* virtual lans */
-+#define TITAN_GE_RX_PERR TITAN_BIT19 /* packet error */
-+#define TITAN_GE_RX_TRUNC TITAN_BIT20 /* packet size greater than 32 buffers */
-+
-+/* Tx Descriptor Command */
-+#define TITAN_GE_TX_BUFFER_OWNED TITAN_BIT5 /* buffer ownership */
-+#define TITAN_GE_TX_ENABLE_INTERRUPT TITAN_BIT15 /* Interrupt Enable */
-+
-+/* Return Status */
-+#define TITAN_OK 0x1 /* Good Status */
-+#define TITAN_ERROR 0x2 /* Error Status */
-+
-+/* MIB specific register offset */
-+#define TITAN_GE_MSTATX_STATS_BASE_LOW 0x0800 /* MSTATX COUNTL[15:0] */
-+#define TITAN_GE_MSTATX_STATS_BASE_MID 0x0804 /* MSTATX COUNTM[15:0] */
-+#define TITAN_GE_MSTATX_STATS_BASE_HI 0x0808 /* MSTATX COUNTH[7:0] */
-+#define TITAN_GE_MSTATX_CONTROL 0x0828 /* MSTATX Control */
-+#define TITAN_GE_MSTATX_VARIABLE_SELECT 0x082C /* MSTATX Variable Select */
-+
-+/* MIB counter offsets, add to the TITAN_GE_MSTATX_STATS_BASE_XXX */
-+#define TITAN_GE_MSTATX_RXFRAMESOK 0x0040
-+#define TITAN_GE_MSTATX_RXOCTETSOK 0x0050
-+#define TITAN_GE_MSTATX_RXFRAMES 0x0060
-+#define TITAN_GE_MSTATX_RXOCTETS 0x0070
-+#define TITAN_GE_MSTATX_RXUNICASTFRAMESOK 0x0080
-+#define TITAN_GE_MSTATX_RXBROADCASTFRAMESOK 0x0090
-+#define TITAN_GE_MSTATX_RXMULTICASTFRAMESOK 0x00A0
-+#define TITAN_GE_MSTATX_RXTAGGEDFRAMESOK 0x00B0
-+#define TITAN_GE_MSTATX_RXMACPAUSECONTROLFRAMESOK 0x00C0
-+#define TITAN_GE_MSTATX_RXMACCONTROLFRAMESOK 0x00D0
-+#define TITAN_GE_MSTATX_RXFCSERROR 0x00E0
-+#define TITAN_GE_MSTATX_RXALIGNMENTERROR 0x00F0
-+#define TITAN_GE_MSTATX_RXSYMBOLERROR 0x0100
-+#define TITAN_GE_MSTATX_RXLAYER1ERROR 0x0110
-+#define TITAN_GE_MSTATX_RXINRANGELENGTHERROR 0x0120
-+#define TITAN_GE_MSTATX_RXLONGLENGTHERROR 0x0130
-+#define TITAN_GE_MSTATX_RXLONGLENGTHCRCERROR 0x0140
-+#define TITAN_GE_MSTATX_RXSHORTLENGTHERROR 0x0150
-+#define TITAN_GE_MSTATX_RXSHORTLLENGTHCRCERROR 0x0160
-+#define TITAN_GE_MSTATX_RXFRAMES64OCTETS 0x0170
-+#define TITAN_GE_MSTATX_RXFRAMES65TO127OCTETS 0x0180
-+#define TITAN_GE_MSTATX_RXFRAMES128TO255OCTETS 0x0190
-+#define TITAN_GE_MSTATX_RXFRAMES256TO511OCTETS 0x01A0
-+#define TITAN_GE_MSTATX_RXFRAMES512TO1023OCTETS 0x01B0
-+#define TITAN_GE_MSTATX_RXFRAMES1024TO1518OCTETS 0x01C0
-+#define TITAN_GE_MSTATX_RXFRAMES1519TOMAXSIZE 0x01D0
-+#define TITAN_GE_MSTATX_RXSTATIONADDRESSFILTERED 0x01E0
-+#define TITAN_GE_MSTATX_RXVARIABLE 0x01F0
-+#define TITAN_GE_MSTATX_GENERICADDRESSFILTERED 0x0200
-+#define TITAN_GE_MSTATX_UNICASTFILTERED 0x0210
-+#define TITAN_GE_MSTATX_MULTICASTFILTERED 0x0220
-+#define TITAN_GE_MSTATX_BROADCASTFILTERED 0x0230
-+#define TITAN_GE_MSTATX_HASHFILTERED 0x0240
-+#define TITAN_GE_MSTATX_TXFRAMESOK 0x0250
-+#define TITAN_GE_MSTATX_TXOCTETSOK 0x0260
-+#define TITAN_GE_MSTATX_TXOCTETS 0x0270
-+#define TITAN_GE_MSTATX_TXTAGGEDFRAMESOK 0x0280
-+#define TITAN_GE_MSTATX_TXMACPAUSECONTROLFRAMESOK 0x0290
-+#define TITAN_GE_MSTATX_TXFCSERROR 0x02A0
-+#define TITAN_GE_MSTATX_TXSHORTLENGTHERROR 0x02B0
-+#define TITAN_GE_MSTATX_TXLONGLENGTHERROR 0x02C0
-+#define TITAN_GE_MSTATX_TXSYSTEMERROR 0x02D0
-+#define TITAN_GE_MSTATX_TXMACERROR 0x02E0
-+#define TITAN_GE_MSTATX_TXCARRIERSENSEERROR 0x02F0
-+#define TITAN_GE_MSTATX_TXSQETESTERROR 0x0300
-+#define TITAN_GE_MSTATX_TXUNICASTFRAMESOK 0x0310
-+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESOK 0x0320
-+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESOK 0x0330
-+#define TITAN_GE_MSTATX_TXUNICASTFRAMESATTEMPTED 0x0340
-+#define TITAN_GE_MSTATX_TXBROADCASTFRAMESATTEMPTED 0x0350
-+#define TITAN_GE_MSTATX_TXMULTICASTFRAMESATTEMPTED 0x0360
-+#define TITAN_GE_MSTATX_TXFRAMES64OCTETS 0x0370
-+#define TITAN_GE_MSTATX_TXFRAMES65TO127OCTETS 0x0380
-+#define TITAN_GE_MSTATX_TXFRAMES128TO255OCTETS 0x0390
-+#define TITAN_GE_MSTATX_TXFRAMES256TO511OCTETS 0x03A0
-+#define TITAN_GE_MSTATX_TXFRAMES512TO1023OCTETS 0x03B0
-+#define TITAN_GE_MSTATX_TXFRAMES1024TO1518OCTETS 0x03C0
-+#define TITAN_GE_MSTATX_TXFRAMES1519TOMAXSIZE 0x03D0
-+#define TITAN_GE_MSTATX_TXVARIABLE 0x03E0
-+#define TITAN_GE_MSTATX_RXSYSTEMERROR 0x03F0
-+#define TITAN_GE_MSTATX_SINGLECOLLISION 0x0400
-+#define TITAN_GE_MSTATX_MULTIPLECOLLISION 0x0410
-+#define TITAN_GE_MSTATX_DEFERREDXMISSIONS 0x0420
-+#define TITAN_GE_MSTATX_LATECOLLISIONS 0x0430
-+#define TITAN_GE_MSTATX_ABORTEDDUETOXSCOLLS 0x0440
-+
-+/* Interrupt specific defines */
-+#define TITAN_GE_DEVICE_ID 0x0000 /* Device ID */
-+#define TITAN_GE_RESET 0x0004 /* Reset reg */
-+#define TITAN_GE_TSB_CTRL_0 0x000C /* TSB Control reg 0 */
-+#define TITAN_GE_TSB_CTRL_1 0x0010 /* TSB Control reg 1 */
-+#define TITAN_GE_INTR_GRP0_STATUS 0x0040 /* General Interrupt Group 0 Status */
-+#define TITAN_GE_INTR_XDMA_CORE_A 0x0048 /* XDMA Channel Interrupt Status, Core A*/
-+#define TITAN_GE_INTR_XDMA_CORE_B 0x004C /* XDMA Channel Interrupt Status, Core B*/
-+#define TITAN_GE_INTR_XDMA_IE 0x0058 /* XDMA Channel Interrupt Enable */
-+#define TITAN_GE_SDQPF_ECC_INTR 0x480C /* SDQPF ECC Interrupt Status */
-+#define TITAN_GE_SDQPF_RXFIFO_CTL 0x4828 /* SDQPF RxFifo Control and Interrupt Enb*/
-+#define TITAN_GE_SDQPF_RXFIFO_INTR 0x482C /* SDQPF RxFifo Interrupt Status */
-+#define TITAN_GE_SDQPF_TXFIFO_CTL 0x4928 /* SDQPF TxFifo Control and Interrupt Enb*/
-+#define TITAN_GE_SDQPF_TXFIFO_INTR 0x492C /* SDQPF TxFifo Interrupt Status */
-+#define TITAN_GE_SDQPF_RXFIFO_0 0x4840 /* SDQPF RxFIFO Enable */
-+#define TITAN_GE_SDQPF_TXFIFO_0 0x4940 /* SDQPF TxFIFO Enable */
-+#define TITAN_GE_XDMA_CONFIG 0x5000 /* XDMA Global Configuration */
-+#define TITAN_GE_XDMA_INTR_SUMMARY 0x5010 /* XDMA Interrupt Summary */
-+#define TITAN_GE_XDMA_BUFADDRPRE 0x5018 /* XDMA Buffer Address Prefix */
-+#define TITAN_GE_XDMA_DESCADDRPRE 0x501C /* XDMA Descriptor Address Prefix */
-+#define TITAN_GE_XDMA_PORTWEIGHT 0x502C /* XDMA Port Weight Configuration */
-+
-+/* Rx MAC defines */
-+#define TITAN_GE_RMAC_CONFIG_1 0x1200 /* RMAC Configuration 1 */
-+#define TITAN_GE_RMAC_CONFIG_2 0x1204 /* RMAC Configuration 2 */
-+#define TITAN_GE_RMAC_MAX_FRAME_LEN 0x1208 /* RMAC Max Frame Length */
-+#define TITAN_GE_RMAC_STATION_HI 0x120C /* Rx Station Address High */
-+#define TITAN_GE_RMAC_STATION_MID 0x1210 /* Rx Station Address Middle */
-+#define TITAN_GE_RMAC_STATION_LOW 0x1214 /* Rx Station Address Low */
-+#define TITAN_GE_RMAC_LINK_CONFIG 0x1218 /* RMAC Link Configuration */
-+
-+/* Tx MAC defines */
-+#define TITAN_GE_TMAC_CONFIG_1 0x1240 /* TMAC Configuration 1 */
-+#define TITAN_GE_TMAC_CONFIG_2 0x1244 /* TMAC Configuration 2 */
-+#define TITAN_GE_TMAC_IPG 0x1248 /* TMAC Inter-Packet Gap */
-+#define TITAN_GE_TMAC_STATION_HI 0x124C /* Tx Station Address High */
-+#define TITAN_GE_TMAC_STATION_MID 0x1250 /* Tx Station Address Middle */
-+#define TITAN_GE_TMAC_STATION_LOW 0x1254 /* Tx Station Address Low */
-+#define TITAN_GE_TMAC_MAX_FRAME_LEN 0x1258 /* TMAC Max Frame Length */
-+#define TITAN_GE_TMAC_MIN_FRAME_LEN 0x125C /* TMAC Min Frame Length */
-+#define TITAN_GE_TMAC_PAUSE_FRAME_TIME 0x1260 /* TMAC Pause Frame Time */
-+#define TITAN_GE_TMAC_PAUSE_FRAME_INTERVAL 0x1264 /* TMAC Pause Frame Interval */
-+
-+/* GMII register */
-+#define TITAN_GE_GMII_INTERRUPT_STATUS 0x1348 /* GMII Interrupt Status */
-+#define TITAN_GE_GMII_CONFIG_GENERAL 0x134C /* GMII Configuration General */
-+#define TITAN_GE_GMII_CONFIG_MODE 0x1350 /* GMII Configuration Mode */
-+
-+/* Tx and Rx XDMA defines */
-+#define TITAN_GE_INT_COALESCING 0x5030 /* Interrupt Coalescing */
-+#define TITAN_GE_CHANNEL0_CONFIG 0x5040 /* Channel 0 XDMA config */
-+#define TITAN_GE_CHANNEL0_INTERRUPT 0x504c /* Channel 0 Interrupt Status */
-+#define TITAN_GE_GDI_INTERRUPT_ENABLE 0x5050 /* IE for the GDI Errors */
-+#define TITAN_GE_CHANNEL0_PACKET 0x5060 /* Channel 0 Packet count */
-+#define TITAN_GE_CHANNEL0_BYTE 0x5064 /* Channel 0 Byte count */
-+#define TITAN_GE_CHANNEL0_TX_DESC 0x5054 /* Channel 0 Tx first desc */
-+#define TITAN_GE_CHANNEL0_RX_DESC 0x5058 /* Channel 0 Rx first desc */
-+
-+/* AFX (Address Filter Exact) register offsets for Slice 0 */
-+#define TITAN_GE_AFX_EXACT_MATCH_LOW 0x1100 /* AFX Exact Match Address Low*/
-+#define TITAN_GE_AFX_EXACT_MATCH_MID 0x1104 /* AFX Exact Match Address Mid*/
-+#define TITAN_GE_AFX_EXACT_MATCH_HIGH 0x1108 /* AFX Exact Match Address Hi */
-+#define TITAN_GE_AFX_EXACT_MATCH_VID 0x110C /* AFX Exact Match VID */
-+#define TITAN_GE_AFX_MULTICAST_HASH_LOW 0x1110 /* AFX Multicast HASH Low */
-+#define TITAN_GE_AFX_MULTICAST_HASH_MIDLOW 0x1114 /* AFX Multicast HASH MidLow */
-+#define TITAN_GE_AFX_MULTICAST_HASH_MIDHI 0x1118 /* AFX Multicast HASH MidHi */
-+#define TITAN_GE_AFX_MULTICAST_HASH_HI 0x111C /* AFX Multicast HASH Hi */
-+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_0 0x1120 /* AFX Address Filter Ctrl 0 */
-+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_1 0x1124 /* AFX Address Filter Ctrl 1 */
-+#define TITAN_GE_AFX_ADDRS_FILTER_CTRL_2 0x1128 /* AFX Address Filter Ctrl 2 */
-+
-+/* Traffic Groomer block */
-+#define TITAN_GE_TRTG_CONFIG 0x1000 /* TRTG Config */
-+
-+#endif /* _TITAN_GE_H_ */
-+
-diff --git a/drivers/net/titan_mdio.c b/drivers/net/titan_mdio.c
-new file mode 100644
-index 0000000..8a8785b
---- /dev/null
-+++ b/drivers/net/titan_mdio.c
-@@ -0,0 +1,217 @@
-+/*
-+ * drivers/net/titan_mdio.c - Driver for Titan ethernet ports
-+ *
-+ * Copyright (C) 2003 PMC-Sierra Inc.
-+ * Author : Manish Lachwani (lachwani@pmc-sierra.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 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.
-+ *
-+ * Management Data IO (MDIO) driver for the Titan GMII. Interacts with the Marvel PHY
-+ * on the Titan. No support for the TBI as yet.
-+ *
-+ */
-+
-+#include "titan_mdio.h"
-+
-+#define MDIO_DEBUG
-+
-+/*
-+ * Local constants
-+ */
-+#define MAX_CLKA 1023
-+#define MAX_PHY_DEV 31
-+#define MAX_PHY_REG 31
-+#define WRITEADDRS_OPCODE 0x0
-+#define READ_OPCODE 0x2
-+#define WRITE_OPCODE 0x1
-+#define MAX_MDIO_POLL 100
-+
-+/*
-+ * Titan MDIO and SCMB registers
-+ */
-+#define TITAN_GE_SCMB_CONTROL 0x01c0 /* SCMB Control */
-+#define TITAN_GE_SCMB_CLKA 0x01c4 /* SCMB Clock A */
-+#define TITAN_GE_MDIO_COMMAND 0x01d0 /* MDIO Command */
-+#define TITAN_GE_MDIO_DEVICE_PORT_ADDRESS 0x01d4 /* MDIO Device and Port addrs */
-+#define TITAN_GE_MDIO_DATA 0x01d8 /* MDIO Data */
-+#define TITAN_GE_MDIO_INTERRUPTS 0x01dC /* MDIO Interrupts */
-+
-+/*
-+ * Function to poll the MDIO
-+ */
-+static int titan_ge_mdio_poll(void)
-+{
-+ int i, val;
-+
-+ for (i = 0; i < MAX_MDIO_POLL; i++) {
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
-+
-+ if (!(val & 0x8000))
-+ return TITAN_GE_MDIO_GOOD;
-+ }
-+
-+ return TITAN_GE_MDIO_ERROR;
-+}
-+
-+
-+/*
-+ * Initialize and configure the MDIO
-+ */
-+int titan_ge_mdio_setup(titan_ge_mdio_config *titan_mdio)
-+{
-+ unsigned long val;
-+
-+ /* Reset the SCMB and program into MDIO mode*/
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x9000);
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CONTROL, 0x1000);
-+
-+ /* CLK A */
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_SCMB_CLKA);
-+ val = ( (val & ~(0x03ff)) | (titan_mdio->clka & 0x03ff));
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_SCMB_CLKA, val);
-+
-+ /* Preamble Suppresion */
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
-+ val = ( (val & ~(0x0001)) | (titan_mdio->mdio_spre & 0x0001));
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
-+
-+ /* MDIO mode */
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
-+ val = ( (val & ~(0x4000)) | (titan_mdio->mdio_mode & 0x4000));
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
-+
-+ return TITAN_GE_MDIO_GOOD;
-+}
-+
-+/*
-+ * Set the PHY address in indirect mode
-+ */
-+int titan_ge_mdio_inaddrs(int dev_addr, int reg_addr)
-+{
-+ volatile unsigned long val;
-+
-+ /* Setup the PHY device */
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
-+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
-+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
-+
-+ /* Write the new address */
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
-+ val = ( (val & ~(0x0300)) | ( (WRITEADDRS_OPCODE << 8) & 0x0300));
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
-+
-+ return TITAN_GE_MDIO_GOOD;
-+}
-+
-+/*
-+ * Read the MDIO register. This is what the individual parametes mean:
-+ *
-+ * dev_addr : PHY ID
-+ * reg_addr : register offset
-+ *
-+ * See the spec for the Titan MAC. We operate in the Direct Mode.
-+ */
-+
-+#define MAX_RETRIES 2
-+
-+int titan_ge_mdio_read(int dev_addr, int reg_addr, unsigned int *pdata)
-+{
-+ volatile unsigned long val;
-+ int retries = 0;
-+
-+ /* Setup the PHY device */
-+
-+again:
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
-+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
-+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
-+ val |= 0x4000;
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
-+
-+ udelay(30);
-+
-+ /* Issue the read command */
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
-+ val = ( (val & ~(0x0300)) | ( (READ_OPCODE << 8) & 0x0300));
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
-+
-+ udelay(30);
-+
-+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
-+ return TITAN_GE_MDIO_ERROR;
-+
-+ *pdata = (unsigned int)TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DATA);
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);
-+
-+ udelay(30);
-+
-+ if (val & 0x2) {
-+ if (retries == MAX_RETRIES)
-+ return TITAN_GE_MDIO_ERROR;
-+ else {
-+ retries++;
-+ goto again;
-+ }
-+ }
-+
-+ return TITAN_GE_MDIO_GOOD;
-+}
-+
-+/*
-+ * Write to the MDIO register
-+ *
-+ * dev_addr : PHY ID
-+ * reg_addr : register that needs to be written to
-+ *
-+ */
-+int titan_ge_mdio_write(int dev_addr, int reg_addr, unsigned int data)
-+{
-+ volatile unsigned long val;
-+
-+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
-+ return TITAN_GE_MDIO_ERROR;
-+
-+ /* Setup the PHY device */
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS);
-+ val = ( (val & ~(0x1f00)) | ( (dev_addr << 8) & 0x1f00));
-+ val = ( (val & ~(0x001f)) | ( reg_addr & 0x001f));
-+ val |= 0x4000;
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DEVICE_PORT_ADDRESS, val);
-+
-+ udelay(30);
-+
-+ /* Setup the data to write */
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_DATA, data);
-+
-+ udelay(30);
-+
-+ /* Issue the write command */
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_COMMAND);
-+ val = ( (val & ~(0x0300)) | ( (WRITE_OPCODE << 8) & 0x0300));
-+ TITAN_GE_MDIO_WRITE(TITAN_GE_MDIO_COMMAND, val);
-+
-+ udelay(30);
-+
-+ if (titan_ge_mdio_poll() != TITAN_GE_MDIO_GOOD)
-+ return TITAN_GE_MDIO_ERROR;
-+
-+ val = TITAN_GE_MDIO_READ(TITAN_GE_MDIO_INTERRUPTS);
-+ if (val & 0x2)
-+ return TITAN_GE_MDIO_ERROR;
-+
-+ return TITAN_GE_MDIO_GOOD;
-+}
-+
-diff --git a/drivers/net/titan_mdio.h b/drivers/net/titan_mdio.h
-new file mode 100644
-index 0000000..5d23344
---- /dev/null
-+++ b/drivers/net/titan_mdio.h
-@@ -0,0 +1,56 @@
-+/*
-+ * MDIO used to interact with the PHY when using GMII/MII
-+ */
-+#ifndef _TITAN_MDIO_H
-+#define _TITAN_MDIO_H
-+
-+#include <linux/netdevice.h>
-+#include <linux/workqueue.h>
-+#include <linux/delay.h>
-+#include "titan_ge.h"
-+
-+
-+#define TITAN_GE_MDIO_ERROR (-9000)
-+#define TITAN_GE_MDIO_GOOD 0
-+
-+#define TITAN_GE_MDIO_BASE titan_ge_base
-+
-+#define TITAN_GE_MDIO_READ(offset) \
-+ *(volatile u32 *)(titan_ge_base + (offset))
-+
-+#define TITAN_GE_MDIO_WRITE(offset, data) \
-+ *(volatile u32 *)(titan_ge_base + (offset)) = (data)
-+
-+
-+/* GMII specific registers */
-+#define TITAN_GE_MARVEL_PHY_ID 0x00
-+#define TITAN_PHY_AUTONEG_ADV 0x04
-+#define TITAN_PHY_LP_ABILITY 0x05
-+#define TITAN_GE_MDIO_MII_CTRL 0x09
-+#define TITAN_GE_MDIO_MII_EXTENDED 0x0f
-+#define TITAN_GE_MDIO_PHY_CTRL 0x10
-+#define TITAN_GE_MDIO_PHY_STATUS 0x11
-+#define TITAN_GE_MDIO_PHY_IE 0x12
-+#define TITAN_GE_MDIO_PHY_IS 0x13
-+#define TITAN_GE_MDIO_PHY_LED 0x18
-+#define TITAN_GE_MDIO_PHY_LED_OVER 0x19
-+#define PHY_ANEG_TIME_WAIT 45 /* 45 seconds wait time */
-+
-+/*
-+ * MDIO Config Structure
-+ */
-+typedef struct {
-+ unsigned int clka;
-+ int mdio_spre;
-+ int mdio_mode;
-+} titan_ge_mdio_config;
-+
-+/*
-+ * Function Prototypes
-+ */
-+int titan_ge_mdio_setup(titan_ge_mdio_config *);
-+int titan_ge_mdio_inaddrs(int, int);
-+int titan_ge_mdio_read(int, int, unsigned int *);
-+int titan_ge_mdio_write(int, int, unsigned int);
-+
-+#endif /* _TITAN_MDIO_H */
-diff --git a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c
-index 3411671..4d252c1 100644
---- a/drivers/net/wireless/rtl818x/rtl8187/rfkill.c
-+++ b/drivers/net/wireless/rtl818x/rtl8187/rfkill.c
-@@ -22,6 +22,10 @@
-
- static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv)
- {
-+#ifdef CONFIG_LEMOTE_MACH2F
-+ /* Allow users to activate rfkill through only the /sys interface */
-+ return 1;
-+#else
- u8 gpio;
-
- gpio = rtl818x_ioread8(priv, &priv->map->GPIO0);
-@@ -29,6 +33,7 @@ static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv)
- gpio = rtl818x_ioread8(priv, &priv->map->GPIO1);
-
- return gpio & priv->rfkill_mask;
-+#endif
- }
-
- void rtl8187_rfkill_init(struct ieee80211_hw *hw)
-diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
-index 09fde58..eacabd1 100644
---- a/drivers/platform/Kconfig
-+++ b/drivers/platform/Kconfig
-@@ -4,5 +4,8 @@ endif
- if GOLDFISH
- source "drivers/platform/goldfish/Kconfig"
- endif
-+if MIPS
-+source "drivers/platform/mips/Kconfig"
-+endif
-
- source "drivers/platform/chrome/Kconfig"
-diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
-index 3656b7b..ca26925 100644
---- a/drivers/platform/Makefile
-+++ b/drivers/platform/Makefile
-@@ -3,6 +3,7 @@
- #
-
- obj-$(CONFIG_X86) += x86/
-+obj-$(CONFIG_MIPS) += mips/
- obj-$(CONFIG_OLPC) += olpc/
- obj-$(CONFIG_GOLDFISH) += goldfish/
- obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
-diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
-new file mode 100644
-index 0000000..722d690
---- /dev/null
-+++ b/drivers/platform/mips/Kconfig
-@@ -0,0 +1,60 @@
-+#
-+# MIPS Platform Specific Drivers
-+#
-+
-+menuconfig MIPS_PLATFORM_DEVICES
-+ bool "MIPS Platform Specific Device Drivers"
-+ default y
-+ help
-+ Say Y here to get to see options for device drivers of various
-+ MIPS platforms, including vendor-specific netbook/laptop/pc extension
-+ drivers. This option alone does not add any kernel code.
-+
-+ If you say N, all options in this submenu will be skipped and disabled.
-+
-+if MIPS_PLATFORM_DEVICES
-+
-+config LEMOTE_YEELOONG2F
-+ tristate "Lemote YeeLoong Laptop"
-+ depends on LEMOTE_MACH2F
-+ select BACKLIGHT_LCD_SUPPORT
-+ select LCD_CLASS_DEVICE
-+ select BACKLIGHT_CLASS_DEVICE
-+ select POWER_SUPPLY
-+ select HWMON
-+ select VIDEO_OUTPUT_CONTROL
-+ select INPUT_SPARSEKMAP
-+ select INPUT_EVDEV
-+ depends on INPUT
-+ default m
-+ help
-+ YeeLoong netbook is a mini laptop made by Lemote, which is basically
-+ compatible to FuLoong2F mini PC, but it has an extra Embedded
-+ Controller(kb3310b) for battery, hotkey, backlight, temperature and
-+ fan management.
-+
-+config LEMOTE_LYNLOONG2F
-+ tristate "Lemote LynLoong PC"
-+ depends on LEMOTE_MACH2F
-+ select BACKLIGHT_LCD_SUPPORT
-+ select BACKLIGHT_CLASS_DEVICE
-+ select VIDEO_OUTPUT_CONTROL
-+ default m
-+ help
-+ LynLoong PC is an AllINONE machine made by Lemote, which is basically
-+ compatible to FuLoong2F Mini PC, the only difference is that it has a
-+ size-fixed screen: 1360x768 with sisfb video driver. and also, it has
-+ its own specific suspend support.
-+
-+config GDIUM_LAPTOP
-+ tristate "GDIUM laptop extras"
-+ depends on DEXXON_GDIUM
-+ select POWER_SUPPLY
-+ select I2C
-+ select INPUT_POLLDEV
-+ default m
-+ help
-+ This mini-driver drives the ST7 chipset present in the Gdium laptops.
-+ This gives battery support, wlan rfkill.
-+
-+endif # MIPS_PLATFORM_DEVICES
-diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile
-new file mode 100644
-index 0000000..f013e78
---- /dev/null
-+++ b/drivers/platform/mips/Makefile
-@@ -0,0 +1,9 @@
-+#
-+# Makefile for MIPS Platform-Specific Drivers
-+#
-+
-+obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o # yeeloong_ecrom.o
-+CFLAGS_yeeloong_laptop.o = -I$(srctree)/arch/mips/loongson/lemote-2f
-+
-+obj-$(CONFIG_LEMOTE_LYNLOONG2F) += lynloong_pc.o
-+obj-$(CONFIG_GDIUM_LAPTOP) += gdium_laptop.o
-diff --git a/drivers/platform/mips/gdium_laptop.c b/drivers/platform/mips/gdium_laptop.c
-new file mode 100644
-index 0000000..41a65ad
---- /dev/null
-+++ b/drivers/platform/mips/gdium_laptop.c
-@@ -0,0 +1,927 @@
-+/*
-+ * gdium_laptop -- Gdium laptop extras
-+ *
-+ * Arnaud Patard <apatard@mandriva.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.
-+ *
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
-+#include <linux/input-polldev.h>
-+#include <linux/debugfs.h>
-+#include <linux/seq_file.h>
-+#include <linux/i2c.h>
-+#include <linux/mutex.h>
-+#include <linux/power_supply.h>
-+#include <linux/workqueue.h>
-+#include <linux/delay.h>
-+#include <linux/slab.h>
-+#include <asm/gpio.h>
-+
-+/* For input device */
-+#define SCAN_INTERVAL 150
-+
-+/* For battery status */
-+#define BAT_SCAN_INTERVAL 500
-+
-+#define EC_FIRM_VERSION 0
-+
-+#if CONFIG_GDIUM_VERSION > 2
-+#define EC_REG_BASE 1
-+#else
-+#define EC_REG_BASE 0
-+#endif
-+
-+#define EC_STATUS (EC_REG_BASE+0)
-+#define EC_STATUS_LID (1<<0)
-+#define EC_STATUS_PWRBUT (1<<1)
-+#define EC_STATUS_BATID (1<<2) /* this bit has no real meaning on v2. */
-+ /* Same as EC_STATUS_ADAPT */
-+ /* but on v3 it's BATID which mean bat present */
-+#define EC_STATUS_SYS_POWER (1<<3)
-+#define EC_STATUS_WLAN (1<<4)
-+#define EC_STATUS_ADAPT (1<<5)
-+
-+#define EC_CTRL (EC_REG_BASE+1)
-+#define EC_CTRL_DDR_CLK (1<<0)
-+#define EC_CTRL_CHARGE_LED (1<<1)
-+#define EC_CTRL_BEEP (1<<2)
-+#define EC_CTRL_SUSB (1<<3) /* memory power */
-+#define EC_CTRL_TRICKLE (1<<4)
-+#define EC_CTRL_WLAN_EN (1<<5)
-+#define EC_CTRL_SUSC (1<<6) /* main power */
-+#define EC_CTRL_CHARGE_EN (1<<7)
-+
-+#define EC_BAT_LOW (EC_REG_BASE+2)
-+#define EC_BAT_HIGH (EC_REG_BASE+3)
-+
-+#define EC_SIGN (EC_REG_BASE+4)
-+#define EC_SIGN_OS 0xAE /* write 0xae to control pm stuff */
-+#define EC_SIGN_EC 0x00 /* write 0x00 to let the st7 manage pm stuff */
-+
-+#if 0
-+#define EC_TEST (EC_REG_BASE+5) /* Depending on firmware version this register */
-+ /* may be the programmation register so don't play */
-+ /* with it */
-+#endif
-+
-+#define BAT_VOLT_PRESENT 500000 /* Min voltage to consider battery present uV */
-+#define BAT_MIN 7000000 /* Min battery voltage in uV */
-+#define BAT_MIN_MV 7000 /* Min battery voltage in mV */
-+#define BAT_TRICKLE_EN 8000000 /* Charging at 1.4A before 8.0V and then charging at 0.25A */
-+#define BAT_MAX 7950000 /* Max battery voltage ~8V in V */
-+#define BAT_MAX_MV 7950 /* Max battery voltage ~8V in V */
-+#define BAT_READ_ERROR 300000 /* battery read error of 0.3V */
-+#define BAT_READ_ERROR_MV 300 /* battery read error of 0.3V */
-+
-+#define SM502_WLAN_ON (224+16)/* SM502 GPIO16 may be used on gdium v2 (v3?) as wlan_on */
-+ /* when R422 is connected */
-+
-+static unsigned char verbose;
-+static unsigned char gpio16;
-+static unsigned char ec;
-+module_param(verbose, byte, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(verbose, "Add some debugging messages");
-+module_param(gpio16, byte, S_IRUGO);
-+MODULE_PARM_DESC(gpio16, "Enable wlan_on signal on SM502");
-+module_param(ec, byte, S_IRUGO);
-+MODULE_PARM_DESC(ec, "Let the ST7 handle the battery (default OS)");
-+
-+struct gdium_laptop_data {
-+ struct i2c_client *client;
-+ struct input_polled_dev *input_polldev;
-+ struct dentry *debugfs;
-+ struct mutex mutex;
-+ struct platform_device *bat_pdev;
-+ struct power_supply gdium_ac;
-+ struct power_supply gdium_battery;
-+ struct workqueue_struct *workqueue;
-+ struct delayed_work work;
-+ char charge_cmd;
-+ /* important registers value */
-+ char status;
-+ char ctrl;
-+ /* mV */
-+ int battery_level;
-+ char version;
-+};
-+
-+/**********************************************************************/
-+/* Low level I2C functions */
-+/* All are supposed to be called with mutex held */
-+/**********************************************************************/
-+/*
-+ * Return battery voltage in mV
-+ * >= 0 battery voltage
-+ * < 0 error
-+ */
-+static s32 ec_read_battery(struct i2c_client *client)
-+{
-+ unsigned char bat_low, bat_high;
-+ s32 data;
-+ unsigned int ret;
-+
-+ /*
-+ * a = battery high
-+ * b = battery low
-+ * bat = a << 2 | b & 0x03;
-+ * battery voltage = (bat / 1024) * 5 * 2
-+ */
-+ data = i2c_smbus_read_byte_data(client, EC_BAT_LOW);
-+ if (data < 0) {
-+ dev_err(&client->dev, "ec_read_bat: read bat_low failed\n");
-+ return data;
-+ }
-+ bat_low = data & 0xff;
-+ if (verbose)
-+ dev_info(&client->dev, "bat_low %x\n", bat_low);
-+
-+ data = i2c_smbus_read_byte_data(client, EC_BAT_HIGH);
-+ if (data < 0) {
-+ dev_err(&client->dev, "ec_read_bat: read bat_high failed\n");
-+ return data;
-+ }
-+ bat_high = data & 0xff;
-+ if (verbose)
-+ dev_info(&client->dev, "bat_high %x\n", bat_high);
-+
-+ ret = (bat_high << 2) | (bat_low & 3);
-+ /*
-+ * mV
-+ */
-+ ret = (ret * 5 * 2) * 1000 / 1024;
-+
-+ return ret;
-+}
-+
-+static s32 ec_read_version(struct i2c_client *client)
-+{
-+#if CONFIG_GDIUM_VERSION > 2
-+ return i2c_smbus_read_byte_data(client, EC_FIRM_VERSION);
-+#else
-+ return 0;
-+#endif
-+}
-+
-+static s32 ec_read_status(struct i2c_client *client)
-+{
-+ return i2c_smbus_read_byte_data(client, EC_STATUS);
-+}
-+
-+static s32 ec_read_ctrl(struct i2c_client *client)
-+{
-+ return i2c_smbus_read_byte_data(client, EC_CTRL);
-+}
-+
-+static s32 ec_write_ctrl(struct i2c_client *client, unsigned char newvalue)
-+{
-+ return i2c_smbus_write_byte_data(client, EC_CTRL, newvalue);
-+}
-+
-+static s32 ec_read_sign(struct i2c_client *client)
-+{
-+ return i2c_smbus_read_byte_data(client, EC_SIGN);
-+}
-+
-+static s32 ec_write_sign(struct i2c_client *client, unsigned char sign)
-+{
-+ unsigned char value;
-+ s32 ret;
-+
-+ ret = i2c_smbus_write_byte_data(client, EC_SIGN, sign);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "ec_set_control: write failed\n");
-+ return ret;
-+ }
-+
-+ value = ec_read_sign(client);
-+ if (value != sign) {
-+ dev_err(&client->dev, "Failed to set control to %s\n",
-+ sign == EC_SIGN_OS ? "OS" : "EC");
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+#if 0
-+static int ec_power_off(struct i2c_client *client)
-+{
-+ char value;
-+ int ret;
-+
-+ value = ec_read_ctrl(client);
-+ if (value < 0) {
-+ dev_err(&client->dev, "ec_power_off: read failed\n");
-+ return value;
-+ }
-+ value &= ~(EC_CTRL_SUSB | EC_CTRL_SUSC);
-+ ret = ec_write_ctrl(client, value);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "ec_power_off: write failed\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+#endif
-+
-+static s32 ec_wlan_status(struct i2c_client *client)
-+{
-+ s32 value;
-+
-+ value = ec_read_ctrl(client);
-+ if (value < 0)
-+ return value;
-+
-+ return (value & EC_CTRL_WLAN_EN) ? 1 : 0;
-+}
-+
-+static s32 ec_wlan_en(struct i2c_client *client, int on)
-+{
-+ s32 value;
-+
-+ value = ec_read_ctrl(client);
-+ if (value < 0)
-+ return value;
-+
-+ value &= ~EC_CTRL_WLAN_EN;
-+ if (on)
-+ value |= EC_CTRL_WLAN_EN;
-+
-+ return ec_write_ctrl(client, value&0xff);
-+}
-+
-+#if 0
-+static s32 ec_led_status(struct i2c_client *client)
-+{
-+ s32 value;
-+
-+ value = ec_read_ctrl(client);
-+ if (value < 0)
-+ return value;
-+
-+ return (value & EC_CTRL_CHARGE_LED) ? 1 : 0;
-+}
-+#endif
-+
-+/* Changing the charging led status has never worked */
-+static s32 ec_led_en(struct i2c_client *client, int on)
-+{
-+#if 0
-+ s32 value;
-+
-+ value = ec_read_ctrl(client);
-+ if (value < 0)
-+ return value;
-+
-+ value &= ~EC_CTRL_CHARGE_LED;
-+ if (on)
-+ value |= EC_CTRL_CHARGE_LED;
-+ return ec_write_ctrl(client, value&0xff);
-+#else
-+ return 0;
-+#endif
-+}
-+
-+static s32 ec_charge_en(struct i2c_client *client, int on, int trickle)
-+{
-+ s32 value;
-+ s32 set = 0;
-+
-+ value = ec_read_ctrl(client);
-+ if (value < 0)
-+ return value;
-+
-+ if (on)
-+ set |= EC_CTRL_CHARGE_EN;
-+ if (trickle)
-+ set |= EC_CTRL_TRICKLE;
-+
-+ /* Be clever : don't change values if you don't need to */
-+ if ((value & (EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE)) == set)
-+ return 0;
-+
-+ value &= ~(EC_CTRL_CHARGE_EN | EC_CTRL_TRICKLE);
-+ value |= set;
-+ ec_led_en(client, on);
-+ return ec_write_ctrl(client, (unsigned char)(value&0xff));
-+
-+}
-+
-+/**********************************************************************/
-+/* Input functions */
-+/**********************************************************************/
-+struct gdium_keys {
-+ int last_state;
-+ int key_code;
-+ int mask;
-+ int type;
-+};
-+
-+static struct gdium_keys gkeys[] = {
-+ {
-+ .key_code = KEY_WLAN,
-+ .mask = EC_STATUS_WLAN,
-+ .type = EV_KEY,
-+ },
-+ {
-+ .key_code = KEY_POWER,
-+ .mask = EC_STATUS_PWRBUT,
-+ .type = EV_KEY, /*EV_PWR,*/
-+ },
-+ {
-+ .key_code = SW_LID,
-+ .mask = EC_STATUS_LID,
-+ .type = EV_SW,
-+ },
-+};
-+
-+static void gdium_laptop_keys_poll(struct input_polled_dev *dev)
-+{
-+ int state, i;
-+ struct gdium_laptop_data *data = dev->private;
-+ struct i2c_client *client = data->client;
-+ struct input_dev *input = dev->input;
-+ s32 status;
-+
-+ mutex_lock(&data->mutex);
-+ status = ec_read_status(client);
-+ mutex_unlock(&data->mutex);
-+
-+ if (status < 0) {
-+ /*
-+ * Don't know exactly which version of the firmware
-+ * has this bug but when the power button is pressed
-+ * there are i2c read errors :(
-+ */
-+ if ((data->version >= 0x13) && !gkeys[1].last_state) {
-+ input_event(input, EV_KEY, KEY_POWER, 1);
-+ input_sync(input);
-+ gkeys[1].last_state = 1;
-+ }
-+ return;
-+ }
-+
-+ for (i = 0; i < ARRAY_SIZE(gkeys); i++) {
-+ state = status & gkeys[i].mask;
-+ if (state != gkeys[i].last_state) {
-+ gkeys[i].last_state = state;
-+ /* for power key, we want power & key press/release event */
-+ if (gkeys[i].type == EV_PWR) {
-+ input_event(input, EV_KEY, gkeys[i].key_code, !!state);
-+ input_sync(input);
-+ }
-+ /* Disable wifi on key press but not key release */
-+ /*
-+ * On firmware >= 0x13 the EC_STATUS_WLAN has it's
-+ * original meaning of Wifi status and no more the
-+ * wifi button status so we have to ignore the event
-+ * on theses versions
-+ */
-+ if (state && (gkeys[i].key_code == KEY_WLAN) && (data->version < 0x13)) {
-+ mutex_lock(&data->mutex);
-+ ec_wlan_en(client, !ec_wlan_status(client));
-+ if (gpio16)
-+ gpio_set_value(SM502_WLAN_ON, !ec_wlan_status(client));
-+ mutex_unlock(&data->mutex);
-+ }
-+
-+ input_event(input, gkeys[i].type, gkeys[i].key_code, !!state);
-+ input_sync(input);
-+ }
-+ }
-+}
-+
-+static int gdium_laptop_input_init(struct gdium_laptop_data *data)
-+{
-+ struct i2c_client *client = data->client;
-+ struct input_dev *input;
-+ int ret, i;
-+
-+ data->input_polldev = input_allocate_polled_device();
-+ if (!data->input_polldev) {
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+
-+ input = data->input_polldev->input;
-+ input->evbit[0] = BIT(EV_KEY) | BIT_MASK(EV_PWR) | BIT_MASK(EV_SW);
-+ data->input_polldev->poll = gdium_laptop_keys_poll;
-+ data->input_polldev->poll_interval = SCAN_INTERVAL;
-+ data->input_polldev->private = data;
-+ input->name = "gdium-keys";
-+ input->dev.parent = &client->dev;
-+
-+ input->id.bustype = BUS_HOST;
-+ input->id.vendor = 0x0001;
-+ input->id.product = 0x0001;
-+ input->id.version = 0x0100;
-+
-+ for (i = 0; i < ARRAY_SIZE(gkeys); i++)
-+ input_set_capability(input, gkeys[i].type, gkeys[i].key_code);
-+
-+ ret = input_register_polled_device(data->input_polldev);
-+ if (ret) {
-+ dev_err(&client->dev, "Unable to register button device\n");
-+ goto err_poll_dev;
-+ }
-+
-+ return 0;
-+
-+err_poll_dev:
-+ input_free_polled_device(data->input_polldev);
-+err:
-+ return ret;
-+}
-+
-+static void gdium_laptop_input_exit(struct gdium_laptop_data *data)
-+{
-+ input_unregister_polled_device(data->input_polldev);
-+ input_free_polled_device(data->input_polldev);
-+}
-+
-+/**********************************************************************/
-+/* Battery management */
-+/**********************************************************************/
-+static int gdium_ac_get_props(struct power_supply *psy,
-+ enum power_supply_property psp,
-+ union power_supply_propval *val)
-+{
-+ char status;
-+ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_ac);
-+ int ret = 0;
-+
-+ if (!data) {
-+ pr_err("gdium-ac: gdium_laptop_data not found\n");
-+ return -EINVAL;
-+ }
-+
-+ status = data->status;
-+ switch (psp) {
-+ case POWER_SUPPLY_PROP_ONLINE:
-+ val->intval = !!(status & EC_STATUS_ADAPT);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+#undef RET
-+#define RET (val->intval)
-+
-+static int gdium_battery_get_props(struct power_supply *psy,
-+ enum power_supply_property psp,
-+ union power_supply_propval *val)
-+{
-+ char status, ctrl;
-+ struct gdium_laptop_data *data = container_of(psy, struct gdium_laptop_data, gdium_battery);
-+ int percentage_capacity = 0, charge_now = 0, time_to_empty = 0;
-+ int ret = 0, tmp;
-+
-+ if (!data) {
-+ pr_err("gdium-battery: gdium_laptop_data not found\n");
-+ return -EINVAL;
-+ }
-+
-+ status = data->status;
-+ ctrl = data->ctrl;
-+ switch (psp) {
-+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
-+ /* uAh */
-+ RET = 5000000;
-+ break;
-+ case POWER_SUPPLY_PROP_CURRENT_NOW:
-+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
-+ /* This formula is gotten by gnuplot with the statistic data */
-+ time_to_empty = (data->battery_level - BAT_MIN_MV + BAT_READ_ERROR_MV) * 113 - 29870;
-+ if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW) {
-+ /* seconds */
-+ RET = time_to_empty / 10;
-+ break;
-+ }
-+ /* fall through */
-+ case POWER_SUPPLY_PROP_CHARGE_NOW:
-+ case POWER_SUPPLY_PROP_CAPACITY: {
-+ tmp = data->battery_level * 1000;
-+ /* > BAT_MIN to avoid negative values */
-+ percentage_capacity = 0;
-+ if ((status & EC_STATUS_BATID) && (tmp > BAT_MIN))
-+ percentage_capacity = (tmp-BAT_MIN)*100/(BAT_MAX-BAT_MIN);
-+
-+ if (percentage_capacity > 100)
-+ percentage_capacity = 100;
-+
-+ if (psp == POWER_SUPPLY_PROP_CAPACITY) {
-+ RET = percentage_capacity;
-+ break;
-+ }
-+ charge_now = 50000 * percentage_capacity;
-+ if (psp == POWER_SUPPLY_PROP_CHARGE_NOW) {
-+ /* uAh */
-+ RET = charge_now;
-+ break;
-+ }
-+ } /* fall through */
-+ case POWER_SUPPLY_PROP_STATUS: {
-+ if (status & EC_STATUS_ADAPT)
-+ if (ctrl & EC_CTRL_CHARGE_EN)
-+ RET = POWER_SUPPLY_STATUS_CHARGING;
-+ else
-+ RET = POWER_SUPPLY_STATUS_NOT_CHARGING;
-+ else
-+ RET = POWER_SUPPLY_STATUS_DISCHARGING;
-+
-+ if (psp == POWER_SUPPLY_PROP_STATUS)
-+ break;
-+ /* mAh -> µA */
-+ switch (RET) {
-+ case POWER_SUPPLY_STATUS_CHARGING:
-+ RET = -(data->charge_cmd == 2) ? 1400000 : 250000;
-+ break;
-+ case POWER_SUPPLY_STATUS_DISCHARGING:
-+ RET = charge_now / time_to_empty * 36000;
-+ break;
-+ case POWER_SUPPLY_STATUS_NOT_CHARGING:
-+ default:
-+ RET = 0;
-+ break;
-+ }
-+ } break;
-+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-+ RET = BAT_MAX+BAT_READ_ERROR;
-+ break;
-+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
-+ RET = BAT_MIN-BAT_READ_ERROR;
-+ break;
-+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-+ /* mV -> uV */
-+ RET = data->battery_level * 1000;
-+ break;
-+ case POWER_SUPPLY_PROP_PRESENT:
-+#if CONFIG_GDIUM_VERSION > 2
-+ RET = !!(status & EC_STATUS_BATID);
-+#else
-+ RET = !!(data->battery_level > BAT_VOLT_PRESENT);
-+#endif
-+ break;
-+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
-+ tmp = data->battery_level * 1000;
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
-+ if (status & EC_STATUS_BATID) {
-+ if (tmp >= BAT_MAX) {
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
-+ if (tmp >= BAT_MAX+BAT_READ_ERROR)
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
-+ } else if (tmp <= BAT_MIN+BAT_READ_ERROR) {
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
-+ if (tmp <= BAT_MIN)
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
-+ } else
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
-+ }
-+ break;
-+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
-+ if (ctrl & EC_CTRL_TRICKLE)
-+ RET = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
-+ else if (ctrl & EC_CTRL_CHARGE_EN)
-+ RET = POWER_SUPPLY_CHARGE_TYPE_FAST;
-+ else
-+ RET = POWER_SUPPLY_CHARGE_TYPE_NONE;
-+ break;
-+ case POWER_SUPPLY_PROP_CURRENT_MAX:
-+ /* 1.4A ? */
-+ RET = 1400000;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return ret;
-+}
-+#undef RET
-+
-+static enum power_supply_property gdium_ac_props[] = {
-+ POWER_SUPPLY_PROP_ONLINE,
-+};
-+
-+static enum power_supply_property gdium_battery_props[] = {
-+ POWER_SUPPLY_PROP_STATUS,
-+ POWER_SUPPLY_PROP_PRESENT,
-+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-+ POWER_SUPPLY_PROP_CHARGE_NOW,
-+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
-+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
-+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
-+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
-+ POWER_SUPPLY_PROP_CURRENT_MAX,
-+ POWER_SUPPLY_PROP_CURRENT_NOW,
-+ POWER_SUPPLY_PROP_CAPACITY,
-+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
-+ POWER_SUPPLY_PROP_CHARGE_TYPE,
-+};
-+
-+static void gdium_laptop_battery_work(struct work_struct *work)
-+{
-+ struct gdium_laptop_data *data = container_of(work, struct gdium_laptop_data, work.work);
-+ struct i2c_client *client;
-+ int ret;
-+ char old_status, old_charge_cmd;
-+ char present;
-+ s32 status;
-+
-+ mutex_lock(&data->mutex);
-+ client = data->client;
-+ status = ec_read_status(client);
-+ ret = ec_read_battery(client);
-+
-+ if ((status < 0) || (ret < 0))
-+ goto i2c_read_error;
-+
-+ old_status = data->status;
-+ old_charge_cmd = data->charge_cmd;
-+ data->status = status;
-+
-+ /*
-+ * Charge only if :
-+ * - battery present
-+ * - ac adapter plugged in
-+ * - battery not fully charged
-+ */
-+#if CONFIG_GDIUM_VERSION > 2
-+ present = !!(data->status & EC_STATUS_BATID);
-+#else
-+ present = !!(ret > BAT_VOLT_PRESENT);
-+#endif
-+ data->battery_level = 0;
-+ if (present) {
-+ data->battery_level = (unsigned int)ret;
-+ if (data->status & EC_STATUS_ADAPT)
-+ data->battery_level -= BAT_READ_ERROR_MV;
-+ }
-+
-+ data->charge_cmd = 0;
-+ if ((data->status & EC_STATUS_ADAPT) && present && (data->battery_level <= BAT_MAX_MV))
-+ data->charge_cmd = (ret < BAT_TRICKLE_EN) ? 2 : 3;
-+
-+ ec_charge_en(client, (data->charge_cmd >> 1) & 1, data->charge_cmd & 1);
-+
-+ /*
-+ * data->ctrl must be set _after_ calling ec_charge_en as this will change the
-+ * control register content
-+ */
-+ data->ctrl = ec_read_ctrl(client);
-+
-+ if ((data->status & EC_STATUS_ADAPT) != (old_status & EC_STATUS_ADAPT)) {
-+ power_supply_changed(&data->gdium_ac);
-+ /* Send charging/discharging state change */
-+ power_supply_changed(&data->gdium_battery);
-+ } else if ((data->status & EC_STATUS_ADAPT) &&
-+ ((old_charge_cmd&2) != (data->charge_cmd&2)))
-+ power_supply_changed(&data->gdium_battery);
-+
-+i2c_read_error:
-+ mutex_unlock(&data->mutex);
-+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL));
-+}
-+
-+static int gdium_laptop_battery_init(struct gdium_laptop_data *data)
-+{
-+ int ret;
-+
-+ data->bat_pdev = platform_device_register_simple("gdium-battery", 0, NULL, 0);
-+ if (IS_ERR(data->bat_pdev))
-+ return PTR_ERR(data->bat_pdev);
-+
-+ data->gdium_battery.name = data->bat_pdev->name;
-+ data->gdium_battery.properties = gdium_battery_props;
-+ data->gdium_battery.num_properties = ARRAY_SIZE(gdium_battery_props);
-+ data->gdium_battery.get_property = gdium_battery_get_props;
-+ data->gdium_battery.use_for_apm = 1;
-+
-+ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_battery);
-+ if (ret)
-+ goto err_platform;
-+
-+ data->gdium_ac.name = "gdium-ac";
-+ data->gdium_ac.type = POWER_SUPPLY_TYPE_MAINS;
-+ data->gdium_ac.properties = gdium_ac_props;
-+ data->gdium_ac.num_properties = ARRAY_SIZE(gdium_ac_props);
-+ data->gdium_ac.get_property = gdium_ac_get_props;
-+/* data->gdium_ac.use_for_apm_ac = 1, */
-+
-+ ret = power_supply_register(&data->bat_pdev->dev, &data->gdium_ac);
-+ if (ret)
-+ goto err_battery;
-+
-+ if (!ec) {
-+ INIT_DELAYED_WORK(&data->work, gdium_laptop_battery_work);
-+ data->workqueue = create_singlethread_workqueue("gdium-battery-work");
-+ if (!data->workqueue) {
-+ ret = -ESRCH;
-+ goto err_work;
-+ }
-+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL));
-+ }
-+
-+ return 0;
-+
-+err_work:
-+err_battery:
-+ power_supply_unregister(&data->gdium_battery);
-+err_platform:
-+ platform_device_unregister(data->bat_pdev);
-+
-+ return ret;
-+}
-+static void gdium_laptop_battery_exit(struct gdium_laptop_data *data)
-+{
-+ if (!ec) {
-+ cancel_rearming_delayed_workqueue(data->workqueue, &data->work);
-+ destroy_workqueue(data->workqueue);
-+ }
-+ power_supply_unregister(&data->gdium_battery);
-+ power_supply_unregister(&data->gdium_ac);
-+ platform_device_unregister(data->bat_pdev);
-+}
-+
-+/* Debug fs */
-+static int gdium_laptop_regs_show(struct seq_file *s, void *p)
-+{
-+ struct gdium_laptop_data *data = s->private;
-+ struct i2c_client *client = data->client;
-+
-+ mutex_lock(&data->mutex);
-+ seq_printf(s, "Version : 0x%02x\n", (unsigned char)ec_read_version(client));
-+ seq_printf(s, "Status : 0x%02x\n", (unsigned char)ec_read_status(client));
-+ seq_printf(s, "Ctrl : 0x%02x\n", (unsigned char)ec_read_ctrl(client));
-+ seq_printf(s, "Sign : 0x%02x\n", (unsigned char)ec_read_sign(client));
-+ seq_printf(s, "Bat Lo : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_LOW));
-+ seq_printf(s, "Bat Hi : 0x%02x\n", (unsigned char)i2c_smbus_read_byte_data(client, EC_BAT_HIGH));
-+ seq_printf(s, "Battery : %d uV\n", (unsigned int)ec_read_battery(client) * 1000);
-+ seq_printf(s, "Charge cmd : %s %s\n", data->charge_cmd & 2 ? "C" : " ", data->charge_cmd & 1 ? "T" : " ");
-+
-+ mutex_unlock(&data->mutex);
-+ return 0;
-+}
-+
-+static int gdium_laptop_regs_open(struct inode *inode,
-+ struct file *file)
-+{
-+ return single_open(file, gdium_laptop_regs_show, inode->i_private);
-+}
-+
-+static const struct file_operations gdium_laptop_regs_fops = {
-+ .open = gdium_laptop_regs_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+ .owner = THIS_MODULE,
-+};
-+
-+
-+static int gdium_laptop_probe(struct i2c_client *client, const struct i2c_device_id *id)
-+{
-+ struct gdium_laptop_data *data;
-+ int ret;
-+
-+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-+ dev_err(&client->dev,
-+ "%s: no smbus_byte support !\n", __func__);
-+ return -ENODEV;
-+ }
-+
-+ data = kzalloc(sizeof(struct gdium_laptop_data), GFP_KERNEL);
-+ if (!data)
-+ return -ENOMEM;
-+
-+ i2c_set_clientdata(client, data);
-+ data->client = client;
-+ mutex_init(&data->mutex);
-+
-+ ret = ec_read_version(client);
-+ if (ret < 0)
-+ goto err_alloc;
-+
-+ data->version = (unsigned char)ret;
-+
-+ ret = gdium_laptop_input_init(data);
-+ if (ret)
-+ goto err_alloc;
-+
-+ ret = gdium_laptop_battery_init(data);
-+ if (ret)
-+ goto err_input;
-+
-+
-+ if (!ec) {
-+ ret = ec_write_sign(client, EC_SIGN_OS);
-+ if (ret)
-+ goto err_sign;
-+ }
-+
-+ if (gpio16) {
-+ ret = gpio_request(SM502_WLAN_ON, "wlan-on");
-+ if (ret < 0)
-+ goto err_sign;
-+ gpio_set_value(SM502_WLAN_ON, ec_wlan_status(client));
-+ gpio_direction_output(SM502_WLAN_ON, 1);
-+ }
-+
-+ dev_info(&client->dev, "Found firmware 0x%02x\n", data->version);
-+ data->debugfs = debugfs_create_file("gdium_laptop", S_IFREG | S_IRUGO,
-+ NULL, data, &gdium_laptop_regs_fops);
-+
-+ return 0;
-+
-+err_sign:
-+ gdium_laptop_battery_exit(data);
-+err_input:
-+ gdium_laptop_input_exit(data);
-+err_alloc:
-+ kfree(data);
-+ return ret;
-+}
-+
-+static int gdium_laptop_remove(struct i2c_client *client)
-+{
-+ struct gdium_laptop_data *data = i2c_get_clientdata(client);
-+
-+ if (gpio16)
-+ gpio_free(SM502_WLAN_ON);
-+ ec_write_sign(client, EC_SIGN_EC);
-+ if (data->debugfs)
-+ debugfs_remove(data->debugfs);
-+
-+ gdium_laptop_battery_exit(data);
-+ gdium_laptop_input_exit(data);
-+
-+ kfree(data);
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int gdium_laptop_suspend(struct i2c_client *client, pm_message_t msg)
-+{
-+ struct gdium_laptop_data *data = i2c_get_clientdata(client);
-+
-+ if (!ec)
-+ cancel_rearming_delayed_workqueue(data->workqueue, &data->work);
-+ return 0;
-+}
-+
-+static int gdium_laptop_resume(struct i2c_client *client)
-+{
-+ struct gdium_laptop_data *data = i2c_get_clientdata(client);
-+
-+ if (!ec)
-+ queue_delayed_work(data->workqueue, &data->work, msecs_to_jiffies(BAT_SCAN_INTERVAL));
-+ return 0;
-+}
-+#else
-+#define gdium_laptop_suspend NULL
-+#define gdium_laptop_resume NULL
-+#endif
-+static const struct i2c_device_id gdium_id[] = {
-+ { "gdium-laptop" },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(i2c, gdium_id);
-+
-+static struct i2c_driver gdium_laptop_driver = {
-+ .driver = {
-+ .name = "gdium-laptop",
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = gdium_laptop_probe,
-+ .remove = gdium_laptop_remove,
-+ .shutdown = gdium_laptop_remove,
-+ .suspend = gdium_laptop_suspend,
-+ .resume = gdium_laptop_resume,
-+ .id_table = gdium_id,
-+};
-+
-+static int __init gdium_laptop_init(void)
-+{
-+ return i2c_add_driver(&gdium_laptop_driver);
-+}
-+
-+static void __exit gdium_laptop_exit(void)
-+{
-+ i2c_del_driver(&gdium_laptop_driver);
-+}
-+
-+module_init(gdium_laptop_init);
-+module_exit(gdium_laptop_exit);
-+
-+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
-+MODULE_DESCRIPTION("Gdium laptop extras");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/platform/mips/lynloong_pc.c b/drivers/platform/mips/lynloong_pc.c
-new file mode 100644
-index 0000000..68f29e4
---- /dev/null
-+++ b/drivers/platform/mips/lynloong_pc.c
-@@ -0,0 +1,515 @@
-+/*
-+ * Driver for LynLoong PC extras
-+ *
-+ * Copyright (C) 2009 Lemote Inc.
-+ * Author: Wu Zhangjin <wuzhangjin@gmail.com>, Xiang Yu <xiangy@lemote.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/backlight.h> /* for backlight subdriver */
-+#include <linux/fb.h>
-+#include <linux/video_output.h> /* for video output subdriver */
-+#include <linux/delay.h> /* for suspend support */
-+
-+#include <cs5536/cs5536.h>
-+#include <cs5536/cs5536_mfgpt.h>
-+
-+#include <loongson.h>
-+
-+static u32 gpio_base, mfgpt_base;
-+
-+static void set_gpio_reg_high(int gpio, int reg)
-+{
-+ u32 val;
-+
-+ val = inl(gpio_base + reg);
-+ val |= (1 << gpio);
-+ val &= ~(1 << (16 + gpio));
-+ outl(val, gpio_base + reg);
-+ mmiowb();
-+}
-+
-+static void set_gpio_reg_low(int gpio, int reg)
-+{
-+ u32 val;
-+
-+ val = inl(gpio_base + reg);
-+ val |= (1 << (16 + gpio));
-+ val &= ~(1 << gpio);
-+ outl(val, gpio_base + reg);
-+ mmiowb();
-+}
-+
-+static void set_gpio_output_low(int gpio)
-+{
-+ set_gpio_reg_high(gpio, GPIOL_OUT_EN);
-+ set_gpio_reg_low(gpio, GPIOL_OUT_VAL);
-+}
-+
-+static void set_gpio_output_high(int gpio)
-+{
-+ set_gpio_reg_high(gpio, GPIOL_OUT_EN);
-+ set_gpio_reg_high(gpio, GPIOL_OUT_VAL);
-+}
-+
-+/* backlight subdriver */
-+
-+#define MAX_BRIGHTNESS 100
-+#define DEFAULT_BRIGHTNESS 50
-+#define MIN_BRIGHTNESS 0
-+static unsigned int level;
-+
-+DEFINE_SPINLOCK(backlight_lock);
-+/* Tune the brightness */
-+static void setup_mfgpt2(void)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&backlight_lock, flags);
-+
-+ /* Set MFGPT2 comparator 1,2 */
-+ outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1);
-+ outw(MAX_BRIGHTNESS, MFGPT2_CMP2);
-+ /* Clear MFGPT2 UP COUNTER */
-+ outw(0, MFGPT2_CNT);
-+ /* Enable counter, compare mode, 32k */
-+ outw(0x8280, MFGPT2_SETUP);
-+
-+ spin_unlock_irqrestore(&backlight_lock, flags);
-+}
-+
-+static int lynloong_set_brightness(struct backlight_device *bd)
-+{
-+ level = (bd->props.fb_blank == FB_BLANK_UNBLANK &&
-+ bd->props.power == FB_BLANK_UNBLANK) ?
-+ bd->props.brightness : 0;
-+
-+ if (level > MAX_BRIGHTNESS)
-+ level = MAX_BRIGHTNESS;
-+ else if (level < MIN_BRIGHTNESS)
-+ level = MIN_BRIGHTNESS;
-+
-+ setup_mfgpt2();
-+
-+ return 0;
-+}
-+
-+static int lynloong_get_brightness(struct backlight_device *bd)
-+{
-+ return level;
-+}
-+
-+static struct backlight_ops backlight_ops = {
-+ .get_brightness = lynloong_get_brightness,
-+ .update_status = lynloong_set_brightness,
-+};
-+
-+static struct backlight_device *lynloong_backlight_dev;
-+
-+static int lynloong_backlight_init(void)
-+{
-+ int ret;
-+ u32 hi;
-+ struct backlight_properties props;
-+
-+ /* Get gpio_base */
-+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base);
-+ /* Get mfgpt_base */
-+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base);
-+ /* Get gpio_base */
-+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base);
-+
-+ /* Select for mfgpt */
-+ set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL);
-+ /* Enable brightness controlling */
-+ set_gpio_output_high(7);
-+
-+ memset(&props, 0, sizeof(struct backlight_properties));
-+ props.max_brightness = MAX_BRIGHTNESS;
-+ props.type = BACKLIGHT_PLATFORM;
-+ lynloong_backlight_dev = backlight_device_register("backlight0", NULL,
-+ NULL, &backlight_ops, &props);
-+
-+ if (IS_ERR(lynloong_backlight_dev)) {
-+ ret = PTR_ERR(lynloong_backlight_dev);
-+ return ret;
-+ }
-+
-+ lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS;
-+ backlight_update_status(lynloong_backlight_dev);
-+
-+ return 0;
-+}
-+
-+static void lynloong_backlight_exit(void)
-+{
-+ if (lynloong_backlight_dev) {
-+ backlight_device_unregister(lynloong_backlight_dev);
-+ lynloong_backlight_dev = NULL;
-+ }
-+ /* Disable brightness controlling */
-+ set_gpio_output_low(7);
-+}
-+
-+/* video output driver */
-+static int vo_status = 1;
-+
-+static int lcd_video_output_get(struct output_device *od)
-+{
-+ return vo_status;
-+}
-+
-+static int lcd_video_output_set(struct output_device *od)
-+{
-+ int i;
-+ unsigned long status;
-+
-+ status = !!od->request_state;
-+
-+ if (status == 0) {
-+ /* Set the current status as off */
-+ vo_status = 0;
-+ /* Turn off the backlight */
-+ set_gpio_output_low(11);
-+ for (i = 0; i < 0x500; i++)
-+ delay();
-+ /* Turn off the LCD */
-+ set_gpio_output_high(8);
-+ } else {
-+ /* Turn on the LCD */
-+ set_gpio_output_low(8);
-+ for (i = 0; i < 0x500; i++)
-+ delay();
-+ /* Turn on the backlight */
-+ set_gpio_output_high(11);
-+ /* Set the current status as on */
-+ vo_status = 1;
-+ }
-+
-+ return 0;
-+}
-+
-+static struct output_properties lcd_output_properties = {
-+ .set_state = lcd_video_output_set,
-+ .get_status = lcd_video_output_get,
-+};
-+
-+static struct output_device *lcd_output_dev;
-+
-+static void lynloong_lcd_vo_set(int status)
-+{
-+ lcd_output_dev->request_state = status;
-+ lcd_video_output_set(lcd_output_dev);
-+}
-+
-+static int lynloong_vo_init(void)
-+{
-+ int ret;
-+
-+ /* Register video output device: lcd */
-+ lcd_output_dev = video_output_register("LCD", NULL, NULL,
-+ &lcd_output_properties);
-+
-+ if (IS_ERR(lcd_output_dev)) {
-+ ret = PTR_ERR(lcd_output_dev);
-+ lcd_output_dev = NULL;
-+ return ret;
-+ }
-+ /* Ensure LCD is on by default */
-+ lynloong_lcd_vo_set(1);
-+
-+ return 0;
-+}
-+
-+static void lynloong_vo_exit(void)
-+{
-+ if (lcd_output_dev) {
-+ video_output_unregister(lcd_output_dev);
-+ lcd_output_dev = NULL;
-+ }
-+}
-+
-+/* suspend support */
-+
-+#ifdef CONFIG_PM
-+
-+static u32 smb_base;
-+
-+/* I2C operations */
-+
-+static int i2c_wait(void)
-+{
-+ char c;
-+ int i;
-+
-+ udelay(1000);
-+ for (i = 0; i < 20; i++) {
-+ c = inb(smb_base | SMB_STS);
-+ if (c & (SMB_STS_BER | SMB_STS_NEGACK))
-+ return -1;
-+ if (c & SMB_STS_SDAST)
-+ return 0;
-+ udelay(100);
-+ }
-+ return -2;
-+}
-+
-+static void i2c_read_single(int addr, int regNo, char *value)
-+{
-+ unsigned char c;
-+
-+ /* Start condition */
-+ c = inb(smb_base | SMB_CTRL1);
-+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
-+ i2c_wait();
-+
-+ /* Send slave address */
-+ outb(addr & 0xfe, smb_base | SMB_SDA);
-+ i2c_wait();
-+
-+ /* Acknowledge smbus */
-+ c = inb(smb_base | SMB_CTRL1);
-+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
-+
-+ /* Send register index */
-+ outb(regNo, smb_base | SMB_SDA);
-+ i2c_wait();
-+
-+ /* Acknowledge smbus */
-+ c = inb(smb_base | SMB_CTRL1);
-+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
-+
-+ /* Start condition again */
-+ c = inb(smb_base | SMB_CTRL1);
-+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
-+ i2c_wait();
-+
-+ /* Send salve address again */
-+ outb(1 | addr, smb_base | SMB_SDA);
-+ i2c_wait();
-+
-+ /* Acknowledge smbus */
-+ c = inb(smb_base | SMB_CTRL1);
-+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
-+
-+ /* Read data */
-+ *value = inb(smb_base | SMB_SDA);
-+
-+ /* Stop condition */
-+ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1);
-+ i2c_wait();
-+}
-+
-+static void i2c_write_single(int addr, int regNo, char value)
-+{
-+ unsigned char c;
-+
-+ /* Start condition */
-+ c = inb(smb_base | SMB_CTRL1);
-+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
-+ i2c_wait();
-+ /* Send slave address */
-+ outb(addr & 0xfe, smb_base | SMB_SDA);
-+ i2c_wait();;
-+
-+ /* Send register index */
-+ outb(regNo, smb_base | SMB_SDA);
-+ i2c_wait();
-+
-+ /* Write data */
-+ outb(value, smb_base | SMB_SDA);
-+ i2c_wait();
-+ /* Stop condition */
-+ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1);
-+ i2c_wait();
-+}
-+
-+static void stop_clock(int clk_reg, int clk_sel)
-+{
-+ u8 value;
-+
-+ i2c_read_single(0xd3, clk_reg, &value);
-+ value &= ~(1 << clk_sel);
-+ i2c_write_single(0xd2, clk_reg, value);
-+}
-+
-+static void enable_clock(int clk_reg, int clk_sel)
-+{
-+ u8 value;
-+
-+ i2c_read_single(0xd3, clk_reg, &value);
-+ value |= (1 << clk_sel);
-+ i2c_write_single(0xd2, clk_reg, value);
-+}
-+
-+static char cached_clk_freq;
-+static char cached_pci_fixed_freq;
-+
-+static void decrease_clk_freq(void)
-+{
-+ char value;
-+
-+ i2c_read_single(0xd3, 1, &value);
-+ cached_clk_freq = value;
-+
-+ /* Select frequency by software */
-+ value |= (1 << 1);
-+ /* CPU, 3V66, PCI : 100, 66, 33(1) */
-+ value |= (1 << 2);
-+ i2c_write_single(0xd2, 1, value);
-+
-+ /* Cache the pci frequency */
-+ i2c_read_single(0xd3, 14, &value);
-+ cached_pci_fixed_freq = value;
-+
-+ /* Enable PCI fix mode */
-+ value |= (1 << 5);
-+ /* 3V66, PCI : 64MHz, 32MHz */
-+ value |= (1 << 3);
-+ i2c_write_single(0xd2, 14, value);
-+
-+}
-+
-+static void resume_clk_freq(void)
-+{
-+ i2c_write_single(0xd2, 1, cached_clk_freq);
-+ i2c_write_single(0xd2, 14, cached_pci_fixed_freq);
-+}
-+
-+static void stop_clocks(void)
-+{
-+ /* CPU Clock Register */
-+ stop_clock(2, 5); /* not used */
-+ stop_clock(2, 6); /* not used */
-+ stop_clock(2, 7); /* not used */
-+
-+ /* PCI Clock Register */
-+ stop_clock(3, 1); /* 8100 */
-+ stop_clock(3, 5); /* SIS */
-+ stop_clock(3, 0); /* not used */
-+ stop_clock(3, 6); /* not used */
-+
-+ /* PCI 48M Clock Register */
-+ stop_clock(4, 6); /* USB grounding */
-+ stop_clock(4, 5); /* REF(5536_14M) */
-+
-+ /* 3V66 Control Register */
-+ stop_clock(5, 0); /* VCH_CLK..., grounding */
-+}
-+
-+static void enable_clocks(void)
-+{
-+ enable_clock(3, 1); /* 8100 */
-+ enable_clock(3, 5); /* SIS */
-+
-+ enable_clock(4, 6);
-+ enable_clock(4, 5); /* REF(5536_14M) */
-+
-+ enable_clock(5, 0); /* VCH_CLOCK, grounding */
-+}
-+
-+static int lynloong_suspend(struct device *dev)
-+{
-+ /* Disable AMP */
-+ set_gpio_output_high(6);
-+ /* Turn off LCD */
-+ lynloong_lcd_vo_set(0);
-+
-+ /* Stop the clocks of some devices */
-+ stop_clocks();
-+
-+ /* Decrease the external clock frequency */
-+ decrease_clk_freq();
-+
-+ return 0;
-+}
-+
-+static int lynloong_resume(struct device *dev)
-+{
-+ /* Turn on the LCD */
-+ lynloong_lcd_vo_set(1);
-+
-+ /* Resume clock frequency, enable the relative clocks */
-+ resume_clk_freq();
-+ enable_clocks();
-+
-+ /* Enable AMP */
-+ set_gpio_output_low(6);
-+
-+ return 0;
-+}
-+
-+static const SIMPLE_DEV_PM_OPS(lynloong_pm_ops, lynloong_suspend,
-+ lynloong_resume);
-+#endif /* !CONFIG_PM */
-+
-+static struct platform_device_id platform_device_ids[] = {
-+ {
-+ .name = "lynloong_pc",
-+ },
-+ {}
-+};
-+
-+MODULE_DEVICE_TABLE(platform, platform_device_ids);
-+
-+static struct platform_driver platform_driver = {
-+ .driver = {
-+ .name = "lynloong_pc",
-+ .owner = THIS_MODULE,
-+#ifdef CONFIG_PM
-+ .pm = &lynloong_pm_ops,
-+#endif
-+ },
-+ .id_table = platform_device_ids,
-+};
-+
-+static int __init lynloong_init(void)
-+{
-+ int ret;
-+
-+ pr_info("LynLoong platform specific driver loaded.\n");
-+
-+ /* Register platform stuff */
-+ ret = platform_driver_register(&platform_driver);
-+ if (ret) {
-+ pr_err("Failed to register LynLoong platform driver.\n");
-+ return ret;
-+ }
-+
-+ ret = lynloong_backlight_init();
-+ if (ret) {
-+ pr_err("Failed to register LynLoong backlight driver.\n");
-+ return ret;
-+ }
-+
-+ ret = lynloong_vo_init();
-+ if (ret) {
-+ pr_err("Failed to register LynLoong backlight driver.\n");
-+ lynloong_vo_exit();
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static void __exit lynloong_exit(void)
-+{
-+ lynloong_vo_exit();
-+ lynloong_backlight_exit();
-+ platform_driver_unregister(&platform_driver);
-+
-+ pr_info("LynLoong platform specific driver unloaded.\n");
-+}
-+
-+module_init(lynloong_init);
-+module_exit(lynloong_exit);
-+
-+MODULE_AUTHOR("Wu Zhangjin <wuzhangjin@gmail.com>; Xiang Yu <xiangy@lemote.com>");
-+MODULE_DESCRIPTION("LynLoong PC driver");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/platform/mips/yeeloong_ecrom.c b/drivers/platform/mips/yeeloong_ecrom.c
-new file mode 100644
-index 0000000..1bfe4cf
---- /dev/null
-+++ b/drivers/platform/mips/yeeloong_ecrom.c
-@@ -0,0 +1,944 @@
-+/*
-+ * Driver for flushing/dumping ROM of EC on YeeLoong laptop
-+ *
-+ * Copyright (C) 2009 Lemote Inc.
-+ * Author: liujl <liujl@lemote.com>
-+ *
-+ * NOTE :
-+ * The EC resources accessing and programming are supported.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/proc_fs.h>
-+#include <linux/miscdevice.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+
-+#include <ec_kb3310b.h>
-+
-+#define EC_MISC_DEV "ec_misc"
-+#define EC_IOC_MAGIC 'E'
-+
-+/* ec registers range */
-+#define EC_MAX_REGADDR 0xFFFF
-+#define EC_MIN_REGADDR 0xF000
-+#define EC_RAM_ADDR 0xF800
-+
-+/* version burned address */
-+#define VER_ADDR 0xf7a1
-+#define VER_MAX_SIZE 7
-+#define EC_ROM_MAX_SIZE 0x10000
-+
-+/* ec internal register */
-+#define REG_POWER_MODE 0xF710
-+#define FLAG_NORMAL_MODE 0x00
-+#define FLAG_IDLE_MODE 0x01
-+#define FLAG_RESET_MODE 0x02
-+
-+/* ec update program flag */
-+#define PROGRAM_FLAG_NONE 0x00
-+#define PROGRAM_FLAG_IE 0x01
-+#define PROGRAM_FLAG_ROM 0x02
-+
-+/* XBI relative registers */
-+#define REG_XBISEG0 0xFEA0
-+#define REG_XBISEG1 0xFEA1
-+#define REG_XBIRSV2 0xFEA2
-+#define REG_XBIRSV3 0xFEA3
-+#define REG_XBIRSV4 0xFEA4
-+#define REG_XBICFG 0xFEA5
-+#define REG_XBICS 0xFEA6
-+#define REG_XBIWE 0xFEA7
-+#define REG_XBISPIA0 0xFEA8
-+#define REG_XBISPIA1 0xFEA9
-+#define REG_XBISPIA2 0xFEAA
-+#define REG_XBISPIDAT 0xFEAB
-+#define REG_XBISPICMD 0xFEAC
-+#define REG_XBISPICFG 0xFEAD
-+#define REG_XBISPIDATR 0xFEAE
-+#define REG_XBISPICFG2 0xFEAF
-+
-+/* commands definition for REG_XBISPICMD */
-+#define SPICMD_WRITE_STATUS 0x01
-+#define SPICMD_BYTE_PROGRAM 0x02
-+#define SPICMD_READ_BYTE 0x03
-+#define SPICMD_WRITE_DISABLE 0x04
-+#define SPICMD_READ_STATUS 0x05
-+#define SPICMD_WRITE_ENABLE 0x06
-+#define SPICMD_HIGH_SPEED_READ 0x0B
-+#define SPICMD_POWER_DOWN 0xB9
-+#define SPICMD_SST_EWSR 0x50
-+#define SPICMD_SST_SEC_ERASE 0x20
-+#define SPICMD_SST_BLK_ERASE 0x52
-+#define SPICMD_SST_CHIP_ERASE 0x60
-+#define SPICMD_FRDO 0x3B
-+#define SPICMD_SEC_ERASE 0xD7
-+#define SPICMD_BLK_ERASE 0xD8
-+#define SPICMD_CHIP_ERASE 0xC7
-+
-+/* bits definition for REG_XBISPICFG */
-+#define SPICFG_AUTO_CHECK 0x01
-+#define SPICFG_SPI_BUSY 0x02
-+#define SPICFG_DUMMY_READ 0x04
-+#define SPICFG_EN_SPICMD 0x08
-+#define SPICFG_LOW_SPICS 0x10
-+#define SPICFG_EN_SHORT_READ 0x20
-+#define SPICFG_EN_OFFSET_READ 0x40
-+#define SPICFG_EN_FAST_READ 0x80
-+
-+/* watchdog timer registers */
-+#define REG_WDTCFG 0xfe80
-+#define REG_WDTPF 0xfe81
-+#define REG_WDT 0xfe82
-+
-+/* lpc configure register */
-+#define REG_LPCCFG 0xfe95
-+
-+/* 8051 reg */
-+#define REG_PXCFG 0xff14
-+
-+/* Fan register in KB3310 */
-+#define REG_ECFAN_SPEED_LEVEL 0xf4e4
-+#define REG_ECFAN_SWITCH 0xf4d2
-+
-+/* the ec flash rom id number */
-+#define EC_ROM_PRODUCT_ID_SPANSION 0x01
-+#define EC_ROM_PRODUCT_ID_MXIC 0xC2
-+#define EC_ROM_PRODUCT_ID_AMIC 0x37
-+#define EC_ROM_PRODUCT_ID_EONIC 0x1C
-+
-+/* misc ioctl operations */
-+#define IOCTL_RDREG _IOR(EC_IOC_MAGIC, 1, int)
-+#define IOCTL_WRREG _IOW(EC_IOC_MAGIC, 2, int)
-+#define IOCTL_READ_EC _IOR(EC_IOC_MAGIC, 3, int)
-+#define IOCTL_PROGRAM_IE _IOW(EC_IOC_MAGIC, 4, int)
-+#define IOCTL_PROGRAM_EC _IOW(EC_IOC_MAGIC, 5, int)
-+
-+/* start address for programming of EC content or IE */
-+/* ec running code start address */
-+#define EC_START_ADDR 0x00000000
-+/* ec information element storing address */
-+#define IE_START_ADDR 0x00020000
-+
-+/* EC state */
-+#define EC_STATE_IDLE 0x00 /* ec in idle state */
-+#define EC_STATE_BUSY 0x01 /* ec in busy state */
-+
-+/* timeout value for programming */
-+#define EC_FLASH_TIMEOUT 0x1000 /* ec program timeout */
-+/* command checkout timeout including cmd to port or state flag check */
-+#define EC_CMD_TIMEOUT 0x1000
-+#define EC_SPICMD_STANDARD_TIMEOUT (4 * 1000) /* unit : us */
-+#define EC_MAX_DELAY_UNIT (10) /* every time for polling */
-+#define SPI_FINISH_WAIT_TIME 10
-+/* EC content max size */
-+#define EC_CONTENT_MAX_SIZE (64 * 1024)
-+#define IE_CONTENT_MAX_SIZE (0x100000 - IE_START_ADDR)
-+
-+/* the register operation access struct */
-+struct ec_reg {
-+ u32 addr; /* the address of kb3310 registers */
-+ u8 val; /* the register value */
-+};
-+
-+struct ec_info {
-+ u32 start_addr;
-+ u32 size;
-+ u8 *buf;
-+};
-+
-+/* open for using rom protection action */
-+#define EC_ROM_PROTECTION
-+
-+/* enable the chip reset mode */
-+static int ec_init_reset_mode(void)
-+{
-+ int timeout;
-+ unsigned char status = 0;
-+ int ret = 0;
-+
-+ /* make chip goto reset mode */
-+ ret = ec_query_seq(CMD_INIT_RESET_MODE);
-+ if (ret < 0) {
-+ printk(KERN_ERR "ec init reset mode failed.\n");
-+ goto out;
-+ }
-+
-+ /* make the action take active */
-+ timeout = EC_CMD_TIMEOUT;
-+ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE;
-+ while (timeout--) {
-+ if (status) {
-+ udelay(EC_REG_DELAY);
-+ break;
-+ }
-+ status = ec_read(REG_POWER_MODE) & FLAG_RESET_MODE;
-+ udelay(EC_REG_DELAY);
-+ }
-+ if (timeout <= 0) {
-+ printk(KERN_ERR "ec rom fixup : can't check reset status.\n");
-+ ret = -EINVAL;
-+ } else
-+ printk(KERN_INFO "(%d/%d)reset 0xf710 : 0x%x\n", timeout,
-+ EC_CMD_TIMEOUT - timeout, status);
-+
-+ /* set MCU to reset mode */
-+ udelay(EC_REG_DELAY);
-+ status = ec_read(REG_PXCFG);
-+ status |= (1 << 0);
-+ ec_write(REG_PXCFG, status);
-+ udelay(EC_REG_DELAY);
-+
-+ /* disable FWH/LPC */
-+ udelay(EC_REG_DELAY);
-+ status = ec_read(REG_LPCCFG);
-+ status &= ~(1 << 7);
-+ ec_write(REG_LPCCFG, status);
-+ udelay(EC_REG_DELAY);
-+
-+ printk(KERN_INFO "entering reset mode ok..............\n");
-+
-+ out:
-+ return ret;
-+}
-+
-+/* make ec exit from reset mode */
-+static void ec_exit_reset_mode(void)
-+{
-+ unsigned char regval;
-+
-+ udelay(EC_REG_DELAY);
-+ regval = ec_read(REG_LPCCFG);
-+ regval |= (1 << 7);
-+ ec_write(REG_LPCCFG, regval);
-+ regval = ec_read(REG_PXCFG);
-+ regval &= ~(1 << 0);
-+ ec_write(REG_PXCFG, regval);
-+ printk(KERN_INFO "exit reset mode ok..................\n");
-+
-+ return;
-+}
-+
-+/* make ec disable WDD */
-+static void ec_disable_WDD(void)
-+{
-+ unsigned char status;
-+
-+ udelay(EC_REG_DELAY);
-+ status = ec_read(REG_WDTCFG);
-+ ec_write(REG_WDTPF, 0x03);
-+ ec_write(REG_WDTCFG, (status & 0x80) | 0x48);
-+ printk(KERN_INFO "Disable WDD ok..................\n");
-+
-+ return;
-+}
-+
-+/* make ec enable WDD */
-+static void ec_enable_WDD(void)
-+{
-+ unsigned char status;
-+
-+ udelay(EC_REG_DELAY);
-+ status = ec_read(REG_WDTCFG);
-+ ec_write(REG_WDT, 0x28); /* set WDT 5sec(0x28) */
-+ ec_write(REG_WDTCFG, (status & 0x80) | 0x03);
-+ printk(KERN_INFO "Enable WDD ok..................\n");
-+
-+ return;
-+}
-+
-+/* make ec goto idle mode */
-+static int ec_init_idle_mode(void)
-+{
-+ int timeout;
-+ unsigned char status = 0;
-+ int ret = 0;
-+
-+ ec_query_seq(CMD_INIT_IDLE_MODE);
-+
-+ /* make the action take active */
-+ timeout = EC_CMD_TIMEOUT;
-+ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE;
-+ while (timeout--) {
-+ if (status) {
-+ udelay(EC_REG_DELAY);
-+ break;
-+ }
-+ status = ec_read(REG_POWER_MODE) & FLAG_IDLE_MODE;
-+ udelay(EC_REG_DELAY);
-+ }
-+ if (timeout <= 0) {
-+ printk(KERN_ERR "ec rom fixup : can't check out the status.\n");
-+ ret = -EINVAL;
-+ } else
-+ printk(KERN_INFO "(%d/%d)0xf710 : 0x%x\n", timeout,
-+ EC_CMD_TIMEOUT - timeout, ec_read(REG_POWER_MODE));
-+
-+ printk(KERN_INFO "entering idle mode ok...................\n");
-+
-+ return ret;
-+}
-+
-+/* make ec exit from idle mode */
-+static int ec_exit_idle_mode(void)
-+{
-+
-+ ec_query_seq(CMD_EXIT_IDLE_MODE);
-+
-+ printk(KERN_INFO "exit idle mode ok...................\n");
-+
-+ return 0;
-+}
-+
-+static int ec_instruction_cycle(void)
-+{
-+ unsigned long timeout;
-+ int ret = 0;
-+
-+ timeout = EC_FLASH_TIMEOUT;
-+ while (timeout-- >= 0) {
-+ if (!(ec_read(REG_XBISPICFG) & SPICFG_SPI_BUSY))
-+ break;
-+ }
-+ if (timeout <= 0) {
-+ printk(KERN_ERR
-+ "EC_INSTRUCTION_CYCLE : timeout for check flag.\n");
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ out:
-+ return ret;
-+}
-+
-+/* To see if the ec is in busy state or not. */
-+static inline int ec_flash_busy(unsigned long timeout)
-+{
-+ /* assurance the first command be going to rom */
-+ if (ec_instruction_cycle() < 0)
-+ return EC_STATE_BUSY;
-+#if 1
-+ timeout = timeout / EC_MAX_DELAY_UNIT;
-+ while (timeout-- > 0) {
-+ /* check the rom's status of busy flag */
-+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
-+ if (ec_instruction_cycle() < 0)
-+ return EC_STATE_BUSY;
-+ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00)
-+ return EC_STATE_IDLE;
-+ udelay(EC_MAX_DELAY_UNIT);
-+ }
-+ if (timeout <= 0) {
-+ printk(KERN_ERR
-+ "EC_FLASH_BUSY : timeout for check rom flag.\n");
-+ return EC_STATE_BUSY;
-+ }
-+#else
-+ /* check the rom's status of busy flag */
-+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
-+ if (ec_instruction_cycle() < 0)
-+ return EC_STATE_BUSY;
-+
-+ timeout = timeout / EC_MAX_DELAY_UNIT;
-+ while (timeout-- > 0) {
-+ if ((ec_read(REG_XBISPIDAT) & 0x01) == 0x00)
-+ return EC_STATE_IDLE;
-+ udelay(EC_MAX_DELAY_UNIT);
-+ }
-+ if (timeout <= 0) {
-+ printk(KERN_ERR
-+ "EC_FLASH_BUSY : timeout for check rom flag.\n");
-+ return EC_STATE_BUSY;
-+ }
-+#endif
-+
-+ return EC_STATE_IDLE;
-+}
-+
-+static int rom_instruction_cycle(unsigned char cmd)
-+{
-+ unsigned long timeout = 0;
-+
-+ switch (cmd) {
-+ case SPICMD_READ_STATUS:
-+ case SPICMD_WRITE_ENABLE:
-+ case SPICMD_WRITE_DISABLE:
-+ case SPICMD_READ_BYTE:
-+ case SPICMD_HIGH_SPEED_READ:
-+ timeout = 0;
-+ break;
-+ case SPICMD_WRITE_STATUS:
-+ timeout = 300 * 1000;
-+ break;
-+ case SPICMD_BYTE_PROGRAM:
-+ timeout = 5 * 1000;
-+ break;
-+ case SPICMD_SST_SEC_ERASE:
-+ case SPICMD_SEC_ERASE:
-+ timeout = 1000 * 1000;
-+ break;
-+ case SPICMD_SST_BLK_ERASE:
-+ case SPICMD_BLK_ERASE:
-+ timeout = 3 * 1000 * 1000;
-+ break;
-+ case SPICMD_SST_CHIP_ERASE:
-+ case SPICMD_CHIP_ERASE:
-+ timeout = 20 * 1000 * 1000;
-+ break;
-+ default:
-+ timeout = EC_SPICMD_STANDARD_TIMEOUT;
-+ }
-+ if (timeout == 0)
-+ return ec_instruction_cycle();
-+ if (timeout < EC_SPICMD_STANDARD_TIMEOUT)
-+ timeout = EC_SPICMD_STANDARD_TIMEOUT;
-+
-+ return ec_flash_busy(timeout);
-+}
-+
-+/* delay for start/stop action */
-+static void delay_spi(int n)
-+{
-+ while (n--)
-+ inb(EC_IO_PORT_HIGH);
-+}
-+
-+/* start the action to spi rom function */
-+static void ec_start_spi(void)
-+{
-+ unsigned char val;
-+
-+ delay_spi(SPI_FINISH_WAIT_TIME);
-+ val = ec_read(REG_XBISPICFG) | SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK;
-+ ec_write(REG_XBISPICFG, val);
-+ delay_spi(SPI_FINISH_WAIT_TIME);
-+}
-+
-+/* stop the action to spi rom function */
-+static void ec_stop_spi(void)
-+{
-+ unsigned char val;
-+
-+ delay_spi(SPI_FINISH_WAIT_TIME);
-+ val =
-+ ec_read(REG_XBISPICFG) & (~(SPICFG_EN_SPICMD | SPICFG_AUTO_CHECK));
-+ ec_write(REG_XBISPICFG, val);
-+ delay_spi(SPI_FINISH_WAIT_TIME);
-+}
-+
-+/* read one byte from xbi interface */
-+static int ec_read_byte(unsigned int addr, unsigned char *byte)
-+{
-+ int ret = 0;
-+
-+ /* enable spicmd writing. */
-+ ec_start_spi();
-+
-+ /* enable write spi flash */
-+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
-+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
-+ printk(KERN_ERR "EC_READ_BYTE : SPICMD_WRITE_ENABLE failed.\n");
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ /* write the address */
-+ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16);
-+ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8);
-+ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0);
-+ /* start action */
-+ ec_write(REG_XBISPICMD, SPICMD_HIGH_SPEED_READ);
-+ if (rom_instruction_cycle(SPICMD_HIGH_SPEED_READ) == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_READ_BYTE : SPICMD_HIGH_SPEED_READ failed.\n");
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ *byte = ec_read(REG_XBISPIDAT);
-+
-+ out:
-+ /* disable spicmd writing. */
-+ ec_stop_spi();
-+
-+ return ret;
-+}
-+
-+/* write one byte to ec rom */
-+static int ec_write_byte(unsigned int addr, unsigned char byte)
-+{
-+ int ret = 0;
-+
-+ /* enable spicmd writing. */
-+ ec_start_spi();
-+
-+ /* enable write spi flash */
-+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
-+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_WRITE_BYTE : SPICMD_WRITE_ENABLE failed.\n");
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ /* write the address */
-+ ec_write(REG_XBISPIA2, (addr & 0xff0000) >> 16);
-+ ec_write(REG_XBISPIA1, (addr & 0x00ff00) >> 8);
-+ ec_write(REG_XBISPIA0, (addr & 0x0000ff) >> 0);
-+ ec_write(REG_XBISPIDAT, byte);
-+ /* start action */
-+ ec_write(REG_XBISPICMD, SPICMD_BYTE_PROGRAM);
-+ if (rom_instruction_cycle(SPICMD_BYTE_PROGRAM) == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_WRITE_BYTE : SPICMD_BYTE_PROGRAM failed.\n");
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ out:
-+ /* disable spicmd writing. */
-+ ec_stop_spi();
-+
-+ return ret;
-+}
-+
-+/* unprotect SPI ROM */
-+/* EC_ROM_unprotect function code */
-+static int EC_ROM_unprotect(void)
-+{
-+ unsigned char status;
-+
-+ /* enable write spi flash */
-+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
-+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n");
-+ return 1;
-+ }
-+
-+ /* unprotect the status register of rom */
-+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
-+ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) {
-+ printk(KERN_ERR "EC_UNIT_ERASE : SPICMD_READ_STATUS failed.\n");
-+ return 1;
-+ }
-+ status = ec_read(REG_XBISPIDAT);
-+ ec_write(REG_XBISPIDAT, status & 0x02);
-+ if (ec_instruction_cycle() < 0) {
-+ printk(KERN_ERR "EC_UNIT_ERASE : write status value failed.\n");
-+ return 1;
-+ }
-+
-+ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS);
-+ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_UNIT_ERASE : SPICMD_WRITE_STATUS failed.\n");
-+ return 1;
-+ }
-+
-+ /* enable write spi flash */
-+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
-+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_UNIT_ERASE : SPICMD_WRITE_ENABLE failed.\n");
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+/* erase one block or chip or sector as needed */
-+static int ec_unit_erase(unsigned char erase_cmd, unsigned int addr)
-+{
-+ unsigned char status;
-+ int ret = 0, i = 0;
-+ int unprotect_count = 3;
-+ int check_flag = 0;
-+
-+ /* enable spicmd writing. */
-+ ec_start_spi();
-+
-+#ifdef EC_ROM_PROTECTION
-+ /* added for re-check SPICMD_READ_STATUS */
-+ while (unprotect_count-- > 0) {
-+ if (EC_ROM_unprotect()) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ /* first time:500ms --> 5.5sec -->10.5sec */
-+ for (i = 0; i < ((2 - unprotect_count) * 100 + 10); i++)
-+ udelay(50000);
-+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
-+ if (rom_instruction_cycle(SPICMD_READ_STATUS)
-+ == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n");
-+ } else {
-+ status = ec_read(REG_XBISPIDAT);
-+ printk(KERN_INFO "Read unprotect status : 0x%x\n",
-+ status);
-+ if ((status & 0x1C) == 0x00) {
-+ printk(KERN_INFO
-+ "Read unprotect status OK1 : 0x%x\n",
-+ status & 0x1C);
-+ check_flag = 1;
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (!check_flag) {
-+ printk(KERN_INFO "SPI ROM unprotect fail.\n");
-+ return 1;
-+ }
-+#endif
-+
-+ /* block address fill */
-+ if (erase_cmd == SPICMD_BLK_ERASE) {
-+ ec_write(REG_XBISPIA2, (addr & 0x00ff0000) >> 16);
-+ ec_write(REG_XBISPIA1, (addr & 0x0000ff00) >> 8);
-+ ec_write(REG_XBISPIA0, (addr & 0x000000ff) >> 0);
-+ }
-+
-+ /* erase the whole chip first */
-+ ec_write(REG_XBISPICMD, erase_cmd);
-+ if (rom_instruction_cycle(erase_cmd) == EC_STATE_BUSY) {
-+ printk(KERN_ERR "EC_UNIT_ERASE : erase failed.\n");
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ out:
-+ /* disable spicmd writing. */
-+ ec_stop_spi();
-+
-+ return ret;
-+}
-+
-+/* update the whole rom content with H/W mode
-+ * PLEASE USING ec_unit_erase() FIRSTLY
-+ */
-+static int ec_program_rom(struct ec_info *info, int flag)
-+{
-+ unsigned int addr = 0;
-+ unsigned long size = 0;
-+ unsigned char *ptr = NULL;
-+ unsigned char data;
-+ unsigned char val = 0;
-+ int ret = 0;
-+ int i, j;
-+ unsigned char status;
-+
-+ /* modify for program serial No.
-+ * set IE_START_ADDR & use idle mode,
-+ * disable WDD
-+ */
-+ if (flag == PROGRAM_FLAG_ROM) {
-+ ret = ec_init_reset_mode();
-+ addr = info->start_addr + EC_START_ADDR;
-+ printk(KERN_INFO "PROGRAM_FLAG_ROM..............\n");
-+ } else if (flag == PROGRAM_FLAG_IE) {
-+ ret = ec_init_idle_mode();
-+ ec_disable_WDD();
-+ addr = info->start_addr + IE_START_ADDR;
-+ printk(KERN_INFO "PROGRAM_FLAG_IE..............\n");
-+ } else {
-+ return 0;
-+ }
-+
-+ if (ret < 0) {
-+ if (flag == PROGRAM_FLAG_IE)
-+ ec_enable_WDD();
-+ return ret;
-+ }
-+
-+ size = info->size;
-+ ptr = info->buf;
-+ printk(KERN_INFO "starting update ec ROM..............\n");
-+
-+ ret = ec_unit_erase(SPICMD_BLK_ERASE, addr);
-+ if (ret) {
-+ printk(KERN_ERR "program ec : erase block failed.\n");
-+ goto out;
-+ }
-+ printk(KERN_ERR "program ec : erase block OK.\n");
-+
-+ i = 0;
-+ while (i < size) {
-+ data = *(ptr + i);
-+ ec_write_byte(addr, data);
-+ ec_read_byte(addr, &val);
-+ if (val != data) {
-+ ec_write_byte(addr, data);
-+ ec_read_byte(addr, &val);
-+ if (val != data) {
-+ printk(KERN_INFO
-+ "EC : Second flash program failed at:\t");
-+ printk(KERN_INFO
-+ "addr : 0x%x, source : 0x%x, dest: 0x%x\n",
-+ addr, data, val);
-+ printk(KERN_INFO "This should not happen... STOP\n");
-+ break;
-+ }
-+ }
-+ i++;
-+ addr++;
-+ }
-+
-+#ifdef EC_ROM_PROTECTION
-+ /* we should start spi access firstly */
-+ ec_start_spi();
-+
-+ /* enable write spi flash */
-+ ec_write(REG_XBISPICMD, SPICMD_WRITE_ENABLE);
-+ if (rom_instruction_cycle(SPICMD_WRITE_ENABLE) == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_PROGRAM_ROM : SPICMD_WRITE_ENABLE failed.\n");
-+ goto out1;
-+ }
-+
-+ /* protect the status register of rom */
-+ ec_write(REG_XBISPICMD, SPICMD_READ_STATUS);
-+ if (rom_instruction_cycle(SPICMD_READ_STATUS) == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_PROGRAM_ROM : SPICMD_READ_STATUS failed.\n");
-+ goto out1;
-+ }
-+ status = ec_read(REG_XBISPIDAT);
-+
-+ ec_write(REG_XBISPIDAT, status | 0x1C);
-+ if (ec_instruction_cycle() < 0) {
-+ printk(KERN_ERR
-+ "EC_PROGRAM_ROM : write status value failed.\n");
-+ goto out1;
-+ }
-+
-+ ec_write(REG_XBISPICMD, SPICMD_WRITE_STATUS);
-+ if (rom_instruction_cycle(SPICMD_WRITE_STATUS) == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_PROGRAM_ROM : SPICMD_WRITE_STATUS failed.\n");
-+ goto out1;
-+ }
-+#endif
-+
-+ /* disable the write action to spi rom */
-+ ec_write(REG_XBISPICMD, SPICMD_WRITE_DISABLE);
-+ if (rom_instruction_cycle(SPICMD_WRITE_DISABLE) == EC_STATE_BUSY) {
-+ printk(KERN_ERR
-+ "EC_PROGRAM_ROM : SPICMD_WRITE_DISABLE failed.\n");
-+ goto out1;
-+ }
-+
-+ out1:
-+ /* we should stop spi access firstly */
-+ ec_stop_spi();
-+ out:
-+ /* for security */
-+ for (j = 0; j < 2000; j++)
-+ udelay(1000);
-+
-+ /* modify for program serial No.
-+ * after program No exit idle mode
-+ * and enable WDD
-+ */
-+ if (flag == PROGRAM_FLAG_ROM) {
-+ /* exit from the reset mode */
-+ ec_exit_reset_mode();
-+ } else {
-+ /* ec exit from idle mode */
-+ ret = ec_exit_idle_mode();
-+ ec_enable_WDD();
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+/* ioctl */
-+static int misc_ioctl(struct inode *inode, struct file *filp, u_int cmd,
-+ u_long arg)
-+{
-+ struct ec_info ecinfo;
-+ void __user *ptr = (void __user *)arg;
-+ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data);
-+ int ret = 0;
-+
-+ switch (cmd) {
-+ case IOCTL_RDREG:
-+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg));
-+ if (ret) {
-+ printk(KERN_ERR "reg read : copy from user error.\n");
-+ return -EFAULT;
-+ }
-+ if ((ecreg->addr > EC_MAX_REGADDR)
-+ || (ecreg->addr < EC_MIN_REGADDR)) {
-+ printk(KERN_ERR
-+ "reg read : out of register address range.\n");
-+ return -EINVAL;
-+ }
-+ ecreg->val = ec_read(ecreg->addr);
-+ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg));
-+ if (ret) {
-+ printk(KERN_ERR "reg read : copy to user error.\n");
-+ return -EFAULT;
-+ }
-+ break;
-+ case IOCTL_WRREG:
-+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg));
-+ if (ret) {
-+ printk(KERN_ERR "reg write : copy from user error.\n");
-+ return -EFAULT;
-+ }
-+ if ((ecreg->addr > EC_MAX_REGADDR)
-+ || (ecreg->addr < EC_MIN_REGADDR)) {
-+ printk(KERN_ERR
-+ "reg write : out of register address range.\n");
-+ return -EINVAL;
-+ }
-+ ec_write(ecreg->addr, ecreg->val);
-+ break;
-+ case IOCTL_READ_EC:
-+ ret = copy_from_user(ecreg, ptr, sizeof(struct ec_reg));
-+ if (ret) {
-+ printk(KERN_ERR "spi read : copy from user error.\n");
-+ return -EFAULT;
-+ }
-+ if ((ecreg->addr > EC_RAM_ADDR)
-+ && (ecreg->addr < EC_MAX_REGADDR)) {
-+ printk(KERN_ERR
-+ "spi read : out of register address range.\n");
-+ return -EINVAL;
-+ }
-+ ec_read_byte(ecreg->addr, &(ecreg->val));
-+ ret = copy_to_user(ptr, ecreg, sizeof(struct ec_reg));
-+ if (ret) {
-+ printk(KERN_ERR "spi read : copy to user error.\n");
-+ return -EFAULT;
-+ }
-+ break;
-+ case IOCTL_PROGRAM_IE:
-+ ecinfo.start_addr = EC_START_ADDR;
-+ ecinfo.size = EC_CONTENT_MAX_SIZE;
-+ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL);
-+ if (ecinfo.buf == NULL) {
-+ printk(KERN_ERR "program ie : kmalloc failed.\n");
-+ return -ENOMEM;
-+ }
-+ ret = copy_from_user(ecinfo.buf, (u8 *) ptr, ecinfo.size);
-+ if (ret) {
-+ printk(KERN_ERR "program ie : copy from user error.\n");
-+ kfree(ecinfo.buf);
-+ ecinfo.buf = NULL;
-+ return -EFAULT;
-+ }
-+
-+ /* use ec_program_rom to write serial No */
-+ ec_program_rom(&ecinfo, PROGRAM_FLAG_IE);
-+
-+ kfree(ecinfo.buf);
-+ ecinfo.buf = NULL;
-+ break;
-+ case IOCTL_PROGRAM_EC:
-+ ecinfo.start_addr = EC_START_ADDR;
-+ if (get_user((ecinfo.size), (u32 *) ptr)) {
-+ printk(KERN_ERR "program ec : get user error.\n");
-+ return -EFAULT;
-+ }
-+ if ((ecinfo.size) > EC_CONTENT_MAX_SIZE) {
-+ printk(KERN_ERR "program ec : size out of limited.\n");
-+ return -EINVAL;
-+ }
-+ ecinfo.buf = (u8 *) kmalloc(ecinfo.size, GFP_KERNEL);
-+ if (ecinfo.buf == NULL) {
-+ printk(KERN_ERR "program ec : kmalloc failed.\n");
-+ return -ENOMEM;
-+ }
-+ ret = copy_from_user(ecinfo.buf, ((u8 *) ptr + 4), ecinfo.size);
-+ if (ret) {
-+ printk(KERN_ERR "program ec : copy from user error.\n");
-+ kfree(ecinfo.buf);
-+ ecinfo.buf = NULL;
-+ return -EFAULT;
-+ }
-+
-+ ec_program_rom(&ecinfo, PROGRAM_FLAG_ROM);
-+
-+ kfree(ecinfo.buf);
-+ ecinfo.buf = NULL;
-+ break;
-+
-+ default:
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static long misc_compat_ioctl(struct file *file, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ return misc_ioctl(file->f_dentry->d_inode, file, cmd, arg);
-+}
-+
-+static int misc_open(struct inode *inode, struct file *filp)
-+{
-+ struct ec_reg *ecreg = NULL;
-+ ecreg = kmalloc(sizeof(struct ec_reg), GFP_KERNEL);
-+ if (ecreg)
-+ filp->private_data = ecreg;
-+
-+ return ecreg ? 0 : -ENOMEM;
-+}
-+
-+static int misc_release(struct inode *inode, struct file *filp)
-+{
-+ struct ec_reg *ecreg = (struct ec_reg *)(filp->private_data);
-+
-+ filp->private_data = NULL;
-+ kfree(ecreg);
-+
-+ return 0;
-+}
-+
-+static const struct file_operations ecmisc_fops = {
-+ .open = misc_open,
-+ .release = misc_release,
-+ .read = NULL,
-+ .write = NULL,
-+#ifdef CONFIG_64BIT
-+ .compat_ioctl = misc_compat_ioctl,
-+#else
-+ .ioctl = misc_ioctl,
-+#endif
-+};
-+
-+static struct miscdevice ecmisc_device = {
-+ .minor = MISC_DYNAMIC_MINOR,
-+ .name = EC_MISC_DEV,
-+ .fops = &ecmisc_fops
-+};
-+
-+static int __init ecmisc_init(void)
-+{
-+ int ret;
-+
-+ printk(KERN_INFO "EC misc device init.\n");
-+ ret = misc_register(&ecmisc_device);
-+
-+ return ret;
-+}
-+
-+static void __exit ecmisc_exit(void)
-+{
-+ printk(KERN_INFO "EC misc device exit.\n");
-+ misc_deregister(&ecmisc_device);
-+}
-+
-+module_init(ecmisc_init);
-+module_exit(ecmisc_exit);
-+
-+MODULE_AUTHOR("liujl <liujl@lemote.com>");
-+MODULE_DESCRIPTION("Driver for flushing/dumping ROM of EC on YeeLoong laptop");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
-new file mode 100644
-index 0000000..c285a67
---- /dev/null
-+++ b/drivers/platform/mips/yeeloong_laptop.c
-@@ -0,0 +1,1360 @@
-+/*
-+ * Driver for YeeLoong laptop extras
-+ *
-+ * Copyright (C) 2009 Lemote Inc.
-+ * Author: Wu Zhangjin <wuzhangjin@gmail.com>, Liu Junliang <liujl@lemote.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/backlight.h> /* for backlight subdriver */
-+#include <linux/fb.h>
-+#include <linux/hwmon.h> /* for hwmon subdriver */
-+#include <linux/hwmon-sysfs.h>
-+#include <linux/video_output.h> /* for video output subdriver */
-+#include <linux/lcd.h> /* for lcd output subdriver */
-+#include <linux/input.h> /* for hotkey subdriver */
-+#include <linux/input/sparse-keymap.h>
-+#include <linux/interrupt.h>
-+#include <linux/delay.h>
-+#include <linux/power_supply.h> /* for AC & Battery subdriver */
-+#include <linux/reboot.h> /* for register_reboot_notifier */
-+#include <linux/suspend.h> /* for register_pm_notifier */
-+
-+#include <cs5536/cs5536.h>
-+
-+#include <loongson.h> /* for loongson_cmdline */
-+#include <ec_kb3310b.h>
-+
-+#define ON 1
-+#define OFF 0
-+#define EVENT_START EVENT_LID
-+
-+/* common function */
-+#define EC_VER_LEN 64
-+
-+static int ec_version_before(char *version)
-+{
-+ char *p, ec_ver[EC_VER_LEN];
-+
-+ p = strstr(loongson_cmdline, "EC_VER=");
-+ if (!p)
-+ memset(ec_ver, 0, EC_VER_LEN);
-+ else {
-+ strncpy(ec_ver, p, EC_VER_LEN);
-+ p = strstr(ec_ver, " ");
-+ if (p)
-+ *p = '\0';
-+ }
-+
-+ return (strncasecmp(ec_ver, version, 64) < 0);
-+}
-+
-+/* backlight subdriver */
-+#define MIN_BRIGHTNESS 1
-+#define MAX_BRIGHTNESS 8
-+
-+static int yeeloong_set_brightness(struct backlight_device *bd)
-+{
-+ unsigned char level;
-+ static unsigned char old_level;
-+
-+ level = (bd->props.fb_blank == FB_BLANK_UNBLANK &&
-+ bd->props.power == FB_BLANK_UNBLANK) ?
-+ bd->props.brightness : 0;
-+
-+ level = clamp_val(level, MIN_BRIGHTNESS, MAX_BRIGHTNESS);
-+
-+ /* Avoid to modify the brightness when EC is tuning it */
-+ if (old_level != level) {
-+ if (ec_read(REG_DISPLAY_BRIGHTNESS) == old_level)
-+ ec_write(REG_DISPLAY_BRIGHTNESS, level);
-+ old_level = level;
-+ }
-+
-+ return 0;
-+}
-+
-+static int yeeloong_get_brightness(struct backlight_device *bd)
-+{
-+ return ec_read(REG_DISPLAY_BRIGHTNESS);
-+}
-+
-+static struct backlight_ops backlight_ops = {
-+ .get_brightness = yeeloong_get_brightness,
-+ .update_status = yeeloong_set_brightness,
-+};
-+
-+static struct backlight_device *yeeloong_backlight_dev;
-+
-+static int yeeloong_backlight_init(void)
-+{
-+ int ret;
-+ struct backlight_properties props;
-+
-+ memset(&props, 0, sizeof(struct backlight_properties));
-+ props.max_brightness = MAX_BRIGHTNESS;
-+ props.type = BACKLIGHT_PLATFORM;
-+ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL,
-+ NULL, &backlight_ops, &props);
-+
-+ if (IS_ERR(yeeloong_backlight_dev)) {
-+ ret = PTR_ERR(yeeloong_backlight_dev);
-+ yeeloong_backlight_dev = NULL;
-+ return ret;
-+ }
-+
-+ yeeloong_backlight_dev->props.brightness =
-+ yeeloong_get_brightness(yeeloong_backlight_dev);
-+ backlight_update_status(yeeloong_backlight_dev);
-+
-+ return 0;
-+}
-+
-+static void yeeloong_backlight_exit(void)
-+{
-+ if (yeeloong_backlight_dev) {
-+ backlight_device_unregister(yeeloong_backlight_dev);
-+ yeeloong_backlight_dev = NULL;
-+ }
-+}
-+
-+/* AC & Battery subdriver */
-+
-+static struct power_supply yeeloong_ac, yeeloong_bat;
-+
-+#define RET (val->intval)
-+
-+#define BAT_CAP_CRITICAL 5
-+#define BAT_CAP_HIGH 95
-+
-+#define get_bat(type) \
-+ ec_read(REG_BAT_##type)
-+
-+#define get_bat_l(type) \
-+ ((get_bat(type##_HIGH) << 8) | get_bat(type##_LOW))
-+
-+static int yeeloong_get_ac_props(struct power_supply *psy,
-+ enum power_supply_property psp,
-+ union power_supply_propval *val)
-+{
-+ if (psp == POWER_SUPPLY_PROP_ONLINE)
-+ RET = !!(get_bat(POWER) & BIT_BAT_POWER_ACIN);
-+
-+ return 0;
-+}
-+
-+static enum power_supply_property yeeloong_ac_props[] = {
-+ POWER_SUPPLY_PROP_ONLINE,
-+};
-+
-+static struct power_supply yeeloong_ac = {
-+ .name = "yeeloong-ac",
-+ .type = POWER_SUPPLY_TYPE_MAINS,
-+ .properties = yeeloong_ac_props,
-+ .num_properties = ARRAY_SIZE(yeeloong_ac_props),
-+ .get_property = yeeloong_get_ac_props,
-+};
-+
-+static inline bool is_bat_in(void)
-+{
-+ return !!(get_bat(STATUS) & BIT_BAT_STATUS_IN);
-+}
-+
-+static int get_bat_temp(void)
-+{
-+ return get_bat_l(TEMPERATURE) * 10;
-+}
-+
-+static int get_bat_current(void)
-+{
-+ return -(s16)get_bat_l(CURRENT);
-+}
-+
-+static int get_bat_voltage(void)
-+{
-+ return get_bat_l(VOLTAGE);
-+}
-+
-+static char *get_manufacturer(void)
-+{
-+ return (get_bat(VENDOR) == FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO";
-+}
-+
-+static int get_relative_cap(void)
-+{
-+ /*
-+ * When the relative capacity becomes 2, the hardware is observed to
-+ * have been turned off forcely. so, we must tune it be suitable to
-+ * make the software do related actions.
-+ */
-+ int tmp = get_bat_l(RELATIVE_CAP);
-+
-+ if (tmp <= (BAT_CAP_CRITICAL * 2))
-+ tmp -= 3;
-+
-+ return tmp;
-+}
-+
-+static int yeeloong_get_bat_props(struct power_supply *psy,
-+ enum power_supply_property psp,
-+ union power_supply_propval *val)
-+{
-+ switch (psp) {
-+ /* Fixed information */
-+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-+ /* mV -> µV */
-+ RET = get_bat_l(DESIGN_VOL) * 1000;
-+ break;
-+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
-+ /* mAh->µAh */
-+ RET = get_bat_l(DESIGN_CAP) * 1000;
-+ break;
-+ case POWER_SUPPLY_PROP_CHARGE_FULL:
-+ /* µAh */
-+ RET = get_bat_l(FULLCHG_CAP) * 1000;
-+ break;
-+ case POWER_SUPPLY_PROP_MANUFACTURER:
-+ val->strval = get_manufacturer();
-+ break;
-+ /* Dynamic information */
-+ case POWER_SUPPLY_PROP_PRESENT:
-+ RET = is_bat_in();
-+ break;
-+ case POWER_SUPPLY_PROP_CURRENT_NOW:
-+ /* mA -> µA */
-+ RET = is_bat_in() ? get_bat_current() * 1000 : 0;
-+ break;
-+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-+ /* mV -> µV */
-+ RET = is_bat_in() ? get_bat_voltage() * 1000 : 0;
-+ break;
-+ case POWER_SUPPLY_PROP_TEMP:
-+ /* Celcius */
-+ RET = is_bat_in() ? get_bat_temp() : 0;
-+ break;
-+ case POWER_SUPPLY_PROP_CAPACITY:
-+ RET = is_bat_in() ? get_relative_cap() : 0;
-+ break;
-+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: {
-+ int status;
-+
-+ if (!is_bat_in()) {
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
-+ break;
-+ }
-+
-+ status = get_bat(STATUS);
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
-+
-+ if (unlikely(status & BIT_BAT_STATUS_DESTROY)) {
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
-+ break;
-+ }
-+
-+ if (status & BIT_BAT_STATUS_FULL)
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
-+ else {
-+ int curr_cap = get_relative_cap();
-+
-+ if (status & BIT_BAT_STATUS_LOW) {
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
-+ if (curr_cap <= BAT_CAP_CRITICAL)
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
-+ } else if (curr_cap >= BAT_CAP_HIGH)
-+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
-+ }
-+ } break;
-+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
-+ /* seconds */
-+ RET = is_bat_in() ? (get_relative_cap() - 3) * 54 + 142 : 0;
-+ break;
-+ case POWER_SUPPLY_PROP_STATUS: {
-+ int charge = get_bat(CHARGE);
-+
-+ RET = POWER_SUPPLY_STATUS_UNKNOWN;
-+ if (charge & FLAG_BAT_CHARGE_DISCHARGE)
-+ RET = POWER_SUPPLY_STATUS_DISCHARGING;
-+ else if (charge & FLAG_BAT_CHARGE_CHARGE)
-+ RET = POWER_SUPPLY_STATUS_CHARGING;
-+ } break;
-+ case POWER_SUPPLY_PROP_HEALTH: {
-+ int status;
-+
-+ if (!is_bat_in()) {
-+ RET = POWER_SUPPLY_HEALTH_UNKNOWN;
-+ break;
-+ }
-+
-+ status = get_bat(STATUS);
-+ RET = POWER_SUPPLY_HEALTH_GOOD;
-+
-+ if (status & (BIT_BAT_STATUS_DESTROY |
-+ BIT_BAT_STATUS_LOW))
-+ RET = POWER_SUPPLY_HEALTH_DEAD;
-+ if (get_bat(CHARGE_STATUS) &
-+ BIT_BAT_CHARGE_STATUS_OVERTEMP)
-+ RET = POWER_SUPPLY_HEALTH_OVERHEAT;
-+ } break;
-+ case POWER_SUPPLY_PROP_CHARGE_NOW: /* 1/100(%)*1000 µAh */
-+ RET = get_relative_cap() * get_bat_l(FULLCHG_CAP) * 10;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+#undef RET
-+
-+static enum power_supply_property yeeloong_bat_props[] = {
-+ POWER_SUPPLY_PROP_STATUS,
-+ POWER_SUPPLY_PROP_PRESENT,
-+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
-+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-+ POWER_SUPPLY_PROP_CHARGE_FULL,
-+ POWER_SUPPLY_PROP_CHARGE_NOW,
-+ POWER_SUPPLY_PROP_CURRENT_NOW,
-+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
-+ POWER_SUPPLY_PROP_HEALTH,
-+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
-+ POWER_SUPPLY_PROP_CAPACITY,
-+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
-+ POWER_SUPPLY_PROP_TEMP,
-+ POWER_SUPPLY_PROP_MANUFACTURER,
-+};
-+
-+static struct power_supply yeeloong_bat = {
-+ .name = "yeeloong-bat",
-+ .type = POWER_SUPPLY_TYPE_BATTERY,
-+ .properties = yeeloong_bat_props,
-+ .num_properties = ARRAY_SIZE(yeeloong_bat_props),
-+ .get_property = yeeloong_get_bat_props,
-+};
-+
-+static int ac_bat_initialized;
-+
-+static int yeeloong_bat_init(void)
-+{
-+ int ret;
-+
-+ ret = power_supply_register(NULL, &yeeloong_ac);
-+ if (ret)
-+ return ret;
-+ ret = power_supply_register(NULL, &yeeloong_bat);
-+ if (ret) {
-+ power_supply_unregister(&yeeloong_ac);
-+ return ret;
-+ }
-+ ac_bat_initialized = 1;
-+
-+ return 0;
-+}
-+
-+static void yeeloong_bat_exit(void)
-+{
-+ ac_bat_initialized = 0;
-+
-+ power_supply_unregister(&yeeloong_ac);
-+ power_supply_unregister(&yeeloong_bat);
-+}
-+/* hwmon subdriver */
-+
-+#define MIN_FAN_SPEED 0
-+#define MAX_FAN_SPEED 3
-+
-+#define get_fan(type) \
-+ ec_read(REG_FAN_##type)
-+
-+#define set_fan(type, val) \
-+ ec_write(REG_FAN_##type, val)
-+
-+static inline int get_fan_speed_level(void)
-+{
-+ return get_fan(SPEED_LEVEL);
-+}
-+static inline void set_fan_speed_level(int speed)
-+{
-+ set_fan(SPEED_LEVEL, speed);
-+}
-+
-+static inline int get_fan_mode(void)
-+{
-+ return get_fan(AUTO_MAN_SWITCH);
-+}
-+static inline void set_fan_mode(int mode)
-+{
-+ set_fan(AUTO_MAN_SWITCH, mode);
-+}
-+
-+/*
-+ * 3 different modes: Full speed(0); manual mode(1); auto mode(2)
-+ */
-+static int get_fan_pwm_enable(void)
-+{
-+ return (get_fan_mode() == BIT_FAN_AUTO) ? 2 :
-+ (get_fan_speed_level() == MAX_FAN_SPEED) ? 0 : 1;
-+}
-+
-+static void set_fan_pwm_enable(int mode)
-+{
-+ set_fan_mode((mode == 2) ? BIT_FAN_AUTO : BIT_FAN_MANUAL);
-+ if (mode == 0)
-+ set_fan_speed_level(MAX_FAN_SPEED);
-+}
-+
-+static int get_fan_pwm(void)
-+{
-+ return get_fan_speed_level();
-+}
-+
-+static void set_fan_pwm(int value)
-+{
-+ if (get_fan_mode() != BIT_FAN_MANUAL)
-+ return;
-+
-+ value = clamp_val(value, MIN_FAN_SPEED, MAX_FAN_SPEED);
-+
-+ /* We must ensure the fan is on */
-+ if (value > 0)
-+ set_fan(CONTROL, ON);
-+
-+ set_fan_speed_level(value);
-+}
-+
-+static inline int get_fan_speed(void)
-+{
-+ return ((get_fan(SPEED_HIGH) & 0x0f) << 8) | get_fan(SPEED_LOW);
-+}
-+
-+static int get_fan_rpm(void)
-+{
-+ return FAN_SPEED_DIVIDER / get_fan_speed();
-+}
-+
-+static int get_cpu_temp(void)
-+{
-+ return (s8)ec_read(REG_TEMPERATURE_VALUE) * 1000;
-+}
-+
-+static int get_cpu_temp_max(void)
-+{
-+ return 60 * 1000;
-+}
-+
-+static int get_bat_temp_alarm(void)
-+{
-+ return !!(get_bat(CHARGE_STATUS) & BIT_BAT_CHARGE_STATUS_OVERTEMP);
-+}
-+
-+static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count)
-+{
-+ int ret;
-+ unsigned long value;
-+
-+ if (!count)
-+ return 0;
-+
-+ ret = strict_strtoul(buf, 10, &value);
-+ if (ret)
-+ return ret;
-+
-+ set(value);
-+
-+ return count;
-+}
-+
-+static ssize_t show_sys_hwmon(int (*get) (void), char *buf)
-+{
-+ return sprintf(buf, "%d\n", get());
-+}
-+
-+#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
-+ static ssize_t show_##_name(struct device *dev, \
-+ struct device_attribute *attr, \
-+ char *buf) \
-+ { \
-+ return show_sys_hwmon(_set, buf); \
-+ } \
-+ static ssize_t store_##_name(struct device *dev, \
-+ struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+ { \
-+ return store_sys_hwmon(_get, buf, count); \
-+ } \
-+ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
-+
-+CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL);
-+CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm);
-+CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable,
-+ set_fan_pwm_enable);
-+CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL);
-+CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL);
-+CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_bat_temp, NULL);
-+CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_bat_temp_alarm, NULL);
-+CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_bat_current, NULL);
-+CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_bat_voltage, NULL);
-+
-+static ssize_t
-+show_name(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ return sprintf(buf, "yeeloong\n");
-+}
-+
-+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
-+
-+static struct attribute *hwmon_attributes[] = {
-+ &sensor_dev_attr_pwm1.dev_attr.attr,
-+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
-+ &sensor_dev_attr_fan1_input.dev_attr.attr,
-+ &sensor_dev_attr_temp1_input.dev_attr.attr,
-+ &sensor_dev_attr_temp1_max.dev_attr.attr,
-+ &sensor_dev_attr_temp2_input.dev_attr.attr,
-+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
-+ &sensor_dev_attr_curr1_input.dev_attr.attr,
-+ &sensor_dev_attr_in1_input.dev_attr.attr,
-+ &sensor_dev_attr_name.dev_attr.attr,
-+ NULL
-+};
-+
-+static struct attribute_group hwmon_attribute_group = {
-+ .attrs = hwmon_attributes
-+};
-+
-+static struct device *yeeloong_hwmon_dev;
-+
-+static int yeeloong_hwmon_init(void)
-+{
-+ int ret;
-+
-+ yeeloong_hwmon_dev = hwmon_device_register(NULL);
-+ if (IS_ERR(yeeloong_hwmon_dev)) {
-+ yeeloong_hwmon_dev = NULL;
-+ return PTR_ERR(yeeloong_hwmon_dev);
-+ }
-+ ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj,
-+ &hwmon_attribute_group);
-+ if (ret) {
-+ hwmon_device_unregister(yeeloong_hwmon_dev);
-+ yeeloong_hwmon_dev = NULL;
-+ return ret;
-+ }
-+ /* ensure fan is set to auto mode */
-+ set_fan_pwm_enable(2);
-+
-+ return 0;
-+}
-+
-+static void yeeloong_hwmon_exit(void)
-+{
-+ if (yeeloong_hwmon_dev) {
-+ sysfs_remove_group(&yeeloong_hwmon_dev->kobj,
-+ &hwmon_attribute_group);
-+ hwmon_device_unregister(yeeloong_hwmon_dev);
-+ yeeloong_hwmon_dev = NULL;
-+ }
-+}
-+
-+/* video output subdriver */
-+
-+#define LCD 0
-+#define CRT 1
-+#define VOD_NUM 2 /* The total number of video output device*/
-+
-+static struct output_device *vod[VOD_NUM];
-+
-+static int vor[] = {REG_DISPLAY_LCD, REG_CRT_DETECT};
-+
-+static int get_vo_dev(struct output_device *od)
-+{
-+ int i, dev;
-+
-+ dev = -1;
-+ for (i = 0; i < VOD_NUM; i++)
-+ if (od == vod[i])
-+ dev = i;
-+
-+ return dev;
-+}
-+
-+static int vo_get_status(int dev)
-+{
-+ return ec_read(vor[dev]);
-+}
-+
-+static int yeeloong_vo_get_status(struct output_device *od)
-+{
-+ int vd;
-+
-+ vd = get_vo_dev(od);
-+ if (vd != -1)
-+ return vo_get_status(vd);
-+
-+ return -ENODEV;
-+}
-+
-+static void vo_set_state(int dev, int state)
-+{
-+ int addr;
-+ unsigned long value;
-+
-+ switch (dev) {
-+ case LCD:
-+ addr = 0x31;
-+ break;
-+ case CRT:
-+ addr = 0x21;
-+ break;
-+ default:
-+ /* return directly if the wrong video output device */
-+ return;
-+ }
-+
-+ outb(addr, 0x3c4);
-+ value = inb(0x3c5);
-+
-+ switch (dev) {
-+ case LCD:
-+ value |= (state ? 0x03 : 0x02);
-+ break;
-+ case CRT:
-+ if (state)
-+ clear_bit(7, &value);
-+ else
-+ set_bit(7, &value);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ outb(addr, 0x3c4);
-+ outb(value, 0x3c5);
-+
-+ if (dev == LCD)
-+ ec_write(REG_BACKLIGHT_CTRL, state);
-+}
-+
-+static int yeeloong_vo_set_state(struct output_device *od)
-+{
-+ int vd;
-+
-+ vd = get_vo_dev(od);
-+ if (vd == -1)
-+ return -ENODEV;
-+
-+ if (vd == CRT && !vo_get_status(vd))
-+ return 0;
-+
-+ vo_set_state(vd, !!od->request_state);
-+
-+ return 0;
-+}
-+
-+static struct output_properties vop = {
-+ .set_state = yeeloong_vo_set_state,
-+ .get_status = yeeloong_vo_get_status,
-+};
-+
-+static int yeeloong_vo_init(void)
-+{
-+ int ret, i;
-+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"};
-+
-+ /* Register video output device: lcd, crt */
-+ for (i = 0; i < VOD_NUM; i++) {
-+ vod[i] = video_output_register(dev_name[i], NULL, NULL, &vop);
-+ if (IS_ERR(vod[i])) {
-+ if (i != 0)
-+ video_output_unregister(vod[i-1]);
-+ ret = PTR_ERR(vod[i]);
-+ vod[i] = NULL;
-+ return ret;
-+ }
-+ }
-+ /* Ensure LCD is on by default */
-+ vo_set_state(LCD, ON);
-+
-+ /*
-+ * Turn off CRT by default, and will be enabled when the CRT
-+ * connectting event reported by SCI
-+ */
-+ vo_set_state(CRT, OFF);
-+
-+ return 0;
-+}
-+
-+static void yeeloong_vo_exit(void)
-+{
-+ int i;
-+
-+ for (i = 0; i < VOD_NUM; i++) {
-+ if (vod[i]) {
-+ video_output_unregister(vod[i]);
-+ vod[i] = NULL;
-+ }
-+ }
-+}
-+
-+/* lcd subdriver */
-+
-+struct lcd_device *lcd[VOD_NUM];
-+
-+static int get_lcd_dev(struct lcd_device *ld)
-+{
-+ int i, dev;
-+
-+ dev = -1;
-+ for (i = 0; i < VOD_NUM; i++)
-+ if (ld == lcd[i])
-+ dev = i;
-+
-+ return dev;
-+}
-+
-+static int yeeloong_lcd_set_power(struct lcd_device *ld, int power)
-+{
-+ int dev = get_lcd_dev(ld);
-+
-+ if (power == FB_BLANK_UNBLANK)
-+ vo_set_state(dev, ON);
-+ if (power == FB_BLANK_POWERDOWN)
-+ vo_set_state(dev, OFF);
-+
-+ return 0;
-+}
-+
-+static int yeeloong_lcd_get_power(struct lcd_device *ld)
-+{
-+ return vo_get_status(get_lcd_dev(ld));
-+}
-+
-+static struct lcd_ops lcd_ops = {
-+ .set_power = yeeloong_lcd_set_power,
-+ .get_power = yeeloong_lcd_get_power,
-+};
-+
-+static int yeeloong_lcd_init(void)
-+{
-+ int ret, i;
-+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"};
-+
-+ /* Register video output device: lcd, crt */
-+ for (i = 0; i < VOD_NUM; i++) {
-+ lcd[i] = lcd_device_register(dev_name[i], NULL, NULL, &lcd_ops);
-+ if (IS_ERR(lcd[i])) {
-+ if (i != 0)
-+ lcd_device_unregister(lcd[i-1]);
-+ ret = PTR_ERR(lcd[i]);
-+ lcd[i] = NULL;
-+ return ret;
-+ }
-+ }
-+#if 0
-+ /* This has been done by the vide output driver */
-+
-+ /* Ensure LCD is on by default */
-+ vo_set_state(LCD, ON);
-+
-+ /*
-+ * Turn off CRT by default, and will be enabled when the CRT
-+ * connectting event reported by SCI
-+ */
-+ vo_set_state(CRT, OFF);
-+#endif
-+ return 0;
-+}
-+
-+static void yeeloong_lcd_exit(void)
-+{
-+ int i;
-+
-+ for (i = 0; i < VOD_NUM; i++) {
-+ if (lcd[i]) {
-+ lcd_device_unregister(lcd[i]);
-+ lcd[i] = NULL;
-+ }
-+ }
-+}
-+
-+/* hotkey subdriver */
-+
-+static struct input_dev *yeeloong_hotkey_dev;
-+
-+static atomic_t reboot_flag, sleep_flag;
-+#define in_sleep() (&sleep_flag)
-+#define in_reboot() (&reboot_flag)
-+
-+static const struct key_entry yeeloong_keymap[] = {
-+ {KE_SW, EVENT_LID, { SW_LID } },
-+ {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */
-+ {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */
-+ {KE_KEY, EVENT_BLACK_SCREEN, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */
-+ {KE_KEY, EVENT_DISPLAY_TOGGLE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */
-+ {KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */
-+ {KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */
-+ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */
-+ {KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + down */
-+ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */
-+ {KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */
-+ {KE_END, 0}
-+};
-+
-+static int is_fake_event(u16 keycode)
-+{
-+ switch (keycode) {
-+ case KEY_SLEEP:
-+ case SW_LID:
-+ return atomic_read(in_sleep()) | atomic_read(in_reboot());
-+ break;
-+ default:
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static struct key_entry *get_event_key_entry(int event, int status)
-+{
-+ struct key_entry *ke;
-+ static int old_brightness_status = -1;
-+ static int old_volume_status = -1;
-+
-+ ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event);
-+ if (!ke)
-+ return NULL;
-+
-+ switch (event) {
-+ case EVENT_DISPLAY_BRIGHTNESS:
-+ /* current status > old one, means up */
-+ if ((status < old_brightness_status) || (0 == status))
-+ ke++;
-+ old_brightness_status = status;
-+ break;
-+ case EVENT_AUDIO_VOLUME:
-+ if ((status < old_volume_status) || (0 == status))
-+ ke++;
-+ old_volume_status = status;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return ke;
-+}
-+
-+static int report_lid_switch(int status)
-+{
-+ static int old_status;
-+
-+ /*
-+ * LID is a switch button, so, two continuous same status should be
-+ * ignored
-+ */
-+ if (old_status != status) {
-+ input_report_switch(yeeloong_hotkey_dev, SW_LID, !status);
-+ input_sync(yeeloong_hotkey_dev);
-+ }
-+ old_status = status;
-+
-+ return status;
-+}
-+
-+static int crt_detect_handler(int status)
-+{
-+ /*
-+ * When CRT is inserted, enable its output and disable the LCD output,
-+ * otherwise, do reversely.
-+ */
-+ vo_set_state(CRT, status);
-+ vo_set_state(LCD, !status);
-+
-+ return status;
-+}
-+
-+static int displaytoggle_handler(int status)
-+{
-+ /* EC(>=PQ1D26) does this job for us, we can not do it again,
-+ * otherwise, the brightness will not resume to the normal level! */
-+ if (ec_version_before("EC_VER=PQ1D26"))
-+ vo_set_state(LCD, status);
-+
-+ return status;
-+}
-+
-+static int mypow(int x, int y)
-+{
-+ int i, j = x;
-+
-+ for (i = 1; i < y; i++)
-+ j *= j;
-+
-+ return j;
-+}
-+
-+static int switchvideomode_handler(int status)
-+{
-+ /* Default status: CRT|LCD = 0|1 = 1 */
-+ static int bin_state = 1;
-+ int i;
-+
-+ /*
-+ * Only enable switch video output button
-+ * when CRT is connected
-+ */
-+ if (!vo_get_status(CRT))
-+ return 0;
-+ /*
-+ * 2. no CRT connected: LCD on, CRT off
-+ * 3. BOTH on
-+ * 0. BOTH off
-+ * 1. LCD off, CRT on
-+ */
-+
-+ bin_state++;
-+ if (bin_state > mypow(2, VOD_NUM) - 1)
-+ bin_state = 0;
-+
-+ for (i = 0; i < VOD_NUM; i++)
-+ vo_set_state(i, bin_state & (1 << i));
-+
-+ return bin_state;
-+}
-+
-+static int camera_handler(int status)
-+{
-+ int value;
-+
-+ value = ec_read(REG_CAMERA_CONTROL);
-+ ec_write(REG_CAMERA_CONTROL, value | (1 << 1));
-+
-+ return status;
-+}
-+
-+static int usb2_handler(int status)
-+{
-+ pr_emerg("USB2 Over Current occurred\n");
-+
-+ return status;
-+}
-+
-+static int usb0_handler(int status)
-+{
-+ pr_emerg("USB0 Over Current occurred\n");
-+
-+ return status;
-+}
-+
-+static int ac_bat_handler(int status)
-+{
-+ if (ac_bat_initialized) {
-+ power_supply_changed(&yeeloong_ac);
-+ power_supply_changed(&yeeloong_bat);
-+ }
-+
-+ return status;
-+}
-+
-+struct sci_event {
-+ int reg;
-+ sci_handler handler;
-+};
-+
-+static const struct sci_event se[] = {
-+ [EVENT_AC_BAT] = {0, ac_bat_handler},
-+ [EVENT_AUDIO_MUTE] = {REG_AUDIO_MUTE, NULL},
-+ [EVENT_AUDIO_VOLUME] = {REG_AUDIO_VOLUME, NULL},
-+ [EVENT_CRT_DETECT] = {REG_CRT_DETECT, crt_detect_handler},
-+ [EVENT_CAMERA] = {REG_CAMERA_STATUS, camera_handler},
-+ [EVENT_BLACK_SCREEN] = {REG_DISPLAY_LCD, displaytoggle_handler},
-+ [EVENT_DISPLAY_BRIGHTNESS] = {REG_DISPLAY_BRIGHTNESS, NULL},
-+ [EVENT_LID] = {REG_LID_DETECT, NULL},
-+ [EVENT_DISPLAY_TOGGLE] = {0, switchvideomode_handler},
-+ [EVENT_USB_OC0] = {REG_USB2_FLAG, usb0_handler},
-+ [EVENT_USB_OC2] = {REG_USB2_FLAG, usb2_handler},
-+ [EVENT_WLAN] = {REG_WLAN, NULL},
-+};
-+
-+static void do_event_action(int event)
-+{
-+ int status = -1;
-+ struct key_entry *ke;
-+ struct sci_event *sep;
-+
-+ sep = (struct sci_event *)&se[event];
-+
-+ if (sep->reg != 0)
-+ status = ec_read(sep->reg);
-+
-+ if (status == -1) {
-+ /* ec_read hasn't been called, status is invalid */
-+ return;
-+ }
-+
-+ if (sep->handler != NULL)
-+ status = sep->handler(status);
-+
-+ pr_debug("%s: event: %d status: %d\n", __func__, event, status);
-+
-+ /* Report current key to user-space */
-+ ke = get_event_key_entry(event, status);
-+
-+ /*
-+ * Ignore the LID and SLEEP event when we are already in sleep or
-+ * reboot state, this will avoid the recursive pm operations. but note:
-+ * the report_lid_switch() called in arch/mips/loongson/lemote-2f/pm.c
-+ * is necessary, because it is used to wake the system from sleep
-+ * state. In the future, perhaps SW_LID should works like SLEEP, no
-+ * need to function as a SWITCH, just report the state when the LID is
-+ * closed is enough, this event can tell the software to "SLEEP", no
-+ * need to tell the softwares when we are resuming from "SLEEP".
-+ */
-+ if (ke && !is_fake_event(ke->keycode)) {
-+ if (ke->keycode == SW_LID)
-+ report_lid_switch(status);
-+ else
-+ sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1,
-+ true);
-+ }
-+}
-+
-+/*
-+ * SCI(system control interrupt) main interrupt routine
-+ *
-+ * We will do the query and get event number together so the interrupt routine
-+ * should be longer than 120us now at least 3ms elpase for it.
-+ */
-+static irqreturn_t sci_irq_handler(int irq, void *dev_id)
-+{
-+ int ret, event;
-+
-+ if (SCI_IRQ_NUM != irq)
-+ return IRQ_NONE;
-+
-+ /* Query the event number */
-+ ret = ec_query_event_num();
-+ if (ret < 0)
-+ return IRQ_NONE;
-+
-+ event = ec_get_event_num();
-+ if (event < EVENT_START || event > EVENT_END)
-+ return IRQ_NONE;
-+
-+ /* Execute corresponding actions */
-+ do_event_action(event);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+/*
-+ * Config and init some msr and gpio register properly.
-+ */
-+static int sci_irq_init(void)
-+{
-+ u32 hi, lo;
-+ u32 gpio_base;
-+ unsigned long flags;
-+ int ret;
-+
-+ /* Get gpio base */
-+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo);
-+ gpio_base = lo & 0xff00;
-+
-+ /* Filter the former kb3310 interrupt for security */
-+ ret = ec_query_event_num();
-+ if (ret)
-+ return ret;
-+
-+ /* For filtering next number interrupt */
-+ udelay(10000);
-+
-+ /* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN
-+ * gpio :
-+ * input, pull-up, no-invert, event-count and value 0,
-+ * no-filter, no edge mode
-+ * gpio27 map to Virtual gpio0
-+ * msr :
-+ * no primary and lpc
-+ * Unrestricted Z input to IG10 from Virtual gpio 0.
-+ */
-+ local_irq_save(flags);
-+ _rdmsr(0x80000024, &hi, &lo);
-+ lo &= ~(1 << 10);
-+ _wrmsr(0x80000024, hi, lo);
-+ _rdmsr(0x80000025, &hi, &lo);
-+ lo &= ~(1 << 10);
-+ _wrmsr(0x80000025, hi, lo);
-+ _rdmsr(0x80000023, &hi, &lo);
-+ lo |= (0x0a << 0);
-+ _wrmsr(0x80000023, hi, lo);
-+ local_irq_restore(flags);
-+
-+ /* Set gpio27 as sci interrupt
-+ *
-+ * input, pull-up, no-fliter, no-negedge, invert
-+ * the sci event is just about 120us
-+ */
-+ asm(".set noreorder\n");
-+ /* input enable */
-+ outl(0x00000800, (gpio_base | 0xA0));
-+ /* revert the input */
-+ outl(0x00000800, (gpio_base | 0xA4));
-+ /* event-int enable */
-+ outl(0x00000800, (gpio_base | 0xB8));
-+ asm(".set reorder\n");
-+
-+ return 0;
-+}
-+
-+static int notify_reboot(struct notifier_block *nb, unsigned long event, void *buf)
-+{
-+ switch (event) {
-+ case SYS_RESTART:
-+ case SYS_HALT:
-+ case SYS_POWER_OFF:
-+ atomic_set(in_reboot(), 1);
-+ break;
-+ default:
-+ return NOTIFY_DONE;
-+ }
-+
-+ return NOTIFY_OK;
-+}
-+
-+static int notify_pm(struct notifier_block *nb, unsigned long event, void *buf)
-+{
-+ switch (event) {
-+ case PM_HIBERNATION_PREPARE:
-+ case PM_SUSPEND_PREPARE:
-+ atomic_inc(in_sleep());
-+ break;
-+ case PM_POST_HIBERNATION:
-+ case PM_POST_SUSPEND:
-+ case PM_RESTORE_PREPARE: /* do we need this ?? */
-+ atomic_dec(in_sleep());
-+ break;
-+ default:
-+ return NOTIFY_DONE;
-+ }
-+
-+ pr_debug("%s: event = %lu, in_sleep() = %d\n", __func__, event,
-+ atomic_read(in_sleep()));
-+
-+ return NOTIFY_OK;
-+}
-+
-+static struct notifier_block reboot_notifier = {
-+ .notifier_call = notify_reboot,
-+};
-+
-+static struct notifier_block pm_notifier = {
-+ .notifier_call = notify_pm,
-+};
-+
-+static int yeeloong_hotkey_init(void)
-+{
-+ int ret = 0;
-+
-+ ret = register_reboot_notifier(&reboot_notifier);
-+ if (ret) {
-+ pr_err("Can't register reboot notifier\n");
-+ goto end;
-+ }
-+
-+ ret = register_pm_notifier(&pm_notifier);
-+ if (ret) {
-+ pr_err("Can't register pm notifier\n");
-+ goto free_reboot_notifier;
-+ }
-+
-+ ret = sci_irq_init();
-+ if (ret) {
-+ pr_err("Can't init SCI interrupt\n");
-+ goto free_pm_notifier;
-+ }
-+
-+ ret = request_threaded_irq(SCI_IRQ_NUM, NULL, &sci_irq_handler,
-+ IRQF_ONESHOT, "sci", NULL);
-+ if (ret) {
-+ pr_err("Can't thread SCI interrupt handler\n");
-+ goto free_pm_notifier;
-+ }
-+
-+ yeeloong_hotkey_dev = input_allocate_device();
-+
-+ if (!yeeloong_hotkey_dev) {
-+ ret = -ENOMEM;
-+ goto free_irq;
-+ }
-+
-+ yeeloong_hotkey_dev->name = "HotKeys";
-+ yeeloong_hotkey_dev->phys = "button/input0";
-+ yeeloong_hotkey_dev->id.bustype = BUS_HOST;
-+ yeeloong_hotkey_dev->dev.parent = NULL;
-+
-+ ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL);
-+ if (ret) {
-+ pr_err("Failed to setup input device keymap\n");
-+ goto free_dev;
-+ }
-+
-+ ret = input_register_device(yeeloong_hotkey_dev);
-+ if (ret)
-+ goto free_keymap;
-+
-+ /* Update the current status of LID */
-+ report_lid_switch(ON);
-+
-+#ifdef CONFIG_LOONGSON_SUSPEND
-+ /* Install the real yeeloong_report_lid_status for pm.c */
-+ yeeloong_report_lid_status = report_lid_switch;
-+#endif
-+ return 0;
-+
-+free_keymap:
-+ sparse_keymap_free(yeeloong_hotkey_dev);
-+free_dev:
-+ input_free_device(yeeloong_hotkey_dev);
-+free_irq:
-+ free_irq(SCI_IRQ_NUM, NULL);
-+free_pm_notifier:
-+ unregister_pm_notifier(&pm_notifier);
-+free_reboot_notifier:
-+ unregister_reboot_notifier(&reboot_notifier);
-+end:
-+ return ret;
-+}
-+
-+static void yeeloong_hotkey_exit(void)
-+{
-+ /* Free irq */
-+ free_irq(SCI_IRQ_NUM, NULL);
-+
-+#ifdef CONFIG_LOONGSON_SUSPEND
-+ /* Uninstall yeeloong_report_lid_status for pm.c */
-+ if (yeeloong_report_lid_status == report_lid_switch)
-+ yeeloong_report_lid_status = NULL;
-+#endif
-+
-+ if (yeeloong_hotkey_dev) {
-+ sparse_keymap_free(yeeloong_hotkey_dev);
-+ input_unregister_device(yeeloong_hotkey_dev);
-+ yeeloong_hotkey_dev = NULL;
-+ }
-+}
-+
-+#ifdef CONFIG_PM
-+static void usb_ports_set(int status)
-+{
-+ status = !!status;
-+
-+ ec_write(REG_USB0_FLAG, status);
-+ ec_write(REG_USB1_FLAG, status);
-+ ec_write(REG_USB2_FLAG, status);
-+}
-+
-+static int yeeloong_suspend(struct device *dev)
-+
-+{
-+ if (ec_version_before("EC_VER=PQ1D27"))
-+ vo_set_state(LCD, OFF);
-+ vo_set_state(CRT, OFF);
-+ usb_ports_set(OFF);
-+
-+ return 0;
-+}
-+
-+static int yeeloong_resume(struct device *dev)
-+{
-+ int ret;
-+
-+ if (ec_version_before("EC_VER=PQ1D27"))
-+ vo_set_state(LCD, ON);
-+ vo_set_state(CRT, ON);
-+ usb_ports_set(ON);
-+
-+ ret = sci_irq_init();
-+ if (ret)
-+ return -EFAULT;
-+
-+ return 0;
-+}
-+
-+static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend,
-+ yeeloong_resume);
-+#endif
-+
-+static struct platform_device_id platform_device_ids[] = {
-+ {
-+ .name = "yeeloong_laptop",
-+ },
-+ {}
-+};
-+
-+MODULE_DEVICE_TABLE(platform, platform_device_ids);
-+
-+static struct platform_driver platform_driver = {
-+ .driver = {
-+ .name = "yeeloong_laptop",
-+ .owner = THIS_MODULE,
-+#ifdef CONFIG_PM
-+ .pm = &yeeloong_pm_ops,
-+#endif
-+ },
-+ .id_table = platform_device_ids,
-+};
-+
-+static int __init yeeloong_init(void)
-+{
-+ int ret;
-+
-+ pr_info("YeeLoong Laptop platform specific driver loaded.\n");
-+
-+ /* Register platform stuff */
-+ ret = platform_driver_register(&platform_driver);
-+ if (ret) {
-+ pr_err("Failed to register YeeLoong platform driver.\n");
-+ return ret;
-+ }
-+
-+#define yeeloong_init_drv(drv, alias) do { \
-+ pr_info("Registered YeeLoong " alias " driver.\n"); \
-+ ret = yeeloong_ ## drv ## _init(); \
-+ if (ret) { \
-+ pr_err("Failed to register YeeLoong " alias " driver.\n"); \
-+ yeeloong_ ## drv ## _exit(); \
-+ return ret; \
-+ } \
-+} while (0)
-+
-+ yeeloong_init_drv(backlight, "backlight");
-+ yeeloong_init_drv(bat, "battery and AC");
-+ yeeloong_init_drv(hwmon, "hardware monitor");
-+ yeeloong_init_drv(vo, "video output");
-+ yeeloong_init_drv(lcd, "lcd output");
-+ yeeloong_init_drv(hotkey, "hotkey input");
-+
-+ return 0;
-+}
-+
-+static void __exit yeeloong_exit(void)
-+{
-+ yeeloong_hotkey_exit();
-+ yeeloong_lcd_exit();
-+ yeeloong_vo_exit();
-+ yeeloong_hwmon_exit();
-+ yeeloong_bat_exit();
-+ yeeloong_backlight_exit();
-+ platform_driver_unregister(&platform_driver);
-+
-+ pr_info("YeeLoong platform specific driver unloaded.\n");
-+}
-+
-+module_init(yeeloong_init);
-+module_exit(yeeloong_exit);
-+
-+MODULE_AUTHOR("Wu Zhangjin <wuzhangjin@gmail.com>; Liu Junliang <liujl@lemote.com>");
-+MODULE_DESCRIPTION("YeeLoong laptop driver");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
-index db933de..1232c4b 100644
---- a/drivers/rtc/Kconfig
-+++ b/drivers/rtc/Kconfig
-@@ -649,6 +649,7 @@ comment "Platform RTC drivers"
- config RTC_DRV_CMOS
- tristate "PC-style 'CMOS'"
- depends on X86 || ARM || M32R || PPC || MIPS || SPARC64
-+ depends on !DEXXON_GDIUM
- default y if X86
- help
- Say "yes" here to get direct support for the real time clock
-diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c
-index 6176d98..e40ce80 100644
---- a/drivers/staging/sm7xxfb/sm7xxfb.c
-+++ b/drivers/staging/sm7xxfb/sm7xxfb.c
-@@ -101,6 +101,7 @@ static struct vesa_mode vesa_mode_table[] = {
- {"0x307", 1280, 1024, 8},
-
- {"0x311", 640, 480, 16},
-+ {"0x313", 800, 480, 16},
- {"0x314", 800, 600, 16},
- {"0x317", 1024, 768, 16},
- {"0x31A", 1280, 1024, 16},
-diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
-index 34fc86c..1569247 100644
---- a/drivers/usb/host/ohci-hcd.c
-+++ b/drivers/usb/host/ohci-hcd.c
-@@ -864,9 +864,13 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
- }
-
- if (ints & OHCI_INTR_WDH) {
-- spin_lock (&ohci->lock);
-- dl_done_list (ohci);
-- spin_unlock (&ohci->lock);
-+ if (ohci->hcca->done_head == 0) {
-+ ints &= ~OHCI_INTR_WDH;
-+ } else {
-+ spin_lock (&ohci->lock);
-+ dl_done_list (ohci);
-+ spin_unlock (&ohci->lock);
-+ }
- }
-
- if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
-diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
-index 2f3aceb..6647c3f 100644
---- a/drivers/usb/host/pci-quirks.c
-+++ b/drivers/usb/host/pci-quirks.c
-@@ -454,6 +454,7 @@ void usb_amd_dev_put(void)
- }
- EXPORT_SYMBOL_GPL(usb_amd_dev_put);
-
-+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE)
- /*
- * Make sure the controller is completely inactive, unable to
- * generate interrupts or do DMA.
-@@ -561,12 +562,16 @@ static void quirk_usb_handoff_uhci(struct pci_dev *pdev)
- if (base)
- uhci_check_and_reset_hc(pdev, base);
- }
-+#else
-+#define quirk_usb_handoff_uhci(x) do { } while (0)
-+#endif /* CONFIG_USB_UHCI_HCD* */
-
- static int mmio_resource_enabled(struct pci_dev *pdev, int idx)
- {
- return pci_resource_start(pdev, idx) && mmio_enabled(pdev);
- }
-
-+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
- static void quirk_usb_handoff_ohci(struct pci_dev *pdev)
- {
- void __iomem *base;
-@@ -633,7 +638,11 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev)
- /* Now the controller is safely in SUSPEND and nothing can wake it up */
- iounmap(base);
- }
-+#else
-+#define quirk_usb_handoff_ohci(x) do { } while(0)
-+#endif /* CONFIG_USB_OHCI_HCD* */
-
-+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
- static const struct dmi_system_id ehci_dmi_nohandoff_table[] = {
- {
- /* Pegatron Lucid (ExoPC) */
-@@ -806,6 +815,9 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev)
-
- iounmap(base);
- }
-+#else
-+#define quirk_usb_disable_ehci(x) do { } while (0)
-+#endif /* CONFIG_USB_EHCI_HCD* */
-
- /*
- * handshake - spin reading a register until handshake completes
-@@ -945,6 +957,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
- }
- EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
-
-+#if defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE)
- /**
- * PCI Quirks for xHCI.
- *
-@@ -1052,6 +1065,9 @@ hc_init:
-
- iounmap(base);
- }
-+#else
-+#define quirk_usb_handoff_xhci(x) do { } while (0)
-+#endif /* CONFIG_USB_UHCI_HCD* */
-
- static void quirk_usb_early_handoff(struct pci_dev *pdev)
- {
-diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
-index 8b34841..54e494d 100644
---- a/drivers/usb/serial/option.c
-+++ b/drivers/usb/serial/option.c
-@@ -79,6 +79,9 @@ static void option_instat_callback(struct urb *urb);
- #define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100
- #define OPTION_PRODUCT_GTM380_MODEM 0x7201
-
-+#define HUAWO_VENDOR_ID 0x21F5
-+#define HUAWO_PRODUCT_E1621 0x2008
-+
- #define HUAWEI_VENDOR_ID 0x12D1
- #define HUAWEI_PRODUCT_E173 0x140C
- #define HUAWEI_PRODUCT_E1750 0x1406
-@@ -633,6 +636,7 @@ static const struct usb_device_id option_ids[] = {
- { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) },
- { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
-+ { USB_DEVICE(HUAWO_VENDOR_ID, HUAWO_PRODUCT_E1621) }, /* QUANTA 6500 chips, Unicom extensive use of this card */
- { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) },
-diff --git a/include/linux/sm501.h b/include/linux/sm501.h
-index 02fde50..a8677f0 100644
---- a/include/linux/sm501.h
-+++ b/include/linux/sm501.h
-@@ -27,6 +27,9 @@ extern unsigned long sm501_set_clock(struct device *dev,
- extern unsigned long sm501_find_clock(struct device *dev,
- int clksrc, unsigned long req_freq);
-
-+extern void sm501_configure_gpio(struct device *dev,
-+ unsigned int gpio, unsigned char mode);
-+
- /* sm501_misc_control
- *
- * Modify the SM501's MISC_CONTROL register
-@@ -122,6 +125,7 @@ struct sm501_reg_init {
- #define SM501_USE_AC97 (1<<7)
- #define SM501_USE_I2S (1<<8)
- #define SM501_USE_GPIO (1<<9)
-+#define SM501_USE_PWM (1<<10)
-
- #define SM501_USE_ALL (0xffffffff)
-
-diff --git a/init/calibrate.c b/init/calibrate.c
-index 520702d..e78762a 100644
---- a/init/calibrate.c
-+++ b/init/calibrate.c
-@@ -21,6 +21,7 @@ static int __init lpj_setup(char *str)
-
- __setup("lpj=", lpj_setup);
-
-+#ifndef ARCH_HAS_PREPARED_LPJ
- #ifdef ARCH_HAS_READ_CURRENT_TIMER
-
- /* This routine uses the read_current_timer() routine and gets the
-@@ -171,6 +172,7 @@ static unsigned long calibrate_delay_direct(void)
- return 0;
- }
- #endif
-+#endif /* ARCH_HAS_PREPARED_LPJ */
-
- /*
- * This is the number of bits of precision for the loops_per_jiffy. Each
-@@ -282,6 +284,7 @@ void calibrate_delay(void)
- lpj = lpj_fine;
- pr_info("Calibrating delay loop (skipped), "
- "value calculated using timer frequency.. ");
-+#ifndef ARCH_HAS_PREPARED_LPJ
- } else if ((lpj = calibrate_delay_is_known())) {
- ;
- } else if ((lpj = calibrate_delay_direct()) != 0) {
-@@ -292,6 +295,7 @@ void calibrate_delay(void)
- if (!printed)
- pr_info("Calibrating delay loop... ");
- lpj = calibrate_delay_converge();
-+#endif /* ARCH_HAS_PREPARED_LPJ */
- }
- per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj;
- if (!printed)
-diff --git a/net/rfkill/core.c b/net/rfkill/core.c
-index ed7e0b4..6cb1ae8 100644
---- a/net/rfkill/core.c
-+++ b/net/rfkill/core.c
-@@ -111,7 +111,7 @@ static LIST_HEAD(rfkill_list); /* list of registered rf switches */
- static DEFINE_MUTEX(rfkill_global_mutex);
- static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */
-
--static unsigned int rfkill_default_state = 1;
-+static unsigned int rfkill_default_state; /* default: 0 = radio off */
- module_param_named(default_state, rfkill_default_state, uint, 0444);
- MODULE_PARM_DESC(default_state,
- "Default initial state for all radio types, 0 = radio off");
-diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
-index 91280b8..6b147ae 100755
---- a/scripts/recordmcount.pl
-+++ b/scripts/recordmcount.pl
-@@ -307,14 +307,33 @@ if ($arch eq "x86_64") {
- $cc .= " -m64";
- $objcopy .= " -O elf64-sparc";
- } elsif ($arch eq "mips") {
-- # To enable module support, we need to enable the -mlong-calls option
-- # of gcc for module, after using this option, we can not get the real
-- # offset of the calling to _mcount, but the offset of the lui
-- # instruction or the addiu one. herein, we record the address of the
-- # first one, and then we can replace this instruction by a branch
-- # instruction to jump over the profiling function to filter the
-- # indicated functions, or swith back to the lui instruction to trace
-- # them, which means dynamic tracing.
-+ # <For kernel>
-+ # To disable tracing, just replace "jal _mcount" with nop;
-+ # to enable tracing, replace back. so, the offset 14 is
-+ # needed to be recorded.
-+ #
-+ # 10: 03e0082d move at,ra
-+ # 14: 0c000000 jal 0
-+ # 14: R_MIPS_26 _mcount
-+ # 14: R_MIPS_NONE *ABS*
-+ # 14: R_MIPS_NONE *ABS*
-+ # 18: 00020021 nop
-+ #
-+ # <For module>
-+ #
-+ # If no long call(-mlong-calls), the same to kernel.
-+ #
-+ # If the module space differs from the kernel space, long
-+ # call is needed, as a result, the address of _mcount is
-+ # needed to be recorded in a register and then jump from
-+ # module space to kernel space via "jalr <register>". To
-+ # disable tracing, "jalr <register>" can be replaced by
-+ # nop; to enable tracing, replace it back. Since the
-+ # offset of "jalr <register>" is not easy to be matched,
-+ # the offset of the 1st _mcount below is recorded and to
-+ # disable tracing, "lui v1, 0x0" is substituted with "b
-+ # label", which jumps over "jalr <register>"; to enable
-+ # tracing, replace it back.
- #
- # c: 3c030000 lui v1,0x0
- # c: R_MIPS_HI16 _mcount
-@@ -326,19 +345,12 @@ if ($arch eq "x86_64") {
- # 10: R_MIPS_NONE *ABS*
- # 14: 03e0082d move at,ra
- # 18: 0060f809 jalr v1
-+ # label:
- #
-- # for the kernel:
-- #
-- # 10: 03e0082d move at,ra
-- # 14: 0c000000 jal 0 <loongson_halt>
-- # 14: R_MIPS_26 _mcount
-- # 14: R_MIPS_NONE *ABS*
-- # 14: R_MIPS_NONE *ABS*
-- # 18: 00020021 nop
- if ($is_module eq "0") {
- $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$";
- } else {
-- $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$";
-+ $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_(HI16|26)\\s+_mcount\$";
- }
- $objdump .= " -Melf-trad".$endian."mips ";
-
-diff --git a/scripts/sstrip.sh b/scripts/sstrip.sh
-new file mode 100755
-index 0000000..49b973a
---- /dev/null
-+++ b/scripts/sstrip.sh
-@@ -0,0 +1,59 @@
-+#!/bin/bash
-+# sstrip.sh -- strip the section table of an elf file
-+#
-+# Copyright (C) 2010 Wu Zhangjin, wuzhangjin@gmail.com
-+# Licensed under the GPLv2
-+#
-+# Since the section table is useless for the embedded device, it can be
-+# stripped out.
-+#
-+# Note: Some bootloader may check the section table but most of the time, it
-+# may be not really used, If it really need the section table, it may need the
-+# decompressed kernel image.
-+
-+# Usage
-+
-+function usage
-+{
-+cat <<EOF
-+
-+ # sstrip.sh -- strip the section table of an elf file
-+
-+ # Input: elf file
-+ # Output: truncated elf file without the section table
-+ # Usage: sstrip.sh /path/to/image
-+
-+EOF
-+}
-+
-+# Do some necessary check
-+IMAGE=$1
-+
-+[ -z "${IMAGE}" ] && echo "$0 : No indicated file to be stripped" && usage && exit -1
-+[ ! -f "${IMAGE}" ] && echo "$0 : ${IMAGE} : No such file" && exit -1
-+FILE_TYPE=`dd if=${IMAGE} bs=1 skip=1 count=3 2>/dev/null`
-+[ "xELF" != "x${FILE_TYPE}" ] && echo "$0: ${IMAGE} is not an ELF file" && exit -1
-+
-+[ "x${V}" == "x1" ] && orig_filesz=`wc -c ${IMAGE} | cut -d' ' -f1`
-+
-+# Get the offset of the section table, here get the end of the program section
-+filesz=$((`${OBJDUMP} -p ${IMAGE} | grep -m1 filesz | tr -s ' ' | cut -d' ' -f3`))
-+
-+# Truncate it via the dd tool
-+dd if=/dev/null bs=1 of=${IMAGE} seek=${filesz} 2>/dev/null
-+
-+# Clear the section table information in the ELF header
-+# The last 6 bytes of the ELF header are the section table information
-+echo -ne "\x00\x00\x00\x00\x00\x00" | dd of=${IMAGE} bs=1 seek=46 count=6 conv=notrunc 2>/dev/null
-+
-+# Debug
-+if [ "x${V}" == "x1" ]; then
-+ echo "----------------------------------------------------------------"
-+ echo "Strip the section table at ${filesz} of ${IMAGE}"
-+ echo "----------------------------------------------------------------"
-+ echo " sstrip: $0"
-+ echo " objdump: ${OBJDUMP}"
-+ echo "original size: ${orig_filesz}"
-+ echo "current size: ${filesz}"
-+ echo "reduced size: $((${orig_filesz} - ${filesz}))"
-+fi