1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2002 ARM Limited, All Rights Reserved. 4 */ 5 6#include <linux/interrupt.h> 7#include <linux/io.h> 8#include <linux/irq.h> 9#include <linux/irqchip/arm-gic.h> 10 11#include "irq-gic-common.h" 12 13static DEFINE_RAW_SPINLOCK(irq_controller_lock); 14 15static const struct gic_kvm_info *gic_kvm_info; 16 17const struct gic_kvm_info *gic_get_kvm_info(void) 18{ 19 return gic_kvm_info; 20} 21 22void gic_set_kvm_info(const struct gic_kvm_info *info) 23{ 24 BUG_ON(gic_kvm_info != NULL); 25 gic_kvm_info = info; 26} 27 28void gic_enable_of_quirks(const struct device_node *np, 29 const struct gic_quirk *quirks, void *data) 30{ 31 for (; quirks->desc; quirks++) { 32 if (!quirks->compatible && !quirks->property) 33 continue; 34 if (quirks->compatible && 35 !of_device_is_compatible(np, quirks->compatible)) 36 continue; 37 if (quirks->property && 38 !of_property_read_bool(np, quirks->property)) 39 continue; 40 if (quirks->init(data)) 41 pr_info("GIC: enabling workaround for %s\n", 42 quirks->desc); 43 } 44} 45 46void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, 47 void *data) 48{ 49 for (; quirks->desc; quirks++) { 50 if (quirks->compatible || quirks->property) 51 continue; 52 if (quirks->iidr != (quirks->mask & iidr)) 53 continue; 54 if (quirks->init(data)) 55 pr_info("GIC: enabling workaround for %s\n", 56 quirks->desc); 57 } 58} 59 60int gic_configure_irq(unsigned int irq, unsigned int type, 61 void __iomem *base, void (*sync_access)(void)) 62{ 63 u32 confmask = 0x2 << ((irq % 16) * 2); 64 u32 confoff = (irq / 16) * 4; 65 u32 val, oldval; 66 int ret = 0; 67 unsigned long flags; 68 69 /* 70 * Read current configuration register, and insert the config 71 * for "irq", depending on "type". 72 */ 73 raw_spin_lock_irqsave(&irq_controller_lock, flags); 74 val = oldval = readl_relaxed(base + confoff); 75 if (type & IRQ_TYPE_LEVEL_MASK) 76 val &= ~confmask; 77 else if (type & IRQ_TYPE_EDGE_BOTH) 78 val |= confmask; 79 80 /* If the current configuration is the same, then we are done */ 81 if (val == oldval) { 82 raw_spin_unlock_irqrestore(&irq_controller_lock, flags); 83 return 0; 84 } 85 86 /* 87 * Write back the new configuration, and possibly re-enable 88 * the interrupt. If we fail to write a new configuration for 89 * an SPI then WARN and return an error. If we fail to write the 90 * configuration for a PPI this is most likely because the GIC 91 * does not allow us to set the configuration or we are in a 92 * non-secure mode, and hence it may not be catastrophic. 93 */ 94 writel_relaxed(val, base + confoff); 95 if (readl_relaxed(base + confoff) != val) 96 ret = -EINVAL; 97 98 raw_spin_unlock_irqrestore(&irq_controller_lock, flags); 99 100 if (sync_access) 101 sync_access(); 102 103 return ret; 104} 105 106void gic_dist_config(void __iomem *base, int gic_irqs, 107 void (*sync_access)(void)) 108{ 109 unsigned int i; 110 111 /* 112 * Set all global interrupts to be level triggered, active low. 113 */ 114 for (i = 32; i < gic_irqs; i += 16) 115 writel_relaxed(GICD_INT_ACTLOW_LVLTRIG, 116 base + GIC_DIST_CONFIG + i / 4); 117 118 /* 119 * Set priority on all global interrupts. 120 */ 121 for (i = 32; i < gic_irqs; i += 4) 122 writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i); 123 124 /* 125 * Deactivate and disable all SPIs. Leave the PPI and SGIs 126 * alone as they are in the redistributor registers on GICv3. 127 */ 128 for (i = 32; i < gic_irqs; i += 32) { 129 writel_relaxed(GICD_INT_EN_CLR_X32, 130 base + GIC_DIST_ACTIVE_CLEAR + i / 8); 131 writel_relaxed(GICD_INT_EN_CLR_X32, 132 base + GIC_DIST_ENABLE_CLEAR + i / 8); 133 } 134 135 if (sync_access) 136 sync_access(); 137} 138 139void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void)) 140{ 141 int i; 142 143 /* 144 * Deal with the banked PPI and SGI interrupts - disable all 145 * private interrupts. Make sure everything is deactivated. 146 */ 147 for (i = 0; i < nr; i += 32) { 148 writel_relaxed(GICD_INT_EN_CLR_X32, 149 base + GIC_DIST_ACTIVE_CLEAR + i / 8); 150 writel_relaxed(GICD_INT_EN_CLR_X32, 151 base + GIC_DIST_ENABLE_CLEAR + i / 8); 152 } 153 154 /* 155 * Set priority on PPI and SGI interrupts 156 */ 157 for (i = 0; i < nr; i += 4) 158 writel_relaxed(GICD_INT_DEF_PRI_X4, 159 base + GIC_DIST_PRI + i * 4 / 4); 160 161 if (sync_access) 162 sync_access(); 163} 164