summaryrefslogtreecommitdiff
path: root/libre/linux-libre-grsec/4.0.2-ae91f13af5-loongson-community.patch
diff options
context:
space:
mode:
Diffstat (limited to 'libre/linux-libre-grsec/4.0.2-ae91f13af5-loongson-community.patch')
-rw-r--r--libre/linux-libre-grsec/4.0.2-ae91f13af5-loongson-community.patch12168
1 files changed, 0 insertions, 12168 deletions
diff --git a/libre/linux-libre-grsec/4.0.2-ae91f13af5-loongson-community.patch b/libre/linux-libre-grsec/4.0.2-ae91f13af5-loongson-community.patch
deleted file mode 100644
index c550ff3da..000000000
--- a/libre/linux-libre-grsec/4.0.2-ae91f13af5-loongson-community.patch
+++ /dev/null
@@ -1,12168 +0,0 @@
-diff --git a/Makefile b/Makefile
-index 0649a60..d43fa5e 100644
---- a/Makefile
-+++ b/Makefile
-@@ -297,8 +297,8 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
-
- HOSTCC = gcc
- HOSTCXX = g++
--HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89
--HOSTCXXFLAGS = -O2
-+HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O3 -fomit-frame-pointer -std=gnu89
-+HOSTCXXFLAGS = -O3
-
- ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1)
- HOSTCFLAGS += -Wno-unused-value -Wno-unused-parameter \
-@@ -616,7 +616,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,)
- ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
- KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,)
- else
--KBUILD_CFLAGS += -O2
-+KBUILD_CFLAGS += -O3
- endif
-
- # Tell gcc to never replace conditional load with a non-conditional one
-diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
-index c7a1690..0f854f0 100644
---- a/arch/mips/Kconfig
-+++ b/arch/mips/Kconfig
-@@ -333,7 +333,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.
-
-@@ -1640,6 +1640,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
-
-@@ -2313,7 +2322,7 @@ config CPU_SUPPORTS_MSA
-
- 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/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 31903cf..14da73c 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/mach-loongson/cs5536/cs5536.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
-index a0ee0cb..4e18add 100644
---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
-+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
-@@ -301,5 +301,40 @@ extern void _wrmsr(u32 msr, u32 hi, u32 lo);
- /* GPIO : I/O SPACE; REG : 32BITS */
- #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..50aafca 100644
---- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
-+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
-@@ -28,8 +28,19 @@ static inline void __maybe_unused enable_mfgpt0_counter(void)
- #define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ)
-
- #define MFGPT_BASE mfgpt_base
-+#define MFGPT0_CMP1 (MFGPT_BASE + 0)
- #define MFGPT0_CMP2 (MFGPT_BASE + 2)
- #define MFGPT0_CNT (MFGPT_BASE + 4)
- #define MFGPT0_SETUP (MFGPT_BASE + 6)
-
-+#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/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
-index 5459ac0..14e82d9 100644
---- a/arch/mips/include/asm/mach-loongson/loongson.h
-+++ b/arch/mips/include/asm/mach-loongson/loongson.h
-@@ -46,6 +46,12 @@ static inline void prom_init_uart_base(void)
- #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);
- extern void __init bonito_irq_init(void);
-diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h
-index cb2b602..78fcd38 100644
---- a/arch/mips/include/asm/mach-loongson/machine.h
-+++ b/arch/mips/include/asm/mach-loongson/machine.h
-@@ -24,6 +24,12 @@
-
- #endif
-
-+#ifdef CONFIG_DEXXON_GDIUM
-+
-+#define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10
-+
-+#endif
-+
- #ifdef CONFIG_LOONGSON_MACH3X
-
- #define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC
-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/sparsemem.h b/arch/mips/include/asm/sparsemem.h
-index b1071c1..8b8e551 100644
---- a/arch/mips/include/asm/sparsemem.h
-+++ b/arch/mips/include/asm/sparsemem.h
-@@ -11,7 +11,11 @@
- #else
- # define SECTION_SIZE_BITS 28
- #endif
--#define MAX_PHYSMEM_BITS 48
-+#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit c461731836 broke Loongson2. */
-+# define MAX_PHYSMEM_BITS 48
-+#else
-+# define MAX_PHYSMEM_BITS 35
-+#endif
-
- #endif /* CONFIG_SPARSEMEM */
- #endif /* _MIPS_SPARSEMEM_H */
-diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h
-index b05bb70..44c9a69 100644
---- a/arch/mips/include/asm/timex.h
-+++ b/arch/mips/include/asm/timex.h
-@@ -11,6 +11,10 @@
-
- #ifdef __KERNEL__
-
-+#ifdef CONFIG_CSRC_R4K
-+#define ARCH_HAS_PREPARED_LPJ
-+#endif
-+
- #include <linux/compiler.h>
-
- #include <asm/cpu.h>
-diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h
-index fc0cf5a..99e6430 100644
---- a/arch/mips/include/uapi/asm/inst.h
-+++ b/arch/mips/include/uapi/asm/inst.h
-@@ -65,6 +65,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
-@@ -151,7 +153,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
- };
-
- /*
-@@ -180,7 +182,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 d07b210..69996f2 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 8d01709..9cd25da 100644
---- a/arch/mips/kernel/time.c
-+++ b/arch/mips/kernel/time.c
-@@ -119,6 +119,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 1e9e900..36fcccc 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
- lib-$(CONFIG_GENERIC_CSUM) := $(filter-out csum_partial.o, $(lib-y))
-diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig
-index 156de85..0a433e6 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,14 +45,13 @@ 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.
-@@ -60,6 +59,31 @@ config LEMOTE_MACH2F
- 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.
-+
- config LOONGSON_MACH3X
- bool "Generic Loongson 3 family machines"
- select ARCH_SPARSEMEM_ENABLE
-@@ -152,6 +176,24 @@ 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.
-+
- config LEFI_FIRMWARE_INTERFACE
- bool
-
-diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile
-index 7429994..63214c8 100644
---- a/arch/mips/loongson/Makefile
-+++ b/arch/mips/loongson/Makefile
-@@ -17,6 +17,12 @@ 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/
-+
-+#
- # All Loongson-3 family machines
- #
-
-diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform
-index 0ac20eb..cd957dd 100644
---- a/arch/mips/loongson/Platform
-+++ b/arch/mips/loongson/Platform
-@@ -30,4 +30,5 @@ 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
- load-$(CONFIG_LOONGSON_MACH3X) += 0xffffffff80200000
-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/env.c b/arch/mips/loongson/common/env.c
-index 045ea3d..1d1db80 100644
---- a/arch/mips/loongson/common/env.c
-+++ b/arch/mips/loongson/common/env.c
-@@ -29,6 +29,7 @@ struct efi_memory_map_loongson *loongson_memmap;
- struct loongson_system_configuration loongson_sysconf;
-
- u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
-+EXPORT_SYMBOL_GPL(loongson_chipcfg);
- u64 loongson_freqctrl[MAX_PACKAGES];
-
- unsigned long long smp_group[4];
-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/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/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
-index b30bf65..c0177cb 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.
-@@ -60,6 +63,11 @@ 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 *);
-
-+#ifdef CONFIG_MACH_LOONGSON
-+static int loongson_spec2_emu(struct pt_regs *,
-+ struct mips_fpu_struct *, mips_instruction, void *__user *);
-+#endif
-+
- /* Control registers */
-
- #define FPCREG_RID 0 /* $0 = revision id */
-@@ -842,6 +850,14 @@ do { \
- #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.
-@@ -1235,6 +1251,16 @@ emul:
- xcp->regs[MIPSInst_RD(ir)] =
- xcp->regs[MIPSInst_RS(ir)];
- break;
-+
-+#ifdef CONFIG_MACH_LOONGSON
-+ case spec2_op:{
-+ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr);
-+ if (sig)
-+ return sig;
-+ break;
-+ }
-+#endif
-+
- default:
- sigill:
- return SIGILL;
-@@ -1312,6 +1338,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 CONFIG_MACH_LOONGSON
-+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 {
-+ union ieee754dp d;
-+ struct {
-+ union ieee754sp s;
-+ union 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:{
-+ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp);
-+ union 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:{
-+ union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp);
-+ union 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:{
-+ union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp);
-+ struct _ieee754_csr ieee754_csr_save;
-+ union ieee754sp fd1, fs1, ft1;
-+ union 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)
- {
-@@ -1413,7 +1605,7 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- break;
-
- default:
-- return SIGILL;
-+ goto SIGILL_unless_prefx_op;
- }
- break;
- }
-@@ -1483,7 +1675,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;
- }
-@@ -1496,6 +1688,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;
- }
-
-@@ -1517,7 +1714,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- unsigned cond;
- union {
- union ieee754dp d;
-- union ieee754sp s;
-+ struct {
-+ union ieee754sp s;
-+#ifdef CONFIG_MACH_LOONGSON
-+ union ieee754sp s2; /* for Loongson paired singles */
-+#endif
-+ };
- int w;
- s64 l;
- } rv; /* resulting value */
-@@ -1614,7 +1816,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:
-@@ -1811,7 +2013,7 @@ copcsr:
- case fmov_op:
- /* an easy one */
- DPFROMREG(rv.d, MIPSInst_FS(ir));
-- goto copcsr;
-+ break;
-
- /* binary op on handler */
- dcopbop:
-@@ -1928,6 +2130,83 @@ dcopuop:
- break;
- }
-
-+#ifdef CONFIG_MACH_LOONGSON
-+ case ps_fmt:{ /* 6 */
-+ /* Support for Loongson paired single fp instructions */
-+ union {
-+ union ieee754sp(*b) (union ieee754sp, union ieee754sp);
-+ union ieee754sp(*u) (union 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;
-+ union ieee754sp fs1, ft1;
-+ union 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;
-+ union ieee754sp fs1;
-+ union 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 l_fmt:
-
- if (!cpu_has_mips_3_4_5 && !cpu_has_mips64)
-@@ -1999,6 +2278,11 @@ dcopuop:
-
- DITOREG(rv.l, MIPSInst_FD(ir));
- break;
-+#ifdef CONFIG_MACH_LOONGSON
-+ case ps_fmt:
-+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
-+ break;
-+#endif
- default:
- return SIGILL;
- }
-diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
-index 300591c..ed272e2 100644
---- a/arch/mips/pci/Makefile
-+++ b/arch/mips/pci/Makefile
-@@ -30,6 +30,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_LOONGSON_MACH3X) += fixup-loongson3.o ops-loongson3.o
- obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o
- obj-$(CONFIG_PMC_MSP7120_GW) += 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 e7567c8..498e42d 100644
---- a/arch/mips/power/hibernate.S
-+++ b/arch/mips/power/hibernate.S
-@@ -30,8 +30,10 @@ LEAF(swsusp_arch_suspend)
- END(swsusp_arch_suspend)
-
- LEAF(swsusp_arch_resume)
-+#if !defined(CONFIG_MACH_LOONGSON) || !defined(CONFIG_CPU_LOONGSON2) /* Commit 771004298d broke Loongson2. */
- /* Avoid TLB mismatch during and after kernel resume */
- jal local_flush_tlb_all
-+#endif
- PTR_L t0, restore_pblist
- 0:
- PTR_L t1, PBE_ADDRESS(t0) /* source */
-diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
-index fc897ba..ac60f6b 100644
---- a/drivers/cpufreq/loongson2_cpufreq.c
-+++ b/drivers/cpufreq/loongson2_cpufreq.c
-@@ -161,20 +161,32 @@ static int __init cpufreq_init(void)
- /* Register platform stuff */
- ret = platform_driver_register(&platform_driver);
- if (ret)
-- return ret;
-+ goto err_return;
-
- pr_info("cpufreq: Loongson-2F CPU frequency driver.\n");
-
-- cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,
-- CPUFREQ_TRANSITION_NOTIFIER);
-+ ret = cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,
-+ CPUFREQ_TRANSITION_NOTIFIER);
-+ if (ret)
-+ goto err_platform_driver_unregister;
-
- ret = cpufreq_register_driver(&loongson2_cpufreq_driver);
-+ if (ret)
-+ goto err_cpufreq_unregister_notifier;
-
-- if (!ret && !nowait) {
-+ if (!nowait) {
- saved_cpu_wait = cpu_wait;
- cpu_wait = loongson2_cpu_wait;
- }
-
-+ return 0;
-+
-+ err_cpufreq_unregister_notifier:
-+ cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block,
-+ CPUFREQ_TRANSITION_NOTIFIER);
-+ err_platform_driver_unregister:
-+ platform_driver_unregister(&platform_driver);
-+ err_return:
- return ret;
- }
-
-diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index 152b006..767d8de 100644
---- a/drivers/hid/Kconfig
-+++ b/drivers/hid/Kconfig
-@@ -871,6 +871,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 && HAS_IOMEM
-diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index 6f19958..2740ff0 100644
---- a/drivers/hid/Makefile
-+++ b/drivers/hid/Makefile
-@@ -99,6 +99,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
- wacom-objs := wacom_wac.o wacom_sys.o
- obj-$(CONFIG_HID_WACOM) += 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 7fe5590..3087a7f 100644
---- a/drivers/hid/hid-ids.h
-+++ b/drivers/hid/hid-ids.h
-@@ -1025,6 +1025,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/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 91077ef..2cfd9ff 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;
-@@ -1124,6 +1124,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)
- {
-@@ -1143,7 +1159,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)
-@@ -1198,6 +1220,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
-@@ -1356,6 +1392,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) {
-@@ -1542,10 +1580,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..32a2bdb
---- /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 = kstrtoul(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 b5b5c3d..f908003 100644
---- a/drivers/rtc/Kconfig
-+++ b/drivers/rtc/Kconfig
-@@ -727,6 +727,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/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
-index f940056..a9bb1db 100644
---- a/drivers/usb/host/pci-quirks.c
-+++ b/drivers/usb/host/pci-quirks.c
-@@ -450,6 +450,26 @@ 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) \
-+ || defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) \
-+ || defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) \
-+ || defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE)
-+static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
-+{
-+ u16 cmd;
-+ return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask);
-+}
-+
-+#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO)
-+#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY)
-+
-+static int mmio_resource_enabled(struct pci_dev *pdev, int idx)
-+{
-+ return pci_resource_start(pdev, idx) && mmio_enabled(pdev);
-+}
-+#endif
-+
-+#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.
-@@ -531,15 +551,6 @@ reset_needed:
- }
- EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
-
--static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
--{
-- u16 cmd;
-- return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask);
--}
--
--#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO)
--#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY)
--
- static void quirk_usb_handoff_uhci(struct pci_dev *pdev)
- {
- unsigned long base = 0;
-@@ -557,12 +568,11 @@ 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;
-@@ -641,7 +651,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) */
-@@ -816,6 +830,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
-@@ -956,6 +973,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.
- *
-@@ -1064,6 +1082,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 f0c0c53..84dff90 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/drivers/video/Kconfig b/drivers/video/Kconfig
-index 8bf495f..f6a15b6 100644
---- a/drivers/video/Kconfig
-+++ b/drivers/video/Kconfig
-@@ -36,6 +36,12 @@ config VGASTATE
- tristate
- default n
-
-+config VIDEO_OUTPUT_CONTROL
-+ tristate "Lowlevel video output switch controls"
-+ help
-+ This framework adds support for low-level control of the video
-+ output switch.
-+
- config VIDEOMODE_HELPERS
- bool
-
-diff --git a/drivers/video/Makefile b/drivers/video/Makefile
-index 9ad3c17..3d869d9 100644
---- a/drivers/video/Makefile
-+++ b/drivers/video/Makefile
-@@ -7,6 +7,8 @@ obj-y += backlight/
-
- obj-y += fbdev/
-
-+#video output switch sysfs driver
-+obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
- obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o
- ifeq ($(CONFIG_OF),y)
- obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o
-diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
-index b3dd417..452035ad 100644
---- a/drivers/video/fbdev/Kconfig
-+++ b/drivers/video/fbdev/Kconfig
-@@ -2450,6 +2450,19 @@ config FB_SIMPLE
- Configuration re: surface address, size, and format must be provided
- through device tree, or plain old platform data.
-
-+config FB_SM712
-+ tristate "Silicon Motion SM712 framebuffer support"
-+ depends on FB && PCI
-+ select FB_CFB_FILLRECT
-+ select FB_CFB_COPYAREA
-+ select FB_CFB_IMAGEBLIT
-+ help
-+ Frame buffer driver for the Silicon Motion SM712 chip.
-+
-+ This driver is also available as a module. The module will be
-+ called sm712fb. If you want to compile it as a module, say M
-+ here and read <file:Documentation/kbuild/modules.txt>.
-+
- source "drivers/video/fbdev/omap/Kconfig"
- source "drivers/video/fbdev/omap2/Kconfig"
- source "drivers/video/fbdev/exynos/Kconfig"
-diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
-index 1979aff..9b694f9 100644
---- a/drivers/video/fbdev/Makefile
-+++ b/drivers/video/fbdev/Makefile
-@@ -114,6 +114,7 @@ obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
- obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
- obj-$(CONFIG_FB_PS3) += ps3fb.o
- obj-$(CONFIG_FB_SM501) += sm501fb.o
-+obj-$(CONFIG_FB_SM712) += sm712fb/
- obj-$(CONFIG_FB_UDL) += udlfb.o
- obj-$(CONFIG_FB_SMSCUFX) += smscufx.o
- obj-$(CONFIG_FB_XILINX) += xilinxfb.o
-diff --git a/drivers/video/fbdev/sm712fb/Makefile b/drivers/video/fbdev/sm712fb/Makefile
-new file mode 100644
-index 0000000..9bf3519
---- /dev/null
-+++ b/drivers/video/fbdev/sm712fb/Makefile
-@@ -0,0 +1,3 @@
-+obj-$(CONFIG_FB_SM712) += sm712fb.o
-+
-+sm712fb-objs := sm712fb_drv.o sm712fb_accel.o
-diff --git a/drivers/video/fbdev/sm712fb/TODO b/drivers/video/fbdev/sm712fb/TODO
-new file mode 100644
-index 0000000..dcfd4e7
---- /dev/null
-+++ b/drivers/video/fbdev/sm712fb/TODO
-@@ -0,0 +1,7 @@
-+TODO:
-+- Dual head support
-+- refine the code, convert more registers magic numbers to macros
-+- Does it really works on Big Endian machines?
-+
-+Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and
-+Tom Li <biergaizi@member.fsf.org>.
-diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.c b/drivers/video/fbdev/sm712fb/sm712fb_accel.c
-new file mode 100644
-index 0000000..12fce1f
---- /dev/null
-+++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.c
-@@ -0,0 +1,246 @@
-+/*
-+ * Silicon Motion SM712 frame buffer device
-+ *
-+ * Copyright (C) 2006 Silicon Motion Technology Corp.
-+ * Authors: Ge Wang, gewang@siliconmotion.com
-+ * Boyod boyod.yang@siliconmotion.com.cn
-+ *
-+ * Copyright (C) 2009 Lemote, Inc.
-+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
-+ *
-+ * Copyright (C) 2011 Igalia, S.L.
-+ * Author: Javier M. Mellid <jmunhoz@igalia.com>
-+ *
-+ * Copyright (C) 2014 Tom Li.
-+ * Author: Tom Li (Yifeng Li) <biergaizi@member.fsf.org>
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive for
-+ * more details.
-+ *
-+ * Framebuffer driver for Silicon Motion SM712 chip
-+ */
-+
-+#include <linux/fb.h>
-+#include <linux/screen_info.h>
-+#include <linux/delay.h>
-+
-+#include "sm712fb_drv.h"
-+#include "sm712fb_accel.h"
-+
-+static inline u32 bytes_to_dword(const u8 *bytes, int length)
-+{
-+ u32 dword = 0;
-+
-+ switch (length) {
-+ case 4:
-+#ifdef __BIG_ENDIAN
-+ dword += bytes[3];
-+#else
-+ dword += bytes[3] << 24;
-+#endif
-+ case 3:
-+#ifdef __BIG_ENDIAN
-+ dword += bytes[2] << 8;
-+#else
-+ dword += bytes[2] << 16;
-+#endif
-+ case 2:
-+#ifdef __BIG_ENDIAN
-+ dword += bytes[1] << 16;
-+#else
-+ dword += bytes[1] << 8;
-+#endif
-+ case 1:
-+#ifdef __BIG_ENDIAN
-+ dword += bytes[0] << 24;
-+#else
-+ dword += bytes[0];
-+#endif
-+ }
-+ return dword;
-+}
-+
-+int sm712fb_init_accel(struct sm712fb_info *fb)
-+{
-+ u8 reg;
-+
-+ /* reset the 2D engine */
-+ sm712_write_seq(fb, 0x21, sm712_read_seq(fb, 0x21) & 0xf8);
-+ reg = sm712_read_seq(fb, 0x15);
-+ sm712_write_seq(fb, 0x15, reg | 0x30);
-+ sm712_write_seq(fb, 0x15, reg);
-+
-+ if (sm712fb_wait(fb) != 0)
-+ return -1;
-+
-+ sm712_write_dpr(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0));
-+
-+ /* same width for DPR_PITCH and DPR_SRC_WINDOW */
-+ sm712_write_dpr(fb, DPR_PITCH,
-+ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres));
-+ sm712_write_dpr(fb, DPR_SRC_WINDOW,
-+ DPR_COORDS(fb->fb.var.xres, fb->fb.var.xres));
-+
-+ sm712_write_dpr(fb, DPR_BYTE_BIT_MASK, 0xffffffff);
-+ sm712_write_dpr(fb, DPR_COLOR_COMPARE_MASK, 0);
-+ sm712_write_dpr(fb, DPR_COLOR_COMPARE, 0);
-+ sm712_write_dpr(fb, DPR_SRC_BASE, 0);
-+ sm712_write_dpr(fb, DPR_DST_BASE, 0);
-+ sm712_read_dpr(fb, DPR_DST_BASE);
-+
-+ return 0;
-+}
-+
-+int sm712fb_wait(struct sm712fb_info *fb)
-+{
-+ int i;
-+ u8 reg;
-+
-+ for (i = 0; i < 10000; i++) {
-+ reg = sm712_read_seq(fb, SCR_DE_STATUS);
-+ if ((reg & SCR_DE_STATUS_MASK) == SCR_DE_ENGINE_IDLE)
-+ return 0;
-+ udelay(1);
-+ }
-+ return -EBUSY;
-+}
-+
-+void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
-+{
-+ u32 width = rect->width, height = rect->height;
-+ u32 dx = rect->dx, dy = rect->dy;
-+ u32 color;
-+
-+ struct sm712fb_info *sfb = info->par;
-+
-+ if (unlikely(info->state != FBINFO_STATE_RUNNING))
-+ return;
-+ if ((rect->dx >= info->var.xres_virtual) ||
-+ (rect->dy >= info->var.yres_virtual))
-+ return;
-+
-+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
-+ info->fix.visual == FB_VISUAL_DIRECTCOLOR)
-+ color = ((u32 *) (info->pseudo_palette))[rect->color];
-+ else
-+ color = rect->color;
-+
-+ sm712_write_dpr(sfb, DPR_FG_COLOR, color);
-+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy));
-+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height));
-+ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE |
-+ (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) |
-+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT));
-+ sm712_read_dpr(sfb, DPR_DE_CTRL);
-+ sm712fb_wait(sfb);
-+}
-+
-+void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
-+{
-+ u32 sx = area->sx, sy = area->sy;
-+ u32 dx = area->dx, dy = area->dy;
-+ u32 height = area->height, width = area->width;
-+ u32 direction;
-+
-+ struct sm712fb_info *sfb = info->par;
-+
-+ if (unlikely(info->state != FBINFO_STATE_RUNNING))
-+ return;
-+ if ((sx >= info->var.xres_virtual) || (sy >= info->var.yres_virtual))
-+ return;
-+
-+ if (sy < dy || (sy == dy && sx <= dx)) {
-+ sx += width - 1;
-+ dx += width - 1;
-+ sy += height - 1;
-+ dy += height - 1;
-+ direction = DE_CTRL_RTOL;
-+ } else
-+ direction = 0;
-+
-+ sm712_write_dpr(sfb, DPR_SRC_COORDS, DPR_COORDS(sx, sy));
-+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy));
-+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height));
-+ sm712_write_dpr(sfb, DPR_DE_CTRL,
-+ DE_CTRL_START | DE_CTRL_ROP_ENABLE | direction |
-+ (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) |
-+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT));
-+ sm712_read_dpr(sfb, DPR_DE_CTRL);
-+ sm712fb_wait(sfb);
-+}
-+
-+void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image)
-+{
-+ u32 dx = image->dx, dy = image->dy;
-+ u32 width = image->width, height = image->height;
-+ u32 fg_color, bg_color;
-+
-+ struct sm712fb_info *sfb = info->par;
-+
-+ u32 imgidx = 0;
-+ u32 line = image->width >> 3;
-+
-+ int i, j;
-+ u32 total_bytes, total_dwords, remain_bytes;
-+
-+ if (unlikely(info->state != FBINFO_STATE_RUNNING))
-+ return;
-+ if ((image->dx >= info->var.xres_virtual) ||
-+ (image->dy >= info->var.yres_virtual))
-+ return;
-+
-+ if (unlikely(image->depth != 1)) {
-+ /* unsupported depth, fallback to draw Tux */
-+ cfb_imageblit(info, image);
-+ return;
-+ }
-+
-+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
-+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
-+ fg_color = ((u32 *) (info->pseudo_palette))[image->fg_color];
-+ bg_color = ((u32 *) (info->pseudo_palette))[image->bg_color];
-+ } else {
-+ fg_color = image->fg_color;
-+ bg_color = image->bg_color;
-+ }
-+
-+ /* total bytes we need to write */
-+ total_bytes = (width + 7) / 8;
-+
-+ /* split the bytes into dwords and remainder bytes */
-+ total_dwords = (total_bytes & ~3) / 4;
-+ remain_bytes = total_bytes & 3;
-+
-+ sm712_write_dpr(sfb, DPR_SRC_COORDS, 0);
-+ sm712_write_dpr(sfb, DPR_DST_COORDS, DPR_COORDS(dx, dy));
-+ sm712_write_dpr(sfb, DPR_SPAN_COORDS, DPR_COORDS(width, height));
-+ sm712_write_dpr(sfb, DPR_FG_COLOR, fg_color);
-+ sm712_write_dpr(sfb, DPR_BG_COLOR, bg_color);
-+
-+ sm712_write_dpr(sfb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE |
-+ (DE_CTRL_COMMAND_HOST_WRITE << DE_CTRL_COMMAND_SHIFT) |
-+ (DE_CTRL_HOST_MONO << DE_CTRL_HOST_SHIFT) |
-+ (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT));
-+
-+ for (i = 0; i < height; i++) {
-+ /* cast bytes data into dwords and write to the dataport */
-+ for (j = 0; j < total_dwords; j++) {
-+ sm712_write_dataport(sfb,
-+ bytes_to_dword(&image->
-+ data[imgidx] +
-+ j * 4, 4));
-+ }
-+
-+ if (remain_bytes) {
-+ sm712_write_dataport(sfb,
-+ bytes_to_dword(&image->
-+ data[imgidx] +
-+ (total_dwords * 4),
-+ remain_bytes));
-+ }
-+ imgidx += line;
-+ }
-+ sm712_read_dpr(sfb, DPR_DE_CTRL);
-+ sm712fb_wait(sfb);
-+}
-diff --git a/drivers/video/fbdev/sm712fb/sm712fb_accel.h b/drivers/video/fbdev/sm712fb/sm712fb_accel.h
-new file mode 100644
-index 0000000..6f79177
---- /dev/null
-+++ b/drivers/video/fbdev/sm712fb/sm712fb_accel.h
-@@ -0,0 +1,33 @@
-+/*
-+ * Silicon Motion SM712 frame buffer device
-+ *
-+ * Copyright (C) 2006 Silicon Motion Technology Corp.
-+ * Authors: Ge Wang, gewang@siliconmotion.com
-+ * Boyod boyod.yang@siliconmotion.com.cn
-+ *
-+ * Copyright (C) 2009 Lemote, Inc.
-+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
-+ *
-+ * Copyright (C) 2011 Igalia, S.L.
-+ * Author: Javier M. Mellid <jmunhoz@igalia.com>
-+ *
-+ * Copyright (C) 2014 Tom Li.
-+ * Author: Tom Li (Yifeng Li) <biergaizi@member.fsf.org>
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive for
-+ * more details.
-+ *
-+ * Framebuffer driver for Silicon Motion SM712 chip
-+ */
-+
-+#ifndef _SM712FB_ACCEL_H
-+#define _SM712FB_ACCEL_H
-+
-+int sm712fb_init_accel(struct sm712fb_info *fb);
-+int sm712fb_wait(struct sm712fb_info *fb);
-+void sm712fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
-+void sm712fb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
-+void sm712fb_imageblit(struct fb_info *info, const struct fb_image *image);
-+
-+#endif
-diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.c b/drivers/video/fbdev/sm712fb/sm712fb_drv.c
-new file mode 100644
-index 0000000..7f7cd4f
---- /dev/null
-+++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.c
-@@ -0,0 +1,1022 @@
-+/*
-+ * Silicon Motion SM712 frame buffer device
-+ *
-+ * Copyright (C) 2006 Silicon Motion Technology Corp.
-+ * Authors: Ge Wang, gewang@siliconmotion.com
-+ * Boyod boyod.yang@siliconmotion.com.cn
-+ *
-+ * Copyright (C) 2009 Lemote, Inc.
-+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
-+ *
-+ * Copyright (C) 2011 Igalia, S.L.
-+ * Author: Javier M. Mellid <jmunhoz@igalia.com>
-+ *
-+ * Copyright (C) 2014 Tom Li.
-+ * Author: Tom Li (Yifeng Li) <biergaizi@member.fsf.org>
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive for
-+ * more details.
-+ *
-+ * Framebuffer driver for Silicon Motion SM712 chip
-+ */
-+
-+#include <linux/io.h>
-+#include <linux/fb.h>
-+#include <linux/pci.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/uaccess.h>
-+#include <linux/module.h>
-+#include <linux/console.h>
-+#include <linux/screen_info.h>
-+
-+#ifdef CONFIG_PM
-+#include <linux/pm.h>
-+#endif
-+
-+#include "sm712fb_drv.h"
-+#include "sm712fb_accel.h"
-+#include "sm712fb_modedb.h"
-+
-+static struct fb_var_screeninfo sm712fb_var = {
-+ .xres = 1024,
-+ .yres = 600,
-+ .xres_virtual = 1024,
-+ .yres_virtual = 600,
-+ .bits_per_pixel = 16,
-+ .red = {16, 8, 0},
-+ .green = {8, 8, 0},
-+ .blue = {0, 8, 0},
-+ .activate = FB_ACTIVATE_NOW,
-+ .height = -1,
-+ .width = -1,
-+ .vmode = FB_VMODE_NONINTERLACED,
-+ .nonstd = 0,
-+ .accel_flags = FB_ACCELF_TEXT,
-+};
-+
-+static struct fb_fix_screeninfo sm712fb_fix = {
-+ .id = "smXXXfb",
-+ .type = FB_TYPE_PACKED_PIXELS,
-+ .visual = FB_VISUAL_TRUECOLOR,
-+ .line_length = 800 * 3,
-+ .accel = FB_ACCEL_SMI_LYNX,
-+ .type_aux = 0,
-+ .xpanstep = 0,
-+ .ypanstep = 0,
-+ .ywrapstep = 0,
-+};
-+
-+struct vesa_mode {
-+ char index[6];
-+ u16 lfb_width;
-+ u16 lfb_height;
-+ u16 lfb_depth;
-+};
-+
-+static bool accel = 1;
-+
-+static struct vesa_mode vesa_mode_table[] = {
-+ {"0x301", 640, 480, 8},
-+ {"0x303", 800, 600, 8},
-+ {"0x305", 1024, 768, 8},
-+ {"0x307", 1280, 1024, 8},
-+
-+ {"0x311", 640, 480, 16},
-+ {"0x314", 800, 600, 16},
-+ {"0x317", 1024, 768, 16},
-+ {"0x31A", 1280, 1024, 16},
-+
-+ {"0x312", 640, 480, 24},
-+ {"0x315", 800, 600, 24},
-+ {"0x318", 1024, 768, 24},
-+ {"0x31B", 1280, 1024, 24},
-+};
-+
-+struct screen_info sm712_scr_info;
-+
-+static int sm712fb_setup(char *options)
-+{
-+ char *this_opt;
-+
-+ if (!options || !*options)
-+ return 0;
-+
-+ while ((this_opt = strsep(&options, ",")) != NULL) {
-+ if (!*this_opt)
-+ continue;
-+
-+ if (!strcmp(this_opt, "accel:0"))
-+ accel = false;
-+ else if (!strcmp(this_opt, "accel:1"))
-+ accel = true;
-+ }
-+ return 0;
-+}
-+
-+/* process command line options, get vga parameter */
-+static int __init sm712_vga_setup(char *options)
-+{
-+ int i;
-+
-+ if (!options || !*options)
-+ return -EINVAL;
-+
-+ sm712_scr_info.lfb_width = 0;
-+ sm712_scr_info.lfb_height = 0;
-+ sm712_scr_info.lfb_depth = 0;
-+
-+ pr_debug("sm712_vga_setup = %s\n", options);
-+
-+ for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
-+ if (strstr(options, vesa_mode_table[i].index)) {
-+ sm712_scr_info.lfb_width = vesa_mode_table[i].lfb_width;
-+ sm712_scr_info.lfb_height =
-+ vesa_mode_table[i].lfb_height;
-+ sm712_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth;
-+ return 0;
-+ }
-+ }
-+
-+ return -1;
-+}
-+
-+__setup("vga=", sm712_vga_setup);
-+
-+static void sm712_setpalette(int regno, unsigned red, unsigned green,
-+ unsigned blue, struct fb_info *info)
-+{
-+ struct sm712fb_info *sfb = info->par;
-+
-+ /* set bit 5:4 = 01 (write LCD RAM only) */
-+ sm712_write_seq(sfb, 0x66, (sm712_read_seq(sfb, 0x66) & 0xC3) | 0x10);
-+
-+ sm712_writeb(sfb->mmio, DAC_REG, regno);
-+ sm712_writeb(sfb->mmio, DAC_VAL, red >> 10);
-+ sm712_writeb(sfb->mmio, DAC_VAL, green >> 10);
-+ sm712_writeb(sfb->mmio, DAC_VAL, blue >> 10);
-+}
-+
-+/* chan_to_field
-+ *
-+ * convert a colour value into a field position
-+ *
-+ * from pxafb.c
-+ */
-+
-+static inline unsigned int chan_to_field(unsigned int chan,
-+ struct fb_bitfield *bf)
-+{
-+ chan &= 0xffff;
-+ chan >>= 16 - bf->length;
-+ return chan << bf->offset;
-+}
-+
-+static int sm712_blank(int blank_mode, struct fb_info *info)
-+{
-+ struct sm712fb_info *sfb = info->par;
-+
-+ /* clear DPMS setting */
-+ switch (blank_mode) {
-+ case FB_BLANK_UNBLANK:
-+ /* Screen On: HSync: On, VSync : On */
-+ sm712_write_seq(sfb, 0x01,
-+ (sm712_read_seq(sfb, 0x01) & (~0x20)));
-+ sm712_write_seq(sfb, 0x6a, 0x16);
-+ sm712_write_seq(sfb, 0x6b, 0x02);
-+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) & 0x77));
-+ sm712_write_seq(sfb, 0x22,
-+ (sm712_read_seq(sfb, 0x22) & (~0x30)));
-+ sm712_write_seq(sfb, 0x23,
-+ (sm712_read_seq(sfb, 0x23) & (~0xc0)));
-+ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01));
-+ sm712_write_seq(sfb, 0x31, (sm712_read_seq(sfb, 0x31) | 0x03));
-+ break;
-+ case FB_BLANK_NORMAL:
-+ /* Screen Off: HSync: On, VSync : On Soft blank */
-+ sm712_write_seq(sfb, 0x01,
-+ (sm712_read_seq(sfb, 0x01) & (~0x20)));
-+ sm712_write_seq(sfb, 0x6a, 0x16);
-+ sm712_write_seq(sfb, 0x6b, 0x02);
-+ sm712_write_seq(sfb, 0x22,
-+ (sm712_read_seq(sfb, 0x22) & (~0x30)));
-+ sm712_write_seq(sfb, 0x23,
-+ (sm712_read_seq(sfb, 0x23) & (~0xc0)));
-+ sm712_write_seq(sfb, 0x24, (sm712_read_seq(sfb, 0x24) | 0x01));
-+ sm712_write_seq(sfb, 0x31,
-+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00));
-+ break;
-+ case FB_BLANK_VSYNC_SUSPEND:
-+ /* Screen On: HSync: On, VSync : Off */
-+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20));
-+ sm712_write_seq(sfb, 0x20,
-+ (sm712_read_seq(sfb, 0x20) & (~0xB0)));
-+ sm712_write_seq(sfb, 0x6a, 0x0c);
-+ sm712_write_seq(sfb, 0x6b, 0x02);
-+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88));
-+ sm712_write_seq(sfb, 0x22,
-+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x20));
-+ sm712_write_seq(sfb, 0x23,
-+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0x20));
-+ sm712_write_seq(sfb, 0x24,
-+ (sm712_read_seq(sfb, 0x24) & (~0x01)));
-+ sm712_write_seq(sfb, 0x31,
-+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00));
-+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80));
-+ break;
-+ case FB_BLANK_HSYNC_SUSPEND:
-+ /* Screen On: HSync: Off, VSync : On */
-+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20));
-+ sm712_write_seq(sfb, 0x20,
-+ (sm712_read_seq(sfb, 0x20) & (~0xB0)));
-+ sm712_write_seq(sfb, 0x6a, 0x0c);
-+ sm712_write_seq(sfb, 0x6b, 0x02);
-+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88));
-+ sm712_write_seq(sfb, 0x22,
-+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x10));
-+ sm712_write_seq(sfb, 0x23,
-+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8));
-+ sm712_write_seq(sfb, 0x24,
-+ (sm712_read_seq(sfb, 0x24) & (~0x01)));
-+ sm712_write_seq(sfb, 0x31,
-+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00));
-+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80));
-+ break;
-+ case FB_BLANK_POWERDOWN:
-+ /* Screen On: HSync: Off, VSync : Off */
-+ sm712_write_seq(sfb, 0x01, (sm712_read_seq(sfb, 0x01) | 0x20));
-+ sm712_write_seq(sfb, 0x20,
-+ (sm712_read_seq(sfb, 0x20) & (~0xB0)));
-+ sm712_write_seq(sfb, 0x6a, 0x5a);
-+ sm712_write_seq(sfb, 0x6b, 0x20);
-+ sm712_write_seq(sfb, 0x21, (sm712_read_seq(sfb, 0x21) | 0x88));
-+ sm712_write_seq(sfb, 0x22,
-+ ((sm712_read_seq(sfb, 0x22) & (~0x30)) | 0x30));
-+ sm712_write_seq(sfb, 0x23,
-+ ((sm712_read_seq(sfb, 0x23) & (~0xc0)) | 0xD8));
-+ sm712_write_seq(sfb, 0x24,
-+ (sm712_read_seq(sfb, 0x24) & (~0x01)));
-+ sm712_write_seq(sfb, 0x31,
-+ ((sm712_read_seq(sfb, 0x31) & (~0x07)) | 0x00));
-+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0x80));
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int sm712_setcolreg(unsigned regno, unsigned red, unsigned green,
-+ unsigned blue, unsigned trans, struct fb_info *info)
-+{
-+ struct sm712fb_info *sfb;
-+ u32 val;
-+
-+ sfb = info->par;
-+
-+ if (regno > 255)
-+ return 1;
-+
-+ switch (sfb->fb.fix.visual) {
-+ case FB_VISUAL_DIRECTCOLOR:
-+ case FB_VISUAL_TRUECOLOR:
-+ /*
-+ * 16/32 bit true-colour, use pseudo-palette for 16 base color
-+ */
-+ if (regno < 16) {
-+ if (sfb->fb.var.bits_per_pixel == 16) {
-+ u32 *pal = sfb->fb.pseudo_palette;
-+
-+ val = chan_to_field(red, &sfb->fb.var.red);
-+ val |= chan_to_field(green, &sfb->fb.var.green);
-+ val |= chan_to_field(blue, &sfb->fb.var.blue);
-+#ifdef __BIG_ENDIAN
-+ pal[regno] =
-+ ((red & 0xf800) >> 8) |
-+ ((green & 0xe000) >> 13) |
-+ ((green & 0x1c00) << 3) |
-+ ((blue & 0xf800) >> 3);
-+#else
-+ pal[regno] = val;
-+#endif
-+ } else {
-+ u32 *pal = sfb->fb.pseudo_palette;
-+
-+ val = chan_to_field(red, &sfb->fb.var.red);
-+ val |= chan_to_field(green, &sfb->fb.var.green);
-+ val |= chan_to_field(blue, &sfb->fb.var.blue);
-+#ifdef __BIG_ENDIAN
-+ val =
-+ (val & 0xff00ff00 >> 8) |
-+ (val & 0x00ff00ff << 8);
-+#endif
-+ pal[regno] = val;
-+ }
-+ }
-+ break;
-+
-+ case FB_VISUAL_PSEUDOCOLOR:
-+ /* color depth 8 bit */
-+ sm712_setpalette(regno, red, green, blue, info);
-+ break;
-+
-+ default:
-+ return 1; /* unknown type */
-+ }
-+
-+ return 0;
-+
-+}
-+
-+#ifdef __BIG_ENDIAN
-+static ssize_t sm712fb_read(struct fb_info *info, char __user *buf,
-+ size_t count, loff_t *ppos)
-+{
-+ unsigned long p = *ppos;
-+
-+ u32 *buffer, *dst;
-+ u32 __iomem *src;
-+ int c, i, cnt = 0, err = 0;
-+ unsigned long total_size;
-+
-+ if (!info || !info->screen_base)
-+ return -ENODEV;
-+
-+ if (info->state != FBINFO_STATE_RUNNING)
-+ return -EPERM;
-+
-+ total_size = info->screen_size;
-+
-+ if (total_size == 0)
-+ total_size = info->fix.smem_len;
-+
-+ if (p >= total_size)
-+ return 0;
-+
-+ if (count >= total_size)
-+ count = total_size;
-+
-+ if (count + p > total_size)
-+ count = total_size - p;
-+
-+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
-+ if (!buffer)
-+ return -ENOMEM;
-+
-+ src = (u32 __iomem *) (info->screen_base + p);
-+
-+ if (info->fbops->fb_sync)
-+ info->fbops->fb_sync(info);
-+
-+ while (count) {
-+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-+ dst = buffer;
-+ for (i = c >> 2; i--;) {
-+ *dst = fb_readl(src++);
-+ *dst =
-+ (*dst & 0xff00ff00 >> 8) | (*dst & 0x00ff00ff << 8);
-+ dst++;
-+ }
-+ if (c & 3) {
-+ u8 *dst8 = (u8 *) dst;
-+ u8 __iomem *src8 = (u8 __iomem *) src;
-+
-+ for (i = c & 3; i--;) {
-+ if (i & 1) {
-+ *dst8++ = fb_readb(++src8);
-+ } else {
-+ *dst8++ = fb_readb(--src8);
-+ src8 += 2;
-+ }
-+ }
-+ src = (u32 __iomem *) src8;
-+ }
-+
-+ if (copy_to_user(buf, buffer, c)) {
-+ err = -EFAULT;
-+ break;
-+ }
-+ *ppos += c;
-+ buf += c;
-+ cnt += c;
-+ count -= c;
-+ }
-+
-+ kfree(buffer);
-+
-+ return (err) ? err : cnt;
-+}
-+
-+static ssize_t
-+sm712fb_write(struct fb_info *info, const char __user *buf, size_t count,
-+ loff_t *ppos)
-+{
-+ unsigned long p = *ppos;
-+
-+ u32 *buffer, *src;
-+ u32 __iomem *dst;
-+ int c, i, cnt = 0, err = 0;
-+ unsigned long total_size;
-+
-+ if (!info || !info->screen_base)
-+ return -ENODEV;
-+
-+ if (info->state != FBINFO_STATE_RUNNING)
-+ return -EPERM;
-+
-+ total_size = info->screen_size;
-+
-+ if (total_size == 0)
-+ total_size = info->fix.smem_len;
-+
-+ if (p > total_size)
-+ return -EFBIG;
-+
-+ if (count > total_size) {
-+ err = -EFBIG;
-+ count = total_size;
-+ }
-+
-+ if (count + p > total_size) {
-+ if (!err)
-+ err = -ENOSPC;
-+
-+ count = total_size - p;
-+ }
-+
-+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
-+ if (!buffer)
-+ return -ENOMEM;
-+
-+ dst = (u32 __iomem *) (info->screen_base + p);
-+
-+ if (info->fbops->fb_sync)
-+ info->fbops->fb_sync(info);
-+
-+ while (count) {
-+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-+ src = buffer;
-+
-+ if (copy_from_user(src, buf, c)) {
-+ err = -EFAULT;
-+ break;
-+ }
-+
-+ for (i = c >> 2; i--;) {
-+ fb_writel((*src & 0xff00ff00 >> 8) |
-+ (*src & 0x00ff00ff << 8), dst++);
-+ src++;
-+ }
-+ if (c & 3) {
-+ u8 *src8 = (u8 *) src;
-+ u8 __iomem *dst8 = (u8 __iomem *) dst;
-+
-+ for (i = c & 3; i--;) {
-+ if (i & 1) {
-+ fb_writeb(*src8++, ++dst8);
-+ } else {
-+ fb_writeb(*src8++, --dst8);
-+ dst8 += 2;
-+ }
-+ }
-+ dst = (u32 __iomem *) dst8;
-+ }
-+
-+ *ppos += c;
-+ buf += c;
-+ cnt += c;
-+ count -= c;
-+ }
-+
-+ kfree(buffer);
-+
-+ return (cnt) ? cnt : err;
-+}
-+#endif /* ! __BIG_ENDIAN */
-+
-+static void sm712_set_timing(struct sm712fb_info *sfb)
-+{
-+ int i = 0, j = 0;
-+ u32 m_nScreenStride;
-+
-+ dev_dbg(&sfb->pdev->dev,
-+ "sfb->width=%d sfb->height=%d "
-+ "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
-+ sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
-+
-+ for (j = 0; j < numVGAModes; j++) {
-+ if (VGAMode[j].mmSizeX != sfb->width ||
-+ VGAMode[j].mmSizeY != sfb->height ||
-+ VGAMode[j].bpp != sfb->fb.var.bits_per_pixel ||
-+ VGAMode[j].hz != sfb->hz) {
-+ continue;
-+ }
-+
-+ dev_dbg(&sfb->pdev->dev,
-+ "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d "
-+ "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n",
-+ VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
-+ VGAMode[j].bpp, VGAMode[j].hz);
-+
-+ dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j);
-+
-+ sm712_writeb(sfb->mmio, 0x3c6, 0x0);
-+
-+ sm712_write_seq(sfb, 0, 0x1);
-+
-+ sm712_writeb(sfb->mmio, 0x3c2, VGAMode[j].Init_MISC);
-+
-+ /* init SEQ register SR00 - SR04 */
-+ for (i = 0; i < SR00_SR04_SIZE; i++)
-+ sm712_write_seq(sfb, i, VGAMode[j].Init_SR00_SR04[i]);
-+
-+ /* init SEQ register SR10 - SR24 */
-+ for (i = 0; i < SR10_SR24_SIZE; i++)
-+ sm712_write_seq(sfb, i + 0x10,
-+ VGAMode[j].Init_SR10_SR24[i]);
-+
-+ /* init SEQ register SR30 - SR75 */
-+ for (i = 0; i < SR30_SR75_SIZE; i++)
-+ if ((i + 0x30) != 0x62 &&
-+ (i + 0x30) != 0x6a && (i + 0x30) != 0x6b)
-+ sm712_write_seq(sfb, i + 0x30,
-+ VGAMode[j].Init_SR30_SR75[i]);
-+
-+ /* init SEQ register SR80 - SR93 */
-+ for (i = 0; i < SR80_SR93_SIZE; i++)
-+ sm712_write_seq(sfb, i + 0x80,
-+ VGAMode[j].Init_SR80_SR93[i]);
-+
-+ /* init SEQ register SRA0 - SRAF */
-+ for (i = 0; i < SRA0_SRAF_SIZE; i++)
-+ sm712_write_seq(sfb, i + 0xa0,
-+ VGAMode[j].Init_SRA0_SRAF[i]);
-+
-+ /* init Graphic register GR00 - GR08 */
-+ for (i = 0; i < GR00_GR08_SIZE; i++)
-+ sm712_write_grph(sfb, i, VGAMode[j].Init_GR00_GR08[i]);
-+
-+ /* init Attribute register AR00 - AR14 */
-+ for (i = 0; i < AR00_AR14_SIZE; i++)
-+ sm712_write_attr(sfb, i, VGAMode[j].Init_AR00_AR14[i]);
-+
-+ /* init CRTC register CR00 - CR18 */
-+ for (i = 0; i < CR00_CR18_SIZE; i++)
-+ sm712_write_crtc(sfb, i, VGAMode[j].Init_CR00_CR18[i]);
-+
-+ /* init CRTC register CR30 - CR4D */
-+ for (i = 0; i < CR30_CR4D_SIZE; i++)
-+ sm712_write_crtc(sfb, i + 0x30,
-+ VGAMode[j].Init_CR30_CR4D[i]);
-+
-+ /* init CRTC register CR90 - CRA7 */
-+ for (i = 0; i < CR90_CRA7_SIZE; i++)
-+ sm712_write_crtc(sfb, i + 0x90,
-+ VGAMode[j].Init_CR90_CRA7[i]);
-+ }
-+ sm712_writeb(sfb->mmio, 0x3c2, 0x67);
-+
-+ /* set VPR registers */
-+ sm712_writel(sfb->vpr, 0x0C, 0x0);
-+ sm712_writel(sfb->vpr, 0x40, 0x0);
-+
-+ /* set data width */
-+ m_nScreenStride = (sfb->width * sfb->fb.var.bits_per_pixel) / 64;
-+ switch (sfb->fb.var.bits_per_pixel) {
-+ case 8:
-+ sm712_writel(sfb->vpr, 0x0, 0x0);
-+ break;
-+ case 16:
-+ sm712_writel(sfb->vpr, 0x0, 0x00020000);
-+ break;
-+ case 24:
-+ sm712_writel(sfb->vpr, 0x0, 0x00040000);
-+ break;
-+ case 32:
-+ sm712_writel(sfb->vpr, 0x0, 0x00030000);
-+ break;
-+ }
-+ sm712_writel(sfb->vpr, 0x10,
-+ (u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride));
-+}
-+
-+static void sm712fb_setmode(struct sm712fb_info *sfb)
-+{
-+ switch (sfb->fb.var.bits_per_pixel) {
-+ case 32:
-+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-+ sfb->fb.fix.line_length = sfb->fb.var.xres * 4;
-+ sfb->fb.var.red.length = 8;
-+ sfb->fb.var.green.length = 8;
-+ sfb->fb.var.blue.length = 8;
-+ sfb->fb.var.red.offset = 16;
-+ sfb->fb.var.green.offset = 8;
-+ sfb->fb.var.blue.offset = 0;
-+ break;
-+ case 24:
-+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-+ sfb->fb.fix.line_length = sfb->fb.var.xres * 3;
-+ sfb->fb.var.red.length = 8;
-+ sfb->fb.var.green.length = 8;
-+ sfb->fb.var.blue.length = 8;
-+ sfb->fb.var.red.offset = 16;
-+ sfb->fb.var.green.offset = 8;
-+ sfb->fb.var.blue.offset = 0;
-+ break;
-+ case 8:
-+ sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
-+ sfb->fb.fix.line_length = sfb->fb.var.xres;
-+ sfb->fb.var.red.length = 3;
-+ sfb->fb.var.green.length = 3;
-+ sfb->fb.var.blue.length = 2;
-+ sfb->fb.var.red.offset = 5;
-+ sfb->fb.var.green.offset = 2;
-+ sfb->fb.var.blue.offset = 0;
-+ break;
-+ case 16:
-+ default:
-+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-+ sfb->fb.fix.line_length = sfb->fb.var.xres * 2;
-+ sfb->fb.var.red.length = 5;
-+ sfb->fb.var.green.length = 6;
-+ sfb->fb.var.blue.length = 5;
-+ sfb->fb.var.red.offset = 11;
-+ sfb->fb.var.green.offset = 5;
-+ sfb->fb.var.blue.offset = 0;
-+ break;
-+ }
-+
-+ sfb->width = sfb->fb.var.xres;
-+ sfb->height = sfb->fb.var.yres;
-+ sfb->hz = 60;
-+ sm712_set_timing(sfb);
-+}
-+
-+static int sm712_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-+{
-+ /* sanity checks */
-+ if (var->xres_virtual < var->xres)
-+ var->xres_virtual = var->xres;
-+
-+ if (var->yres_virtual < var->yres)
-+ var->yres_virtual = var->yres;
-+
-+ /* set valid default bpp */
-+ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) &&
-+ (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
-+ var->bits_per_pixel = 16;
-+
-+ return 0;
-+}
-+
-+static int sm712_set_par(struct fb_info *info)
-+{
-+ sm712fb_setmode(info->par);
-+
-+ return 0;
-+}
-+
-+static struct fb_ops sm712fb_ops = {
-+ .owner = THIS_MODULE,
-+ .fb_check_var = sm712_check_var,
-+ .fb_set_par = sm712_set_par,
-+ .fb_setcolreg = sm712_setcolreg,
-+ .fb_blank = sm712_blank,
-+ .fb_fillrect = cfb_fillrect,
-+ .fb_imageblit = cfb_imageblit,
-+ .fb_copyarea = cfb_copyarea,
-+#ifdef __BIG_ENDIAN
-+ .fb_read = sm712fb_read,
-+ .fb_write = sm712fb_write,
-+#endif
-+};
-+
-+/*
-+ * alloc struct sm712fb_info and assign default values
-+ */
-+static struct sm712fb_info *sm712_fb_info_new(struct pci_dev *pdev)
-+{
-+ struct sm712fb_info *sfb;
-+
-+ sfb = kzalloc(sizeof(*sfb), GFP_KERNEL);
-+
-+ if (!sfb)
-+ return NULL;
-+
-+ sfb->pdev = pdev;
-+
-+ sfb->fb.flags = FBINFO_FLAG_DEFAULT;
-+ sfb->fb.fbops = &sm712fb_ops;
-+ sfb->fb.fix = sm712fb_fix;
-+ sfb->fb.var = sm712fb_var;
-+ sfb->fb.pseudo_palette = sfb->colreg;
-+ sfb->fb.par = sfb;
-+ sfb->accel = accel;
-+
-+ return sfb;
-+}
-+
-+/*
-+ * free struct sm712fb_info
-+ */
-+static void sm712_fb_info_free(struct sm712fb_info *sfb)
-+{
-+ kfree(sfb);
-+}
-+
-+/*
-+ * Map in the screen memory
-+ */
-+
-+static int sm712_map_smem(struct sm712fb_info *sfb,
-+ struct pci_dev *pdev, u_long smem_len)
-+{
-+
-+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
-+
-+#ifdef __BIG_ENDIAN
-+ if (sfb->fb.var.bits_per_pixel == 32)
-+ sfb->fb.fix.smem_start += 0x800000;
-+#endif
-+
-+ sfb->fb.fix.smem_len = smem_len;
-+
-+ sfb->fb.screen_base = sfb->lfb;
-+
-+ if (!sfb->fb.screen_base) {
-+ dev_err(&pdev->dev,
-+ "%s: unable to map screen memory\n", sfb->fb.fix.id);
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * Unmap in the screen memory
-+ *
-+ */
-+static void sm712_unmap_smem(struct sm712fb_info *sfb)
-+{
-+ if (sfb && sfb->fb.screen_base) {
-+ iounmap(sfb->fb.screen_base);
-+ sfb->fb.screen_base = NULL;
-+ sfb->lfb = NULL;
-+ }
-+}
-+
-+static inline void sm712_init_hw(struct sm712fb_info *sfb)
-+{
-+ /* enable linear memory mode and packed pixel format */
-+ outb_p(0x18, 0x3c4);
-+ outb_p(0x11, 0x3c5);
-+
-+ /* set MCLK = 14.31818 * (0x16 / 0x2) */
-+ sm712_write_seq(sfb, 0x6a, 0x16);
-+ sm712_write_seq(sfb, 0x6b, 0x02);
-+ sm712_write_seq(sfb, 0x62, 0x3e);
-+
-+ /* enable PCI burst */
-+ sm712_write_seq(sfb, 0x17, 0x20);
-+
-+#ifdef __BIG_ENDIAN
-+ /* enable word swap */
-+ if (sfb->fb.var.bits_per_pixel == 32)
-+ sm712_write_seq(sfb, 0x17, 0x30);
-+#endif
-+
-+ if (!sfb->accel) {
-+ dev_info(&sfb->pdev->dev, "2d acceleration was disabled by user.\n");
-+ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE;
-+ return;
-+ }
-+
-+ if (sm712fb_init_accel(sfb) < 0) {
-+ dev_info(&sfb->pdev->dev, "failed to enable 2d accleration.\n");
-+ sfb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_NONE;
-+ return;
-+ } else {
-+ sm712fb_ops.fb_fillrect = sm712fb_fillrect;
-+ sm712fb_ops.fb_copyarea = sm712fb_copyarea;
-+ sm712fb_ops.fb_imageblit = sm712fb_imageblit;
-+ sfb->fb.flags |= FBINFO_HWACCEL_COPYAREA |
-+ FBINFO_HWACCEL_FILLRECT |
-+ FBINFO_HWACCEL_IMAGEBLIT |
-+ FBINFO_READS_FAST;
-+ dev_info(&sfb->pdev->dev, "sm712fb: enable 2d acceleration.\n");
-+ }
-+}
-+
-+static int sm712fb_pci_probe(struct pci_dev *pdev,
-+ const struct pci_device_id *ent)
-+{
-+ struct sm712fb_info *sfb;
-+ int err;
-+ unsigned long mmio_base;
-+
-+#ifndef MODULE
-+ char *option = NULL;
-+
-+ if (!fb_get_options("sm712fb", &option))
-+ sm712fb_setup(option);
-+#endif
-+
-+ dev_info(&pdev->dev, "Silicon Motion display driver.");
-+
-+ err = pci_enable_device(pdev); /* enable SMTC chip */
-+ if (err)
-+ return err;
-+
-+ sprintf(sm712fb_fix.id, "sm712fb");
-+
-+ sfb = sm712_fb_info_new(pdev);
-+
-+ if (!sfb) {
-+ err = -ENOMEM;
-+ goto free_fail;
-+ }
-+
-+ sfb->chip_id = ent->device;
-+
-+ pci_set_drvdata(pdev, sfb);
-+
-+ /* get mode parameter from sm712_scr_info */
-+ if (sm712_scr_info.lfb_width != 0) {
-+ sfb->fb.var.xres = sm712_scr_info.lfb_width;
-+ sfb->fb.var.yres = sm712_scr_info.lfb_height;
-+ sfb->fb.var.bits_per_pixel = sm712_scr_info.lfb_depth;
-+ } else {
-+ /* default resolution 1024x600 16bit mode */
-+ sfb->fb.var.xres = SM712_DEFAULT_XRES;
-+ sfb->fb.var.yres = SM712_DEFAULT_YRES;
-+ sfb->fb.var.bits_per_pixel = SM712_DEFAULT_BPP;
-+ }
-+
-+#ifdef __BIG_ENDIAN
-+ if (sfb->fb.var.bits_per_pixel == 24)
-+ sfb->fb.var.bits_per_pixel = (sm712_scr_info.lfb_depth = 32);
-+#endif
-+
-+ /* Map address and memory detection */
-+ mmio_base = pci_resource_start(pdev, 0);
-+ pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
-+
-+ if (sfb->chip_id != 0x712) {
-+ dev_err(&pdev->dev,
-+ "No valid Silicon Motion display chip was detected!");
-+
-+ goto fb_fail;
-+ }
-+
-+ sfb->fb.fix.mmio_start = mmio_base + SM712_REG_BASE;
-+ sfb->fb.fix.mmio_len = SM712_REG_SIZE;
-+#ifdef __BIG_ENDIAN
-+ sfb->lfb = ioremap(mmio_base, 0x00c00000);
-+#else
-+ sfb->lfb = ioremap(mmio_base, 0x00800000);
-+#endif
-+ sfb->mmio = sfb->lfb + SM712_MMIO_BASE;
-+ sfb->dpr = sfb->lfb + SM712_DPR_BASE;
-+ sfb->vpr = sfb->lfb + SM712_VPR_BASE;
-+ sfb->dataport = sfb->lfb + SM712_DATAPORT_BASE;
-+#ifdef __BIG_ENDIAN
-+ if (sfb->fb.var.bits_per_pixel == 32) {
-+ sfb->lfb += 0x800000;
-+ dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb);
-+ }
-+#endif
-+ if (!sfb->mmio) {
-+ dev_err(&pdev->dev,
-+ "%s: unable to map memory mapped IO!", sfb->fb.fix.id);
-+ err = -ENOMEM;
-+ goto fb_fail;
-+ }
-+
-+ sm712_init_hw(sfb);
-+
-+ /* can support 32 bpp */
-+ if (15 == sfb->fb.var.bits_per_pixel)
-+ sfb->fb.var.bits_per_pixel = 16;
-+
-+ sfb->fb.var.xres_virtual = sfb->fb.var.xres;
-+ sfb->fb.var.yres_virtual = sfb->fb.var.yres;
-+ err = sm712_map_smem(sfb, pdev, SM712_VRAM_SIZE);
-+ if (err)
-+ goto fail;
-+
-+ sm712fb_setmode(sfb);
-+
-+ err = register_framebuffer(&sfb->fb);
-+ if (err < 0)
-+ goto fail;
-+
-+ dev_info(&pdev->dev,
-+ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
-+ sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres,
-+ sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);
-+
-+ return 0;
-+
-+fail:
-+ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
-+
-+ sm712_unmap_smem(sfb);
-+fb_fail:
-+ sm712_fb_info_free(sfb);
-+free_fail:
-+ pci_disable_device(pdev);
-+
-+ return err;
-+}
-+
-+/*
-+ * 0x712 (LynxEM+)
-+ */
-+static const struct pci_device_id sm712fb_pci_table[] = {
-+ {PCI_DEVICE(0x126f, 0x712),},
-+ {0,}
-+};
-+
-+static void sm712fb_pci_remove(struct pci_dev *pdev)
-+{
-+ struct sm712fb_info *sfb;
-+
-+ sfb = pci_get_drvdata(pdev);
-+ sm712_unmap_smem(sfb);
-+ unregister_framebuffer(&sfb->fb);
-+ sm712_fb_info_free(sfb);
-+}
-+
-+#ifdef CONFIG_PM
-+static int sm712fb_pci_suspend(struct device *device)
-+{
-+ struct pci_dev *pdev = to_pci_dev(device);
-+ struct sm712fb_info *sfb;
-+
-+ sfb = pci_get_drvdata(pdev);
-+
-+ /* set the hw in sleep mode use external clock and self memory refresh
-+ * so that we can turn off internal PLLs later on
-+ */
-+ sm712_write_seq(sfb, 0x20, (sm712_read_seq(sfb, 0x20) | 0xc0));
-+ sm712_write_seq(sfb, 0x69, (sm712_read_seq(sfb, 0x69) & 0xf7));
-+
-+ console_lock();
-+ fb_set_suspend(&sfb->fb, 1);
-+ console_unlock();
-+
-+ /* additionally turn off all function blocks including internal PLLs */
-+ sm712_write_seq(sfb, 0x21, 0xff);
-+
-+ return 0;
-+}
-+
-+static int sm712fb_pci_resume(struct device *device)
-+{
-+ struct pci_dev *pdev = to_pci_dev(device);
-+ struct sm712fb_info *sfb;
-+
-+ sfb = pci_get_drvdata(pdev);
-+
-+ /* reinit hardware */
-+ sm712_init_hw(sfb);
-+
-+ sm712_write_seq(sfb, 0x34, (sm712_read_seq(sfb, 0x34) | 0xc0));
-+ sm712_write_seq(sfb, 0x33, ((sm712_read_seq(sfb, 0x33) | 0x08) & 0xfb));
-+
-+ sm712fb_setmode(sfb);
-+
-+ console_lock();
-+ fb_set_suspend(&sfb->fb, 0);
-+ console_unlock();
-+
-+ return 0;
-+}
-+
-+static SIMPLE_DEV_PM_OPS(sm712_pm_ops, sm712fb_pci_suspend, sm712fb_pci_resume);
-+#define SM712_PM_OPS (&sm712_pm_ops)
-+
-+#else /* !CONFIG_PM */
-+
-+#define SM712_PM_OPS NULL
-+
-+#endif /* !CONFIG_PM */
-+
-+static struct pci_driver sm712fb_driver = {
-+ .name = "sm712fb",
-+ .id_table = sm712fb_pci_table,
-+ .probe = sm712fb_pci_probe,
-+ .remove = sm712fb_pci_remove,
-+ .driver.pm = SM712_PM_OPS,
-+};
-+
-+module_pci_driver(sm712fb_driver);
-+
-+module_param(accel, bool, S_IRUGO);
-+MODULE_PARM_DESC(accel, "Enable or disable 2D Acceleration");
-+
-+MODULE_AUTHOR("Siliconmotion ");
-+MODULE_DESCRIPTION("Framebuffer driver for Silicon Motion SM712 Graphic Cards");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/video/fbdev/sm712fb/sm712fb_drv.h b/drivers/video/fbdev/sm712fb/sm712fb_drv.h
-new file mode 100644
-index 0000000..bf81bff
---- /dev/null
-+++ b/drivers/video/fbdev/sm712fb/sm712fb_drv.h
-@@ -0,0 +1,130 @@
-+/*
-+ * Silicon Motion SM712 frame buffer device
-+ *
-+ * Copyright (C) 2006 Silicon Motion Technology Corp.
-+ * Authors: Ge Wang, gewang@siliconmotion.com
-+ * Boyod boyod.yang@siliconmotion.com.cn
-+ *
-+ * Copyright (C) 2009 Lemote, Inc.
-+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
-+ *
-+ * Copyright (C) 2011 Igalia, S.L.
-+ * Author: Javier M. Mellid <jmunhoz@igalia.com>
-+ *
-+ * Copyright (C) 2014 Tom Li.
-+ * Author: Tom Li (Yifeng Li) <biergaizi@member.fsf.org>
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive for
-+ * more details.
-+ *
-+ * Framebuffer driver for Silicon Motion SM712 chip
-+ */
-+
-+#ifndef _SM712FB_DRV_H
-+#define _SM712FB_DRV_H
-+
-+/*
-+* Private structure
-+*/
-+struct sm712fb_info {
-+ struct pci_dev *pdev;
-+ struct fb_info fb;
-+ u16 chip_id;
-+ u8 chip_rev_id;
-+
-+ void __iomem *lfb; /* linear frame buffer, the base address */
-+
-+ void __iomem *dpr; /* drawing processor control regs */
-+ void __iomem *vpr; /* video processor control regs */
-+ void __iomem *cpr; /* capture processor control regs */
-+ void __iomem *mmio; /* memory map IO port */
-+ void __iomem *dataport; /* 2d drawing engine data port */
-+
-+ u_int width;
-+ u_int height;
-+ u_int hz;
-+
-+ u32 colreg[17];
-+
-+ bool accel;
-+};
-+
-+/* constants for registers operations */
-+
-+#include "sm712fb_io.h"
-+
-+#define FB_ACCEL_SMI_LYNX 88
-+
-+#define SM712_DEFAULT_XRES 1024
-+#define SM712_DEFAULT_YRES 600
-+#define SM712_DEFAULT_BPP 16
-+
-+#define SM712_VRAM_SIZE 0x00400000
-+
-+#define SM712_REG_BASE 0x00400000
-+#define SM712_REG_SIZE 0x00400000
-+
-+#define SM712_MMIO_BASE 0x00700000
-+
-+#define SM712_DPR_BASE 0x00408000
-+#define SM712_DPR_SIZE (0x6C + 1)
-+
-+#define DPR_COORDS(x, y) (((x) << 16) | (y))
-+
-+#define DPR_SRC_COORDS 0x00
-+#define DPR_DST_COORDS 0x04
-+#define DPR_SPAN_COORDS 0x08
-+#define DPR_DE_CTRL 0x0c
-+#define DPR_PITCH 0x10
-+#define DPR_FG_COLOR 0x14
-+#define DPR_BG_COLOR 0x18
-+#define DPR_STRETCH 0x1c
-+#define DPR_COLOR_COMPARE 0x20
-+#define DPR_COLOR_COMPARE_MASK 0x24
-+#define DPR_BYTE_BIT_MASK 0x28
-+#define DPR_CROP_TOPLEFT_COORDS 0x2c
-+#define DPR_CROP_BOTRIGHT_COORDS 0x30
-+#define DPR_SRC_WINDOW 0x3c
-+#define DPR_SRC_BASE 0x40
-+#define DPR_DST_BASE 0x44
-+
-+#define DE_CTRL_START 0x80000000
-+#define DE_CTRL_RTOL 0x08000000
-+#define DE_CTRL_COMMAND_MASK 0x001f0000
-+#define DE_CTRL_COMMAND_SHIFT 16
-+#define DE_CTRL_COMMAND_BITBLT 0x00
-+#define DE_CTRL_COMMAND_SOLIDFILL 0x01
-+#define DE_CTRL_COMMAND_HOST_WRITE 0x08
-+#define DE_CTRL_ROP_ENABLE 0x00008000
-+#define DE_CTRL_ROP_MASK 0x000000ff
-+#define DE_CTRL_ROP_SHIFT 0
-+#define DE_CTRL_ROP_SRC 0x0c
-+
-+#define DE_CTRL_HOST_SHIFT 22
-+#define DE_CTRL_HOST_MONO 1
-+
-+#define SCR_DE_STATUS 0x16
-+#define SCR_DE_STATUS_MASK 0x18
-+#define SCR_DE_ENGINE_IDLE 0x10
-+
-+#define SM712_VPR_BASE 0x0040c000
-+#define SM712_VPR_SIZE (0x44 + 1)
-+
-+#define SM712_DATAPORT_BASE 0x00400000
-+
-+#define SR00_SR04_SIZE (0x04 - 0x00 + 1)
-+#define SR10_SR24_SIZE (0x24 - 0x10 + 1)
-+#define SR30_SR75_SIZE (0x75 - 0x30 + 1)
-+#define SR80_SR93_SIZE (0x93 - 0x80 + 1)
-+#define SRA0_SRAF_SIZE (0xAF - 0xA0 + 1)
-+#define GR00_GR08_SIZE (0x08 - 0x00 + 1)
-+#define AR00_AR14_SIZE (0x14 - 0x00 + 1)
-+#define CR00_CR18_SIZE (0x18 - 0x00 + 1)
-+#define CR30_CR4D_SIZE (0x4D - 0x30 + 1)
-+#define CR90_CRA7_SIZE (0xA7 - 0x90 + 1)
-+
-+#define DAC_REG (0x3c8)
-+#define DAC_VAL (0x3c9)
-+
-+#endif
-diff --git a/drivers/video/fbdev/sm712fb/sm712fb_io.h b/drivers/video/fbdev/sm712fb/sm712fb_io.h
-new file mode 100644
-index 0000000..93346a0
---- /dev/null
-+++ b/drivers/video/fbdev/sm712fb/sm712fb_io.h
-@@ -0,0 +1,90 @@
-+/*
-+ * Silicon Motion SM712 frame buffer device
-+ *
-+ * Copyright (C) 2006 Silicon Motion Technology Corp.
-+ * Authors: Ge Wang, gewang@siliconmotion.com
-+ * Boyod boyod.yang@siliconmotion.com.cn
-+ *
-+ * Copyright (C) 2009 Lemote, Inc.
-+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
-+ *
-+ * Copyright (C) 2011 Igalia, S.L.
-+ * Author: Javier M. Mellid <jmunhoz@igalia.com>
-+ *
-+ * Copyright (C) 2014 Tom Li.
-+ * Author: Tom Li (Yifeng Li) <biergaizi@member.fsf.org>
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive for
-+ * more details.
-+ *
-+ */
-+
-+
-+#define sm712_writeb(base, reg, dat) writeb(dat, base + reg)
-+#define sm712_writew(base, reg, dat) writew(dat, base + reg)
-+#define sm712_writel(base, reg, dat) writel(dat, base + reg)
-+
-+#define sm712_readb(base, reg) readb(base + reg)
-+#define sm712_readw(base, reg) readw(base + reg)
-+#define sm712_readl(base, reg) readl(base + reg)
-+
-+
-+static inline void sm712_write_crtc(struct sm712fb_info *fb, u8 reg, u8 val)
-+{
-+ sm712_writeb(fb->mmio, 0x3d4, reg);
-+ sm712_writeb(fb->mmio, 0x3d5, val);
-+}
-+
-+static inline u8 sm712_read_crtc(struct sm712fb_info *fb, u8 reg)
-+{
-+ sm712_writeb(fb->mmio, 0x3d4, reg);
-+ return sm712_readb(fb->mmio, 0x3d5);
-+}
-+
-+static inline void sm712_write_grph(struct sm712fb_info *fb, u8 reg, u8 val)
-+{
-+ sm712_writeb(fb->mmio, 0x3ce, reg);
-+ sm712_writeb(fb->mmio, 0x3cf, val);
-+}
-+
-+static inline u8 sm712_read_grph(struct sm712fb_info *fb, u8 reg)
-+{
-+ sm712_writeb(fb->mmio, 0x3ce, reg);
-+ return sm712_readb(fb->mmio, 0x3cf);
-+}
-+
-+static inline void sm712_write_attr(struct sm712fb_info *fb, u8 reg, u8 val)
-+{
-+ sm712_readb(fb->mmio, 0x3da);
-+ sm712_writeb(fb->mmio, 0x3c0, reg);
-+ sm712_readb(fb->mmio, 0x3c1);
-+ sm712_writeb(fb->mmio, 0x3c0, val);
-+}
-+
-+static inline void sm712_write_seq(struct sm712fb_info *fb, u8 reg, u8 val)
-+{
-+ sm712_writeb(fb->mmio, 0x3c4, reg);
-+ sm712_writeb(fb->mmio, 0x3c5, val);
-+}
-+
-+static inline u8 sm712_read_seq(struct sm712fb_info *fb, u8 reg)
-+{
-+ sm712_writeb(fb->mmio, 0x3c4, reg);
-+ return sm712_readb(fb->mmio, 0x3c5);
-+}
-+
-+static inline u32 sm712_read_dpr(struct sm712fb_info *fb, u8 reg)
-+{
-+ return sm712_readl(fb->dpr, reg);
-+}
-+
-+static inline void sm712_write_dpr(struct sm712fb_info *fb, u8 reg, u32 val)
-+{
-+ sm712_writel(fb->dpr, reg, val);
-+}
-+
-+static inline void sm712_write_dataport(struct sm712fb_info *fb, u32 val)
-+{
-+ sm712_writel(fb->dataport, 0, val);
-+}
-diff --git a/drivers/video/fbdev/sm712fb/sm712fb_modedb.h b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h
-new file mode 100644
-index 0000000..16ee7e3
---- /dev/null
-+++ b/drivers/video/fbdev/sm712fb/sm712fb_modedb.h
-@@ -0,0 +1,682 @@
-+/* The next structure holds all information relevant for a specific video mode.
-+ */
-+
-+struct ModeInit {
-+ int mmSizeX;
-+ int mmSizeY;
-+ int bpp;
-+ int hz;
-+ unsigned char Init_MISC;
-+ unsigned char Init_SR00_SR04[SR00_SR04_SIZE];
-+ unsigned char Init_SR10_SR24[SR10_SR24_SIZE];
-+ unsigned char Init_SR30_SR75[SR30_SR75_SIZE];
-+ unsigned char Init_SR80_SR93[SR80_SR93_SIZE];
-+ unsigned char Init_SRA0_SRAF[SRA0_SRAF_SIZE];
-+ unsigned char Init_GR00_GR08[GR00_GR08_SIZE];
-+ unsigned char Init_AR00_AR14[AR00_AR14_SIZE];
-+ unsigned char Init_CR00_CR18[CR00_CR18_SIZE];
-+ unsigned char Init_CR30_CR4D[CR30_CR4D_SIZE];
-+ unsigned char Init_CR90_CRA7[CR90_CRA7_SIZE];
-+};
-+
-+/**********************************************************************
-+ SM712 Mode table.
-+ **********************************************************************/
-+struct ModeInit VGAMode[] = {
-+ {
-+ /* mode#0: 640 x 480 16Bpp 60Hz */
-+ 640, 480, 16, 60,
-+ /* Init_MISC */
-+ 0xE3,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x30, 0x02, 0x01, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
-+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
-+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
-+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
-+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
-+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
-+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
-+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
-+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
-+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
-+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
-+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
-+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
-+ },
-+ },
-+ {
-+ /* mode#1: 640 x 480 24Bpp 60Hz */
-+ 640, 480, 24, 60,
-+ /* Init_MISC */
-+ 0xE3,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x30, 0x02, 0x01, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
-+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
-+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
-+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
-+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
-+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
-+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
-+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
-+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
-+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
-+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
-+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
-+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
-+ },
-+ },
-+ {
-+ /* mode#0: 640 x 480 32Bpp 60Hz */
-+ 640, 480, 32, 60,
-+ /* Init_MISC */
-+ 0xE3,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x30, 0x02, 0x01, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
-+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
-+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
-+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
-+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
-+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
-+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
-+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
-+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
-+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
-+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
-+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
-+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
-+ },
-+ },
-+
-+ { /* mode#2: 800 x 600 16Bpp 60Hz */
-+ 800, 600, 16, 60,
-+ /* Init_MISC */
-+ 0x2B,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x30, 0x02, 0x01, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
-+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
-+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
-+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
-+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
-+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
-+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
-+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
-+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
-+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
-+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
-+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
-+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
-+ },
-+ },
-+ { /* mode#3: 800 x 600 24Bpp 60Hz */
-+ 800, 600, 24, 60,
-+ 0x2B,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x30, 0x02, 0x01, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
-+ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
-+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
-+ 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
-+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
-+ 0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
-+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
-+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
-+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
-+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
-+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
-+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
-+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
-+ },
-+ },
-+ { /* mode#7: 800 x 600 32Bpp 60Hz */
-+ 800, 600, 32, 60,
-+ /* Init_MISC */
-+ 0x2B,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
-+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x30, 0x02, 0x01, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
-+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
-+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
-+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
-+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
-+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
-+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
-+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
-+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
-+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
-+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
-+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
-+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
-+ },
-+ },
-+ /* We use 1024x768 table to light 1024x600 panel for lemote */
-+ { /* mode#4: 1024 x 600 16Bpp 60Hz */
-+ 1024, 600, 16, 60,
-+ /* Init_MISC */
-+ 0xEB,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
-+ 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x30, 0x02, 0x00, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
-+ 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
-+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
-+ 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
-+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
-+ 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
-+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
-+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
-+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
-+ 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
-+ 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
-+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
-+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
-+ },
-+ },
-+ { /* mode#5: 1024 x 768 24Bpp 60Hz */
-+ 1024, 768, 24, 60,
-+ /* Init_MISC */
-+ 0xEB,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
-+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x30, 0x02, 0x01, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
-+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
-+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
-+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
-+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
-+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
-+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
-+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
-+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
-+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
-+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
-+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
-+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
-+ },
-+ },
-+ { /* mode#4: 1024 x 768 32Bpp 60Hz */
-+ 1024, 768, 32, 60,
-+ /* Init_MISC */
-+ 0xEB,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
-+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x32, 0x02, 0x01, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
-+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
-+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
-+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
-+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
-+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
-+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
-+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
-+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
-+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
-+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
-+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
-+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
-+ },
-+ },
-+ { /* mode#6: 320 x 240 16Bpp 60Hz */
-+ 320, 240, 16, 60,
-+ /* Init_MISC */
-+ 0xEB,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
-+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x32, 0x02, 0x01, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
-+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
-+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
-+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
-+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
-+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
-+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
-+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
-+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
-+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
-+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
-+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
-+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
-+ },
-+ },
-+
-+ { /* mode#8: 320 x 240 32Bpp 60Hz */
-+ 320, 240, 32, 60,
-+ /* Init_MISC */
-+ 0xEB,
-+ { /* Init_SR0_SR4 */
-+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
-+ },
-+ { /* Init_SR10_SR24 */
-+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
-+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xC4, 0x32, 0x02, 0x01, 0x01,
-+ },
-+ { /* Init_SR30_SR75 */
-+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
-+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
-+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
-+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
-+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
-+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
-+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
-+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
-+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
-+ },
-+ { /* Init_SR80_SR93 */
-+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
-+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
-+ 0x00, 0x00, 0x00, 0x00,
-+ },
-+ { /* Init_SRA0_SRAF */
-+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
-+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
-+ },
-+ { /* Init_GR00_GR08 */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
-+ 0xFF,
-+ },
-+ { /* Init_AR00_AR14 */
-+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-+ 0x41, 0x00, 0x0F, 0x00, 0x00,
-+ },
-+ { /* Init_CR00_CR18 */
-+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
-+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
-+ 0xFF,
-+ },
-+ { /* Init_CR30_CR4D */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
-+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
-+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
-+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
-+ },
-+ { /* Init_CR90_CRA7 */
-+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
-+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
-+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
-+ },
-+ },
-+};
-+
-+#define numVGAModes ARRAY_SIZE(VGAMode)
-diff --git a/drivers/video/output.c b/drivers/video/output.c
-new file mode 100644
-index 0000000..1446c49
---- /dev/null
-+++ b/drivers/video/output.c
-@@ -0,0 +1,133 @@
-+/*
-+ * output.c - Display Output Switch driver
-+ *
-+ * Copyright (C) 2006 Luming Yu <luming.yu@intel.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.
-+ *
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-+ */
-+#include <linux/module.h>
-+#include <linux/video_output.h>
-+#include <linux/slab.h>
-+#include <linux/err.h>
-+#include <linux/ctype.h>
-+
-+
-+MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
-+
-+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ ssize_t ret_size = 0;
-+ struct output_device *od = to_output_device(dev);
-+ if (od->props)
-+ ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od));
-+ return ret_size;
-+}
-+
-+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf,size_t count)
-+{
-+ char *endp;
-+ struct output_device *od = to_output_device(dev);
-+ int request_state = simple_strtoul(buf,&endp,0);
-+ size_t size = endp - buf;
-+
-+ if (isspace(*endp))
-+ size++;
-+ if (size != count)
-+ return -EINVAL;
-+
-+ if (od->props) {
-+ od->request_state = request_state;
-+ od->props->set_state(od);
-+ }
-+ return count;
-+}
-+static DEVICE_ATTR_RW(state);
-+
-+static void video_output_release(struct device *dev)
-+{
-+ struct output_device *od = to_output_device(dev);
-+ kfree(od);
-+}
-+
-+static struct attribute *video_output_attrs[] = {
-+ &dev_attr_state.attr,
-+ NULL,
-+};
-+ATTRIBUTE_GROUPS(video_output);
-+
-+static struct class video_output_class = {
-+ .name = "video_output",
-+ .dev_release = video_output_release,
-+ .dev_groups = video_output_groups,
-+};
-+
-+struct output_device *video_output_register(const char *name,
-+ struct device *dev,
-+ void *devdata,
-+ struct output_properties *op)
-+{
-+ struct output_device *new_dev;
-+ int ret_code = 0;
-+
-+ new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL);
-+ if (!new_dev) {
-+ ret_code = -ENOMEM;
-+ goto error_return;
-+ }
-+ new_dev->props = op;
-+ new_dev->dev.class = &video_output_class;
-+ new_dev->dev.parent = dev;
-+ dev_set_name(&new_dev->dev, "%s", name);
-+ dev_set_drvdata(&new_dev->dev, devdata);
-+ ret_code = device_register(&new_dev->dev);
-+ if (ret_code) {
-+ kfree(new_dev);
-+ goto error_return;
-+ }
-+ return new_dev;
-+
-+error_return:
-+ return ERR_PTR(ret_code);
-+}
-+EXPORT_SYMBOL(video_output_register);
-+
-+void video_output_unregister(struct output_device *dev)
-+{
-+ if (!dev)
-+ return;
-+ device_unregister(&dev->dev);
-+}
-+EXPORT_SYMBOL(video_output_unregister);
-+
-+static void __exit video_output_class_exit(void)
-+{
-+ class_unregister(&video_output_class);
-+}
-+
-+static int __init video_output_class_init(void)
-+{
-+ return class_register(&video_output_class);
-+}
-+
-+postcore_initcall(video_output_class_init);
-+module_exit(video_output_class_exit);
-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/include/linux/video_output.h b/include/linux/video_output.h
-new file mode 100644
-index 0000000..ed5cdeb
---- /dev/null
-+++ b/include/linux/video_output.h
-@@ -0,0 +1,57 @@
-+/*
-+ *
-+ * Copyright (C) 2006 Luming Yu <luming.yu@intel.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.
-+ *
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-+ */
-+#ifndef _LINUX_VIDEO_OUTPUT_H
-+#define _LINUX_VIDEO_OUTPUT_H
-+#include <linux/device.h>
-+#include <linux/err.h>
-+struct output_device;
-+struct output_properties {
-+ int (*set_state)(struct output_device *);
-+ int (*get_status)(struct output_device *);
-+};
-+struct output_device {
-+ int request_state;
-+ struct output_properties *props;
-+ struct device dev;
-+};
-+#define to_output_device(obj) container_of(obj, struct output_device, dev)
-+#if defined(CONFIG_VIDEO_OUTPUT_CONTROL) || defined(CONFIG_VIDEO_OUTPUT_CONTROL_MODULE)
-+struct output_device *video_output_register(const char *name,
-+ struct device *dev,
-+ void *devdata,
-+ struct output_properties *op);
-+void video_output_unregister(struct output_device *dev);
-+#else
-+static struct output_device *video_output_register(const char *name,
-+ struct device *dev,
-+ void *devdata,
-+ struct output_properties *op)
-+{
-+ return ERR_PTR(-ENODEV);
-+}
-+static void video_output_unregister(struct output_device *dev)
-+{
-+ return;
-+}
-+#endif
-+#endif
-diff --git a/init/calibrate.c b/init/calibrate.c
-index ce635dc..10e775d 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
-@@ -291,6 +293,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) {
-@@ -301,6 +304,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 fa7cd79..616abb5 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 826470d..9e6dc30 100755
---- a/scripts/recordmcount.pl
-+++ b/scripts/recordmcount.pl
-@@ -309,14 +309,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
-@@ -328,19 +347,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