diff options
| -rw-r--r-- | arch/arm/common/gic.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 337741f734ac..7dfa9a85bc0c 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c | |||
| @@ -108,6 +108,51 @@ static void gic_unmask_irq(unsigned int irq) | |||
| 108 | spin_unlock(&irq_controller_lock); | 108 | spin_unlock(&irq_controller_lock); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static int gic_set_type(unsigned int irq, unsigned int type) | ||
| 112 | { | ||
| 113 | void __iomem *base = gic_dist_base(irq); | ||
| 114 | unsigned int gicirq = gic_irq(irq); | ||
| 115 | u32 enablemask = 1 << (gicirq % 32); | ||
| 116 | u32 enableoff = (gicirq / 32) * 4; | ||
| 117 | u32 confmask = 0x2 << ((gicirq % 16) * 2); | ||
| 118 | u32 confoff = (gicirq / 16) * 4; | ||
| 119 | bool enabled = false; | ||
| 120 | u32 val; | ||
| 121 | |||
| 122 | /* Interrupt configuration for SGIs can't be changed */ | ||
| 123 | if (gicirq < 16) | ||
| 124 | return -EINVAL; | ||
| 125 | |||
| 126 | if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING) | ||
| 127 | return -EINVAL; | ||
| 128 | |||
| 129 | spin_lock(&irq_controller_lock); | ||
| 130 | |||
| 131 | val = readl(base + GIC_DIST_CONFIG + confoff); | ||
| 132 | if (type == IRQ_TYPE_LEVEL_HIGH) | ||
| 133 | val &= ~confmask; | ||
| 134 | else if (type == IRQ_TYPE_EDGE_RISING) | ||
| 135 | val |= confmask; | ||
| 136 | |||
| 137 | /* | ||
| 138 | * As recommended by the spec, disable the interrupt before changing | ||
| 139 | * the configuration | ||
| 140 | */ | ||
| 141 | if (readl(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) { | ||
| 142 | writel(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff); | ||
| 143 | enabled = true; | ||
| 144 | } | ||
| 145 | |||
| 146 | writel(val, base + GIC_DIST_CONFIG + confoff); | ||
| 147 | |||
| 148 | if (enabled) | ||
| 149 | writel(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); | ||
| 150 | |||
| 151 | spin_unlock(&irq_controller_lock); | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 111 | #ifdef CONFIG_SMP | 156 | #ifdef CONFIG_SMP |
| 112 | static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val) | 157 | static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val) |
| 113 | { | 158 | { |
| @@ -161,6 +206,7 @@ static struct irq_chip gic_chip = { | |||
| 161 | .ack = gic_ack_irq, | 206 | .ack = gic_ack_irq, |
| 162 | .mask = gic_mask_irq, | 207 | .mask = gic_mask_irq, |
| 163 | .unmask = gic_unmask_irq, | 208 | .unmask = gic_unmask_irq, |
| 209 | .set_type = gic_set_type, | ||
| 164 | #ifdef CONFIG_SMP | 210 | #ifdef CONFIG_SMP |
| 165 | .set_affinity = gic_set_cpu, | 211 | .set_affinity = gic_set_cpu, |
| 166 | #endif | 212 | #endif |
