diff options
Diffstat (limited to 'arch/frv/kernel/irq-mb93093.c')
-rw-r--r-- | arch/frv/kernel/irq-mb93093.c | 115 |
1 files changed, 74 insertions, 41 deletions
diff --git a/arch/frv/kernel/irq-mb93093.c b/arch/frv/kernel/irq-mb93093.c index 48b2a6420888..f60db7988e78 100644 --- a/arch/frv/kernel/irq-mb93093.c +++ b/arch/frv/kernel/irq-mb93093.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* irq-mb93093.c: MB93093 FPGA interrupt handling | 1 | /* irq-mb93093.c: MB93093 FPGA interrupt handling |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -24,7 +24,6 @@ | |||
24 | #include <asm/delay.h> | 24 | #include <asm/delay.h> |
25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
26 | #include <asm/irc-regs.h> | 26 | #include <asm/irc-regs.h> |
27 | #include <asm/irq-routing.h> | ||
28 | 27 | ||
29 | #define __reg16(ADDR) (*(volatile unsigned short *)(__region_CS2 + (ADDR))) | 28 | #define __reg16(ADDR) (*(volatile unsigned short *)(__region_CS2 + (ADDR))) |
30 | 29 | ||
@@ -33,66 +32,100 @@ | |||
33 | #define __get_IFR() ({ __reg16(0x02); }) | 32 | #define __get_IFR() ({ __reg16(0x02); }) |
34 | #define __clr_IFR(M) do { __reg16(0x02) = ~(M); wmb(); } while(0) | 33 | #define __clr_IFR(M) do { __reg16(0x02) = ~(M); wmb(); } while(0) |
35 | 34 | ||
36 | static void frv_fpga_doirq(struct irq_source *source); | ||
37 | static void frv_fpga_control(struct irq_group *group, int irq, int on); | ||
38 | |||
39 | /*****************************************************************************/ | ||
40 | /* | 35 | /* |
41 | * FPGA IRQ multiplexor | 36 | * off-CPU FPGA PIC operations |
42 | */ | 37 | */ |
43 | static struct irq_source frv_fpga[4] = { | 38 | static void frv_fpga_enable(unsigned int irq) |
44 | #define __FPGA(X, M) \ | 39 | { |
45 | [X] = { \ | 40 | uint16_t imr = __get_IMR(); |
46 | .muxname = "fpga."#X, \ | ||
47 | .irqmask = M, \ | ||
48 | .doirq = frv_fpga_doirq, \ | ||
49 | } | ||
50 | |||
51 | __FPGA(0, 0x0700), | ||
52 | }; | ||
53 | 41 | ||
54 | static struct irq_group frv_fpga_irqs = { | 42 | imr &= ~(1 << (irq - IRQ_BASE_FPGA)); |
55 | .first_irq = IRQ_BASE_FPGA, | ||
56 | .control = frv_fpga_control, | ||
57 | .sources = { | ||
58 | [ 8] = &frv_fpga[0], | ||
59 | [ 9] = &frv_fpga[0], | ||
60 | [10] = &frv_fpga[0], | ||
61 | }, | ||
62 | }; | ||
63 | 43 | ||
44 | __set_IMR(imr); | ||
45 | } | ||
64 | 46 | ||
65 | static void frv_fpga_control(struct irq_group *group, int index, int on) | 47 | static void frv_fpga_disable(unsigned int irq) |
66 | { | 48 | { |
67 | uint16_t imr = __get_IMR(); | 49 | uint16_t imr = __get_IMR(); |
68 | 50 | ||
69 | if (on) | 51 | imr |= 1 << (irq - IRQ_BASE_FPGA); |
70 | imr &= ~(1 << index); | ||
71 | else | ||
72 | imr |= 1 << index; | ||
73 | 52 | ||
74 | __set_IMR(imr); | 53 | __set_IMR(imr); |
75 | } | 54 | } |
76 | 55 | ||
77 | static void frv_fpga_doirq(struct irq_source *source) | 56 | static void frv_fpga_ack(unsigned int irq) |
57 | { | ||
58 | __clr_IFR(1 << (irq - IRQ_BASE_FPGA)); | ||
59 | } | ||
60 | |||
61 | static void frv_fpga_end(unsigned int irq) | ||
62 | { | ||
63 | } | ||
64 | |||
65 | static struct irq_chip frv_fpga_pic = { | ||
66 | .name = "mb93093", | ||
67 | .enable = frv_fpga_enable, | ||
68 | .disable = frv_fpga_disable, | ||
69 | .ack = frv_fpga_ack, | ||
70 | .mask = frv_fpga_disable, | ||
71 | .unmask = frv_fpga_enable, | ||
72 | .end = frv_fpga_end, | ||
73 | }; | ||
74 | |||
75 | /* | ||
76 | * FPGA PIC interrupt handler | ||
77 | */ | ||
78 | static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs) | ||
78 | { | 79 | { |
79 | uint16_t mask, imr; | 80 | uint16_t imr, mask = (unsigned long) _mask; |
81 | irqreturn_t iret = 0; | ||
80 | 82 | ||
81 | imr = __get_IMR(); | 83 | imr = __get_IMR(); |
82 | mask = source->irqmask & ~imr & __get_IFR(); | 84 | mask = mask & ~imr & __get_IFR(); |
83 | if (mask) { | 85 | |
84 | __set_IMR(imr | mask); | 86 | /* poll all the triggered IRQs */ |
85 | __clr_IFR(mask); | 87 | while (mask) { |
86 | distribute_irqs(&frv_fpga_irqs, mask); | 88 | int irq; |
87 | __set_IMR(imr); | 89 | |
90 | asm("scan %1,gr0,%0" : "=r"(irq) : "r"(mask)); | ||
91 | irq = 31 - irq; | ||
92 | mask &= ~(1 << irq); | ||
93 | |||
94 | if (__do_IRQ(IRQ_BASE_FPGA + irq, regs)) | ||
95 | iret |= IRQ_HANDLED; | ||
88 | } | 96 | } |
97 | |||
98 | return iret; | ||
89 | } | 99 | } |
90 | 100 | ||
101 | /* | ||
102 | * define an interrupt action for each FPGA PIC output | ||
103 | * - use dev_id to indicate the FPGA PIC input to output mappings | ||
104 | */ | ||
105 | static struct irqaction fpga_irq[1] = { | ||
106 | [0] = { | ||
107 | .handler = fpga_interrupt, | ||
108 | .flags = IRQF_DISABLED, | ||
109 | .mask = CPU_MASK_NONE, | ||
110 | .name = "fpga.0", | ||
111 | .dev_id = (void *) 0x0700UL, | ||
112 | } | ||
113 | }; | ||
114 | |||
115 | /* | ||
116 | * initialise the motherboard FPGA's PIC | ||
117 | */ | ||
91 | void __init fpga_init(void) | 118 | void __init fpga_init(void) |
92 | { | 119 | { |
120 | int irq; | ||
121 | |||
122 | /* all PIC inputs are all set to be edge triggered */ | ||
93 | __set_IMR(0x0700); | 123 | __set_IMR(0x0700); |
94 | __clr_IFR(0x0000); | 124 | __clr_IFR(0x0000); |
95 | 125 | ||
96 | frv_irq_route_external(&frv_fpga[0], IRQ_CPU_EXTERNAL2); | 126 | for (irq = IRQ_BASE_FPGA + 8; irq <= IRQ_BASE_FPGA + 10; irq++) |
97 | frv_irq_set_group(&frv_fpga_irqs); | 127 | set_irq_chip_and_handler(irq, &frv_fpga_pic, handle_edge_irq); |
128 | |||
129 | /* the FPGA drives external IRQ input #2 on the CPU PIC */ | ||
130 | setup_irq(IRQ_CPU_EXTERNAL2, &fpga_irq[0]); | ||
98 | } | 131 | } |