diff options
Diffstat (limited to 'target/linux/adm5120-2.6/files/arch/mips/adm5120')
4 files changed, 180 insertions, 286 deletions
| diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile b/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile index f3e0e7f98..deb1adf7e 100644 --- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile @@ -2,7 +2,8 @@  # Makefile for the ADMtek ADM5120 SoC specific parts of the kernel  # -obj-y  := setup.o prom.o irq.o memory.o int-handler.o adm5120_info.o -obj-y  += gpio.o +obj-y	:= setup.o prom.o irq.o memory.o adm5120_info.o +obj-y	+= gpio.o +obj-y	+= time.o  EXTRA_AFLAGS := $(CFLAGS) diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S b/target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S deleted file mode 100644 index f118fb402..000000000 --- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999, 2000 MIPS Technologies, Inc.  All rights reserved. - * - * ######################################################################## - * - *  This program is free software; you can distribute it and/or modify it - *  under the terms of the GNU General Public License (Version 2) as - *  published by the Free Software Foundation. - * - *  This program is distributed in the hope 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. - * - * ######################################################################## - * - * Interrupt exception dispatch code. - * - */ -#include <linux/autoconf.h> - -#include <asm/asm.h> -#include <asm/mipsregs.h> -#include <asm/regdef.h> -#include <asm/stackframe.h> - -#define STATUS_IE	0x00000001 - -/* A lot of complication here is taken away because: - * - * 1) We handle one interrupt and return, sitting in a loop and moving across - *    all the pending IRQ bits in the cause register is _NOT_ the answer, the - *    common case is one pending IRQ so optimize in that direction. - * - * 2) We need not check against bits in the status register IRQ mask, that - *    would make this routine slow as hell. - * - * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in - *    between like BSD spl() brain-damage. - * - * Furthermore, the IRQs on the MIPS board look basically (barring software - * IRQs which we don't use at all and all external interrupt sources are - * combined together on hardware interrupt 0 (MIPS IRQ 2)) like: - * - *	MIPS IRQ	Source - *      --------        ------ - *             0	Software (ignored) - *             1        Software (ignored) - *             2        Combined hardware interrupt (hw0) - *             3        Hardware (ignored) - *             4        Hardware (ignored) - *             5        Hardware (ignored) - *             6        Hardware (ignored) - *             7        R4k timer (what we use) - * - * Note: On the SEAD board thing are a little bit different. - *       Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired - *       wired to UART1. - *	 - * We handle the IRQ according to _our_ priority which is: - * - * Highest ----     R4k Timer - * Lowest  ----     Combined hardware interrupt - * - * then we just return, if multiple IRQs are pending then we will just take - * another exception, big deal. - */ - -	.text -	.set	noreorder -	.set	noat -	.align	5 - -NESTED(mipsIRQ, PT_SIZE, sp) -	SAVE_ALL -	CLI -	.set	at - -	mfc0	s0, CP0_CAUSE		 -	mfc0	s1, CP0_STATUS -	and     s0, s0, s1 -	 -	/* First we check for r4k counter/timer IRQ. */ -	andi	a0, s0, CAUSEF_IP7 -	beq		a0, zero, 1f -	nop - -	move	a0, sp -	jal		mips_timer_interrupt -	nop - -	j		ret_from_irq -	nop				 - -1: -	andi	a0, s0, CAUSEF_IP2 -	beq		a0, zero, 1f	 -	nop -	 -	move	a0, sp			 -	jal		adm5120_hw0_irqdispatch	  -	nop -1: -	j		ret_from_irq -	nop							 - -END(mipsIRQ) - - -LEAF(mips_int_lock) -	.set noreorder -	mfc0	v0, CP0_STATUS -	li		v1, ~STATUS_IE -	and		v1, v1, v0 -	mtc0	v1, CP0_STATUS -	j		ra -	and		v0, v0, STATUS_IE -	.set reorder -END(mips_int_lock) - - -LEAF(mips_int_unlock) -	mfc0	v0, CP0_STATUS -	and		a0, a0, STATUS_IE -	or		v0, v0, a0 -	mtc0	v0, CP0_STATUS -	j		ra -	nop -END(mips_int_unlock) - diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c index c53272e1e..3e14c92f1 100644 --- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c @@ -1,157 +1,203 @@  /* - *	Copyright (C) ADMtek Incorporated. - *		Creator : daniell@admtek.com.tw - *	Carsten Langgaard, carstenl@mips.com - *	Copyright (C) 2000, 2001 MIPS Technologies, Inc. - *	Copyright (C) 2001 Ralf Baechle - *	Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + *  $Id$ + * + *  ADM5120 specific interrupt handlers + * + *  Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu> + *  Copyright (C) 2007 OpenWrt.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., 51 Franklin Street, Fifth Floor, + *  Boston, MA  02110-1301, USA. + *   */ -#include <linux/autoconf.h>  #include <linux/init.h> -#include <linux/kernel_stat.h> -#include <linux/signal.h> -#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/version.h>  #include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/pm.h> +#include <linux/ioport.h>  #include <asm/irq.h> -#include <asm/time.h> -#include <asm/mipsregs.h> -#include <asm/gdb-stub.h>  #include <asm/irq_cpu.h> +#include <asm/mipsregs.h> +#include <asm/bitops.h> + +#include <asm/mach-adm5120/adm5120_defs.h> +#include <asm/mach-adm5120/adm5120_irq.h> + +#define INTC_REG(r) (*(volatile u32 *)(KSEG1ADDR(ADM5120_INTC_BASE) + r)) + +static void adm5120_intc_irq_unmask(unsigned int irq); +static void adm5120_intc_irq_mask(unsigned int irq); +static int  adm5120_intc_irq_set_type(unsigned int irq, unsigned int flow_type); + +static struct irq_chip adm5120_intc_irq_chip = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +	.name 		= "INTC", +#else +	.typename 	= "INTC", +#endif +	.unmask 	= adm5120_intc_irq_unmask, +	.mask 		= adm5120_intc_irq_mask, +	.mask_ack	= adm5120_intc_irq_mask, +	.set_type	= adm5120_intc_irq_set_type +}; -#define MIPS_CPU_TIMER_IRQ 7 - -extern int setup_irq(unsigned int irq, struct irqaction *irqaction); -extern irq_desc_t irq_desc[]; -extern asmlinkage void mipsIRQ(void); - -int mips_int_lock(void); -void mips_int_unlock(int); - -unsigned int mips_counter_frequency; - -#define ADM5120_INTC_REG(reg)	(*(volatile u32 *)(KSEG1ADDR(0x12200000+(reg)))) -#define ADM5120_INTC_STATUS	ADM5120_INTC_REG(0x00) -#define ADM5120_INTC_ENABLE	ADM5120_INTC_REG(0x08) -#define ADM5120_INTC_DISABLE	ADM5120_INTC_REG(0x0c) -#define ADM5120_IRQ_MAX		9 -#define ADM5120_IRQ_MASK	0x3ff +static struct irqaction adm5120_intc_irq_action = { +	.handler 	= no_action, +	.name 		= "cascade [INTC]" +}; -void adm5120_hw0_irqdispatch(struct pt_regs *regs) +static void adm5120_intc_irq_unmask(unsigned int irq)  { -	unsigned long intsrc; -	int i; - -	intsrc = ADM5120_INTC_STATUS & ADM5120_IRQ_MASK; - -	if (intsrc) { -		for (i = 0; intsrc; intsrc >>= 1, i++) -			if (intsrc & 0x1) -				do_IRQ(i); -	} else -		spurious_interrupt(); -} +	unsigned long flags; -void mips_timer_interrupt(struct pt_regs *regs) -{ -        write_c0_compare(read_c0_count()+ mips_counter_frequency/HZ); -        ll_timer_interrupt(MIPS_CPU_TIMER_IRQ); +	irq -= ADM5120_INTC_IRQ_BASE; +	local_irq_save(flags); +	INTC_REG(INTC_REG_IRQ_ENABLE) = (1 << irq); +	local_irq_restore(flags);  } -/* Main interrupt dispatcher */ -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +static void adm5120_intc_irq_mask(unsigned int irq)  { -        unsigned int cp0_cause = read_c0_cause() & read_c0_status(); +	unsigned long flags; -        if (cp0_cause & CAUSEF_IP7) { -                mips_timer_interrupt( regs); -        } else if (cp0_cause & CAUSEF_IP2) { -                adm5120_hw0_irqdispatch( regs); -        } +	irq -= ADM5120_INTC_IRQ_BASE; +	local_irq_save(flags); +	INTC_REG(INTC_REG_IRQ_DISABLE) = (1 << irq); +	local_irq_restore(flags);  } -void enable_adm5120_irq(unsigned int irq) +static int adm5120_intc_irq_set_type(unsigned int irq, unsigned int flow_type)  { -	int s; - -	/* Disable all interrupts (FIQ/IRQ) */ -	s = mips_int_lock(); - -	if ((irq < 0) || (irq > ADM5120_IRQ_MAX))  -		goto err_exit; - -	ADM5120_INTC_ENABLE = (1<<irq); - -err_exit: - -	/* Restore the interrupts states */ -	mips_int_unlock(s); +	/* TODO: not yet tested */ +#if 1 +	unsigned int sense; +	unsigned long mode; +	int err; + +	err = 0; +	sense = flow_type & (IRQ_TYPE_SENSE_MASK); +	switch (sense) { +	case IRQ_TYPE_NONE: +	case IRQ_TYPE_LEVEL_HIGH: +		break; +	case IRQ_TYPE_LEVEL_LOW: +		switch (irq) { +		case ADM5120_IRQ_GPIO2: +		case ADM5120_IRQ_GPIO4: +			break; +		default: +			err = -EINVAL; +			break; +		} +		break; +	default: +		err = -EINVAL; +		break; +	} +	 +	if (err) +		return err; +	 +	switch (irq) { +	case ADM5120_IRQ_GPIO2: +	case ADM5120_IRQ_GPIO4: +		mode = INTC_REG(INTC_REG_INT_MODE); +		if (sense == IRQ_TYPE_LEVEL_LOW) +			mode |= (1 << (irq-ADM5120_INTC_IRQ_BASE)); +		else +			mode &= (1 << (irq-ADM5120_INTC_IRQ_BASE)); +			 +		INTC_REG(INTC_REG_INT_MODE) = mode; +		/* fallthrogh */ +	default: +		irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK; +		irq_desc[irq].status |= sense; +		break; +	} +#endif +	return 0;  } - -void disable_adm5120_irq(unsigned int irq) +static void adm5120_intc_irq_dispatch(void)  { -	int s; - -	/* Disable all interrupts (FIQ/IRQ) */ -	s = mips_int_lock(); +	unsigned long status; +	int irq; -	if ((irq < 0) || (irq > ADM5120_IRQ_MAX))  -		goto err_exit; +#if 1 +	/* dispatch only one IRQ at a time */ +	status = INTC_REG(INTC_REG_IRQ_STATUS) & INTC_INT_ALL; -	ADM5120_INTC_DISABLE = (1<<irq); - -err_exit: -	/* Restore the interrupts states */ -	mips_int_unlock(s); +	if (status) { +		irq = ADM5120_INTC_IRQ_BASE+fls(status)-1; +		do_IRQ(irq); +	} else +		spurious_interrupt(); +#else +	status = INTC_REG(INTC_REG_IRQ_STATUS) & INTC_INT_ALL; +	if (status) { +		for (irq=ADM5120_INTC_IRQ_BASE; irq <= ADM5120_INTC_IRQ_BASE + +			INTC_IRQ_LAST;	irq++, status >>=1) { +			if ((status & 1) == 1) +				do_IRQ(irq); +		} +	} else +		spurious_interrupt(); +#endif  } -unsigned int startup_adm5120_irq(unsigned int irq) +asmlinkage void plat_irq_dispatch(void)  { -	enable_adm5120_irq(irq); -	return 0; -} +	unsigned long pending; -void shutdown_adm5120_irq(unsigned int irq) -{ -	disable_adm5120_irq(irq); -} +	pending = read_c0_status() & read_c0_cause(); -static inline void ack_adm5120_irq(unsigned int irq_nr) -{ -	ADM5120_INTC_DISABLE = (1 << irq_nr); +	if (pending & STATUSF_IP7) +		do_IRQ(ADM5120_IRQ_COUNTER); +	else if (pending & STATUSF_IP2) +		adm5120_intc_irq_dispatch(); +	else +		spurious_interrupt();  } - -static void end_adm5120_irq(unsigned int irq_nr) +#define INTC_IRQ_STATUS (IRQ_LEVEL | IRQ_TYPE_LEVEL_HIGH | IRQ_DISABLED) +static void __init adm5120_intc_irq_init(int base)  { -	ADM5120_INTC_ENABLE = (1 << irq_nr); -} +	int i; -static hw_irq_controller adm5120_irq_type = { -	.typename 	= "MIPS", -	.startup	= startup_adm5120_irq, -	.shutdown	= shutdown_adm5120_irq, -	.enable		= enable_adm5120_irq, -	.disable	= disable_adm5120_irq, -	.ack 		= ack_adm5120_irq, -	.end		= end_adm5120_irq, -	.set_affinity	= NULL, -}; +	/* disable all interrupts */ +	INTC_REG(INTC_REG_IRQ_DISABLE) = INTC_INT_ALL; +	/* setup all interrupts to generate IRQ instead of FIQ */ +	INTC_REG(INTC_REG_INT_MODE) = 0; +	/* set active level for all external interrupts to HIGH */ +	INTC_REG(INTC_REG_INT_LEVEL) = 0; +	/* disable usage of the TEST_SOURCE register */ +	INTC_REG(INTC_REG_IRQ_SOURCE_SELECT) = 0; + +	for(i=ADM5120_INTC_IRQ_BASE; i <= ADM5120_INTC_IRQ_BASE+INTC_IRQ_LAST; +		i++) { +		irq_desc[i].status = INTC_IRQ_STATUS; +		set_irq_chip_and_handler(i, &adm5120_intc_irq_chip,  +			handle_level_irq); +	} +	setup_irq(ADM5120_IRQ_INTC, &adm5120_intc_irq_action); +} -void __init arch_init_irq(void) -{ -	int i; -	 -	for (i = 0; i <= ADM5120_IRQ_MAX; i++) { -		irq_desc[i].status = IRQ_DISABLED; -		irq_desc[i].action = 0; -		irq_desc[i].depth = 1; -		irq_desc[i].chip = &adm5120_irq_type; -	} +void __init arch_init_irq(void) { +	mips_cpu_irq_init(); +	adm5120_intc_irq_init(ADM5120_INTC_IRQ_BASE);  } diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c index 5767df8b2..aa30dc5c8 100644 --- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c @@ -15,15 +15,13 @@  #include <asm/io.h>  #include <asm/time.h> -#include <adm5120_info.h> +#include <asm/mach-adm5120/adm5120_info.h> +#include <asm/mach-adm5120/adm5120_defs.h> +#include <asm/mach-adm5120/adm5120_irq.h> -#define ADM5120_SOFTRESET	0x12000004 -#define STATUS_IE		0x00000001 -#define ALLINTS (IE_IRQ0 | IE_IRQ5 | STATUS_IE) - -void  mips_time_init(void); +extern void adm5120_time_init(void) __init; -extern unsigned int mips_counter_frequency; +#define ADM5120_SOFTRESET	0x12000004  void adm5120_restart(char *command)  { @@ -43,25 +41,11 @@ void adm5120_power_off(void)          adm5120_halt();  } -void __init adm5120_time_init(void) -{ -	mips_counter_frequency = adm5120_speed >> 1; -} - -void __init plat_timer_setup(struct irqaction *irq) -{ -	/* to generate the first timer interrupt */ -	write_c0_compare(read_c0_count()+ mips_counter_frequency/HZ); -	clear_c0_status(ST0_BEV); -	set_c0_status(ALLINTS); -} -  void __init plat_mem_setup(void)  {  	printk(KERN_INFO "ADM5120 board setup\n");  	board_time_init = adm5120_time_init; -	//board_timer_setup = mips_timer_setup;  	_machine_restart = adm5120_restart;  	_machine_halt = adm5120_halt; @@ -75,16 +59,15 @@ const char *get_system_type(void)  	return adm5120_board_name();  } -#ifdef CONFIG_USB  static struct resource adm5120_hcd_resources[] = {  	[0] = { -		.start	= 0x11200000, -		.end	= 0x11200084, +		.start	= ADM5120_USBC_BASE, +		.end	= ADM5120_USBC_BASE+ADM5120_USBC_SIZE-1,  		.flags	= IORESOURCE_MEM,  	},  	[1] = { -		.start	= 0x3, -		.end	= 0x3, +		.start	= ADM5120_IRQ_USBC, +		.end	= ADM5120_IRQ_USBC,  		.flags	= IORESOURCE_IRQ,  	},  }; @@ -105,5 +88,4 @@ static int __init adm5120_init(void)  	return platform_add_devices(devices, ARRAY_SIZE(devices));  } -arch_initcall(adm5120_init); -#endif +subsys_initcall(adm5120_init); | 
