diff options
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*)(¤t->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" |