2005-04-17 02:20:36 +04:00
/*
* linux / arch / arm / mach - footbridge / irq . c
*
* Copyright ( C ) 1996 - 2000 Russell King
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* Changelog :
* 22 - Aug - 1998 RMK Restructured IRQ routines
* 03 - Sep - 1998 PJB Merged CATS support
* 20 - Jan - 1998 RMK Started merge of EBSA286 , CATS and NetWinder
* 26 - Jan - 1999 PJB Don ' t use IACK on CATS
* 16 - Mar - 1999 RMK Added autodetect of ISA PICs
*/
# include <linux/ioport.h>
# include <linux/interrupt.h>
# include <linux/list.h>
# include <linux/init.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2008-12-06 11:25:16 +03:00
# include <linux/spinlock.h>
2005-04-17 02:20:36 +04:00
# include <asm/mach/irq.h>
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2005-04-17 02:20:36 +04:00
# include <asm/hardware/dec21285.h>
# include <asm/irq.h>
# include <asm/mach-types.h>
2009-01-08 18:42:41 +03:00
# include "common.h"
2010-11-29 12:30:13 +03:00
static void isa_mask_pic_lo_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
2010-11-29 12:30:13 +03:00
unsigned int mask = 1 < < ( d - > irq & 7 ) ;
2005-04-17 02:20:36 +04:00
outb ( inb ( PIC_MASK_LO ) | mask , PIC_MASK_LO ) ;
}
2010-11-29 12:30:13 +03:00
static void isa_ack_pic_lo_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
2010-11-29 12:30:13 +03:00
unsigned int mask = 1 < < ( d - > irq & 7 ) ;
2005-04-17 02:20:36 +04:00
outb ( inb ( PIC_MASK_LO ) | mask , PIC_MASK_LO ) ;
outb ( 0x20 , PIC_LO ) ;
}
2010-11-29 12:30:13 +03:00
static void isa_unmask_pic_lo_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
2010-11-29 12:30:13 +03:00
unsigned int mask = 1 < < ( d - > irq & 7 ) ;
2005-04-17 02:20:36 +04:00
outb ( inb ( PIC_MASK_LO ) & ~ mask , PIC_MASK_LO ) ;
}
2006-11-23 14:41:32 +03:00
static struct irq_chip isa_lo_chip = {
2010-11-29 12:30:13 +03:00
. irq_ack = isa_ack_pic_lo_irq ,
. irq_mask = isa_mask_pic_lo_irq ,
. irq_unmask = isa_unmask_pic_lo_irq ,
2005-04-17 02:20:36 +04:00
} ;
2010-11-29 12:30:13 +03:00
static void isa_mask_pic_hi_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
2010-11-29 12:30:13 +03:00
unsigned int mask = 1 < < ( d - > irq & 7 ) ;
2005-04-17 02:20:36 +04:00
outb ( inb ( PIC_MASK_HI ) | mask , PIC_MASK_HI ) ;
}
2010-11-29 12:30:13 +03:00
static void isa_ack_pic_hi_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
2010-11-29 12:30:13 +03:00
unsigned int mask = 1 < < ( d - > irq & 7 ) ;
2005-04-17 02:20:36 +04:00
outb ( inb ( PIC_MASK_HI ) | mask , PIC_MASK_HI ) ;
outb ( 0x62 , PIC_LO ) ;
outb ( 0x20 , PIC_HI ) ;
}
2010-11-29 12:30:13 +03:00
static void isa_unmask_pic_hi_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
2010-11-29 12:30:13 +03:00
unsigned int mask = 1 < < ( d - > irq & 7 ) ;
2005-04-17 02:20:36 +04:00
outb ( inb ( PIC_MASK_HI ) & ~ mask , PIC_MASK_HI ) ;
}
2006-11-23 14:41:32 +03:00
static struct irq_chip isa_hi_chip = {
2010-11-29 12:30:13 +03:00
. irq_ack = isa_ack_pic_hi_irq ,
. irq_mask = isa_mask_pic_hi_irq ,
. irq_unmask = isa_unmask_pic_hi_irq ,
2005-04-17 02:20:36 +04:00
} ;
2015-09-14 11:42:37 +03:00
static void isa_irq_handler ( struct irq_desc * desc )
2005-04-17 02:20:36 +04:00
{
unsigned int isa_irq = * ( unsigned char * ) PCIIACK_BASE ;
if ( isa_irq < _ISA_IRQ ( 0 ) | | isa_irq > = _ISA_IRQ ( 16 ) ) {
2015-09-14 11:42:37 +03:00
do_bad_IRQ ( desc ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2008-10-09 16:36:24 +04:00
generic_handle_irq ( isa_irq ) ;
2005-04-17 02:20:36 +04:00
}
2006-07-03 16:18:04 +04:00
static struct irqaction irq_cascade = {
. handler = no_action ,
. name = " cascade " ,
} ;
static struct resource pic1_resource = {
. name = " pic1 " ,
. start = 0x20 ,
. end = 0x3f ,
} ;
static struct resource pic2_resource = {
. name = " pic2 " ,
. start = 0xa0 ,
. end = 0xbf ,
} ;
2005-04-17 02:20:36 +04:00
void __init isa_init_irq ( unsigned int host_irq )
{
unsigned int irq ;
/*
* Setup , and then probe for an ISA PIC
* If the PIC is not there , then we
* ignore the PIC .
*/
outb ( 0x11 , PIC_LO ) ;
outb ( _ISA_IRQ ( 0 ) , PIC_MASK_LO ) ; /* IRQ number */
outb ( 0x04 , PIC_MASK_LO ) ; /* Slave on Ch2 */
outb ( 0x01 , PIC_MASK_LO ) ; /* x86 */
outb ( 0xf5 , PIC_MASK_LO ) ; /* pattern: 11110101 */
outb ( 0x11 , PIC_HI ) ;
outb ( _ISA_IRQ ( 8 ) , PIC_MASK_HI ) ; /* IRQ number */
outb ( 0x02 , PIC_MASK_HI ) ; /* Slave on Ch1 */
outb ( 0x01 , PIC_MASK_HI ) ; /* x86 */
outb ( 0xfa , PIC_MASK_HI ) ; /* pattern: 11111010 */
outb ( 0x0b , PIC_LO ) ;
outb ( 0x0b , PIC_HI ) ;
if ( inb ( PIC_MASK_LO ) = = 0xf5 & & inb ( PIC_MASK_HI ) = = 0xfa ) {
outb ( 0xff , PIC_MASK_LO ) ; /* mask all IRQs */
outb ( 0xff , PIC_MASK_HI ) ; /* mask all IRQs */
} else {
printk ( KERN_INFO " IRQ: ISA PIC not found \n " ) ;
host_irq = ( unsigned int ) - 1 ;
}
if ( host_irq ! = ( unsigned int ) - 1 ) {
for ( irq = _ISA_IRQ ( 0 ) ; irq < _ISA_IRQ ( 8 ) ; irq + + ) {
2011-03-24 15:35:09 +03:00
irq_set_chip_and_handler ( irq , & isa_lo_chip ,
handle_level_irq ) ;
2015-07-27 23:55:13 +03:00
irq_clear_status_flags ( irq , IRQ_NOREQUEST | IRQ_NOPROBE ) ;
2005-04-17 02:20:36 +04:00
}
for ( irq = _ISA_IRQ ( 8 ) ; irq < _ISA_IRQ ( 16 ) ; irq + + ) {
2011-03-24 15:35:09 +03:00
irq_set_chip_and_handler ( irq , & isa_hi_chip ,
handle_level_irq ) ;
2015-07-27 23:55:13 +03:00
irq_clear_status_flags ( irq , IRQ_NOREQUEST | IRQ_NOPROBE ) ;
2005-04-17 02:20:36 +04:00
}
request_resource ( & ioport_resource , & pic1_resource ) ;
request_resource ( & ioport_resource , & pic2_resource ) ;
setup_irq ( IRQ_ISA_CASCADE , & irq_cascade ) ;
2011-03-24 15:25:22 +03:00
irq_set_chained_handler ( host_irq , isa_irq_handler ) ;
2005-04-17 02:20:36 +04:00
/*
* On the NetWinder , don ' t automatically
* enable ISA IRQ11 when it is requested .
* There appears to be a missing pull - up
* resistor on this line .
*/
if ( machine_is_netwinder ( ) )
2015-07-27 23:55:13 +03:00
irq_modify_status ( _ISA_IRQ ( 11 ) ,
IRQ_NOREQUEST | IRQ_NOPROBE , IRQ_NOAUTOEN ) ;
2005-04-17 02:20:36 +04:00
}
}