2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2005-04-16 15:20:36 -07:00
/*
2005-09-08 23:07:38 +01:00
* linux / arch / arm / mach - omap1 / fpga . c
2005-04-16 15:20:36 -07:00
*
* Interrupt handler for OMAP - 1510 Innovator FPGA
*
* Copyright ( C ) 2001 RidgeRun , Inc .
* Author : Greg Lonnon < glonnon @ ridgerun . com >
*
* Copyright ( C ) 2002 MontaVista Software , Inc .
*
* Separated FPGA interrupts from innovator1510 . c and cleaned up for 2.6
* Copyright ( C ) 2004 Nokia Corporation by Tony Lindrgen < tony @ atomide . com >
*/
# include <linux/types.h>
2011-07-26 10:53:52 +01:00
# include <linux/gpio.h>
2005-04-16 15:20:36 -07:00
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/device.h>
# include <linux/errno.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2005-04-16 15:20:36 -07:00
# include <asm/irq.h>
# include <asm/mach/irq.h>
2019-08-06 16:16:03 +02:00
# include "hardware.h"
2012-02-24 10:34:34 -08:00
# include "iomap.h"
2012-10-26 13:21:48 -06:00
# include "common.h"
2012-10-31 14:02:46 -07:00
# include "fpga.h"
2012-02-24 10:34:34 -08:00
2010-11-29 10:39:27 +01:00
static void fpga_mask_irq ( struct irq_data * d )
2005-04-16 15:20:36 -07:00
{
2010-11-29 10:39:27 +01:00
unsigned int irq = d - > irq - OMAP_FPGA_IRQ_BASE ;
2005-04-16 15:20:36 -07:00
if ( irq < 8 )
__raw_writeb ( ( __raw_readb ( OMAP1510_FPGA_IMR_LO )
& ~ ( 1 < < irq ) ) , OMAP1510_FPGA_IMR_LO ) ;
else if ( irq < 16 )
__raw_writeb ( ( __raw_readb ( OMAP1510_FPGA_IMR_HI )
& ~ ( 1 < < ( irq - 8 ) ) ) , OMAP1510_FPGA_IMR_HI ) ;
else
__raw_writeb ( ( __raw_readb ( INNOVATOR_FPGA_IMR2 )
& ~ ( 1 < < ( irq - 16 ) ) ) , INNOVATOR_FPGA_IMR2 ) ;
}
static inline u32 get_fpga_unmasked_irqs ( void )
{
return
( ( __raw_readb ( OMAP1510_FPGA_ISR_LO ) &
__raw_readb ( OMAP1510_FPGA_IMR_LO ) ) ) |
( ( __raw_readb ( OMAP1510_FPGA_ISR_HI ) &
__raw_readb ( OMAP1510_FPGA_IMR_HI ) ) < < 8 ) |
( ( __raw_readb ( INNOVATOR_FPGA_ISR2 ) &
__raw_readb ( INNOVATOR_FPGA_IMR2 ) ) < < 16 ) ;
}
2010-11-29 10:39:27 +01:00
static void fpga_ack_irq ( struct irq_data * d )
2005-04-16 15:20:36 -07:00
{
/* Don't need to explicitly ACK FPGA interrupts */
}
2010-11-29 10:39:27 +01:00
static void fpga_unmask_irq ( struct irq_data * d )
2005-04-16 15:20:36 -07:00
{
2010-11-29 10:39:27 +01:00
unsigned int irq = d - > irq - OMAP_FPGA_IRQ_BASE ;
2005-04-16 15:20:36 -07:00
if ( irq < 8 )
__raw_writeb ( ( __raw_readb ( OMAP1510_FPGA_IMR_LO ) | ( 1 < < irq ) ) ,
OMAP1510_FPGA_IMR_LO ) ;
else if ( irq < 16 )
__raw_writeb ( ( __raw_readb ( OMAP1510_FPGA_IMR_HI )
| ( 1 < < ( irq - 8 ) ) ) , OMAP1510_FPGA_IMR_HI ) ;
else
__raw_writeb ( ( __raw_readb ( INNOVATOR_FPGA_IMR2 )
| ( 1 < < ( irq - 16 ) ) ) , INNOVATOR_FPGA_IMR2 ) ;
}
2010-11-29 10:39:27 +01:00
static void fpga_mask_ack_irq ( struct irq_data * d )
2005-04-16 15:20:36 -07:00
{
2010-11-29 10:39:27 +01:00
fpga_mask_irq ( d ) ;
fpga_ack_irq ( d ) ;
2005-04-16 15:20:36 -07:00
}
2015-09-14 10:42:37 +02:00
static void innovator_fpga_IRQ_demux ( struct irq_desc * desc )
2005-04-16 15:20:36 -07:00
{
u32 stat ;
int fpga_irq ;
stat = get_fpga_unmasked_irqs ( ) ;
if ( ! stat )
return ;
2008-07-03 12:24:41 +03:00
for ( fpga_irq = OMAP_FPGA_IRQ_BASE ;
( fpga_irq < OMAP_FPGA_IRQ_END ) & & stat ;
2005-04-16 15:20:36 -07:00
fpga_irq + + , stat > > = 1 ) {
if ( stat & 1 ) {
2008-10-09 13:36:24 +01:00
generic_handle_irq ( fpga_irq ) ;
2005-04-16 15:20:36 -07:00
}
}
}
2006-08-01 22:26:25 +01:00
static struct irq_chip omap_fpga_irq_ack = {
. name = " FPGA-ack " ,
2010-11-29 10:39:27 +01:00
. irq_ack = fpga_mask_ack_irq ,
. irq_mask = fpga_mask_irq ,
. irq_unmask = fpga_unmask_irq ,
2005-04-16 15:20:36 -07:00
} ;
2006-08-01 22:26:25 +01:00
static struct irq_chip omap_fpga_irq = {
. name = " FPGA " ,
2010-11-29 10:39:27 +01:00
. irq_ack = fpga_ack_irq ,
. irq_mask = fpga_mask_irq ,
. irq_unmask = fpga_unmask_irq ,
2005-04-16 15:20:36 -07:00
} ;
/*
* All of the FPGA interrupt request inputs except for the touchscreen are
* edge - sensitive ; the touchscreen is level - sensitive . The edge - sensitive
* interrupts are acknowledged as a side - effect of reading the interrupt
* status register from the FPGA . The edge - sensitive interrupt inputs
* cause a problem with level interrupt requests , such as Ethernet . The
* problem occurs when a level interrupt request is asserted while its
* interrupt input is masked in the FPGA , which results in a missed
* interrupt .
*
* In an attempt to workaround the problem with missed interrupts , the
* mask_ack routine for all of the FPGA interrupts has been changed from
* fpga_mask_ack_irq ( ) to fpga_ack_irq ( ) so that the specific FPGA interrupt
* being serviced is left unmasked . We can do this because the FPGA cascade
2013-09-07 09:19:25 +02:00
* interrupt is run with all interrupts masked .
2005-04-16 15:20:36 -07:00
*
* Limited testing indicates that this workaround appears to be effective
* for the smc9194 Ethernet driver used on the Innovator . It should work
* on other FPGA interrupts as well , but any drivers that explicitly mask
* interrupts at the interrupt controller via disable_irq / enable_irq
* could pose a problem .
*/
void omap1510_fpga_init_irq ( void )
{
2010-12-17 18:37:08 -08:00
int i , res ;
2005-04-16 15:20:36 -07:00
__raw_writeb ( 0 , OMAP1510_FPGA_IMR_LO ) ;
__raw_writeb ( 0 , OMAP1510_FPGA_IMR_HI ) ;
__raw_writeb ( 0 , INNOVATOR_FPGA_IMR2 ) ;
2008-07-03 12:24:41 +03:00
for ( i = OMAP_FPGA_IRQ_BASE ; i < OMAP_FPGA_IRQ_END ; i + + ) {
2005-04-16 15:20:36 -07:00
if ( i = = OMAP1510_INT_FPGA_TS ) {
/*
* The touchscreen interrupt is level - sensitive , so
* we ' ll use the regular mask_ack routine for it .
*/
2011-03-24 13:25:22 +01:00
irq_set_chip ( i , & omap_fpga_irq_ack ) ;
2005-04-16 15:20:36 -07:00
}
else {
/*
* All FPGA interrupts except the touchscreen are
* edge - sensitive , so we won ' t mask them .
*/
2011-03-24 13:25:22 +01:00
irq_set_chip ( i , & omap_fpga_irq ) ;
2005-04-16 15:20:36 -07:00
}
2011-03-24 13:25:22 +01:00
irq_set_handler ( i , handle_edge_irq ) ;
2015-07-27 15:55:13 -05:00
irq_clear_status_flags ( i , IRQ_NOREQUEST ) ;
2005-04-16 15:20:36 -07:00
}
/*
* The FPGA interrupt line is connected to GPIO13 . Claim this pin for
* the ARM .
*
* NOTE : For general GPIO / MPUIO access and interrupts , please see
* gpio . [ ch ]
*/
2010-12-17 18:37:08 -08:00
res = gpio_request ( 13 , " FPGA irq " ) ;
if ( res ) {
pr_err ( " %s failed to get gpio \n " , __func__ ) ;
return ;
}
2008-12-10 17:35:26 -08:00
gpio_direction_input ( 13 ) ;
2011-03-24 13:25:22 +01:00
irq_set_irq_type ( gpio_to_irq ( 13 ) , IRQ_TYPE_EDGE_RISING ) ;
irq_set_chained_handler ( OMAP1510_INT_FPGA , innovator_fpga_IRQ_demux ) ;
2005-04-16 15:20:36 -07:00
}