summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/Makefile13
-rw-r--r--arch/mips/config.in25
-rw-r--r--arch/mips/defconfig2
-rw-r--r--arch/mips/defconfig-atlas3
-rw-r--r--arch/mips/defconfig-ddb54763
-rw-r--r--arch/mips/defconfig-decstation3
-rw-r--r--arch/mips/defconfig-ev641203
-rw-r--r--arch/mips/defconfig-ev961003
-rw-r--r--arch/mips/defconfig-ip222
-rw-r--r--arch/mips/defconfig-it81723
-rw-r--r--arch/mips/defconfig-malta3
-rw-r--r--arch/mips/defconfig-ocelot3
-rw-r--r--arch/mips/defconfig-rm2002
-rw-r--r--arch/mips/kernel/Makefile8
-rw-r--r--arch/mips/kernel/proc.c3
-rw-r--r--arch/mips/kernel/r2300_fpu.S6
-rw-r--r--arch/mips/kernel/setup.c28
-rw-r--r--arch/mips/kernel/traps.c1
-rw-r--r--arch/mips/lib/Makefile6
-rw-r--r--arch/mips/mm/Makefile1
-rw-r--r--arch/mips/mm/loadmmu.c6
-rw-r--r--arch/mips/philips/drivers/.cvsignore2
-rw-r--r--arch/mips/philips/drivers/Makefile20
-rw-r--r--arch/mips/philips/drivers/generic_serial.c1078
-rw-r--r--arch/mips/philips/drivers/uart-pr31700.c1313
-rw-r--r--arch/mips/philips/drivers/uart-pr31700.h126
-rw-r--r--arch/mips/philips/nino/.cvsignore2
-rw-r--r--arch/mips/philips/nino/Makefile26
-rw-r--r--arch/mips/philips/nino/int-handler.S138
-rw-r--r--arch/mips/philips/nino/irq.c304
-rw-r--r--arch/mips/philips/nino/kgdb.c83
-rw-r--r--arch/mips/philips/nino/power.c36
-rw-r--r--arch/mips/philips/nino/prom.c83
-rw-r--r--arch/mips/philips/nino/reset.c37
-rw-r--r--arch/mips/philips/nino/rtc.c34
-rw-r--r--arch/mips/philips/nino/setup.c117
-rw-r--r--arch/mips/philips/nino/time.c216
-rw-r--r--arch/mips/philips/nino/wbflush.c36
-rw-r--r--drivers/char/Makefile5
-rw-r--r--include/asm-mips/bootinfo.h19
-rw-r--r--include/asm-mips/cache.h3
-rw-r--r--include/asm-mips/cpu.h2
-rw-r--r--include/asm-mips/isadep.h2
-rw-r--r--include/asm-mips/mipsregs.h33
-rw-r--r--include/asm-mips/mmu_context.h2
-rw-r--r--include/asm-mips/pgtable.h2
-rw-r--r--include/asm-mips/philips/pr31700.h609
-rw-r--r--include/asm-mips/stackframe.h2
-rw-r--r--include/asm-mips/string.h4
49 files changed, 4440 insertions, 21 deletions
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index cfcc8ab64..569ce05ea 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -51,6 +51,9 @@ endif
ifdef CONFIG_CPU_R3000
GCCFLAGS += -mcpu=r3000 -mips1
endif
+ifdef CONFIG_CPU_R3912
+GCCFLAGS += -mcpu=r3000 -mips1
+endif
ifdef CONFIG_CPU_R6000
GCCFLAGS += -mcpu=r6000 -mips2 -Wa,--trap
endif
@@ -218,6 +221,16 @@ LOADADDR += 0x80100000
endif
#
+# Philips Nino
+#
+ifdef CONFIG_NINO
+CORE_FILES += arch/mips/philips/nino/nino.o \
+ arch/mips/philips/drivers/drivers.o
+SUBDIRS += arch/mips/philips/nino arch/mips/philips/drivers
+LOADADDR += 0x80000000
+endif
+
+#
# ITE 8172 eval board with QED 5231 CPU
#
ifdef CONFIG_MIPS_ITE8172
diff --git a/arch/mips/config.in b/arch/mips/config.in
index 5b98968a0..4484bd651 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -31,6 +31,13 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
fi
bool 'Support for MIPS Atlas board' CONFIG_MIPS_ATLAS
bool 'Support for MIPS Malta board' CONFIG_MIPS_MALTA
+ bool 'Support for Philips Nino (EXPERIMENTAL)' CONFIG_NINO
+ if [ "$CONFIG_NINO" = "y" ]; then
+ choice 'Nino Model Number' \
+ "Model-300/301/302/319 CONFIG_NINO_4MB \
+ Model-200/210/312/320/325/350/390 CONFIG_NINO_8MB \
+ Model-500/510 CONFIG_NINO_16MB" CONFIG_NINO_8MB
+ fi
fi
bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000
bool 'Support for Momentum Ocelot board' CONFIG_MOMENCO_OCELOT
@@ -185,6 +192,7 @@ comment 'CPU selection'
choice 'CPU type' \
"R3000 CONFIG_CPU_R3000 \
+ R3912 CONFIG_CPU_R3912 \
R6000 CONFIG_CPU_R6000 \
R4300 CONFIG_CPU_R4300 \
R4x00 CONFIG_CPU_R4X00 \
@@ -211,15 +219,23 @@ else
define_bool CONFIG_CPU_HAS_WB n
fi
else
- define_bool CONFIG_CPU_HAS_LLSC y
- define_bool CONFIG_CPU_HAS_WB n
+ if [ "$CONFIG_CPU_R3912" = "y" ]; then
+ define_bool CONFIG_CPU_HAS_LLSC n
+ define_bool CONFIG_CPU_HAS_WB n
+ else
+ define_bool CONFIG_CPU_HAS_LLSC y
+ define_bool CONFIG_CPU_HAS_WB n
+ fi
fi
fi
endmenu
mainmenu_option next_comment
comment 'General setup'
-if [ "$CONFIG_DECSTATION" = "y" -o "$CONFIG_DDB5074" = "y" -o "$CONFIG_DDB5476" = "y" ]; then
+if [ "$CONFIG_DECSTATION" = "y" -o \
+ "$CONFIG_DDB5074" = "y" -o \
+ "$CONFIG_DDB5476" = "y" -o \
+ "$CONFIG_NINO" = "y" ]; then
define_bool CONFIG_CPU_LITTLE_ENDIAN y
else
bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
@@ -484,6 +500,9 @@ fi
if [ "$CONFIG_SERIAL" = "y" ]; then
bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
fi
+if [ "$CONFIG_SERIAL" = "y" ]; then
+ bool 'Low-level debugging' CONFIG_LL_DEBUG
+fi
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
if [ "$CONFIG_SMP" != "y" ]; then
bool 'Run uncached' CONFIG_MIPS_UNCACHED
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index 2d853e08f..9cea1dad3 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -21,6 +21,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_DDB5476 is not set
@@ -51,6 +52,7 @@ CONFIG_KMOD=y
# CPU selection
#
# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
diff --git a/arch/mips/defconfig-atlas b/arch/mips/defconfig-atlas
index ffef4845e..c4d0780e5 100644
--- a/arch/mips/defconfig-atlas
+++ b/arch/mips/defconfig-atlas
@@ -21,6 +21,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_MIPS_EV64120 is not set
CONFIG_MIPS_ATLAS=y
# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_DDB5476 is not set
@@ -46,6 +47,7 @@ CONFIG_SWAP_IO_SPACE=y
# CPU selection
#
# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
@@ -466,5 +468,6 @@ CONFIG_MSDOS_PARTITION=y
#
CONFIG_CROSSCOMPILE=y
# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_MIPS_UNCACHED is not set
diff --git a/arch/mips/defconfig-ddb5476 b/arch/mips/defconfig-ddb5476
index 5663e131b..f5aea46b9 100644
--- a/arch/mips/defconfig-ddb5476
+++ b/arch/mips/defconfig-ddb5476
@@ -21,6 +21,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MOMENCO_OCELOT is not set
CONFIG_DDB5476=y
@@ -47,6 +48,7 @@ CONFIG_EISA=y
# CPU selection
#
# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
@@ -534,5 +536,6 @@ CONFIG_FONT_8x16=y
#
CONFIG_CROSSCOMPILE=y
# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_MIPS_UNCACHED is not set
diff --git a/arch/mips/defconfig-decstation b/arch/mips/defconfig-decstation
index 080d4a561..872744d32 100644
--- a/arch/mips/defconfig-decstation
+++ b/arch/mips/defconfig-decstation
@@ -21,6 +21,7 @@ CONFIG_DECSTATION=y
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_DDB5476 is not set
@@ -47,6 +48,7 @@ CONFIG_KMOD=y
# CPU selection
#
CONFIG_CPU_R3000=y
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
@@ -339,5 +341,6 @@ CONFIG_ULTRIX_PARTITION=y
CONFIG_CROSSCOMPILE=y
# CONFIG_MIPS_FPE_MODULE is not set
# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_MIPS_UNCACHED is not set
diff --git a/arch/mips/defconfig-ev64120 b/arch/mips/defconfig-ev64120
index dd0fe79ee..8f08b2f7a 100644
--- a/arch/mips/defconfig-ev64120
+++ b/arch/mips/defconfig-ev64120
@@ -25,6 +25,7 @@ CONFIG_MIPS_EV64120=y
CONFIG_SYSCLK_100=y
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_DDB5476 is not set
@@ -53,6 +54,7 @@ CONFIG_MODULES=y
# CPU selection
#
# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
@@ -441,5 +443,6 @@ CONFIG_MSDOS_PARTITION=y
CONFIG_CROSSCOMPILE=y
# CONFIG_MIPS_FPE_MODULE is not set
# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_MIPS_UNCACHED is not set
diff --git a/arch/mips/defconfig-ev96100 b/arch/mips/defconfig-ev96100
index 5ad4bcf8d..7c7b0eb2e 100644
--- a/arch/mips/defconfig-ev96100
+++ b/arch/mips/defconfig-ev96100
@@ -21,6 +21,7 @@ CONFIG_MIPS_EV96100=y
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_DDB5476 is not set
@@ -49,6 +50,7 @@ CONFIG_MODULES=y
# CPU selection
#
# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
@@ -432,5 +434,6 @@ CONFIG_MSDOS_PARTITION=y
CONFIG_CROSSCOMPILE=y
# CONFIG_MIPS_FPE_MODULE is not set
# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_MIPS_UNCACHED is not set
diff --git a/arch/mips/defconfig-ip22 b/arch/mips/defconfig-ip22
index 2d853e08f..9cea1dad3 100644
--- a/arch/mips/defconfig-ip22
+++ b/arch/mips/defconfig-ip22
@@ -21,6 +21,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_DDB5476 is not set
@@ -51,6 +52,7 @@ CONFIG_KMOD=y
# CPU selection
#
# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
diff --git a/arch/mips/defconfig-it8172 b/arch/mips/defconfig-it8172
index 3fef74c3f..e8b3f37e8 100644
--- a/arch/mips/defconfig-it8172
+++ b/arch/mips/defconfig-it8172
@@ -21,6 +21,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_DDB5476 is not set
@@ -54,6 +55,7 @@ CONFIG_MODULES=y
# CPU selection
#
# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
@@ -562,5 +564,6 @@ CONFIG_MSDOS_PARTITION=y
CONFIG_CROSSCOMPILE=y
# CONFIG_MIPS_FPE_MODULE is not set
# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_MIPS_UNCACHED is not set
diff --git a/arch/mips/defconfig-malta b/arch/mips/defconfig-malta
index b0b9c5840..9e7c31c55 100644
--- a/arch/mips/defconfig-malta
+++ b/arch/mips/defconfig-malta
@@ -21,6 +21,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_ATLAS is not set
CONFIG_MIPS_MALTA=y
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_DDB5476 is not set
@@ -47,6 +48,7 @@ CONFIG_SWAP_IO_SPACE=y
# CPU selection
#
# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
@@ -465,5 +467,6 @@ CONFIG_MSDOS_PARTITION=y
#
CONFIG_CROSSCOMPILE=y
# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_MIPS_UNCACHED is not set
diff --git a/arch/mips/defconfig-ocelot b/arch/mips/defconfig-ocelot
index 92b695a5a..acf8331bb 100644
--- a/arch/mips/defconfig-ocelot
+++ b/arch/mips/defconfig-ocelot
@@ -21,6 +21,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
CONFIG_MOMENCO_OCELOT=y
# CONFIG_DDB5476 is not set
@@ -47,6 +48,7 @@ CONFIG_SWAP_IO_SPACE=y
# CPU selection
#
# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
@@ -428,5 +430,6 @@ CONFIG_MSDOS_PARTITION=y
#
CONFIG_CROSSCOMPILE=y
# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_MIPS_UNCACHED is not set
diff --git a/arch/mips/defconfig-rm200 b/arch/mips/defconfig-rm200
index 97f1afc53..a9c2aee2f 100644
--- a/arch/mips/defconfig-rm200
+++ b/arch/mips/defconfig-rm200
@@ -21,6 +21,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_DDB5476 is not set
@@ -50,6 +51,7 @@ CONFIG_KMOD=y
# CPU selection
#
# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 86947b0ba..b4c91f991 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -26,6 +26,9 @@ obj-$(CONFIG_MODULES) += mips_ksyms.o
ifdef CONFIG_CPU_R3000
obj-y += r2300_misc.o r2300_fpu.o r2300_switch.o
else
+ifdef CONFIG_CPU_R3912
+obj-y += r2300_misc.o r2300_fpu.o r2300_switch.o
+else
obj-y += r4k_misc.o r4k_switch.o
ifdef CONFIG_CPU_R6000
obj-y += r6000_fpu.o
@@ -33,6 +36,7 @@ else
obj-y += r4k_fpu.o
endif
endif
+endif
obj-$(CONFIG_MIPS_FPE_MODULE) += fpe.o
ifndef CONFIG_MIPS_FPU_EMULATOR
@@ -49,7 +53,9 @@ ifndef CONFIG_DECSTATION
ifndef CONFIG_MIPS_MALTA
ifndef CONFIG_MIPS_EV96100
ifndef CONFIG_MIPS_ITE8172
- obj-y += time.o
+ ifndef CONFIG_NINO
+ obj-y += time.o
+ endif
endif
endif
endif
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 34feb549d..671a6da84 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -40,12 +40,13 @@ int get_cpuinfo(char *buffer)
const char *mach_galileo_names[] = GROUP_GALILEO_NAMES;
const char *mach_momenco_names[] = GROUP_MOMENCO_NAMES;
const char *mach_ite_names[] = GROUP_ITE_NAMES;
+ const char *mach_phillips_names[] = GROUP_PHILIPS_NAMES;
const char **mach_group_to_name[] = { mach_unknown_names,
mach_jazz_names, mach_dec_names, mach_arc_names,
mach_sni_rm_names, mach_acn_names, mach_sgi_names,
mach_cobalt_names, mach_nec_ddb_names, mach_baget_names,
mach_cosine_names, mach_galileo_names, mach_momenco_names,
- mach_ite_names};
+ mach_ite_names, mach_phillips_names};
unsigned int version = read_32bit_cp0_register(CP0_PRID);
int len;
diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S
index 34881ef94..5489ea9b8 100644
--- a/arch/mips/kernel/r2300_fpu.S
+++ b/arch/mips/kernel/r2300_fpu.S
@@ -62,11 +62,11 @@ LEAF(_save_fp_context)
EX(swc1 $f29,(SC_FPREGS+232)(a0))
EX(swc1 $f30,(SC_FPREGS+240)(a0))
EX(swc1 $f31,(SC_FPREGS+248)(a0))
- EX(sw t1,SC_FPC_CSR(a0))
+ EX(sw t1,(SC_FPC_CSR)(a0))
cfc1 t0,$0 # implementation/version
jr ra
.set nomacro
- EX(sw t0,SC_FPC_EIR(a0))
+ EX(sw t0,(SC_FPC_EIR)(a0))
.set macro
END(_save_fp_context)
@@ -81,7 +81,7 @@ LEAF(_save_fp_context)
*/
LEAF(_restore_fp_context)
li v0, 0 # assume success
- EX(lw t0,SC_FPC_CSR(a0))
+ EX(lw t0,(SC_FPC_CSR)(a0))
EX(lwc1 $f0,(SC_FPREGS+0)(a0))
EX(lwc1 $f1,(SC_FPREGS+8)(a0))
EX(lwc1 $f2,(SC_FPREGS+16)(a0))
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index b2c71f054..1e9287b5f 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -209,12 +209,23 @@ static inline void cpu_probe(void)
mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
mips_cpu.tlbsize = 48;
break;
+/*
+ * This processor doesn't have an MMU, so it's not "real easy" to
+ * run Linux on it. It is left purely for documentation.
+ *
case PRID_IMP_R4650:
mips_cpu.cputype = CPU_R4650;
mips_cpu.isa_level = MIPS_CPU_ISA_III;
mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
mips_cpu.tlbsize = 48;
break;
+ */
+ case PRID_IMP_R3912:
+ mips_cpu.cputype = CPU_R3912;
+ mips_cpu.isa_level = MIPS_CPU_ISA_I;
+ mips_cpu.options = MIPS_CPU_TLB;
+ mips_cpu.tlbsize = 32;
+ break;
case PRID_IMP_R4700:
mips_cpu.cputype = CPU_R4700;
mips_cpu.isa_level = MIPS_CPU_ISA_III;
@@ -450,7 +461,11 @@ void __init setup_arch(char **cmdline_p)
void ev96100_setup(void);
void malta_setup(void);
void momenco_ocelot_setup(void);
+ void nino_setup(void);
+#ifdef CONFIG_BLK_DEV_INITRD
+ extern void * __rd_start, * __rd_end;
+#endif
unsigned long bootmap_size;
unsigned long start_pfn, max_pfn;
int i;
@@ -540,6 +555,11 @@ void __init setup_arch(char **cmdline_p)
it8172_setup();
break;
#endif
+#ifdef CONFIG_NINO
+ case MACH_GROUP_PHILIPS:
+ nino_setup();
+ break;
+#endif
default:
panic("Unsupported architecture");
}
@@ -626,6 +646,13 @@ void __init setup_arch(char **cmdline_p)
/* Reserve the bootmap memory. */
reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size);
+#ifdef CONFIG_NINO
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ initrd_start = (unsigned long)&__rd_start;
+ initrd_end = (unsigned long)&__rd_end;
+ initrd_below_start_ok = 1;
+#endif
+
#if 0
#ifdef CONFIG_BLK_DEV_INITRD
#error "Fixme, I'm broken."
@@ -698,4 +725,3 @@ void r4k_wait(void)
"wait\n\t"
".set\tmips0");
}
-
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index a6eb61ad0..2ca05ac74 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -906,6 +906,7 @@ void __init trap_init(void)
case CPU_R3052:
case CPU_R3081:
case CPU_R3081E:
+ case CPU_R3912:
save_fp_context = _save_fp_context;
restore_fp_context = _restore_fp_context;
memcpy((void *)KSEG0, &except_vec0_r2300, 0x80);
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 8d2a45406..b51696301 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -17,7 +17,11 @@ obj-y += csum_partial.o csum_partial_copy.o \
ifdef CONFIG_CPU_R3000
obj-y += r3k_dump_tlb.o
else
- obj-y += dump_tlb.o
+ ifdef CONFIG_CPU_R3912
+ obj-y += r3k_dump_tlb.o
+ else
+ obj-y += dump_tlb.o
+ endif
endif
obj-$(CONFIG_BLK_DEV_FD) += floppy-no.o floppy-std.o
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index 94dba1fde..57e3325dd 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -12,6 +12,7 @@ O_TARGET := mm.o
obj-y += extable.o init.o fault.o loadmmu.o
obj-$(CONFIG_CPU_R3000) += r2300.o
+obj-$(CONFIG_CPU_R3912) += r2300.o
obj-$(CONFIG_CPU_R4300) += r4xx0.o
obj-$(CONFIG_CPU_R4X00) += r4xx0.o
obj-$(CONFIG_CPU_R5000) += r4xx0.o
diff --git a/arch/mips/mm/loadmmu.c b/arch/mips/mm/loadmmu.c
index 8d618e913..2c5e2e9d6 100644
--- a/arch/mips/mm/loadmmu.c
+++ b/arch/mips/mm/loadmmu.c
@@ -74,6 +74,12 @@ void __init loadmmu(void)
ld_mmu_r2300();
break;
#endif
+#ifdef CONFIG_CPU_R3912
+ case CPU_R3912:
+ printk("Loading R[23]00 MMU routines.\n");
+ ld_mmu_r2300();
+ break;
+#endif
#if defined(CONFIG_CPU_R5432)
case CPU_R5432:
diff --git a/arch/mips/philips/drivers/.cvsignore b/arch/mips/philips/drivers/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/arch/mips/philips/drivers/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/arch/mips/philips/drivers/Makefile b/arch/mips/philips/drivers/Makefile
new file mode 100644
index 000000000..a0e316db0
--- /dev/null
+++ b/arch/mips/philips/drivers/Makefile
@@ -0,0 +1,20 @@
+#
+# Makefile for the Philips Nino specific parts of the kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.S.s:
+ $(CPP) $(AFLAGS) $< -o $@
+.S.o:
+ $(CC) $(AFLAGS) -c $< -o $@
+
+O_TARGET := drivers.o
+
+all: drivers.o
+
+obj-$(CONFIG_SERIAL) += uart-pr31700.o generic_serial.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/mips/philips/drivers/generic_serial.c b/arch/mips/philips/drivers/generic_serial.c
new file mode 100644
index 000000000..acd3402f8
--- /dev/null
+++ b/arch/mips/philips/drivers/generic_serial.c
@@ -0,0 +1,1078 @@
+/*
+ * generic_serial.c
+ *
+ * Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl
+ *
+ * written for the SX serial driver.
+ * Contains the code that should be shared over all the serial drivers.
+ *
+ * Credit for the idea to do it this way might go to Alan Cox.
+ *
+ *
+ * Version 0.1 -- December, 1998. Initial version.
+ * Version 0.2 -- March, 1999. Some more routines. Bugfixes. Etc.
+ * Version 0.5 -- August, 1999. Some more fixes. Reformat for Linus.
+ *
+ * BitWizard is actively maintaining this file. We sometimes find
+ * that someone submitted changes to this file. We really appreciate
+ * your help, but please submit changes through us. We're doing our
+ * best to be responsive. -- REW
+ * */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/mm.h>
+#include <linux/generic_serial.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#define DEBUG
+
+static char * tmp_buf;
+static DECLARE_MUTEX(tmp_buf_sem);
+
+static int gs_debug;
+
+#ifdef DEBUG
+#define gs_dprintk(f, str...) if (gs_debug & f) printk (str)
+#else
+#define gs_dprintk(f, str...) /* nothing */
+#endif
+
+#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
+#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit " __FUNCTION__ "\n")
+
+#if NEW_WRITE_LOCKING
+#define DECL /* Nothing */
+#define LOCKIT down (& port->port_write_sem);
+#define RELEASEIT up (&port->port_write_sem);
+#else
+#define DECL unsigned long flags;
+#define LOCKIT save_flags (flags);cli ()
+#define RELEASEIT restore_flags (flags)
+#endif
+
+#define RS_EVENT_WRITE_WAKEUP 1
+
+MODULE_PARM(gs_debug, "i");
+
+
+void gs_put_char(struct tty_struct * tty, unsigned char ch)
+{
+ struct gs_port *port;
+ DECL
+
+ func_enter ();
+
+ if (!tty) return;
+
+ port = tty->driver_data;
+
+ if (!port) return;
+
+ if (! (port->flags & ASYNC_INITIALIZED)) return;
+
+ /* Take a lock on the serial tranmit buffer! */
+ LOCKIT;
+
+ if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+ /* Sorry, buffer is full, drop character. Update statistics???? -- REW */
+ RELEASEIT;
+ return;
+ }
+
+ port->xmit_buf[port->xmit_head++] = ch;
+ port->xmit_head &= SERIAL_XMIT_SIZE - 1;
+ port->xmit_cnt++; /* Characters in buffer */
+
+ RELEASEIT;
+ func_exit ();
+}
+
+
+#ifdef NEW_WRITE_LOCKING
+
+/*
+> Problems to take into account are:
+> -1- Interrupts that empty part of the buffer.
+> -2- page faults on the access to userspace.
+> -3- Other processes that are also trying to do a "write".
+*/
+
+int gs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct gs_port *port;
+ int c, total = 0;
+ int t;
+
+ func_enter ();
+
+ if (!tty) return 0;
+
+ port = tty->driver;
+
+ if (!port) return 0;
+
+ if (! (port->flags & ASYNC_INITIALIZED))
+ return 0;
+
+ /* get exclusive "write" access to this port (problem 3) */
+ /* This is not a spinlock because we can have a disk access (page
+ fault) in copy_from_user */
+ down (& port->port_write_sem);
+
+ while (1) {
+
+ c = count;
+
+ /* This is safe because we "OWN" the "head". Noone else can
+ change the "head": we own the port_write_sem. */
+ /* Don't overrun the end of the buffer */
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+
+ /* This is safe because the xmit_cnt can only decrease. This
+ would increase "t", so we might copy too little chars. */
+ /* Don't copy past the "head" of the buffer */
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ /* Can't copy more? break out! */
+ if (c <= 0) break;
+ if (from_user)
+ copy_from_user (port->xmit_buf + port->xmit_head, buf, c);
+ else
+ memcpy (port->xmit_buf + port->xmit_head, buf, c);
+
+ port -> xmit_cnt += c;
+ port -> xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE -1);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ up (& port->port_write_sem);
+
+ gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n",
+ (port->flags & GS_TX_INTEN)?"enabled": "disabled");
+
+ if (port->xmit_cnt &&
+ !tty->stopped &&
+ !tty->hw_stopped &&
+ !(port->flags & GS_TX_INTEN)) {
+ port->flags |= GS_TX_INTEN;
+ port->rd->enable_tx_interrupts (port);
+ }
+ func_exit ();
+ return total;
+}
+#else
+/*
+> Problems to take into account are:
+> -1- Interrupts that empty part of the buffer.
+> -2- page faults on the access to userspace.
+> -3- Other processes that are also trying to do a "write".
+*/
+
+int gs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct gs_port *port;
+ int c, total = 0;
+ int t;
+ unsigned long flags;
+
+ func_enter ();
+
+ /* The standard serial driver returns 0 in this case.
+ That sounds to me as "No error, I just didn't get to writing any
+ bytes. Feel free to try again."
+ The "official" way to write n bytes from buf is:
+
+ for (nwritten = 0;nwritten < n;nwritten += rv) {
+ rv = write (fd, buf+nwritten, n-nwritten);
+ if (rv < 0) break; // Error: bail out. //
+ }
+
+ which will loop endlessly in this case. The manual page for write
+ agrees with me. In practise almost everybody writes
+ "write (fd, buf,n);" but some people might have had to deal with
+ incomplete writes in the past and correctly implemented it by now...
+ */
+
+ if (!tty) return -EIO;
+
+ port = tty->driver_data;
+ if (!port || !port->xmit_buf || !tmp_buf)
+ return -EIO;
+
+ save_flags(flags);
+ if (from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ c = count;
+
+ /* This is safe because we "OWN" the "head". Noone else can
+ change the "head": we own the port_write_sem. */
+ /* Don't overrun the end of the buffer */
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+
+ /* This is safe because the xmit_cnt can only decrease. This
+ would increase "t", so we might copy too little chars. */
+ /* Don't copy past the "head" of the buffer */
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ /* Can't copy more? break out! */
+ if (c <= 0) break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!total)
+ total = -EFAULT;
+ break;
+ }
+ cli();
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);
+ port->xmit_head = ((port->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ port->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ while (1) {
+ cli();
+ c = count;
+
+ /* This is safe because we "OWN" the "head". Noone else can
+ change the "head": we own the port_write_sem. */
+ /* Don't overrun the end of the buffer */
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+
+ /* This is safe because the xmit_cnt can only decrease. This
+ would increase "t", so we might copy too little chars. */
+ /* Don't copy past the "head" of the buffer */
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ /* Can't copy more? break out! */
+ if (c <= 0) {
+ restore_flags(flags);
+ break;
+ }
+ memcpy(port->xmit_buf + port->xmit_head, buf, c);
+ port->xmit_head = ((port->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ port->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ }
+
+ if (port->xmit_cnt &&
+ !tty->stopped &&
+ !tty->hw_stopped &&
+ !(port->flags & GS_TX_INTEN)) {
+ port->flags |= GS_TX_INTEN;
+ port->rd->enable_tx_interrupts (port);
+ }
+ func_exit ();
+ return total;
+}
+
+#endif
+
+
+
+int gs_write_room(struct tty_struct * tty)
+{
+ struct gs_port *port = tty->driver_data;
+ int ret;
+
+ func_enter ();
+ ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ func_exit ();
+ return ret;
+}
+
+
+int gs_chars_in_buffer(struct tty_struct *tty)
+{
+ struct gs_port *port = tty->driver_data;
+ func_enter ();
+
+ func_exit ();
+ return port->xmit_cnt;
+}
+
+
+int gs_real_chars_in_buffer(struct tty_struct *tty)
+{
+ struct gs_port *port;
+ func_enter ();
+
+ if (!tty) return 0;
+ port = tty->driver_data;
+
+ if (!port->rd) return 0;
+ if (!port->rd->chars_in_buffer) return 0;
+
+ func_exit ();
+ return port->xmit_cnt + port->rd->chars_in_buffer (port);
+}
+
+
+static int gs_wait_tx_flushed (void * ptr, int timeout)
+{
+ struct gs_port *port = ptr;
+ long end_jiffies;
+ int jiffies_to_transmit, charsleft = 0, rv = 0;
+ int to, rcib;
+
+ func_enter();
+
+ gs_dprintk (GS_DEBUG_FLUSH, "port=%p.\n", port);
+ if (port) {
+ gs_dprintk (GS_DEBUG_FLUSH, "xmit_cnt=%x, xmit_buf=%p, tty=%p.\n",
+ port->xmit_cnt, port->xmit_buf, port->tty);
+ }
+
+ if (!port || port->xmit_cnt < 0 || !port->xmit_buf) {
+ gs_dprintk (GS_DEBUG_FLUSH, "ERROR: !port, !port->xmit_buf or prot->xmit_cnt < 0.\n");
+ func_exit();
+ return -EINVAL; /* This is an error which we don't know how to handle. */
+ }
+
+ rcib = gs_real_chars_in_buffer(port->tty);
+
+ if(rcib <= 0) {
+ gs_dprintk (GS_DEBUG_FLUSH, "nothing to wait for.\n");
+ func_exit();
+ return rv;
+ }
+ /* stop trying: now + twice the time it would normally take + seconds */
+ end_jiffies = jiffies;
+ if (timeout != MAX_SCHEDULE_TIMEOUT)
+ end_jiffies += port->baud?(2 * rcib * 10 * HZ / port->baud):0;
+ end_jiffies += timeout;
+
+ gs_dprintk (GS_DEBUG_FLUSH, "now=%lx, end=%lx (%ld).\n",
+ jiffies, end_jiffies, end_jiffies-jiffies);
+
+ to = 100;
+ /* the expression is actually jiffies < end_jiffies, but that won't
+ work around the wraparound. Tricky eh? */
+ while (to-- &&
+ (charsleft = gs_real_chars_in_buffer (port->tty)) &&
+ time_after (end_jiffies, jiffies)) {
+ /* Units check:
+ chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies!
+ check! */
+
+ charsleft += 16; /* Allow 16 chars more to be transmitted ... */
+ jiffies_to_transmit = port->baud?(1 + charsleft * 10 * HZ / port->baud):0;
+ /* ^^^ Round up.... */
+ if (jiffies_to_transmit <= 0) jiffies_to_transmit = 1;
+
+ gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies "
+ "(%d chars).\n", jiffies_to_transmit, charsleft);
+
+ set_current_state (TASK_INTERRUPTIBLE);
+ schedule_timeout(jiffies_to_transmit);
+ if (signal_pending (current)) {
+ gs_dprintk (GS_DEBUG_FLUSH, "Signal pending. Bombing out: ");
+ rv = -EINTR;
+ break;
+ }
+ }
+
+ gs_dprintk (GS_DEBUG_FLUSH, "charsleft = %d.\n", charsleft);
+ set_current_state (TASK_RUNNING);
+
+ func_exit();
+ return rv;
+}
+
+
+
+void gs_flush_buffer(struct tty_struct *tty)
+{
+ struct gs_port *port;
+ unsigned long flags;
+
+ func_enter ();
+
+ if (!tty) return;
+
+ port = tty->driver_data;
+
+ if (!port) return;
+
+ /* XXX Would the write semaphore do? */
+ save_flags(flags); cli();
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ restore_flags(flags);
+
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ func_exit ();
+}
+
+
+void gs_flush_chars(struct tty_struct * tty)
+{
+ struct gs_port *port;
+
+ func_enter ();
+
+ if (!tty) return;
+
+ port = tty->driver_data;
+
+ if (!port) return;
+
+ if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !port->xmit_buf) {
+ func_exit ();
+ return;
+ }
+
+ /* Beats me -- REW */
+ port->flags |= GS_TX_INTEN;
+ port->rd->enable_tx_interrupts (port);
+ func_exit ();
+}
+
+
+void gs_stop(struct tty_struct * tty)
+{
+ struct gs_port *port;
+
+ func_enter ();
+
+ if (!tty) return;
+
+ port = tty->driver_data;
+
+ if (!port) return;
+
+ if (port->xmit_cnt &&
+ port->xmit_buf &&
+ (port->flags & GS_TX_INTEN) ) {
+ port->flags &= ~GS_TX_INTEN;
+ port->rd->disable_tx_interrupts (port);
+ }
+ func_exit ();
+}
+
+
+void gs_start(struct tty_struct * tty)
+{
+ struct gs_port *port;
+
+ if (!tty) return;
+
+ port = tty->driver_data;
+
+ if (!port) return;
+
+ if (port->xmit_cnt &&
+ port->xmit_buf &&
+ !(port->flags & GS_TX_INTEN) ) {
+ port->flags |= GS_TX_INTEN;
+ port->rd->enable_tx_interrupts (port);
+ }
+ func_exit ();
+}
+
+
+void gs_shutdown_port (struct gs_port *port)
+{
+ long flags;
+
+ func_enter();
+
+ if (!port) return;
+
+ if (!(port->flags & ASYNC_INITIALIZED))
+ return;
+
+ save_flags (flags);
+ cli ();
+
+ if (port->xmit_buf) {
+ free_page((unsigned long) port->xmit_buf);
+ port->xmit_buf = 0;
+ }
+
+ if (port->tty)
+ set_bit(TTY_IO_ERROR, &port->tty->flags);
+
+ port->rd->shutdown_port (port);
+
+ port->flags &= ~ASYNC_INITIALIZED;
+ restore_flags (flags);
+
+ func_exit();
+}
+
+
+void gs_hangup(struct tty_struct *tty)
+{
+ struct gs_port *port;
+
+ func_enter ();
+
+ if (!tty) return;
+
+ port = tty->driver_data;
+ tty = port->tty;
+ if (!tty)
+ return;
+
+ gs_shutdown_port (port);
+ port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE |GS_ACTIVE);
+ port->tty = NULL;
+ port->count = 0;
+
+ wake_up_interruptible(&port->open_wait);
+ func_exit ();
+}
+
+
+void gs_do_softint(void *private_)
+{
+ struct gs_port *port = private_;
+ struct tty_struct *tty;
+
+ func_enter ();
+
+ if (!port) return;
+
+ tty = port->tty;
+
+ if (!tty) return;
+
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+ func_exit ();
+}
+
+
+int gs_block_til_ready(void *port_, struct file * filp)
+{
+ struct gs_port *port = port_;
+ DECLARE_WAITQUEUE(wait, current);
+ int retval;
+ int do_clocal = 0;
+ int CD;
+ struct tty_struct *tty;
+
+ func_enter ();
+
+ if (!port) return 0;
+
+ tty = port->tty;
+
+ if (!tty) return 0;
+
+ gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n");
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&port->close_wait);
+ if (port->flags & ASYNC_HUP_NOTIFY)
+ return -EAGAIN;
+ else
+ return -ERESTARTSYS;
+ }
+
+ gs_dprintk (GS_DEBUG_BTR, "after hung up\n");
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == GS_TYPE_CALLOUT) {
+ if (port->flags & ASYNC_NORMAL_ACTIVE)
+ return -EBUSY;
+ if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (port->flags & ASYNC_SESSION_LOCKOUT) &&
+ (port->session != current->session))
+ return -EBUSY;
+ if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (port->flags & ASYNC_PGRP_LOCKOUT) &&
+ (port->pgrp != current->pgrp))
+ return -EBUSY;
+ port->flags |= ASYNC_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ gs_dprintk (GS_DEBUG_BTR, "after subtype\n");
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (port->flags & ASYNC_CALLOUT_ACTIVE)
+ return -EBUSY;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ gs_dprintk (GS_DEBUG_BTR, "after nonblock\n");
+
+ if (port->flags & ASYNC_CALLOUT_ACTIVE) {
+ if (port->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (C_CLOCAL(tty))
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, port->count is dropped by one, so that
+ * rs_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+
+ add_wait_queue(&port->open_wait, &wait);
+
+ gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n");
+ cli();
+ if (!tty_hung_up_p(filp))
+ port->count--;
+ sti();
+ port->blocked_open++;
+ while (1) {
+ CD = port->rd->get_CD (port);
+ gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD);
+ set_current_state (TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(port->flags & ASYNC_INITIALIZED)) {
+ if (port->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ break;
+ }
+ if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&
+ !(port->flags & ASYNC_CLOSING) &&
+ (do_clocal || CD))
+ break;
+ gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n",
+ (int)signal_pending (current), *(long*)(&current->blocked));
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n",
+ port->blocked_open);
+ set_current_state (TASK_RUNNING);
+ remove_wait_queue(&port->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ port->count++;
+ port->blocked_open--;
+ if (retval)
+ return retval;
+
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ func_exit ();
+ return 0;
+}
+
+
+void gs_close(struct tty_struct * tty, struct file * filp)
+{
+ unsigned long flags;
+ struct gs_port *port;
+
+ func_enter ();
+
+ if (!tty) return;
+
+ port = (struct gs_port *) tty->driver_data;
+
+ if (!port) return;
+
+ if (!port->tty) {
+ /* This seems to happen when this is called from vhangup. */
+ gs_dprintk (GS_DEBUG_CLOSE, "gs: Odd: port->tty is NULL\n");
+ port->tty = tty;
+ }
+
+ save_flags(flags); cli();
+
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ port->rd->hungup (port);
+ func_exit ();
+ return;
+ }
+
+ if ((tty->count == 1) && (port->count != 1)) {
+ printk(KERN_ERR "gs: gs_close: bad port count;"
+ " tty->count is 1, port count is %d\n", port->count);
+ port->count = 1;
+ }
+ if (--port->count < 0) {
+ printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count);
+ port->count = 0;
+ }
+ if (port->count) {
+ gs_dprintk(GS_DEBUG_CLOSE, "gs_close: count: %d\n", port->count);
+ restore_flags(flags);
+ func_exit ();
+ return;
+ }
+ port->flags |= ASYNC_CLOSING;
+
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (port->flags & ASYNC_NORMAL_ACTIVE)
+ port->normal_termios = *tty->termios;
+ if (port->flags & ASYNC_CALLOUT_ACTIVE)
+ port->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ /* if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, port->closing_wait); */
+
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receive line status interrupts, and tell the
+ * interrupt driver to stop checking the data ready bit in the
+ * line status register.
+ */
+
+ port->rd->disable_rx_interrupts (port);
+
+ /* close has no way of returning "EINTR", so discard return value */
+ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ gs_wait_tx_flushed (port, port->closing_wait);
+
+ port->flags &= ~GS_ACTIVE;
+
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+
+ port->event = 0;
+ port->rd->close (port);
+ port->rd->shutdown_port (port);
+ port->tty = 0;
+
+ if (port->blocked_open) {
+ if (port->close_delay) {
+ set_current_state (TASK_INTERRUPTIBLE);
+ schedule_timeout(port->close_delay);
+ }
+ wake_up_interruptible(&port->open_wait);
+ }
+ port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+ ASYNC_CLOSING | ASYNC_INITIALIZED);
+ wake_up_interruptible(&port->close_wait);
+
+ restore_flags(flags);
+ func_exit ();
+}
+
+
+static unsigned int gs_baudrates[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
+};
+
+
+void gs_set_termios (struct tty_struct * tty,
+ struct termios * old_termios)
+{
+ struct gs_port *port;
+ int baudrate, tmp, rv;
+ struct termios *tiosp;
+
+ func_enter();
+
+ if (!tty) return;
+
+ port = tty->driver_data;
+
+ if (!port) return;
+
+ tiosp = tty->termios;
+
+ if (gs_debug & GS_DEBUG_TERMIOS) {
+ gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);
+ }
+
+#if 0
+ /* This is an optimization that is only allowed for dumb cards */
+ /* Smart cards require knowledge of iflags and oflags too: that
+ might change hardware cooking mode.... */
+#endif
+ if (old_termios) {
+ if( (tiosp->c_iflag == old_termios->c_iflag)
+ && (tiosp->c_oflag == old_termios->c_oflag)
+ && (tiosp->c_cflag == old_termios->c_cflag)
+ && (tiosp->c_lflag == old_termios->c_lflag)
+ && (tiosp->c_line == old_termios->c_line)
+ && (memcmp(tiosp->c_cc, old_termios->c_cc, NCC) == 0)) {
+ gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: optimized away\n");
+ return /* 0 */;
+ }
+ } else
+ gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: no old_termios: "
+ "no optimization\n");
+
+ if(old_termios && (gs_debug & GS_DEBUG_TERMIOS)) {
+ if(tiosp->c_iflag != old_termios->c_iflag) printk("c_iflag changed\n");
+ if(tiosp->c_oflag != old_termios->c_oflag) printk("c_oflag changed\n");
+ if(tiosp->c_cflag != old_termios->c_cflag) printk("c_cflag changed\n");
+ if(tiosp->c_lflag != old_termios->c_lflag) printk("c_lflag changed\n");
+ if(tiosp->c_line != old_termios->c_line) printk("c_line changed\n");
+ if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n");
+ }
+
+ baudrate = tiosp->c_cflag & CBAUD;
+ if (baudrate & CBAUDEX) {
+ baudrate &= ~CBAUDEX;
+ if ((baudrate < 1) || (baudrate > 4))
+ tiosp->c_cflag &= ~CBAUDEX;
+ else
+ baudrate += 15;
+ }
+
+ baudrate = gs_baudrates[baudrate];
+ if ((tiosp->c_cflag & CBAUD) == B38400) {
+ if ( (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ baudrate = 57600;
+ else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ baudrate = 115200;
+ else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ baudrate = 230400;
+ else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ baudrate = 460800;
+ else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+ baudrate = (port->baud_base / port->custom_divisor);
+ }
+
+ /* I recommend using THIS instead of the mess in termios (and
+ duplicating the above code). Next we should create a clean
+ interface towards this variable. If your card supports arbitrary
+ baud rates, (e.g. CD1400 or 16550 based cards) then everything
+ will be very easy..... */
+ port->baud = baudrate;
+
+ /* Two timer ticks seems enough to wakeup something like SLIP driver */
+ /* Baudrate/10 is cps. Divide by HZ to get chars per tick. */
+ tmp = (baudrate / 10 / HZ) * 2;
+
+ if (tmp < 0) tmp = 0;
+ if (tmp >= SERIAL_XMIT_SIZE) tmp = SERIAL_XMIT_SIZE-1;
+
+ port->wakeup_chars = tmp;
+
+ /* We should really wait for the characters to be all sent before
+ changing the settings. -- CAL */
+ rv = gs_wait_tx_flushed (port, MAX_SCHEDULE_TIMEOUT);
+ if (rv < 0) return /* rv */;
+
+ rv = port->rd->set_real_termios(port);
+ if (rv < 0) return /* rv */;
+
+ if ((!old_termios ||
+ (old_termios->c_cflag & CRTSCTS)) &&
+ !( tiosp->c_cflag & CRTSCTS)) {
+ tty->stopped = 0;
+ gs_start(tty);
+ }
+
+#ifdef tytso_patch_94Nov25_1726
+ /* This "makes sense", Why is it commented out? */
+
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&info->open_wait);
+#endif
+
+ func_exit();
+ return /* 0 */;
+}
+
+
+
+/* Must be called with interrupts enabled */
+int gs_init_port(struct gs_port *port)
+{
+ unsigned long flags;
+ unsigned long page;
+
+ save_flags (flags);
+ if (!tmp_buf) {
+ page = get_free_page(GFP_KERNEL);
+
+ cli (); /* Don't expect this to make a difference. */
+ if (tmp_buf)
+ free_page(page);
+ else
+ tmp_buf = (unsigned char *) page;
+ restore_flags (flags);
+
+ if (!tmp_buf) {
+ return -ENOMEM;
+ }
+ }
+
+ if (port->flags & ASYNC_INITIALIZED)
+ return 0;
+
+ if (!port->xmit_buf) {
+ /* We may sleep in get_free_page() */
+ unsigned long tmp;
+
+ tmp = get_free_page(GFP_KERNEL);
+
+ /* Spinlock? */
+ cli ();
+ if (port->xmit_buf)
+ free_page (tmp);
+ else
+ port->xmit_buf = (unsigned char *) tmp;
+ restore_flags (flags);
+
+ if (!port->xmit_buf)
+ return -ENOMEM;
+ }
+
+ cli();
+
+ if (port->tty)
+ clear_bit(TTY_IO_ERROR, &port->tty->flags);
+
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+
+ gs_set_termios(port->tty, NULL);
+
+ port->flags |= ASYNC_INITIALIZED;
+ port->flags &= ~GS_TX_INTEN;
+
+ restore_flags(flags);
+ return 0;
+}
+
+
+int gs_setserial(struct gs_port *port, struct serial_struct *sp)
+{
+ struct serial_struct sio;
+
+ copy_from_user(&sio, sp, sizeof(struct serial_struct));
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((sio.baud_base != port->baud_base) ||
+ (sio.close_delay != port->close_delay) ||
+ ((sio.flags & ~ASYNC_USR_MASK) !=
+ (port->flags & ~ASYNC_USR_MASK)))
+ return(-EPERM);
+ }
+
+ port->flags = (port->flags & ~ASYNC_USR_MASK) |
+ (sio.flags & ASYNC_USR_MASK);
+
+ port->baud_base = sio.baud_base;
+ port->close_delay = sio.close_delay;
+ port->closing_wait = sio.closing_wait;
+ port->custom_divisor = sio.custom_divisor;
+
+ gs_set_termios (port->tty, NULL);
+
+ return 0;
+}
+
+
+/*****************************************************************************/
+
+/*
+ * Generate the serial struct info.
+ */
+
+void gs_getserial(struct gs_port *port, struct serial_struct *sp)
+{
+ struct serial_struct sio;
+
+ memset(&sio, 0, sizeof(struct serial_struct));
+ sio.flags = port->flags;
+ sio.baud_base = port->baud_base;
+ sio.close_delay = port->close_delay;
+ sio.closing_wait = port->closing_wait;
+ sio.custom_divisor = port->custom_divisor;
+ sio.hub6 = 0;
+
+ /* If you want you can override these. */
+ sio.type = PORT_UNKNOWN;
+ sio.xmit_fifo_size = -1;
+ sio.line = -1;
+ sio.port = -1;
+ sio.irq = -1;
+
+ if (port->rd->getserial)
+ port->rd->getserial (port, &sio);
+
+ copy_to_user(sp, &sio, sizeof(struct serial_struct));
+}
+
+EXPORT_SYMBOL(gs_put_char);
+EXPORT_SYMBOL(gs_write);
+EXPORT_SYMBOL(gs_write_room);
+EXPORT_SYMBOL(gs_chars_in_buffer);
+EXPORT_SYMBOL(gs_flush_buffer);
+EXPORT_SYMBOL(gs_flush_chars);
+EXPORT_SYMBOL(gs_stop);
+EXPORT_SYMBOL(gs_start);
+EXPORT_SYMBOL(gs_hangup);
+EXPORT_SYMBOL(gs_do_softint);
+EXPORT_SYMBOL(gs_block_til_ready);
+EXPORT_SYMBOL(gs_close);
+EXPORT_SYMBOL(gs_set_termios);
+EXPORT_SYMBOL(gs_init_port);
+EXPORT_SYMBOL(gs_setserial);
+EXPORT_SYMBOL(gs_getserial);
+
diff --git a/arch/mips/philips/drivers/uart-pr31700.c b/arch/mips/philips/drivers/uart-pr31700.c
new file mode 100644
index 000000000..92adb7056
--- /dev/null
+++ b/arch/mips/philips/drivers/uart-pr31700.c
@@ -0,0 +1,1313 @@
+/*
+ * Serial driver for r39xx
+ *
+ * Copyright (C) 2000 Jim Pick <jim@jimpick.com>
+ *
+ * Inspired by, and/or includes bits from:
+ *
+ * drivers/char/serial.c (standard serial driver)
+ * drivers/char/sx.c (use of generic_serial interface)
+ * drivers/char/esp.c (another UART that uses DMA)
+ * arch/mips/vr41xx/serial.c (another MIPS serial driver)
+ *
+ * Please see those files for credits.
+ *
+ * Also, the original rough serial console code was:
+ *
+ * Copyright (C) 1999 Harald Koerfgen
+ *
+ * $Id: r39xx_serial.c,v 1.16 2001/01/11 20:24:47 pavel Exp $
+ */
+
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <asm/uaccess.h>
+#include <asm/philips/pr31700.h>
+#include <asm/delay.h>
+#include <asm/wbflush.h>
+#include "uart-pr31700.h"
+
+/* Prototypes */
+
+static void rs_disable_tx_interrupts (void * ptr);
+static void rs_enable_tx_interrupts (void * ptr);
+static void rs_disable_rx_interrupts (void * ptr);
+static void rs_enable_rx_interrupts (void * ptr);
+static int rs_get_CD (void * ptr);
+static void rs_shutdown_port (void * ptr);
+static int rs_set_real_termios (void *ptr);
+static int rs_chars_in_buffer (void * ptr);
+static void rs_hungup (void *ptr);
+static void rs_close (void *ptr);
+
+
+
+static struct real_driver rs_real_driver = {
+ disable_tx_interrupts: rs_disable_tx_interrupts,
+ enable_tx_interrupts: rs_enable_tx_interrupts,
+ disable_rx_interrupts: rs_disable_rx_interrupts,
+ enable_rx_interrupts: rs_enable_rx_interrupts,
+ get_CD: rs_get_CD,
+ shutdown_port: rs_shutdown_port,
+ set_real_termios: rs_set_real_termios,
+ chars_in_buffer: rs_chars_in_buffer,
+ close: rs_close,
+ hungup: rs_hungup,
+};
+
+static struct tty_driver rs_driver, rs_callout_driver;
+
+static struct tty_struct * rs_table[RS_NPORTS] = { NULL, };
+static struct termios ** rs_termios;
+static struct termios ** rs_termios_locked;
+
+struct rs_port *rs_ports;
+int rs_refcount;
+int rs_initialized = 0;
+
+#ifdef CONFIG_PM
+static struct pm_dev *pmdev;
+static int pm_request(struct pm_dev* dev, pm_request_t req, void* data);
+#endif
+
+#define DEBUG
+#undef DEBUG2
+
+#ifdef DEBUG2
+int rs_debug = RS_DEBUG_ALL & ~RS_DEBUG_TRANSMIT;
+#else
+int rs_debug = 0;
+#endif
+
+
+/*
+ * Helper routines
+ */
+
+
+static inline unsigned int serial_in(struct rs_port *port, int offset)
+{
+ unsigned int tmp;
+
+ tmp = *(volatile unsigned int *)(port->base + offset);
+ tmp &= 0xff;
+ barrier();
+ return tmp;
+}
+
+static inline void serial_out(struct rs_port *port, int offset, int value)
+{
+ *(volatile unsigned int *)(port->base + offset) = (unsigned char)value;
+
+ barrier();
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines. All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt(). They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off. People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible. After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+
+
+static inline void receive_char_pio(struct rs_port *port)
+{
+ struct tty_struct *tty = port->gs.tty;
+ unsigned char ch;
+ int counter = 2048;
+
+ /* While there are characters, get them ... */
+ while (counter>0) {
+ // printk("R%08x", (int)port->base[UART_R39XX_CTRL1]);
+ if (!(port->base[UART_R39XX_CTRL1] & UART_RX_HOLD_FULL)) {
+ break;
+ }
+ ch = serial_in(port, UART_R39XX_DATA);
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ *tty->flip.char_buf_ptr++ = ch;
+ *tty->flip.flag_buf_ptr++ = 0;
+ tty->flip.count++;
+ }
+ udelay(1); /* Allow things to happen - it take a while */
+ counter--;
+ }
+ if (!counter)
+ printk( "Ugh, looped in receive_char_pio!\n" );
+
+ tty_flip_buffer_push(tty);
+#if 0
+ /* Now handle error conditions */
+ if (*status & (INTTYPE(UART_RXOVERRUN_INT) |
+ INTTYPE(UART_FRAMEERR_INT) |
+ INTTYPE(UART_PARITYERR_INT) |
+ INTTYPE(UART_BREAK_INT))) {
+
+ /*
+ * Now check to see if character should be
+ * ignored, and mask off conditions which
+ * should be ignored.
+ */
+ if (*status & port->ignore_status_mask) {
+ goto ignore_char;
+ }
+ *status &= port->read_status_mask;
+
+ if (*status & INTTYPE(UART_BREAK_INT)) {
+ rs_dprintk(RS_DEBUG_INTERRUPTS, "handling break....");
+ *tty->flip.flag_buf_ptr = TTY_BREAK;
+ }
+ else if (*status & INTTYPE(UART_PARITYERR_INT)) {
+ *tty->flip.flag_buf_ptr = TTY_PARITY;
+ }
+ else if (*status & INTTYPE(UART_FRAMEERR_INT)) {
+ *tty->flip.flag_buf_ptr = TTY_FRAME;
+ }
+ if (*status & INTTYPE(UART_RXOVERRUN_INT)) {
+ /*
+ * Overrun is special, since it's
+ * reported immediately, and doesn't
+ * affect the current character
+ */
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ tty->flip.count++;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ }
+ }
+ }
+
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+
+ ignore_char:
+
+ tty_flip_buffer_push(tty);
+#endif
+}
+
+static inline void transmit_char_pio(struct rs_port *port)
+{
+ /* While I'm able to transmit ... */
+ for (;;) {
+ // printk("T%08x", (int)port->base[UART_R39XX_CTRL1]);
+ if (!(port->base[UART_R39XX_CTRL1] & UART_TX_EMPTY)) {
+ break;
+ }
+ else if (port->x_char) {
+ serial_out(port, UART_R39XX_DATA, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ }
+ else if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped ||
+ port->gs.tty->hw_stopped) {
+ break;
+ }
+ else {
+ serial_out(port, UART_R39XX_DATA, port->gs.xmit_buf[port->gs.xmit_tail++]);
+ port->icount.tx++;
+ port->gs.xmit_tail &= SERIAL_XMIT_SIZE-1;
+ if (--port->gs.xmit_cnt <= 0) {
+ break;
+ }
+ }
+ udelay(10); /* Allow things to happen - it take a while */
+ }
+
+ if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped ||
+ port->gs.tty->hw_stopped) {
+ rs_disable_tx_interrupts(port);
+ }
+
+ if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {
+ if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ port->gs.tty->ldisc.write_wakeup)
+ (port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+ rs_dprintk (RS_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
+ port->gs.wakeup_chars);
+ wake_up_interruptible(&port->gs.tty->write_wait);
+ }
+}
+
+
+
+static inline void check_modem_status(struct rs_port *port)
+{
+ /* We don't have a carrier detect line - but just respond
+ like we had one anyways so that open() becomes unblocked */
+ wake_up_interruptible(&port->gs.open_wait);
+}
+
+int count = 0;
+
+/*
+ * This is the serial driver's interrupt routine (inlined, because
+ * there are two different versions of this, one for each serial port,
+ * differing only by the bits used in interrupt status 2 register)
+ */
+
+static inline void rs_rx_interrupt(int irq, void *dev_id,
+ struct pt_regs * regs, int intshift)
+{
+ struct rs_port * port;
+ unsigned long int2status;
+ unsigned long flags;
+ unsigned long ints;
+
+ save_and_cli(flags);
+
+ port = (struct rs_port *)dev_id;
+ /* rs_dprintk (RS_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift); */
+
+ /* Get the interrrupts we have enabled */
+ int2status = IntStatus2 & IntEnable2;
+
+ /* Get interrupts in easy to use form */
+ ints = int2status >> intshift;
+ // printk("IR%03x%03x", (int)(IntStatus2 >> intshift), (int)(IntEnable2 >> intshift));
+
+ /* Clear any interrupts we might be about to handle */
+ IntClear2 = int2status & (
+ (INTTYPE(UART_RXOVERRUN_INT) |
+ INTTYPE(UART_FRAMEERR_INT) |
+ INTTYPE(UART_BREAK_INT) |
+ INTTYPE(UART_PARITYERR_INT) |
+ INTTYPE(UART_RX_INT)) << intshift);
+
+ if (!port || !port->gs.tty) {
+ restore_flags(flags);
+ return;
+ }
+
+ /* RX Receiver Holding Register Overrun */
+ if (ints & INTTYPE(UART_RXOVERRUN_INT)) {
+ rs_dprintk (RS_DEBUG_INTERRUPTS, "overrun");
+ port->icount.overrun++;
+ }
+
+ /* RX Frame Error */
+ if (ints & INTTYPE(UART_FRAMEERR_INT)) {
+ rs_dprintk (RS_DEBUG_INTERRUPTS, "frame error");
+ port->icount.frame++;
+ }
+
+ /* Break signal received */
+ if (ints & INTTYPE(UART_BREAK_INT)) {
+ rs_dprintk (RS_DEBUG_INTERRUPTS, "break");
+ port->icount.brk++;
+ }
+
+ /* RX Parity Error */
+ if (ints & INTTYPE(UART_PARITYERR_INT)) {
+ rs_dprintk (RS_DEBUG_INTERRUPTS, "parity error");
+ port->icount.parity++;
+ }
+
+ /* Receive byte (non-DMA) */
+ if (ints & INTTYPE(UART_RX_INT)) {
+ receive_char_pio(port);
+ }
+
+ /*
+ check_modem_status();
+ */
+
+ // printk("OR%03x", (int)((IntStatus2 & IntEnable2) >> intshift));
+
+ restore_flags(flags);
+
+/* rs_dprintk (RS_DEBUG_INTERRUPTS, "end.\n"); */
+
+}
+
+static inline void rs_tx_interrupt(int irq, void *dev_id,
+ struct pt_regs * regs, int intshift)
+{
+ struct rs_port * port;
+ unsigned long int2status;
+ unsigned long flags;
+ unsigned long ints;
+
+ save_and_cli(flags);
+
+ port = (struct rs_port *)dev_id;
+ /* rs_dprintk (RS_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift); */
+
+ /* Get the interrrupts we have enabled */
+ int2status = IntStatus2 & IntEnable2;
+
+ if (!port || !port->gs.tty) {
+ restore_flags(flags);
+ return;
+ }
+
+ /* Get interrupts in easy to use form */
+ ints = int2status >> intshift;
+
+ /* Clear any interrupts we might be about to handle */
+ IntClear2 = int2status & (
+ (INTTYPE(UART_TX_INT) |
+ INTTYPE(UART_EMPTY_INT) |
+ INTTYPE(UART_TXOVERRUN_INT)) << intshift);
+
+ //printk("IT%03x", (int)ints);
+
+ /* TX holding register empty, so transmit byte (non-DMA) */
+ if (ints & (INTTYPE(UART_TX_INT) | INTTYPE(UART_EMPTY_INT))) {
+ transmit_char_pio(port);
+ }
+
+ /* TX Transmit Holding Register Overrun (shouldn't happen) */
+ if (ints & INTTYPE(UART_TXOVERRUN_INT)) {
+ printk ( "rs: TX overrun\n");
+ }
+
+ /*
+ check_modem_status();
+ */
+
+ restore_flags(flags);
+
+/* rs_dprintk (RS_DEBUG_INTERRUPTS, "end.\n"); */
+
+}
+
+static void rs_rx_interrupt_uarta(int irq, void *dev_id,
+ struct pt_regs * regs)
+{
+ rs_rx_interrupt(irq, dev_id, regs, UARTA_SHIFT);
+}
+
+static void rs_tx_interrupt_uarta(int irq, void *dev_id,
+ struct pt_regs * regs)
+{
+ rs_tx_interrupt(irq, dev_id, regs, UARTA_SHIFT);
+}
+
+#if 0
+static void rs_interrupt_uartb(int irq, void *dev_id,
+ struct pt_regs * regs)
+{
+ rs_interrupt(irq, dev_id, regs, UARTB_SHIFT);
+}
+#endif
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+
+
+
+
+/* ********************************************************************** *
+ * Here are the routines that actually *
+ * interface with the generic_serial driver *
+ * ********************************************************************** */
+
+static void rs_disable_tx_interrupts (void * ptr)
+{
+ struct rs_port *port = ptr;
+ unsigned long flags;
+
+ save_and_cli(flags);
+ port->gs.flags &= ~GS_TX_INTEN;
+
+ IntEnable2 &= ~((INTTYPE(UART_TX_INT) |
+ INTTYPE(UART_EMPTY_INT) |
+ INTTYPE(UART_TXOVERRUN_INT)) << port->intshift);
+
+ IntClear2 = (INTTYPE(UART_TX_INT) |
+ INTTYPE(UART_EMPTY_INT) |
+ INTTYPE(UART_TXOVERRUN_INT)) << port->intshift;
+
+ restore_flags(flags);
+}
+
+
+static void rs_enable_tx_interrupts (void * ptr)
+{
+ struct rs_port *port = ptr;
+ unsigned long flags;
+
+ save_and_cli(flags);
+
+ IntClear2 = (INTTYPE(UART_TX_INT) |
+ INTTYPE(UART_EMPTY_INT) |
+ INTTYPE(UART_TXOVERRUN_INT)) << port->intshift;
+
+ IntEnable2 |= (INTTYPE(UART_TX_INT) |
+ INTTYPE(UART_EMPTY_INT) |
+ INTTYPE(UART_TXOVERRUN_INT)) << port->intshift;
+
+ /* Send a char to start TX interrupts happening */
+ transmit_char_pio(port);
+
+ restore_flags(flags);
+}
+
+
+static void rs_disable_rx_interrupts (void * ptr)
+{
+ struct rs_port *port = ptr;
+ unsigned long flags;
+
+ save_and_cli(flags);
+
+ IntEnable2 &= ~((INTTYPE(UART_RX_INT) |
+ INTTYPE(UART_RXOVERRUN_INT) |
+ INTTYPE(UART_FRAMEERR_INT) |
+ INTTYPE(UART_BREAK_INT) |
+ INTTYPE(UART_PARITYERR_INT)) << port->intshift);
+
+ IntClear2 = (INTTYPE(UART_RX_INT) |
+ INTTYPE(UART_RXOVERRUN_INT) |
+ INTTYPE(UART_FRAMEERR_INT) |
+ INTTYPE(UART_BREAK_INT) |
+ INTTYPE(UART_PARITYERR_INT)) << port->intshift;
+
+ restore_flags(flags);
+}
+
+static void rs_enable_rx_interrupts (void * ptr)
+{
+ struct rs_port *port = ptr;
+ unsigned long flags;
+
+ save_and_cli(flags);
+
+ IntEnable2 |= (INTTYPE(UART_RX_INT) |
+ INTTYPE(UART_RXOVERRUN_INT) |
+ INTTYPE(UART_FRAMEERR_INT) |
+ INTTYPE(UART_BREAK_INT) |
+ INTTYPE(UART_PARITYERR_INT)) << port->intshift;
+
+ /* Empty the input buffer - apparently this is *vital* */
+ while (port->base[UART_R39XX_CTRL1] & UART_RX_HOLD_FULL) {
+ serial_in(port, UART_R39XX_DATA);
+ }
+
+ IntClear2 = (INTTYPE(UART_RX_INT) |
+ INTTYPE(UART_RXOVERRUN_INT) |
+ INTTYPE(UART_FRAMEERR_INT) |
+ INTTYPE(UART_BREAK_INT) |
+ INTTYPE(UART_PARITYERR_INT)) << port->intshift;
+
+ restore_flags(flags);
+}
+
+
+static int rs_get_CD (void * ptr)
+{
+ struct rs_port *port = ptr;
+ func_enter2();
+
+ /* No Carried Detect in Hardware - just return true */
+
+ func_exit();
+ return (1);
+}
+
+
+
+
+static void rs_shutdown_port (void * ptr)
+{
+ struct rs_port *port = ptr;
+
+ func_enter();
+
+ port->gs.flags &= ~ GS_ACTIVE;
+
+ /* Jim: Disable interrupts and power down port? */
+
+ func_exit();
+}
+
+
+
+static int rs_set_real_termios (void *ptr)
+{
+ struct rs_port *port = ptr;
+ int t;
+
+ func_enter2();
+
+ switch (port->gs.baud) {
+ /* Save some typing work... */
+#define e(x) case x:t= SER_BAUD_ ## x ; break
+ e(300);e(600);e(1200);e(2400);e(4800);e(9600);
+ e(19200);e(38400);e(57600);e(76800);e(115200);e(230400);
+ case 0 :t = -1;
+ break;
+ default:
+ /* Can I return "invalid"? */
+ t = SER_BAUD_9600;
+ printk (KERN_INFO "rs: unsupported baud rate: %d.\n", port->gs.baud);
+ break;
+ }
+#undef e
+ if (t >= 0) {
+ /* Jim: Set Hardware Baud rate - there is some good
+ code in drivers/char/serial.c */
+
+ /* Program hardware for parity, data bits, stop bits (note: these are hardcoded to 8N1 */
+ UartA_Ctrl1 &= 0xf000000f;
+ UartA_Ctrl1 &= ~(UART_DIS_TXD | SER_SEVEN_BIT | SER_EVEN_PARITY | SER_TWO_STOP);
+
+#define CFLAG port->gs.tty->termios->c_cflag
+ if (C_PARENB(port->gs.tty))
+ if (!C_PARODD(port->gs.tty))
+ UartA_Ctrl1 |= SER_EVEN_PARITY;
+ else
+ UartA_Ctrl1 |= SER_ODD_PARITY;
+ if ((CFLAG & CSIZE)==CS6)
+ printk(KERN_ERR "6 bits not supported\n");
+ if ((CFLAG & CSIZE)==CS5)
+ printk(KERN_ERR "5 bits not supported\n");
+ if ((CFLAG & CSIZE)==CS7)
+ UartA_Ctrl1 |= SER_SEVEN_BIT;
+ if (C_CSTOPB(port->gs.tty))
+ UartA_Ctrl1 |= SER_TWO_STOP;
+
+ UartA_Ctrl2 = t;
+ UartA_DMActl1 = 0;
+ UartA_DMActl2 = 0;
+ UartA_Ctrl1 |= UART_ON;
+ }
+
+ /* Jim: Lots of good stuff in drivers/char/serial.c:change_speed() */
+
+ func_exit ();
+ return 0;
+}
+
+
+static int rs_chars_in_buffer (void * ptr)
+{
+ struct rs_port *port = ptr;
+ int scratch;
+/* func_enter2(); */
+
+ scratch = serial_in(port, UART_R39XX_CTRL1);
+
+/* func_exit(); */
+ return ( (scratch & UART_TX_EMPTY) ? 0 : 1 );
+}
+
+
+
+/* ********************************************************************** *
+ * Here are the routines that actually *
+ * interface with the rest of the system *
+ * ********************************************************************** */
+
+
+static int rs_open (struct tty_struct * tty, struct file * filp)
+{
+ struct rs_port *port;
+ int retval, line;
+
+ func_enter();
+
+ if (!rs_initialized) {
+ return -EIO;
+ }
+
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ rs_dprintk (RS_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p)\n",
+ (int) current->pid, line, tty, current->tty);
+
+ if ((line < 0) || (line >= RS_NPORTS))
+ return -ENODEV;
+
+ /* Pre-initialized already */
+ port = & rs_ports[line];
+
+ rs_dprintk (RS_DEBUG_OPEN, "port = %p\n", port);
+
+ tty->driver_data = port;
+ port->gs.tty = tty;
+ port->gs.count++;
+
+ rs_dprintk (RS_DEBUG_OPEN, "starting port\n");
+
+ /*
+ * Start up serial port
+ */
+ retval = gs_init_port(&port->gs);
+ rs_dprintk (RS_DEBUG_OPEN, "done gs_init\n");
+ if (retval) {
+ port->gs.count--;
+ return retval;
+ }
+
+ port->gs.flags |= GS_ACTIVE;
+
+ rs_dprintk (RS_DEBUG_OPEN, "before inc_use_count (count=%d.\n",
+ port->gs.count);
+ if (port->gs.count == 1) {
+ MOD_INC_USE_COUNT;
+ }
+ rs_dprintk (RS_DEBUG_OPEN, "after inc_use_count\n");
+
+ /* Jim: Initialize port hardware here */
+
+ /* Enable high-priority interrupts for UARTA */
+ IntEnable6 |= INT6_UARTARXINT;
+ rs_enable_rx_interrupts(&rs_ports[0]);
+
+ retval = gs_block_til_ready(&port->gs, filp);
+ rs_dprintk (RS_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",
+ retval, port->gs.count);
+
+ if (retval) {
+ MOD_DEC_USE_COUNT;
+ port->gs.count--;
+ return retval;
+ }
+ /* tty->low_latency = 1; */
+
+ if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = port->gs.normal_termios;
+ else
+ *tty->termios = port->gs.callout_termios;
+ rs_set_real_termios (port);
+ }
+
+ port->gs.session = current->session;
+ port->gs.pgrp = current->pgrp;
+ func_exit();
+
+ /* Jim */
+/* cli(); */
+
+ return 0;
+
+}
+
+
+
+static void rs_close (void *ptr)
+{
+ func_enter ();
+
+ /* Anything to do here? */
+
+ MOD_DEC_USE_COUNT;
+ func_exit ();
+}
+
+
+/* I haven't the foggiest why the decrement use count has to happen
+ here. The whole linux serial drivers stuff needs to be redesigned.
+ My guess is that this is a hack to minimize the impact of a bug
+ elsewhere. Thinking about it some more. (try it sometime) Try
+ running minicom on a serial port that is driven by a modularized
+ driver. Have the modem hangup. Then remove the driver module. Then
+ exit minicom. I expect an "oops". -- REW */
+static void rs_hungup (void *ptr)
+{
+ func_enter ();
+ MOD_DEC_USE_COUNT;
+ func_exit ();
+}
+
+static int rs_ioctl (struct tty_struct * tty, struct file * filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc;
+ struct rs_port *port = tty->driver_data;
+ int ival;
+
+ /* func_enter2(); */
+
+ rc = 0;
+ switch (cmd) {
+ case TIOCGSOFTCAR:
+ rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
+ (unsigned int *) arg);
+ break;
+ case TIOCSSOFTCAR:
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(int))) == 0) {
+ get_user(ival, (unsigned int *) arg);
+ tty->termios->c_cflag =
+ (tty->termios->c_cflag & ~CLOCAL) |
+ (ival ? CLOCAL : 0);
+ }
+ break;
+ case TIOCGSERIAL:
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct serial_struct))) == 0)
+ gs_getserial(&port->gs, (struct serial_struct *) arg);
+ break;
+ case TIOCSSERIAL:
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(struct serial_struct))) == 0)
+ rc = gs_setserial(&port->gs, (struct serial_struct *) arg);
+ break;
+ default:
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+
+ /* func_exit(); */
+ return rc;
+}
+
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_send_xchar(struct tty_struct * tty, char ch)
+{
+ struct rs_port *port = (struct rs_port *)tty->driver_data;
+ func_enter ();
+
+ port->x_char = ch;
+ if (ch) {
+ /* Make sure transmit interrupts are on */
+ rs_enable_tx_interrupts(tty);
+ }
+
+ func_exit();
+}
+
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+#ifdef RS_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("throttle %s: %d....\n", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ func_enter ();
+
+ if (I_IXOFF(tty))
+ rs_send_xchar(tty, STOP_CHAR(tty));
+
+ func_exit ();
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+ struct rs_port *port = (struct rs_port *)tty->driver_data;
+#ifdef RS_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ func_enter();
+
+ if (I_IXOFF(tty)) {
+ if (port->x_char)
+ port->x_char = 0;
+ else
+ rs_send_xchar(tty, START_CHAR(tty));
+ }
+
+ func_exit();
+}
+
+
+
+
+
+/* ********************************************************************** *
+ * Here are the initialization routines. *
+ * ********************************************************************** */
+
+void * ckmalloc (int size)
+{
+ void *p;
+
+ p = kmalloc(size, GFP_KERNEL);
+ if (p)
+ memset(p, 0, size);
+ return p;
+}
+
+
+
+static int rs_init_portstructs(void)
+{
+ struct rs_port *port;
+ int i;
+
+ func_enter();
+
+ /* Many drivers statically allocate the maximum number of ports
+ There is no reason not to allocate them dynamically. Is there? -- REW */
+ rs_ports = ckmalloc(RS_NPORTS * sizeof (struct rs_port));
+ if (!rs_ports)
+ return -ENOMEM;
+
+ rs_termios = ckmalloc(RS_NPORTS * sizeof (struct termios *));
+ if (!rs_termios) {
+ kfree (rs_ports);
+ return -ENOMEM;
+ }
+
+ rs_termios_locked = ckmalloc(RS_NPORTS * sizeof (struct termios *));
+ if (!rs_termios_locked) {
+ kfree (rs_ports);
+ kfree (rs_termios);
+ return -ENOMEM;
+ }
+
+ /* Adjust the values in the "driver" */
+ rs_driver.termios = rs_termios;
+ rs_driver.termios_locked = rs_termios_locked;
+
+ port = rs_ports;
+ for (i=0; i < RS_NPORTS;i++) {
+ rs_dprintk (RS_DEBUG_INIT, "initing port %d\n", i);
+ port->gs.callout_termios = tty_std_termios;
+ port->gs.normal_termios = tty_std_termios;
+ port->gs.magic = SERIAL_MAGIC;
+ port->gs.close_delay = HZ/2;
+ port->gs.closing_wait = 30 * HZ;
+ port->gs.rd = &rs_real_driver;
+#ifdef NEW_WRITE_LOCKING
+ port->gs.port_write_sem = MUTEX;
+#endif
+#ifdef DECLARE_WAITQUEUE
+ init_waitqueue_head(&port->gs.open_wait);
+ init_waitqueue_head(&port->gs.close_wait);
+#endif
+ port->base = (i == 0) ? (unsigned long *) &UartA_Ctrl1 :
+ (unsigned long *) &UartB_Ctrl1;
+ port->intshift = (i == 0) ? UARTA_SHIFT : UARTB_SHIFT;
+ rs_dprintk (RS_DEBUG_INIT, "base %p intshift %d\n",
+ port->base, port->intshift);
+ port++;
+ }
+
+ func_exit();
+ return 0;
+}
+
+static int rs_init_drivers(void)
+{
+ int error;
+
+ func_enter();
+
+ memset(&rs_driver, 0, sizeof(rs_driver));
+ rs_driver.magic = TTY_DRIVER_MAGIC;
+ rs_driver.driver_name = "serial";
+ rs_driver.name = "ttyS";
+ rs_driver.major = TTY_MAJOR;
+ rs_driver.minor_start = 64;
+ rs_driver.num = RS_NPORTS;
+ rs_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ rs_driver.subtype = SERIAL_TYPE_NORMAL;
+ rs_driver.init_termios = tty_std_termios;
+ rs_driver.init_termios.c_cflag =
+ //B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+ rs_driver.flags = TTY_DRIVER_REAL_RAW;
+ rs_driver.refcount = &rs_refcount;
+ rs_driver.table = rs_table;
+ rs_driver.termios = rs_termios;
+ rs_driver.termios_locked = rs_termios_locked;
+
+ rs_driver.open = rs_open;
+ rs_driver.close = gs_close;
+ rs_driver.write = gs_write;
+ rs_driver.put_char = gs_put_char;
+ rs_driver.flush_chars = gs_flush_chars;
+ rs_driver.write_room = gs_write_room;
+ rs_driver.chars_in_buffer = gs_chars_in_buffer;
+ rs_driver.flush_buffer = gs_flush_buffer;
+ rs_driver.ioctl = rs_ioctl;
+ rs_driver.throttle = rs_throttle;
+ rs_driver.unthrottle = rs_unthrottle;
+ rs_driver.set_termios = gs_set_termios;
+ rs_driver.stop = gs_stop;
+ rs_driver.start = gs_start;
+ rs_driver.hangup = gs_hangup;
+
+ rs_callout_driver = rs_driver;
+ rs_callout_driver.name = "cua";
+ rs_callout_driver.major = TTYAUX_MAJOR;
+ rs_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+ if ((error = tty_register_driver(&rs_driver))) {
+ printk(KERN_ERR "Couldn't register serial driver, error = %d\n",
+ error);
+ return 1;
+ }
+ if ((error = tty_register_driver(&rs_callout_driver))) {
+ tty_unregister_driver(&rs_driver);
+ printk(KERN_ERR "Couldn't register callout driver, error = %d\n",
+ error);
+ return 1;
+ }
+
+ func_exit();
+ return 0;
+}
+
+
+static void rs_release_drivers(void)
+{
+ func_enter();
+ tty_unregister_driver(&rs_driver);
+ tty_unregister_driver(&rs_callout_driver);
+#ifdef CONFIG_PM
+ pm_unregister(pmdev);
+#endif
+ func_exit();
+}
+
+#if defined(CONFIG_VTECH_HELIO) && defined(CONFIG_PM)
+static
+int pm_request(struct pm_dev* dev, pm_request_t req, void* data)
+{
+ static unsigned long ctrlA;
+ static unsigned long ctrlB;
+ static unsigned long clk;
+ static unsigned long out;
+
+ switch (req) {
+ case PM_SUSPEND:
+ /* disable both uarts */
+ ctrlA = UartA_Ctrl1 & (UART_ENABLE | UART_DIS_TXD);
+ UartA_Ctrl1 &= ~UART_ENABLE;
+#if 0 /* would be nice if this worked, but it hangs the suspend process for me - 20001030 nop */
+ while (UartA_Ctrl1 & UART_ON)
+ /*wait till its empty */;
+#endif
+ UartA_Ctrl1 |= UART_DIS_TXD;
+ ctrlB = UartB_Ctrl1 & (UART_ENABLE | UART_DIS_TXD);
+ UartB_Ctrl1 &= ~UART_ENABLE;
+#if 0 /* would be nice if this worked */
+ while (UartB_Ctrl1 & UART_ON)
+ /*wait till its empty */;
+#endif
+ UartB_Ctrl1 |= UART_DIS_TXD;
+
+ /* turn the clocks off */
+ clk = ClockControl & (CLK_EN_UART_A | CLK_EN_UART_B);
+ ClockControl &= ~(CLK_EN_UART_A | CLK_EN_UART_B);
+
+ /* remember the state of these pins */
+ out = MFIOOutput & (MFIO_PIN_UART_TX_ENABLE |
+ MFIO_PIN_UART_RX_DISABLE |
+ MFIO_PIN_MODEM_RTS);
+
+ MFIOOutput &= ~MFIO_PIN_UART_TX_ENABLE;
+ MFIOOutput |= (MFIO_PIN_UART_RX_DISABLE | /* Set High (Disable RX) */
+ MFIO_PIN_MODEM_RTS);
+ break;
+
+ case PM_RESUME:
+
+ /* restore the driver pin state */
+ MFIOOutput = (MFIOOutput & ~(MFIO_PIN_UART_TX_ENABLE |
+ MFIO_PIN_UART_RX_DISABLE |
+ MFIO_PIN_MODEM_RTS)) | out;
+
+ /* restore the clock */
+ ClockControl = (ClockControl & ~(CLK_EN_UART_A | CLK_EN_UART_B)) | clk;
+
+ /* restore the Uart state */
+ UartA_Ctrl1 = (UartA_Ctrl1 & ~(UART_ENABLE | UART_DIS_TXD))
+ | ctrlA;
+ UartB_Ctrl1 = (UartB_Ctrl1 & ~(UART_ENABLE | UART_DIS_TXD))
+ | ctrlB;
+ break;
+ }
+ return 0;
+}
+#endif
+
+
+int __init rs_init(void)
+{
+ int rc;
+
+ func_enter();
+ rs_dprintk (RS_DEBUG_INIT, "Initing serial module... (rs_debug=%d)\n", rs_debug);
+
+ if (abs ((long) (&rs_debug) - rs_debug) < 0x10000) {
+ printk (KERN_WARNING "rs: rs_debug is an address, instead of a value. "
+ "Assuming -1.\n");
+ printk ("(%p)\n", &rs_debug);
+ rs_debug=-1;
+ }
+
+ rc = rs_init_portstructs ();
+ rs_init_drivers ();
+ if (request_irq(2, rs_tx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT,
+ "serial", &rs_ports[0])) {
+ printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n");
+ rc = 0;
+ }
+ if (request_irq(3, rs_rx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT,
+ "serial", &rs_ports[0])) {
+ printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n");
+ rc = 0;
+ }
+
+ IntEnable6 |= INT6_UARTARXINT;
+ rs_enable_rx_interrupts(&rs_ports[0]);
+
+#ifndef CONFIG_SERIAL_CONSOLE
+ printk( "Initializing uart...\n" );
+ earlyInitUartPR31700();
+ printk( "okay\n" );
+#endif
+
+ /* Note: I didn't do anything to enable the second UART */
+
+ if (rc >= 0)
+ rs_initialized++;
+
+ func_exit();
+ return 0;
+}
+
+
+void rs_exit(void)
+{
+ func_enter();
+ rs_dprintk (RS_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", rs_initialized);
+ if (rs_initialized)
+ rs_release_drivers ();
+
+ kfree (rs_ports);
+ kfree (rs_termios);
+ kfree (rs_termios_locked);
+ func_exit();
+
+}
+
+module_init(rs_init);
+module_exit(rs_exit);
+
+
+#ifdef DEBUG
+void my_hd (unsigned char *addr, int len)
+{
+ int i, j, ch;
+
+ for (i=0;i<len;i+=16) {
+ printk ("%08x ", (int) addr+i);
+ for (j=0;j<16;j++) {
+ printk ("%02x %s", addr[j+i], (j==7)?" ":"");
+ }
+ for (j=0;j<16;j++) {
+ ch = addr[j+i];
+ printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+ }
+ printk ("\n");
+ }
+}
+#endif
+
+
+
+
+/*
+ *
+ * Very simple routines to get UART humming...
+ *
+ */
+
+/* not static, its called from prom_init() too */
+void earlyInitUartPR31700(void)
+{
+ /* Setup master clock for UART */
+ ClockControl &= ~CLK_SIBMCLKDIV_MASK;
+ ClockControl |= CLK_SIBMCLKDIR | CLK_ENSIBMCLK |
+ ((2 << CLK_SIBMCLKDIV_SHIFT) & CLK_SIBMCLKDIV_MASK) |
+ CLK_CSERSEL;
+
+ /* Configure UARTA clock */
+ ClockControl |= ((3 << CLK_CSERDIV_SHIFT) & CLK_CSERDIV_MASK) |
+ CLK_ENCSERCLK | CLK_EN_UART_A;
+
+ /* Setup UARTA for 115200 baud, 8N1 */
+ UartA_Ctrl1 &= 0xf000000f;
+ UartA_Ctrl1 &= ~UART_DIS_TXD; /* turn on txd */
+ UartA_Ctrl1 &= ~SER_SEVEN_BIT; /* use 8-bit data */
+ UartA_Ctrl1 &= ~SER_EVEN_PARITY; /* no parity */
+ UartA_Ctrl1 &= ~SER_TWO_STOP; /* 1 stop bit */
+ UartA_Ctrl2 = SER_BAUD_115200;
+ UartA_DMActl1 = 0; /* No DMA */
+ UartA_DMActl2 = 0; /* No DMA */
+ UartA_Ctrl1 |= UART_ON; /* Turn UART on */
+
+ while (~UartA_Ctrl1 & UART_ON);
+}
+
+void serial_outc(unsigned char c)
+{
+ int i;
+ unsigned long int2;
+ #define BUSY_WAIT 10000
+
+ /*
+ * Turn UART A Interrupts off
+ */
+ int2 = IntEnable2;
+ IntEnable2 &=
+ ~(INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY);
+
+ /*
+ * The UART_TX_EMPTY bit in UartA_Ctrl1 seems
+ * not to be very reliable :-(
+ *
+ * Wait for the Tx register to become empty
+ */
+ for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++);
+
+ IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY;
+
+ UartA_Data = c;
+ for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++);
+ IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY;
+
+ IntEnable2 = int2;
+}
+
+void serial_console_read_raw(struct console *co, char *buf, int size)
+{
+ int i;
+ unsigned int int2, flags;
+
+ save_and_cli(flags);
+
+ int2 = IntEnable2;
+ IntEnable2 = 0;
+
+ for (i=0; i<size; i++) {
+ while (!(UartA_Ctrl1 & UART_RX_HOLD_FULL))
+ ;
+ buf[i] = UartA_Data;
+ udelay(10); /* Allow things to happen - it take a while */
+ }
+ IntEnable2 = int2;
+ restore_flags(flags);
+}
+
+int serial_console_wait_key(struct console *co)
+{
+ unsigned int int2, res;
+
+ int2 = IntEnable2;
+ IntEnable2 = 0;
+
+ while (!(UartA_Ctrl1 & UART_RX_HOLD_FULL))
+ ;
+ res = UartA_Data;
+ udelay(10); /* Allow things to happen - it take a while */
+
+ IntEnable2 = int2;
+ return res;
+}
+
+/* used in slip? in Slip??? SLIP /ought/ to work with sl->tty! (PM2000) */
+void serial_console_write_raw(struct console *co, const char *s,
+ unsigned count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ serial_outc(*s++);
+ }
+}
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+void serial_console_write(struct console *co, const char *s,
+ unsigned count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ if (*s == '\n')
+ serial_outc('\r');
+ serial_outc(*s++);
+ }
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static __init int serial_console_setup(struct console *co, char *options)
+{
+ earlyInitUartPR31700();
+
+ return 0;
+}
+
+
+static struct console sercons = {
+ name: "ttyS",
+ write: serial_console_write,
+ device: serial_console_device,
+ wait_key: serial_console_wait_key,
+ setup: serial_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1
+};
+
+/*
+ * Register console.
+ */
+
+void __init serial_console_init(void)
+{
+ register_console(&sercons);
+}
+
+#endif
diff --git a/arch/mips/philips/drivers/uart-pr31700.h b/arch/mips/philips/drivers/uart-pr31700.h
new file mode 100644
index 000000000..221baa89f
--- /dev/null
+++ b/arch/mips/philips/drivers/uart-pr31700.h
@@ -0,0 +1,126 @@
+/*
+ * Serial driver for r39xx
+ *
+ * Copyright (C) 2000 Jim Pick <jim@jimpick.com>
+ *
+ * Inspired by, and/or includes bits from:
+ *
+ * drivers/char/serial.c (standard serial driver)
+ * drivers/char/sx.c (use of generic_serial interface)
+ * drivers/char/esp.c (another UART that uses DMA)
+ * arch/mips/vr41xx/serial.c (another MIPS serial driver)
+ *
+ * Please see those files for credits.
+ *
+ * Also, the original rough serial console code was:
+ *
+ * Copyright (C) 1999 Harald Koerfgen
+ *
+ * $Id: r39xx_serial.h,v 1.3 2000/11/01 03:02:27 nop Exp $
+ */
+
+#include <linux/serial.h>
+#include <linux/generic_serial.h>
+
+
+/* r39xx UART Register Offsets */
+#define UART_R39XX_CTRL1 0
+#define UART_R39XX_CTRL2 1
+#define UART_R39XX_DMACTRL1 2
+#define UART_R39XX_DMACTRL2 3
+#define UART_R39XX_DMACNT 4
+#define UART_R39XX_DATA 5
+
+/* UART Interrupt (Interrupt 2) bits (UARTA,UARTB) */
+#define UART_RX_INT 9 /* receiver holding register full (31, 21) */
+#define UART_RXOVERRUN_INT 8 /* receiver overrun error (30, 20) */
+#define UART_FRAMEERR_INT 7 /* receiver frame error (29, 19) */
+#define UART_BREAK_INT 6 /* received break signal (28, 18) */
+#define UART_PARITYERR_INT 5 /* receiver parity error (27, 17) */
+#define UART_TX_INT 4 /* transmit holding register empty (26, 16) */
+#define UART_TXOVERRUN_INT 3 /* transmit overrun error (25, 15) */
+#define UART_EMPTY_INT 2 /* both trans/recv regs empty (24, 14) */
+#define UART_DMAFULL_INT 1 /* DMA at end of buffer (23, 13) */
+#define UART_DMAHALF_INT 0 /* DMA halfway through buffer */ (22, 12) */
+
+#define UARTA_SHIFT 22
+#define UARTB_SHIFT 12
+
+#define INT2BIT(interrupttype, intshift) (1 << (interrupttype + intshift))
+#define INTTYPE(interrupttype) (1 << interrupttype)
+
+/* Driver status flags */
+#define RS_STAT_RX_TIMEOUT 0x01
+#define RS_STAT_DMA_RX 0x02
+#define RS_STAT_DMA_TX 0x04
+#define RS_STAT_NEVER_DMA 0x08
+#define RS_STAT_USE_PIO 0x10
+
+/*
+ This driver can spew a whole lot of debugging output at you. If you
+ need maximum performance, you should disable the DEBUG define. To
+ aid in debugging in the field, I'm leaving the compile-time debug
+ features enabled, and disable them "runtime". That allows me to
+ instruct people with problems to enable debugging without requiring
+ them to recompile...
+*/
+#define DEBUG
+
+
+#ifdef DEBUG
+#define rs_dprintk(f, str...) if (rs_debug & f) printk (str)
+#else
+#define rs_dprintk(f, str...) /* nothing */
+#endif
+
+
+
+#define func_enter() rs_dprintk (RS_DEBUG_FLOW, "rs: enter " __FUNCTION__ "\n")
+#define func_exit() rs_dprintk (RS_DEBUG_FLOW, "rs: exit " __FUNCTION__ "\n")
+
+#define func_enter2() rs_dprintk (RS_DEBUG_FLOW, "rs: enter " __FUNCTION__ \
+ "(port %p, base %p)\n", port, port->base)
+
+
+/* Debug flags. Add these together to get more debug info. */
+
+#define RS_DEBUG_OPEN 0x00000001
+#define RS_DEBUG_SETTING 0x00000002
+#define RS_DEBUG_FLOW 0x00000004
+#define RS_DEBUG_MODEMSIGNALS 0x00000008
+#define RS_DEBUG_TERMIOS 0x00000010
+#define RS_DEBUG_TRANSMIT 0x00000020
+#define RS_DEBUG_RECEIVE 0x00000040
+#define RS_DEBUG_INTERRUPTS 0x00000080
+#define RS_DEBUG_PROBE 0x00000100
+#define RS_DEBUG_INIT 0x00000200
+#define RS_DEBUG_CLEANUP 0x00000400
+#define RS_DEBUG_CLOSE 0x00000800
+#define RS_DEBUG_FIRMWARE 0x00001000
+#define RS_DEBUG_MEMTEST 0x00002000
+#define RS_DEBUG_THROTTLE 0x00004000
+
+#define RS_DEBUG_ALL 0xffffffff
+
+
+#define RS_NPORTS 2
+
+struct rs_port {
+ /* must be first field! */
+ struct gs_port gs;
+
+ /* rest is private for this driver */
+ unsigned long *base;
+ int intshift; /* for interrupt register */
+ struct wait_queue *shutdown_wait;
+ int stat_flags;
+ struct async_icount icount; /* kernel counters for the 4
+ input interrupts */
+ int read_status_mask;
+ int ignore_status_mask;
+ int x_char; /* xon/xoff character */
+};
+
+
+
+#define SERIAL_MAGIC 0x5301
diff --git a/arch/mips/philips/nino/.cvsignore b/arch/mips/philips/nino/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/arch/mips/philips/nino/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/arch/mips/philips/nino/Makefile b/arch/mips/philips/nino/Makefile
new file mode 100644
index 000000000..7d31a66fb
--- /dev/null
+++ b/arch/mips/philips/nino/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for the Philips Nino specific parts of the kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.S.s:
+ $(CPP) $(AFLAGS) $< -o $@
+.S.o:
+ $(CC) $(AFLAGS) -c $< -o $@
+
+O_TARGET := nino.o
+
+all: nino.o
+
+obj-y := int-handler.o setup.o irq.o time.o reset.o rtc.o prom.o power.o wbflush.o
+
+obj-$(CONFIG_BLK_DEV_INITRD) += ../boot/ramdisk.o
+
+obj-$(CONFIG_REMOTE_DEBUG) += kgdb.o
+
+int-handler.o: int-handler.S
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/mips/philips/nino/int-handler.S b/arch/mips/philips/nino/int-handler.S
new file mode 100644
index 000000000..90d7f8818
--- /dev/null
+++ b/arch/mips/philips/nino/int-handler.S
@@ -0,0 +1,138 @@
+/*
+ * linux/arch/mips/philips/nino/int-handler.S
+ *
+ * Copyright (C) 1999 Harald Koerfgen (Harald.Koerfgen@home.ivm.de)
+ * Copyright (C) 2000 Jim Pick (jim@jimpick.com)
+ * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.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.
+ *
+ * Interrupt handler for PR31700.
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#include <asm/philips/pr31700.h>
+
+
+ .data
+ .globl HighPriVect
+
+HighPriVect: .word spurious # Reserved
+ .word io_posnegint0 # IOPOSINT(0) or IONEGINT(0)
+ .word spurious # CHIDMACNTINT
+ .word spurious # TELDMACNTINT
+ .word spurious # SNDDMACNTINT
+ .word spurious # Reserved
+ .word io_negint56 # IONEGINT(6) or IONEGINT(5)
+ .word spurious # Reserved
+ .word io_posint56 # IOPOSINT(6) or IOPOSINT(5)
+ .word spurious # Reserved
+ .word spurious # UARTBRXINT
+ .word uarta_rx # UARTARXINT
+ .word spurious # Reserved
+ .word periodic_timer # PERINT
+ .word spurious # ALARMINT
+ .word spurious # POSPWROKINT or NEGPWROKINT
+
+/*
+ * Here is the entry point to handle all interrupts.
+ */
+ .text
+ .set noreorder
+ .align 5
+ NESTED(nino_handle_int, PT_SIZE, ra)
+ .set noat
+ SAVE_ALL
+ CLI
+ .set at
+
+ /*
+ * Get pending Interrupts
+ */
+ mfc0 t0, CP0_CAUSE # Get pending interrupts
+ andi t2, t0, IE_IRQ4 # IRQ4 (high priority)
+ bne t2, IE_IRQ4, low_priority
+ nop
+
+/*
+ * Ok, we've got a high priority interrupt (a.k.a. an external interrupt).
+ * Read Interrupt Status Register 6 to get vector.
+ */
+high_priority:
+ lui t0, %hi(IntStatus6)
+ lw t1, %lo(IntStatus6)(t0)
+ andi t1, INT6_INTVECT
+ la t2, HighPriVect
+ addu t1, t1, t2
+ lw t2, 0(t1)
+ jr t2
+ nop
+
+/*
+ * Ok, we've got one of over a hundred other interupts.
+ */
+low_priority:
+ lui t0, %hi(IntStatus1)
+ lw t1, %lo(IntStatus1)(t0)
+ j handle_it
+ li a0, 20
+
+/*
+ * We don't currently handle spurious interrupts.
+ */
+spurious:
+ j spurious_interrupt
+ nop
+
+/*
+ * We have the IRQ number, dispatch to the real handler.
+ */
+handle_it: jal do_IRQ
+ move a1,sp
+ j ret_from_irq
+ nop
+
+/************************************
+ * High priority interrupt mappings *
+ ************************************/
+
+/*
+ * Periodic timer - IRQ 0
+ */
+periodic_timer:
+ j handle_it
+ li a0, 0
+
+/*
+ * UARTA RX - IRQ 3
+ */
+uarta_rx:
+ j handle_it
+ li a0, 3
+
+/*
+ * GPIO Pin 0 transition - IRQ 10
+ */
+io_posnegint0:
+ j handle_it
+ li a0, 10
+
+/*
+ * GPIO Pin 5 or 6 transition (0-to-1) - IRQ 11
+ */
+io_posint56:
+ j handle_it
+ li a0, 11
+
+/*
+ * GPIO Pin 5 or 6 transition (1-to-0) - IRQ 12
+ */
+io_negint56:
+ j handle_it
+ li a0, 12
+
+ END(nino_handle_int)
diff --git a/arch/mips/philips/nino/irq.c b/arch/mips/philips/nino/irq.c
new file mode 100644
index 000000000..71aba8599
--- /dev/null
+++ b/arch/mips/philips/nino/irq.c
@@ -0,0 +1,304 @@
+/*
+ * linux/arch/mips/philips/nino/irq.c
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ * Copyright (C) 1999 Harald Koerfgen (Harald.Koerfgen@home.ivm.de)
+ * Copyright (C) 2000 Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.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.
+ *
+ * Generic interrupt handler for PR31700.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/philips/pr31700.h>
+
+unsigned long spurious_count = 0;
+
+irq_cpustat_t irq_stat [NR_CPUS];
+
+static inline void mask_irq(unsigned int irq_nr)
+{
+ switch (irq_nr) {
+ case 0: /* Periodic Timer Interrupt */
+ IntClear5 = INT5_PERIODICINT;
+ IntClear6 = INT6_PERIODICINT;
+ IntEnable6 &= ~INT6_PERIODICINT;
+ break;
+
+ case 3: /* Serial port receive interrupt */
+ break;
+
+ case 2: /* Serial port transmit interrupt */
+ break;
+
+ default:
+ printk( "Attempt to mask unknown IRQ %d?\n", irq_nr );
+ }
+}
+
+static inline void unmask_irq(unsigned int irq_nr)
+{
+ switch (irq_nr) {
+ case 0:
+ IntEnable6 |= INT6_PERIODICINT;
+ break;
+
+ case 3: /* Serial port receive interrupt */
+ /* FIXME: currently handled in driver */
+ break;
+
+ case 2: /* Serial port transmit interrupt */
+ /* FIXME: currently handled in driver */
+ break;
+
+ default:
+ printk( "Attempt to unmask unknown IRQ %d?\n", irq_nr );
+ }
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ mask_irq(irq_nr);
+ restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ unmask_irq(irq_nr);
+ restore_flags(flags);
+}
+
+/*
+ * Pointers to the low-level handlers: first the general ones, then the
+ * fast ones, then the bad ones.
+ */
+extern void interrupt(void);
+
+static struct irqaction *irq_action[NR_IRQS] =
+{
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ struct irqaction *action;
+
+ for (i = 0; i < NR_IRQS; i++) {
+ action = irq_action[i];
+ if (!action)
+ continue;
+ len += sprintf(buf + len, "%2d: %8d %c %s",
+ i, kstat.irqs[0][i],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action = action->next; action; action = action->next) {
+ len += sprintf(buf + len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf + len, "\n");
+ }
+ return len;
+}
+
+atomic_t __mips_bh_counter;
+
+/*
+ * do_IRQ handles IRQ's that have been installed without the
+ * SA_INTERRUPT flag: it uses the full signal-handling return
+ * and runs with other interrupts enabled. All relatively slow
+ * IRQ's should use this format: notably the keyboard/timer
+ * routines.
+ */
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+{
+ struct irqaction *action;
+ int do_random, cpu;
+
+ cpu = smp_processor_id();
+ irq_enter(cpu, irq);
+ kstat.irqs[cpu][irq]++;
+
+ if (irq == 20) {
+ printk("20 %08lx %08lx\n %08lx %08lx\n %08lx\n",
+ IntStatus1, IntStatus2, IntStatus3,
+ IntStatus4, IntStatus5 );
+ printk("20 %08lx %08lx\n %08lx %08lx\n %08lx\n",
+ IntEnable1, IntEnable2, IntEnable3,
+ IntEnable4, IntEnable5 );
+
+ }
+
+ mask_irq(irq);
+ action = *(irq + irq_action);
+ if (action) {
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+ do_random = 0;
+ do {
+ do_random |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ if (do_random & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ unmask_irq(irq);
+ __cli();
+ } else {
+ IntClear3 = ~0;
+ IntClear4 = ~0;
+ IntClear5 = ~0;
+ unmask_irq(irq);
+ }
+ irq_exit(cpu, irq);
+
+ /* unmasking and bottom half handling is done magically for us. */
+}
+
+/*
+ * Idea is to put all interrupts
+ * in a single table and differenciate them just by number.
+ */
+int setup_nino_irq(int irq, struct irqaction *new)
+{
+ int shared = 0;
+ struct irqaction *old, **p;
+ unsigned long flags;
+
+ p = irq_action + irq;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ))
+ return -EBUSY;
+
+ /* Can't share interrupts unless both are same type */
+ if ((old->flags ^ new->flags) & SA_INTERRUPT)
+ return -EBUSY;
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+ if (new->flags & SA_SAMPLE_RANDOM)
+ rand_initialize_irq(irq);
+
+ save_and_cli(flags);
+ *p = new;
+
+ if (!shared) {
+ unmask_irq(irq);
+ }
+ restore_flags(flags);
+ return 0;
+}
+
+int request_irq(unsigned int irq,
+ void (*handler) (int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id)
+{
+ int retval;
+ struct irqaction *action;
+
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+ if (!handler)
+ return -EINVAL;
+
+ action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->next = NULL;
+ action->dev_id = dev_id;
+
+ retval = setup_nino_irq(irq, action);
+
+ if (retval)
+ kfree(action);
+ return retval;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *action, **p;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS) {
+ printk(KERN_CRIT __FUNCTION__ ": trying to free IRQ%d\n", irq);
+ return;
+ }
+ for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now free it */
+ save_and_cli(flags);
+ *p = action->next;
+ if (!irq[irq_action])
+ mask_irq(irq);
+ restore_flags(flags);
+ kfree(action);
+ return;
+ }
+ printk(KERN_CRIT __FUNCTION__ ": trying to free free IRQ%d\n", irq);
+}
+
+unsigned long probe_irq_on(void)
+{
+ /* TODO */
+ return 0;
+}
+
+int probe_irq_off(unsigned long irqs)
+{
+ /* TODO */
+ return 0;
+}
+
+void __init init_IRQ(void)
+{
+ irq_setup();
+}
diff --git a/arch/mips/philips/nino/kgdb.c b/arch/mips/philips/nino/kgdb.c
new file mode 100644
index 000000000..0bb03e86f
--- /dev/null
+++ b/arch/mips/philips/nino/kgdb.c
@@ -0,0 +1,83 @@
+/*
+ * linux/arch/mips/philips/nino/kgdb.c
+ *
+ * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.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.
+ *
+ * Low level functions for remote debugging on PR31700.
+ */
+#include <asm/system.h>
+#include <asm/philips/pr31700.h>
+
+static int remoteDebugInitialized = 0;
+
+void debugInit(void)
+{
+/*
+ * If low-level debugging (before GDB or console operational) is
+ * configured, then we do not need to re-initialize the UART.
+ */
+#ifndef CONFIG_DEBUG_LL
+ earlyInitUartPR31700();
+#endif
+}
+
+char getDebugChar(void)
+{
+ char buf;
+ unsigned long int2, flags;
+
+ if (!remoteDebugInitialized) {
+ debugInit();
+ remoteDebugInitialized = 1;
+ }
+
+ save_and_cli(flags);
+
+ int2 = IntEnable2;
+
+ IntEnable2 = 0;
+
+ while(!(UartA_Ctrl1 & UART_RX_HOLD_FULL));
+
+ buf = UartA_Data;
+
+ IntEnable2 = int2;
+
+ restore_flags(flags);
+
+ return buf;
+}
+
+int putDebugChar(char c)
+{
+ int i;
+ unsigned long int2;
+
+ if (!remoteDebugInitialized) {
+ debugInit();
+ remoteDebugInitialized = 1;
+ }
+
+ int2 = IntEnable2;
+
+ IntEnable2 &=
+ ~(INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY);
+
+ for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < 10000); i++);
+
+ IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY;
+
+ UartA_Data = c;
+
+ for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < 10000); i++);
+
+ IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY;
+
+ IntEnable2 = int2;
+
+ return 1;
+}
diff --git a/arch/mips/philips/nino/power.c b/arch/mips/philips/nino/power.c
new file mode 100644
index 000000000..907b134b7
--- /dev/null
+++ b/arch/mips/philips/nino/power.c
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/mips/philips/nino/power.c
+ *
+ * Copyright (C) 2000 Jim Pick <jim@jimpick.com>
+ * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.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.
+ *
+ * Routines for power management on the Nino.
+ */
+#include <asm/philips/pr31700.h>
+
+void nino_wait(void)
+{
+ /* We stop the CPU to conserve power */
+ PowerControl |= PWR_STOPCPU;
+
+ /*
+ * We wait until an interrupt happens...
+ */
+
+ /* We resume here */
+ PowerControl &= ~PWR_STOPCPU;
+
+ /* Give ourselves a little delay */
+ __asm__ __volatile__(
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t");
+}
diff --git a/arch/mips/philips/nino/prom.c b/arch/mips/philips/nino/prom.c
new file mode 100644
index 000000000..bb4582099
--- /dev/null
+++ b/arch/mips/philips/nino/prom.c
@@ -0,0 +1,83 @@
+/*
+ * linux/arch/mips/philips-hpc/nino/prom.c
+ *
+ * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.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.
+ *
+ * Early initialization code for the Nino.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/bootinfo.h>
+
+char arcs_cmdline[COMMAND_LINE_SIZE];
+
+#ifdef CONFIG_LL_DEBUG
+extern void init_uart(void);
+
+int __init prom_printf(const char * fmt, ...)
+{
+ extern void serial_outc(char);
+ static char buf[1024];
+ va_list args;
+ char c;
+ int i = 0;
+
+ /*
+ * Printing messages via serial port
+ */
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ va_end(args);
+
+ for (i = 0; buf[i] != '\0'; i++) {
+ c = buf[i];
+ if (c == '\n')
+ serial_outc('\r');
+ serial_outc(c);
+ }
+
+ return i;
+}
+#endif
+
+/* Do basic initialization */
+void __init prom_init(int argc, char **argv,
+ unsigned long magic, int *prom_vec)
+{
+ int i;
+
+ /*
+ * collect args and prepare cmd_line
+ */
+ for (i = 1; i < argc; i++) {
+ strcat(arcs_cmdline, argv[i]);
+ if (i < (argc - 1))
+ strcat(arcs_cmdline, " ");
+ }
+
+#ifdef CONFIG_LL_DEBUG
+ earlyInitUartPR31700();
+#endif
+
+ mips_machgroup = MACH_GROUP_PHILIPS;
+ mips_machtype = MACH_PHILIPS_NINO;
+
+ /* Add memory region */
+#ifdef CONFIG_NINO_4MB
+ add_memory_region(0, 4 << 20, BOOT_MEM_RAM);
+#elif CONFIG_NINO_8MB
+ add_memory_region(0, 8 << 20, BOOT_MEM_RAM);
+#elif CONFIG_NINO_16MB
+ add_memory_region(0, 16 << 20, BOOT_MEM_RAM);
+#endif
+}
+
+void __init prom_free_prom_memory (void)
+{
+}
diff --git a/arch/mips/philips/nino/reset.c b/arch/mips/philips/nino/reset.c
new file mode 100644
index 000000000..c809b6b93
--- /dev/null
+++ b/arch/mips/philips/nino/reset.c
@@ -0,0 +1,37 @@
+/*
+ * linux/arch/mips/philips/nino/reset.c
+ *
+ * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.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.
+ *
+ * Generic restart, halt and power off functions.
+ */
+#include <linux/init.h>
+#include <asm/reboot.h>
+
+void (*reset_vector)(void) = (void (*)(void)) 0xBFC00000;
+
+void nino_machine_restart(char *command)
+{
+ reset_vector();
+}
+
+void nino_machine_halt(void)
+{
+ reset_vector();
+}
+
+void nino_machine_power_off(void)
+{
+ reset_vector();
+}
+
+void __init setup_nino_reset_vectors(void)
+{
+ _machine_restart = nino_machine_restart;
+ _machine_halt = nino_machine_halt;
+ _machine_power_off = nino_machine_power_off;
+}
diff --git a/arch/mips/philips/nino/rtc.c b/arch/mips/philips/nino/rtc.c
new file mode 100644
index 000000000..f1127fae0
--- /dev/null
+++ b/arch/mips/philips/nino/rtc.c
@@ -0,0 +1,34 @@
+/*
+ * linux/arch/mips/philips-mobile/nino/rtc.c
+ *
+ * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.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.
+ *
+ * Functions to access the RTC on the PR31700 chip.
+ */
+#include <linux/spinlock.h>
+#include <linux/mc146818rtc.h>
+
+static unsigned char nino_rtc_read_data(unsigned long addr)
+{
+ return 0;
+}
+
+static void nino_rtc_write_data(unsigned char data, unsigned long addr)
+{
+}
+
+static int nino_rtc_bcd_mode(void)
+{
+ return 0;
+}
+
+struct rtc_ops nino_rtc_ops =
+{
+ &nino_rtc_read_data,
+ &nino_rtc_write_data,
+ &nino_rtc_bcd_mode
+};
diff --git a/arch/mips/philips/nino/setup.c b/arch/mips/philips/nino/setup.c
new file mode 100644
index 000000000..7ac6cdf06
--- /dev/null
+++ b/arch/mips/philips/nino/setup.c
@@ -0,0 +1,117 @@
+/*
+ * linux/arch/mips/philips/nino/setup.c
+ *
+ * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.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.
+ *
+ * Interrupt and exception initialization for PR31700.
+ */
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+#include <linux/sched.h>
+#include <asm/addrspace.h>
+#include <asm/gdb-stub.h>
+#include <asm/irq.h>
+#include <asm/wbflush.h>
+#include <asm/philips/pr31700.h>
+
+extern struct rtc_ops nino_rtc_ops;
+
+extern void nino_wait(void);
+extern void setup_nino_reset_vectors(void);
+extern asmlinkage void nino_handle_int(void);
+extern int setup_nino_irq(int, struct irqaction *);
+void (*board_time_init) (struct irqaction * irq);
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void set_debug_traps(void);
+extern void breakpoint(void);
+static int remote_debug = 0;
+#endif
+
+static void __init nino_irq_setup(void)
+{
+ unsigned int tmp;
+
+ /* Turn all interrupts off */
+ IntEnable1 = 0;
+ IntEnable2 = 0;
+ IntEnable3 = 0;
+ IntEnable4 = 0;
+ IntEnable5 = 0;
+ IntEnable6 = 0;
+
+ /* Clear all interrupts */
+ IntClear1 = 0xffffffff;
+ IntClear2 = 0xffffffff;
+ IntClear3 = 0xffffffff;
+ IntClear4 = 0xffffffff;
+ IntClear5 = 0xffffffff;
+ IntClear6 = 0xffffffff;
+
+ /*
+ * Enable only the interrupts for the UART and negative
+ * edge (1-to-0) triggered multi-function I/O pins.
+ */
+ set_cp0_status(ST0_BEV, 0);
+ tmp = read_32bit_cp0_register(CP0_STATUS);
+ set_cp0_status(ST0_IM, tmp | IE_IRQ2 | IE_IRQ4);
+
+ /* Register the global interrupt handler */
+ set_except_vector(0, nino_handle_int);
+
+#ifdef CONFIG_REMOTE_DEBUG
+ if (remote_debug) {
+ set_debug_traps();
+ breakpoint();
+ }
+#endif
+}
+
+static __init void nino_time_init(struct irqaction *irq)
+{
+ /*
+ * Enable periodic interrupts
+ */
+ setup_nino_irq(0, irq);
+
+ RTCperiodTimer = PER_TIMER_COUNT;
+ RTCtimerControl = TIM_ENPERTIMER;
+ IntEnable5 |= INT5_PERIODICINT;
+ ClockControl |= CLK_ENTIMERCLK;
+
+ /* Enable all interrupts */
+ IntEnable6 |= INT6_GLOBALEN | INT6_PERIODICINT;
+}
+
+void __init nino_setup(void)
+{
+ irq_setup = nino_irq_setup;
+
+ board_time_init = nino_time_init;
+
+ /* Base address to use for PC type I/O accesses */
+ mips_io_port_base = KSEG1ADDR(0x08000000);
+
+ setup_nino_reset_vectors();
+
+ /* Function called during process idle (cpu_idle) */
+ cpu_wait = nino_wait;
+
+#ifdef CONFIG_FB
+ conswitchp = &dummy_con;
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+ remote_debug = 1;
+#endif
+
+ rtc_ops = &nino_rtc_ops;
+
+ wbflush_setup();
+}
diff --git a/arch/mips/philips/nino/time.c b/arch/mips/philips/nino/time.c
new file mode 100644
index 000000000..b3bc87e7e
--- /dev/null
+++ b/arch/mips/philips/nino/time.c
@@ -0,0 +1,216 @@
+/*
+ * linux/arch/mips/philips/nino/time.c
+ *
+ * Copyright (C) 1999 Harald Koerfgen (Harald.Koerfgen@home.ivm.de)
+ * Copyright (C) 2000 Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.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.
+ *
+ * Time handling details for PR31700.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/delay.h>
+#include <asm/philips/pr31700.h>
+
+extern volatile unsigned long wall_jiffies;
+extern rwlock_t xtime_lock;
+
+static struct timeval xbase;
+
+#define USECS_PER_JIFFY (1000000/HZ)
+
+/*
+ * Poll the Interrupt Status Registers
+ */
+#undef POLL_STATUS
+
+static unsigned long do_gettimeoffset(void)
+{
+ /*
+ * This is a kludge
+ */
+ return 0;
+}
+
+static
+void inline readRTC(unsigned long *high, unsigned long *low)
+{
+ /* read twice, and keep reading till we find two
+ * the same pairs. This is needed in case the RTC
+ * was updating its registers and we read a old
+ * High but a new Low. */
+ do {
+ *high = RTChigh & RTC_HIGHMASK;
+ *low = RTClow;
+ } while (*high != (RTChigh & RTC_HIGHMASK) || RTClow!=*low);
+}
+
+/*
+ * This version of gettimeofday has near millisecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ unsigned long high, low;
+
+ read_lock_irqsave(&xtime_lock, flags);
+ // 40 bit RTC, driven by 32khz source:
+ // +-----------+-----------------------------------------+
+ // | HHHH.HHHH | LLLL.LLLL.LLLL.LLLL.LMMM.MMMM.MMMM.MMMM |
+ // +-----------+-----------------------------------------+
+ readRTC(&high,&low);
+ tv->tv_sec = (high << 17) | (low >> 15);
+ tv->tv_usec = (low % 32768) * 1953 / 64;
+ tv->tv_sec += xbase.tv_sec;
+ tv->tv_usec += xbase.tv_usec;
+
+ tv->tv_usec += do_gettimeoffset();
+
+ /*
+ * xtime is atomically updated in timer_bh. lost_ticks is
+ * nonzero if the timer bottom half hasnt executed yet.
+ */
+ if (jiffies - wall_jiffies)
+ tv->tv_usec += USECS_PER_JIFFY;
+
+ read_unlock_irqrestore(&xtime_lock, flags);
+
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ write_lock_irq(&xtime_lock);
+ /* This is revolting. We need to set the xtime.tv_usec
+ * correctly. However, the value in this location is
+ * is value at the last tick.
+ * Discover what correction gettimeofday
+ * would have done, and then undo it!
+ */
+ tv->tv_usec -= do_gettimeoffset();
+
+ if (tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+
+ /* reset RTC to 0 (real time is xbase + RTC) */
+ xbase = *tv;
+ RTCtimerControl |= TIM_RTCCLEAR;
+ RTCtimerControl &= ~TIM_RTCCLEAR;
+ RTCalarmHigh = RTCalarmLow = ~0UL;
+
+ xtime = *tv;
+ time_state = TIME_BAD;
+ time_maxerror = MAXPHASE;
+ time_esterror = MAXPHASE;
+ write_unlock_irq(&xtime_lock);
+}
+
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+
+ return retval;
+}
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+
+int do_write = 1;
+
+static void
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+#ifdef POLL_STATUS
+ static unsigned long old_IntStatus1 = 0;
+ static unsigned long old_IntStatus3 = 0;
+ static unsigned long old_IntStatus4 = 0;
+ static unsigned long old_IntStatus5 = 0;
+ static int counter = 0;
+ int i;
+
+ new_spircv = SPIData & 0xff;
+ if ((old_spircv != new_spircv) && (new_spircv != 0xff)) {
+ printk( "SPIData changed: %x\n", new_spircv );
+ }
+ old_spircv = new_spircv;
+ if (do_write)
+ SPIData = 0;
+#endif
+
+ if (!user_mode(regs)) {
+ if (prof_buffer && current->pid) {
+ extern int _stext;
+ unsigned long pc = regs->cp0_epc;
+
+ pc -= (unsigned long) &_stext;
+ pc >>= prof_shift;
+ /*
+ * Dont ignore out-of-bounds pc values silently,
+ * put them into the last histogram slot, so if
+ * present, they will show up as a sharp peak.
+ */
+ if (pc > prof_len - 1)
+ pc = prof_len - 1;
+ atomic_inc((atomic_t *) & prof_buffer[pc]);
+ }
+ }
+
+ /*
+ * aaaand... action!
+ */
+ do_timer(regs);
+
+ /*
+ * If we have an externally syncronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ */
+ if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec > 500000 - (tick >> 1) &&
+ xtime.tv_usec < 500000 + (tick >> 1))
+ {
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ }
+}
+
+static struct irqaction irq0 = {timer_interrupt, SA_INTERRUPT, 0,
+ "timer", NULL, NULL};
+
+void (*board_time_init) (struct irqaction * irq);
+
+int __init time_init(void)
+{
+ struct timeval starttime;
+
+ starttime.tv_sec = mktime(2000, 1, 1, 0, 0, 0);
+ starttime.tv_usec = 0;
+ do_settimeofday(&starttime);
+
+ board_time_init(&irq0);
+
+ return 0;
+}
diff --git a/arch/mips/philips/nino/wbflush.c b/arch/mips/philips/nino/wbflush.c
new file mode 100644
index 000000000..2b1056259
--- /dev/null
+++ b/arch/mips/philips/nino/wbflush.c
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/mips/philips/nino/wbflush.c
+ *
+ * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.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.
+ *
+ * Function to flush the write buffer on the PR31700 chip.
+ */
+#include <linux/init.h>
+
+void (*__wbflush) (void);
+
+void nino_wbflush(void)
+{
+ /*
+ * The status of the writeback buffer is available
+ * via the Coprocessor 0 condition
+ */
+ __asm__ __volatile__(
+ ".set\tpush\n\t"
+ ".set\tnoreorder\n\t"
+ ".set\tmips3\n\t"
+ "sync\n\t"
+ "nop\n\t"
+ "1:\tbc0f\t1b\n\t"
+ "nop\n\t"
+ ".set\tpop");
+}
+
+void __init wbflush_setup(void)
+{
+ __wbflush = nino_wbflush;
+}
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index e0fd5b5f5..830f8a8ec 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -87,6 +87,11 @@ ifeq ($(CONFIG_BAGET_MIPS),y)
SERIAL =
endif
+ifeq ($(CONFIG_NINO),y)
+ KEYBD =
+ SERIAL =
+endif
+
ifneq ($(CONFIG_SUN_SERIAL),)
SERIAL =
endif
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index f09346385..83e5dc895 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -25,10 +25,12 @@
#define MACH_GROUP_COSINE 10 /* CoSine Orion */
#define MACH_GROUP_GALILEO 11 /* Galileo Eval Boards */
#define MACH_GROUP_MOMENCO 12 /* Momentum Boards */
-#define MACH_GROUP_ITE 13 /* ITE Semi Eval Boards*/
+#define MACH_GROUP_ITE 13 /* ITE Semi Eval Boards */
+#define MACH_GROUP_PHILLIPS 14
#define GROUP_NAMES { "unknown", "Jazz", "Digital", "ARC", "SNI", "ACN", \
- "SGI", "Cobalt", "NEC DDB", "Baget", "Cosine", "Galileo", "Momentum", "ITE" }
+ "SGI", "Cobalt", "NEC DDB", "Baget", "Cosine", "Galileo", "Momentum", \
+ "ITE", "Phillips" }
/*
* Valid machtype values for group unknown (low order halfword of mips_machtype)
@@ -150,6 +152,14 @@
#define GROUP_ITE_NAMES { "QED-4N-S01B" } /* the actual board name */
/*
+ * Valid machtype for group PHILIPS
+ */
+#define MACH_PHILIPS_NINO 0 /* Nino */
+#define MACH_PHILIPS_VELO 1 /* Velo */
+
+#define GROUP_PHILIPS_NAMES { "Nino" , "Velo" }
+
+/*
* Valid cputype values
*/
#define CPU_UNKNOWN 0
@@ -185,14 +195,15 @@
#define CPU_4KC 30
#define CPU_5KC 31
#define CPU_R4310 32
-#define CPU_LAST 32
+#define CPU_R3912 33
+#define CPU_LAST 33
#define CPU_NAMES { "unknown", "R2000", "R3000", "R3000A", "R3041", "R3051", \
"R3052", "R3081", "R3081E", "R4000PC", "R4000SC", "R4000MC", \
"R4200", "R4400PC", "R4400SC", "R4400MC", "R4600", "R6000", \
"R6000A", "R8000", "R10000", "R4300", "R4650", "R4700", "R5000", \
"R5000A", "R4640", "Nevada", "RM7000", "R5432", "MIPS 4Kc", \
- "MIPS 5Kc", "R4310" }
+ "MIPS 5Kc", "R4310", "R3912" }
#define COMMAND_LINE_SIZE 256
diff --git a/include/asm-mips/cache.h b/include/asm-mips/cache.h
index 28f08756e..11cb10f60 100644
--- a/include/asm-mips/cache.h
+++ b/include/asm-mips/cache.h
@@ -28,7 +28,8 @@ struct cache_desc {
*/
#define MIPS_CACHE_NOT_PRESENT 0x00000001
-#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R6000)
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R6000) || \
+ defined(CONFIG_CPU_R3912)
#define L1_CACHE_BYTES 16
#else
#define L1_CACHE_BYTES 32 /* A guess */
diff --git a/include/asm-mips/cpu.h b/include/asm-mips/cpu.h
index 2dbaf5f7c..0d6db87bc 100644
--- a/include/asm-mips/cpu.h
+++ b/include/asm-mips/cpu.h
@@ -25,6 +25,7 @@
#define PRID_IMP_R8000 0x1000
#define PRID_IMP_R4600 0x2000
#define PRID_IMP_R4700 0x2100
+#define PRID_IMP_R3912 0x2200
#define PRID_IMP_R4640 0x2200
#define PRID_IMP_R4650 0x2200 /* Same as R4640 */
#define PRID_IMP_R5000 0x2300
@@ -43,6 +44,7 @@
#define PRID_REV_R3000A 0x0030
#define PRID_REV_R3000 0x0020
#define PRID_REV_R2000A 0x0010
+#define PRID_REV_R3912 0x0010
#ifndef _LANGUAGE_ASSEMBLY
/*
diff --git a/include/asm-mips/isadep.h b/include/asm-mips/isadep.h
index 16d07ccab..2351b14bc 100644
--- a/include/asm-mips/isadep.h
+++ b/include/asm-mips/isadep.h
@@ -12,7 +12,7 @@
#ifndef __ASM_MIPS_ISADEP_H
#define __ASM_MIPS_ISADEP_H
-#if defined(CONFIG_CPU_R3000)
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R3912)
/*
* R2000 or R3000
*/
diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h
index 9d3f591f6..c5d8ac759 100644
--- a/include/asm-mips/mipsregs.h
+++ b/include/asm-mips/mipsregs.h
@@ -294,6 +294,39 @@ __BUILD_SET_CP0(config,CP0_CONFIG)
#define ST0_DL (1 << 24)
/*
+ * Bitfields in the R3912 CP0 Configuration Register 3
+ */
+#define R3912_CONF_ICS_SHIFT 19
+#define R3912_CONF_ICS_MASK 0x00380000
+#define R3912_CONF_ICS_1KB 0x00000000
+#define R3912_CONF_ICS_2KB 0x00080000
+#define R3912_CONF_ICS_4KB 0x00100000
+#define R3912_CONF_ICS_8KB 0x00180000
+#define R3912_CONF_ICS_16KB 0x00200000
+
+#define R3912_CONF_DCS_SHIFT 16
+#define R3912_CONF_DCS_MASK 0x00070000
+#define R3912_CONF_DCS_1KB 0x00000000
+#define R3912_CONF_DCS_2KB 0x00010000
+#define R3912_CONF_DCS_4KB 0x00020000
+#define R3912_CONF_DCS_8KB 0x00030000
+#define R3912_CONF_DCS_16KB 0x00040000
+
+#define R3912_CONF_CWFON 0x00004000
+#define R3912_CONF_WBON 0x00002000
+#define R3912_CONF_RF_SHIFT 10
+#define R3912_CONF_RF_MASK 0x00000c00
+#define R3912_CONF_DOZE 0x00000200
+#define R3912_CONF_HALT 0x00000100
+#define R3912_CONF_LOCK 0x00000080
+#define R3912_CONF_ICE 0x00000020
+#define R3912_CONF_DCE 0x00000010
+#define R3912_CONF_IRSIZE_SHIFT 2
+#define R3912_CONF_IRSIZE_MASK 0x0000000c
+#define R3912_CONF_DRSIZE_SHIFT 0
+#define R3912_CONF_DRSIZE_MASK 0x00000003
+
+/*
* Status register bits available in all MIPS CPUs.
*/
#define ST0_IM 0x0000ff00
diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h
index 9be6976e8..5912b9966 100644
--- a/include/asm-mips/mmu_context.h
+++ b/include/asm-mips/mmu_context.h
@@ -19,7 +19,7 @@
extern unsigned long asid_cache;
extern pgd_t *current_pgd;
-#if defined(CONFIG_CPU_R3000)
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R3912)
#define ASID_INC 0x40
#define ASID_MASK 0xfc0
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index 93cf91fa6..25666e99f 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -118,7 +118,7 @@ extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
#define _PAGE_ACCESSED (1<<3) /* implemented in software */
#define _PAGE_MODIFIED (1<<4) /* implemented in software */
-#if defined(CONFIG_CPU_R3000)
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R3912)
#define _PAGE_GLOBAL (1<<8)
#define _PAGE_VALID (1<<9)
diff --git a/include/asm-mips/philips/pr31700.h b/include/asm-mips/philips/pr31700.h
new file mode 100644
index 000000000..78f3a4078
--- /dev/null
+++ b/include/asm-mips/philips/pr31700.h
@@ -0,0 +1,609 @@
+/*
+ * linux/include/asm-mips/philips/pr31700.h
+ *
+ * Copyright (C) 2000 Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.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.
+ *
+ * Defines for the PR31700 processor used in the Philips Nino and Velo.
+ */
+#ifndef __PR31700_H__
+#define __PR31700_H__
+
+#include <asm/addrspace.h>
+
+/******************************************************************************
+*
+* 01 General macro definitions
+*
+******************************************************************************/
+
+#define REGISTER_BASE 0xb0c00000
+
+#ifndef _LANGUAGE_ASSEMBLY
+
+ #define REG_AT(x) (*((volatile unsigned long *)(REGISTER_BASE + x)))
+
+#else
+
+ #define REG_AT(x) (REGISTER_BASE + x)
+
+#endif
+
+#define BIT(x) (1 << x)
+
+/******************************************************************************
+*
+* 02 Bus Interface Unit
+*
+******************************************************************************/
+
+#define MemConfig0 REG_AT(0x000)
+#define MemConfig1 REG_AT(0x004)
+#define MemConfig2 REG_AT(0x008)
+#define MemConfig3 REG_AT(0x00c)
+#define MemConfig4 REG_AT(0x010)
+#define MemConfig5 REG_AT(0x014)
+#define MemConfig6 REG_AT(0x018)
+#define MemConfig7 REG_AT(0x01c)
+#define MemConfig8 REG_AT(0x020)
+
+/* Memory config register 1 */
+#define MEM1_ENCS1USER BIT(21)
+
+/* Memory config register 3 */
+#define MEM3_CARD1ACCVAL_MASK (BIT(24) | BIT(25) | BIT(26) | BIT(27))
+#define MEM3_CARD1IOEN BIT(4)
+
+/* Memory config register 4 */
+#define MEM4_ARBITRATIONEN BIT(29)
+#define MEM4_MEMPOWERDOWN BIT(16)
+#define MEM4_ENREFRESH1 BIT(15)
+#define MEM4_ENREFRESH0 BIT(14)
+#define MEM4_ENWATCH BIT(24)
+#define MEM4_WATCHTIMEVAL_MASK (0xf)
+#define MEM4_WATCHTIMEVAL_SHIFT (20)
+#define MEM4_WATCHTIME_VALUE (0xf)
+
+/******************************************************************************
+*
+* 06 Clock module
+*
+******************************************************************************/
+
+#define ClockControl REG_AT(0x1C0)
+
+#define CLK_CHICLKDIV_MASK 0xff000000
+#define CLK_CHICLKDIV_SHIFT 24
+#define CLK_ENCLKTEST BIT(23)
+#define CLK_CLKTESTSELSIB BIT(22)
+#define CLK_CHIMCLKSEL BIT(21)
+#define CLK_CHICLKDIR BIT(20)
+#define CLK_ENCHIMCLK BIT(19)
+#define CLK_ENVIDCLK BIT(18)
+#define CLK_ENMBUSCLK BIT(17)
+#define CLK_ENSPICLK BIT(16)
+#define CLK_ENTIMERCLK BIT(15)
+#define CLK_ENFASTTIMERCLK BIT(14)
+#define CLK_SIBMCLKDIR BIT(13)
+#define CLK_ENSIBMCLK BIT(11)
+#define CLK_SIBMCLKDIV_MASK (BIT(10) | BIT(9) | BIT(8))
+#define CLK_SIBMCLKDIV_SHIFT 8
+#define CLK_CSERSEL BIT(7)
+#define CLK_CSERDIV_MASK (BIT(6) | BIT(5) | BIT(4))
+#define CLK_CSERDIV_SHIFT 4
+#define CLK_ENCSERCLK BIT(3)
+#define CLK_ENIRCLK BIT(2)
+#define CLK_EN_UART_A BIT(1)
+#define CLK_EN_UART_B BIT(0)
+
+/******************************************************************************
+*
+* 07 CHI module
+*
+******************************************************************************/
+
+#define CHIControl REG_AT(0x1D8)
+#define CHIPointerEnable REG_AT(0x1DC)
+#define CHIReceivePtrA REG_AT(0x1E0)
+#define CHIReceivePtrB REG_AT(0x1E4)
+#define CHITransmitPtrA REG_AT(0x1E8)
+#define CHITransmitPtrB REG_AT(0x1EC)
+#define CHISize REG_AT(0x1F0)
+#define CHIReceiveStart REG_AT(0x1F4)
+#define CHITransmitStart REG_AT(0x1F8)
+#define CHIHoldingReg REG_AT(0x1FC)
+
+/* CHI Control Register */
+/* <incomplete!> */
+#define CHI_RXEN BIT(2)
+#define CHI_TXEN BIT(1)
+#define CHI_ENCHI BIT(0)
+
+/******************************************************************************
+*
+* 08 Interrupt module
+*
+******************************************************************************/
+
+/* Register locations */
+
+#define IntStatus1 REG_AT(0x100)
+#define IntStatus2 REG_AT(0x104)
+#define IntStatus3 REG_AT(0x108)
+#define IntStatus4 REG_AT(0x10c)
+#define IntStatus5 REG_AT(0x110)
+#define IntStatus6 REG_AT(0x114)
+
+#define IntClear1 REG_AT(0x100)
+#define IntClear2 REG_AT(0x104)
+#define IntClear3 REG_AT(0x108)
+#define IntClear4 REG_AT(0x10c)
+#define IntClear5 REG_AT(0x110)
+#define IntClear6 REG_AT(0x114)
+
+#define IntEnable1 REG_AT(0x118)
+#define IntEnable2 REG_AT(0x11c)
+#define IntEnable3 REG_AT(0x120)
+#define IntEnable4 REG_AT(0x124)
+#define IntEnable5 REG_AT(0x128)
+#define IntEnable6 REG_AT(0x12c)
+
+/* Interrupt Status Register 1 at offset 100 */
+#define INT1_LCDINT BIT(31)
+#define INT1_DFINT BIT(30)
+#define INT1_CHIDMAHALF BIT(29)
+#define INT1_CHIDMAFULL BIT(28)
+#define INT1_CHIDMACNTINT BIT(27)
+#define INT1_CHIRXAINT BIT(26)
+#define INT1_CHIRXBINT BIT(25)
+#define INT1_CHIACTINT BIT(24)
+#define INT1_CHIERRINT BIT(23)
+#define INT1_SND0_5INT BIT(22)
+#define INT1_SND1_0INT BIT(21)
+#define INT1_TEL0_5INT BIT(20)
+#define INT1_TEL1_0INT BIT(19)
+#define INT1_SNDDMACNTINT BIT(18)
+#define INT1_TELDMACNTINT BIT(17)
+#define INT1_LSNDCLIPINT BIT(16)
+#define INT1_RSNDCLIPINT BIT(15)
+#define INT1_VALSNDPOSINT BIT(14)
+#define INT1_VALSNDNEGINT BIT(13)
+#define INT1_VALTELPOSINT BIT(12)
+#define INT1_VALTELNEGINT BIT(11)
+#define INT1_SNDININT BIT(10)
+#define INT1_TELININT BIT(9)
+#define INT1_SIBSF0INT BIT(8)
+#define INT1_SIBSF1INT BIT(7)
+#define INT1_SIBIRQPOSINT BIT(6)
+#define INT1_SIBIRQNEGINT BIT(5)
+
+/* Interrupt Status Register 2 at offset 104 */
+#define INT2_UARTARXINT BIT(31)
+#define INT2_UARTARXOVERRUN BIT(30)
+#define INT2_UARTAFRAMEINT BIT(29)
+#define INT2_UARTABREAKINT BIT(28)
+#define INT2_UARTATXINT BIT(26)
+#define INT2_UARTATXOVERRUN BIT(25)
+#define INT2_UARTAEMPTY BIT(24)
+
+#define INT2_UARTBRXINT BIT(21)
+#define INT2_UARTBRXOVERRUN BIT(20)
+#define INT2_UARTBFRAMEINT BIT(29)
+#define INT2_UARTBBREAKINT BIT(18)
+#define INT2_UARTBTXINT BIT(16)
+#define INT2_UARTBTXOVERRUN BIT(15)
+#define INT2_UARTBEMPTY BIT(14)
+
+#define INT2_UARTA_RX (BIT(31) | BIT(30) | BIT(29) | BIT(28) | BIT(27))
+#define INT2_UARTA_TX (BIT(26) | BIT(25) | BIT(24))
+#define INT2_UARTA_DMA (BIT(23) | BIT(22))
+
+#define INT2_UARTB_RX (BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17))
+#define INT2_UARTB_TX (BIT(16) | BIT(15) | BIT(14))
+#define INT2_UARTB_DMA (BIT(13) | BIT(12))
+
+/* Interrupt Status Register 5 */
+#define INT5_RTCINT BIT(31)
+#define INT5_ALARMINT BIT(30)
+#define INT5_PERIODICINT BIT(29)
+#define INT5_POSPWRINT BIT(27)
+#define INT5_NEGPWRINT BIT(26)
+#define INT5_POSPWROKINT BIT(25)
+#define INT5_NEGPWROKINT BIT(24)
+#define INT5_POSONBUTINT BIT(23)
+#define INT5_NEGONBUTINT BIT(22)
+#define INT5_SPIAVAILINT BIT(21) /* 0x0020 0000 */
+#define INT5_SPIERRINT BIT(20) /* 0x0010 0000 */
+#define INT5_SPIRCVINT BIT(19) /* 0x0008 0000 */
+#define INT5_SPIEMPTYINT BIT(18) /* 0x0004 0000 */
+#define INT5_IOPOSINT6 BIT(13)
+#define INT5_IOPOSINT5 BIT(12)
+#define INT5_IOPOSINT4 BIT(11)
+#define INT5_IOPOSINT3 BIT(10)
+#define INT5_IOPOSINT2 BIT(9)
+#define INT5_IOPOSINT1 BIT(8)
+#define INT5_IOPOSINT0 BIT(7)
+#define INT5_IONEGINT6 BIT(6)
+#define INT5_IONEGINT5 BIT(5)
+#define INT5_IONEGINT4 BIT(4)
+#define INT5_IONEGINT3 BIT(3)
+#define INT5_IONEGINT2 BIT(2)
+#define INT5_IONEGINT1 BIT(1)
+#define INT5_IONEGINT0 BIT(0)
+
+#define INT5_IONEGINT_SHIFT 0
+#define INT5_IONEGINT_MASK (0x7F<<INT5_IONEGINT_SHIFT)
+#define INT5_IOPOSINT_SHIFT 7
+#define INT5_IOPOSINT_MASK (0x7F<<INT5_IOPOSINT_SHIFT)
+
+/* Interrupt Status Register 6 */
+#define INT6_IRQHIGH BIT(31)
+#define INT6_IRQLOW BIT(30)
+#define INT6_INTVECT (BIT(5) | BIT(4) | BIT(3) | BIT(2))
+
+
+/* Interrupt Enable Register 6 */
+#define INT6_GLOBALEN BIT(18)
+#define INT6_PWROKINT BIT(15)
+#define INT6_ALARMINT BIT(14)
+#define INT6_PERIODICINT BIT(13)
+#define INT6_MBUSINT BIT(12)
+#define INT6_UARTARXINT BIT(11)
+#define INT6_UARTBRXINT BIT(10)
+#define INT6_MFIOPOSINT1619 BIT(9)
+#define INT6_IOPOSINT56 BIT(8)
+#define INT6_MFIONEGINT1619 BIT(7)
+#define INT6_IONEGINT56 BIT(6)
+#define INT6_MBUSDMAFULLINT BIT(5)
+#define INT6_SNDDMACNTINT BIT(4)
+#define INT6_TELDMACNTINT BIT(3)
+#define INT6_CHIDMACNTINT BIT(2)
+#define INT6_IOPOSNEGINT0 BIT(1)
+
+/******************************************************************************
+*
+* 09 GPIO and MFIO modules
+*
+******************************************************************************/
+
+#define IOControl REG_AT(0x180)
+#define MFIOOutput REG_AT(0x184)
+#define MFIODirection REG_AT(0x188)
+#define MFIOInput REG_AT(0x18c)
+#define MFIOSelect REG_AT(0x190)
+#define IOPowerDown REG_AT(0x194)
+#define MFIOPowerDown REG_AT(0x198)
+
+#define IODIN_MASK 0x0000007f
+#define IODIN_SHIFT 0
+#define IODOUT_MASK 0x00007f00
+#define IODOUT_SHIFT 8
+#define IODIREC_MASK 0x007f0000
+#define IODIREC_SHIFT 16
+#define IODEBSEL_MASK 0x7f000000
+#define IODEBSEL_SHIFT 24
+
+/******************************************************************************
+*
+* 10 IR module
+*
+******************************************************************************/
+
+#define IRControl1 REG_AT(0x0a0)
+#define IRControl2 REG_AT(0x0a4)
+
+/* IR Control 1 Register */
+#define IR_CARDRET BIT(24)
+#define IR_BAUDVAL_MASK 0x00ff0000
+#define IR_BAUDVAL_SHIFT 16
+#define IR_TESTIR BIT(4)
+#define IR_DTINVERT BIT(3)
+#define IR_RXPWR BIT(2)
+#define IR_ENSTATE BIT(1)
+#define IR_ENCONSM BIT(0)
+
+/* IR Control 2 Register */
+#define IR_PER_MASK 0xff000000
+#define IR_PER_SHIFT 24
+#define IR_ONTIME_MASK 0x00ff0000
+#define IR_ONTIME_SHIFT 16
+#define IR_DELAYVAL_MASK 0x0000ff00
+#define IR_DELAYVAL_SHIFT 8
+#define IR_WAITVAL_MASK 0x000000ff
+#define IR_WAITVAL_SHIFT 0
+
+/******************************************************************************
+*
+* 11 Magicbus Module
+*
+******************************************************************************/
+
+#define MbusCntrl1 REG_AT(0x0e0)
+#define MbusCntrl2 REG_AT(0x0e4)
+#define MbusDMACntrl1 REG_AT(0x0e8)
+#define MbusDMACntrl2 REG_AT(0x0ec)
+#define MbusDMACount REG_AT(0x0f0)
+#define MbusTxReg REG_AT(0x0f4)
+#define MbusRxReg REG_AT(0x0f8)
+
+#define MBUS_CLKPOL BIT(4)
+#define MBUS_SLAVE BIT(3)
+#define MBUS_FSLAVE BIT(2)
+#define MBUS_LONG BIT(1)
+#define MBUS_ENMBUS BIT(0)
+
+/******************************************************************************
+*
+* 12 Power module
+*
+******************************************************************************/
+
+#define PowerControl REG_AT(0x1C4)
+
+#define PWR_ONBUTN BIT(31)
+#define PWR_PWRINT BIT(30)
+#define PWR_PWROK BIT(29)
+#define PWR_VIDRF_MASK (BIT(28) | BIT(27))
+#define PWR_VIDRF_SHIFT 27
+#define PWR_SLOWBUS BIT(26)
+#define PWR_DIVMOD BIT(25)
+#define PWR_STPTIMERVAL_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12))
+#define PWR_STPTIMERVAL_SHIFT 12
+#define PWR_ENSTPTIMER BIT(11)
+#define PWR_ENFORCESHUTDWN BIT(10)
+#define PWR_FORCESHUTDWN BIT(9)
+#define PWR_FORCESHUTDWNOCC BIT(8)
+#define PWR_SELC2MS BIT(7)
+#define PWR_BPDBVCC3 BIT(5)
+#define PWR_STOPCPU BIT(4)
+#define PWR_DBNCONBUTN BIT(3)
+#define PWR_COLDSTART BIT(2)
+#define PWR_PWRCS BIT(1)
+#define PWR_VCCON BIT(0)
+
+/******************************************************************************
+*
+* 13 SIB (Serial Interconnect Bus) Module
+*
+******************************************************************************/
+
+/* Register locations */
+#define SIBSize REG_AT(0x060)
+#define SIBSoundRXStart REG_AT(0x064)
+#define SIBSoundTXStart REG_AT(0x068)
+#define SIBTelecomRXStart REG_AT(0x06C)
+#define SIBTelecomTXStart REG_AT(0x070)
+#define SIBControl REG_AT(0x074)
+#define SIBSoundTXRXHolding REG_AT(0x078)
+#define SIBTelecomTXRXHolding REG_AT(0x07C)
+#define SIBSubFrame0Control REG_AT(0x080)
+#define SIBSubFrame1Control REG_AT(0x084)
+#define SIBSubFrame0Status REG_AT(0x088)
+#define SIBSubFrame1Status REG_AT(0x08C)
+#define SIBDMAControl REG_AT(0x090)
+
+/* SIB Size Register */
+#define SIB_SNDSIZE_MASK 0x3ffc0000
+#define SIB_SNDSIZE_SHIFT 18
+#define SIB_TELSIZE_MASK 0x00003ffc
+#define SIB_TELSIZE_SHIFT 2
+
+/* SIB Control Register */
+#define SIB_SIBIRQ BIT(31)
+#define SIB_ENCNTTEST BIT(30)
+#define SIB_ENDMATEST BIT(29)
+#define SIB_SNDMONO BIT(28)
+#define SIB_RMONOSNDIN BIT(27)
+#define SIB_SIBSCLKDIV_MASK (BIT(26) | BIT(25) | BIT(24))
+#define SIB_SIBSCLKDIV_SHIFT 24
+#define SIB_TEL16 BIT(23)
+#define SIB_TELFSDIV_MASK 0x007f0000
+#define SIB_TELFSDIV_SHIFT 16
+#define SIB_SND16 BIT(15)
+#define SIB_SNDFSDIV_MASK 0x00007f00
+#define SIB_SNDFSDIV_SHIFT 8
+#define SIB_SELTELSF1 BIT(7)
+#define SIB_SELSNDSF1 BIT(6)
+#define SIB_ENTEL BIT(5)
+#define SIB_ENSND BIT(4)
+#define SIB_SIBLOOP BIT(3)
+#define SIB_ENSF1 BIT(2)
+#define SIB_ENSF0 BIT(1)
+#define SIB_ENSIB BIT(0)
+
+/* SIB Frame Format (SIBSubFrame0Status and SIBSubFrame1Status) */
+#define SIB_REGISTER_EXT BIT(31) /* Must be zero */
+#define SIB_ADDRESS_MASK 0x78000000
+#define SIB_ADDRESS_SHIFT 27
+#define SIB_WRITE BIT(26)
+#define SIB_AUD_VALID BIT(17)
+#define SIB_TEL_VALID BIT(16)
+#define SIB_DATA_MASK 0x00ff
+#define SIB_DATA_SHIFT 0
+
+/* SIB DMA Control Register */
+#define SIB_SNDBUFF1TIME BIT(31)
+#define SIB_SNDDMALOOP BIT(30)
+#define SIB_SNDDMAPTR_MASK 0x3ffc0000
+#define SIB_SNDDMAPTR_SHIFT 18
+#define SIB_ENDMARXSND BIT(17)
+#define SIB_ENDMATXSND BIT(16)
+#define SIB_TELBUFF1TIME BIT(15)
+#define SIB_TELDMALOOP BIT(14)
+#define SIB_TELDMAPTR_MASK 0x00003ffc
+#define SIB_TELDMAPTR_SHIFT 2
+#define SIB_ENDMARXTEL BIT(1)
+#define SIB_ENDMATXTEL BIT(0)
+
+/******************************************************************************
+*
+* 14 SPI module
+*
+******************************************************************************/
+
+#define SPIControl REG_AT(0x160)
+#define SPITransmit REG_AT(0x164)
+#define SPIReceive REG_AT(0x164)
+
+#define SPI_SPION BIT(17)
+#define SPI_EMPTY BIT(16)
+#define SPI_DELAYVAL_MASK (BIT(12) | BIT(13) | BIT(14) | BIT(15))
+#define SPI_DELAYVAL_SHIFT 12
+#define SPI_BAUDRATE_MASK (BIT(8) | BIT(9) | BIT(10) | BIT(11))
+#define SPI_BAUDRATE_SHIFT 8
+#define SPI_PHAPOL BIT(5)
+#define SPI_CLKPOL BIT(4)
+#define SPI_WORD BIT(2)
+#define SPI_LSB BIT(1)
+#define SPI_ENSPI BIT(0)
+
+/******************************************************************************
+*
+* 15 Timer module
+*
+******************************************************************************/
+
+#define RTChigh REG_AT(0x140)
+#define RTClow REG_AT(0x144)
+#define RTCalarmHigh REG_AT(0x148)
+#define RTCalarmLow REG_AT(0x14c)
+#define RTCtimerControl REG_AT(0x150)
+#define RTCperiodTimer REG_AT(0x154)
+
+/* RTC Timer Control */
+#define TIM_FREEZEPRE BIT(7)
+#define TIM_FREEZERTC BIT(6)
+#define TIM_FREEZETIMER BIT(5)
+#define TIM_ENPERTIMER BIT(4)
+#define TIM_RTCCLEAR BIT(3)
+
+#define RTC_HIGHMASK (0xFF)
+
+/* RTC Periodic Timer */
+#define TIM_PERCNT 0xFFFF0000
+#define TIM_PERVAL 0x0000FFFF
+
+/* For a system clock frequency of 36.864MHz, the timer counts at one tick
+ every 868nS (ie CLK/32). Therefore 11520 counts gives a 10mS interval
+ */
+#define PER_TIMER_COUNT (1152000/HZ)
+
+/******************************************************************************
+*
+* 16 UART module
+*
+******************************************************************************/
+
+#define UartA_Ctrl1 REG_AT(0x0b0)
+#define UartA_Ctrl2 REG_AT(0x0b4)
+#define UartA_DMActl1 REG_AT(0x0b8)
+#define UartA_DMActl2 REG_AT(0x0bc)
+#define UartA_DMAcnt REG_AT(0x0c0)
+#define UartA_Data REG_AT(0x0c4)
+#define UartB_Ctrl1 REG_AT(0x0c8)
+#define UartB_Ctrl2 REG_AT(0x0cc)
+#define UartB_DMActl1 REG_AT(0x0d0)
+#define UartB_DMActl2 REG_AT(0x0d4)
+#define UartB_DMAcnt REG_AT(0x0d8)
+#define UartB_Data REG_AT(0x0dc)
+
+/* bit allocations within UART control register 1 */
+#define UART_ON BIT(31) /* indicates status of UART */
+#define UART_TX_EMPTY BIT(30) /* tx holding and shift registers empty */
+#define UART_PRX_HOLD_FULL BIT(29) /* pre-rx holding register full */
+#define UART_RX_HOLD_FULL BIT(28) /* rx holding register is full */
+#define UART_EN_DMA_RX BIT(15) /* enable rx DMA */
+#define UART_EN_DMA_TX BIT(14) /* enable tx DMA */
+#define UART_BREAK_HALT BIT(12) /* enable halt after receiving break */
+#define UART_DMA_LOOP BIT(10) /* enable DMA loop-roud */
+#define UART_PULSE_THREE BIT(9) /* tx data is 3 low pulses */
+#define UART_PULSE_SIX BIT(8) /* tx data is 6 low pulses */
+#define UART_DT_INVERT BIT(7) /* invert txd and rxd */
+#define UART_DIS_TXD BIT(6) /* set txd low */
+#define UART_LOOPBACK BIT(4) /* enable loopback mode */
+#define UART_ENABLE BIT(0) /* enable UART */
+
+#define SER_SEVEN_BIT BIT(3) /* use 7-bit data */
+#define SER_EIGHT_BIT 0 /* use 8-bit data */
+#define SER_EVEN_PARITY (BIT(2) | BIT(1)) /* use even parity */
+#define SER_ODD_PARITY BIT(1) /* use odd parity */
+#define SER_NO_PARITY 0 /* enable parity checking */
+#define SER_TWO_STOP BIT(5) /* transmit 2 stop bits */
+#define SER_ONE_STOP 0 /* transmit 1 stop bits */
+
+/* Baud rate definitions for UART control register 2 */
+#define SER_BAUD_230400 ( 0)
+#define SER_BAUD_115200 ( 1)
+#define SER_BAUD_76800 ( 2)
+#define SER_BAUD_57600 ( 3)
+#define SER_BAUD_38400 ( 5) /* divisors are 3.6864MHz */
+#define SER_BAUD_19200 (11) /* ----------- - 1 */
+#ifdef CONFIG_VTECH_HELIO_EMULATOR
+#define SER_BAUD_9600 (23)
+#else
+#define SER_BAUD_9600 (22) /* (baud * 16) */
+#endif
+#define SER_BAUD_4800 (47)
+#define SER_BAUD_2400 (95)
+#define SER_BAUD_1200 (191)
+#define SER_BAUD_600 (383)
+#define SER_BAUD_300 (767)
+
+/******************************************************************************
+*
+* 17 Video module
+*
+******************************************************************************/
+
+#define VidCtrl1 REG_AT(0x028)
+#define VidCtrl2 REG_AT(0x02C)
+#define VidCtrl3 REG_AT(0x030)
+#define VidCtrl4 REG_AT(0x034)
+#define VidCtrl5 REG_AT(0x038)
+#define VidCtrl6 REG_AT(0x03C)
+#define VidCtrl7 REG_AT(0x040)
+#define VidCtrl8 REG_AT(0x044)
+#define VidCtrl9 REG_AT(0x048)
+#define VidCtrl10 REG_AT(0x04C)
+#define VidCtrl11 REG_AT(0x050)
+#define VidCtrl12 REG_AT(0x054)
+#define VidCtrl13 REG_AT(0x058)
+#define VidCtrl14 REG_AT(0x05C)
+
+/* VidCtrl1 */
+#define LINECNT 0xffc00000
+#define LINECNT_SHIFT 22
+#define LOADDLY BIT(21)
+#define BAUDVAL (BIT(20) | BIT(19) | BIT(18) | BIT(17) | BIT(16))
+#define BAUDVAL_SHIFT 16
+#define VIDDONEVAL (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9))
+#define VIDDONEVAL_SHIFT 9
+#define ENFREEZEFRAME BIT(8)
+#define BITSEL_MASK 0xc0
+#define BITSEL_SHIFT 6
+#define DISPSPLIT BIT(5)
+#define DISP8 BIT(4)
+#define DFMODE BIT(3)
+#define INVVID BIT(2)
+#define DISPON BIT(1)
+#define ENVID BIT(0)
+
+/* VidCtrl2 */
+#define VIDRATE_MASK 0xffc00000
+#define VIDRATE_SHIFT 22
+#define HORZVAL_MASK 0x001ff000
+#define HORZVAL_SHIFT 12
+#define LINEVAL_MASK 0x000001ff
+
+/* VidCtrl3 */
+#define VIDBANK_MASK 0xfff00000
+#define VIDBASEHI_MASK 0x000ffff0
+
+/* VidCtrl4 */
+#define VIDBASELO_MASK 0x000ffff0
+
+#endif /* __PR31700_H__ */
diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h
index 252c3a58b..2f436e79f 100644
--- a/include/asm-mips/stackframe.h
+++ b/include/asm-mips/stackframe.h
@@ -144,7 +144,7 @@ __asm__ ( \
lw $23, PT_R23(sp); \
lw $30, PT_R30(sp)
-#if defined(CONFIG_CPU_R3000)
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R3912)
#define RESTORE_SOME \
.set push; \
diff --git a/include/asm-mips/string.h b/include/asm-mips/string.h
index e19a50fbb..e2b0ba4e8 100644
--- a/include/asm-mips/string.h
+++ b/include/asm-mips/string.h
@@ -76,7 +76,7 @@ extern __inline__ int strcmp(__const__ char *__cs, __const__ char *__ct)
"addiu\t%1,1\n\t"
"bnez\t%2,1b\n\t"
"lbu\t%2,(%0)\n\t"
-#if defined(CONFIG_CPU_R3000)
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R3912)
"nop\n\t"
#endif
"move\t%2,$1\n"
@@ -108,7 +108,7 @@ strncmp(__const__ char *__cs, __const__ char *__ct, size_t __count)
"bnez\t%3,1b\n\t"
"addiu\t%1,1\n"
"2:\n\t"
-#if defined(CONFIG_CPU_R3000)
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_R3912)
"nop\n\t"
#endif
"move\t%3,$1\n"