diff options
Diffstat (limited to 'arch/mips/vr41xx')
26 files changed, 3315 insertions, 0 deletions
diff --git a/arch/mips/vr41xx/casio-e55/Makefile b/arch/mips/vr41xx/casio-e55/Makefile new file mode 100644 index 000000000000..d4c03cc8eb05 --- /dev/null +++ b/arch/mips/vr41xx/casio-e55/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the CASIO CASSIOPEIA E-55/65 specific parts of the kernel +# + +obj-y += setup.o diff --git a/arch/mips/vr41xx/casio-e55/setup.c b/arch/mips/vr41xx/casio-e55/setup.c new file mode 100644 index 000000000000..aa8605ab76ff --- /dev/null +++ b/arch/mips/vr41xx/casio-e55/setup.c @@ -0,0 +1,40 @@ +/* + * setup.c, Setup for the CASIO CASSIOPEIA E-11/15/55/65. + * + * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/init.h> +#include <linux/ioport.h> + +#include <asm/io.h> +#include <asm/vr41xx/e55.h> + +const char *get_system_type(void) +{ + return "CASIO CASSIOPEIA E-11/15/55/65"; +} + +static int __init casio_e55_setup(void) +{ + set_io_port_base(IO_PORT_BASE); + ioport_resource.start = IO_PORT_RESOURCE_START; + ioport_resource.end = IO_PORT_RESOURCE_END; + + return 0; +} + +arch_initcall(casio_e55_setup); diff --git a/arch/mips/vr41xx/common/Makefile b/arch/mips/vr41xx/common/Makefile new file mode 100644 index 000000000000..92c11e9bbb3f --- /dev/null +++ b/arch/mips/vr41xx/common/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for common code of the NEC VR4100 series. +# + +obj-y += bcu.o cmu.o giu.o icu.o init.o int-handler.o pmu.o +obj-$(CONFIG_VRC4173) += vrc4173.o + +EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/vr41xx/common/bcu.c b/arch/mips/vr41xx/common/bcu.c new file mode 100644 index 000000000000..cdfa4273a1c5 --- /dev/null +++ b/arch/mips/vr41xx/common/bcu.c @@ -0,0 +1,222 @@ +/* + * bcu.c, Bus Control Unit routines for the NEC VR4100 series. + * + * Copyright (C) 2002 MontaVista Software Inc. + * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> + * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * Changes: + * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> + * - New creation, NEC VR4122 and VR4131 are supported. + * - Added support for NEC VR4111 and VR4121. + * + * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * - Added support for NEC VR4133. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/smp.h> +#include <linux/types.h> + +#include <asm/cpu.h> +#include <asm/io.h> + +#define CLKSPEEDREG_TYPE1 (void __iomem *)KSEG1ADDR(0x0b000014) +#define CLKSPEEDREG_TYPE2 (void __iomem *)KSEG1ADDR(0x0f000014) + #define CLKSP(x) ((x) & 0x001f) + #define CLKSP_VR4133(x) ((x) & 0x0007) + + #define DIV2B 0x8000 + #define DIV3B 0x4000 + #define DIV4B 0x2000 + + #define DIVT(x) (((x) & 0xf000) >> 12) + #define DIVVT(x) (((x) & 0x0f00) >> 8) + + #define TDIVMODE(x) (2 << (((x) & 0x1000) >> 12)) + #define VTDIVMODE(x) (((x) & 0x0700) >> 8) + +static unsigned long vr41xx_vtclock; +static unsigned long vr41xx_tclock; + +unsigned long vr41xx_get_vtclock_frequency(void) +{ + return vr41xx_vtclock; +} + +EXPORT_SYMBOL_GPL(vr41xx_get_vtclock_frequency); + +unsigned long vr41xx_get_tclock_frequency(void) +{ + return vr41xx_tclock; +} + +EXPORT_SYMBOL_GPL(vr41xx_get_tclock_frequency); + +static inline uint16_t read_clkspeed(void) +{ + switch (current_cpu_data.cputype) { + case CPU_VR4111: + case CPU_VR4121: return readw(CLKSPEEDREG_TYPE1); + case CPU_VR4122: + case CPU_VR4131: + case CPU_VR4133: return readw(CLKSPEEDREG_TYPE2); + default: + printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); + break; + } + + return 0; +} + +static inline unsigned long calculate_pclock(uint16_t clkspeed) +{ + unsigned long pclock = 0; + + switch (current_cpu_data.cputype) { + case CPU_VR4111: + case CPU_VR4121: + pclock = 18432000 * 64; + pclock /= CLKSP(clkspeed); + break; + case CPU_VR4122: + pclock = 18432000 * 98; + pclock /= CLKSP(clkspeed); + break; + case CPU_VR4131: + pclock = 18432000 * 108; + pclock /= CLKSP(clkspeed); + break; + case CPU_VR4133: + switch (CLKSP_VR4133(clkspeed)) { + case 0: + pclock = 133000000; + break; + case 1: + pclock = 149000000; + break; + case 2: + pclock = 165900000; + break; + case 3: + pclock = 199100000; + break; + case 4: + pclock = 265900000; + break; + default: + printk(KERN_INFO "Unknown PClock speed for NEC VR4133\n"); + break; + } + break; + default: + printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); + break; + } + + printk(KERN_INFO "PClock: %ldHz\n", pclock); + + return pclock; +} + +static inline unsigned long calculate_vtclock(uint16_t clkspeed, unsigned long pclock) +{ + unsigned long vtclock = 0; + + switch (current_cpu_data.cputype) { + case CPU_VR4111: + /* The NEC VR4111 doesn't have the VTClock. */ + break; + case CPU_VR4121: + vtclock = pclock; + /* DIVVT == 9 Divide by 1.5 . VTClock = (PClock * 6) / 9 */ + if (DIVVT(clkspeed) == 9) + vtclock = pclock * 6; + /* DIVVT == 10 Divide by 2.5 . VTClock = (PClock * 4) / 10 */ + else if (DIVVT(clkspeed) == 10) + vtclock = pclock * 4; + vtclock /= DIVVT(clkspeed); + printk(KERN_INFO "VTClock: %ldHz\n", vtclock); + break; + case CPU_VR4122: + if(VTDIVMODE(clkspeed) == 7) + vtclock = pclock / 1; + else if(VTDIVMODE(clkspeed) == 1) + vtclock = pclock / 2; + else + vtclock = pclock / VTDIVMODE(clkspeed); + printk(KERN_INFO "VTClock: %ldHz\n", vtclock); + break; + case CPU_VR4131: + case CPU_VR4133: + vtclock = pclock / VTDIVMODE(clkspeed); + printk(KERN_INFO "VTClock: %ldHz\n", vtclock); + break; + default: + printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); + break; + } + + return vtclock; +} + +static inline unsigned long calculate_tclock(uint16_t clkspeed, unsigned long pclock, + unsigned long vtclock) +{ + unsigned long tclock = 0; + + switch (current_cpu_data.cputype) { + case CPU_VR4111: + if (!(clkspeed & DIV2B)) + tclock = pclock / 2; + else if (!(clkspeed & DIV3B)) + tclock = pclock / 3; + else if (!(clkspeed & DIV4B)) + tclock = pclock / 4; + break; + case CPU_VR4121: + tclock = pclock / DIVT(clkspeed); + break; + case CPU_VR4122: + case CPU_VR4131: + case CPU_VR4133: + tclock = vtclock / TDIVMODE(clkspeed); + break; + default: + printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n"); + break; + } + + printk(KERN_INFO "TClock: %ldHz\n", tclock); + + return tclock; +} + +void vr41xx_calculate_clock_frequency(void) +{ + unsigned long pclock; + uint16_t clkspeed; + + clkspeed = read_clkspeed(); + + pclock = calculate_pclock(clkspeed); + vr41xx_vtclock = calculate_vtclock(clkspeed, pclock); + vr41xx_tclock = calculate_tclock(clkspeed, pclock, vr41xx_vtclock); +} + +EXPORT_SYMBOL_GPL(vr41xx_calculate_clock_frequency); diff --git a/arch/mips/vr41xx/common/cmu.c b/arch/mips/vr41xx/common/cmu.c new file mode 100644 index 000000000000..fcd3cb8cdd9d --- /dev/null +++ b/arch/mips/vr41xx/common/cmu.c @@ -0,0 +1,257 @@ +/* + * cmu.c, Clock Mask Unit routines for the NEC VR4100 series. + * + * Copyright (C) 2001-2002 MontaVista Software Inc. + * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> + * Copuright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * Changes: + * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> + * - New creation, NEC VR4122 and VR4131 are supported. + * - Added support for NEC VR4111 and VR4121. + * + * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * - Added support for NEC VR4133. + */ +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/smp.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +#include <asm/cpu.h> +#include <asm/io.h> +#include <asm/vr41xx/vr41xx.h> + +#define CMU_TYPE1_BASE 0x0b000060UL +#define CMU_TYPE1_SIZE 0x4 + +#define CMU_TYPE2_BASE 0x0f000060UL +#define CMU_TYPE2_SIZE 0x4 + +#define CMU_TYPE3_BASE 0x0f000060UL +#define CMU_TYPE3_SIZE 0x8 + +#define CMUCLKMSK 0x0 + #define MSKPIU 0x0001 + #define MSKSIU 0x0002 + #define MSKAIU 0x0004 + #define MSKKIU 0x0008 + #define MSKFIR 0x0010 + #define MSKDSIU 0x0820 + #define MSKCSI 0x0040 + #define MSKPCIU 0x0080 + #define MSKSSIU 0x0100 + #define MSKSHSP 0x0200 + #define MSKFFIR 0x0400 + #define MSKSCSI 0x1000 + #define MSKPPCIU 0x2000 +#define CMUCLKMSK2 0x4 + #define MSKCEU 0x0001 + #define MSKMAC0 0x0002 + #define MSKMAC1 0x0004 + +static void __iomem *cmu_base; +static uint16_t cmuclkmsk, cmuclkmsk2; +static spinlock_t cmu_lock; + +#define cmu_read(offset) readw(cmu_base + (offset)) +#define cmu_write(offset, value) writew((value), cmu_base + (offset)) + +void vr41xx_supply_clock(vr41xx_clock_t clock) +{ + spin_lock_irq(&cmu_lock); + + switch (clock) { + case PIU_CLOCK: + cmuclkmsk |= MSKPIU; + break; + case SIU_CLOCK: + cmuclkmsk |= MSKSIU | MSKSSIU; + break; + case AIU_CLOCK: + cmuclkmsk |= MSKAIU; + break; + case KIU_CLOCK: + cmuclkmsk |= MSKKIU; + break; + case FIR_CLOCK: + cmuclkmsk |= MSKFIR | MSKFFIR; + break; + case DSIU_CLOCK: + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) + cmuclkmsk |= MSKDSIU; + else + cmuclkmsk |= MSKSIU | MSKDSIU; + break; + case CSI_CLOCK: + cmuclkmsk |= MSKCSI | MSKSCSI; + break; + case PCIU_CLOCK: + cmuclkmsk |= MSKPCIU; + break; + case HSP_CLOCK: + cmuclkmsk |= MSKSHSP; + break; + case PCI_CLOCK: + cmuclkmsk |= MSKPPCIU; + break; + case CEU_CLOCK: + cmuclkmsk2 |= MSKCEU; + break; + case ETHER0_CLOCK: + cmuclkmsk2 |= MSKMAC0; + break; + case ETHER1_CLOCK: + cmuclkmsk2 |= MSKMAC1; + break; + default: + break; + } + + if (clock == CEU_CLOCK || clock == ETHER0_CLOCK || + clock == ETHER1_CLOCK) + cmu_write(CMUCLKMSK2, cmuclkmsk2); + else + cmu_write(CMUCLKMSK, cmuclkmsk); + + spin_unlock_irq(&cmu_lock); +} + +EXPORT_SYMBOL_GPL(vr41xx_supply_clock); + +void vr41xx_mask_clock(vr41xx_clock_t clock) +{ + spin_lock_irq(&cmu_lock); + + switch (clock) { + case PIU_CLOCK: + cmuclkmsk &= ~MSKPIU; + break; + case SIU_CLOCK: + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + cmuclkmsk &= ~(MSKSIU | MSKSSIU); + } else { + if (cmuclkmsk & MSKDSIU) + cmuclkmsk &= ~MSKSSIU; + else + cmuclkmsk &= ~(MSKSIU | MSKSSIU); + } + break; + case AIU_CLOCK: + cmuclkmsk &= ~MSKAIU; + break; + case KIU_CLOCK: + cmuclkmsk &= ~MSKKIU; + break; + case FIR_CLOCK: + cmuclkmsk &= ~(MSKFIR | MSKFFIR); + break; + case DSIU_CLOCK: + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + cmuclkmsk &= ~MSKDSIU; + } else { + if (cmuclkmsk & MSKSSIU) + cmuclkmsk &= ~MSKDSIU; + else + cmuclkmsk &= ~(MSKSIU | MSKDSIU); + } + break; + case CSI_CLOCK: + cmuclkmsk &= ~(MSKCSI | MSKSCSI); + break; + case PCIU_CLOCK: + cmuclkmsk &= ~MSKPCIU; + break; + case HSP_CLOCK: + cmuclkmsk &= ~MSKSHSP; + break; + case PCI_CLOCK: + cmuclkmsk &= ~MSKPPCIU; + break; + case CEU_CLOCK: + cmuclkmsk2 &= ~MSKCEU; + break; + case ETHER0_CLOCK: + cmuclkmsk2 &= ~MSKMAC0; + break; + case ETHER1_CLOCK: + cmuclkmsk2 &= ~MSKMAC1; + break; + default: + break; + } + + if (clock == CEU_CLOCK || clock == ETHER0_CLOCK || + clock == ETHER1_CLOCK) + cmu_write(CMUCLKMSK2, cmuclkmsk2); + else + cmu_write(CMUCLKMSK, cmuclkmsk); + + spin_unlock_irq(&cmu_lock); +} + +EXPORT_SYMBOL_GPL(vr41xx_mask_clock); + +static int __init vr41xx_cmu_init(void) +{ + unsigned long start, size; + + switch (current_cpu_data.cputype) { + case CPU_VR4111: + case CPU_VR4121: + start = CMU_TYPE1_BASE; + size = CMU_TYPE1_SIZE; + break; + case CPU_VR4122: + case CPU_VR4131: + start = CMU_TYPE2_BASE; + size = CMU_TYPE2_SIZE; + break; + case CPU_VR4133: + start = CMU_TYPE3_BASE; + size = CMU_TYPE3_SIZE; + break; + default: + panic("Unexpected CPU of NEC VR4100 series"); + break; + } + + if (request_mem_region(start, size, "CMU") == NULL) + return -EBUSY; + + cmu_base = ioremap(start, size); + if (cmu_base == NULL) { + release_mem_region(start, size); + return -EBUSY; + } + + cmuclkmsk = cmu_read(CMUCLKMSK); + if (current_cpu_data.cputype == CPU_VR4133) + cmuclkmsk2 = cmu_read(CMUCLKMSK2); + + spin_lock_init(&cmu_lock); + + return 0; +} + +core_initcall(vr41xx_cmu_init); diff --git a/arch/mips/vr41xx/common/giu.c b/arch/mips/vr41xx/common/giu.c new file mode 100644 index 000000000000..9c6b21a79e8f --- /dev/null +++ b/arch/mips/vr41xx/common/giu.c @@ -0,0 +1,455 @@ +/* + * giu.c, General-purpose I/O Unit Interrupt routines for NEC VR4100 series. + * + * Copyright (C) 2002 MontaVista Software Inc. + * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> + * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * Changes: + * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> + * - New creation, NEC VR4111, VR4121, VR4122 and VR4131 are supported. + * + * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * - Added support for NEC VR4133. + * - Removed board_irq_init. + */ +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/smp.h> +#include <linux/types.h> + +#include <asm/cpu.h> +#include <asm/io.h> +#include <asm/vr41xx/vr41xx.h> + +#define GIUIOSELL_TYPE1 KSEG1ADDR(0x0b000100) +#define GIUIOSELL_TYPE2 KSEG1ADDR(0x0f000140) + +#define GIUIOSELL 0x00 +#define GIUIOSELH 0x02 +#define GIUINTSTATL 0x08 +#define GIUINTSTATH 0x0a +#define GIUINTENL 0x0c +#define GIUINTENH 0x0e +#define GIUINTTYPL 0x10 +#define GIUINTTYPH 0x12 +#define GIUINTALSELL 0x14 +#define GIUINTALSELH 0x16 +#define GIUINTHTSELL 0x18 +#define GIUINTHTSELH 0x1a +#define GIUFEDGEINHL 0x20 +#define GIUFEDGEINHH 0x22 +#define GIUREDGEINHL 0x24 +#define GIUREDGEINHH 0x26 + +static uint32_t giu_base; + +static struct irqaction giu_cascade = { + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "cascade", +}; + +#define read_giuint(offset) readw(giu_base + (offset)) +#define write_giuint(val, offset) writew((val), giu_base + (offset)) + +#define GIUINT_HIGH_OFFSET 16 + +static inline uint16_t set_giuint(uint8_t offset, uint16_t set) +{ + uint16_t res; + + res = read_giuint(offset); + res |= set; + write_giuint(res, offset); + + return res; +} + +static inline uint16_t clear_giuint(uint8_t offset, uint16_t clear) +{ + uint16_t res; + + res = read_giuint(offset); + res &= ~clear; + write_giuint(res, offset); + + return res; +} + +static unsigned int startup_giuint_low_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GIU_IRQ_TO_PIN(irq); + write_giuint((uint16_t)1 << pin, GIUINTSTATL); + set_giuint(GIUINTENL, (uint16_t)1 << pin); + + return 0; +} + +static void shutdown_giuint_low_irq(unsigned int irq) +{ + clear_giuint(GIUINTENL, (uint16_t)1 << GIU_IRQ_TO_PIN(irq)); +} + +static void enable_giuint_low_irq(unsigned int irq) +{ + set_giuint(GIUINTENL, (uint16_t)1 << GIU_IRQ_TO_PIN(irq)); +} + +#define disable_giuint_low_irq shutdown_giuint_low_irq + +static void ack_giuint_low_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GIU_IRQ_TO_PIN(irq); + clear_giuint(GIUINTENL, (uint16_t)1 << pin); + write_giuint((uint16_t)1 << pin, GIUINTSTATL); +} + +static void end_giuint_low_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + set_giuint(GIUINTENL, (uint16_t)1 << GIU_IRQ_TO_PIN(irq)); +} + +static struct hw_interrupt_type giuint_low_irq_type = { + .typename = "GIUINTL", + .startup = startup_giuint_low_irq, + .shutdown = shutdown_giuint_low_irq, + .enable = enable_giuint_low_irq, + .disable = disable_giuint_low_irq, + .ack = ack_giuint_low_irq, + .end = end_giuint_low_irq, +}; + +static unsigned int startup_giuint_high_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET); + write_giuint((uint16_t)1 << pin, GIUINTSTATH); + set_giuint(GIUINTENH, (uint16_t)1 << pin); + + return 0; +} + +static void shutdown_giuint_high_irq(unsigned int irq) +{ + clear_giuint(GIUINTENH, (uint16_t)1 << GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET)); +} + +static void enable_giuint_high_irq(unsigned int irq) +{ + set_giuint(GIUINTENH, (uint16_t)1 << GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET)); +} + +#define disable_giuint_high_irq shutdown_giuint_high_irq + +static void ack_giuint_high_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET); + clear_giuint(GIUINTENH, (uint16_t)1 << pin); + write_giuint((uint16_t)1 << pin, GIUINTSTATH); +} + +static void end_giuint_high_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + set_giuint(GIUINTENH, (uint16_t)1 << GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET)); +} + +static struct hw_interrupt_type giuint_high_irq_type = { + .typename = "GIUINTH", + .startup = startup_giuint_high_irq, + .shutdown = shutdown_giuint_high_irq, + .enable = enable_giuint_high_irq, + .disable = disable_giuint_high_irq, + .ack = ack_giuint_high_irq, + .end = end_giuint_high_irq, +}; + +void __init init_vr41xx_giuint_irq(void) +{ + int i; + + for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { + if (i < (GIU_IRQ_BASE + GIUINT_HIGH_OFFSET)) + irq_desc[i].handler = &giuint_low_irq_type; + else + irq_desc[i].handler = &giuint_high_irq_type; + } + + setup_irq(GIUINT_CASCADE_IRQ, &giu_cascade); +} + +void vr41xx_set_irq_trigger(int pin, int trigger, int hold) +{ + uint16_t mask; + + if (pin < GIUINT_HIGH_OFFSET) { + mask = (uint16_t)1 << pin; + if (trigger != TRIGGER_LEVEL) { + set_giuint(GIUINTTYPL, mask); + if (hold == SIGNAL_HOLD) + set_giuint(GIUINTHTSELL, mask); + else + clear_giuint(GIUINTHTSELL, mask); + if (current_cpu_data.cputype == CPU_VR4133) { + switch (trigger) { + case TRIGGER_EDGE_FALLING: + set_giuint(GIUFEDGEINHL, mask); + clear_giuint(GIUREDGEINHL, mask); + break; + case TRIGGER_EDGE_RISING: + clear_giuint(GIUFEDGEINHL, mask); + set_giuint(GIUREDGEINHL, mask); + break; + default: + set_giuint(GIUFEDGEINHL, mask); + set_giuint(GIUREDGEINHL, mask); + break; + } + } + } else { + clear_giuint(GIUINTTYPL, mask); + clear_giuint(GIUINTHTSELL, mask); + } + write_giuint(mask, GIUINTSTATL); + } else { + mask = (uint16_t)1 << (pin - GIUINT_HIGH_OFFSET); + if (trigger != TRIGGER_LEVEL) { + set_giuint(GIUINTTYPH, mask); + if (hold == SIGNAL_HOLD) + set_giuint(GIUINTHTSELH, mask); + else + clear_giuint(GIUINTHTSELH, mask); + if (current_cpu_data.cputype == CPU_VR4133) { + switch (trigger) { + case TRIGGER_EDGE_FALLING: + set_giuint(GIUFEDGEINHH, mask); + clear_giuint(GIUREDGEINHH, mask); + break; + case TRIGGER_EDGE_RISING: + clear_giuint(GIUFEDGEINHH, mask); + set_giuint(GIUREDGEINHH, mask); + break; + default: + set_giuint(GIUFEDGEINHH, mask); + set_giuint(GIUREDGEINHH, mask); + break; + } + } + } else { + clear_giuint(GIUINTTYPH, mask); + clear_giuint(GIUINTHTSELH, mask); + } + write_giuint(mask, GIUINTSTATH); + } +} + +EXPORT_SYMBOL(vr41xx_set_irq_trigger); + +void vr41xx_set_irq_level(int pin, int level) +{ + uint16_t mask; + + if (pin < GIUINT_HIGH_OFFSET) { + mask = (uint16_t)1 << pin; + if (level == LEVEL_HIGH) + set_giuint(GIUINTALSELL, mask); + else + clear_giuint(GIUINTALSELL, mask); + write_giuint(mask, GIUINTSTATL); + } else { + mask = (uint16_t)1 << (pin - GIUINT_HIGH_OFFSET); + if (level == LEVEL_HIGH) + set_giuint(GIUINTALSELH, mask); + else + clear_giuint(GIUINTALSELH, mask); + write_giuint(mask, GIUINTSTATH); + } +} + +EXPORT_SYMBOL(vr41xx_set_irq_level); + +#define GIUINT_NR_IRQS 32 + +enum { + GIUINT_NO_CASCADE, + GIUINT_CASCADE +}; + +struct vr41xx_giuint_cascade { + unsigned int flag; + int (*get_irq_number)(int irq); +}; + +static struct vr41xx_giuint_cascade giuint_cascade[GIUINT_NR_IRQS]; + +static int no_irq_number(int irq) +{ + return -EINVAL; +} + +int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq)) +{ + unsigned int pin; + int retval; + + if (irq < GIU_IRQ(0) || irq > GIU_IRQ(31)) + return -EINVAL; + + if(!get_irq_number) + return -EINVAL; + + pin = GIU_IRQ_TO_PIN(irq); + giuint_cascade[pin].flag = GIUINT_CASCADE; + giuint_cascade[pin].get_irq_number = get_irq_number; + + retval = setup_irq(irq, &giu_cascade); + if (retval != 0) { + giuint_cascade[pin].flag = GIUINT_NO_CASCADE; + giuint_cascade[pin].get_irq_number = no_irq_number; + } + + return retval; +} + +EXPORT_SYMBOL(vr41xx_cascade_irq); + +static inline int get_irq_pin_number(void) +{ + uint16_t pendl, pendh, maskl, maskh; + int i; + + pendl = read_giuint(GIUINTSTATL); + pendh = read_giuint(GIUINTSTATH); + maskl = read_giuint(GIUINTENL); + maskh = read_giuint(GIUINTENH); + + maskl &= pendl; + maskh &= pendh; + + if (maskl) { + for (i = 0; i < 16; i++) { + if (maskl & ((uint16_t)1 << i)) + return i; + } + } else if (maskh) { + for (i = 0; i < 16; i++) { + if (maskh & ((uint16_t)1 << i)) + return i + GIUINT_HIGH_OFFSET; + } + } + + printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", + maskl, pendl, maskh, pendh); + + atomic_inc(&irq_err_count); + + return -1; +} + +static inline void ack_giuint_irq(int pin) +{ + if (pin < GIUINT_HIGH_OFFSET) { + clear_giuint(GIUINTENL, (uint16_t)1 << pin); + write_giuint((uint16_t)1 << pin, GIUINTSTATL); + } else { + pin -= GIUINT_HIGH_OFFSET; + clear_giuint(GIUINTENH, (uint16_t)1 << pin); + write_giuint((uint16_t)1 << pin, GIUINTSTATH); + } +} + +static inline void end_giuint_irq(int pin) +{ + if (pin < GIUINT_HIGH_OFFSET) + set_giuint(GIUINTENL, (uint16_t)1 << pin); + else + set_giuint(GIUINTENH, (uint16_t)1 << (pin - GIUINT_HIGH_OFFSET)); +} + +void giuint_irq_dispatch(struct pt_regs *regs) +{ + struct vr41xx_giuint_cascade *cascade; + unsigned int giuint_irq; + int pin; + + pin = get_irq_pin_number(); + if (pin < 0) + return; + + disable_irq(GIUINT_CASCADE_IRQ); + + cascade = &giuint_cascade[pin]; + giuint_irq = GIU_IRQ(pin); + if (cascade->flag == GIUINT_CASCADE) { + int irq = cascade->get_irq_number(giuint_irq); + ack_giuint_irq(pin); + if (irq >= 0) + do_IRQ(irq, regs); + end_giuint_irq(pin); + } else { + do_IRQ(giuint_irq, regs); + } + + enable_irq(GIUINT_CASCADE_IRQ); +} + +static int __init vr41xx_giu_init(void) +{ + int i; + + switch (current_cpu_data.cputype) { + case CPU_VR4111: + case CPU_VR4121: + giu_base = GIUIOSELL_TYPE1; + break; + case CPU_VR4122: + case CPU_VR4131: + case CPU_VR4133: + giu_base = GIUIOSELL_TYPE2; + break; + default: + printk(KERN_ERR "GIU: Unexpected CPU of NEC VR4100 series\n"); + return -EINVAL; + } + + for (i = 0; i < GIUINT_NR_IRQS; i++) { + if (i < GIUINT_HIGH_OFFSET) + clear_giuint(GIUINTENL, (uint16_t)1 << i); + else + clear_giuint(GIUINTENH, (uint16_t)1 << (i - GIUINT_HIGH_OFFSET)); + giuint_cascade[i].flag = GIUINT_NO_CASCADE; + giuint_cascade[i].get_irq_number = no_irq_number; + } + + return 0; +} + +early_initcall(vr41xx_giu_init); diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c new file mode 100644 index 000000000000..c842661144cb --- /dev/null +++ b/arch/mips/vr41xx/common/icu.c @@ -0,0 +1,757 @@ +/* + * icu.c, Interrupt Control Unit routines for the NEC VR4100 series. + * + * Copyright (C) 2001-2002 MontaVista Software Inc. + * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> + * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * Changes: + * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> + * - New creation, NEC VR4122 and VR4131 are supported. + * - Added support for NEC VR4111 and VR4121. + * + * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * - Coped with INTASSIGN of NEC VR4133. + */ +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/smp.h> +#include <linux/types.h> + +#include <asm/cpu.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/irq_cpu.h> +#include <asm/vr41xx/vr41xx.h> + +extern asmlinkage void vr41xx_handle_interrupt(void); + +extern void init_vr41xx_giuint_irq(void); +extern void giuint_irq_dispatch(struct pt_regs *regs); + +static uint32_t icu1_base; +static uint32_t icu2_base; + +static struct irqaction icu_cascade = { + .handler = no_action, + .mask = CPU_MASK_NONE, + .name = "cascade", +}; + +static unsigned char sysint1_assign[16] = { + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static unsigned char sysint2_assign[16] = { + 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +#define SYSINT1REG_TYPE1 KSEG1ADDR(0x0b000080) +#define SYSINT2REG_TYPE1 KSEG1ADDR(0x0b000200) + +#define SYSINT1REG_TYPE2 KSEG1ADDR(0x0f000080) +#define SYSINT2REG_TYPE2 KSEG1ADDR(0x0f0000a0) + +#define SYSINT1REG 0x00 +#define PIUINTREG 0x02 +#define INTASSIGN0 0x04 +#define INTASSIGN1 0x06 +#define GIUINTLREG 0x08 +#define DSIUINTREG 0x0a +#define MSYSINT1REG 0x0c +#define MPIUINTREG 0x0e +#define MAIUINTREG 0x10 +#define MKIUINTREG 0x12 +#define MGIUINTLREG 0x14 +#define MDSIUINTREG 0x16 +#define NMIREG 0x18 +#define SOFTREG 0x1a +#define INTASSIGN2 0x1c +#define INTASSIGN3 0x1e + +#define SYSINT2REG 0x00 +#define GIUINTHREG 0x02 +#define FIRINTREG 0x04 +#define MSYSINT2REG 0x06 +#define MGIUINTHREG 0x08 +#define MFIRINTREG 0x0a +#define PCIINTREG 0x0c + #define PCIINT0 0x0001 +#define SCUINTREG 0x0e + #define SCUINT0 0x0001 +#define CSIINTREG 0x10 +#define MPCIINTREG 0x12 +#define MSCUINTREG 0x14 +#define MCSIINTREG 0x16 +#define BCUINTREG 0x18 + #define BCUINTR 0x0001 +#define MBCUINTREG 0x1a + +#define SYSINT1_IRQ_TO_PIN(x) ((x) - SYSINT1_IRQ_BASE) /* Pin 0-15 */ +#define SYSINT2_IRQ_TO_PIN(x) ((x) - SYSINT2_IRQ_BASE) /* Pin 0-15 */ + +#define read_icu1(offset) readw(icu1_base + (offset)) +#define write_icu1(val, offset) writew((val), icu1_base + (offset)) + +#define read_icu2(offset) readw(icu2_base + (offset)) +#define write_icu2(val, offset) writew((val), icu2_base + (offset)) + +#define INTASSIGN_MAX 4 +#define INTASSIGN_MASK 0x0007 + +static inline uint16_t set_icu1(uint8_t offset, uint16_t set) +{ + uint16_t res; + + res = read_icu1(offset); + res |= set; + write_icu1(res, offset); + + return res; +} + +static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear) +{ + uint16_t res; + + res = read_icu1(offset); + res &= ~clear; + write_icu1(res, offset); + + return res; +} + +static inline uint16_t set_icu2(uint8_t offset, uint16_t set) +{ + uint16_t res; + + res = read_icu2(offset); + res |= set; + write_icu2(res, offset); + + return res; +} + +static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear) +{ + uint16_t res; + + res = read_icu2(offset); + res &= ~clear; + write_icu2(res, offset); + + return res; +} + +/*=======================================================================*/ + +void vr41xx_enable_piuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + PIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + set_icu1(MPIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_enable_piuint); + +void vr41xx_disable_piuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + PIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu1(MPIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_disable_piuint); + +void vr41xx_enable_aiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + AIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + set_icu1(MAIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_enable_aiuint); + +void vr41xx_disable_aiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + AIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu1(MAIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_disable_aiuint); + +void vr41xx_enable_kiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + KIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + set_icu1(MKIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_enable_kiuint); + +void vr41xx_disable_kiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + KIU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4111 || + current_cpu_data.cputype == CPU_VR4121) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu1(MKIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_disable_kiuint); + +void vr41xx_enable_dsiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + DSIU_IRQ; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + set_icu1(MDSIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vr41xx_enable_dsiuint); + +void vr41xx_disable_dsiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + DSIU_IRQ; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + clear_icu1(MDSIUINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vr41xx_disable_dsiuint); + +void vr41xx_enable_firint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + FIR_IRQ; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + set_icu2(MFIRINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vr41xx_enable_firint); + +void vr41xx_disable_firint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + FIR_IRQ; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + clear_icu2(MFIRINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vr41xx_disable_firint); + +void vr41xx_enable_pciint(void) +{ + irq_desc_t *desc = irq_desc + PCI_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(PCIINT0, MPCIINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_enable_pciint); + +void vr41xx_disable_pciint(void) +{ + irq_desc_t *desc = irq_desc + PCI_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(0, MPCIINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_disable_pciint); + +void vr41xx_enable_scuint(void) +{ + irq_desc_t *desc = irq_desc + SCU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(SCUINT0, MSCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_enable_scuint); + +void vr41xx_disable_scuint(void) +{ + irq_desc_t *desc = irq_desc + SCU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(0, MSCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_disable_scuint); + +void vr41xx_enable_csiint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + CSI_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + set_icu2(MCSIINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_enable_csiint); + +void vr41xx_disable_csiint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + CSI_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + clear_icu2(MCSIINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_disable_csiint); + +void vr41xx_enable_bcuint(void) +{ + irq_desc_t *desc = irq_desc + BCU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(BCUINTR, MBCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_enable_bcuint); + +void vr41xx_disable_bcuint(void) +{ + irq_desc_t *desc = irq_desc + BCU_IRQ; + unsigned long flags; + + if (current_cpu_data.cputype == CPU_VR4122 || + current_cpu_data.cputype == CPU_VR4131 || + current_cpu_data.cputype == CPU_VR4133) { + spin_lock_irqsave(&desc->lock, flags); + write_icu2(0, MBCUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +EXPORT_SYMBOL(vr41xx_disable_bcuint); + +/*=======================================================================*/ + +static unsigned int startup_sysint1_irq(unsigned int irq) +{ + set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); + + return 0; /* never anything pending */ +} + +static void shutdown_sysint1_irq(unsigned int irq) +{ + clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); +} + +static void enable_sysint1_irq(unsigned int irq) +{ + set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); +} + +#define disable_sysint1_irq shutdown_sysint1_irq +#define ack_sysint1_irq shutdown_sysint1_irq + +static void end_sysint1_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); +} + +static struct hw_interrupt_type sysint1_irq_type = { + .typename = "SYSINT1", + .startup = startup_sysint1_irq, + .shutdown = shutdown_sysint1_irq, + .enable = enable_sysint1_irq, + .disable = disable_sysint1_irq, + .ack = ack_sysint1_irq, + .end = end_sysint1_irq, +}; + +/*=======================================================================*/ + +static unsigned int startup_sysint2_irq(unsigned int irq) +{ + set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); + + return 0; /* never anything pending */ +} + +static void shutdown_sysint2_irq(unsigned int irq) +{ + clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); +} + +static void enable_sysint2_irq(unsigned int irq) +{ + set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); +} + +#define disable_sysint2_irq shutdown_sysint2_irq +#define ack_sysint2_irq shutdown_sysint2_irq + +static void end_sysint2_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); +} + +static struct hw_interrupt_type sysint2_irq_type = { + .typename = "SYSINT2", + .startup = startup_sysint2_irq, + .shutdown = shutdown_sysint2_irq, + .enable = enable_sysint2_irq, + .disable = disable_sysint2_irq, + .ack = ack_sysint2_irq, + .end = end_sysint2_irq, +}; + +/*=======================================================================*/ + +static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) +{ + irq_desc_t *desc = irq_desc + irq; + uint16_t intassign0, intassign1; + unsigned int pin; + + pin = SYSINT1_IRQ_TO_PIN(irq); + + spin_lock_irq(&desc->lock); + + intassign0 = read_icu1(INTASSIGN0); + intassign1 = read_icu1(INTASSIGN1); + + switch (pin) { + case 0: + intassign0 &= ~INTASSIGN_MASK; + intassign0 |= (uint16_t)assign; + break; + case 1: + intassign0 &= ~(INTASSIGN_MASK << 3); + intassign0 |= (uint16_t)assign << 3; + break; + case 2: + intassign0 &= ~(INTASSIGN_MASK << 6); + intassign0 |= (uint16_t)assign << 6; + break; + case 3: + intassign0 &= ~(INTASSIGN_MASK << 9); + intassign0 |= (uint16_t)assign << 9; + break; + case 8: + intassign0 &= ~(INTASSIGN_MASK << 12); + intassign0 |= (uint16_t)assign << 12; + break; + case 9: + intassign1 &= ~INTASSIGN_MASK; + intassign1 |= (uint16_t)assign; + break; + case 11: + intassign1 &= ~(INTASSIGN_MASK << 6); + intassign1 |= (uint16_t)assign << 6; + break; + case 12: + intassign1 &= ~(INTASSIGN_MASK << 9); + intassign1 |= (uint16_t)assign << 9; + break; + default: + return -EINVAL; + } + + sysint1_assign[pin] = assign; + write_icu1(intassign0, INTASSIGN0); + write_icu1(intassign1, INTASSIGN1); + + spin_unlock_irq(&desc->lock); + + return 0; +} + +static inline int set_sysint2_assign(unsigned int irq, unsigned char assign) +{ + irq_desc_t *desc = irq_desc + irq; + uint16_t intassign2, intassign3; + unsigned int pin; + + pin = SYSINT2_IRQ_TO_PIN(irq); + + spin_lock_irq(&desc->lock); + + intassign2 = read_icu1(INTASSIGN2); + intassign3 = read_icu1(INTASSIGN3); + + switch (pin) { + case 0: + intassign2 &= ~INTASSIGN_MASK; + intassign2 |= (uint16_t)assign; + break; + case 1: + intassign2 &= ~(INTASSIGN_MASK << 3); + intassign2 |= (uint16_t)assign << 3; + break; + case 3: + intassign2 &= ~(INTASSIGN_MASK << 6); + intassign2 |= (uint16_t)assign << 6; + break; + case 4: + intassign2 &= ~(INTASSIGN_MASK << 9); + intassign2 |= (uint16_t)assign << 9; + break; + case 5: + intassign2 &= ~(INTASSIGN_MASK << 12); + intassign2 |= (uint16_t)assign << 12; + break; + case 6: + intassign3 &= ~INTASSIGN_MASK; + intassign3 |= (uint16_t)assign; + break; + case 7: + intassign3 &= ~(INTASSIGN_MASK << 3); + intassign3 |= (uint16_t)assign << 3; + break; + case 8: + intassign3 &= ~(INTASSIGN_MASK << 6); + intassign3 |= (uint16_t)assign << 6; + break; + case 9: + intassign3 &= ~(INTASSIGN_MASK << 9); + intassign3 |= (uint16_t)assign << 9; + break; + case 10: + intassign3 &= ~(INTASSIGN_MASK << 12); + intassign3 |= (uint16_t)assign << 12; + break; + default: + return -EINVAL; + } + + sysint2_assign[pin] = assign; + write_icu1(intassign2, INTASSIGN2); + write_icu1(intassign3, INTASSIGN3); + + spin_unlock_irq(&desc->lock); + + return 0; +} + +int vr41xx_set_intassign(unsigned int irq, unsigned char intassign) +{ + int retval = -EINVAL; + + if (current_cpu_data.cputype != CPU_VR4133) + return -EINVAL; + + if (intassign > INTASSIGN_MAX) + return -EINVAL; + + if (irq >= SYSINT1_IRQ_BASE && irq <= SYSINT1_IRQ_LAST) + retval = set_sysint1_assign(irq, intassign); + else if (irq >= SYSINT2_IRQ_BASE && irq <= SYSINT2_IRQ_LAST) + retval = set_sysint2_assign(irq, intassign); + + return retval; +} + +EXPORT_SYMBOL(vr41xx_set_intassign); + +/*=======================================================================*/ + +asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs) +{ + uint16_t pend1, pend2; + uint16_t mask1, mask2; + int i; + + pend1 = read_icu1(SYSINT1REG); + mask1 = read_icu1(MSYSINT1REG); + + pend2 = read_icu2(SYSINT2REG); + mask2 = read_icu2(MSYSINT2REG); + + mask1 &= pend1; + mask2 &= pend2; + + if (mask1) { + for (i = 0; i < 16; i++) { + if (intnum == sysint1_assign[i] && + (mask1 & ((uint16_t)1 << i))) { + if (i == 8) + giuint_irq_dispatch(regs); + else + do_IRQ(SYSINT1_IRQ(i), regs); + return; + } + } + } + + if (mask2) { + for (i = 0; i < 16; i++) { + if (intnum == sysint2_assign[i] && + (mask2 & ((uint16_t)1 << i))) { + do_IRQ(SYSINT2_IRQ(i), regs); + return; + } + } + } + + printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2); + + atomic_inc(&irq_err_count); +} + +/*=======================================================================*/ + +static int __init vr41xx_icu_init(void) +{ + switch (current_cpu_data.cputype) { + case CPU_VR4111: + case CPU_VR4121: + icu1_base = SYSINT1REG_TYPE1; + icu2_base = SYSINT2REG_TYPE1; + break; + case CPU_VR4122: + case CPU_VR4131: + case CPU_VR4133: + icu1_base = SYSINT1REG_TYPE2; + icu2_base = SYSINT2REG_TYPE2; + break; + default: + printk(KERN_ERR "ICU: Unexpected CPU of NEC VR4100 series\n"); + return -EINVAL; + } + + write_icu1(0, MSYSINT1REG); + write_icu1(0xffff, MGIUINTLREG); + + write_icu2(0, MSYSINT2REG); + write_icu2(0xffff, MGIUINTHREG); + + return 0; +} + +early_initcall(vr41xx_icu_init); + +/*=======================================================================*/ + +static inline void init_vr41xx_icu_irq(void) +{ + int i; + + for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++) + irq_desc[i].handler = &sysint1_irq_type; + + for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++) + irq_desc[i].handler = &sysint2_irq_type; + + setup_irq(INT0_CASCADE_IRQ, &icu_cascade); + setup_irq(INT1_CASCADE_IRQ, &icu_cascade); + setup_irq(INT2_CASCADE_IRQ, &icu_cascade); + setup_irq(INT3_CASCADE_IRQ, &icu_cascade); + setup_irq(INT4_CASCADE_IRQ, &icu_cascade); +} + +void __init arch_init_irq(void) +{ + mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); + init_vr41xx_icu_irq(); + init_vr41xx_giuint_irq(); + + set_except_vector(0, vr41xx_handle_interrupt); +} diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c new file mode 100644 index 000000000000..e03be896cbc4 --- /dev/null +++ b/arch/mips/vr41xx/common/init.c @@ -0,0 +1,85 @@ +/* + * init.c, Common initialization routines for NEC VR4100 series. + * + * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> +#include <asm/time.h> +#include <asm/vr41xx/vr41xx.h> + +#define IO_MEM_RESOURCE_START 0UL +#define IO_MEM_RESOURCE_END 0x1fffffffUL + +static void __init iomem_resource_init(void) +{ + iomem_resource.start = IO_MEM_RESOURCE_START; + iomem_resource.end = IO_MEM_RESOURCE_END; +} + +static void __init setup_timer_frequency(void) +{ + unsigned long tclock; + + tclock = vr41xx_get_tclock_frequency(); + if (current_cpu_data.processor_id == PRID_VR4131_REV2_0 || + current_cpu_data.processor_id == PRID_VR4131_REV2_1) + mips_hpt_frequency = tclock / 2; + else + mips_hpt_frequency = tclock / 4; +} + +static void __init setup_timer_irq(struct irqaction *irq) +{ + setup_irq(TIMER_IRQ, irq); +} + +static void __init timer_init(void) +{ + board_time_init = setup_timer_frequency; + board_timer_setup = setup_timer_irq; +} + +void __init prom_init(void) +{ + int argc, i; + char **argv; + + argc = fw_arg0; + argv = (char **)fw_arg1; + + for (i = 1; i < argc; i++) { + strcat(arcs_cmdline, argv[i]); + if (i < (argc - 1)) + strcat(arcs_cmdline, " "); + } + + vr41xx_calculate_clock_frequency(); + + timer_init(); + + iomem_resource_init(); +} + +unsigned long __init prom_free_prom_memory (void) +{ + return 0UL; +} diff --git a/arch/mips/vr41xx/common/int-handler.S b/arch/mips/vr41xx/common/int-handler.S new file mode 100644 index 000000000000..38ff89b505f2 --- /dev/null +++ b/arch/mips/vr41xx/common/int-handler.S @@ -0,0 +1,114 @@ +/* + * FILE NAME + * arch/mips/vr41xx/common/int-handler.S + * + * BRIEF MODULE DESCRIPTION + * Interrupt dispatcher for the NEC VR4100 series. + * + * Author: Yoichi Yuasa + * yyuasa@mvista.com or source@mvista.com + * + * Copyright 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * Changes: + * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> + * - New creation, NEC VR4100 series are supported. + * + * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * - Coped with INTASSIGN of NEC VR4133. + */ +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/stackframe.h> + + .text + .set noreorder + + .align 5 + NESTED(vr41xx_handle_interrupt, PT_SIZE, ra) + .set noat + SAVE_ALL + CLI + .set at + .set noreorder + + /* + * Get the pending interrupts + */ + mfc0 t0, CP0_CAUSE + mfc0 t1, CP0_STATUS + andi t0, 0xff00 + and t0, t0, t1 + + andi t1, t0, CAUSEF_IP7 # MIPS timer interrupt + bnez t1, handle_irq + li a0, 7 + + andi t1, t0, 0x7800 # check for Int1-4 + beqz t1, 1f + + andi t1, t0, CAUSEF_IP3 # check for Int1 + bnez t1, handle_int + li a0, 1 + + andi t1, t0, CAUSEF_IP4 # check for Int2 + bnez t1, handle_int + li a0, 2 + + andi t1, t0, CAUSEF_IP5 # check for Int3 + bnez t1, handle_int + li a0, 3 + + andi t1, t0, CAUSEF_IP6 # check for Int4 + bnez t1, handle_int + li a0, 4 + +1: + andi t1, t0, CAUSEF_IP2 # check for Int0 + bnez t1, handle_int + li a0, 0 + + andi t1, t0, CAUSEF_IP0 # check for IP0 + bnez t1, handle_irq + li a0, 0 + + andi t1, t0, CAUSEF_IP1 # check for IP1 + bnez t1, handle_irq + li a0, 1 + + j spurious_interrupt + nop + +handle_int: + jal irq_dispatch + move a1, sp + j ret_from_irq + nop + +handle_irq: + jal do_IRQ + move a1, sp + j ret_from_irq + END(vr41xx_handle_interrupt) diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c new file mode 100644 index 000000000000..c5f1043de938 --- /dev/null +++ b/arch/mips/vr41xx/common/pmu.c @@ -0,0 +1,81 @@ +/* + * pmu.c, Power Management Unit routines for NEC VR4100 series. + * + * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/smp.h> +#include <linux/types.h> + +#include <asm/cpu.h> +#include <asm/io.h> +#include <asm/reboot.h> +#include <asm/system.h> + +#define PMUCNT2REG KSEG1ADDR(0x0f0000c6) + #define SOFTRST 0x0010 + +static inline void software_reset(void) +{ + uint16_t val; + + switch (current_cpu_data.cputype) { + case CPU_VR4122: + case CPU_VR4131: + case CPU_VR4133: + val = readw(PMUCNT2REG); + val |= SOFTRST; + writew(val, PMUCNT2REG); + break; + default: + break; + } +} + +static void vr41xx_restart(char *command) +{ + local_irq_disable(); + software_reset(); + printk(KERN_NOTICE "\nYou can reset your system\n"); + while (1) ; +} + +static void vr41xx_halt(void) +{ + local_irq_disable(); + printk(KERN_NOTICE "\nYou can turn off the power supply\n"); + while (1) ; +} + +static void vr41xx_power_off(void) +{ + local_irq_disable(); + printk(KERN_NOTICE "\nYou can turn off the power supply\n"); + while (1) ; +} + +static int __init vr41xx_pmu_init(void) +{ + _machine_restart = vr41xx_restart; + _machine_halt = vr41xx_halt; + _machine_power_off = vr41xx_power_off; + + return 0; +} + +early_initcall(vr41xx_pmu_init); diff --git a/arch/mips/vr41xx/common/vrc4173.c b/arch/mips/vr41xx/common/vrc4173.c new file mode 100644 index 000000000000..5475dd72e264 --- /dev/null +++ b/arch/mips/vr41xx/common/vrc4173.c @@ -0,0 +1,581 @@ +/* + * vrc4173.c, NEC VRC4173 base driver for NEC VR4122/VR4131. + * + * Copyright (C) 2001-2003 MontaVista Software Inc. + * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> + * Copyright (C) 2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +#include <asm/vr41xx/vr41xx.h> +#include <asm/vr41xx/vrc4173.h> + +MODULE_DESCRIPTION("NEC VRC4173 base driver for NEC VR4122/4131"); +MODULE_AUTHOR("Yoichi Yuasa <yyuasa@mvista.com>"); +MODULE_LICENSE("GPL"); + +#define VRC4173_CMUCLKMSK 0x040 + #define MSKPIU 0x0001 + #define MSKKIU 0x0002 + #define MSKAIU 0x0004 + #define MSKPS2CH1 0x0008 + #define MSKPS2CH2 0x0010 + #define MSKUSB 0x0020 + #define MSKCARD1 0x0040 + #define MSKCARD2 0x0080 + #define MSKAC97 0x0100 + #define MSK48MUSB 0x0400 + #define MSK48MPIN 0x0800 + #define MSK48MOSC 0x1000 +#define VRC4173_CMUSRST 0x042 + #define USBRST 0x0001 + #define CARD1RST 0x0002 + #define CARD2RST 0x0004 + #define AC97RST 0x0008 + +#define VRC4173_SYSINT1REG 0x060 +#define VRC4173_MSYSINT1REG 0x06c +#define VRC4173_MPIUINTREG 0x06e +#define VRC4173_MAIUINTREG 0x070 +#define VRC4173_MKIUINTREG 0x072 + +#define VRC4173_SELECTREG 0x09e + #define SEL3 0x0008 + #define SEL2 0x0004 + #define SEL1 0x0002 + #define SEL0 0x0001 + +static struct pci_device_id vrc4173_id_table[] __devinitdata = { + { .vendor = PCI_VENDOR_ID_NEC, + .device = PCI_DEVICE_ID_NEC_VRC4173, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, + { .vendor = 0, }, +}; + +unsigned long vrc4173_io_offset = 0; + +EXPORT_SYMBOL(vrc4173_io_offset); + +static int vrc4173_initialized; +static uint16_t vrc4173_cmuclkmsk; +static uint16_t vrc4173_selectreg; +static spinlock_t vrc4173_cmu_lock; +static spinlock_t vrc4173_giu_lock; + +static inline void set_cmusrst(uint16_t val) +{ + uint16_t cmusrst; + + cmusrst = vrc4173_inw(VRC4173_CMUSRST); + cmusrst |= val; + vrc4173_outw(cmusrst, VRC4173_CMUSRST); +} + +static inline void clear_cmusrst(uint16_t val) +{ + uint16_t cmusrst; + + cmusrst = vrc4173_inw(VRC4173_CMUSRST); + cmusrst &= ~val; + vrc4173_outw(cmusrst, VRC4173_CMUSRST); +} + +void vrc4173_supply_clock(vrc4173_clock_t clock) +{ + if (vrc4173_initialized) { + spin_lock_irq(&vrc4173_cmu_lock); + + switch (clock) { + case VRC4173_PIU_CLOCK: + vrc4173_cmuclkmsk |= MSKPIU; + break; + case VRC4173_KIU_CLOCK: + vrc4173_cmuclkmsk |= MSKKIU; + break; + case VRC4173_AIU_CLOCK: + vrc4173_cmuclkmsk |= MSKAIU; + break; + case VRC4173_PS2_CH1_CLOCK: + vrc4173_cmuclkmsk |= MSKPS2CH1; + break; + case VRC4173_PS2_CH2_CLOCK: + vrc4173_cmuclkmsk |= MSKPS2CH2; + break; + case VRC4173_USBU_PCI_CLOCK: + set_cmusrst(USBRST); + vrc4173_cmuclkmsk |= MSKUSB; + break; + case VRC4173_CARDU1_PCI_CLOCK: + set_cmusrst(CARD1RST); + vrc4173_cmuclkmsk |= MSKCARD1; + break; + case VRC4173_CARDU2_PCI_CLOCK: + set_cmusrst(CARD2RST); + vrc4173_cmuclkmsk |= MSKCARD2; + break; + case VRC4173_AC97U_PCI_CLOCK: + set_cmusrst(AC97RST); + vrc4173_cmuclkmsk |= MSKAC97; + break; + case VRC4173_USBU_48MHz_CLOCK: + set_cmusrst(USBRST); + vrc4173_cmuclkmsk |= MSK48MUSB; + break; + case VRC4173_EXT_48MHz_CLOCK: + if (vrc4173_cmuclkmsk & MSK48MOSC) + vrc4173_cmuclkmsk |= MSK48MPIN; + else + printk(KERN_WARNING + "vrc4173_supply_clock: " + "Please supply VRC4173_48MHz_CLOCK first " + "rather than VRC4173_EXT_48MHz_CLOCK.\n"); + break; + case VRC4173_48MHz_CLOCK: + vrc4173_cmuclkmsk |= MSK48MOSC; + break; + default: + printk(KERN_WARNING + "vrc4173_supply_clock: Invalid CLOCK value %u\n", clock); + break; + } + + vrc4173_outw(vrc4173_cmuclkmsk, VRC4173_CMUCLKMSK); + + switch (clock) { + case VRC4173_USBU_PCI_CLOCK: + case VRC4173_USBU_48MHz_CLOCK: + clear_cmusrst(USBRST); + break; + case VRC4173_CARDU1_PCI_CLOCK: + clear_cmusrst(CARD1RST); + break; + case VRC4173_CARDU2_PCI_CLOCK: + clear_cmusrst(CARD2RST); + break; + case VRC4173_AC97U_PCI_CLOCK: + clear_cmusrst(AC97RST); + break; + default: + break; + } + + spin_unlock_irq(&vrc4173_cmu_lock); + } +} + +EXPORT_SYMBOL(vrc4173_supply_clock); + +void vrc4173_mask_clock(vrc4173_clock_t clock) +{ + if (vrc4173_initialized) { + spin_lock_irq(&vrc4173_cmu_lock); + + switch (clock) { + case VRC4173_PIU_CLOCK: + vrc4173_cmuclkmsk &= ~MSKPIU; + break; + case VRC4173_KIU_CLOCK: + vrc4173_cmuclkmsk &= ~MSKKIU; + break; + case VRC4173_AIU_CLOCK: + vrc4173_cmuclkmsk &= ~MSKAIU; + break; + case VRC4173_PS2_CH1_CLOCK: + vrc4173_cmuclkmsk &= ~MSKPS2CH1; + break; + case VRC4173_PS2_CH2_CLOCK: + vrc4173_cmuclkmsk &= ~MSKPS2CH2; + break; + case VRC4173_USBU_PCI_CLOCK: + set_cmusrst(USBRST); + vrc4173_cmuclkmsk &= ~MSKUSB; + break; + case VRC4173_CARDU1_PCI_CLOCK: + set_cmusrst(CARD1RST); + vrc4173_cmuclkmsk &= ~MSKCARD1; + break; + case VRC4173_CARDU2_PCI_CLOCK: + set_cmusrst(CARD2RST); + vrc4173_cmuclkmsk &= ~MSKCARD2; + break; + case VRC4173_AC97U_PCI_CLOCK: + set_cmusrst(AC97RST); + vrc4173_cmuclkmsk &= ~MSKAC97; + break; + case VRC4173_USBU_48MHz_CLOCK: + set_cmusrst(USBRST); + vrc4173_cmuclkmsk &= ~MSK48MUSB; + break; + case VRC4173_EXT_48MHz_CLOCK: + vrc4173_cmuclkmsk &= ~MSK48MPIN; + break; + case VRC4173_48MHz_CLOCK: + vrc4173_cmuclkmsk &= ~MSK48MOSC; + break; + default: + printk(KERN_WARNING "vrc4173_mask_clock: Invalid CLOCK value %u\n", clock); + break; + } + + vrc4173_outw(vrc4173_cmuclkmsk, VRC4173_CMUCLKMSK); + + switch (clock) { + case VRC4173_USBU_PCI_CLOCK: + case VRC4173_USBU_48MHz_CLOCK: + clear_cmusrst(USBRST); + break; + case VRC4173_CARDU1_PCI_CLOCK: + clear_cmusrst(CARD1RST); + break; + case VRC4173_CARDU2_PCI_CLOCK: + clear_cmusrst(CARD2RST); + break; + case VRC4173_AC97U_PCI_CLOCK: + clear_cmusrst(AC97RST); + break; + default: + break; + } + + spin_unlock_irq(&vrc4173_cmu_lock); + } +} + +EXPORT_SYMBOL(vrc4173_mask_clock); + +static inline void vrc4173_cmu_init(void) +{ + vrc4173_cmuclkmsk = vrc4173_inw(VRC4173_CMUCLKMSK); + + spin_lock_init(&vrc4173_cmu_lock); +} + +void vrc4173_select_function(vrc4173_function_t function) +{ + if (vrc4173_initialized) { + spin_lock_irq(&vrc4173_giu_lock); + + switch(function) { + case PS2_CHANNEL1: + vrc4173_selectreg |= SEL2; + break; + case PS2_CHANNEL2: + vrc4173_selectreg |= SEL1; + break; + case TOUCHPANEL: + vrc4173_selectreg &= SEL2 | SEL1 | SEL0; + break; + case KEYBOARD_8SCANLINES: + vrc4173_selectreg &= SEL3 | SEL2 | SEL1; + break; + case KEYBOARD_10SCANLINES: + vrc4173_selectreg &= SEL3 | SEL2; + break; + case KEYBOARD_12SCANLINES: + vrc4173_selectreg &= SEL3; + break; + case GPIO_0_15PINS: + vrc4173_selectreg |= SEL0; + break; + case GPIO_16_20PINS: + vrc4173_selectreg |= SEL3; + break; + } + + vrc4173_outw(vrc4173_selectreg, VRC4173_SELECTREG); + + spin_unlock_irq(&vrc4173_giu_lock); + } +} + +EXPORT_SYMBOL(vrc4173_select_function); + +static inline void vrc4173_giu_init(void) +{ + vrc4173_selectreg = vrc4173_inw(VRC4173_SELECTREG); + + spin_lock_init(&vrc4173_giu_lock); +} + +void vrc4173_enable_piuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_PIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MPIUINTREG); + val |= mask; + vrc4173_outw(val, VRC4173_MPIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_enable_piuint); + +void vrc4173_disable_piuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_PIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MPIUINTREG); + val &= ~mask; + vrc4173_outw(val, VRC4173_MPIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_disable_piuint); + +void vrc4173_enable_aiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_AIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MAIUINTREG); + val |= mask; + vrc4173_outw(val, VRC4173_MAIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_enable_aiuint); + +void vrc4173_disable_aiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_AIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MAIUINTREG); + val &= ~mask; + vrc4173_outw(val, VRC4173_MAIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_disable_aiuint); + +void vrc4173_enable_kiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_KIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MKIUINTREG); + val |= mask; + vrc4173_outw(val, VRC4173_MKIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_enable_kiuint); + +void vrc4173_disable_kiuint(uint16_t mask) +{ + irq_desc_t *desc = irq_desc + VRC4173_KIU_IRQ; + unsigned long flags; + uint16_t val; + + spin_lock_irqsave(&desc->lock, flags); + val = vrc4173_inw(VRC4173_MKIUINTREG); + val &= ~mask; + vrc4173_outw(val, VRC4173_MKIUINTREG); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vrc4173_disable_kiuint); + +static void enable_vrc4173_irq(unsigned int irq) +{ + uint16_t val; + + val = vrc4173_inw(VRC4173_MSYSINT1REG); + val |= (uint16_t)1 << (irq - VRC4173_IRQ_BASE); + vrc4173_outw(val, VRC4173_MSYSINT1REG); +} + +static void disable_vrc4173_irq(unsigned int irq) +{ + uint16_t val; + + val = vrc4173_inw(VRC4173_MSYSINT1REG); + val &= ~((uint16_t)1 << (irq - VRC4173_IRQ_BASE)); + vrc4173_outw(val, VRC4173_MSYSINT1REG); +} + +static unsigned int startup_vrc4173_irq(unsigned int irq) +{ + enable_vrc4173_irq(irq); + return 0; /* never anything pending */ +} + +#define shutdown_vrc4173_irq disable_vrc4173_irq +#define ack_vrc4173_irq disable_vrc4173_irq + +static void end_vrc4173_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + enable_vrc4173_irq(irq); +} + +static struct hw_interrupt_type vrc4173_irq_type = { + .typename = "VRC4173", + .startup = startup_vrc4173_irq, + .shutdown = shutdown_vrc4173_irq, + .enable = enable_vrc4173_irq, + .disable = disable_vrc4173_irq, + .ack = ack_vrc4173_irq, + .end = end_vrc4173_irq, +}; + +static int vrc4173_get_irq_number(int irq) +{ + uint16_t status, mask; + int i; + + status = vrc4173_inw(VRC4173_SYSINT1REG); + mask = vrc4173_inw(VRC4173_MSYSINT1REG); + + status &= mask; + if (status) { + for (i = 0; i < 16; i++) + if (status & (0x0001 << i)) + return VRC4173_IRQ(i); + } + + return -EINVAL; +} + +static inline int vrc4173_icu_init(int cascade_irq) +{ + int i; + + if (cascade_irq < GIU_IRQ(0) || cascade_irq > GIU_IRQ(15)) + return -EINVAL; + + vrc4173_outw(0, VRC4173_MSYSINT1REG); + + vr41xx_set_irq_trigger(GIU_IRQ_TO_PIN(cascade_irq), TRIGGER_LEVEL, SIGNAL_THROUGH); + vr41xx_set_irq_level(GIU_IRQ_TO_PIN(cascade_irq), LEVEL_LOW); + + for (i = VRC4173_IRQ_BASE; i <= VRC4173_IRQ_LAST; i++) + irq_desc[i].handler = &vrc4173_irq_type; + + return 0; +} + +static int __devinit vrc4173_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + unsigned long start, flags; + int err; + + err = pci_enable_device(dev); + if (err < 0) { + printk(KERN_ERR "vrc4173: Failed to enable PCI device, aborting\n"); + return err; + } + + pci_set_master(dev); + + start = pci_resource_start(dev, 0); + if (start == 0) { + printk(KERN_ERR "vrc4173:No such PCI I/O resource, aborting\n"); + return -ENXIO; + } + + flags = pci_resource_flags(dev, 0); + if ((flags & IORESOURCE_IO) == 0) { + printk(KERN_ERR "vrc4173: No such PCI I/O resource, aborting\n"); + return -ENXIO; + } + + err = pci_request_regions(dev, "NEC VRC4173"); + if (err < 0) { + printk(KERN_ERR "vrc4173: PCI resources are busy, aborting\n"); + return err; + } + + set_vrc4173_io_offset(start); + + vrc4173_cmu_init(); + vrc4173_giu_init(); + + err = vrc4173_icu_init(dev->irq); + if (err < 0) { + printk(KERN_ERR "vrc4173: Invalid IRQ %d, aborting\n", dev->irq); + return err; + } + + err = vr41xx_cascade_irq(dev->irq, vrc4173_get_irq_number); + if (err < 0) { + printk(KERN_ERR "vrc4173: IRQ resource %d is busy, aborting\n", dev->irq); + return err; + } + + printk(KERN_INFO + "NEC VRC4173 at 0x%#08lx, IRQ is cascaded to %d\n", start, dev->irq); + + return 0; +} + +static void vrc4173_remove(struct pci_dev *dev) +{ + free_irq(dev->irq, NULL); + + pci_release_regions(dev); +} + +static struct pci_driver vrc4173_driver = { + .name = "NEC VRC4173", + .probe = vrc4173_probe, + .remove = vrc4173_remove, + .id_table = vrc4173_id_table, +}; + +static int __devinit vrc4173_init(void) +{ + int err; + + err = pci_module_init(&vrc4173_driver); + if (err < 0) + return err; + + vrc4173_initialized = 1; + + return 0; +} + +static void __devexit vrc4173_exit(void) +{ + vrc4173_initialized = 0; + + pci_unregister_driver(&vrc4173_driver); +} + +module_init(vrc4173_init); +module_exit(vrc4173_exit); diff --git a/arch/mips/vr41xx/ibm-workpad/Makefile b/arch/mips/vr41xx/ibm-workpad/Makefile new file mode 100644 index 000000000000..5ffaff0f0f89 --- /dev/null +++ b/arch/mips/vr41xx/ibm-workpad/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the IBM WorkPad z50 specific parts of the kernel +# + +obj-y += setup.o diff --git a/arch/mips/vr41xx/ibm-workpad/setup.c b/arch/mips/vr41xx/ibm-workpad/setup.c new file mode 100644 index 000000000000..cff44602d3d4 --- /dev/null +++ b/arch/mips/vr41xx/ibm-workpad/setup.c @@ -0,0 +1,40 @@ +/* + * setup.c, Setup for the IBM WorkPad z50. + * + * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/init.h> +#include <linux/ioport.h> + +#include <asm/io.h> +#include <asm/vr41xx/workpad.h> + +const char *get_system_type(void) +{ + return "IBM WorkPad z50"; +} + +static int __init ibm_workpad_setup(void) +{ + set_io_port_base(IO_PORT_BASE); + ioport_resource.start = IO_PORT_RESOURCE_START; + ioport_resource.end = IO_PORT_RESOURCE_END; + + return 0; +} + +arch_initcall(ibm_workpad_setup); diff --git a/arch/mips/vr41xx/nec-cmbvr4133/Makefile b/arch/mips/vr41xx/nec-cmbvr4133/Makefile new file mode 100644 index 000000000000..5835cae54aca --- /dev/null +++ b/arch/mips/vr41xx/nec-cmbvr4133/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the NEC-CMBVR4133 +# + +obj-y := init.o setup.o + +obj-$(CONFIG_PCI) += m1535plus.o +obj-$(CONFIG_ROCKHOPPER) += irq.o diff --git a/arch/mips/vr41xx/nec-cmbvr4133/init.c b/arch/mips/vr41xx/nec-cmbvr4133/init.c new file mode 100644 index 000000000000..87f06b3f5a9c --- /dev/null +++ b/arch/mips/vr41xx/nec-cmbvr4133/init.c @@ -0,0 +1,78 @@ +/* + * arch/mips/vr41xx/nec-cmbvr4133/init.c + * + * PROM library initialisation code for NEC CMB-VR4133 board. + * + * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> and + * Jun Sun <jsun@mvista.com, or source@mvista.com> and + * Alex Sapkov <asapkov@ru.mvista.com> + * + * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * Support for NEC-CMBVR4133 in 2.6 + * Manish Lachwani (mlachwani@mvista.com) + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> + +#ifdef CONFIG_ROCKHOPPER +#include <asm/io.h> +#include <linux/pci.h> + +#define PCICONFDREG 0xaf000c14 +#define PCICONFAREG 0xaf000c18 +#endif + +const char *get_system_type(void) +{ + return "NEC CMB-VR4133"; +} + +#ifdef CONFIG_ROCKHOPPER +void disable_pcnet(void) +{ + u32 data; + + /* + * Workaround for the bug in PMON on VR4133. PMON leaves + * AMD PCNet controller (on Rockhopper) initialized and running in + * bus master mode. We have do disable it before doing any + * further initialization. Or we get problems with PCI bus 2 + * and random lockups and crashes. + */ + + writel((2 << 16) | + (PCI_DEVFN(1,0) << 8) | + (0 & 0xfc) | + 1UL, + PCICONFAREG); + + data = readl(PCICONFDREG); + + writel((2 << 16) | + (PCI_DEVFN(1,0) << 8) | + (4 & 0xfc) | + 1UL, + PCICONFAREG); + + data = readl(PCICONFDREG); + + writel((2 << 16) | + (PCI_DEVFN(1,0) << 8) | + (4 & 0xfc) | + 1UL, + PCICONFAREG); + + data &= ~4; + + writel(data, PCICONFDREG); +} +#endif + diff --git a/arch/mips/vr41xx/nec-cmbvr4133/irq.c b/arch/mips/vr41xx/nec-cmbvr4133/irq.c new file mode 100644 index 000000000000..31db6b61a39e --- /dev/null +++ b/arch/mips/vr41xx/nec-cmbvr4133/irq.c @@ -0,0 +1,114 @@ +/* + * arch/mips/vr41xx/nec-cmbvr4133/irq.c + * + * Interrupt routines for the NEC CMB-VR4133 board. + * + * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> and + * Alex Sapkov <asapkov@ru.mvista.com> + * + * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * Support for NEC-CMBVR4133 in 2.6 + * Manish Lachwani (mlachwani@mvista.com) + */ +#include <linux/bitops.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> + +#include <asm/io.h> +#include <asm/vr41xx/cmbvr4133.h> + +extern void enable_8259A_irq(unsigned int irq); +extern void disable_8259A_irq(unsigned int irq); +extern void mask_and_ack_8259A(unsigned int irq); +extern void init_8259A(int hoge); + +extern int vr4133_rockhopper; + +static unsigned int startup_i8259_irq(unsigned int irq) +{ + enable_8259A_irq(irq - I8259_IRQ_BASE); + return 0; +} + +static void shutdown_i8259_irq(unsigned int irq) +{ + disable_8259A_irq(irq - I8259_IRQ_BASE); +} + +static void enable_i8259_irq(unsigned int irq) +{ + enable_8259A_irq(irq - I8259_IRQ_BASE); +} + +static void disable_i8259_irq(unsigned int irq) +{ + disable_8259A_irq(irq - I8259_IRQ_BASE); +} + +static void ack_i8259_irq(unsigned int irq) +{ + mask_and_ack_8259A(irq - I8259_IRQ_BASE); +} + +static void end_i8259_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_8259A_irq(irq - I8259_IRQ_BASE); +} + +static struct hw_interrupt_type i8259_irq_type = { + .typename = "XT-PIC", + .startup = startup_i8259_irq, + .shutdown = shutdown_i8259_irq, + .enable = enable_i8259_irq, + .disable = disable_i8259_irq, + .ack = ack_i8259_irq, + .end = end_i8259_irq, +}; + +static int i8259_get_irq_number(int irq) +{ + unsigned long isr; + + isr = inb(0x20); + irq = ffz(~isr); + if (irq == 2) { + isr = inb(0xa0); + irq = 8 + ffz(~isr); + } + + if (irq < 0 || irq > 15) + return -EINVAL; + + return I8259_IRQ_BASE + irq; +} + +static struct irqaction i8259_slave_cascade = { + .handler = &no_action, + .name = "cascade", +}; + +void __init rockhopper_init_irq(void) +{ + int i; + + if(!vr4133_rockhopper) { + printk(KERN_ERR "Not a Rockhopper Board \n"); + return; + } + + for (i = I8259_IRQ_BASE; i <= I8259_IRQ_LAST; i++) + irq_desc[i].handler = &i8259_irq_type; + + setup_irq(I8259_SLAVE_IRQ, &i8259_slave_cascade); + + vr41xx_set_irq_trigger(CMBVR41XX_INTC_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH); + vr41xx_set_irq_level(CMBVR41XX_INTC_PIN, LEVEL_HIGH); + vr41xx_cascade_irq(CMBVR41XX_INTC_IRQ, i8259_get_irq_number); +} diff --git a/arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c b/arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c new file mode 100644 index 000000000000..1f6b24ef8695 --- /dev/null +++ b/arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c @@ -0,0 +1,250 @@ +/* + * arch/mips/vr41xx/nec-cmbvr4133/m1535plus.c + * + * Initialize for ALi M1535+(included M5229 and M5237). + * + * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> and + * Alex Sapkov <asapkov@ru.mvista.com> + * + * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * Support for NEC-CMBVR4133 in 2.6 + * Author: Manish Lachwani (mlachwani@mvista.com) + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/serial.h> + +#include <asm/vr41xx/cmbvr4133.h> +#include <linux/pci.h> +#include <asm/io.h> + +#define CONFIG_PORT(port) ((port) ? 0x3f0 : 0x370) +#define DATA_PORT(port) ((port) ? 0x3f1 : 0x371) +#define INDEX_PORT(port) CONFIG_PORT(port) + +#define ENTER_CONFIG_MODE(port) \ + do { \ + outb_p(0x51, CONFIG_PORT(port)); \ + outb_p(0x23, CONFIG_PORT(port)); \ + } while(0) + +#define SELECT_LOGICAL_DEVICE(port, dev_no) \ + do { \ + outb_p(0x07, INDEX_PORT(port)); \ + outb_p((dev_no), DATA_PORT(port)); \ + } while(0) + +#define WRITE_CONFIG_DATA(port,index,data) \ + do { \ + outb_p((index), INDEX_PORT(port)); \ + outb_p((data), DATA_PORT(port)); \ + } while(0) + +#define EXIT_CONFIG_MODE(port) outb(0xbb, CONFIG_PORT(port)) + +#define PCI_CONFIG_ADDR KSEG1ADDR(0x0f000c18) +#define PCI_CONFIG_DATA KSEG1ADDR(0x0f000c14) + +#ifdef CONFIG_BLK_DEV_FD + +void __devinit ali_m1535plus_fdc_init(int port) +{ + ENTER_CONFIG_MODE(port); + SELECT_LOGICAL_DEVICE(port, 0); /* FDC */ + WRITE_CONFIG_DATA(port, 0x30, 0x01); /* FDC: enable */ + WRITE_CONFIG_DATA(port, 0x60, 0x03); /* I/O port base: 0x3f0 */ + WRITE_CONFIG_DATA(port, 0x61, 0xf0); + WRITE_CONFIG_DATA(port, 0x70, 0x06); /* IRQ: 6 */ + WRITE_CONFIG_DATA(port, 0x74, 0x02); /* DMA: channel 2 */ + WRITE_CONFIG_DATA(port, 0xf0, 0x08); + WRITE_CONFIG_DATA(port, 0xf1, 0x00); + WRITE_CONFIG_DATA(port, 0xf2, 0xff); + WRITE_CONFIG_DATA(port, 0xf4, 0x00); + EXIT_CONFIG_MODE(port); +} + +#endif + +void __devinit ali_m1535plus_parport_init(int port) +{ + ENTER_CONFIG_MODE(port); + SELECT_LOGICAL_DEVICE(port, 3); /* Parallel Port */ + WRITE_CONFIG_DATA(port, 0x30, 0x01); + WRITE_CONFIG_DATA(port, 0x60, 0x03); /* I/O port base: 0x378 */ + WRITE_CONFIG_DATA(port, 0x61, 0x78); + WRITE_CONFIG_DATA(port, 0x70, 0x07); /* IRQ: 7 */ + WRITE_CONFIG_DATA(port, 0x74, 0x04); /* DMA: None */ + WRITE_CONFIG_DATA(port, 0xf0, 0x8c); /* IRQ polarity: Active Low */ + WRITE_CONFIG_DATA(port, 0xf1, 0xc5); + EXIT_CONFIG_MODE(port); +} + +void __devinit ali_m1535plus_keyboard_init(int port) +{ + ENTER_CONFIG_MODE(port); + SELECT_LOGICAL_DEVICE(port, 7); /* KEYBOARD */ + WRITE_CONFIG_DATA(port, 0x30, 0x01); /* KEYBOARD: eable */ + WRITE_CONFIG_DATA(port, 0x70, 0x01); /* IRQ: 1 */ + WRITE_CONFIG_DATA(port, 0x72, 0x0c); /* PS/2 Mouse IRQ: 12 */ + WRITE_CONFIG_DATA(port, 0xf0, 0x00); + EXIT_CONFIG_MODE(port); +} + +void __devinit ali_m1535plus_hotkey_init(int port) +{ + ENTER_CONFIG_MODE(port); + SELECT_LOGICAL_DEVICE(port, 0xc); /* HOTKEY */ + WRITE_CONFIG_DATA(port, 0x30, 0x00); + WRITE_CONFIG_DATA(port, 0xf0, 0x35); + WRITE_CONFIG_DATA(port, 0xf1, 0x14); + WRITE_CONFIG_DATA(port, 0xf2, 0x11); + WRITE_CONFIG_DATA(port, 0xf3, 0x71); + WRITE_CONFIG_DATA(port, 0xf5, 0x05); + EXIT_CONFIG_MODE(port); +} + +void ali_m1535plus_init(struct pci_dev *dev) +{ + pci_write_config_byte(dev, 0x40, 0x18); /* PCI Interface Control */ + pci_write_config_byte(dev, 0x41, 0xc0); /* PS2 keyb & mouse enable */ + pci_write_config_byte(dev, 0x42, 0x41); /* ISA bus cycle control */ + pci_write_config_byte(dev, 0x43, 0x00); /* ISA bus cycle control 2 */ + pci_write_config_byte(dev, 0x44, 0x5d); /* IDE enable & IRQ 14 */ + pci_write_config_byte(dev, 0x45, 0x0b); /* PCI int polling mode */ + pci_write_config_byte(dev, 0x47, 0x00); /* BIOS chip select control */ + + /* IRQ routing */ + pci_write_config_byte(dev, 0x48, 0x03); /* INTA IRQ10, INTB disable */ + pci_write_config_byte(dev, 0x49, 0x00); /* INTC and INTD disable */ + pci_write_config_byte(dev, 0x4a, 0x00); /* INTE and INTF disable */ + pci_write_config_byte(dev, 0x4b, 0x90); /* Audio IRQ11, Modem disable */ + + pci_write_config_word(dev, 0x50, 0x4000); /* Parity check IDE enable */ + pci_write_config_word(dev, 0x52, 0x0000); /* USB & RTC disable */ + pci_write_config_word(dev, 0x54, 0x0002); /* ??? no info */ + pci_write_config_word(dev, 0x56, 0x0002); /* PCS1J signal disable */ + + pci_write_config_byte(dev, 0x59, 0x00); /* PCSDS */ + pci_write_config_byte(dev, 0x5a, 0x00); + pci_write_config_byte(dev, 0x5b, 0x00); + pci_write_config_word(dev, 0x5c, 0x0000); + pci_write_config_byte(dev, 0x5e, 0x00); + pci_write_config_byte(dev, 0x5f, 0x00); + pci_write_config_word(dev, 0x60, 0x0000); + + pci_write_config_byte(dev, 0x6c, 0x00); + pci_write_config_byte(dev, 0x6d, 0x48); /* ROM address mapping */ + pci_write_config_byte(dev, 0x6e, 0x00); /* ??? what for? */ + + pci_write_config_byte(dev, 0x70, 0x12); /* Serial IRQ control */ + pci_write_config_byte(dev, 0x71, 0xEF); /* DMA channel select */ + pci_write_config_byte(dev, 0x72, 0x03); /* USB IDSEL */ + pci_write_config_byte(dev, 0x73, 0x00); /* ??? no info */ + + /* + * IRQ setup ALi M5237 USB Host Controller + * IRQ: 9 + */ + pci_write_config_byte(dev, 0x74, 0x01); /* USB IRQ9 */ + + pci_write_config_byte(dev, 0x75, 0x1f); /* IDE2 IRQ 15 */ + pci_write_config_byte(dev, 0x76, 0x80); /* ACPI disable */ + pci_write_config_byte(dev, 0x77, 0x40); /* Modem disable */ + pci_write_config_dword(dev, 0x78, 0x20000000); /* Pin select 2 */ + pci_write_config_byte(dev, 0x7c, 0x00); /* Pin select 3 */ + pci_write_config_byte(dev, 0x81, 0x00); /* ID read/write control */ + pci_write_config_byte(dev, 0x90, 0x00); /* PCI PM block control */ + pci_write_config_word(dev, 0xa4, 0x0000); /* PMSCR */ + +#ifdef CONFIG_BLK_DEV_FD + ali_m1535plus_fdc_init(1); +#endif + + ali_m1535plus_keyboard_init(1); + ali_m1535plus_hotkey_init(1); +} + +static inline void ali_config_writeb(u8 reg, u8 val, int devfn) +{ + u32 data; + int shift; + + writel((1 << 16) | (devfn << 8) | (reg & 0xfc) | 1UL, PCI_CONFIG_ADDR); + data = readl(PCI_CONFIG_DATA); + + shift = (reg & 3) << 3; + data &= ~(0xff << shift); + data |= (((u32)val) << shift); + + writel(data, PCI_CONFIG_DATA); +} + +static inline u8 ali_config_readb(u8 reg, int devfn) +{ + u32 data; + + writel((1 << 16) | (devfn << 8) | (reg & 0xfc) | 1UL, PCI_CONFIG_ADDR); + data = readl(PCI_CONFIG_DATA); + + return (u8)(data >> ((reg & 3) << 3)); +} + +static inline u16 ali_config_readw(u8 reg, int devfn) +{ + u32 data; + + writel((1 << 16) | (devfn << 8) | (reg & 0xfc) | 1UL, PCI_CONFIG_ADDR); + data = readl(PCI_CONFIG_DATA); + + return (u16)(data >> ((reg & 2) << 3)); +} + +int vr4133_rockhopper = 0; +void __init ali_m5229_preinit(void) +{ + if (ali_config_readw(PCI_VENDOR_ID,16) == PCI_VENDOR_ID_AL && + ali_config_readw(PCI_DEVICE_ID,16) == PCI_DEVICE_ID_AL_M1533) { + printk(KERN_INFO "Found an NEC Rockhopper \n"); + vr4133_rockhopper = 1; + /* + * Enable ALi M5229 IDE Controller (both channels) + * IDSEL: A27 + */ + ali_config_writeb(0x58, 0x4c, 16); + } +} + +void __init ali_m5229_init(struct pci_dev *dev) +{ + /* + * Enable Primary/Secondary Channel Cable Detect 40-Pin + */ + pci_write_config_word(dev, 0x4a, 0xc023); + + /* + * Set only the 3rd byteis for the master IDE's cycle and + * enable Internal IDE Function + */ + pci_write_config_byte(dev, 0x50, 0x23); /* Class code attr register */ + + pci_write_config_byte(dev, 0x09, 0xff); /* Set native mode & stuff */ + pci_write_config_byte(dev, 0x52, 0x00); /* use timing registers */ + pci_write_config_byte(dev, 0x58, 0x02); /* Primary addr setup timing */ + pci_write_config_byte(dev, 0x59, 0x22); /* Primary cmd block timing */ + pci_write_config_byte(dev, 0x5a, 0x22); /* Pr drv 0 R/W timing */ + pci_write_config_byte(dev, 0x5b, 0x22); /* Pr drv 1 R/W timing */ + pci_write_config_byte(dev, 0x5c, 0x02); /* Sec addr setup timing */ + pci_write_config_byte(dev, 0x5d, 0x22); /* Sec cmd block timing */ + pci_write_config_byte(dev, 0x5e, 0x22); /* Sec drv 0 R/W timing */ + pci_write_config_byte(dev, 0x5f, 0x22); /* Sec drv 1 R/W timing */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); + pci_write_config_word(dev, PCI_COMMAND, + PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | + PCI_COMMAND_IO); +} + diff --git a/arch/mips/vr41xx/nec-cmbvr4133/setup.c b/arch/mips/vr41xx/nec-cmbvr4133/setup.c new file mode 100644 index 000000000000..db686ce42e85 --- /dev/null +++ b/arch/mips/vr41xx/nec-cmbvr4133/setup.c @@ -0,0 +1,96 @@ +/* + * arch/mips/vr41xx/nec-cmbvr4133/setup.c + * + * Setup for the NEC CMB-VR4133. + * + * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com> and + * Alex Sapkov <asapkov@ru.mvista.com> + * + * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * Support for CMBVR4133 board in 2.6 + * Author: Manish Lachwani (mlachwani@mvista.com) + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <linux/ioport.h> + +#include <asm/reboot.h> +#include <asm/time.h> +#include <asm/vr41xx/cmbvr4133.h> +#include <asm/bootinfo.h> + +#ifdef CONFIG_MTD +#include <linux/mtd/physmap.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> + +static struct mtd_partition cmbvr4133_mtd_parts[] = { + { + .name = "User FS", + .size = 0x1be0000, + .offset = 0, + .mask_flags = 0, + }, + { + .name = "PMON", + .size = 0x140000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "User FS2", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0, + } +}; + +#define number_partitions (sizeof(cmbvr4133_mtd_parts)/sizeof(struct mtd_partition)) +#endif + +extern void i8259_init(void); + +static int __init nec_cmbvr4133_setup(void) +{ +#ifdef CONFIG_ROCKHOPPER + extern void disable_pcnet(void); + + disable_pcnet(); +#endif + set_io_port_base(KSEG1ADDR(0x16000000)); + + mips_machgroup = MACH_GROUP_NEC_VR41XX; + mips_machtype = MACH_NEC_CMBVR4133; + +#ifdef CONFIG_PCI +#ifdef CONFIG_ROCKHOPPER + ali_m5229_preinit(); +#endif +#endif + +#ifdef CONFIG_ROCKHOPPER + rockhopper_init_irq(); +#endif + +#ifdef CONFIG_MTD + /* we use generic physmap mapping driver and we use partitions */ + physmap_configure(0x1C000000, 0x02000000, 4, NULL); + physmap_set_partitions(cmbvr4133_mtd_parts, number_partitions); +#endif + + /* 128 MB memory support */ + add_memory_region(0, 0x08000000, BOOT_MEM_RAM); + +#ifdef CONFIG_ROCKHOPPER + i8259_init(); +#endif + return 0; +} + +early_initcall(nec_cmbvr4133_setup); diff --git a/arch/mips/vr41xx/tanbac-tb0226/Makefile b/arch/mips/vr41xx/tanbac-tb0226/Makefile new file mode 100644 index 000000000000..372f953d240b --- /dev/null +++ b/arch/mips/vr41xx/tanbac-tb0226/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the TANBAC TB0226 specific parts of the kernel +# + +obj-y += setup.o diff --git a/arch/mips/vr41xx/tanbac-tb0226/setup.c b/arch/mips/vr41xx/tanbac-tb0226/setup.c new file mode 100644 index 000000000000..60027e5dea25 --- /dev/null +++ b/arch/mips/vr41xx/tanbac-tb0226/setup.c @@ -0,0 +1,24 @@ +/* + * setup.c, Setup for the TANBAC TB0226. + * + * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +const char *get_system_type(void) +{ + return "TANBAC TB0226"; +} diff --git a/arch/mips/vr41xx/tanbac-tb0229/Makefile b/arch/mips/vr41xx/tanbac-tb0229/Makefile new file mode 100644 index 000000000000..9c6b864ef2ef --- /dev/null +++ b/arch/mips/vr41xx/tanbac-tb0229/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the TANBAC TB0229(VR4131DIMM) specific parts of the kernel +# + +obj-y := setup.o diff --git a/arch/mips/vr41xx/tanbac-tb0229/setup.c b/arch/mips/vr41xx/tanbac-tb0229/setup.c new file mode 100644 index 000000000000..5c1b757bfb0c --- /dev/null +++ b/arch/mips/vr41xx/tanbac-tb0229/setup.c @@ -0,0 +1,27 @@ +/* + * setup.c, Setup for the TANBAC TB0229 (VR4131DIMM) + * + * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * Modified for TANBAC TB0229: + * Copyright (C) 2003 Megasolution Inc. <matsu@megasolution.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +const char *get_system_type(void) +{ + return "TANBAC TB0229"; +} diff --git a/arch/mips/vr41xx/victor-mpc30x/Makefile b/arch/mips/vr41xx/victor-mpc30x/Makefile new file mode 100644 index 000000000000..a2e8086a31a6 --- /dev/null +++ b/arch/mips/vr41xx/victor-mpc30x/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Victor MP-C303/304 specific parts of the kernel +# + +obj-y += setup.o diff --git a/arch/mips/vr41xx/victor-mpc30x/setup.c b/arch/mips/vr41xx/victor-mpc30x/setup.c new file mode 100644 index 000000000000..f591e36726e6 --- /dev/null +++ b/arch/mips/vr41xx/victor-mpc30x/setup.c @@ -0,0 +1,24 @@ +/* + * setup.c, Setup for the Victor MP-C303/304. + * + * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +const char *get_system_type(void) +{ + return "Victor MP-C303/304"; +} diff --git a/arch/mips/vr41xx/zao-capcella/Makefile b/arch/mips/vr41xx/zao-capcella/Makefile new file mode 100644 index 000000000000..cf420197cd23 --- /dev/null +++ b/arch/mips/vr41xx/zao-capcella/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the ZAO Networks Capcella specific parts of the kernel +# + +obj-y += setup.o diff --git a/arch/mips/vr41xx/zao-capcella/setup.c b/arch/mips/vr41xx/zao-capcella/setup.c new file mode 100644 index 000000000000..17bade241fe2 --- /dev/null +++ b/arch/mips/vr41xx/zao-capcella/setup.c @@ -0,0 +1,24 @@ +/* + * setup.c, Setup for the ZAO Networks Capcella. + * + * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +const char *get_system_type(void) +{ + return "ZAO Networks Capcella"; +} |