^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/arch/arm/mach-omap1/fpga.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Interrupt handler for OMAP-1510 Innovator FPGA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2001 RidgeRun, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Author: Greg Lonnon <glonnon@ridgerun.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2002 MontaVista Software, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen <tony@atomide.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/mach/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <mach/hardware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include "iomap.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include "fpga.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static void fpga_mask_irq(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (irq < 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) & ~(1 << irq)), OMAP1510_FPGA_IMR_LO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) else if (irq < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) & ~(1 << (irq - 8))), OMAP1510_FPGA_IMR_HI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) & ~(1 << (irq - 16))), INNOVATOR_FPGA_IMR2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static inline u32 get_fpga_unmasked_irqs(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) ((__raw_readb(OMAP1510_FPGA_ISR_LO) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) __raw_readb(OMAP1510_FPGA_IMR_LO))) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) ((__raw_readb(OMAP1510_FPGA_ISR_HI) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) __raw_readb(OMAP1510_FPGA_IMR_HI)) << 8) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ((__raw_readb(INNOVATOR_FPGA_ISR2) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) __raw_readb(INNOVATOR_FPGA_IMR2)) << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static void fpga_ack_irq(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* Don't need to explicitly ACK FPGA interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static void fpga_unmask_irq(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (irq < 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) OMAP1510_FPGA_IMR_LO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) else if (irq < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) | (1 << (irq - 8))), OMAP1510_FPGA_IMR_HI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) | (1 << (irq - 16))), INNOVATOR_FPGA_IMR2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static void fpga_mask_ack_irq(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) fpga_mask_irq(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) fpga_ack_irq(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static void innovator_fpga_IRQ_demux(struct irq_desc *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u32 stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int fpga_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) stat = get_fpga_unmasked_irqs();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (!stat)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) for (fpga_irq = OMAP_FPGA_IRQ_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) (fpga_irq < OMAP_FPGA_IRQ_END) && stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) fpga_irq++, stat >>= 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (stat & 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) generic_handle_irq(fpga_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static struct irq_chip omap_fpga_irq_ack = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .name = "FPGA-ack",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .irq_ack = fpga_mask_ack_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .irq_mask = fpga_mask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .irq_unmask = fpga_unmask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static struct irq_chip omap_fpga_irq = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .name = "FPGA",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .irq_ack = fpga_ack_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) .irq_mask = fpga_mask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .irq_unmask = fpga_unmask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * All of the FPGA interrupt request inputs except for the touchscreen are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * edge-sensitive; the touchscreen is level-sensitive. The edge-sensitive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * interrupts are acknowledged as a side-effect of reading the interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * status register from the FPGA. The edge-sensitive interrupt inputs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * cause a problem with level interrupt requests, such as Ethernet. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * problem occurs when a level interrupt request is asserted while its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * interrupt input is masked in the FPGA, which results in a missed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * interrupt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * In an attempt to workaround the problem with missed interrupts, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * mask_ack routine for all of the FPGA interrupts has been changed from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * fpga_mask_ack_irq() to fpga_ack_irq() so that the specific FPGA interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * being serviced is left unmasked. We can do this because the FPGA cascade
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * interrupt is run with all interrupts masked.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * Limited testing indicates that this workaround appears to be effective
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * for the smc9194 Ethernet driver used on the Innovator. It should work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * on other FPGA interrupts as well, but any drivers that explicitly mask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * interrupts at the interrupt controller via disable_irq/enable_irq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * could pose a problem.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) void omap1510_fpga_init_irq(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) int i, res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) __raw_writeb(0, OMAP1510_FPGA_IMR_LO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) __raw_writeb(0, OMAP1510_FPGA_IMR_HI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) __raw_writeb(0, INNOVATOR_FPGA_IMR2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) for (i = OMAP_FPGA_IRQ_BASE; i < OMAP_FPGA_IRQ_END; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (i == OMAP1510_INT_FPGA_TS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * The touchscreen interrupt is level-sensitive, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * we'll use the regular mask_ack routine for it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) irq_set_chip(i, &omap_fpga_irq_ack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * All FPGA interrupts except the touchscreen are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * edge-sensitive, so we won't mask them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) irq_set_chip(i, &omap_fpga_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) irq_set_handler(i, handle_edge_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) irq_clear_status_flags(i, IRQ_NOREQUEST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * The FPGA interrupt line is connected to GPIO13. Claim this pin for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * the ARM.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * NOTE: For general GPIO/MPUIO access and interrupts, please see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * gpio.[ch]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) res = gpio_request(13, "FPGA irq");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) pr_err("%s failed to get gpio\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) gpio_direction_input(13);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) irq_set_irq_type(gpio_to_irq(13), IRQ_TYPE_EDGE_RISING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) irq_set_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }