Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/arch/arm/mach-omap1/fpga.c
0004  *
0005  * Interrupt handler for OMAP-1510 Innovator FPGA
0006  *
0007  * Copyright (C) 2001 RidgeRun, Inc.
0008  * Author: Greg Lonnon <glonnon@ridgerun.com>
0009  *
0010  * Copyright (C) 2002 MontaVista Software, Inc.
0011  *
0012  * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6
0013  * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen <tony@atomide.com>
0014  */
0015 
0016 #include <linux/types.h>
0017 #include <linux/gpio.h>
0018 #include <linux/init.h>
0019 #include <linux/kernel.h>
0020 #include <linux/device.h>
0021 #include <linux/errno.h>
0022 #include <linux/io.h>
0023 
0024 #include <asm/irq.h>
0025 #include <asm/mach/irq.h>
0026 
0027 #include "hardware.h"
0028 #include "iomap.h"
0029 #include "common.h"
0030 #include "fpga.h"
0031 
0032 static void fpga_mask_irq(struct irq_data *d)
0033 {
0034     unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE;
0035 
0036     if (irq < 8)
0037         __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO)
0038                   & ~(1 << irq)), OMAP1510_FPGA_IMR_LO);
0039     else if (irq < 16)
0040         __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI)
0041                   & ~(1 << (irq - 8))), OMAP1510_FPGA_IMR_HI);
0042     else
0043         __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2)
0044                   & ~(1 << (irq - 16))), INNOVATOR_FPGA_IMR2);
0045 }
0046 
0047 
0048 static inline u32 get_fpga_unmasked_irqs(void)
0049 {
0050     return
0051         ((__raw_readb(OMAP1510_FPGA_ISR_LO) &
0052           __raw_readb(OMAP1510_FPGA_IMR_LO))) |
0053         ((__raw_readb(OMAP1510_FPGA_ISR_HI) &
0054           __raw_readb(OMAP1510_FPGA_IMR_HI)) << 8) |
0055         ((__raw_readb(INNOVATOR_FPGA_ISR2) &
0056           __raw_readb(INNOVATOR_FPGA_IMR2)) << 16);
0057 }
0058 
0059 
0060 static void fpga_ack_irq(struct irq_data *d)
0061 {
0062     /* Don't need to explicitly ACK FPGA interrupts */
0063 }
0064 
0065 static void fpga_unmask_irq(struct irq_data *d)
0066 {
0067     unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE;
0068 
0069     if (irq < 8)
0070         __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)),
0071              OMAP1510_FPGA_IMR_LO);
0072     else if (irq < 16)
0073         __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI)
0074                   | (1 << (irq - 8))), OMAP1510_FPGA_IMR_HI);
0075     else
0076         __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2)
0077                   | (1 << (irq - 16))), INNOVATOR_FPGA_IMR2);
0078 }
0079 
0080 static void fpga_mask_ack_irq(struct irq_data *d)
0081 {
0082     fpga_mask_irq(d);
0083     fpga_ack_irq(d);
0084 }
0085 
0086 static void innovator_fpga_IRQ_demux(struct irq_desc *desc)
0087 {
0088     u32 stat;
0089     int fpga_irq;
0090 
0091     stat = get_fpga_unmasked_irqs();
0092 
0093     if (!stat)
0094         return;
0095 
0096     for (fpga_irq = OMAP_FPGA_IRQ_BASE;
0097          (fpga_irq < OMAP_FPGA_IRQ_END) && stat;
0098          fpga_irq++, stat >>= 1) {
0099         if (stat & 1) {
0100             generic_handle_irq(fpga_irq);
0101         }
0102     }
0103 }
0104 
0105 static struct irq_chip omap_fpga_irq_ack = {
0106     .name       = "FPGA-ack",
0107     .irq_ack    = fpga_mask_ack_irq,
0108     .irq_mask   = fpga_mask_irq,
0109     .irq_unmask = fpga_unmask_irq,
0110 };
0111 
0112 
0113 static struct irq_chip omap_fpga_irq = {
0114     .name       = "FPGA",
0115     .irq_ack    = fpga_ack_irq,
0116     .irq_mask   = fpga_mask_irq,
0117     .irq_unmask = fpga_unmask_irq,
0118 };
0119 
0120 /*
0121  * All of the FPGA interrupt request inputs except for the touchscreen are
0122  * edge-sensitive; the touchscreen is level-sensitive.  The edge-sensitive
0123  * interrupts are acknowledged as a side-effect of reading the interrupt
0124  * status register from the FPGA.  The edge-sensitive interrupt inputs
0125  * cause a problem with level interrupt requests, such as Ethernet.  The
0126  * problem occurs when a level interrupt request is asserted while its
0127  * interrupt input is masked in the FPGA, which results in a missed
0128  * interrupt.
0129  *
0130  * In an attempt to workaround the problem with missed interrupts, the
0131  * mask_ack routine for all of the FPGA interrupts has been changed from
0132  * fpga_mask_ack_irq() to fpga_ack_irq() so that the specific FPGA interrupt
0133  * being serviced is left unmasked.  We can do this because the FPGA cascade
0134  * interrupt is run with all interrupts masked.
0135  *
0136  * Limited testing indicates that this workaround appears to be effective
0137  * for the smc9194 Ethernet driver used on the Innovator.  It should work
0138  * on other FPGA interrupts as well, but any drivers that explicitly mask
0139  * interrupts at the interrupt controller via disable_irq/enable_irq
0140  * could pose a problem.
0141  */
0142 void omap1510_fpga_init_irq(void)
0143 {
0144     int i, res;
0145 
0146     __raw_writeb(0, OMAP1510_FPGA_IMR_LO);
0147     __raw_writeb(0, OMAP1510_FPGA_IMR_HI);
0148     __raw_writeb(0, INNOVATOR_FPGA_IMR2);
0149 
0150     for (i = OMAP_FPGA_IRQ_BASE; i < OMAP_FPGA_IRQ_END; i++) {
0151 
0152         if (i == OMAP1510_INT_FPGA_TS) {
0153             /*
0154              * The touchscreen interrupt is level-sensitive, so
0155              * we'll use the regular mask_ack routine for it.
0156              */
0157             irq_set_chip(i, &omap_fpga_irq_ack);
0158         }
0159         else {
0160             /*
0161              * All FPGA interrupts except the touchscreen are
0162              * edge-sensitive, so we won't mask them.
0163              */
0164             irq_set_chip(i, &omap_fpga_irq);
0165         }
0166 
0167         irq_set_handler(i, handle_edge_irq);
0168         irq_clear_status_flags(i, IRQ_NOREQUEST);
0169     }
0170 
0171     /*
0172      * The FPGA interrupt line is connected to GPIO13. Claim this pin for
0173      * the ARM.
0174      *
0175      * NOTE: For general GPIO/MPUIO access and interrupts, please see
0176      * gpio.[ch]
0177      */
0178     res = gpio_request(13, "FPGA irq");
0179     if (res) {
0180         pr_err("%s failed to get gpio\n", __func__);
0181         return;
0182     }
0183     gpio_direction_input(13);
0184     irq_set_irq_type(gpio_to_irq(13), IRQ_TYPE_EDGE_RISING);
0185     irq_set_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux);
0186 }