| Jonas Bonn | 816ebaa | 2011-06-04 22:18:56 +0300 | [diff] [blame] | 1 | /* | 
|  | 2 | * OpenRISC irq.c | 
|  | 3 | * | 
|  | 4 | * Linux architectural port borrowing liberally from similar works of | 
|  | 5 | * others.  All original copyrights apply as per the original source | 
|  | 6 | * declaration. | 
|  | 7 | * | 
|  | 8 | * Modifications for the OpenRISC architecture: | 
|  | 9 | * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> | 
|  | 10 | * | 
|  | 11 | *      This program is free software; you can redistribute it and/or | 
|  | 12 | *      modify it under the terms of the GNU General Public License | 
|  | 13 | *      as published by the Free Software Foundation; either version | 
|  | 14 | *      2 of the License, or (at your option) any later version. | 
|  | 15 | */ | 
|  | 16 |  | 
|  | 17 | #include <linux/ptrace.h> | 
|  | 18 | #include <linux/errno.h> | 
|  | 19 | #include <linux/interrupt.h> | 
|  | 20 | #include <linux/init.h> | 
|  | 21 | #include <linux/of.h> | 
|  | 22 | #include <linux/ftrace.h> | 
|  | 23 | #include <linux/irq.h> | 
|  | 24 | #include <linux/seq_file.h> | 
|  | 25 | #include <linux/kernel_stat.h> | 
|  | 26 |  | 
|  | 27 | #include <linux/irqflags.h> | 
|  | 28 |  | 
|  | 29 | /* read interrupt enabled status */ | 
|  | 30 | unsigned long arch_local_save_flags(void) | 
|  | 31 | { | 
|  | 32 | return mfspr(SPR_SR) & (SPR_SR_IEE|SPR_SR_TEE); | 
|  | 33 | } | 
|  | 34 | EXPORT_SYMBOL(arch_local_save_flags); | 
|  | 35 |  | 
|  | 36 | /* set interrupt enabled status */ | 
|  | 37 | void arch_local_irq_restore(unsigned long flags) | 
|  | 38 | { | 
|  | 39 | mtspr(SPR_SR, ((mfspr(SPR_SR) & ~(SPR_SR_IEE|SPR_SR_TEE)) | flags)); | 
|  | 40 | } | 
|  | 41 | EXPORT_SYMBOL(arch_local_irq_restore); | 
|  | 42 |  | 
|  | 43 |  | 
|  | 44 | /* OR1K PIC implementation */ | 
|  | 45 |  | 
|  | 46 | /* We're a couple of cycles faster than the generic implementations with | 
|  | 47 | * these 'fast' versions. | 
|  | 48 | */ | 
|  | 49 |  | 
|  | 50 | static void or1k_pic_mask(struct irq_data *data) | 
|  | 51 | { | 
|  | 52 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->irq)); | 
|  | 53 | } | 
|  | 54 |  | 
|  | 55 | static void or1k_pic_unmask(struct irq_data *data) | 
|  | 56 | { | 
|  | 57 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->irq)); | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | static void or1k_pic_ack(struct irq_data *data) | 
|  | 61 | { | 
|  | 62 | /* EDGE-triggered interrupts need to be ack'ed in order to clear | 
|  | 63 | * the latch. | 
|  | 64 | * LEVER-triggered interrupts do not need to be ack'ed; however, | 
|  | 65 | * ack'ing the interrupt has no ill-effect and is quicker than | 
|  | 66 | * trying to figure out what type it is... | 
|  | 67 | */ | 
|  | 68 |  | 
|  | 69 | /* The OpenRISC 1000 spec says to write a 1 to the bit to ack the | 
|  | 70 | * interrupt, but the OR1200 does this backwards and requires a 0 | 
|  | 71 | * to be written... | 
|  | 72 | */ | 
|  | 73 |  | 
|  | 74 | #ifdef CONFIG_OR1K_1200 | 
|  | 75 | /* There are two oddities with the OR1200 PIC implementation: | 
|  | 76 | * i)  LEVEL-triggered interrupts are latched and need to be cleared | 
|  | 77 | * ii) the interrupt latch is cleared by writing a 0 to the bit, | 
|  | 78 | *     as opposed to a 1 as mandated by the spec | 
|  | 79 | */ | 
|  | 80 |  | 
|  | 81 | mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->irq)); | 
|  | 82 | #else | 
|  | 83 | WARN(1, "Interrupt handling possibily broken\n"); | 
|  | 84 | mtspr(SPR_PICSR, (1UL << irq)); | 
|  | 85 | #endif | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | static void or1k_pic_mask_ack(struct irq_data *data) | 
|  | 89 | { | 
|  | 90 | /* Comments for pic_ack apply here, too */ | 
|  | 91 |  | 
|  | 92 | #ifdef CONFIG_OR1K_1200 | 
|  | 93 | mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->irq)); | 
|  | 94 | #else | 
|  | 95 | WARN(1, "Interrupt handling possibily broken\n"); | 
|  | 96 | mtspr(SPR_PICSR, (1UL << irq)); | 
|  | 97 | #endif | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | static int or1k_pic_set_type(struct irq_data *data, unsigned int flow_type) | 
|  | 101 | { | 
|  | 102 | /* There's nothing to do in the PIC configuration when changing | 
|  | 103 | * flow type.  Level and edge-triggered interrupts are both | 
|  | 104 | * supported, but it's PIC-implementation specific which type | 
|  | 105 | * is handled. */ | 
|  | 106 |  | 
|  | 107 | return irq_setup_alt_chip(data, flow_type); | 
|  | 108 | } | 
|  | 109 |  | 
|  | 110 | static inline int pic_get_irq(int first) | 
|  | 111 | { | 
|  | 112 | int irq; | 
|  | 113 |  | 
|  | 114 | irq = ffs(mfspr(SPR_PICSR) >> first); | 
|  | 115 |  | 
|  | 116 | return irq ? irq + first - 1 : NO_IRQ; | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | static void __init or1k_irq_init(void) | 
|  | 120 | { | 
|  | 121 | struct irq_chip_generic *gc; | 
|  | 122 | struct irq_chip_type *ct; | 
|  | 123 |  | 
|  | 124 | /* Disable all interrupts until explicitly requested */ | 
|  | 125 | mtspr(SPR_PICMR, (0UL)); | 
|  | 126 |  | 
|  | 127 | gc = irq_alloc_generic_chip("or1k-PIC", 1, 0, 0, handle_level_irq); | 
|  | 128 | ct = gc->chip_types; | 
|  | 129 |  | 
|  | 130 | ct->chip.irq_unmask = or1k_pic_unmask; | 
|  | 131 | ct->chip.irq_mask = or1k_pic_mask; | 
|  | 132 | ct->chip.irq_ack = or1k_pic_ack; | 
|  | 133 | ct->chip.irq_mask_ack = or1k_pic_mask_ack; | 
|  | 134 | ct->chip.irq_set_type = or1k_pic_set_type; | 
|  | 135 |  | 
|  | 136 | /* The OR1K PIC can handle both level and edge trigged | 
|  | 137 | * interrupts in roughly the same manner | 
|  | 138 | */ | 
|  | 139 | #if 0 | 
|  | 140 | /* FIXME: chip.type??? */ | 
|  | 141 | ct->chip.type = IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_MASK; | 
|  | 142 | #endif | 
|  | 143 |  | 
|  | 144 | irq_setup_generic_chip(gc, IRQ_MSK(NR_IRQS), 0, | 
|  | 145 | IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); | 
|  | 146 | } | 
|  | 147 |  | 
|  | 148 | void __init init_IRQ(void) | 
|  | 149 | { | 
|  | 150 | or1k_irq_init(); | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | void __irq_entry do_IRQ(struct pt_regs *regs) | 
|  | 154 | { | 
|  | 155 | int irq = -1; | 
|  | 156 | struct pt_regs *old_regs = set_irq_regs(regs); | 
|  | 157 |  | 
|  | 158 | irq_enter(); | 
|  | 159 |  | 
|  | 160 | while ((irq = pic_get_irq(irq + 1)) != NO_IRQ) | 
|  | 161 | generic_handle_irq(irq); | 
|  | 162 |  | 
|  | 163 | irq_exit(); | 
|  | 164 | set_irq_regs(old_regs); | 
|  | 165 | } | 
|  | 166 |  | 
|  | 167 | unsigned int irq_create_of_mapping(struct device_node *controller, | 
|  | 168 | const u32 *intspec, unsigned int intsize) | 
|  | 169 | { | 
|  | 170 | return intspec[0]; | 
|  | 171 | } | 
|  | 172 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); |