Merge tag 'v3.10.88' of http://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable into linux-3.10-stable
This is the 3.10.88 stable release
diff --git a/Makefile b/Makefile
index e94ce68..175685c 100644
--- a/Makefile
+++ b/Makefile
@@ -241,8 +241,8 @@
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
# Decide whether to build built-in, modular, or both.
# Normally, just do built-in.
@@ -575,7 +575,7 @@
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,)
else
-KBUILD_CFLAGS += -O2
+KBUILD_CFLAGS += -O3
endif
include $(srctree)/arch/$(SRCARCH)/Makefile
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index e53e2b4..86c2834 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -270,7 +270,7 @@
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.
@@ -932,6 +932,60 @@
config CSRC_R4K
bool
+config MIPS_USER_RDTSC
+ bool "Emulate rdtsc instruction for MIPS"
+ depends on CSRC_R4K && MIPS32_O32
+ default n
+ help
+ This optoin enables the Emulated rdtsc support for MIPS, which allows
+ the user-space applications read the R4k count directly. Currently,
+ this only support the CONFIG_MIPS32_O32 and R4K, but future, we may
+ add support for scall64-{n32,64}.S and scall32-32.S and for the count
+ registers provided by the other MIPS variants.
+
+ This emulation based on the syscall instruction, by default, the
+ syscall is encoded as 0x0000000c, except the 0xc, the other parts can
+ be encoded as specific meaning. when a syscall instruction is issued,
+ through checking the encoding of the instruction, when the encoding
+ is the generic 0x000000c, we do the generic syscall work, if
+ something other is encoded in, we can do relevant things, except for
+ the light-weight things, such as read a register. herein, we read the
+ count register whenever there is something encoded in the syscall
+ instruction. In the future, we may be possible to abstract more
+ light-weight & frequently-used operations and add a
+ sys_call_table-like table to store the entries of some light-weight
+ operations and encode 1,2,3... into the syscall instruction and jump
+ to respective entry for diffrent numbers, as a result, we get
+ fast-syscall and which may speed up the user-space applications and
+ even be possibly improve the determinism.
+
+ *Example*
+
+ #include <stdio.h>
+ #include <stdint.h>
+
+ /*
+ * Currently, our return value is only 32bit, In the long run,
+ * this should be uint64_t, just like clock_gettime(), but it
+ * should has high precision/low overhead than clock_gettime()
+ */
+ uint32_t rdtsc(void)
+ {
+ /*
+ * Linux will store the value of the count register into
+ * the v0 register, which is just the return value of this
+ * function, so, please ignore the compiling warning.
+ */
+ __asm__ __volatile__ (
+ "syscall 1\n"
+ :::"$2");
+ }
+
+ int main(int argc, char *argv[])
+ {
+ return printf("cycles: %u\n", rdtsc());
+ }
+
config CSRC_GIC
bool
@@ -1537,6 +1591,15 @@
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
@@ -2131,7 +2194,7 @@
config ARCH_FLATMEM_ENABLE
def_bool y
- depends on !NUMA && !CPU_LOONGSON2
+ depends on !NUMA && !(CPU_LOONGSON2 && HIBERNATION)
config ARCH_DISCONTIGMEM_ENABLE
bool
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 5a43aa0..96f8852 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -7,9 +7,9 @@
source "lib/Kconfig.debug"
config EARLY_PRINTK
- bool "Early printk" if EXPERT
+ bool "Early printk"
depends on SYS_HAS_EARLY_PRINTK
- default y
+ default n
help
This option enables special console drivers which allow the kernel
to print messages very early in the bootup process.
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index dd58a04..a24c24b 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -260,18 +260,19 @@
# Other need ECOFF, so we build a 32-bit ELF binary for them which we then
# convert to ECOFF using elf2ecoff.
#
+quiet_cmd_32 = OBJCOPY $@
+ cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
vmlinux.32: vmlinux
- $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
-
-
-#obj-$(CONFIG_KPROBES) += kprobes.o
+ $(call cmd,32)
#
# The 64-bit ELF tools are pretty broken so at this time we generate 64-bit
# ELF files from 32-bit files by conversion.
#
+quiet_cmd_64 = OBJCOPY $@
+ cmd_64 = $(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@
vmlinux.64: vmlinux
- $(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@
+ $(call cmd,64)
all: $(all-y)
diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c
index 79fe32d..5eb36f3 100644
--- a/arch/mips/bcm63xx/cpu.c
+++ b/arch/mips/bcm63xx/cpu.c
@@ -293,7 +293,7 @@
/* soc registers location depends on cpu type */
chipid_reg = 0;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_BMIPS3300:
if ((read_c0_prid() & 0xff00) != PRID_IMP_BMIPS3300_ALT)
__cpu_name[cpu] = "Broadcom BCM6338";
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
index bbaa1d4..87af880 100644
--- a/arch/mips/boot/compressed/Makefile
+++ b/arch/mips/boot/compressed/Makefile
@@ -28,9 +28,10 @@
targets := head.o decompress.o dbg.o uart-16550.o uart-alchemy.o
# decompressor objects (linked with vmlinuz)
-vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o
+vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.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
@@ -71,9 +72,18 @@
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
@@ -86,14 +96,14 @@
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 $@
@@ -102,11 +112,11 @@
$(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 d498a1f..4d9810f 100644
--- a/arch/mips/boot/compressed/decompress.c
+++ b/arch/mips/boot/compressed/decompress.c
@@ -28,8 +28,13 @@
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 8e6b07c..99ca111 100644
--- a/arch/mips/boot/compressed/ld.script
+++ b/arch/mips/boot/compressed/ld.script
@@ -46,5 +46,6 @@
*(.reginfo)
*(.comment)
*(.note)
+ *(.gnu.attributes)
}
}
diff --git a/arch/mips/configs/fuloong2e_defconfig b/arch/mips/configs/fuloong2e_defconfig
index e5b73de..1e02d0b 100644
--- a/arch/mips/configs/fuloong2e_defconfig
+++ b/arch/mips/configs/fuloong2e_defconfig
@@ -12,7 +12,6 @@
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_NAMESPACES=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
@@ -222,7 +221,8 @@
CONFIG_REISERFS_FS=m
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
-CONFIG_FUSE_FS=y
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
@@ -260,9 +260,9 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=y
# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_DEBUG_FS=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_EARLY_PRINTK is not set
CONFIG_CRYPTO_FIPS=y
CONFIG_CRYPTO_AUTHENC=m
CONFIG_CRYPTO_CCM=m
diff --git a/arch/mips/configs/gdium_minimal_defconfig b/arch/mips/configs/gdium_minimal_defconfig
new file mode 100644
index 0000000..595b414
--- /dev/null
+++ b/arch/mips/configs/gdium_minimal_defconfig
@@ -0,0 +1,125 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_DEXXON_GDIUM=y
+CONFIG_64BIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139TOO=y
+CONFIG_R8169=y
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_MOUSE_PS2_ALPS is not set
+# CONFIG_MOUSE_PS2_LOGIPS2PP is not set
+# CONFIG_MOUSE_PS2_TRACKPOINT is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_GPIO=y
+CONFIG_SENSORS_LM75=y
+CONFIG_MFD_SM501=y
+CONFIG_MFD_SM501_GPIO=y
+CONFIG_FB=y
+CONFIG_FB_SIS=y
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_SM501=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_ZEROPLUS_FF=y
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_M41T80=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_FB_SM7XX=y
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/mips/configs/gdium_small_defconfig b/arch/mips/configs/gdium_small_defconfig
new file mode 100644
index 0000000..8027d5d
--- /dev/null
+++ b/arch/mips/configs/gdium_small_defconfig
@@ -0,0 +1,149 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_DEXXON_GDIUM=y
+CONFIG_64BIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_PM=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_STD_PARTITION="/dev/sda4"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_LOONGSON2_CPUFREQ=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_DEFAULT_PS is not set
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_LIB80211=y
+CONFIG_MAC80211=y
+CONFIG_RFKILL=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_MISC_DEVICES=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_SATA_PMP is not set
+CONFIG_PATA_AMD=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139TOO=y
+CONFIG_R8169=y
+# CONFIG_NETDEV_10000 is not set
+CONFIG_RT2X00=m
+CONFIG_RT61PCI=m
+CONFIG_INPUT_FF_MEMLESS=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_MOUSE_PS2=m
+# CONFIG_MOUSE_PS2_ALPS is not set
+# CONFIG_MOUSE_PS2_LOGIPS2PP is not set
+# CONFIG_MOUSE_PS2_TRACKPOINT is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_GPIO=y
+CONFIG_HWMON=m
+CONFIG_SENSORS_LM75=m
+CONFIG_MFD_SM501=y
+CONFIG_MFD_SM501_GPIO=y
+CONFIG_FB=y
+CONFIG_FB_SIS=y
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_SM501=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=m
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_CS5535AUDIO=m
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_HID_GDIUM=y
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_M41T80=y
+CONFIG_RTC_DRV_M41T80_WDT=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_FB_SM7XX=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FANOTIFY=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_EARLY_PRINTK is not set
diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig
index 343bebc..ef8b4d13 100644
--- a/arch/mips/configs/lemote2f_defconfig
+++ b/arch/mips/configs/lemote2f_defconfig
@@ -1,27 +1,27 @@
CONFIG_MACH_LOONGSON=y
CONFIG_LEMOTE_MACH2F=y
-CONFIG_CS5536_MFGPT=y
CONFIG_64BIT=y
+CONFIG_KSM=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
-CONFIG_KEXEC=y
-# CONFIG_SECCOMP is not set
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_AUDIT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
-CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_SCHED_AUTOGROUP=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_RD_BZIP2=y
-CONFIG_RD_LZMA=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
@@ -34,20 +34,17 @@
CONFIG_MIPS32_COMPAT=y
CONFIG_MIPS32_O32=y
CONFIG_MIPS32_N32=y
-CONFIG_PM=y
CONFIG_HIBERNATION=y
-CONFIG_PM_STD_PARTITION="/dev/hda3"
+CONFIG_PM_STD_PARTITION="/dev/sda3"
CONFIG_PM_RUNTIME=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_DEBUG=y
-CONFIG_CPU_FREQ_STAT=m
CONFIG_CPU_FREQ_STAT_DETAILS=y
-CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=m
-CONFIG_CPU_FREQ_GOV_USERSPACE=m
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_LOONGSON2_CPUFREQ=m
-CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=m
@@ -59,7 +56,6 @@
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
@@ -79,12 +75,249 @@
CONFIG_IPV6_SUBTREES=y
CONFIG_NETWORK_SECMARK=y
CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_IP_DCCP=m
+CONFIG_IP_SCTP=m
+CONFIG_RDS=m
+CONFIG_RDS_TCP=m
+CONFIG_TIPC=m
+CONFIG_TIPC_ADVANCED=y
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
-CONFIG_IPX=m
+CONFIG_ATALK=m
CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_PKTGEN=m
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_DEV=m
+CONFIG_CAN_CALC_BITTIMING=y
+CONFIG_CAN_SJA1000=m
+CONFIG_CAN_SJA1000_ISA=m
+CONFIG_CAN_SJA1000_PLATFORM=m
+CONFIG_CAN_EMS_PCI=m
+CONFIG_CAN_KVASER_PCI=m
+CONFIG_CAN_PLX_PCI=m
+CONFIG_CAN_EMS_USB=m
+CONFIG_CAN_ESD_USB2=m
+CONFIG_IRDA=m
+CONFIG_IRLAN=m
+CONFIG_IRCOMM=m
+CONFIG_IRTTY_SIR=m
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_TOIM3232_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+CONFIG_ACT200L_DONGLE=m
+CONFIG_KINGSUN_DONGLE=m
+CONFIG_KSDAZZLE_DONGLE=m
+CONFIG_KS959_DONGLE=m
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_VLSI_FIR=m
+CONFIG_MCS_FIR=m
CONFIG_BT=m
CONFIG_BT_L2CAP=y
CONFIG_BT_SCO=y
@@ -95,30 +328,114 @@
CONFIG_BT_BNEP_PROTO_FILTER=y
CONFIG_BT_HIDP=m
CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
CONFIG_BT_HCIBFUSB=m
CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+CONFIG_BT_MRVL_SDIO=m
+CONFIG_BT_ATH3K=m
CONFIG_CFG80211=m
CONFIG_LIB80211=m
CONFIG_LIB80211_DEBUG=y
CONFIG_MAC80211=m
-CONFIG_MAC80211_LEDS=y
+CONFIG_WIMAX=m
CONFIG_RFKILL=m
-CONFIG_RFKILL_INPUT=y
+CONFIG_CAIF=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_TASK_IOCTL=y
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_AMD74XX=y
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
+CONFIG_MISC_DEVICES=y
+CONFIG_EEPROM_AT24=m
+CONFIG_EEPROM_LEGACY=m
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=m
+CONFIG_CHR_DEV_SCH=m
CONFIG_SCSI_MULTI_LUN=y
-# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_FC_TGT_ATTRS=y
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SCSI_SRP_TGT_ATTRS=y
+CONFIG_ISCSI_TCP=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_BE2ISCSI=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+CONFIG_SCSI_AIC94XX=m
+# CONFIG_AIC94XX_DEBUG is not set
+CONFIG_SCSI_MVSAS=m
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_MPT2SAS=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_FCOE=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_LPFC=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_SRP=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_DH=m
+CONFIG_SCSI_DH_RDAC=m
+CONFIG_SCSI_DH_HP_SW=m
+CONFIG_SCSI_DH_EMC=m
+CONFIG_SCSI_DH_ALUA=m
+CONFIG_SCSI_OSD_INITIATOR=m
+CONFIG_SCSI_OSD_ULD=m
+CONFIG_ATA=y
+CONFIG_SATA_AHCI=m
+CONFIG_SATA_INIC162X=m
+CONFIG_SATA_SIL24=m
+CONFIG_PDC_ADMA=m
+CONFIG_SATA_QSTOR=m
+CONFIG_SATA_SX4=m
+CONFIG_ATA_PIIX=m
+CONFIG_SATA_MV=m
+CONFIG_SATA_NV=m
+CONFIG_SATA_PROMISE=m
+CONFIG_SATA_SIL=y
+CONFIG_SATA_SIS=m
+CONFIG_SATA_SVW=m
+CONFIG_SATA_ULI=m
+CONFIG_SATA_VIA=m
+CONFIG_SATA_VITESSE=m
+CONFIG_PATA_ARTOP=m
+CONFIG_PATA_ATP867X=m
+CONFIG_PATA_CMD64X=m
+CONFIG_PATA_CS5536=y
+CONFIG_PATA_IT821X=m
+CONFIG_PATA_JMICRON=m
+CONFIG_PATA_MARVELL=m
+CONFIG_PATA_RDC=m
+CONFIG_PATA_SCH=m
+CONFIG_PATA_TOSHIBA=m
+CONFIG_ATA_GENERIC=m
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
@@ -129,7 +446,6 @@
CONFIG_MD_MULTIPATH=m
CONFIG_MD_FAULTY=m
CONFIG_BLK_DEV_DM=m
-CONFIG_DM_DEBUG=y
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
@@ -140,55 +456,192 @@
CONFIG_DM_MULTIPATH_ST=m
CONFIG_DM_DELAY=m
CONFIG_DM_UEVENT=y
-CONFIG_NETDEVICES=y
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=m
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SAS=m
+CONFIG_FUSION_MAX_SGE=40
+CONFIG_FUSION_CTL=m
CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
CONFIG_TUN=m
CONFIG_VETH=m
+CONFIG_MII=y
CONFIG_NET_ETHERNET=y
CONFIG_NET_PCI=y
-CONFIG_8139TOO=y
-# CONFIG_8139TOO_PIO is not set
-CONFIG_R8169=y
-CONFIG_R8169_VLAN=y
-# CONFIG_NETDEV_10000 is not set
-CONFIG_USB_USBNET=m
+CONFIG_8139TOO=m
+CONFIG_R8169=m
+CONFIG_AT76C50X_USB=m
+CONFIG_USB_ZD1201=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_RTL8187B=m
+CONFIG_ATH_COMMON=m
+CONFIG_AR9170_USB=m
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT35XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_ZD1211RW=m
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_WAN=y
+CONFIG_LANMEDIA=m
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=m
+CONFIG_HDLC_RAW_ETH=m
+CONFIG_HDLC_CISCO=m
+CONFIG_HDLC_FR=m
+CONFIG_HDLC_PPP=m
+CONFIG_PCI200SYN=m
+CONFIG_WANXL=m
+CONFIG_PC300TOO=m
+CONFIG_N2=m
+CONFIG_C101=m
+CONFIG_FARSYNC=m
+CONFIG_DSCC4=m
+CONFIG_DLCI=m
+CONFIG_SDLA=m
+CONFIG_ATM_DUMMY=m
+CONFIG_ATM_TCP=m
+CONFIG_ATM_LANAI=m
+CONFIG_ATM_ENI=m
+CONFIG_ATM_ENI_DEBUG=y
+CONFIG_CAIF_TTY=m
+CONFIG_CAIF_SPI_SLAVE=m
+CONFIG_PPP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+CONFIG_PPPOL2TP=m
+CONFIG_SLIP=m
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_NET_FC=y
CONFIG_NETCONSOLE=m
-CONFIG_NETCONSOLE_DYNAMIC=y
-CONFIG_INPUT_POLLDEV=m
+CONFIG_NETPOLL_TRAP=y
+CONFIG_VMXNET3=m
+CONFIG_PHONE=m
+CONFIG_PHONE_IXJ=m
CONFIG_INPUT_EVDEV=y
-# CONFIG_MOUSE_PS2_ALPS is not set
-# CONFIG_MOUSE_PS2_LOGIPS2PP is not set
-# CONFIG_MOUSE_PS2_TRACKPOINT is not set
+CONFIG_KEYBOARD_LKKBD=m
+CONFIG_KEYBOARD_NEWTON=m
+CONFIG_KEYBOARD_OPENCORES=m
+CONFIG_KEYBOARD_STOWAWAY=m
+CONFIG_KEYBOARD_SUNKBD=m
+CONFIG_KEYBOARD_XTKBD=m
CONFIG_MOUSE_APPLETOUCH=m
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_MOUSE_BCM5974=m
+CONFIG_INPUT_TABLET=y
+CONFIG_TABLET_USB_ACECAD=m
+CONFIG_TABLET_USB_AIPTEK=m
+CONFIG_TABLET_USB_GTCO=m
+CONFIG_TABLET_USB_KBTAB=m
+CONFIG_TABLET_USB_WACOM=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_AD7879=m
+CONFIG_TOUCHSCREEN_DYNAPRO=m
+CONFIG_TOUCHSCREEN_HAMPSHIRE=m
+CONFIG_TOUCHSCREEN_FUJITSU=m
+CONFIG_TOUCHSCREEN_GUNZE=m
+CONFIG_TOUCHSCREEN_ELO=m
+CONFIG_TOUCHSCREEN_WACOM_W8001=m
+CONFIG_TOUCHSCREEN_MTOUCH=m
+CONFIG_TOUCHSCREEN_INEXIO=m
+CONFIG_TOUCHSCREEN_MK712=m
+CONFIG_TOUCHSCREEN_HTCPEN=m
+CONFIG_TOUCHSCREEN_PENMOUNT=m
+CONFIG_TOUCHSCREEN_TOUCHRIGHT=m
+CONFIG_TOUCHSCREEN_TOUCHWIN=m
+CONFIG_TOUCHSCREEN_WM97XX=m
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_TOUCHIT213=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_ATI_REMOTE=m
+CONFIG_INPUT_ATI_REMOTE2=m
+CONFIG_INPUT_KEYSPAN_REMOTE=m
+CONFIG_INPUT_YEALINK=m
+CONFIG_INPUT_CM109=m
+CONFIG_INPUT_ADXL34X=m
+CONFIG_LEGACY_PTY_COUNT=16
+CONFIG_NOZOMI=m
+CONFIG_N_GSM=m
CONFIG_SERIAL_8250=m
-# CONFIG_SERIAL_8250_PCI is not set
CONFIG_SERIAL_8250_NR_UARTS=16
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_FOURPORT=y
-CONFIG_LEGACY_PTY_COUNT=16
CONFIG_HW_RANDOM=y
CONFIG_RTC=y
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MUX=m
+CONFIG_I2C_MUX_PCA954x=m
+CONFIG_I2C_OCORES=m
+CONFIG_I2C_PARPORT_LIGHT=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_SCx200_ACB=m
+CONFIG_SPI=y
+CONFIG_W1=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2433_CRC=y
+CONFIG_W1_SLAVE_DS2760=m
+CONFIG_W1_SLAVE_BQ27000=m
CONFIG_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_USBPCWATCHDOG=m
CONFIG_MEDIA_SUPPORT=m
CONFIG_VIDEO_DEV=m
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_DVB_CORE=m
CONFIG_VIDEO_VIVI=m
CONFIG_USB_VIDEO_CLASS=m
CONFIG_USB_M5602=m
CONFIG_USB_STV06XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_GSPCA_BENQ=m
CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
CONFIG_USB_GSPCA_ETOMS=m
CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
CONFIG_USB_GSPCA_MARS=m
CONFIG_USB_GSPCA_MR97310A=m
CONFIG_USB_GSPCA_OV519=m
CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SN9C2028=m
CONFIG_USB_GSPCA_SN9C20X=m
CONFIG_USB_GSPCA_SONIXB=m
CONFIG_USB_GSPCA_SONIXJ=m
@@ -198,30 +651,72 @@
CONFIG_USB_GSPCA_SPCA506=m
CONFIG_USB_GSPCA_SPCA508=m
CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
CONFIG_USB_GSPCA_SQ905=m
CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STV0680=m
CONFIG_USB_GSPCA_SUNPLUS=m
CONFIG_USB_GSPCA_T613=m
CONFIG_USB_GSPCA_TV8532=m
CONFIG_USB_GSPCA_VC032X=m
CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_PVRUSB2_DEBUGIFC=y
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_ALSA=m
+CONFIG_VIDEO_USBVISION=m
CONFIG_USB_ET61X251=m
CONFIG_USB_SN9C102=m
+CONFIG_USB_PWC=m
CONFIG_USB_ZR364XX=m
CONFIG_USB_STKWEBCAM=m
CONFIG_USB_S2255=m
-# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_USB_DSBR=m
+CONFIG_USB_MR800=m
+CONFIG_DVB_USB=m
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_AF9015=m
+CONFIG_DVB_USB_CE6230=m
+CONFIG_DVB_USB_FRIIO=m
+CONFIG_DVB_USB_EC168=m
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
-CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
CONFIG_FB_SIS=y
CONFIG_FB_SIS_300=y
CONFIG_FB_SIS_315=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_FB_UDL=m
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_GENERIC=m
# CONFIG_VGA_CONSOLE is not set
@@ -238,8 +733,6 @@
CONFIG_FONT_SUN12x22=y
CONFIG_FONT_10x18=y
CONFIG_LOGO=y
-# CONFIG_LOGO_LINUX_MONO is not set
-# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_SOUND=m
CONFIG_SND=m
CONFIG_SND_SEQUENCER=m
@@ -255,30 +748,18 @@
CONFIG_SND_AC97_POWER_SAVE=y
CONFIG_SND_AC97_POWER_SAVE_DEFAULT=10
CONFIG_SND_CS5535AUDIO=m
-# CONFIG_SND_MIPS is not set
CONFIG_SND_USB_AUDIO=m
CONFIG_SND_USB_CAIAQ=m
CONFIG_SND_USB_CAIAQ_INPUT=y
CONFIG_HIDRAW=y
+CONFIG_USB_HID=m
CONFIG_USB_HIDDEV=y
-CONFIG_HID_A4TECH=m
-CONFIG_HID_APPLE=m
-CONFIG_HID_BELKIN=m
-CONFIG_HID_CHERRY=m
-CONFIG_HID_CHICONY=m
-CONFIG_HID_CYPRESS=m
CONFIG_HID_DRAGONRISE=m
CONFIG_DRAGONRISE_FF=y
-CONFIG_HID_EZKEY=m
-CONFIG_HID_KYE=m
CONFIG_HID_GYRATION=m
CONFIG_HID_TWINHAN=m
-CONFIG_HID_KENSINGTON=m
-CONFIG_HID_LOGITECH=m
CONFIG_LOGITECH_FF=y
CONFIG_LOGIRUMBLEPAD2_FF=y
-CONFIG_HID_MICROSOFT=m
-CONFIG_HID_MONTEREY=m
CONFIG_HID_NTRIG=m
CONFIG_HID_PANTHERLORD=m
CONFIG_PANTHERLORD_FF=y
@@ -293,18 +774,14 @@
CONFIG_HID_TOPSEED=m
CONFIG_HID_THRUSTMASTER=m
CONFIG_THRUSTMASTER_FF=y
-CONFIG_HID_WACOM=m
CONFIG_HID_ZEROPLUS=m
CONFIG_ZEROPLUS_FF=y
CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
CONFIG_USB_DYNAMIC_MINORS=y
CONFIG_USB_OTG_WHITELIST=y
CONFIG_USB_MON=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_UHCI_HCD=m
CONFIG_USB_WHCI_HCD=m
@@ -312,7 +789,7 @@
CONFIG_USB_ACM=m
CONFIG_USB_PRINTER=m
CONFIG_USB_WDM=m
-CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DATAFAB=m
CONFIG_USB_STORAGE_FREECOM=m
CONFIG_USB_STORAGE_ISD200=m
@@ -321,22 +798,123 @@
CONFIG_USB_STORAGE_SDDR55=m
CONFIG_USB_STORAGE_JUMPSHOT=m
CONFIG_USB_STORAGE_ALAUDA=m
+CONFIG_USB_STORAGE_ONETOUCH=m
+CONFIG_USB_STORAGE_KARMA=m
+CONFIG_USB_STORAGE_CYPRESS_ATACB=m
CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
CONFIG_USB_SERIAL=m
CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_FUNSOFT=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MOTOROLA=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_SIEMENS_MPI=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m
+CONFIG_USB_SERIAL_ZIO=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_ADUTUX=m
+CONFIG_USB_SEVSEG=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
CONFIG_USB_LED=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+CONFIG_USB_APPLEDISPLAY=m
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+CONFIG_USB_IOWARRIOR=m
+CONFIG_USB_ISIGHTFW=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
CONFIG_USB_GADGET=m
CONFIG_USB_GADGET_M66592=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_AUDIO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FUNCTIONFS=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_MIDI_GADGET=m
+CONFIG_USB_G_PRINTER=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_G_MULTI=m
+CONFIG_USB_G_WEBCAM=m
+CONFIG_NOP_USB_XCEIV=m
CONFIG_MMC=m
CONFIG_LEDS_CLASS=y
CONFIG_STAGING=y
# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_PRISM2_USB=m
+CONFIG_R8187SE=m
+CONFIG_RTL8192E=m
+CONFIG_USB_SERIAL_QUATECH2=m
+CONFIG_USB_SERIAL_QUATECH_USB2=m
CONFIG_FB_SM7XX=y
-CONFIG_EXT2_FS=m
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EASYCAP=m
CONFIG_EXT4_FS=y
CONFIG_REISERFS_FS=m
CONFIG_REISERFS_PROC_INFO=y
@@ -346,16 +924,17 @@
CONFIG_XFS_FS=m
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
-CONFIG_BTRFS_FS=m
-CONFIG_QUOTA=y
-CONFIG_QFMT_V2=m
-CONFIG_AUTOFS_FS=m
+CONFIG_GFS2_FS=m
+CONFIG_BTRFS_FS=y
CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
CONFIG_FSCACHE=m
CONFIG_CACHEFILES=m
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_NTFS_FS=m
@@ -366,6 +945,7 @@
CONFIG_SQUASHFS=m
CONFIG_SQUASHFS_EMBEDDED=y
CONFIG_ROMFS_FS=m
+CONFIG_UFS_FS=m
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
@@ -411,15 +991,15 @@
CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=y
-CONFIG_PRINTK_TIME=y
CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
CONFIG_STRIP_ASM_SYMS=y
CONFIG_DEBUG_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_TIMER_STATS=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_KEYS=y
CONFIG_KEYS_DEBUG_PROC_KEYS=y
-CONFIG_CRYPTO_FIPS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_CRYPTD=m
CONFIG_CRYPTO_AUTHENC=m
@@ -429,15 +1009,12 @@
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_HMAC=m
CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD128=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_RMD256=m
CONFIG_CRYPTO_RMD320=m
-CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
@@ -457,4 +1034,3 @@
CONFIG_CRYPTO_DEFLATE=m
CONFIG_CRYPTO_ZLIB=m
CONFIG_CRYPTO_LZO=m
-CONFIG_CRC_T10DIF=y
diff --git a/arch/mips/configs/lemote2f_minimal_defconfig b/arch/mips/configs/lemote2f_minimal_defconfig
new file mode 100644
index 0000000..82ad0bd4
--- /dev/null
+++ b/arch/mips/configs/lemote2f_minimal_defconfig
@@ -0,0 +1,122 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_LEMOTE_MACH2F=y
+CONFIG_64BIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_MISC_DEVICES is not set
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_SATA_PMP is not set
+CONFIG_PATA_AMD=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139TOO=y
+CONFIG_R8169=y
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_MFD_SUPPORT is not set
+CONFIG_FB=y
+CONFIG_FB_SIS=y
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_ZEROPLUS_FF=y
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_FB_SM7XX=y
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_EXT4_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/mips/configs/lemote2f_small_defconfig b/arch/mips/configs/lemote2f_small_defconfig
new file mode 100644
index 0000000..45a833e
--- /dev/null
+++ b/arch/mips/configs/lemote2f_small_defconfig
@@ -0,0 +1,151 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_LEMOTE_MACH2F=y
+CONFIG_64BIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=15
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_PM=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_STD_PARTITION="/dev/sda3"
+CONFIG_PM_RUNTIME=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_LOONGSON2_CPUFREQ=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_DEFAULT_PS is not set
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_LIB80211=y
+CONFIG_MAC80211=y
+CONFIG_RFKILL=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_SATA_PMP is not set
+CONFIG_PATA_AMD=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139TOO=y
+CONFIG_R8169=y
+# CONFIG_NETDEV_10000 is not set
+CONFIG_RTL8187B=m
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_HW_RANDOM is not set
+CONFIG_HWMON=m
+# CONFIG_MFD_SUPPORT is not set
+CONFIG_FB=y
+CONFIG_FB_SIS=y
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_CS5535AUDIO=m
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_ZEROPLUS_FF=y
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_FB_SM7XX=y
+CONFIG_EXT4_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
+CONFIG_FRAME_WARN=1024
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/mips/configs/yeeloong_tiny_defconfig b/arch/mips/configs/yeeloong_tiny_defconfig
new file mode 100644
index 0000000..93e3e7b
--- /dev/null
+++ b/arch/mips/configs/yeeloong_tiny_defconfig
@@ -0,0 +1,74 @@
+CONFIG_MACH_LOONGSON=y
+CONFIG_LEMOTE_MACH2F=y
+CONFIG_HZ_1000=y
+CONFIG_PREEMPT=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
+# CONFIG_SWAP is not set
+CONFIG_TINY_RCU=y
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PRINTK is not set
+# CONFIG_BUG is not set
+# CONFIG_ELF_CORE is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_SHMEM is not set
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_PCI_QUIRKS is not set
+CONFIG_SLOB=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_SATA_PMP is not set
+CONFIG_PATA_AMD=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_CONSOLE_TRANSLATIONS is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_MFD_SUPPORT is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_FB=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_CMOS=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_FB_SM7XX=y
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_PROC_FS is not set
+# CONFIG_SYSFS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_BKL is not set
+CONFIG_CRC16=y
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index e5ec8fc..bcce9b0 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -13,6 +13,10 @@
#include <asm/cpu-info.h>
#include <cpu-feature-overrides.h>
+#ifndef current_cpu_prid
+#define current_cpu_prid() current_cpu_data.processor_id
+#endif
+
#ifndef current_cpu_type
#define current_cpu_type() current_cpu_data.cputype
#endif
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index dd86ab2..5eb6c38 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -37,6 +37,8 @@
#define PRID_COMP_CAVIUM 0x0d0000
#define PRID_COMP_INGENIC 0xd00000
+#define PRID_COMP_MASK 0xff0000
+
/*
* Assigned values for the product ID register. In order to detect a
* certain CPU type exactly eventually additional registers may need to
@@ -74,6 +76,7 @@
#define PRID_IMP_LOONGSON2 0x6300
#define PRID_IMP_UNKNOWN 0xff00
+#define PRID_IMP_MASK 0xff00
/*
* These are the PRID's for when 23:16 == PRID_COMP_MIPS
@@ -202,6 +205,13 @@
#define PRID_REV_LOONGSON1B 0x0020
#define PRID_REV_LOONGSON2E 0x0002
#define PRID_REV_LOONGSON2F 0x0003
+#define PRID_REV_LOONGSON1B 0x0020
+
+#define cpu_prid_comp() (current_cpu_prid() & PRID_COMP_MASK)
+#define cpu_prid_imp() (current_cpu_prid() & PRID_IMP_MASK)
+#define cpu_prid_rev() (current_cpu_prid() & PRID_REV_MASK)
+
+#define cpu_prid_encode(comp, imp, rev) ((comp) | (imp) | (rev))
/*
* Older processors used to encode processor version and revision in two
diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
index 84238c5..28e0b03 100644
--- a/arch/mips/include/asm/dma-mapping.h
+++ b/arch/mips/include/asm/dma-mapping.h
@@ -6,9 +6,7 @@
#include <asm/cache.h>
#include <asm-generic/dma-coherent.h>
-#ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */
#include <dma-coherence.h>
-#endif
extern struct dma_map_ops *mips_dma_map_ops;
diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h
index ce35c9a..4c02d4c 100644
--- a/arch/mips/include/asm/ftrace.h
+++ b/arch/mips/include/asm/ftrace.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive for
* more details.
*
- * Copyright (C) 2009 DSLab, Lanzhou University, China
+ * Copyright (C) 2009, 2010 DSLab, Lanzhou University, China
* Author: Wu Zhangjin <wuzhangjin@gmail.com>
*/
@@ -83,8 +83,8 @@
struct dyn_arch_ftrace {
};
-
#endif /* CONFIG_DYNAMIC_FTRACE */
+
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_TRACER */
#endif /* _ASM_MIPS_FTRACE_H */
diff --git a/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h b/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h
index c0f3ef4..223de04 100644
--- a/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h
+++ b/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h
@@ -16,6 +16,20 @@
#ifndef __ASM_MACH_LOONGSON_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_LOONGSON_CPU_FEATURE_OVERRIDES_H
+#ifdef CONFIG_CPU_LOONGSON2
+#define cpu_prid_loongson2() \
+ cpu_prid_encode(PRID_COMP_LEGACY, PRID_IMP_LOONGSON2, 0)
+
+#ifdef CONFIG_CPU_LOONGSON2F
+#define current_cpu_prid() (cpu_prid_loongson2() | PRID_REV_LOONGSON2F)
+#else /* CONFIG_CPU_LOONGSON2E */
+#define current_cpu_prid() (cpu_prid_loongson2() | PRID_REV_LOONGSON2E)
+#endif
+
+#endif /* CONFIG_CPU_LOONGSON2 */
+
+#define current_cpu_type() CPU_LOONGSON2
+
#define cpu_dcache_line_size() 32
#define cpu_icache_line_size() 32
#define cpu_scache_line_size() 32
diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
index a0ee0cb..c6df1c4 100644
--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
@@ -299,7 +299,42 @@
/****************** NATIVE ***************************/
/* GPIO : I/O SPACE; REG : 32BITS */
-#define GPIOL_OUT_VAL 0x00
-#define GPIOL_OUT_EN 0x04
+#define GPIOL_OUT_VAL 0x00
+#define GPIOL_OUT_EN 0x04
+#define GPIOL_OUT_AUX1_SEL 0x10
+/* SMB : I/O SPACE, REG : 8BITS WIDTH */
+#define SMB_SDA 0x00
+#define SMB_STS 0x01
+#define SMB_STS_SLVSTP (1 << 7)
+#define SMB_STS_SDAST (1 << 6)
+#define SMB_STS_BER (1 << 5)
+#define SMB_STS_NEGACK (1 << 4)
+#define SMB_STS_STASTR (1 << 3)
+#define SMB_STS_NMATCH (1 << 2)
+#define SMB_STS_MASTER (1 << 1)
+#define SMB_STS_XMIT (1 << 0)
+#define SMB_CTRL_STS 0x02
+#define SMB_CSTS_TGSTL (1 << 5)
+#define SMB_CSTS_TSDA (1 << 4)
+#define SMB_CSTS_GCMTCH (1 << 3)
+#define SMB_CSTS_MATCH (1 << 2)
+#define SMB_CSTS_BB (1 << 1)
+#define SMB_CSTS_BUSY (1 << 0)
+#define SMB_CTRL1 0x03
+#define SMB_CTRL1_STASTRE (1 << 7)
+#define SMB_CTRL1_NMINTE (1 << 6)
+#define SMB_CTRL1_GCMEN (1 << 5)
+#define SMB_CTRL1_ACK (1 << 4)
+#define SMB_CTRL1_RSVD (1 << 3)
+#define SMB_CTRL1_INTEN (1 << 2)
+#define SMB_CTRL1_STOP (1 << 1)
+#define SMB_CTRL1_START (1 << 0)
+#define SMB_ADDR 0x04
+#define SMB_ADDR_SAEN (1 << 7)
+#define SMB_CONTROLLER_ADDR (0xef << 0)
+#define SMB_CTRL2 0x05
+#define SMB_FREQ (0x20 << 1)
+#define SMB_ENABLE (0x01 << 0)
+#define SMB_CTRL3 0x06
#endif /* _CS5536_H */
diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
index 021d017..d058e46 100644
--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
@@ -10,26 +10,45 @@
#ifdef CONFIG_CS5536_MFGPT
extern void setup_mfgpt0_timer(void);
-extern void disable_mfgpt0_counter(void);
-extern void enable_mfgpt0_counter(void);
+extern void disable_mfgpt_counter(void);
+extern void enable_mfgpt_counter(void);
#else
static inline void __maybe_unused setup_mfgpt0_timer(void)
{
}
-static inline void __maybe_unused disable_mfgpt0_counter(void)
+static inline void __maybe_unused disable_mfgpt_counter(void)
{
}
-static inline void __maybe_unused enable_mfgpt0_counter(void)
+static inline void __maybe_unused enable_mfgpt_counter(void)
{
}
#endif
-#define MFGPT_TICK_RATE 14318000
-#define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ)
+#define MFGPT_CLK_RATE(c) ((14318000UL-32768)*c + 32768)
+#define MFGPT_TICK_RATE(c, scale) (MFGPT_CLK_RATE(c) / (1 << scale))
+#define MFGPT_COMPARE(c, scale) ((MFGPT_TICK_RATE(c, scale)+HZ/2)/HZ)
-#define MFGPT_BASE mfgpt_base
-#define MFGPT0_CMP2 (MFGPT_BASE + 2)
-#define MFGPT0_CNT (MFGPT_BASE + 4)
-#define MFGPT0_SETUP (MFGPT_BASE + 6)
+#define MFGPT_SETUP_ENABLE (1 << 15)
+#define MFGPT_SETUP_ACK (3 << 13)
+#define MFGPT_SETUP_SETUP (1 << 12)
+#define MFGPT_SETUP_CMP2EVT (3 << 8)
+#define MFGPT_SETUP_CMP1EVT (3 << 6)
+#define MFGPT_SETUP_CLOCK(c) (c << 4)
+#define MFGPT_SETUP_SCALE(scale) scale
+
+#define MFGPT0_CMP1 mfgpt_base
+#define MFGPT0_CMP2 (mfgpt_base + 0x02)
+#define MFGPT0_CNT (mfgpt_base + 0x04)
+#define MFGPT0_SETUP (mfgpt_base + 0x06)
+
+#define MFGPT1_CMP1 (mfgpt_base + 0x08)
+#define MFGPT1_CMP2 (mfgpt_base + 0x0A)
+#define MFGPT1_CNT (mfgpt_base + 0x0C)
+#define MFGPT1_SETUP (mfgpt_base + 0x0E)
+
+#define MFGPT2_CMP1 (mfgpt_base + 0x10)
+#define MFGPT2_CMP2 (mfgpt_base + 0x12)
+#define MFGPT2_CNT (mfgpt_base + 0x14)
+#define MFGPT2_SETUP (mfgpt_base + 0x16)
#endif /*!_CS5536_MFGPT_H */
diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h
index 8a7ecb4..ac01334 100644
--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_pci.h
@@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
extern void cs5536_pci_conf_write4(int function, int reg, u32 value);
extern u32 cs5536_pci_conf_read4(int function, int reg);
diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h
index 1f17c18..9bc368f0d 100644
--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_vsm.h
@@ -17,15 +17,43 @@
extern void pci_##name##_write_reg(int reg, u32 value); \
extern u32 pci_##name##_read_reg(int reg);
-/* ide module */
-DECLARE_CS5536_MODULE(ide)
-/* acc module */
-DECLARE_CS5536_MODULE(acc)
-/* ohci module */
-DECLARE_CS5536_MODULE(ohci)
+#define DEFINE_CS5536_MODULE(name) \
+static void pci_##name##_write_reg(int reg, u32 value) {} \
+static u32 pci_##name##_read_reg(int reg) { return 0; }
+
/* isa module */
+#ifdef CONFIG_CS5536_ISA
DECLARE_CS5536_MODULE(isa)
+#else
+DEFINE_CS5536_MODULE(isa)
+#endif
+
+/* ide module */
+#ifdef CONFIG_CS5536_IDE
+DECLARE_CS5536_MODULE(ide)
+#else
+DEFINE_CS5536_MODULE(ide)
+#endif
+
+/* acc module */
+#ifdef CONFIG_CS5536_AUDIO
+DECLARE_CS5536_MODULE(acc)
+#else
+DEFINE_CS5536_MODULE(acc)
+#endif
+
+/* ohci module */
+#ifdef CONFIG_CS5536_OHCI
+DECLARE_CS5536_MODULE(ohci)
+#else
+DEFINE_CS5536_MODULE(ohci)
+#endif
+
/* ehci module */
+#ifdef CONFIG_CS5536_EHCI
DECLARE_CS5536_MODULE(ehci)
+#else
+DEFINE_CS5536_MODULE(ehci)
+#endif
#endif /* _CS5536_VSM_H */
diff --git a/arch/mips/loongson/lemote-2f/ec_kb3310b.h b/arch/mips/include/asm/mach-loongson/ec_kb3310b.h
similarity index 91%
rename from arch/mips/loongson/lemote-2f/ec_kb3310b.h
rename to arch/mips/include/asm/mach-loongson/ec_kb3310b.h
index 5a3f186..600ac10 100644
--- a/arch/mips/loongson/lemote-2f/ec_kb3310b.h
+++ b/arch/mips/include/asm/mach-loongson/ec_kb3310b.h
@@ -3,6 +3,8 @@
*
* Copyright (C) 2008 Lemote Inc.
* Author: liujl <liujl@lemote.com>, 2008-03-14
+ * 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
@@ -22,6 +24,9 @@
typedef int (*sci_handler) (int status);
extern sci_handler yeeloong_report_lid_status;
+#define ON 1
+#define OFF 0
+
#define SCI_IRQ_NUM 0x0A
/*
@@ -111,7 +116,6 @@
#define BIT_BAT_POWER_ON (1 << 1)
#define BIT_BAT_POWER_ACIN (1 << 0)
-/* other registers */
/* Audio: rd/wr */
#define REG_AUDIO_VOLUME 0xF46C
#define REG_AUDIO_MUTE 0xF4E7
@@ -168,21 +172,23 @@
/* SCI Event Number from EC */
enum {
- EVENT_LID = 0x23, /* LID open/close */
- EVENT_DISPLAY_TOGGLE, /* Fn+F3 for display switch */
+ EVENT_LID = 0x23, /* Turn on/off LID */
+ EVENT_SWITCHVIDEOMODE, /* Fn+F3 for display switch */
EVENT_SLEEP, /* Fn+F1 for entering sleep mode */
EVENT_OVERTEMP, /* Over-temperature happened */
EVENT_CRT_DETECT, /* CRT is connected */
EVENT_CAMERA, /* Camera on/off */
EVENT_USB_OC2, /* USB2 Over Current occurred */
EVENT_USB_OC0, /* USB0 Over Current occurred */
- EVENT_BLACK_SCREEN, /* Turn on/off backlight */
- EVENT_AUDIO_MUTE, /* Mute on/off */
- EVENT_DISPLAY_BRIGHTNESS,/* LCD backlight brightness adjust */
+ EVENT_DISPLAYTOGGLE, /* Fn+F2, Turn on/off backlight */
+ EVENT_AUDIO_MUTE, /* Fn+F4, Mute on/off */
+ EVENT_DISPLAY_BRIGHTNESS,/* Fn+^/V, LCD backlight brightness adjust */
EVENT_AC_BAT, /* AC & Battery relative issue */
- EVENT_AUDIO_VOLUME, /* Volume adjust */
+ EVENT_AUDIO_VOLUME, /* Fn+<|>, Volume adjust */
EVENT_WLAN, /* Wlan on/off */
- EVENT_END
};
+#define EVENT_START EVENT_LID
+#define EVENT_END EVENT_WLAN
+
#endif /* !_EC_KB3310B_H */
diff --git a/arch/mips/include/asm/mach-loongson/gpio.h b/arch/mips/include/asm/mach-loongson/gpio.h
index 211a7b7..f15db3c 100644
--- a/arch/mips/include/asm/mach-loongson/gpio.h
+++ b/arch/mips/include/asm/mach-loongson/gpio.h
@@ -13,12 +13,16 @@
#ifndef __STLS2F_GPIO_H
#define __STLS2F_GPIO_H
+#ifdef CONFIG_GPIOLIB
+#define ARCH_NR_GPIOS 4
#include <asm-generic/gpio.h>
extern void gpio_set_value(unsigned gpio, int value);
extern int gpio_get_value(unsigned gpio);
extern int gpio_cansleep(unsigned gpio);
+#endif
+
/* The chip can do interrupt
* but it has not been tested and doc not clear
*/
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index b286534..222d179 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -32,17 +32,13 @@
extern void __init prom_init_cmdline(void);
extern void __init prom_init_machtype(void);
extern void __init prom_init_env(void);
-#ifdef CONFIG_LOONGSON_UART_BASE
-extern unsigned long _loongson_uart_base, loongson_uart_base;
-extern void prom_init_loongson_uart_base(void);
-#endif
+extern void __init prom_init_uart_base(void);
-static inline void prom_init_uart_base(void)
-{
-#ifdef CONFIG_LOONGSON_UART_BASE
- prom_init_loongson_uart_base();
-#endif
-}
+/*
+ * Copy kernel command line from arcs_cmdline
+ */
+#include <asm/setup.h>
+extern char loongson_cmdline[COMMAND_LINE_SIZE];
/* irq operation functions */
extern void bonito_irqdispatch(void);
@@ -249,6 +245,12 @@
/* Chip Config */
#define LOONGSON_CHIPCFG0 LOONGSON_REG(LOONGSON_REGBASE + 0x80)
+#define LOONGSON_GET_CPUFREQ() (LOONGSON_CHIPCFG0 & 7)
+
+#define LOONGSON_SET_CPUFREQ(level) do { \
+ LOONGSON_CHIPCFG0 = (LOONGSON_CHIPCFG0 & (~7)) | (level); \
+} while (0)
+
#endif
/*
diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h
index 3810d5c..a596622 100644
--- a/arch/mips/include/asm/mach-loongson/machine.h
+++ b/arch/mips/include/asm/mach-loongson/machine.h
@@ -12,16 +12,16 @@
#define __ASM_MACH_LOONGSON_MACHINE_H
#ifdef CONFIG_LEMOTE_FULOONG2E
-
-#define LOONGSON_MACHTYPE MACH_LEMOTE_FL2E
-
+ #define LOONGSON_MACHTYPE MACH_LEMOTE_FL2E
#endif
/* use fuloong2f as the default machine of LEMOTE_MACH2F */
#ifdef CONFIG_LEMOTE_MACH2F
+ #define LOONGSON_MACHTYPE MACH_LEMOTE_FL2F
+#endif
-#define LOONGSON_MACHTYPE MACH_LEMOTE_FL2F
-
+#ifdef CONFIG_DEXXON_GDIUM
+ #define LOONGSON_MACHTYPE MACH_DEXXON_GDIUM2F10
#endif
#endif /* __ASM_MACH_LOONGSON_MACHINE_H */
diff --git a/arch/mips/include/asm/mach-loongson1/clock.h b/arch/mips/include/asm/mach-loongson1/clock.h
new file mode 100644
index 0000000..dd1afdb
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson1/clock.h
@@ -0,0 +1,53 @@
+#ifndef __ASM_MACH_LOONGSON1_CLOCK_H
+#define __ASM_MACH_LOONGSON1_CLOCK_H
+
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/seq_file.h>
+#include <linux/clk.h>
+
+extern void (*cpu_wait) (void);
+
+struct clk;
+
+struct clk_ops {
+ void (*init) (struct clk *clk);
+ void (*enable) (struct clk *clk);
+ void (*disable) (struct clk *clk);
+ void (*recalc) (struct clk *clk);
+ int (*set_rate) (struct clk *clk, unsigned long rate, int algo_id);
+ long (*round_rate) (struct clk *clk, unsigned long rate);
+};
+
+struct clk {
+ struct list_head node;
+ const char *name;
+ int id;
+ struct module *owner;
+
+ struct clk *parent;
+ struct clk_ops *ops;
+
+ struct kref kref;
+
+ unsigned long rate;
+ unsigned long flags;
+};
+
+#define CLK_ALWAYS_ENABLED (1 << 0)
+#define CLK_RATE_PROPAGATES (1 << 1)
+
+/* Should be defined by processor-specific code */
+void arch_init_clk_ops(struct clk_ops **, int type);
+
+int clk_init(void);
+
+int __clk_enable(struct clk *);
+void __clk_disable(struct clk *);
+
+void clk_recalc_rate(struct clk *);
+
+int clk_register(struct clk *);
+void clk_unregister(struct clk *);
+
+#endif /* __ASM_MIPS_CLOCK_H */
diff --git a/arch/mips/include/asm/mach-loongson1/regs-intc.h b/arch/mips/include/asm/mach-loongson1/regs-intc.h
new file mode 100644
index 0000000..6d5db23
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson1/regs-intc.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * Loongson1 Interrupt register definitions.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_MACH_LOONGSON1_REGS_INTC_H
+#define __ASM_MACH_LOONGSON1_REGS_INTC_H
+
+#define LS1X_INTC_REG(n, x) \
+ (ioremap(LS1X_INTC_BASE + (n * 0x18) + (x), 4))
+
+#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0)
+#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4)
+#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8)
+#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc)
+#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10)
+#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14)
+
+#endif /* __ASM_MACH_LOONGSON1_REGS_INTC_H */
diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h
index 44b705d..c28a782 100644
--- a/arch/mips/include/asm/module.h
+++ b/arch/mips/include/asm/module.h
@@ -126,6 +126,8 @@
#define MODULE_PROC_FAMILY "LOONGSON1 "
#elif defined CONFIG_CPU_LOONGSON2
#define MODULE_PROC_FAMILY "LOONGSON2 "
+#elif defined CONFIG_CPU_LOONGSON1
+#define MODULE_PROC_FAMILY "LOONGSON1 "
#elif defined CONFIG_CPU_CAVIUM_OCTEON
#define MODULE_PROC_FAMILY "OCTEON "
#elif defined CONFIG_CPU_XLR
diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h
index 6529704..bf6a701 100644
--- a/arch/mips/include/asm/timex.h
+++ b/arch/mips/include/asm/timex.h
@@ -10,6 +10,10 @@
#ifdef __KERNEL__
+#ifdef CONFIG_CSRC_R4K
+#define ARCH_HAS_PREPARED_LPJ
+#endif
+
#include <asm/mipsregs.h>
/*
diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h
index 0f4aec2..7c79b47 100644
--- a/arch/mips/include/uapi/asm/inst.h
+++ b/arch/mips/include/uapi/asm/inst.h
@@ -62,6 +62,8 @@
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
@@ -134,7 +136,7 @@
*/
enum cop1_fmt {
s_fmt, d_fmt, e_fmt, q_fmt,
- w_fmt, l_fmt
+ w_fmt, l_fmt, ps_fmt
};
/*
@@ -162,8 +164,8 @@
*/
enum cop1x_func {
lwxc1_op = 0x00, ldxc1_op = 0x01,
- pfetch_op = 0x07, swxc1_op = 0x08,
- sdxc1_op = 0x09, madd_s_op = 0x20,
+ swxc1_op = 0x08, sdxc1_op = 0x09,
+ 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/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index c6568bf..ff54da8 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -53,16 +53,14 @@
static inline void check_errata(void)
{
- struct cpuinfo_mips *c = ¤t_cpu_data;
-
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_34K:
/*
* Erratum "RPS May Cause Incorrect Instruction Execution"
* This code only handles VPE0, any SMP/SMTC/RTOS code
* making use of VPE1 will be responsable for that VPE.
*/
- if ((c->processor_id & PRID_REV_MASK) <= PRID_REV_34K_V1_0_2)
+ if (cpu_prid_rev() <= PRID_REV_34K_V1_0_2)
write_c0_config7(read_c0_config7() | MIPS_CONF7_RPS);
break;
default:
@@ -328,7 +326,7 @@
static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
{
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_R2000:
c->cputype = CPU_R2000;
__cpu_name[cpu] = "R2000";
@@ -340,7 +338,7 @@
c->tlbsize = 64;
break;
case PRID_IMP_R3000:
- if ((c->processor_id & 0xff) == PRID_REV_R3000A) {
+ if (cpu_prid_rev() == PRID_REV_R3000A) {
if (cpu_has_confreg()) {
c->cputype = CPU_R3081E;
__cpu_name[cpu] = "R3081";
@@ -361,7 +359,7 @@
break;
case PRID_IMP_R4000:
if (read_c0_config() & CONF_SC) {
- if ((c->processor_id & 0xff) >= PRID_REV_R4400) {
+ if (cpu_prid_rev() >= PRID_REV_R4400) {
c->cputype = CPU_R4400PC;
__cpu_name[cpu] = "R4400PC";
} else {
@@ -369,7 +367,7 @@
__cpu_name[cpu] = "R4000PC";
}
} else {
- if ((c->processor_id & 0xff) >= PRID_REV_R4400) {
+ if (cpu_prid_rev() >= PRID_REV_R4400) {
c->cputype = CPU_R4400SC;
__cpu_name[cpu] = "R4400SC";
} else {
@@ -398,7 +396,7 @@
__cpu_name[cpu] = "NEC VR4121";
break;
case PRID_REV_VR4122:
- if ((c->processor_id & 0xf) < 0x3) {
+ if ((current_cpu_prid() & 0xf) < 0x3) {
c->cputype = CPU_VR4122;
__cpu_name[cpu] = "NEC VR4122";
} else {
@@ -407,7 +405,7 @@
}
break;
case PRID_REV_VR4130:
- if ((c->processor_id & 0xf) < 0x4) {
+ if ((current_cpu_prid() & 0xf) < 0x4) {
c->cputype = CPU_VR4131;
__cpu_name[cpu] = "NEC VR4131";
} else {
@@ -458,12 +456,12 @@
set_isa(c, MIPS_CPU_ISA_I);
c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE;
- if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
+ if ((current_cpu_prid() & 0xf0) == (PRID_REV_TX3927 & 0xf0)) {
c->cputype = CPU_TX3927;
__cpu_name[cpu] = "TX3927";
c->tlbsize = 64;
} else {
- switch (c->processor_id & 0xff) {
+ switch (cpu_prid_rev()) {
case PRID_REV_TX3912:
c->cputype = CPU_TX3912;
__cpu_name[cpu] = "TX3912";
@@ -490,7 +488,7 @@
__cpu_name[cpu] = "R49XX";
set_isa(c, MIPS_CPU_ISA_III);
c->options = R4K_OPTS | MIPS_CPU_LLSC;
- if (!(c->processor_id & 0x08))
+ if (!(current_cpu_prid() & 0x08))
c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR;
c->tlbsize = 48;
break;
@@ -649,7 +647,7 @@
static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_4KC:
c->cputype = CPU_4KC;
__cpu_name[cpu] = "MIPS 4Kc";
@@ -720,11 +718,11 @@
static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_AU1_REV1:
case PRID_IMP_AU1_REV2:
c->cputype = CPU_ALCHEMY;
- switch ((c->processor_id >> 24) & 0xff) {
+ switch ((current_cpu_prid() >> 24) & 0xff) {
case 0:
__cpu_name[cpu] = "Au1000";
break;
@@ -739,7 +737,7 @@
break;
case 4:
__cpu_name[cpu] = "Au1200";
- if ((c->processor_id & 0xff) == 2)
+ if (cpu_prid_rev() == 2)
__cpu_name[cpu] = "Au1250";
break;
case 5:
@@ -757,12 +755,12 @@
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_SB1:
c->cputype = CPU_SB1;
__cpu_name[cpu] = "SiByte SB1";
/* FPU in pass1 is known to have issues. */
- if ((c->processor_id & 0xff) < 0x02)
+ if (cpu_prid_rev() < 0x02)
c->options &= ~(MIPS_CPU_FPU | MIPS_CPU_32FPR);
break;
case PRID_IMP_SB1A:
@@ -775,7 +773,7 @@
static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_SR71000:
c->cputype = CPU_SR71000;
__cpu_name[cpu] = "Sandcraft SR71000";
@@ -788,7 +786,7 @@
static inline void cpu_probe_nxp(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_PR4450:
c->cputype = CPU_PR4450;
__cpu_name[cpu] = "Philips PR4450";
@@ -800,7 +798,7 @@
static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_BMIPS32_REV4:
case PRID_IMP_BMIPS32_REV8:
c->cputype = CPU_BMIPS32;
@@ -815,7 +813,7 @@
set_elf_platform(cpu, "bmips3300");
break;
case PRID_IMP_BMIPS43XX: {
- int rev = c->processor_id & 0xff;
+ int rev = cpu_prid_rev();
if (rev >= PRID_REV_BMIPS4380_LO &&
rev <= PRID_REV_BMIPS4380_HI) {
@@ -841,7 +839,7 @@
static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
{
decode_configs(c);
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_CAVIUM_CN38XX:
case PRID_IMP_CAVIUM_CN31XX:
case PRID_IMP_CAVIUM_CN30XX:
@@ -877,7 +875,7 @@
decode_configs(c);
/* JZRISC does not implement the CP0 counter. */
c->options &= ~MIPS_CPU_COUNTER;
- switch (c->processor_id & 0xff00) {
+ switch (cpu_prid_imp()) {
case PRID_IMP_JZRISC:
c->cputype = CPU_JZRISC;
__cpu_name[cpu] = "Ingenic JZRISC";
@@ -980,7 +978,7 @@
c->cputype = CPU_UNKNOWN;
c->processor_id = read_c0_prid();
- switch (c->processor_id & 0xff0000) {
+ switch (cpu_prid_comp()) {
case PRID_COMP_LEGACY:
cpu_probe_legacy(c, cpu);
break;
@@ -1060,7 +1058,7 @@
struct cpuinfo_mips *c = ¤t_cpu_data;
printk(KERN_INFO "CPU revision is: %08x (%s)\n",
- c->processor_id, cpu_name_string());
+ current_cpu_prid(), cpu_name_string());
if (c->options & MIPS_CPU_FPU)
printk(KERN_INFO "FPU revision is: %08x\n", c->fpu_id);
}
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 37605dc..e09d1ec 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/spram.c b/arch/mips/kernel/spram.c
index 6af08d8..4be9669 100644
--- a/arch/mips/kernel/spram.c
+++ b/arch/mips/kernel/spram.c
@@ -198,10 +198,9 @@
}
void __cpuinit spram_config(void)
{
- struct cpuinfo_mips *c = ¤t_cpu_data;
unsigned int config0;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_24K:
case CPU_34K:
case CPU_74K:
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 9d686bf..a90822f 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -105,7 +105,7 @@
* The published errata for the R4400 up to 3.0 say the CPU
* has the mfc0 from count bug.
*/
- if ((current_cpu_data.processor_id & 0xff) <= 0x30)
+ if (cpu_prid_rev() <= 0x30)
return 1;
/*
@@ -119,6 +119,11 @@
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();
if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug())
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index eeddc58..d7bec00 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -2,10 +2,14 @@
# Makefile for MIPS-specific library files..
#
-lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \
+lib-y += bitops.o csum_partial.o memcpy.o memset.o \
mips-atomic.o strlen_user.o strncpy_user.o \
strnlen_user.o uncached.o
+ifndef CONFIG_CSRC_R4K
+lib-y += delay.o
+endif
+
obj-y += iomap.o
obj-$(CONFIG_PCI) += iomap-pci.o
diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig
index 263beb9..d56d594 100644
--- a/arch/mips/loongson/Kconfig
+++ b/arch/mips/loongson/Kconfig
@@ -32,16 +32,43 @@
config LEMOTE_MACH2F
bool "Lemote Loongson 2F family machines"
+ 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 if PCI
+ select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
+ select DMA_NONCOHERENT
+ select GENERIC_ISA_DMA_SUPPORT_BROKEN
+ select HAVE_CLK
+ select HW_HAS_PCI
+ select I8259
+ select IRQ_CPU
+ select SYS_HAS_CPU_LOONGSON2F
+ select SYS_HAS_EARLY_PRINTK
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
+ select SYS_SUPPORTS_HIGHMEM if ! EMBEDDED
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select LOONGSON_MC146818 if RTC_DRV_CMOS
+ help
+ Lemote Loongson 2F family machines utilize the 2F revision of
+ Loongson processor and the AMD CS5536 south bridge.
+
+ These family machines include fuloong2f mini PC, yeeloong2f notebook,
+ LingLoong allinone PC and so forth.
+
+config DEXXON_GDIUM
+ bool "Dexxon Gdium Netbook"
select ARCH_SPARSEMEM_ENABLE
select BOARD_SCACHE
select BOOT_ELF32
select CEVT_R4K if ! MIPS_EXTERNAL_TIMER
select CPU_HAS_WB
- select CS5536
select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
select DMA_NONCOHERENT
select GENERIC_ISA_DMA_SUPPORT_BROKEN
- select HAVE_CLK
select HW_HAS_PCI
select I8259
select IRQ_CPU
@@ -52,16 +79,34 @@
select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_LITTLE_ENDIAN
- select LOONGSON_MC146818
+ select ARCH_REQUIRE_GPIOLIB
+ select HAVE_PWM if MFD_SM501
help
- Lemote Loongson 2F family machines utilize the 2F revision of
- Loongson processor and the AMD CS5536 south bridge.
-
- These family machines include fuloong2f mini PC, yeeloong2f notebook,
- LingLoong allinone PC and so forth.
+ Dexxon gdium netbook based on Loongson 2F and SM502.
endchoice
config CS5536
+ select CS5536_IDE if (PATA_AMD || BLK_DEV_AMD74XX || PATA_CS5536)
+ select CS5536_OHCI if USB_OHCI_HCD
+ select CS5536_EHCI if USB_EHCI_HCD
+ select CS5536_AUDIO if SND_CS5535AUDIO
+ select CS5536_ISA
+ bool
+
+config CS5536_ISA
+ select ISA
+ bool
+
+config CS5536_IDE
+ bool
+
+config CS5536_OHCI
+ bool
+
+config CS5536_EHCI
+ bool
+
+config CS5536_AUDIO
bool
config CS5536_MFGPT
@@ -81,13 +126,25 @@
default y
depends on CPU_SUPPORTS_CPUFREQ && SUSPEND
-config LOONGSON_UART_BASE
- bool
- default y
- depends on EARLY_PRINTK || SERIAL_8250
-
config LOONGSON_MC146818
bool
default n
+config GDIUM_PWM_CLOCK
+ tristate "Gdium PWM Timer"
+ default n
+ depends on HAVE_PWM && EXPERIMENTAL && BROKEN
+ select MIPS_EXTERNAL_TIMER
+ help
+ This options enables the experimental sm501-pwm based clock. With it,
+ you may be possible to use the loongson2f cpufreq driver.
+
+config GDIUM_VERSION
+ int "Configure Gdium Version"
+ depends on DEXXON_GDIUM
+ default "3"
+ help
+ I have no information about how to determine which version your board
+ is, If the default config doesn't work for it, please change it to
+ smaller ones.
endif # MACH_LOONGSON
diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile
index 0dc0055..4b69866 100644
--- a/arch/mips/loongson/Makefile
+++ b/arch/mips/loongson/Makefile
@@ -15,3 +15,9 @@
#
obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/
+
+#
+# Dexxon gdium netbook, based on loongson 2F and SM502
+#
+
+obj-$(CONFIG_DEXXON_GDIUM) += gdium/
diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform
index 29692e5..6be5dff 100644
--- a/arch/mips/loongson/Platform
+++ b/arch/mips/loongson/Platform
@@ -30,3 +30,4 @@
cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely
load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000
load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000
+load-$(CONFIG_DEXXON_GDIUM) += 0xffffffff80200000
diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile
index 33f76e6..703b058 100644
--- a/arch/mips/loongson/common/Makefile
+++ b/arch/mips/loongson/common/Makefile
@@ -4,15 +4,14 @@
obj-y += setup.o init.o cmdline.o env.o time.o reset.o irq.o \
pci.o bonito-irq.o mem.o machtype.o platform.o
+
obj-$(CONFIG_GPIOLIB) += gpio.o
#
# Serial port support
#
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-loongson-serial-$(CONFIG_SERIAL_8250) := serial.o
-obj-y += $(loongson-serial-m) $(loongson-serial-y)
-obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
+obj-$(CONFIG_SERIAL_8250) += serial.o
obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
#
diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c
index 72fed00..96d5919 100644
--- a/arch/mips/loongson/common/cmdline.c
+++ b/arch/mips/loongson/common/cmdline.c
@@ -17,10 +17,15 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
+#include <linux/module.h>
#include <asm/bootinfo.h>
#include <loongson.h>
+/* the kernel command line copied from arcs_cmdline */
+char loongson_cmdline[COMMAND_LINE_SIZE];
+EXPORT_SYMBOL(loongson_cmdline);
+
void __init prom_init_cmdline(void)
{
int prom_argc;
@@ -45,4 +50,31 @@
}
prom_init_machtype();
+
+ /* append machine specific command line */
+ switch (mips_machtype) {
+ case MACH_LEMOTE_LL2F:
+ if ((strstr(arcs_cmdline, "video=")) == NULL)
+ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60");
+ break;
+ case MACH_LEMOTE_FL2F:
+ if ((strstr(arcs_cmdline, "ide_core.ignore_cable=")) == NULL)
+ strcat(arcs_cmdline, " ide_core.ignore_cable=0");
+ break;
+ case MACH_LEMOTE_ML2F7:
+ /* Mengloong-2F has a 800x480 screen */
+ if ((strstr(arcs_cmdline, "vga=")) == NULL)
+ strcat(arcs_cmdline, " vga=0x313");
+ break;
+ case MACH_DEXXON_GDIUM2F10:
+ /* gdium has a 1024x600 screen */
+ if ((strstr(arcs_cmdline, "video=")) == NULL)
+ strcat(arcs_cmdline, " video=sm501fb:1024x600@60");
+ break;
+ default:
+ break;
+ }
+
+ /* copy arcs_cmdline into loongson_cmdline */
+ strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE);
}
diff --git a/arch/mips/loongson/common/cs5536/Makefile b/arch/mips/loongson/common/cs5536/Makefile
index f12e640..70f6057 100644
--- a/arch/mips/loongson/common/cs5536/Makefile
+++ b/arch/mips/loongson/common/cs5536/Makefile
@@ -2,8 +2,13 @@
# Makefile for CS5536 support.
#
-obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \
- cs5536_isa.o cs5536_ehci.o
+obj-$(CONFIG_CS5536) += cs5536_pci.o
+
+obj-$(CONFIG_ISA) += cs5536_isa.o
+obj-$(CONFIG_CS5536_IDE) += cs5536_ide.o
+obj-$(CONFIG_CS5536_AUDIO) += cs5536_acc.o
+obj-$(CONFIG_CS5536_OHCI) += cs5536_ohci.o
+obj-$(CONFIG_CS5536_EHCI) += cs5536_ehci.o
#
# Enable cs5536 mfgpt Timer
diff --git a/arch/mips/loongson/common/cs5536/cs5536_acc.c b/arch/mips/loongson/common/cs5536/cs5536_acc.c
index ab4d6cc..2b0d31e 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_acc.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_acc.c
@@ -18,7 +18,7 @@
void pci_acc_write_reg(int reg, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
switch (reg) {
case PCI_COMMAND:
@@ -66,75 +66,73 @@
u32 pci_acc_read_reg(int reg)
{
u32 hi, lo;
- u32 conf_data = 0;
+ u32 cfg = 0;
switch (reg) {
case PCI_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_ACC_DEVICE_ID, CS5536_VENDOR_ID);
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_AUDIO,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_COMMAND:
_rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
if (((lo & 0xfff00000) || (hi & 0x000000ff))
&& ((hi & 0xf0000000) == 0xa0000000))
- conf_data |= PCI_COMMAND_IO;
+ cfg |= PCI_COMMAND_IO;
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
if ((lo & 0x300) == 0x300)
- conf_data |= PCI_COMMAND_MASTER;
+ cfg |= PCI_COMMAND_MASTER;
break;
case PCI_STATUS:
- conf_data |= PCI_STATUS_66MHZ;
- conf_data |= PCI_STATUS_FAST_BACK;
+ cfg |= PCI_STATUS_66MHZ;
+ cfg |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
- conf_data |= PCI_STATUS_PARITY;
- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ cfg |= PCI_STATUS_PARITY;
+ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(ACC_MSR_REG(ACC_CAP), &hi, &lo);
- conf_data = lo & 0x000000ff;
- conf_data |= (CS5536_ACC_CLASS_CODE << 8);
+ cfg = lo & 0x000000ff;
+ cfg |= (CS5536_ACC_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
- conf_data =
- CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
- PCI_NORMAL_LATENCY_TIMER);
+ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+ PCI_NORMAL_LATENCY_TIMER);
break;
case PCI_BAR0_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_ACC_FLAG) {
- conf_data = CS5536_ACC_RANGE |
+ cfg = CS5536_ACC_RANGE |
PCI_BASE_ADDRESS_SPACE_IO;
lo &= ~SOFT_BAR_ACC_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
- conf_data = (hi & 0x000000ff) << 12;
- conf_data |= (lo & 0xfff00000) >> 20;
- conf_data |= 0x01;
- conf_data &= ~0x02;
+ cfg = (hi & 0x000000ff) << 12;
+ cfg |= (lo & 0xfff00000) >> 20;
+ cfg |= 0x01;
+ cfg &= ~0x02;
}
break;
case PCI_CARDBUS_CIS:
- conf_data = PCI_CARDBUS_CIS_POINTER;
+ cfg = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_SUBSYSTEM_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_ACC_SUB_ID, CS5536_SUB_VENDOR_ID);
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_AUDIO,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_ROM_ADDRESS:
- conf_data = PCI_EXPANSION_ROM_BAR;
+ cfg = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
- conf_data = PCI_CAPLIST_USB_POINTER;
+ cfg = PCI_CAPLIST_USB_POINTER;
break;
case PCI_INTERRUPT_LINE:
- conf_data =
- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR);
+ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR);
break;
default:
break;
}
- return conf_data;
+ return cfg;
}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ehci.c b/arch/mips/loongson/common/cs5536/cs5536_ehci.c
index ec2e360..3c2163a 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_ehci.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_ehci.c
@@ -18,7 +18,7 @@
void pci_ehci_write_reg(int reg, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
switch (reg) {
case PCI_COMMAND:
@@ -78,83 +78,78 @@
u32 pci_ehci_read_reg(int reg)
{
- u32 conf_data = 0;
+ u32 cfg = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_EHCI_DEVICE_ID, CS5536_VENDOR_ID);
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_EHC,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_COMMAND:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
if (hi & PCI_COMMAND_MASTER)
- conf_data |= PCI_COMMAND_MASTER;
+ cfg |= PCI_COMMAND_MASTER;
if (hi & PCI_COMMAND_MEMORY)
- conf_data |= PCI_COMMAND_MEMORY;
+ cfg |= PCI_COMMAND_MEMORY;
break;
case PCI_STATUS:
- conf_data |= PCI_STATUS_66MHZ;
- conf_data |= PCI_STATUS_FAST_BACK;
+ cfg |= PCI_STATUS_66MHZ;
+ cfg |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
- conf_data |= PCI_STATUS_PARITY;
- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ cfg |= PCI_STATUS_PARITY;
+ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
- conf_data = lo & 0x000000ff;
- conf_data |= (CS5536_EHCI_CLASS_CODE << 8);
+ cfg = lo & 0x000000ff;
+ cfg |= (CS5536_EHCI_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
- conf_data =
- CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
- PCI_NORMAL_LATENCY_TIMER);
+ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+ PCI_NORMAL_LATENCY_TIMER);
break;
case PCI_BAR0_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_EHCI_FLAG) {
- conf_data = CS5536_EHCI_RANGE |
+ cfg = CS5536_EHCI_RANGE |
PCI_BASE_ADDRESS_SPACE_MEMORY;
lo &= ~SOFT_BAR_EHCI_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
- conf_data = lo & 0xfffff000;
+ cfg = lo & 0xfffff000;
}
break;
case PCI_CARDBUS_CIS:
- conf_data = PCI_CARDBUS_CIS_POINTER;
- break;
- case PCI_SUBSYSTEM_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_EHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
+ cfg = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_ROM_ADDRESS:
- conf_data = PCI_EXPANSION_ROM_BAR;
+ cfg = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
- conf_data = PCI_CAPLIST_USB_POINTER;
+ cfg = PCI_CAPLIST_USB_POINTER;
break;
case PCI_INTERRUPT_LINE:
- conf_data =
- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
+ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
break;
case PCI_EHCI_LEGSMIEN_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
- conf_data = (hi & 0x003f0000) >> 16;
+ cfg = (hi & 0x003f0000) >> 16;
break;
case PCI_EHCI_LEGSMISTS_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
- conf_data = (hi & 0x3f000000) >> 24;
+ cfg = (hi & 0x3f000000) >> 24;
break;
case PCI_EHCI_FLADJ_REG:
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
- conf_data = hi & 0x00003f00;
+ cfg = hi & 0x00003f00;
break;
default:
break;
}
- return conf_data;
+ return cfg;
}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ide.c b/arch/mips/loongson/common/cs5536/cs5536_ide.c
index a73414d..4699e15 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_ide.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_ide.c
@@ -18,7 +18,7 @@
void pci_ide_write_reg(int reg, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
switch (reg) {
case PCI_COMMAND:
@@ -72,26 +72,16 @@
_wrmsr(IDE_MSR_REG(IDE_CFG), hi, lo);
}
break;
- case PCI_IDE_DTC_REG:
- _rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
- lo = value;
- _wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo);
+#define SET_PCI_IDE_REG(r) \
+ case PCI_IDE_##r##_REG: \
+ _rdmsr(IDE_MSR_REG(IDE_##r), &hi, &lo); \
+ lo = value; \
+ _wrmsr(IDE_MSR_REG(IDE_##r), hi, lo); \
break;
- case PCI_IDE_CAST_REG:
- _rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
- lo = value;
- _wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo);
- break;
- case PCI_IDE_ETC_REG:
- _rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
- lo = value;
- _wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo);
- break;
- case PCI_IDE_PM_REG:
- _rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
- lo = value;
- _wrmsr(IDE_MSR_REG(IDE_INTERNAL_PM), hi, lo);
- break;
+ SET_PCI_IDE_REG(DTC)
+ SET_PCI_IDE_REG(CAST)
+ SET_PCI_IDE_REG(ETC)
+ SET_PCI_IDE_REG(PM)
default:
break;
}
@@ -99,94 +89,79 @@
u32 pci_ide_read_reg(int reg)
{
- u32 conf_data = 0;
+ u32 cfg = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_IDE_DEVICE_ID, CS5536_VENDOR_ID);
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_IDE,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_COMMAND:
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
if (lo & 0xfffffff0)
- conf_data |= PCI_COMMAND_IO;
+ cfg |= PCI_COMMAND_IO;
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
if ((lo & 0x30) == 0x30)
- conf_data |= PCI_COMMAND_MASTER;
+ cfg |= PCI_COMMAND_MASTER;
break;
case PCI_STATUS:
- conf_data |= PCI_STATUS_66MHZ;
- conf_data |= PCI_STATUS_FAST_BACK;
+ cfg |= PCI_STATUS_66MHZ;
+ cfg |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
- conf_data |= PCI_STATUS_PARITY;
- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ cfg |= PCI_STATUS_PARITY;
+ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(IDE_MSR_REG(IDE_CAP), &hi, &lo);
- conf_data = lo & 0x000000ff;
- conf_data |= (CS5536_IDE_CLASS_CODE << 8);
+ cfg = lo & 0x000000ff;
+ cfg |= (CS5536_IDE_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
hi &= 0x000000f8;
- conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi);
+ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi);
break;
case PCI_BAR4_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_IDE_FLAG) {
- conf_data = CS5536_IDE_RANGE |
+ cfg = CS5536_IDE_RANGE |
PCI_BASE_ADDRESS_SPACE_IO;
lo &= ~SOFT_BAR_IDE_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
- conf_data = lo & 0xfffffff0;
- conf_data |= 0x01;
- conf_data &= ~0x02;
+ cfg = lo & 0xfffffff0;
+ cfg |= 0x01;
+ cfg &= ~0x02;
}
break;
case PCI_CARDBUS_CIS:
- conf_data = PCI_CARDBUS_CIS_POINTER;
- break;
- case PCI_SUBSYSTEM_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_IDE_SUB_ID, CS5536_SUB_VENDOR_ID);
+ cfg = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_ROM_ADDRESS:
- conf_data = PCI_EXPANSION_ROM_BAR;
+ cfg = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
- conf_data = PCI_CAPLIST_POINTER;
+ cfg = PCI_CAPLIST_POINTER;
break;
case PCI_INTERRUPT_LINE:
- conf_data =
- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR);
+ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR);
break;
- case PCI_IDE_CFG_REG:
- _rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
- conf_data = lo;
+#define GET_PCI_IDE_REG(r) \
+ case PCI_IDE_##r##_REG: \
+ _rdmsr(IDE_MSR_REG(IDE_##r), &hi, &cfg); \
break;
- case PCI_IDE_DTC_REG:
- _rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
- conf_data = lo;
- break;
- case PCI_IDE_CAST_REG:
- _rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
- conf_data = lo;
- break;
- case PCI_IDE_ETC_REG:
- _rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
- conf_data = lo;
- break;
- case PCI_IDE_PM_REG:
- _rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
- conf_data = lo;
- break;
+ GET_PCI_IDE_REG(CFG)
+ GET_PCI_IDE_REG(DTC)
+ GET_PCI_IDE_REG(CAST)
+ GET_PCI_IDE_REG(ETC)
+ GET_PCI_IDE_REG(PM)
default:
break;
}
- return conf_data;
+ return cfg;
}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_isa.c b/arch/mips/loongson/common/cs5536/cs5536_isa.c
index a6eb2e8..f74aeb3 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_isa.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_isa.c
@@ -86,7 +86,7 @@
void pci_isa_write_bar(int n, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
if (value == PCI_BAR_RANGE_MASK) {
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
@@ -95,7 +95,7 @@
} else if (value & 0x01) {
/* NATIVE reg */
hi = 0x0000f001;
- lo &= bar_space_range[n];
+ lo = value & bar_space_range[n];
_wrmsr(divil_msr_reg[n], hi, lo);
/* RCONFx is 4bytes in units for I/O space */
@@ -112,21 +112,21 @@
u32 pci_isa_read_bar(int n)
{
- u32 conf_data = 0;
+ u32 cfg = 0;
u32 hi, lo;
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & soft_bar_flag[n]) {
- conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
+ cfg = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
lo &= ~soft_bar_flag[n];
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(divil_msr_reg[n], &hi, &lo);
- conf_data = lo & bar_space_range[n];
- conf_data |= 0x01;
- conf_data &= ~0x02;
+ cfg = lo & bar_space_range[n];
+ cfg |= 0x01;
+ cfg &= ~0x02;
}
- return conf_data;
+ return cfg;
}
/*
@@ -136,7 +136,7 @@
*/
void pci_isa_write_reg(int reg, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
u32 temp;
switch (reg) {
@@ -230,45 +230,46 @@
*/
u32 pci_isa_read_reg(int reg)
{
- u32 conf_data = 0;
+ u32 cfg = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID);
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_ISA,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_COMMAND:
/* we just check the first LBAR for the IO enable bit, */
/* maybe we should changed later. */
_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);
if (hi & 0x01)
- conf_data |= PCI_COMMAND_IO;
+ cfg |= PCI_COMMAND_IO;
break;
case PCI_STATUS:
- conf_data |= PCI_STATUS_66MHZ;
- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
- conf_data |= PCI_STATUS_FAST_BACK;
+ cfg |= PCI_STATUS_66MHZ;
+ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
+ cfg |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_TAS_ERR_FLAG)
- conf_data |= PCI_STATUS_SIG_TARGET_ABORT;
+ cfg |= PCI_STATUS_SIG_TARGET_ABORT;
if (lo & SB_TAR_ERR_FLAG)
- conf_data |= PCI_STATUS_REC_TARGET_ABORT;
+ cfg |= PCI_STATUS_REC_TARGET_ABORT;
if (lo & SB_MAR_ERR_FLAG)
- conf_data |= PCI_STATUS_REC_MASTER_ABORT;
+ cfg |= PCI_STATUS_REC_MASTER_ABORT;
if (lo & SB_PARE_ERR_FLAG)
- conf_data |= PCI_STATUS_DETECTED_PARITY;
+ cfg |= PCI_STATUS_DETECTED_PARITY;
break;
case PCI_CLASS_REVISION:
_rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo);
- conf_data = lo & 0x000000ff;
- conf_data |= (CS5536_ISA_CLASS_CODE << 8);
+ cfg = lo & 0x000000ff;
+ cfg |= (CS5536_ISA_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
hi &= 0x000000f8;
- conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
+ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
break;
/*
* we only use the LBAR of DIVIL, no RCONF used.
@@ -292,25 +293,21 @@
return pci_isa_read_bar(5);
break;
case PCI_CARDBUS_CIS:
- conf_data = PCI_CARDBUS_CIS_POINTER;
- break;
- case PCI_SUBSYSTEM_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID);
+ cfg = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_ROM_ADDRESS:
- conf_data = PCI_EXPANSION_ROM_BAR;
+ cfg = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
- conf_data = PCI_CAPLIST_POINTER;
+ cfg = PCI_CAPLIST_POINTER;
break;
case PCI_INTERRUPT_LINE:
/* no interrupt used here */
- conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
+ cfg = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
break;
default:
break;
}
- return conf_data;
+ return cfg;
}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
index c639b9d..a7078ae 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
@@ -7,6 +7,9 @@
* Copyright (C) 2009 Lemote Inc.
* Author: Wu zhangjin, wuzhangjin@gmail.com
*
+ * Copyright (C) 2010 Lemote Inc.
+ * Author: Gang Liang, randomizedthinking@gmail.com
+ *
* Reference: AMD Geode(TM) CS5536 Companion Device Data Book
*
* This program is free software; you can redistribute it and/or modify it
@@ -15,11 +18,24 @@
* option) any later version.
*/
+/*
+ * The MFGPT base address is variable, i.e., it could change over time. In
+ * reality, it only changes once when setting up the PCI memory mapping (occurs
+ * about 0.2 second from boot). But because of this, we have to read in the
+ * mfgpt base address repeatly in the beginning of various routines, most
+ * noticeably, mfgpt1_read_cycle (for sched_clock), and mfgpt1_interrupt.
+ *
+ * The source of problem is that PMON and the current cs5536 set up pci
+ * register window differently (to be further confirmed). Can we set
+ * them the same so as to save the trouble here?
+ *
+ * Now an ugly hack is used to save a few CPU cycles... likely an
+ * over-optimization. Feel free to remove it.
+ */
+
#include <linux/io.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/clockchips.h>
@@ -27,93 +43,127 @@
#include <cs5536/cs5536_mfgpt.h>
-DEFINE_SPINLOCK(mfgpt_lock);
-EXPORT_SYMBOL(mfgpt_lock);
+static void mfgpt0_set_mode(enum clock_event_mode, struct clock_event_device*);
+static int mfgpt0_next_event(unsigned long, struct clock_event_device*);
+static irqreturn_t mfgpt0_interrupt(int irq, void *dev_id);
+static void mfgpt0_start_timer(u16 delta);
+static cycle_t mfgpt1_read_cycle(struct clocksource *cs);
+
+static enum clock_event_mode mfgpt0_mode = CLOCK_EVT_MODE_SHUTDOWN;
static u32 mfgpt_base;
-/*
- * Initialize the MFGPT timer.
- *
- * This is also called after resume to bring the MFGPT into operation again.
- */
-
-/* disable counter */
-void disable_mfgpt0_counter(void)
-{
- outw(inw(MFGPT0_SETUP) & 0x7fff, MFGPT0_SETUP);
-}
-EXPORT_SYMBOL(disable_mfgpt0_counter);
-
-/* enable counter, comparator2 to event mode, 14.318MHz clock */
-void enable_mfgpt0_counter(void)
-{
- outw(0xe310, MFGPT0_SETUP);
-}
-EXPORT_SYMBOL(enable_mfgpt0_counter);
-
-static void init_mfgpt_timer(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- spin_lock(&mfgpt_lock);
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */
- outw(0, MFGPT0_CNT); /* set counter to 0 */
- enable_mfgpt0_counter();
- break;
-
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_UNUSED:
- if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
- evt->mode == CLOCK_EVT_MODE_ONESHOT)
- disable_mfgpt0_counter();
- break;
-
- case CLOCK_EVT_MODE_ONESHOT:
- /* The oneshot mode have very high deviation, Not use it! */
- break;
-
- case CLOCK_EVT_MODE_RESUME:
- /* Nothing to do here */
- break;
- }
- spin_unlock(&mfgpt_lock);
-}
-
-static struct clock_event_device mfgpt_clockevent = {
- .name = "mfgpt",
- .features = CLOCK_EVT_FEAT_PERIODIC,
- .set_mode = init_mfgpt_timer,
+static struct clock_event_device mfgpt0_clockevent = {
+ .name = "mfgpt0",
+ .features = CLOCK_EVT_MODE_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ .set_mode = mfgpt0_set_mode,
+ .set_next_event = mfgpt0_next_event,
+ .rating = 220,
.irq = CS5536_MFGPT_INTR,
};
-static irqreturn_t timer_interrupt(int irq, void *dev_id)
+static struct irqaction irq5 = {
+ .handler = mfgpt0_interrupt,
+ .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
+ .name = "mfgpt0-timer"
+};
+
+static struct clocksource mfgpt1_clocksource = {
+ .name = "mfgpt1",
+ .rating = 210,
+ .read = mfgpt1_read_cycle,
+ .mask = CLOCKSOURCE_MASK(16),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS
+};
+
+static inline void enable_mfgpt0_counter(void)
{
u32 basehi;
-
- /*
- * get MFGPT base address
- *
- * NOTE: do not remove me, it's need for the value of mfgpt_base is
- * variable
- */
_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
- /* ack */
- outw(inw(MFGPT0_SETUP) | 0x4000, MFGPT0_SETUP);
-
- mfgpt_clockevent.event_handler(&mfgpt_clockevent);
-
- return IRQ_HANDLED;
+ /* clockevent: 14M, divisor = 8 (scale=3), CMP2 event mode */
+ outw(MFGPT_SETUP_ACK | MFGPT_SETUP_CMP2EVT |
+ MFGPT_SETUP_CLOCK(1) | MFGPT_SETUP_SCALE(3), MFGPT0_SETUP);
+ outw(0, MFGPT0_CNT);
+ outw(MFGPT_COMPARE(1, 3), MFGPT0_CMP2);
+ outw(0xFFFF, MFGPT0_SETUP);
}
-static struct irqaction irq5 = {
- .handler = timer_interrupt,
- .flags = IRQF_NOBALANCING | IRQF_TIMER,
- .name = "timer"
-};
+static inline void enable_mfgpt1_counter(void)
+{
+ u32 basehi;
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
+
+ /* clocksource: 32K w/ divisor = 2 (scale=1) */
+ outw(MFGPT_SETUP_ACK | MFGPT_SETUP_CLOCK(0) |
+ MFGPT_SETUP_SCALE(1), MFGPT1_SETUP);
+
+ outw(0, MFGPT1_CNT);
+ outw(0xFFFF, MFGPT1_CMP2); /* CNT won't tick with no CMP set */
+ outw(0xFFFF, MFGPT1_SETUP);
+}
+
+void enable_mfgpt_counter(void)
+{
+ /* TODO: add a mfgpt system hard reset here
+ * timers might not reset correctly when OS crashes
+ */
+
+ enable_mfgpt0_counter();
+ enable_mfgpt1_counter();
+}
+EXPORT_SYMBOL(enable_mfgpt_counter);
+
+void disable_mfgpt_counter(void)
+{
+ outw(0x7FFF, MFGPT0_SETUP);
+ outw(0x7FFF, MFGPT1_SETUP);
+}
+EXPORT_SYMBOL(disable_mfgpt_counter);
+
+static void mfgpt0_start_timer(u16 delta)
+{
+ outw(0x7FFF, MFGPT0_SETUP);
+ outw(0, MFGPT0_CNT);
+ outw(delta, MFGPT0_CMP2);
+ outw(0xFFFF, MFGPT0_SETUP);
+}
+
+static void mfgpt0_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ outw(0x7FFF, MFGPT0_SETUP);
+ if (mode == CLOCK_EVT_MODE_PERIODIC)
+ mfgpt0_start_timer(MFGPT_COMPARE(1, 3));
+
+ mfgpt0_mode = mode;
+}
+
+static int mfgpt0_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ mfgpt0_start_timer(delta);
+ return 0;
+}
+
+static irqreturn_t mfgpt0_interrupt(int irq, void *dev_id)
+{
+ u32 basehi;
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
+
+ /* stop the timer and ack the interrupt */
+ outw(0x7FFF, MFGPT0_SETUP);
+
+ if (mfgpt0_mode == CLOCK_EVT_MODE_SHUTDOWN)
+ return IRQ_HANDLED;
+
+ /* restart timer for periodic mode */
+ if (mfgpt0_mode == CLOCK_EVT_MODE_PERIODIC)
+ outw(0xFFFF, MFGPT0_SETUP);
+
+ mfgpt0_clockevent.event_handler(&mfgpt0_clockevent);
+ return IRQ_HANDLED;
+}
/*
* Initialize the conversion factor and the min/max deltas of the clock event
@@ -121,14 +171,15 @@
*/
void __init setup_mfgpt0_timer(void)
{
- u32 basehi;
- struct clock_event_device *cd = &mfgpt_clockevent;
+ struct clock_event_device *cd = &mfgpt0_clockevent;
unsigned int cpu = smp_processor_id();
-
cd->cpumask = cpumask_of(cpu);
- clockevent_set_clock(cd, MFGPT_TICK_RATE);
- cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
- cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
+
+ cd->shift = 22;
+ cd->mult = div_sc(MFGPT_TICK_RATE(1, 3), NSEC_PER_SEC, cd->shift);
+
+ cd->min_delta_ns = clockevent_delta2ns(0xF, cd);
+ cd->max_delta_ns = clockevent_delta2ns(0xFFFF, cd);
/* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */
_wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
@@ -136,79 +187,24 @@
/* Enable Interrupt Gate 5 */
_wrmsr(DIVIL_MSR_REG(PIC_ZSEL_LOW), 0, 0x50000);
- /* get MFGPT base address */
- _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
-
+ enable_mfgpt0_counter();
clockevents_register_device(cd);
-
setup_irq(CS5536_MFGPT_INTR, &irq5);
}
-/*
- * Since the MFGPT overflows every tick, its not very useful
- * to just read by itself. So use jiffies to emulate a free
- * running counter:
- */
-static cycle_t mfgpt_read(struct clocksource *cs)
+static cycle_t mfgpt1_read_cycle(struct clocksource *cs)
{
- unsigned long flags;
- int count;
- u32 jifs;
- static int old_count;
- static u32 old_jifs;
-
- spin_lock_irqsave(&mfgpt_lock, flags);
- /*
- * Although our caller may have the read side of xtime_lock,
- * this is now a seqlock, and we are cheating in this routine
- * by having side effects on state that we cannot undo if
- * there is a collision on the seqlock and our caller has to
- * retry. (Namely, old_jifs and old_count.) So we must treat
- * jiffies as volatile despite the lock. We read jiffies
- * before latching the timer count to guarantee that although
- * the jiffies value might be older than the count (that is,
- * the counter may underflow between the last point where
- * jiffies was incremented and the point where we latch the
- * count), it cannot be newer.
- */
- jifs = jiffies;
- /* read the count */
- count = inw(MFGPT0_CNT);
-
- /*
- * It's possible for count to appear to go the wrong way for this
- * reason:
- *
- * The timer counter underflows, but we haven't handled the resulting
- * interrupt and incremented jiffies yet.
- *
- * Previous attempts to handle these cases intelligently were buggy, so
- * we just do the simple thing now.
- */
- if (count < old_count && jifs == old_jifs)
- count = old_count;
-
- old_count = count;
- old_jifs = jifs;
-
- spin_unlock_irqrestore(&mfgpt_lock, flags);
-
- return (cycle_t) (jifs * COMPARE) + count;
+ return inw(MFGPT1_CNT);
}
-static struct clocksource clocksource_mfgpt = {
- .name = "mfgpt",
- .rating = 120, /* Functional for real use, but not desired */
- .read = mfgpt_read,
- .mask = CLOCKSOURCE_MASK(32),
-};
-
-int __init init_mfgpt_clocksource(void)
+int __init init_mfgpt1_clocksource(void)
{
if (num_possible_cpus() > 1) /* MFGPT does not scale! */
return 0;
- return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
+ enable_mfgpt1_counter();
+
+ return clocksource_register_hz(&mfgpt1_clocksource, MFGPT_TICK_RATE(0, 1));
}
-arch_initcall(init_mfgpt_clocksource);
+arch_initcall(init_mfgpt1_clocksource);
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ohci.c b/arch/mips/loongson/common/cs5536/cs5536_ohci.c
index f7c905e..a181193 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_ohci.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_ohci.c
@@ -18,7 +18,7 @@
void pci_ohci_write_reg(int reg, u32 value)
{
- u32 hi = 0, lo = value;
+ u32 hi, lo;
switch (reg) {
case PCI_COMMAND:
@@ -73,77 +73,72 @@
u32 pci_ohci_read_reg(int reg)
{
- u32 conf_data = 0;
+ u32 cfg = 0;
u32 hi, lo;
switch (reg) {
case PCI_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_OHCI_DEVICE_ID, CS5536_VENDOR_ID);
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ cfg = CFG_PCI_VENDOR_ID(PCI_DEVICE_ID_AMD_CS5536_OHC,
+ PCI_VENDOR_ID_AMD);
break;
case PCI_COMMAND:
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
if (hi & PCI_COMMAND_MASTER)
- conf_data |= PCI_COMMAND_MASTER;
+ cfg |= PCI_COMMAND_MASTER;
if (hi & PCI_COMMAND_MEMORY)
- conf_data |= PCI_COMMAND_MEMORY;
+ cfg |= PCI_COMMAND_MEMORY;
break;
case PCI_STATUS:
- conf_data |= PCI_STATUS_66MHZ;
- conf_data |= PCI_STATUS_FAST_BACK;
+ cfg |= PCI_STATUS_66MHZ;
+ cfg |= PCI_STATUS_FAST_BACK;
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
if (lo & SB_PARE_ERR_FLAG)
- conf_data |= PCI_STATUS_PARITY;
- conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ cfg |= PCI_STATUS_PARITY;
+ cfg |= PCI_STATUS_DEVSEL_MEDIUM;
break;
case PCI_CLASS_REVISION:
_rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
- conf_data = lo & 0x000000ff;
- conf_data |= (CS5536_OHCI_CLASS_CODE << 8);
+ cfg = lo & 0x000000ff;
+ cfg |= (CS5536_OHCI_CLASS_CODE << 8);
break;
case PCI_CACHE_LINE_SIZE:
- conf_data =
- CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
- PCI_NORMAL_LATENCY_TIMER);
+ cfg = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+ PCI_NORMAL_LATENCY_TIMER);
break;
case PCI_BAR0_REG:
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
if (lo & SOFT_BAR_OHCI_FLAG) {
- conf_data = CS5536_OHCI_RANGE |
+ cfg = CS5536_OHCI_RANGE |
PCI_BASE_ADDRESS_SPACE_MEMORY;
lo &= ~SOFT_BAR_OHCI_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else {
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
- conf_data = lo & 0xffffff00;
- conf_data &= ~0x0000000f; /* 32bit mem */
+ cfg = lo & 0xffffff00;
+ cfg &= ~0x0000000f; /* 32bit mem */
}
break;
case PCI_CARDBUS_CIS:
- conf_data = PCI_CARDBUS_CIS_POINTER;
- break;
- case PCI_SUBSYSTEM_VENDOR_ID:
- conf_data =
- CFG_PCI_VENDOR_ID(CS5536_OHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
+ cfg = PCI_CARDBUS_CIS_POINTER;
break;
case PCI_ROM_ADDRESS:
- conf_data = PCI_EXPANSION_ROM_BAR;
+ cfg = PCI_EXPANSION_ROM_BAR;
break;
case PCI_CAPABILITY_LIST:
- conf_data = PCI_CAPLIST_USB_POINTER;
+ cfg = PCI_CAPLIST_USB_POINTER;
break;
case PCI_INTERRUPT_LINE:
- conf_data =
- CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
+ cfg = CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
break;
case PCI_OHCI_INT_REG:
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
if ((lo & 0x00000f00) == CS5536_USB_INTR)
- conf_data = 1;
+ cfg = 1;
break;
default:
break;
}
- return conf_data;
+ return cfg;
}
diff --git a/arch/mips/loongson/common/early_printk.c b/arch/mips/loongson/common/early_printk.c
index ced461b..89aecbf 100644
--- a/arch/mips/loongson/common/early_printk.c
+++ b/arch/mips/loongson/common/early_printk.c
@@ -10,9 +10,13 @@
* option) any later version.
*/
#include <linux/serial_reg.h>
+#include <linux/module.h>
+#include <asm/bootinfo.h>
#include <loongson.h>
+unsigned long _loongson_uart_base;
+
#define PORT(base, offset) (u8 *)(base + offset)
static inline unsigned int serial_in(unsigned char *base, int offset)
@@ -39,3 +43,29 @@
serial_out(uart_base, UART_TX, c);
}
+
+void __init prom_init_uart_base(void)
+{
+ unsigned long loongson_uart_base;
+
+ switch (mips_machtype) {
+ case MACH_LEMOTE_FL2E:
+ loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8;
+ break;
+ case MACH_LEMOTE_FL2F:
+ case MACH_LEMOTE_LL2F:
+ loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8;
+ break;
+ case MACH_LEMOTE_ML2F7:
+ case MACH_LEMOTE_YL2F89:
+ case MACH_DEXXON_GDIUM2F10:
+ case MACH_LEMOTE_NAS:
+ default:
+ /* The CPU provided serial port */
+ loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
+ break;
+ }
+
+ _loongson_uart_base =
+ (unsigned long)ioremap_nocache(loongson_uart_base, 8);
+}
diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c
index 0a18fcf..0e69c16 100644
--- a/arch/mips/loongson/common/env.c
+++ b/arch/mips/loongson/common/env.c
@@ -40,7 +40,6 @@
/* pmon passes arguments in 32bit pointers */
int *_prom_envp;
unsigned long bus_clock;
- unsigned int processor_id;
long l;
/* firmware arguments are initialized in head.S */
@@ -60,8 +59,7 @@
if (bus_clock == 0)
bus_clock = 66000000;
if (cpu_clock_freq == 0) {
- processor_id = (¤t_cpu_data)->processor_id;
- switch (processor_id & PRID_REV_MASK) {
+ switch (cpu_prid_rev()) {
case PRID_REV_LOONGSON2E:
cpu_clock_freq = 533080000;
break;
diff --git a/arch/mips/loongson/common/gpio.c b/arch/mips/loongson/common/gpio.c
index 2186990..8a1f77c 100644
--- a/arch/mips/loongson/common/gpio.c
+++ b/arch/mips/loongson/common/gpio.c
@@ -19,7 +19,6 @@
#include <loongson.h>
#include <linux/gpio.h>
-#define STLS2F_N_GPIO 4
#define STLS2F_GPIO_IN_OFFSET 16
static DEFINE_SPINLOCK(gpio_lock);
@@ -29,7 +28,7 @@
u32 val;
u32 mask;
- if (gpio >= STLS2F_N_GPIO)
+ if (gpio >= ARCH_NR_GPIOS)
return __gpio_get_value(gpio);
mask = 1 << (gpio + STLS2F_GPIO_IN_OFFSET);
@@ -46,7 +45,7 @@
u32 val;
u32 mask;
- if (gpio >= STLS2F_N_GPIO) {
+ if (gpio >= ARCH_NR_GPIOS) {
__gpio_set_value(gpio, state);
return ;
}
@@ -66,7 +65,7 @@
int gpio_cansleep(unsigned gpio)
{
- if (gpio < STLS2F_N_GPIO)
+ if (gpio < ARCH_NR_GPIOS)
return 0;
else
return __gpio_cansleep(gpio);
@@ -78,7 +77,7 @@
u32 temp;
u32 mask;
- if (gpio >= STLS2F_N_GPIO)
+ if (gpio >= ARCH_NR_GPIOS)
return -EINVAL;
spin_lock(&gpio_lock);
@@ -97,7 +96,7 @@
u32 temp;
u32 mask;
- if (gpio >= STLS2F_N_GPIO)
+ if (gpio >= ARCH_NR_GPIOS)
return -EINVAL;
gpio_set_value(gpio, level);
@@ -129,7 +128,7 @@
.direction_output = ls2f_gpio_direction_output,
.set = ls2f_gpio_set_value,
.base = 0,
- .ngpio = STLS2F_N_GPIO,
+ .ngpio = ARCH_NR_GPIOS,
};
static int __init ls2f_gpio_setup(void)
diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c
index ae7af1f..3083978 100644
--- a/arch/mips/loongson/common/init.c
+++ b/arch/mips/loongson/common/init.c
@@ -30,8 +30,10 @@
prom_init_env();
prom_init_memory();
+#ifdef CONFIG_EARLY_PRINTK
/*init the uart base address */
prom_init_uart_base();
+#endif
}
void __init prom_free_prom_memory(void)
diff --git a/arch/mips/loongson/common/irq.c b/arch/mips/loongson/common/irq.c
index 687003b..d62fa77 100644
--- a/arch/mips/loongson/common/irq.c
+++ b/arch/mips/loongson/common/irq.c
@@ -10,6 +10,10 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <asm/irq_cpu.h>
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+
#include <loongson.h>
/*
* the first level int-handler will jump here if it is a bonito irq
@@ -48,20 +52,32 @@
void __init arch_init_irq(void)
{
/*
- * Clear all of the interrupts while we change the able around a bit.
- * int-handler is not on bootstrap
+ * The vector addresses of the generic exceptions are in the cached
+ * address space.
*/
- clear_c0_status(ST0_IM | ST0_BEV);
+ clear_c0_status(ST0_BEV);
- /* no steer */
+ /* No steer */
LOONGSON_INTSTEER = 0;
/*
- * Mask out all interrupt by writing "1" to all bit position in
- * the interrupt reset reg.
+ * Clear all interrupts
*/
LOONGSON_INTENCLR = ~0;
+ /*
+ * Sets the first-level interrupt dispatcher:
+ *
+ * 0-15: i8259 interrupt (If CONFIG_I8259 selected)
+ * 16-23: mips cpu interrupt
+ * 32-63: bonito irq
+ */
+ mips_cpu_irq_init();
+ bonito_irq_init();
+#ifdef CONFIG_I8259
+ init_i8259_irqs();
+#endif
+
/* machine specific irq init */
mach_init_irq();
}
diff --git a/arch/mips/loongson/common/mem.c b/arch/mips/loongson/common/mem.c
index 8626a42..7aea259 100644
--- a/arch/mips/loongson/common/mem.c
+++ b/arch/mips/loongson/common/mem.c
@@ -14,39 +14,24 @@
#include <mem.h>
#include <pci.h>
+#define MB(x) ((x) << 20)
+
void __init prom_init_memory(void)
{
- add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM);
-
- add_memory_region(memsize << 20, LOONGSON_PCI_MEM_START - (memsize <<
- 20), BOOT_MEM_RESERVED);
-
+ add_memory_region(0x0, MB(memsize), BOOT_MEM_RAM);
+ add_memory_region(MB(memsize), LOONGSON_PCI_MEM_START - MB(memsize), BOOT_MEM_RESERVED);
#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
- {
- int bit;
-
- bit = fls(memsize + highmemsize);
- if (bit != ffs(memsize + highmemsize))
- bit += 20;
- else
- bit = bit + 20 - 1;
-
- /* set cpu window3 to map CPU to DDR: 2G -> 2G */
- LOONGSON_ADDRWIN_CPUTODDR(ADDRWIN_WIN3, 0x80000000ul,
- 0x80000000ul, (1 << bit));
- mmiowb();
- }
-#endif /* !CONFIG_CPU_SUPPORTS_ADDRWINCFG */
+ /* set cpu window3 to map CPU to DDR: 2G -> 0G */
+ LOONGSON_ADDRWIN_CPUTODDR(ADDRWIN_WIN3, 0x80000000ul, 0, MB(memsize + highmemsize));
+ mmiowb();
+#endif
#ifdef CONFIG_64BIT
if (highmemsize > 0)
- add_memory_region(LOONGSON_HIGHMEM_START,
- highmemsize << 20, BOOT_MEM_RAM);
-
+ add_memory_region(LOONGSON_HIGHMEM_START, MB(highmemsize), BOOT_MEM_RAM);
add_memory_region(LOONGSON_PCI_MEM_END + 1, LOONGSON_HIGHMEM_START -
- LOONGSON_PCI_MEM_END - 1, BOOT_MEM_RESERVED);
-
-#endif /* !CONFIG_64BIT */
+ LOONGSON_PCI_MEM_END - 1, BOOT_MEM_RESERVED);
+#endif
}
/* override of arch/mips/mm/cache.c: __uncached_access */
diff --git a/arch/mips/loongson/common/mtd.c b/arch/mips/loongson/common/mtd.c
new file mode 100644
index 0000000..49a57a7
--- /dev/null
+++ b/arch/mips/loongson/common/mtd.c
@@ -0,0 +1,91 @@
+/*
+ * Driver for flushing/dumping ROM of PMON on loongson family machines
+ *
+ * Copyright (C) 2008-2009 Lemote Inc.
+ * Author: Yan Hua <yanh@lemote.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+#include <loongson.h>
+
+#define FLASH_PHYS_ADDR LOONGSON_BOOT_BASE
+#define FLASH_SIZE 0x080000
+
+#define FLASH_PARTITION0_ADDR 0x00000000
+#define FLASH_PARTITION0_SIZE 0x00080000
+
+struct map_info flash_map = {
+ .name = "flash device",
+ .size = FLASH_SIZE,
+ .bankwidth = 1,
+};
+
+struct mtd_partition flash_parts[] = {
+ {
+ .name = "Bootloader",
+ .offset = FLASH_PARTITION0_ADDR,
+ .size = FLASH_PARTITION0_SIZE},
+};
+
+#define PARTITION_COUNT ARRAY_SIZE(flash_parts)
+
+static struct mtd_info *mymtd;
+
+int __init init_flash(void)
+{
+ printk(KERN_NOTICE "flash device: %x at %x\n",
+ FLASH_SIZE, FLASH_PHYS_ADDR);
+
+ flash_map.phys = FLASH_PHYS_ADDR;
+ flash_map.virt = ioremap(FLASH_PHYS_ADDR, FLASH_SIZE);
+
+ if (!flash_map.virt) {
+ printk(KERN_NOTICE "Failed to ioremap\n");
+ return -EIO;
+ }
+
+ simple_map_init(&flash_map);
+
+ mymtd = do_map_probe("cfi_probe", &flash_map);
+ if (mymtd) {
+ add_mtd_partitions(mymtd, flash_parts, PARTITION_COUNT);
+ printk(KERN_NOTICE "pmon flash device initialized\n");
+ return 0;
+ }
+
+ iounmap((void *)flash_map.virt);
+ return -ENXIO;
+}
+
+static void __exit cleanup_flash(void)
+{
+ if (mymtd) {
+ del_mtd_partitions(mymtd);
+ map_destroy(mymtd);
+ }
+ if (flash_map.virt) {
+ iounmap((void *)flash_map.virt);
+ flash_map.virt = 0;
+ }
+}
+
+module_init(init_flash);
+module_exit(cleanup_flash);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yanhua <yanh@lemote.com>");
+MODULE_DESCRIPTION("MTD driver for pmon flushing/dumping");
diff --git a/arch/mips/loongson/common/pci.c b/arch/mips/loongson/common/pci.c
index fa77844..a992931 100644
--- a/arch/mips/loongson/common/pci.c
+++ b/arch/mips/loongson/common/pci.c
@@ -50,11 +50,11 @@
LOONGSON_PCIMAP_WIN(0, 0);
/*
- * PCI-DMA to local mapping: [2G,2G+256M] -> [0M,256M]
+ * PCI-DMA to local mapping: [2G,4G] -> [0M,2G]
*/
LOONGSON_PCIBASE0 = 0x80000000ul; /* base: 2G -> mmap: 0M */
- /* size: 256M, burst transmission, pre-fetch enable, 64bit */
- LOONGSON_PCI_HIT0_SEL_L = 0xc000000cul;
+ /* size: 2G, burst transmission, pre-fetch enable, 64bit */
+ LOONGSON_PCI_HIT0_SEL_L = 0x8000000cul;
LOONGSON_PCI_HIT0_SEL_H = 0xfffffffful;
LOONGSON_PCI_HIT1_SEL_L = 0x00000006ul; /* set this BAR as invalid */
LOONGSON_PCI_HIT1_SEL_H = 0x00000000ul;
diff --git a/arch/mips/loongson/common/platform.c b/arch/mips/loongson/common/platform.c
index 0ed3832..4fed18c 100644
--- a/arch/mips/loongson/common/platform.c
+++ b/arch/mips/loongson/common/platform.c
@@ -13,16 +13,14 @@
#include <linux/platform_device.h>
static struct platform_device loongson2_cpufreq_device = {
- .name = "loongson2_cpufreq",
+ .name = "l2_cpufreq",
.id = -1,
};
static int __init loongson2_cpufreq_init(void)
{
- struct cpuinfo_mips *c = ¤t_cpu_data;
-
/* Only 2F revision and it's successors support CPUFreq */
- if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_LOONGSON2F)
+ if (cpu_prid_rev() >= PRID_REV_LOONGSON2F)
return platform_device_register(&loongson2_cpufreq_device);
return -ENODEV;
diff --git a/arch/mips/loongson/common/serial.c b/arch/mips/loongson/common/serial.c
index 5f2b78a..c828600 100644
--- a/arch/mips/loongson/common/serial.c
+++ b/arch/mips/loongson/common/serial.c
@@ -10,6 +10,7 @@
* Author: Wu Zhangjin (wuzhangjin@gmail.com)
*/
+#include <linux/module.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/serial_8250.h>
@@ -19,58 +20,44 @@
#include <loongson.h>
#include <machine.h>
-#define PORT(int) \
+#define PORT(int, base_baud, io_type, port) \
{ \
.irq = int, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
+ .uartclk = base_baud, \
+ .iotype = io_type, \
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
.regshift = 0, \
+ .iobase = port, \
}
-#define PORT_M(int) \
-{ \
- .irq = MIPS_CPU_IRQ_BASE + (int), \
- .uartclk = 3686400, \
- .iotype = UPIO_MEM, \
- .membase = (void __iomem *)NULL, \
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
- .regshift = 0, \
-}
-
-static struct plat_serial8250_port uart8250_data[][2] = {
- [MACH_LOONGSON_UNKNOWN] {},
- [MACH_LEMOTE_FL2E] {PORT(4), {} },
- [MACH_LEMOTE_FL2F] {PORT(3), {} },
- [MACH_LEMOTE_ML2F7] {PORT_M(3), {} },
- [MACH_LEMOTE_YL2F89] {PORT_M(3), {} },
- [MACH_DEXXON_GDIUM2F10] {PORT_M(3), {} },
- [MACH_LEMOTE_NAS] {PORT_M(3), {} },
- [MACH_LEMOTE_LL2F] {PORT(3), {} },
- [MACH_LOONGSON_END] {},
+static struct plat_serial8250_port uart8250_data[] = {
+ /* ttyS0: cpu_uart0 Yeeloong, Gdium, UNAS, ... */
+ PORT((MIPS_CPU_IRQ_BASE + 3), 3686400, UPIO_MEM, 0x3f8),
+ /* ttyS1: sb_uart1 2E */
+ PORT(4, 1843200, UPIO_PORT, 0x3f8),
+ /* ttyS2: sb_uart2 fuloong2f */
+ PORT(3, 1843200, UPIO_PORT, 0x2f8),
+ {},
};
static struct platform_device uart8250_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = uart8250_data,
+ },
};
static int __init serial_init(void)
{
- unsigned char iotype;
+ uart8250_data[0].membase = (void __iomem *)ioremap_nocache(
+ LOONGSON_LIO1_BASE + uart8250_data[0].iobase, 8);
- iotype = uart8250_data[mips_machtype][0].iotype;
-
- if (UPIO_MEM == iotype)
- uart8250_data[mips_machtype][0].membase =
- (void __iomem *)_loongson_uart_base;
- else if (UPIO_PORT == iotype)
- uart8250_data[mips_machtype][0].iobase =
- loongson_uart_base - LOONGSON_PCIIO_BASE;
-
- uart8250_device.dev.platform_data = uart8250_data[mips_machtype];
-
- return platform_device_register(&uart8250_device);
+ platform_device_register(&uart8250_device);
+ return 0;
}
device_initcall(serial_init);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("liu shiwei <liushiwei@anheng.com.cn>");
+MODULE_DESCRIPTION("loongson serial");
diff --git a/arch/mips/loongson/common/time.c b/arch/mips/loongson/common/time.c
index 262a1f6..eebbeef 100644
--- a/arch/mips/loongson/common/time.c
+++ b/arch/mips/loongson/common/time.c
@@ -10,6 +10,8 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
+#include <linux/rtc.h>
+
#include <asm/mc146818-time.h>
#include <asm/time.h>
@@ -24,8 +26,81 @@
setup_mfgpt0_timer();
}
+#ifdef CONFIG_LOONGSON_MC146818
void read_persistent_clock(struct timespec *ts)
{
ts->tv_sec = mc146818_get_cmos_time();
ts->tv_nsec = 0;
}
+#else
+
+/* If no CMOS RTC, use the one below */
+
+/*
+ * Cloned from drivers/rtc/hctosys.c
+ *
+ * If CONFIG_RTC_HCTOSYS=y is enabled, the system time can be set from the
+ * hardware clock(when boot and resuming from suspend), this may be also done
+ * (duplicately) by the timekeeper, which may need to be avoided(TODO).
+ *
+ * read_persistent_clock() may be useful in some places, e.g. there is not
+ * peristent clock in the system, we can use this to recover the system time.
+ *
+ * Note: The device indicated by CONFIG_RTC_HCTOSYS_DEVICE must be the one
+ * created by the RTC driver. Use Gdium as an example, We must disable the
+ * rt_cmos driver If we want to use the rtc_m41t80 driver for
+ * CONFIG_RTC_HCTOSYS_DEVICE is configured as /dev/rtc0, if rtc_cmos is
+ * enabled, rtc_cmos driver will be used, but it is not supported by Gdium.
+ * So, for Gdium, please ensure "# CONFIG_RTC_DRV_CMOS is not set"
+ */
+
+#ifdef CONFIG_RTC_HCTOSYS
+void read_persistent_clock(struct timespec *ts)
+{
+ int err = -ENODEV;
+ struct rtc_time tm;
+ struct rtc_device *rtc;
+
+ /* We can not access the RTC device before it is initialized ... */
+ if (rtc_hctosys_ret != 0) {
+ ts->tv_sec = 0;
+ ts->tv_nsec = 0;
+ return;
+ }
+
+ rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
+ if (rtc == NULL) {
+ pr_err("%s: unable to open rtc device (%s)\n",
+ __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+ goto err_open;
+ }
+
+ err = rtc_read_time(rtc, &tm);
+ if (err) {
+ dev_err(rtc->dev.parent,
+ "hctosys: unable to read the hardware clock\n");
+ goto err_read;
+
+ }
+
+ err = rtc_valid_tm(&tm);
+ if (err) {
+ dev_err(rtc->dev.parent,
+ "hctosys: invalid date/time\n");
+ goto err_invalid;
+ }
+
+ ts->tv_nsec = NSEC_PER_SEC >> 1,
+ rtc_tm_to_time(&tm, &ts->tv_sec);
+
+err_invalid:
+err_read:
+ rtc_class_close(rtc);
+
+err_open:
+ rtc_hctosys_ret = err;
+}
+#endif /* CONFIG_RTC_HCTOSYS */
+
+#endif /* !CONFIG_LOONGSON_MC146818 */
diff --git a/arch/mips/loongson/common/uart_base.c b/arch/mips/loongson/common/uart_base.c
deleted file mode 100644
index e192ad0..0000000
--- a/arch/mips/loongson/common/uart_base.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2009 Lemote Inc.
- * Author: Wu Zhangjin, wuzhangjin@gmail.com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/module.h>
-#include <asm/bootinfo.h>
-
-#include <loongson.h>
-
-/* ioremapped */
-unsigned long _loongson_uart_base;
-EXPORT_SYMBOL(_loongson_uart_base);
-/* raw */
-unsigned long loongson_uart_base;
-EXPORT_SYMBOL(loongson_uart_base);
-
-void prom_init_loongson_uart_base(void)
-{
- switch (mips_machtype) {
- case MACH_LEMOTE_FL2E:
- loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8;
- break;
- case MACH_LEMOTE_FL2F:
- case MACH_LEMOTE_LL2F:
- loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8;
- break;
- case MACH_LEMOTE_ML2F7:
- case MACH_LEMOTE_YL2F89:
- case MACH_DEXXON_GDIUM2F10:
- case MACH_LEMOTE_NAS:
- default:
- /* The CPU provided serial port */
- loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
- break;
- }
-
- _loongson_uart_base =
- (unsigned long)ioremap_nocache(loongson_uart_base, 8);
-}
diff --git a/arch/mips/loongson/fuloong-2e/irq.c b/arch/mips/loongson/fuloong-2e/irq.c
index ef5ec8f..232930e 100644
--- a/arch/mips/loongson/fuloong-2e/irq.c
+++ b/arch/mips/loongson/fuloong-2e/irq.c
@@ -9,7 +9,6 @@
*/
#include <linux/interrupt.h>
-#include <asm/irq_cpu.h>
#include <asm/i8259.h>
#include <loongson.h>
@@ -57,11 +56,6 @@
LOONGSON_INTEDGE = LOONGSON_ICU_SYSTEMERR | LOONGSON_ICU_MASTERERR |
LOONGSON_ICU_RETRYERR | LOONGSON_ICU_MBOXES;
- /* Sets the first-level interrupt dispatcher. */
- mips_cpu_irq_init();
- init_i8259_irqs();
- bonito_irq_init();
-
/* bonito irq at IP2 */
setup_irq(MIPS_CPU_IRQ_BASE + 2, &cascade_irqaction);
/* 8259 irq at IP5 */
diff --git a/arch/mips/loongson/gdium/Makefile b/arch/mips/loongson/gdium/Makefile
new file mode 100644
index 0000000..f3f4f51
--- /dev/null
+++ b/arch/mips/loongson/gdium/Makefile
@@ -0,0 +1,6 @@
+# Makefile for gdium
+
+obj-y += irq.o reset.o platform.o
+
+obj-$(CONFIG_MFD_SM501) += sm501-pwm.o
+obj-$(CONFIG_GDIUM_PWM_CLOCK) += gdium-clock.o
diff --git a/arch/mips/loongson/gdium/gdium-clock.c b/arch/mips/loongson/gdium/gdium-clock.c
new file mode 100644
index 0000000..fdbf42a
--- /dev/null
+++ b/arch/mips/loongson/gdium/gdium-clock.c
@@ -0,0 +1,234 @@
+/*
+ * Doesn't work really well. When used, the clocksource is producing
+ * bad timings and the clockevent can't be used (don't have one shot feature
+ * thus can't switch on the fly and the pwm is initialised too late to be able
+ * to use it at boot time).
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pwm.h>
+#include <linux/clocksource.h>
+#include <linux/debugfs.h>
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+#include <asm/mips-boards/bonito64.h>
+#include <asm/time.h>
+
+#include <loongson.h>
+
+#define CLOCK_PWM 1
+#define CLOCK_PWM_FREQ 1500000 /* Freq in Hz */
+#define CLOCK_LATCH ((CLOCK_PWM_FREQ + HZ/2) / HZ)
+#define CLOCK_PWM_PERIOD (1000000000/CLOCK_PWM_FREQ) /* period ns */
+#define CLOCK_PWM_DUTY 50
+#define CLOCK_PWM_IRQ (MIPS_CPU_IRQ_BASE + 4)
+
+static const char drv_name[] = "gdium-clock";
+
+static struct pwm_device *clock_pwm;
+
+static DEFINE_SPINLOCK(clock_pwm_lock);
+static uint64_t clock_tick;
+
+static irqreturn_t gdium_pwm_clock_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = dev_id;
+ unsigned long flag;
+
+ spin_lock_irqsave(&clock_pwm_lock, flag);
+ clock_tick++;
+ /* wait intn2 to finish */
+ do {
+ LOONGSON_INTENCLR = (1 << 13);
+ } while (LOONGSON_INTISR & (1 << 13));
+ spin_unlock_irqrestore(&clock_pwm_lock, flag);
+
+ if (cd && cd->event_handler)
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static cycle_t gdium_pwm_clock_read(struct clocksource *cs)
+{
+ unsigned long flag;
+ uint32_t jifs;
+ uint64_t ticks;
+
+ spin_lock_irqsave(&clock_pwm_lock, flag);
+ jifs = jiffies;
+ ticks = clock_tick;
+ spin_unlock_irqrestore(&clock_pwm_lock, flag);
+ /* return (cycle_t)ticks; */
+ return (cycle_t)(CLOCK_LATCH * jifs);
+}
+
+static struct clocksource gdium_pwm_clock_clocksource = {
+ .name = "gdium_csrc",
+ .read = gdium_pwm_clock_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_MUST_VERIFY,
+ .shift = 20,
+};
+
+/* Debug fs */
+static int gdium_pwm_clock_show(struct seq_file *s, void *p)
+{
+ unsigned long flag;
+ uint64_t ticks;
+
+ spin_lock_irqsave(&clock_pwm_lock, flag);
+ ticks = clock_tick;
+ spin_unlock_irqrestore(&clock_pwm_lock, flag);
+ seq_printf(s, "%lld\n", ticks);
+ return 0;
+}
+
+static int gdium_pwm_clock_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, gdium_pwm_clock_show, inode->i_private);
+}
+
+static const struct file_operations gdium_pwm_clock_fops = {
+ .open = gdium_pwm_clock_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+static struct dentry *debugfs_file;
+
+static void gdium_pwm_clock_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ /* Nothing to do ... */
+}
+
+static struct clock_event_device gdium_pwm_clock_cevt = {
+ .name = "gdium_cevt",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
+ .rating = 299,
+ .irq = CLOCK_PWM_IRQ,
+ .set_mode = gdium_pwm_clock_set_mode,
+};
+
+static struct platform_device_id platform_device_ids[] = {
+ {
+ .name = "gdium-pwmclk",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, platform_device_ids);
+
+static struct platform_driver gdium_pwm_clock_driver = {
+ .driver = {
+ .name = drv_name,
+ .owner = THIS_MODULE,
+ },
+ .id_table = platform_device_ids,
+};
+
+static int gdium_pwm_clock_drvinit(void)
+{
+ int ret;
+ struct clocksource *cs = &gdium_pwm_clock_clocksource;
+ struct clock_event_device *cd = &gdium_pwm_clock_cevt;
+ unsigned int cpu = smp_processor_id();
+
+ clock_tick = 0;
+
+ clock_pwm = pwm_request(CLOCK_PWM, drv_name);
+ if (clock_pwm == NULL) {
+ pr_err("unable to request PWM for Gdium clock\n");
+ return -EBUSY;
+ }
+ ret = pwm_config(clock_pwm, CLOCK_PWM_DUTY, CLOCK_PWM_PERIOD);
+ if (ret) {
+ pr_err("unable to configure PWM for Gdium clock\n");
+ goto err_pwm_request;
+ }
+ ret = pwm_enable(clock_pwm);
+ if (ret) {
+ pr_err("unable to enable PWM for Gdium clock\n");
+ goto err_pwm_request;
+ }
+
+ cd->cpumask = cpumask_of(cpu);
+
+ cd->shift = 22;
+ cd->mult = div_sc(CLOCK_PWM_FREQ, NSEC_PER_SEC, cd->shift);
+ cd->max_delta_ns = clockevent_delta2ns(0x7FFF, cd);
+ cd->min_delta_ns = clockevent_delta2ns(0xF, cd);
+ clockevents_register_device(&gdium_pwm_clock_cevt);
+
+ /* SM501 PWM1 connected to intn2 <->ip4 */
+ LOONGSON_INTPOL = (1 << 13);
+ LOONGSON_INTEDGE &= ~(1 << 13);
+ ret = request_irq(CLOCK_PWM_IRQ, gdium_pwm_clock_interrupt, IRQF_DISABLED, drv_name, &gdium_pwm_clock_cevt);
+ if (ret) {
+ pr_err("Can't claim irq\n");
+ goto err_pwm_disable;
+ }
+
+ cs->rating = 200;
+ cs->mult = clocksource_hz2mult(CLOCK_PWM_FREQ, cs->shift);
+ ret = clocksource_register(&gdium_pwm_clock_clocksource);
+ if (ret) {
+ pr_err("Can't register clocksource\n");
+ goto err_irq;
+ }
+ pr_info("Clocksource registered with shift %d and mult %d\n",
+ cs->shift, cs->mult);
+
+ debugfs_file = debugfs_create_file(drv_name, S_IFREG | S_IRUGO,
+ NULL, NULL, &gdium_pwm_clock_fops);
+
+ return 0;
+
+err_irq:
+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt);
+err_pwm_disable:
+ pwm_disable(clock_pwm);
+err_pwm_request:
+ pwm_free(clock_pwm);
+ return ret;
+}
+
+static void gdium_pwm_clock_drvexit(void)
+{
+ free_irq(CLOCK_PWM_IRQ, &gdium_pwm_clock_cevt);
+ pwm_disable(clock_pwm);
+ pwm_free(clock_pwm);
+}
+
+
+static int __devinit gdium_pwm_clock_init(void)
+{
+ int ret = gdium_pwm_clock_drvinit();
+
+ if (ret) {
+ pr_err("Fail to register gdium clock driver\n");
+ return ret;
+ }
+
+ return platform_driver_register(&gdium_pwm_clock_driver);
+}
+
+static void __exit gdium_pwm_clock_cleanup(void)
+{
+ gdium_pwm_clock_drvexit();
+ platform_driver_unregister(&gdium_pwm_clock_driver);
+}
+
+module_init(gdium_pwm_clock_init);
+module_exit(gdium_pwm_clock_cleanup);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Gdium PWM clock driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gdium-pwmclk");
diff --git a/arch/mips/loongson/gdium/irq.c b/arch/mips/loongson/gdium/irq.c
new file mode 100644
index 0000000..2415d20
--- /dev/null
+++ b/arch/mips/loongson/gdium/irq.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 Lemote Inc.
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ *
+ * Copyright (c) 2010 yajin <yajin@vm-kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <loongson.h>
+#include <machine.h>
+
+#define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */
+#define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */
+#define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */
+
+void mach_irq_dispatch(unsigned int pending)
+{
+ if (pending & CAUSEF_IP7)
+ do_IRQ(LOONGSON_TIMER_IRQ);
+ else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */
+ do_perfcnt_IRQ();
+ bonito_irqdispatch();
+ } else if (pending & CAUSEF_IP3) /* CPU UART */
+ do_IRQ(LOONGSON_UART_IRQ);
+#if defined(CONFIG_GDIUM_PWM_CLOCK) || defined(CONFIG_GDIUM_PWM_CLOCK_MODULE)
+ else if (pending & CAUSEF_IP4) /* SM501 PWM clock */
+ do_IRQ(MIPS_CPU_IRQ_BASE + 4);
+#endif
+ else
+ spurious_interrupt();
+}
+
+static irqreturn_t ip6_action(int cpl, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+struct irqaction ip6_irqaction = {
+ .handler = ip6_action,
+ .name = "cascade",
+ .flags = IRQF_SHARED,
+};
+
+void __init mach_init_irq(void)
+{
+ /* setup north bridge irq (bonito) */
+ setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction);
+}
diff --git a/arch/mips/loongson/gdium/platform.c b/arch/mips/loongson/gdium/platform.c
new file mode 100644
index 0000000..ffafba4
--- /dev/null
+++ b/arch/mips/loongson/gdium/platform.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pwm_backlight.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+
+#define GDIUM_GPIO_BASE 224
+
+static struct i2c_board_info __initdata sm502dev_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("lm75", 0x48),
+ },
+ {
+ I2C_BOARD_INFO("m41t83", 0x68),
+ },
+ {
+ I2C_BOARD_INFO("gdium-laptop", 0x40),
+ },
+};
+
+static int sm502dev_backlight_init(struct device *dev)
+{
+ /* Add gpio request stuff here */
+ return 0;
+}
+
+static void sm502dev_backlight_exit(struct device *dev)
+{
+ /* Add gpio free stuff here */
+}
+
+static struct platform_pwm_backlight_data backlight_data = {
+ .pwm_id = 0,
+ .max_brightness = 15,
+ .dft_brightness = 8,
+ .pwm_period_ns = 50000, /* 20 kHz */
+ .init = sm502dev_backlight_init,
+ .exit = sm502dev_backlight_exit,
+};
+
+static struct platform_device backlight = {
+ .name = "pwm-backlight",
+ .dev = {
+ .platform_data = &backlight_data,
+ },
+ .id = -1,
+};
+
+/*
+ * Warning this stunt is very dangerous
+ * as the sm501 gpio have dynamic numbers...
+ */
+/* bus 0 is the one for the ST7, DS75 etc... */
+static struct i2c_gpio_platform_data i2c_gpio0_data = {
+#if CONFIG_GDIUM_VERSION > 2
+ .sda_pin = GDIUM_GPIO_BASE + 13,
+ .scl_pin = GDIUM_GPIO_BASE + 6,
+#else
+ .sda_pin = 192+15,
+ .scl_pin = 192+14,
+#endif
+ .udelay = 5,
+ .timeout = HZ / 10,
+ .sda_is_open_drain = 0,
+ .scl_is_open_drain = 0,
+};
+
+static struct platform_device i2c_gpio0_device = {
+ .name = "i2c-gpio",
+ .id = 0,
+ .dev = { .platform_data = &i2c_gpio0_data, },
+};
+
+/* bus 1 is for the CRT/VGA external screen */
+static struct i2c_gpio_platform_data i2c_gpio1_data = {
+ .sda_pin = GDIUM_GPIO_BASE + 10,
+ .scl_pin = GDIUM_GPIO_BASE + 9,
+ .udelay = 5,
+ .timeout = HZ / 10,
+ .sda_is_open_drain = 0,
+ .scl_is_open_drain = 0,
+};
+
+static struct platform_device i2c_gpio1_device = {
+ .name = "i2c-gpio",
+ .id = 1,
+ .dev = { .platform_data = &i2c_gpio1_data, },
+};
+
+static struct platform_device gdium_clock = {
+ .name = "gdium-pwmclk",
+ .id = -1,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &i2c_gpio0_device,
+ &i2c_gpio1_device,
+ &backlight,
+ &gdium_clock,
+};
+
+static int __init gdium_platform_devices_setup(void)
+{
+ int ret;
+
+ pr_info("Registering gdium platform devices\n");
+
+ ret = i2c_register_board_info(0, sm502dev_i2c_devices,
+ ARRAY_SIZE(sm502dev_i2c_devices));
+
+ if (ret != 0) {
+ pr_info("Error while registering platform devices: %d\n", ret);
+ return ret;
+ }
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+
+ return 0;
+}
+
+/*
+ * some devices are on the pwm stuff which is behind the mfd which is
+ * behind the pci bus so arch_initcall can't work because too early
+ */
+late_initcall(gdium_platform_devices_setup);
diff --git a/arch/mips/loongson/gdium/reset.c b/arch/mips/loongson/gdium/reset.c
new file mode 100644
index 0000000..8289f95
--- /dev/null
+++ b/arch/mips/loongson/gdium/reset.c
@@ -0,0 +1,22 @@
+/* Board-specific reboot/shutdown routines
+ *
+ * Copyright (C) 2010 yajin <yajin@vm-kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <loongson.h>
+
+void mach_prepare_shutdown(void)
+{
+ LOONGSON_GPIOIE &= ~(1<<1);
+ LOONGSON_GPIODATA |= (1<<1);
+}
+
+void mach_prepare_reboot(void)
+{
+ LOONGSON_GPIOIE &= ~(1<<2);
+ LOONGSON_GPIODATA &= ~(1<<2);
+}
diff --git a/arch/mips/loongson/gdium/sm501-pwm.c b/arch/mips/loongson/gdium/sm501-pwm.c
new file mode 100644
index 0000000..5af3b23
--- /dev/null
+++ b/arch/mips/loongson/gdium/sm501-pwm.c
@@ -0,0 +1,465 @@
+/*
+ * SM501 PWM clock
+ * Copyright (C) 2009-2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pwm.h>
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static const char drv_name[] = "sm501-pwm";
+
+#define INPUT_CLOCK 96 /* MHz */
+#define PWM_COUNT 3
+
+#define SM501PWM_HIGH_COUNTER (1<<20)
+#define SM501PWM_LOW_COUNTER (1<<8)
+#define SM501PWM_CLOCK_DIVIDE (1>>4)
+#define SM501PWM_IP (1<<3)
+#define SM501PWM_I (1<<2)
+#define SM501PWM_E (1<<0)
+
+struct pwm_device {
+ struct list_head node;
+ struct device *dev;
+ void __iomem *regs;
+ int duty_ns;
+ int period_ns;
+ char enabled;
+ void (*handler)(struct pwm_device *pwm);
+
+ const char *label;
+ unsigned int use_count;
+ unsigned int pwm_id;
+};
+
+struct sm501pwm_info {
+ void __iomem *regs;
+ int irq;
+ struct resource *res;
+ struct device *dev;
+ struct dentry *debugfs;
+
+ struct pwm_device pwm[3];
+};
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ unsigned int high, low, divider;
+ int divider1, divider2;
+ unsigned long long delay;
+
+ if (!pwm || !pwm->regs || period_ns == 0 || duty_ns > period_ns)
+ return -EINVAL;
+
+ /* Get delay
+ * We're loosing some precision but multiplying then dividing
+ * will overflow
+ */
+ if (period_ns > 1000) {
+ delay = period_ns / 1000;
+ delay *= INPUT_CLOCK;
+ } else {
+ delay = period_ns * 96;
+ delay /= 1000;
+ }
+
+ /* Get the number of clock low and high */
+ high = delay * duty_ns / period_ns;
+ low = delay - high;
+
+ /* Get divider to make 'low' and 'high' fit into 12 bits */
+ /* No need to say that the divider must be >= 0 */
+ divider1 = fls(low)-12;
+ divider2 = fls(high)-12;
+
+ if (divider1 < 0)
+ divider1 = 0;
+ if (divider2 < 0)
+ divider2 = 0;
+
+ divider = max(divider1, divider2);
+
+ low >>= divider;
+ high >>= divider;
+
+ pwm->duty_ns = duty_ns;
+ pwm->period_ns = period_ns;
+
+ writel((high<<20)|(low<<8)|(divider<<4), pwm->regs);
+ return 0;
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+ u32 reg;
+
+ if (!pwm)
+ return -EINVAL;
+
+ switch (pwm->pwm_id) {
+ case 0:
+ sm501_configure_gpio(pwm->dev->parent, 29, 1);
+ break;
+ case 1:
+ sm501_configure_gpio(pwm->dev->parent, 30, 1);
+ break;
+ case 2:
+ sm501_configure_gpio(pwm->dev->parent, 31, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ reg = readl(pwm->regs);
+ reg |= (SM501PWM_IP | SM501PWM_E);
+ writel(reg, pwm->regs);
+ pwm->enabled = 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+ u32 reg;
+
+ if (!pwm)
+ return;
+
+ reg = readl(pwm->regs);
+ reg &= ~(SM501PWM_IP | SM501PWM_E);
+ writel(reg, pwm->regs);
+
+ switch (pwm->pwm_id) {
+ case 0:
+ sm501_configure_gpio(pwm->dev->parent, 29, 0);
+ break;
+ case 1:
+ sm501_configure_gpio(pwm->dev->parent, 30, 0);
+ break;
+ case 2:
+ sm501_configure_gpio(pwm->dev->parent, 31, 0);
+ break;
+ default:
+ break;
+ }
+ pwm->enabled = 0;
+}
+EXPORT_SYMBOL(pwm_disable);
+
+static DEFINE_MUTEX(pwm_lock);
+static LIST_HEAD(pwm_list);
+
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+ struct pwm_device *pwm;
+ int found = 0;
+
+ mutex_lock(&pwm_lock);
+
+ list_for_each_entry(pwm, &pwm_list, node) {
+ if (pwm->pwm_id == pwm_id && pwm->use_count == 0) {
+ pwm->use_count++;
+ pwm->label = label;
+ found = 1;
+ break;
+ }
+ }
+
+ mutex_unlock(&pwm_lock);
+
+ return (found) ? pwm : NULL;
+}
+EXPORT_SYMBOL(pwm_request);
+
+void pwm_free(struct pwm_device *pwm)
+{
+ mutex_lock(&pwm_lock);
+
+ if (pwm->use_count) {
+ pwm->use_count--;
+ pwm->label = NULL;
+ } else
+ dev_warn(pwm->dev, "PWM device already freed\n");
+
+ mutex_unlock(&pwm_lock);
+}
+EXPORT_SYMBOL(pwm_free);
+
+int pwm_int_enable(struct pwm_device *pwm)
+{
+ unsigned long conf;
+
+ if (!pwm || !pwm->regs || !pwm->handler)
+ return -EINVAL;
+
+ conf = readl(pwm->regs);
+ conf |= SM501PWM_I;
+ writel(conf, pwm->regs);
+ return 0;
+}
+EXPORT_SYMBOL(pwm_int_enable);
+
+int pwm_int_disable(struct pwm_device *pwm)
+{
+ unsigned long conf;
+
+ if (!pwm || !pwm->regs || !pwm->handler)
+ return -EINVAL;
+
+ conf = readl(pwm->regs);
+ conf &= ~SM501PWM_I;
+ writel(conf, pwm->regs);
+ return 0;
+}
+EXPORT_SYMBOL(pwm_int_disable);
+
+int pwm_set_handler(struct pwm_device *pwm,
+ void (*handler)(struct pwm_device *pwm))
+{
+ if (!pwm || !handler)
+ return -EINVAL;
+ pwm->handler = handler;
+ return 0;
+}
+EXPORT_SYMBOL(pwm_set_handler);
+
+static irqreturn_t sm501pwm_irq(int irq, void *dev_id)
+{
+ unsigned long value;
+ struct sm501pwm_info *info = (struct sm501pwm_info *)dev_id;
+ struct pwm_device *pwm;
+ int i;
+
+ value = sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 0);
+
+ /* Check is the interrupt is for us */
+ if (value & (1<<22)) {
+ for (i = 0 ; i < PWM_COUNT ; i++) {
+ /*
+ * Find which pwm triggered the interrupt
+ * and ack
+ */
+ value = readl(info->regs + i*4);
+ if (value & SM501PWM_IP)
+ writel(value | SM501PWM_IP, info->regs + i*4);
+
+ pwm = &info->pwm[i];
+ if (pwm->handler)
+ pwm->handler(pwm);
+ }
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static void add_pwm(int id, struct sm501pwm_info *info)
+{
+ struct pwm_device *pwm = &info->pwm[id];
+
+ pwm->use_count = 0;
+ pwm->pwm_id = id;
+ pwm->dev = info->dev;
+ pwm->regs = info->regs + id * 4;
+
+ mutex_lock(&pwm_lock);
+ list_add_tail(&pwm->node, &pwm_list);
+ mutex_unlock(&pwm_lock);
+}
+
+static void del_pwm(int id, struct sm501pwm_info *info)
+{
+ struct pwm_device *pwm = &info->pwm[id];
+
+ pwm->use_count = 0;
+ pwm->pwm_id = -1;
+ mutex_lock(&pwm_lock);
+ list_del(&pwm->node);
+ mutex_unlock(&pwm_lock);
+}
+
+/* Debug fs */
+static int sm501pwm_show(struct seq_file *s, void *p)
+{
+ struct pwm_device *pwm;
+
+ mutex_lock(&pwm_lock);
+ list_for_each_entry(pwm, &pwm_list, node) {
+ if (pwm->use_count) {
+ seq_printf(s, "pwm-%d (%12s) %d %d %s\n",
+ pwm->pwm_id, pwm->label,
+ pwm->duty_ns, pwm->period_ns,
+ pwm->enabled ? "on" : "off");
+ seq_printf(s, " %08x\n", readl(pwm->regs));
+ }
+ }
+ mutex_unlock(&pwm_lock);
+
+ return 0;
+}
+
+static int sm501pwm_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, sm501pwm_show, inode->i_private);
+}
+
+static const struct file_operations sm501pwm_fops = {
+ .open = sm501pwm_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int __init sm501pwm_probe(struct platform_device *pdev)
+{
+ struct sm501pwm_info *info;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret = 0;
+ int res_len;
+ int i;
+
+ info = kzalloc(sizeof(struct sm501pwm_info), GFP_KERNEL);
+ if (!info) {
+ dev_err(dev, "Allocation failure\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ info->dev = dev;
+ platform_set_drvdata(pdev, info);
+
+ /* Get irq number */
+ info->irq = platform_get_irq(pdev, 0);
+ if (!info->irq) {
+ dev_err(dev, "no irq found\n");
+ ret = -ENODEV;
+ goto err_alloc;
+ }
+
+ /* Get regs address */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "No memory resource found\n");
+ ret = -ENODEV;
+ goto err_alloc;
+ }
+ info->res = res;
+ res_len = (res->end - res->start)+1;
+
+ if (!request_mem_region(res->start, res_len, drv_name)) {
+ dev_err(dev, "Can't request iomem resource\n");
+ ret = -EBUSY;
+ goto err_alloc;
+ }
+
+ info->regs = ioremap(res->start, res_len);
+ if (!info->regs) {
+ dev_err(dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+
+ ret = request_irq(info->irq, sm501pwm_irq, IRQF_SHARED, drv_name, info);
+ if (ret != 0) {
+ dev_err(dev, "can't get irq\n");
+ goto err_map;
+ }
+
+
+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 1);
+
+ for (i = 0; i < 3; i++)
+ add_pwm(i, info);
+
+ dev_info(dev, "SM501 PWM Found at %lx irq %d\n",
+ (unsigned long)info->res->start, info->irq);
+
+ info->debugfs = debugfs_create_file("pwm", S_IFREG | S_IRUGO,
+ NULL, info, &sm501pwm_fops);
+
+
+ return 0;
+
+err_map:
+ iounmap(info->regs);
+
+err_mem:
+ release_mem_region(res->start, res_len);
+
+err_alloc:
+ kfree(info);
+ platform_set_drvdata(pdev, NULL);
+err:
+ return ret;
+}
+
+static int sm501pwm_remove(struct platform_device *pdev)
+{
+ struct sm501pwm_info *info = platform_get_drvdata(pdev);
+ int i;
+
+ if (info->debugfs)
+ debugfs_remove(info->debugfs);
+
+ for (i = 0; i < 3; i++) {
+ pwm_disable(&info->pwm[i]);
+ del_pwm(i, info);
+ }
+
+ sm501_unit_power(info->dev->parent, SM501_GATE_GPIO, 0);
+ sm501_modify_reg(info->dev->parent, SM501_IRQ_STATUS, 0, 1<<22);
+
+ free_irq(info->irq, info);
+ iounmap(info->regs);
+ release_mem_region(info->res->start,
+ (info->res->end - info->res->start)+1);
+ kfree(info);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver sm501pwm_driver = {
+ .probe = sm501pwm_probe,
+ .remove = sm501pwm_remove,
+ .driver = {
+ .name = drv_name,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __devinit sm501pwm_init(void)
+{
+ return platform_driver_register(&sm501pwm_driver);
+}
+
+static void __exit sm501pwm_cleanup(void)
+{
+ platform_driver_unregister(&sm501pwm_driver);
+}
+
+module_init(sm501pwm_init);
+module_exit(sm501pwm_cleanup);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("SM501 PWM driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sm501-pwm");
diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile
index 4f9eaa3..f945bd7 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/ec_kb3310b.c b/arch/mips/loongson/lemote-2f/ec_kb3310b.c
index 2b666d3..88ef558 100644
--- a/arch/mips/loongson/lemote-2f/ec_kb3310b.c
+++ b/arch/mips/loongson/lemote-2f/ec_kb3310b.c
@@ -14,7 +14,7 @@
#include <linux/spinlock.h>
#include <linux/delay.h>
-#include "ec_kb3310b.h"
+#include <ec_kb3310b.h>
static DEFINE_SPINLOCK(index_access_lock);
static DEFINE_SPINLOCK(port_access_lock);
@@ -76,12 +76,9 @@
spin_unlock_irqrestore(&port_access_lock, flags);
if (timeout <= 0) {
- printk(KERN_ERR "%s: deadable error : timeout...\n", __func__);
+ pr_err("%s: deadable error : timeout...\n", __func__);
ret = -EINVAL;
- } else
- printk(KERN_INFO
- "(%x/%d)ec issued command %d status : 0x%x\n",
- timeout, EC_CMD_TIMEOUT - timeout, cmd, status);
+ }
return ret;
}
@@ -116,8 +113,7 @@
udelay(EC_REG_DELAY);
}
if (timeout <= 0) {
- pr_info("%s: get event number timeout.\n", __func__);
-
+ pr_err("%s: get event number timeout.\n", __func__);
return -EINVAL;
}
value = inb(EC_DAT_PORT);
diff --git a/arch/mips/loongson/lemote-2f/irq.c b/arch/mips/loongson/lemote-2f/irq.c
index 6f8682e..2d54037 100644
--- a/arch/mips/loongson/lemote-2f/irq.c
+++ b/arch/mips/loongson/lemote-2f/irq.c
@@ -11,9 +11,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <asm/irq_cpu.h>
#include <asm/i8259.h>
-#include <asm/mipsregs.h>
#include <loongson.h>
#include <machine.h>
@@ -117,11 +115,6 @@
LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1;
LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1);
- /* Sets the first-level interrupt dispatcher. */
- mips_cpu_irq_init();
- init_i8259_irqs();
- bonito_irq_init();
-
/* setup north bridge irq (bonito) */
setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction);
/* setup source bridge irq (i8259) */
diff --git a/arch/mips/loongson/lemote-2f/platform.c b/arch/mips/loongson/lemote-2f/platform.c
new file mode 100644
index 0000000..5316360
--- /dev/null
+++ b/arch/mips/loongson/lemote-2f/platform.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#include <asm/bootinfo.h>
+
+static struct platform_device yeeloong_pdev = {
+ .name = "yeeloong_laptop",
+ .id = -1,
+};
+
+static struct platform_device lynloong_pdev = {
+ .name = "lynloong_pc",
+ .id = -1,
+};
+
+static int __init lemote2f_platform_init(void)
+{
+ struct platform_device *pdev = NULL;
+
+ switch (mips_machtype) {
+ case MACH_LEMOTE_YL2F89:
+ pdev = &yeeloong_pdev;
+ break;
+ case MACH_LEMOTE_LL2F:
+ pdev = &lynloong_pdev;
+ break;
+ default:
+ break;
+
+ }
+
+ if (pdev != NULL)
+ return platform_device_register(pdev);
+
+ return -ENODEV;
+}
+
+arch_initcall(lemote2f_platform_init);
diff --git a/arch/mips/loongson/lemote-2f/pm.c b/arch/mips/loongson/lemote-2f/pm.c
index cac4d38..b82ab17 100644
--- a/arch/mips/loongson/lemote-2f/pm.c
+++ b/arch/mips/loongson/lemote-2f/pm.c
@@ -23,7 +23,7 @@
#include <loongson.h>
#include <cs5536/cs5536_mfgpt.h>
-#include "ec_kb3310b.h"
+#include <ec_kb3310b.h>
#define I8042_KBD_IRQ 1
#define I8042_CTR_KBDINT 0x01
@@ -88,7 +88,7 @@
static void yeeloong_lid_update_task(struct work_struct *work)
{
if (yeeloong_report_lid_status)
- yeeloong_report_lid_status(BIT_LID_DETECT_ON);
+ yeeloong_report_lid_status(ON);
}
int wakeup_loongson(void)
@@ -100,7 +100,7 @@
if (irq < 0)
return 0;
- printk(KERN_INFO "%s: irq = %d\n", __func__, irq);
+ pr_debug("%s: irq = %d\n", __func__, irq);
if (irq == I8042_KBD_IRQ)
return 1;
@@ -118,7 +118,7 @@
/* check the LID status */
lid_status = ec_read(REG_LID_DETECT);
/* wakeup cpu when people open the LID */
- if (lid_status == BIT_LID_DETECT_ON) {
+ if (lid_status == ON) {
/* If we call it directly here, the WARNING
* will be sent out by getnstimeofday
* via "WARN_ON(timekeeping_suspended);"
@@ -140,10 +140,10 @@
void __weak mach_suspend(void)
{
- disable_mfgpt0_counter();
+ disable_mfgpt_counter();
}
void __weak mach_resume(void)
{
- enable_mfgpt0_counter();
+ enable_mfgpt_counter();
}
diff --git a/arch/mips/loongson/lemote-2f/reset.c b/arch/mips/loongson/lemote-2f/reset.c
index 90962a3..5d3d95b 100644
--- a/arch/mips/loongson/lemote-2f/reset.c
+++ b/arch/mips/loongson/lemote-2f/reset.c
@@ -20,15 +20,14 @@
#include <loongson.h>
#include <cs5536/cs5536.h>
-#include "ec_kb3310b.h"
+#include <ec_kb3310b.h>
static void reset_cpu(void)
{
/*
- * reset cpu to full speed, this is needed when enabling cpu frequency
- * scalling
+ * reset cpu to full speed
*/
- LOONGSON_CHIPCFG0 |= 0x7;
+ LOONGSON_CHIPCFG0 |= 7;
}
/* reset support for fuloong2f */
@@ -81,7 +80,7 @@
reset_cpu();
/* sending an reset signal to EC(embedded controller) */
- ec_write(REG_RESET, BIT_RESET_ON);
+ ec_write(REG_RESET, ON);
}
#define yl2f89_reboot ml2f_reboot
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index f03771900..85c2a15 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -7,6 +7,9 @@
* Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc.
*
+ * Loongson instruction support
+ * Copyright (C) 2011 Mark H Weaver <mhw@netris.org>
+ *
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
@@ -58,6 +61,14 @@
#endif
#define __mips 4
+#ifdef __loongson_fp
+#undef __loongson_fp
+#endif
+#if __mips >= 4 && __mips != 32
+/* Include support for Loongson floating point instructions */
+#define __loongson_fp 1
+#endif
+
/* Function which emulates a floating point instruction. */
static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
@@ -67,6 +78,10 @@
static int fpux_emu(struct pt_regs *,
struct mips_fpu_struct *, mips_instruction, void *__user *);
#endif
+#ifdef __loongson_fp
+static int loongson_spec2_emu(struct pt_regs *,
+ struct mips_fpu_struct *, mips_instruction, void *__user *);
+#endif
/* Further private data for which no space exists in mips_fpu_struct */
@@ -884,6 +899,14 @@
#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.
@@ -1260,6 +1283,15 @@
break;
#endif
+#ifdef __loongson_fp
+ case spec2_op:{
+ int sig = loongson_spec2_emu(xcp, ctx, ir, fault_addr);
+ if (sig)
+ return sig;
+ break;
+ }
+#endif
+
default:
return SIGILL;
}
@@ -1338,6 +1370,172 @@
DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
+#ifdef __loongson_fp
+static int loongson_spec2_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
+ mips_instruction ir, void *__user *fault_addr)
+{
+ int rfmt; /* resulting format */
+ unsigned rcsr = 0; /* resulting csr */
+ union {
+ ieee754dp d;
+ struct {
+ ieee754sp s;
+ ieee754sp s2;
+ };
+ } rv; /* resulting value */
+
+ /* XXX maybe add a counter for loongson spec2 fp instructions? */
+ /* MIPS_FPU_EMU_INC_STATS(cp1xops); */
+
+ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
+ case s_fmt:{
+ ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
+ ieee754sp fd, fs, ft;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case loongson_madd_op:
+ handler = fpemu_sp_madd;
+ goto scoptop;
+ case loongson_msub_op:
+ handler = fpemu_sp_msub;
+ goto scoptop;
+ case loongson_nmadd_op:
+ handler = fpemu_sp_nmadd;
+ goto scoptop;
+ case loongson_nmsub_op:
+ handler = fpemu_sp_nmsub;
+ goto scoptop;
+
+ scoptop:
+ SPFROMREG(fd, MIPSInst_FD(ir));
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ SPFROMREG(ft, MIPSInst_FT(ir));
+ rv.s = (*handler) (fd, fs, ft);
+
+ copcsr:
+ if (ieee754_cxtest(IEEE754_INEXACT))
+ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
+ if (ieee754_cxtest(IEEE754_UNDERFLOW))
+ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
+ if (ieee754_cxtest(IEEE754_OVERFLOW))
+ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
+ if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
+ rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
+
+ break;
+
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+
+ case d_fmt:{
+ ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);
+ ieee754dp fd, fs, ft;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case loongson_madd_op:
+ handler = fpemu_dp_madd;
+ goto dcoptop;
+ case loongson_msub_op:
+ handler = fpemu_dp_msub;
+ goto dcoptop;
+ case loongson_nmadd_op:
+ handler = fpemu_dp_nmadd;
+ goto dcoptop;
+ case loongson_nmsub_op:
+ handler = fpemu_dp_nmsub;
+ goto dcoptop;
+
+ dcoptop:
+ DPFROMREG(fd, MIPSInst_FD(ir));
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ DPFROMREG(ft, MIPSInst_FT(ir));
+ rv.d = (*handler) (fd, fs, ft);
+ goto copcsr;
+
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+
+ case ps_fmt:{
+ ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
+ struct _ieee754_csr ieee754_csr_save;
+ ieee754sp fd1, fs1, ft1;
+ ieee754sp fd2, fs2, ft2;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case loongson_madd_op:
+ handler = fpemu_sp_madd;
+ goto pscoptop;
+ case loongson_msub_op:
+ handler = fpemu_sp_msub;
+ goto pscoptop;
+ case loongson_nmadd_op:
+ handler = fpemu_sp_nmadd;
+ goto pscoptop;
+ case loongson_nmsub_op:
+ handler = fpemu_sp_nmsub;
+ goto pscoptop;
+
+ pscoptop:
+ PSPFROMREG(fd1, fd2, MIPSInst_FD(ir));
+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
+ rv.s = (*handler) (fd1, fs1, ft1);
+ ieee754_csr_save = ieee754_csr;
+ rv.s2 = (*handler) (fd2, fs2, ft2);
+ ieee754_csr.cx |= ieee754_csr_save.cx;
+ ieee754_csr.sx |= ieee754_csr_save.sx;
+ goto copcsr;
+
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+
+ default:
+ return SIGILL;
+ }
+
+ /*
+ * Update the fpu CSR register for this operation.
+ * If an exception is required, generate a tidy SIGFPE exception,
+ * without updating the result register.
+ * Note: cause exception bits do not accumulate, they are rewritten
+ * for each op; only the flag/sticky bits accumulate.
+ */
+ ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
+ if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
+ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */
+ return SIGFPE;
+ }
+
+ /*
+ * Now we can safely write the result back to the register file.
+ */
+ switch (rfmt) {
+ case d_fmt:
+ DPTOREG(rv.d, MIPSInst_FD(ir));
+ break;
+ case s_fmt:
+ SPTOREG(rv.s, MIPSInst_FD(ir));
+ break;
+ case ps_fmt:
+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
+ break;
+ default:
+ return SIGILL;
+ }
+
+ return 0;
+}
+#endif
+
static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
mips_instruction ir, void *__user *fault_addr)
{
@@ -1431,7 +1629,7 @@
break;
default:
- return SIGILL;
+ goto SIGILL_unless_prefx_op;
}
break;
}
@@ -1501,19 +1699,17 @@
goto copcsr;
default:
- return SIGILL;
+ goto SIGILL_unless_prefx_op;
}
break;
}
- case 0x7: /* 7 */
- if (MIPSInst_FUNC(ir) != pfetch_op) {
- return SIGILL;
- }
- /* ignore prefx operation */
- break;
-
default:
+ SIGILL_unless_prefx_op:
+ if (MIPSInst_FUNC(ir) == prefx_op) {
+ /* ignore prefx operation */
+ break;
+ }
return SIGILL;
}
@@ -1534,7 +1730,12 @@
unsigned cond;
union {
ieee754dp d;
- ieee754sp s;
+ struct {
+ ieee754sp s;
+#ifdef __loongson_fp
+ ieee754sp s2; /* for Loongson paired singles */
+#endif
+ };
int w;
#ifdef __mips64
s64 l;
@@ -1606,7 +1807,7 @@
case fmov_op:
/* an easy one */
SPFROMREG(rv.s, MIPSInst_FS(ir));
- goto copcsr;
+ break;
/* binary op on handler */
scopbop:
@@ -1793,7 +1994,7 @@
case fmov_op:
/* an easy one */
DPFROMREG(rv.d, MIPSInst_FS(ir));
- goto copcsr;
+ break;
/* binary op on handler */
dcopbop:{
@@ -1904,6 +2105,83 @@
break;
}
+#ifdef __loongson_fp
+ case ps_fmt:{ /* 6 */
+ /* Support for Loongson paired single fp instructions */
+ union {
+ ieee754sp(*b) (ieee754sp, ieee754sp);
+ ieee754sp(*u) (ieee754sp);
+ } handler;
+
+ switch (MIPSInst_FUNC(ir)) {
+ /* binary ops */
+ case fadd_op:
+ handler.b = ieee754sp_add;
+ goto pscopbop;
+ case fsub_op:
+ handler.b = ieee754sp_sub;
+ goto pscopbop;
+ case fmul_op:
+ handler.b = ieee754sp_mul;
+ goto pscopbop;
+
+ /* unary ops */
+ case fabs_op:
+ handler.u = ieee754sp_abs;
+ goto pscopuop;
+ case fneg_op:
+ handler.u = ieee754sp_neg;
+ goto pscopuop;
+ case fmov_op:
+ /* an easy one */
+ PSPFROMREG(rv.s, rv.s2, MIPSInst_FS(ir));
+ break;
+
+ pscopbop: /* paired binary op handler */
+ {
+ struct _ieee754_csr ieee754_csr_save;
+ ieee754sp fs1, ft1;
+ ieee754sp fs2, ft2;
+
+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
+ PSPFROMREG(ft1, ft2, MIPSInst_FT(ir));
+ rv.s = (*handler.b) (fs1, ft1);
+ ieee754_csr_save = ieee754_csr;
+ rv.s2 = (*handler.b) (fs2, ft2);
+ ieee754_csr.cx |= ieee754_csr_save.cx;
+ ieee754_csr.sx |= ieee754_csr_save.sx;
+ goto copcsr;
+ }
+ pscopuop: /* paired unary op handler */
+ {
+ struct _ieee754_csr ieee754_csr_save;
+ ieee754sp fs1;
+ ieee754sp fs2;
+
+ PSPFROMREG(fs1, fs2, MIPSInst_FS(ir));
+ rv.s = (*handler.u) (fs1);
+ ieee754_csr_save = ieee754_csr;
+ rv.s2 = (*handler.u) (fs2);
+ ieee754_csr.cx |= ieee754_csr_save.cx;
+ ieee754_csr.sx |= ieee754_csr_save.sx;
+ goto copcsr;
+ }
+ break;
+
+ default:
+ if (MIPSInst_FUNC(ir) >= fcmp_op) {
+ /* Loongson fp hardware handles all
+ cases of fp compare insns, so we
+ shouldn't have to */
+ printk ("Loongson paired-single fp compare"
+ " unimplemented in cp1emu.c\n");
+ }
+ return SIGILL;
+ }
+ break;
+ }
+#endif
+
case w_fmt:{
ieee754sp fs;
@@ -1993,6 +2271,11 @@
DITOREG(rv.l, MIPSInst_FD(ir));
break;
#endif
+#ifdef __loongson_fp
+ case ps_fmt:
+ PSPTOREG(rv.s, rv.s2, MIPSInst_FD(ir));
+ break;
+#endif
default:
return SIGILL;
}
diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c
index 8557fb5..8b568ef 100644
--- a/arch/mips/mm/c-octeon.c
+++ b/arch/mips/mm/c-octeon.c
@@ -188,7 +188,7 @@
struct cpuinfo_mips *c = ¤t_cpu_data;
config1 = read_c0_config1();
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_CAVIUM_OCTEON:
case CPU_CAVIUM_OCTEON_PLUS:
c->icache.linesz = 2 << ((config1 >> 19) & 7);
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index c2ec87e..d0c7905 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -816,7 +816,7 @@
unsigned long config1;
unsigned int lsize;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_R4600: /* QED style two way caches? */
case CPU_R4700:
case CPU_R5000:
@@ -904,10 +904,10 @@
write_c0_config(config & ~VR41_CONF_P4K);
case CPU_VR4131:
/* Workaround for cache instruction bug of VR4131 */
- if (c->processor_id == 0x0c80U || c->processor_id == 0x0c81U ||
- c->processor_id == 0x0c82U) {
+ if (current_cpu_prid() == 0x0c80U || current_cpu_prid() == 0x0c81U ||
+ current_cpu_prid() == 0x0c82U) {
config |= 0x00400000U;
- if (c->processor_id == 0x0c80U)
+ if (current_cpu_prid() == 0x0c80U)
config |= VR41_CONF_BP;
write_c0_config(config);
} else
@@ -1052,7 +1052,7 @@
* normally they'd suffer from aliases but magic in the hardware deals
* with that for us so we don't need to take care ourselves.
*/
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_20KC:
case CPU_25KF:
case CPU_SB1:
@@ -1085,7 +1085,7 @@
c->dcache.flags |= MIPS_CACHE_ALIASES;
}
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_20KC:
/*
* Some older 20Kc chips doesn't have the 'VI' bit in
@@ -1214,7 +1214,7 @@
* processors don't have a S-cache that would be relevant to the
* Linux memory management.
*/
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_R4000SC:
case CPU_R4000MC:
case CPU_R4400SC:
@@ -1391,9 +1391,8 @@
{
extern char __weak except_vec2_generic;
extern char __weak except_vec2_sb1;
- struct cpuinfo_mips *c = ¤t_cpu_data;
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_SB1:
case CPU_SB1A:
set_uncached_handler(0x100, &except_vec2_sb1, 0x80);
diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c
index 23129d1..27e33a4 100644
--- a/arch/mips/mm/dma-default.c
+++ b/arch/mips/mm/dma-default.c
@@ -335,7 +335,7 @@
return plat_dma_supported(dev, mask);
}
-void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+void mips_dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction)
{
BUG_ON(direction == DMA_NONE);
@@ -345,8 +345,6 @@
__dma_sync_virtual(vaddr, size, direction);
}
-EXPORT_SYMBOL(dma_cache_sync);
-
static struct dma_map_ops mips_default_dma_map_ops = {
.alloc = mips_dma_alloc_coherent,
.free = mips_dma_free_coherent,
diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
index 4eb8dcf..72207dc 100644
--- a/arch/mips/mm/page.c
+++ b/arch/mips/mm/page.c
@@ -164,7 +164,7 @@
* hints are broken.
*/
if (current_cpu_type() == CPU_SB1 &&
- (current_cpu_data.processor_id & 0xff) < 0x02) {
+ cpu_prid_rev() < 0x02) {
pref_src_mode = Pref_Load;
pref_dst_mode = Pref_Store;
} else {
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index df96da7..cceaaaf 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -71,7 +71,7 @@
unsigned int tmp;
/* Check the bypass bit (L2B) */
- switch (c->cputype) {
+ switch (current_cpu_type()) {
case CPU_34K:
case CPU_74K:
case CPU_1004K:
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index a91a7a9..08eead9 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -138,7 +138,7 @@
*/
static int __cpuinit m4kc_tlbp_war(void)
{
- return (current_cpu_data.processor_id & 0xffff00) ==
+ return (current_cpu_prid() & 0xffff00) ==
(PRID_COMP_MIPS | PRID_IMP_4KC);
}
@@ -631,7 +631,7 @@
default:
panic("No TLB refill handler yet (CPU type: %d)",
- current_cpu_data.cputype);
+ current_cpu_type());
break;
}
}
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
index e4b1140..6ffce07 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -381,7 +381,7 @@
break;
case CPU_R10000:
- if ((current_cpu_data.processor_id & 0xff) == 0x20)
+ if (current_cpu_prid() == 0x20)
op_model_mipsxx_ops.cpu_type = "mips/r10000-v2.x";
else
op_model_mipsxx_ops.cpu_type = "mips/r10000";
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 2cb1d31..9491e3a 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -29,6 +29,7 @@
obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o
obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o
obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o
+obj-$(CONFIG_DEXXON_GDIUM) += fixup-gdium.o ops-loongson2.o
obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o
obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o
obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
diff --git a/arch/mips/pci/fixup-gdium.c b/arch/mips/pci/fixup-gdium.c
new file mode 100644
index 0000000..b296220
--- /dev/null
+++ b/arch/mips/pci/fixup-gdium.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 yajin <yajin@vm-kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <loongson.h>
+/*
+ * http://www.pcidatabase.com
+ * GDIUM has different PCI mapping
+ * slot 13 (0x1814/0x0301) -> RaLink rt2561 Wireless-G PCI
+ * slog 14 (0x126f/0x0501) -> sm501
+ * slot 15 (0x1033/0x0035) -> NEC Dual OHCI controllers
+ * plus Single EHCI controller
+ * slot 16 (0x10ec/0x8139) -> Realtek 8139c
+ * slot 17 (0x1033/0x00e0) -> NEC USB 2.0 Host Controller
+ */
+
+#undef INT_IRQA
+#undef INT_IRQB
+#undef INT_IRQC
+#undef INT_IRQD
+#define INT_IRQA 36
+#define INT_IRQB 37
+#define INT_IRQC 38
+#define INT_IRQD 39
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq = 0;
+
+ switch (slot) {
+ case 13:
+ irq = INT_IRQC + ((pin - 1) & 3);
+ break;
+ case 14:
+ irq = INT_IRQA;
+ break;
+ case 15:
+#if CONFIG_GDIUM_VERSION > 2
+ irq = INT_IRQB;
+#else
+ irq = INT_IRQA + ((pin - 1) & 3);
+#endif
+ break;
+ case 16:
+ irq = INT_IRQD;
+ break;
+#if CONFIG_GDIUM_VERSION > 2
+ case 17:
+ irq = INT_IRQC;
+ break;
+#endif
+ default:
+ pr_info(" strange pci slot number %d on gdium.\n", slot);
+ break;
+ }
+ return irq;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+/* Fixups for the USB host controllers */
+static void __init gdium_usb_host_fixup(struct pci_dev *dev)
+{
+ unsigned int val;
+ pci_read_config_dword(dev, 0xe0, &val);
+#if CONFIG_GDIUM_VERSION > 2
+ pci_write_config_dword(dev, 0xe0, (val & ~3) | 0x3);
+#else
+ pci_write_config_dword(dev, 0xe0, (val & ~7) | 0x5);
+ pci_write_config_dword(dev, 0xe4, 1<<5);
+#endif
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,
+ gdium_usb_host_fixup);
+#if CONFIG_GDIUM_VERSION > 2
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_CT_65550,
+ gdium_usb_host_fixup);
+#endif
diff --git a/arch/mips/pci/ops-loongson2.c b/arch/mips/pci/ops-loongson2.c
index 98254af..6b0f694 100644
--- a/arch/mips/pci/ops-loongson2.c
+++ b/arch/mips/pci/ops-loongson2.c
@@ -22,6 +22,7 @@
#ifdef CONFIG_CS5536
#include <cs5536/cs5536_pci.h>
#include <cs5536/cs5536.h>
+#include <linux/export.h>
#endif
#define PCI_ACCESS_READ 0
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 @@
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/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c
index 2391632..aca5c76 100644
--- a/arch/mips/vr41xx/common/init.c
+++ b/arch/mips/vr41xx/common/init.c
@@ -43,8 +43,8 @@
vr41xx_calculate_clock_frequency();
tclock = vr41xx_get_tclock_frequency();
- if (current_cpu_data.processor_id == PRID_VR4131_REV2_0 ||
- current_cpu_data.processor_id == PRID_VR4131_REV2_1)
+ if (current_cpu_prid() == PRID_VR4131_REV2_0 ||
+ current_cpu_prid() == PRID_VR4131_REV2_1)
mips_hpt_frequency = tclock / 2;
else
mips_hpt_frequency = tclock / 4;
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
index 0448860..fa7cfab 100644
--- a/drivers/ata/pata_cs5536.c
+++ b/drivers/ata/pata_cs5536.c
@@ -46,8 +46,6 @@
module_param_named(msr, use_msr, int, 0644);
MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
#else
-#undef rdmsr /* avoid accidental MSR usage on, e.g. x86-64 */
-#undef wrmsr
#define rdmsr(x, y, z) do { } while (0)
#define wrmsr(x, y, z) do { } while (0)
#define use_msr 0
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index bee88ee..fc9062f 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -748,6 +748,13 @@
---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 && GENERIC_HARDIRQS
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 2065694..10b48f0 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -115,6 +115,7 @@
obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
+obj-$(CONFIG_HID_GDIUM) += hid-gdium.o
obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
diff --git a/drivers/hid/hid-gdium.c b/drivers/hid/hid-gdium.c
new file mode 100644
index 0000000..67cc095
--- /dev/null
+++ b/drivers/hid/hid-gdium.c
@@ -0,0 +1,210 @@
+/*
+ * hid-gdium -- Gdium laptop function keys
+ *
+ * Arnaud Patard <apatard@mandriva.com>
+ *
+ * Based on hid-apple.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#define GDIUM_FN_ON 1
+
+static int fnmode = GDIUM_FN_ON;
+module_param(fnmode, int, 0644);
+MODULE_PARM_DESC(fnmode, "Mode of fn key on Gdium (0 = disabled, 1 = Enabled)");
+
+struct gdium_data {
+ unsigned int fn_on;
+};
+
+
+struct gdium_key_translation {
+ u16 from;
+ u16 to;
+};
+
+static struct gdium_key_translation gdium_fn_keys[] = {
+ { KEY_F1, KEY_CAMERA },
+ { KEY_F2, KEY_CONNECT },
+ { KEY_F3, KEY_MUTE },
+ { KEY_F4, KEY_VOLUMEUP},
+ { KEY_F5, KEY_VOLUMEDOWN },
+ { KEY_F6, KEY_SWITCHVIDEOMODE },
+ { KEY_F7, KEY_F19 }, /* F7+12. Have to use existant keycodes */
+ { KEY_F8, KEY_BRIGHTNESSUP },
+ { KEY_F9, KEY_BRIGHTNESSDOWN },
+ { KEY_F10, KEY_SLEEP },
+ { KEY_F11, KEY_PROG1 },
+ { KEY_F12, KEY_PROG2 },
+ { KEY_UP, KEY_PAGEUP },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_INSERT, KEY_NUMLOCK },
+ { KEY_DELETE, KEY_SCROLLLOCK },
+ { KEY_T, KEY_STOPCD },
+ { KEY_F, KEY_PREVIOUSSONG },
+ { KEY_H, KEY_NEXTSONG },
+ { KEY_G, KEY_PLAYPAUSE },
+ { }
+};
+
+static struct gdium_key_translation *gdium_find_translation(
+ struct gdium_key_translation *table, u16 from)
+{
+ struct gdium_key_translation *trans;
+
+ /* Look for the translation */
+ for (trans = table; trans->from; trans++)
+ if (trans->from == from)
+ return trans;
+ return NULL;
+}
+
+static int hidinput_gdium_event(struct hid_device *hid, struct input_dev *input,
+ struct hid_usage *usage, __s32 value)
+{
+ struct gdium_data *data = hid_get_drvdata(hid);
+ struct gdium_key_translation *trans;
+ int do_translate;
+
+ if (usage->type != EV_KEY)
+ return 0;
+
+ if ((usage->code == KEY_FN)) {
+ data->fn_on = !!value;
+ input_event(input, usage->type, usage->code, value);
+ return 1;
+ }
+
+ if (fnmode) {
+ trans = gdium_find_translation(gdium_fn_keys, usage->code);
+ if (trans) {
+ do_translate = data->fn_on;
+ if (do_translate) {
+ input_event(input, usage->type, trans->to, value);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int gdium_input_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || !usage->type)
+ return 0;
+
+ if (hidinput_gdium_event(hdev, field->hidinput->input, usage, value))
+ return 1;
+
+ return 0;
+}
+
+
+static void gdium_input_setup(struct input_dev *input)
+{
+ struct gdium_key_translation *trans;
+
+ set_bit(KEY_NUMLOCK, input->keybit);
+
+ /* Enable all needed keys */
+ for (trans = gdium_fn_keys; trans->from; trans++)
+ set_bit(trans->to, input->keybit);
+}
+
+static int gdium_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD)
+ && ((usage->hid & HID_USAGE) == 0x82)) {
+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
+ gdium_input_setup(hi->input);
+ return 1;
+ }
+ return 0;
+}
+
+static int gdium_input_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ struct gdium_data *data;
+ int ret;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&hdev->dev, "can't alloc gdium keyboard data\n");
+ return -ENOMEM;
+ }
+
+ hid_set_drvdata(hdev, data);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ return 0;
+err_free:
+ kfree(data);
+ return ret;
+}
+static void gdium_input_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id gdium_input_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_GDIUM, USB_DEVICE_ID_GDIUM) },
+ {}
+};
+MODULE_DEVICE_TABLE(hid, gdium_input_devices);
+
+static struct hid_driver gdium_input_driver = {
+ .name = "gdium-fnkeys",
+ .id_table = gdium_input_devices,
+ .probe = gdium_input_probe,
+ .remove = gdium_input_remove,
+ .event = gdium_input_event,
+ .input_mapping = gdium_input_mapping,
+};
+
+static int gdium_input_init(void)
+{
+ int ret;
+
+ ret = hid_register_driver(&gdium_input_driver);
+ if (ret)
+ pr_err("can't register gdium keyboard driver\n");
+
+ return ret;
+}
+static void gdium_input_exit(void)
+{
+ hid_unregister_driver(&gdium_input_driver);
+}
+
+module_init(gdium_input_init);
+module_exit(gdium_input_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 45c593d..0a3dbf4 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -913,6 +913,9 @@
#define USB_VENDOR_ID_ZYTRONIC 0x14c8
#define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005
+#define USB_VENDOR_ID_GDIUM 0x04B4
+#define USB_DEVICE_ID_GDIUM 0xe001
+
#define USB_VENDOR_ID_PRIMAX 0x0461
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d4fe13e..8c1daa0 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -946,7 +946,7 @@
config SCx200_ACB
tristate "Geode ACCESS.bus support"
- depends on X86_32 && PCI
+ depends on PCI
help
Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
SC1100 processors and the CS5535 and CS5536 Geode companion devices.
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 376f2dc..b576801 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -27,6 +27,10 @@
#include <asm/uaccess.h>
#include <asm/io.h>
+#ifdef CONFIG_LEMOTE_MACH2F
+#include <asm/bootinfo.h>
+#endif
+
void SELECT_MASK(ide_drive_t *drive, int mask)
{
const struct ide_port_ops *port_ops = drive->hwif->port_ops;
@@ -300,6 +304,11 @@
{
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 c04e08d..d44af21 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -58,7 +58,7 @@
struct sm501_gpio {
/* no gpio support, empty definition for sm501_devdata. */
};
-#endif
+#endif /* CONFIG_MFD_SM501_GPIO */
struct sm501_devdata {
spinlock_t reg_lock;
@@ -1135,6 +1135,22 @@
{
return sm->gpio.registered;
}
+
+void sm501_configure_gpio(struct device *dev, unsigned int gpio, unsigned
+ char mode)
+{
+ unsigned long set, reg, offset = gpio;
+
+ if (offset >= 32) {
+ reg = SM501_GPIO63_32_CONTROL;
+ offset = gpio - 32;
+ } else
+ reg = SM501_GPIO31_0_CONTROL;
+
+ set = mode ? 1 << offset : 0;
+
+ sm501_modify_reg(dev, reg, set, 0);
+}
#else
static inline int sm501_register_gpio(struct sm501_devdata *sm)
{
@@ -1154,7 +1170,13 @@
{
return 0;
}
-#endif
+
+void sm501_configure_gpio(struct device *dev, unsigned int gpio,
+ unsigned char mode)
+{
+}
+#endif /* CONFIG_MFD_SM501_GPIO */
+EXPORT_SYMBOL_GPL(sm501_configure_gpio);
static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm,
struct sm501_platdata_gpio_i2c *iic)
@@ -1209,6 +1231,20 @@
return 0;
}
+/* register sm501 PWM device */
+static int sm501_register_pwm(struct sm501_devdata *sm)
+{
+ struct platform_device *pdev;
+
+ pdev = sm501_create_subdev(sm, "sm501-pwm", 2, 0);
+ if (!pdev)
+ return -ENOMEM;
+ sm501_create_subio(sm, &pdev->resource[0], 0x10020, 0xC);
+ sm501_create_irq(sm, &pdev->resource[1]);
+
+ return sm501_register_device(sm, pdev);
+}
+
/* sm501_dbg_regs
*
* Debug attribute to attach to parent device to show core registers
@@ -1367,6 +1403,8 @@
sm501_register_uart(sm, idata->devices);
if (idata->devices & SM501_USE_GPIO)
sm501_register_gpio(sm);
+ if (idata->devices & SM501_USE_PWM)
+ sm501_register_pwm(sm);
}
if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
@@ -1553,10 +1591,15 @@
.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, ®_data);
+
+ if (reg_data & 0x0400) {
+ /* Link status change */
+ titan_ge_mdio_read(port_num,
+ TITAN_GE_MDIO_PHY_STATUS, ®_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/Kconfig b/drivers/net/wireless/Kconfig
index f8f0156..e6b8e8a 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -213,6 +213,91 @@
If you choose to build a module, it'll be called rndis_wlan.
+config RTL8180
+ tristate "Realtek 8180/8185 PCI support"
+ depends on MAC80211 && PCI && EXPERIMENTAL
+ select EEPROM_93CX6
+ ---help---
+ This is a driver for RTL8180 and RTL8185 based cards.
+ These are PCI based chips found in cards such as:
+
+ (RTL8185 802.11g)
+ A-Link WL54PC
+
+ (RTL8180 802.11b)
+ Belkin F5D6020 v3
+ Belkin F5D6020 v3
+ Dlink DWL-610
+ Dlink DWL-510
+ Netgear MA521
+ Level-One WPC-0101
+ Acer Aspire 1357 LMi
+ VCTnet PC-11B1
+ Ovislink AirLive WL-1120PCM
+ Mentor WL-PCI
+ Linksys WPC11 v4
+ TrendNET TEW-288PI
+ D-Link DWL-520 Rev D
+ Repotec RP-WP7126
+ TP-Link TL-WN250/251
+ Zonet ZEW1000
+ Longshine LCS-8031-R
+ HomeLine HLW-PCC200
+ GigaFast WF721-AEX
+ Planet WL-3553
+ Encore ENLWI-PCI1-NT
+ TrendNET TEW-266PC
+ Gigabyte GN-WLMR101
+ Siemens-fujitsu Amilo D1840W
+ Edimax EW-7126
+ PheeNet WL-11PCIR
+ Tonze PC-2100T
+ Planet WL-8303
+ Dlink DWL-650 v M1
+ Edimax EW-7106
+ Q-Tec 770WC
+ Topcom Skyr@cer 4011b
+ Roper FreeLan 802.11b (edition 2004)
+ Wistron Neweb Corp CB-200B
+ Pentagram HorNET
+ QTec 775WC
+ TwinMOS Booming B Series
+ Micronet SP906BB
+ Sweex LC700010
+ Surecom EP-9428
+ Safecom SWLCR-1100
+
+ Thanks to Realtek for their support!
+
+config RTL8187
+ tristate "Realtek 8187 and 8187B USB support"
+ depends on MAC80211 && USB && !LEMOTE_MACH2F
+ select EEPROM_93CX6
+ ---help---
+ This is a driver for RTL8187 and RTL8187B based cards.
+ These are USB based chips found in devices such as:
+
+ Netgear WG111v2
+ Level 1 WNC-0301USB
+ Micronet SP907GK V5
+ Encore ENUWI-G2
+ Trendnet TEW-424UB
+ ASUS P5B Deluxe/P5K Premium motherboards
+ Toshiba Satellite Pro series of laptops
+ Asus Wireless Link
+ Linksys WUSB54GC-EU v2
+ (v1 = rt73usb; v3 is rt2070-based,
+ use staging/rt3070 or try rt2800usb)
+
+ Thanks to Realtek for their support!
+
+# If possible, automatically enable LEDs for RTL8187.
+
+config RTL8187_LEDS
+ bool
+ depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187)
+ default y
+
source "drivers/net/wireless/rtl818x/Kconfig"
config ADM8211
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 67156ef..940aaf7 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -24,7 +24,7 @@
obj-$(CONFIG_ZD1211RW) += zd1211rw/
obj-$(CONFIG_RTL8180) += rtl818x/
obj-$(CONFIG_RTL8187) += rtl818x/
-obj-$(CONFIG_RTLWIFI) += rtlwifi/
+obj-$(CONFIG_RTL8192CE) += rtlwifi/
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index f49220e..acbfed9 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -1015,6 +1015,9 @@
u32 reg;
mutex_lock(&priv->conf_mutex);
+
+ priv->vif = NULL;
+
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -1134,10 +1137,7 @@
static void rtl8187_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif)
{
- struct rtl8187_priv *priv = dev->priv;
- mutex_lock(&priv->conf_mutex);
- priv->vif = NULL;
- mutex_unlock(&priv->conf_mutex);
+ /* Nothing to do */
}
static int rtl8187_config(struct ieee80211_hw *dev, u32 changed)
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 @@
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 69616ae..20f4f61 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -4,4 +4,6 @@
if GOLDFISH
source "drivers/platform/goldfish/Kconfig"
endif
-
+if MIPS
+source "drivers/platform/mips/Kconfig"
+endif
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index 8a44a4c..f38b7e8 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -3,5 +3,6 @@
#
obj-$(CONFIG_X86) += x86/
+obj-$(CONFIG_MIPS) += mips/
obj-$(CONFIG_OLPC) += olpc/
obj-$(CONFIG_GOLDFISH) += goldfish/
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..0eadf8e
--- /dev/null
+++ b/drivers/platform/mips/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for MIPS Platform-Specific Drivers
+#
+
+obj-$(CONFIG_LEMOTE_YEELOONG2F) += yeeloong_laptop.o
+
+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..3db791e
--- /dev/null
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -0,0 +1,1356 @@
+/*
+ * 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>
+
+/* common function */
+#define EC_VER_LEN 64
+
+static int ec_version_before(char *version)
+{
+ char *p, ec_ver[EC_VER_LEN];
+
+ p = strstr(loongson_cmdline, "EC_VER=");
+ if (!p)
+ memset(ec_ver, 0, EC_VER_LEN);
+ else {
+ strncpy(ec_ver, p, EC_VER_LEN);
+ p = strstr(ec_ver, " ");
+ if (p)
+ *p = '\0';
+ }
+
+ return (strncasecmp(ec_ver, version, 64) < 0);
+}
+
+/* backlight subdriver */
+#define MIN_BRIGHTNESS 1
+#define MAX_BRIGHTNESS 8
+
+static int yeeloong_set_brightness(struct backlight_device *bd)
+{
+ unsigned char level;
+ static unsigned char old_level;
+
+ level = (bd->props.fb_blank == FB_BLANK_UNBLANK &&
+ bd->props.power == FB_BLANK_UNBLANK) ?
+ bd->props.brightness : 0;
+
+ level = clamp_val(level, MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+
+ /* Avoid to modify the brightness when EC is tuning it */
+ if (old_level != level) {
+ if (ec_read(REG_DISPLAY_BRIGHTNESS) == old_level)
+ ec_write(REG_DISPLAY_BRIGHTNESS, level);
+ old_level = level;
+ }
+
+ return 0;
+}
+
+static int yeeloong_get_brightness(struct backlight_device *bd)
+{
+ return ec_read(REG_DISPLAY_BRIGHTNESS);
+}
+
+static struct backlight_ops backlight_ops = {
+ .get_brightness = yeeloong_get_brightness,
+ .update_status = yeeloong_set_brightness,
+};
+
+static struct backlight_device *yeeloong_backlight_dev;
+
+static int yeeloong_backlight_init(void)
+{
+ int ret;
+ struct backlight_properties props;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = MAX_BRIGHTNESS;
+ props.type = BACKLIGHT_PLATFORM;
+ yeeloong_backlight_dev = backlight_device_register("backlight0", NULL,
+ NULL, &backlight_ops, &props);
+
+ if (IS_ERR(yeeloong_backlight_dev)) {
+ ret = PTR_ERR(yeeloong_backlight_dev);
+ yeeloong_backlight_dev = NULL;
+ return ret;
+ }
+
+ yeeloong_backlight_dev->props.brightness =
+ yeeloong_get_brightness(yeeloong_backlight_dev);
+ backlight_update_status(yeeloong_backlight_dev);
+
+ return 0;
+}
+
+static void yeeloong_backlight_exit(void)
+{
+ if (yeeloong_backlight_dev) {
+ backlight_device_unregister(yeeloong_backlight_dev);
+ yeeloong_backlight_dev = NULL;
+ }
+}
+
+/* AC & Battery subdriver */
+
+static struct power_supply yeeloong_ac, yeeloong_bat;
+
+#define RET (val->intval)
+
+#define BAT_CAP_CRITICAL 5
+#define BAT_CAP_HIGH 95
+
+#define get_bat(type) \
+ ec_read(REG_BAT_##type)
+
+#define get_bat_l(type) \
+ ((get_bat(type##_HIGH) << 8) | get_bat(type##_LOW))
+
+static int yeeloong_get_ac_props(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ if (psp == POWER_SUPPLY_PROP_ONLINE)
+ RET = !!(get_bat(POWER) & BIT_BAT_POWER_ACIN);
+
+ return 0;
+}
+
+static enum power_supply_property yeeloong_ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static struct power_supply yeeloong_ac = {
+ .name = "yeeloong-ac",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .properties = yeeloong_ac_props,
+ .num_properties = ARRAY_SIZE(yeeloong_ac_props),
+ .get_property = yeeloong_get_ac_props,
+};
+
+static inline bool is_bat_in(void)
+{
+ return !!(get_bat(STATUS) & BIT_BAT_STATUS_IN);
+}
+
+static int get_bat_temp(void)
+{
+ return get_bat_l(TEMPERATURE) * 10;
+}
+
+static int get_bat_current(void)
+{
+ return -(s16)get_bat_l(CURRENT);
+}
+
+static int get_bat_voltage(void)
+{
+ return get_bat_l(VOLTAGE);
+}
+
+static char *get_manufacturer(void)
+{
+ return (get_bat(VENDOR) == FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO";
+}
+
+static int get_relative_cap(void)
+{
+ /*
+ * When the relative capacity becomes 2, the hardware is observed to
+ * have been turned off forcely. so, we must tune it be suitable to
+ * make the software do related actions.
+ */
+ int tmp = get_bat_l(RELATIVE_CAP);
+
+ if (tmp <= (BAT_CAP_CRITICAL * 2))
+ tmp -= 3;
+
+ return tmp;
+}
+
+static int yeeloong_get_bat_props(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ switch (psp) {
+ /* Fixed information */
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ /* mV -> µV */
+ RET = get_bat_l(DESIGN_VOL) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ /* mAh->µAh */
+ RET = get_bat_l(DESIGN_CAP) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ /* µAh */
+ RET = get_bat_l(FULLCHG_CAP) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = get_manufacturer();
+ break;
+ /* Dynamic information */
+ case POWER_SUPPLY_PROP_PRESENT:
+ RET = is_bat_in();
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ /* mA -> µA */
+ RET = is_bat_in() ? get_bat_current() * 1000 : 0;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* mV -> µV */
+ RET = is_bat_in() ? get_bat_voltage() * 1000 : 0;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ /* Celcius */
+ RET = is_bat_in() ? get_bat_temp() : 0;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ RET = is_bat_in() ? get_relative_cap() : 0;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: {
+ int status;
+
+ if (!is_bat_in()) {
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+ break;
+ }
+
+ status = get_bat(STATUS);
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+
+ if (unlikely(status & BIT_BAT_STATUS_DESTROY)) {
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+ break;
+ }
+
+ if (status & BIT_BAT_STATUS_FULL)
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+ else {
+ int curr_cap = get_relative_cap();
+
+ if (status & BIT_BAT_STATUS_LOW) {
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+ if (curr_cap <= BAT_CAP_CRITICAL)
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+ } else if (curr_cap >= BAT_CAP_HIGH)
+ RET = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
+ }
+ } break;
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+ /* seconds */
+ RET = is_bat_in() ? (get_relative_cap() - 3) * 54 + 142 : 0;
+ break;
+ case POWER_SUPPLY_PROP_STATUS: {
+ int charge = get_bat(CHARGE);
+
+ RET = POWER_SUPPLY_STATUS_UNKNOWN;
+ if (charge & FLAG_BAT_CHARGE_DISCHARGE)
+ RET = POWER_SUPPLY_STATUS_DISCHARGING;
+ else if (charge & FLAG_BAT_CHARGE_CHARGE)
+ RET = POWER_SUPPLY_STATUS_CHARGING;
+ } break;
+ case POWER_SUPPLY_PROP_HEALTH: {
+ int status;
+
+ if (!is_bat_in()) {
+ RET = POWER_SUPPLY_HEALTH_UNKNOWN;
+ break;
+ }
+
+ status = get_bat(STATUS);
+ RET = POWER_SUPPLY_HEALTH_GOOD;
+
+ if (status & (BIT_BAT_STATUS_DESTROY |
+ BIT_BAT_STATUS_LOW))
+ RET = POWER_SUPPLY_HEALTH_DEAD;
+ if (get_bat(CHARGE_STATUS) &
+ BIT_BAT_CHARGE_STATUS_OVERTEMP)
+ RET = POWER_SUPPLY_HEALTH_OVERHEAT;
+ } break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW: /* 1/100(%)*1000 µAh */
+ RET = get_relative_cap() * get_bat_l(FULLCHG_CAP) * 10;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+#undef RET
+
+static enum power_supply_property yeeloong_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static struct power_supply yeeloong_bat = {
+ .name = "yeeloong-bat",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = yeeloong_bat_props,
+ .num_properties = ARRAY_SIZE(yeeloong_bat_props),
+ .get_property = yeeloong_get_bat_props,
+};
+
+static int ac_bat_initialized;
+
+static int yeeloong_bat_init(void)
+{
+ int ret;
+
+ ret = power_supply_register(NULL, &yeeloong_ac);
+ if (ret)
+ return ret;
+ ret = power_supply_register(NULL, &yeeloong_bat);
+ if (ret) {
+ power_supply_unregister(&yeeloong_ac);
+ return ret;
+ }
+ ac_bat_initialized = 1;
+
+ return 0;
+}
+
+static void yeeloong_bat_exit(void)
+{
+ ac_bat_initialized = 0;
+
+ power_supply_unregister(&yeeloong_ac);
+ power_supply_unregister(&yeeloong_bat);
+}
+/* hwmon subdriver */
+
+#define MIN_FAN_SPEED 0
+#define MAX_FAN_SPEED 3
+
+#define get_fan(type) \
+ ec_read(REG_FAN_##type)
+
+#define set_fan(type, val) \
+ ec_write(REG_FAN_##type, val)
+
+static inline int get_fan_speed_level(void)
+{
+ return get_fan(SPEED_LEVEL);
+}
+static inline void set_fan_speed_level(int speed)
+{
+ set_fan(SPEED_LEVEL, speed);
+}
+
+static inline int get_fan_mode(void)
+{
+ return get_fan(AUTO_MAN_SWITCH);
+}
+static inline void set_fan_mode(int mode)
+{
+ set_fan(AUTO_MAN_SWITCH, mode);
+}
+
+/*
+ * 3 different modes: Full speed(0); manual mode(1); auto mode(2)
+ */
+static int get_fan_pwm_enable(void)
+{
+ return (get_fan_mode() == BIT_FAN_AUTO) ? 2 :
+ (get_fan_speed_level() == MAX_FAN_SPEED) ? 0 : 1;
+}
+
+static void set_fan_pwm_enable(int mode)
+{
+ set_fan_mode((mode == 2) ? BIT_FAN_AUTO : BIT_FAN_MANUAL);
+ if (mode == 0)
+ set_fan_speed_level(MAX_FAN_SPEED);
+}
+
+static int get_fan_pwm(void)
+{
+ return get_fan_speed_level();
+}
+
+static void set_fan_pwm(int value)
+{
+ if (get_fan_mode() != BIT_FAN_MANUAL)
+ return;
+
+ value = clamp_val(value, MIN_FAN_SPEED, MAX_FAN_SPEED);
+
+ /* We must ensure the fan is on */
+ if (value > 0)
+ set_fan(CONTROL, ON);
+
+ set_fan_speed_level(value);
+}
+
+static inline int get_fan_speed(void)
+{
+ return ((get_fan(SPEED_HIGH) & 0x0f) << 8) | get_fan(SPEED_LOW);
+}
+
+static int get_fan_rpm(void)
+{
+ return FAN_SPEED_DIVIDER / get_fan_speed();
+}
+
+static int get_cpu_temp(void)
+{
+ return (s8)ec_read(REG_TEMPERATURE_VALUE) * 1000;
+}
+
+static int get_cpu_temp_max(void)
+{
+ return 60 * 1000;
+}
+
+static int get_bat_temp_alarm(void)
+{
+ return !!(get_bat(CHARGE_STATUS) & BIT_BAT_CHARGE_STATUS_OVERTEMP);
+}
+
+static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count)
+{
+ int ret;
+ unsigned long value;
+
+ if (!count)
+ return 0;
+
+ ret = strict_strtoul(buf, 10, &value);
+ if (ret)
+ return ret;
+
+ set(value);
+
+ return count;
+}
+
+static ssize_t show_sys_hwmon(int (*get) (void), char *buf)
+{
+ return sprintf(buf, "%d\n", get());
+}
+
+#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
+ static ssize_t show_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
+ return show_sys_hwmon(_set, buf); \
+ } \
+ static ssize_t store_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ return store_sys_hwmon(_get, buf, count); \
+ } \
+ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
+
+CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL);
+CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm);
+CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable,
+ set_fan_pwm_enable);
+CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL);
+CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL);
+CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_bat_temp, NULL);
+CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_bat_temp_alarm, NULL);
+CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_bat_current, NULL);
+CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_bat_voltage, NULL);
+
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "yeeloong\n");
+}
+
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static struct attribute *hwmon_attributes[] = {
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_name.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group hwmon_attribute_group = {
+ .attrs = hwmon_attributes
+};
+
+static struct device *yeeloong_hwmon_dev;
+
+static int yeeloong_hwmon_init(void)
+{
+ int ret;
+
+ yeeloong_hwmon_dev = hwmon_device_register(NULL);
+ if (IS_ERR(yeeloong_hwmon_dev)) {
+ yeeloong_hwmon_dev = NULL;
+ return PTR_ERR(yeeloong_hwmon_dev);
+ }
+ ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj,
+ &hwmon_attribute_group);
+ if (ret) {
+ hwmon_device_unregister(yeeloong_hwmon_dev);
+ yeeloong_hwmon_dev = NULL;
+ return ret;
+ }
+ /* ensure fan is set to auto mode */
+ set_fan_pwm_enable(2);
+
+ return 0;
+}
+
+static void yeeloong_hwmon_exit(void)
+{
+ if (yeeloong_hwmon_dev) {
+ sysfs_remove_group(&yeeloong_hwmon_dev->kobj,
+ &hwmon_attribute_group);
+ hwmon_device_unregister(yeeloong_hwmon_dev);
+ yeeloong_hwmon_dev = NULL;
+ }
+}
+
+/* video output subdriver */
+
+#define LCD 0
+#define CRT 1
+#define VOD_NUM 2 /* The total number of video output device*/
+
+static struct output_device *vod[VOD_NUM];
+
+static int vor[] = {REG_DISPLAY_LCD, REG_CRT_DETECT};
+
+static int get_vo_dev(struct output_device *od)
+{
+ int i, dev;
+
+ dev = -1;
+ for (i = 0; i < VOD_NUM; i++)
+ if (od == vod[i])
+ dev = i;
+
+ return dev;
+}
+
+static int vo_get_status(int dev)
+{
+ return ec_read(vor[dev]);
+}
+
+static int yeeloong_vo_get_status(struct output_device *od)
+{
+ int vd;
+
+ vd = get_vo_dev(od);
+ if (vd != -1)
+ return vo_get_status(vd);
+
+ return -ENODEV;
+}
+
+static void vo_set_state(int dev, int state)
+{
+ int addr;
+ unsigned long value;
+
+ switch (dev) {
+ case LCD:
+ addr = 0x31;
+ break;
+ case CRT:
+ addr = 0x21;
+ break;
+ default:
+ /* return directly if the wrong video output device */
+ return;
+ }
+
+ outb(addr, 0x3c4);
+ value = inb(0x3c5);
+
+ switch (dev) {
+ case LCD:
+ value |= (state ? 0x03 : 0x02);
+ break;
+ case CRT:
+ if (state)
+ clear_bit(7, &value);
+ else
+ set_bit(7, &value);
+ break;
+ default:
+ break;
+ }
+
+ outb(addr, 0x3c4);
+ outb(value, 0x3c5);
+
+ if (dev == LCD)
+ ec_write(REG_BACKLIGHT_CTRL, state);
+}
+
+static int yeeloong_vo_set_state(struct output_device *od)
+{
+ int vd;
+
+ vd = get_vo_dev(od);
+ if (vd == -1)
+ return -ENODEV;
+
+ if (vd == CRT && !vo_get_status(vd))
+ return 0;
+
+ vo_set_state(vd, !!od->request_state);
+
+ return 0;
+}
+
+static struct output_properties vop = {
+ .set_state = yeeloong_vo_set_state,
+ .get_status = yeeloong_vo_get_status,
+};
+
+static int yeeloong_vo_init(void)
+{
+ int ret, i;
+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"};
+
+ /* Register video output device: lcd, crt */
+ for (i = 0; i < VOD_NUM; i++) {
+ vod[i] = video_output_register(dev_name[i], NULL, NULL, &vop);
+ if (IS_ERR(vod[i])) {
+ if (i != 0)
+ video_output_unregister(vod[i-1]);
+ ret = PTR_ERR(vod[i]);
+ vod[i] = NULL;
+ return ret;
+ }
+ }
+ /* Ensure LCD is on by default */
+ vo_set_state(LCD, ON);
+
+ /*
+ * Turn off CRT by default, and will be enabled when the CRT
+ * connectting event reported by SCI
+ */
+ vo_set_state(CRT, OFF);
+
+ return 0;
+}
+
+static void yeeloong_vo_exit(void)
+{
+ int i;
+
+ for (i = 0; i < VOD_NUM; i++) {
+ if (vod[i]) {
+ video_output_unregister(vod[i]);
+ vod[i] = NULL;
+ }
+ }
+}
+
+/* lcd subdriver */
+
+struct lcd_device *lcd[VOD_NUM];
+
+static int get_lcd_dev(struct lcd_device *ld)
+{
+ int i, dev;
+
+ dev = -1;
+ for (i = 0; i < VOD_NUM; i++)
+ if (ld == lcd[i])
+ dev = i;
+
+ return dev;
+}
+
+static int yeeloong_lcd_set_power(struct lcd_device *ld, int power)
+{
+ int dev = get_lcd_dev(ld);
+
+ if (power == FB_BLANK_UNBLANK)
+ vo_set_state(dev, ON);
+ if (power == FB_BLANK_POWERDOWN)
+ vo_set_state(dev, OFF);
+
+ return 0;
+}
+
+static int yeeloong_lcd_get_power(struct lcd_device *ld)
+{
+ return vo_get_status(get_lcd_dev(ld));
+}
+
+static struct lcd_ops lcd_ops = {
+ .set_power = yeeloong_lcd_set_power,
+ .get_power = yeeloong_lcd_get_power,
+};
+
+static int yeeloong_lcd_init(void)
+{
+ int ret, i;
+ char dev_name[VOD_NUM][4] = {"LCD", "CRT"};
+
+ /* Register video output device: lcd, crt */
+ for (i = 0; i < VOD_NUM; i++) {
+ lcd[i] = lcd_device_register(dev_name[i], NULL, NULL, &lcd_ops);
+ if (IS_ERR(lcd[i])) {
+ if (i != 0)
+ lcd_device_unregister(lcd[i-1]);
+ ret = PTR_ERR(lcd[i]);
+ lcd[i] = NULL;
+ return ret;
+ }
+ }
+#if 0
+ /* This has been done by the vide output driver */
+
+ /* Ensure LCD is on by default */
+ vo_set_state(LCD, ON);
+
+ /*
+ * Turn off CRT by default, and will be enabled when the CRT
+ * connectting event reported by SCI
+ */
+ vo_set_state(CRT, OFF);
+#endif
+ return 0;
+}
+
+static void yeeloong_lcd_exit(void)
+{
+ int i;
+
+ for (i = 0; i < VOD_NUM; i++) {
+ if (lcd[i]) {
+ lcd_device_unregister(lcd[i]);
+ lcd[i] = NULL;
+ }
+ }
+}
+
+/* hotkey subdriver */
+
+static struct input_dev *yeeloong_hotkey_dev;
+
+static atomic_t reboot_flag, sleep_flag;
+#define in_sleep() (&sleep_flag)
+#define in_reboot() (&reboot_flag)
+
+static const struct key_entry yeeloong_keymap[] = {
+ {KE_SW, EVENT_LID, { SW_LID } },
+ {KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */
+ {KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */
+ {KE_KEY, EVENT_DISPLAYTOGGLE, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */
+ {KE_KEY, EVENT_SWITCHVIDEOMODE, { 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_DISPLAYTOGGLE] = {REG_DISPLAY_LCD, displaytoggle_handler},
+ [EVENT_DISPLAY_BRIGHTNESS] = {REG_DISPLAY_BRIGHTNESS, NULL},
+ [EVENT_LID] = {REG_LID_DETECT, NULL},
+ [EVENT_SWITCHVIDEOMODE] = {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 b983813..1d8b111 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -598,6 +598,7 @@
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
depends on X86 || ALPHA || ARM || M32R || ATARI || 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/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 6ae046b..4c46047 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -739,8 +739,8 @@
/* FIXME:
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
*/
- if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
- dev_warn(dev, "only 24-hr supported\n");
+ if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
+ dev_dbg(dev, "only 24-hr supported\n");
retval = -ENXIO;
goto cleanup1;
}
diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c
index 8add64b..df8d3fb 100644
--- a/drivers/staging/sm7xxfb/sm7xxfb.c
+++ b/drivers/staging/sm7xxfb/sm7xxfb.c
@@ -101,6 +101,7 @@
{"0x307", 1280, 1024, 8},
{"0x311", 640, 480, 16},
+ {"0x313", 800, 480, 16},
{"0x314", 800, 600, 16},
{"0x317", 1024, 768, 16},
{"0x31A", 1280, 1024, 16},
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 865946c..8b7434fdb 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -863,9 +863,13 @@
}
if (ints & OHCI_INTR_WDH) {
- spin_lock (&ohci->lock);
- dl_done_list (ohci);
- spin_unlock (&ohci->lock);
+ if (ohci->hcca->done_head == 0) {
+ ints &= ~OHCI_INTR_WDH;
+ } else {
+ spin_lock (&ohci->lock);
+ dl_done_list (ohci);
+ spin_unlock (&ohci->lock);
+ }
}
if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 66c9058..4fdeb97 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -353,6 +353,7 @@
}
EXPORT_SYMBOL_GPL(usb_amd_dev_put);
+#if defined(CONFIG_USB_UHCI_HCD) || defined(CONFIG_USB_UHCI_HCD_MODULE)
/*
* Make sure the controller is completely inactive, unable to
* generate interrupts or do DMA.
@@ -460,12 +461,16 @@
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;
@@ -544,7 +549,11 @@
/* 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) */
@@ -717,6 +726,9 @@
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
@@ -861,6 +873,7 @@
}
EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
+#if defined(CONFIG_USB_XHCI_HCD) || defined(CONFIG_USB_XHCI_HCD_MODULE)
/**
* PCI Quirks for xHCI.
*
@@ -968,6 +981,9 @@
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 096438e..08219b1 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -79,6 +79,9 @@
#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 @@
{ 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/Makefile b/drivers/video/Makefile
index e8bae8d..ad1d873 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -141,7 +141,7 @@
obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
obj-$(CONFIG_FB_OMAP) += omap/
-obj-y += omap2/
+obj-$(CONFIG_FB_OMAP2) += omap2/
obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
obj-$(CONFIG_FB_CARMINE) += carminefb.o
obj-$(CONFIG_FB_MB862XX) += mb862xx/
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_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 @@
#define SM501_USE_AC97 (1<<7)
#define SM501_USE_I2S (1<<8)
#define SM501_USE_GPIO (1<<9)
+#define SM501_USE_PWM (1<<10)
#define SM501_USE_ALL (0xffffffff)
diff --git a/init/calibrate.c b/init/calibrate.c
index fda0a7b..7b5b4e5 100644
--- a/init/calibrate.c
+++ b/init/calibrate.c
@@ -21,6 +21,7 @@
__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
@@ -168,6 +169,7 @@
#else
static unsigned long __cpuinit 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
@@ -279,6 +281,7 @@
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) {
@@ -289,7 +292,9 @@
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)
pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 1cec5e4..f6e5eae 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -113,7 +113,7 @@
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 679218b..4619488 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -306,14 +306,33 @@
$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
@@ -325,19 +344,12 @@
# 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