From 57f0f512b273f60d52568b8c6b77e17f5636edc0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 5 Aug 2015 17:04:01 -0300 Subject: Initial import --- arch/frv/kernel/irq-mb93093.c | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 arch/frv/kernel/irq-mb93093.c (limited to 'arch/frv/kernel/irq-mb93093.c') diff --git a/arch/frv/kernel/irq-mb93093.c b/arch/frv/kernel/irq-mb93093.c new file mode 100644 index 000000000..1f3015cf8 --- /dev/null +++ b/arch/frv/kernel/irq-mb93093.c @@ -0,0 +1,129 @@ +/* irq-mb93093.c: MB93093 FPGA interrupt handling + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define __reg16(ADDR) (*(volatile unsigned short *)(__region_CS2 + (ADDR))) + +#define __get_IMR() ({ __reg16(0x0a); }) +#define __set_IMR(M) do { __reg16(0x0a) = (M); wmb(); } while(0) +#define __get_IFR() ({ __reg16(0x02); }) +#define __clr_IFR(M) do { __reg16(0x02) = ~(M); wmb(); } while(0) + +/* + * off-CPU FPGA PIC operations + */ +static void frv_fpga_mask(struct irq_data *d) +{ + uint16_t imr = __get_IMR(); + + imr |= 1 << (d->irq - IRQ_BASE_FPGA); + __set_IMR(imr); +} + +static void frv_fpga_ack(struct irq_data *d) +{ + __clr_IFR(1 << (d->irq - IRQ_BASE_FPGA)); +} + +static void frv_fpga_mask_ack(struct irq_data *d) +{ + uint16_t imr = __get_IMR(); + + imr |= 1 << (d->irq - IRQ_BASE_FPGA); + __set_IMR(imr); + + __clr_IFR(1 << (d->irq - IRQ_BASE_FPGA)); +} + +static void frv_fpga_unmask(struct irq_data *d) +{ + uint16_t imr = __get_IMR(); + + imr &= ~(1 << (d->irq - IRQ_BASE_FPGA)); + + __set_IMR(imr); +} + +static struct irq_chip frv_fpga_pic = { + .name = "mb93093", + .irq_ack = frv_fpga_ack, + .irq_mask = frv_fpga_mask, + .irq_mask_ack = frv_fpga_mask_ack, + .irq_unmask = frv_fpga_unmask, +}; + +/* + * FPGA PIC interrupt handler + */ +static irqreturn_t fpga_interrupt(int irq, void *_mask) +{ + uint16_t imr, mask = (unsigned long) _mask; + + imr = __get_IMR(); + mask = mask & ~imr & __get_IFR(); + + /* poll all the triggered IRQs */ + while (mask) { + int irq; + + asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask)); + irq = 31 - irq; + mask &= ~(1 << irq); + + generic_handle_irq(IRQ_BASE_FPGA + irq); + } + + return IRQ_HANDLED; +} + +/* + * define an interrupt action for each FPGA PIC output + * - use dev_id to indicate the FPGA PIC input to output mappings + */ +static struct irqaction fpga_irq[1] = { + [0] = { + .handler = fpga_interrupt, + .name = "fpga.0", + .dev_id = (void *) 0x0700UL, + } +}; + +/* + * initialise the motherboard FPGA's PIC + */ +void __init fpga_init(void) +{ + int irq; + + /* all PIC inputs are all set to be edge triggered */ + __set_IMR(0x0700); + __clr_IFR(0x0000); + + for (irq = IRQ_BASE_FPGA + 8; irq <= IRQ_BASE_FPGA + 10; irq++) + irq_set_chip_and_handler(irq, &frv_fpga_pic, handle_edge_irq); + + /* the FPGA drives external IRQ input #2 on the CPU PIC */ + setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[0]); +} -- cgit v1.2.3-54-g00ecf