1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2024-2025 ARM Limited, All Rights Reserved. 4 */ 5 #define pr_fmt(fmt) "GICv5 IWB: " fmt 6 7 #include <linux/init.h> 8 #include <linux/kernel.h> 9 #include <linux/msi.h> 10 #include <linux/of.h> 11 #include <linux/of_address.h> 12 #include <linux/of_platform.h> 13 14 #include <linux/irqchip.h> 15 #include <linux/irqchip/arm-gic-v5.h> 16 17 struct gicv5_iwb_chip_data { 18 void __iomem *iwb_base; 19 u16 nr_regs; 20 }; 21 22 static u32 iwb_readl_relaxed(struct gicv5_iwb_chip_data *iwb_node, const u32 reg_offset) 23 { 24 return readl_relaxed(iwb_node->iwb_base + reg_offset); 25 } 26 27 static void iwb_writel_relaxed(struct gicv5_iwb_chip_data *iwb_node, const u32 val, 28 const u32 reg_offset) 29 { 30 writel_relaxed(val, iwb_node->iwb_base + reg_offset); 31 } 32 33 static int gicv5_iwb_wait_for_wenabler(struct gicv5_iwb_chip_data *iwb_node) 34 { 35 return gicv5_wait_for_op_atomic(iwb_node->iwb_base, GICV5_IWB_WENABLE_STATUSR, 36 GICV5_IWB_WENABLE_STATUSR_IDLE, NULL); 37 } 38 39 static int __gicv5_iwb_set_wire_enable(struct gicv5_iwb_chip_data *iwb_node, 40 u32 iwb_wire, bool enable) 41 { 42 u32 n = iwb_wire / 32; 43 u8 i = iwb_wire % 32; 44 u32 val; 45 46 if (n >= iwb_node->nr_regs) { 47 pr_err("IWB_WENABLER<n> is invalid for n=%u\n", n); 48 return -EINVAL; 49 } 50 51 /* 52 * Enable IWB wire/pin at this point 53 * Note: This is not the same as enabling the interrupt 54 */ 55 val = iwb_readl_relaxed(iwb_node, GICV5_IWB_WENABLER + (4 * n)); 56 if (enable) 57 val |= BIT(i); 58 else 59 val &= ~BIT(i); 60 iwb_writel_relaxed(iwb_node, val, GICV5_IWB_WENABLER + (4 * n)); 61 62 return gicv5_iwb_wait_for_wenabler(iwb_node); 63 } 64 65 static int gicv5_iwb_enable_wire(struct gicv5_iwb_chip_data *iwb_node, 66 u32 iwb_wire) 67 { 68 return __gicv5_iwb_set_wire_enable(iwb_node, iwb_wire, true); 69 } 70 71 static int gicv5_iwb_disable_wire(struct gicv5_iwb_chip_data *iwb_node, 72 u32 iwb_wire) 73 { 74 return __gicv5_iwb_set_wire_enable(iwb_node, iwb_wire, false); 75 } 76 77 static void gicv5_iwb_irq_disable(struct irq_data *d) 78 { 79 struct gicv5_iwb_chip_data *iwb_node = irq_data_get_irq_chip_data(d); 80 81 gicv5_iwb_disable_wire(iwb_node, d->hwirq); 82 irq_chip_disable_parent(d); 83 } 84 85 static void gicv5_iwb_irq_enable(struct irq_data *d) 86 { 87 struct gicv5_iwb_chip_data *iwb_node = irq_data_get_irq_chip_data(d); 88 89 gicv5_iwb_enable_wire(iwb_node, d->hwirq); 90 irq_chip_enable_parent(d); 91 } 92 93 static int gicv5_iwb_set_type(struct irq_data *d, unsigned int type) 94 { 95 struct gicv5_iwb_chip_data *iwb_node = irq_data_get_irq_chip_data(d); 96 u32 iwb_wire, n, wtmr; 97 u8 i; 98 99 iwb_wire = d->hwirq; 100 i = iwb_wire % 32; 101 n = iwb_wire / 32; 102 103 if (n >= iwb_node->nr_regs) { 104 pr_err_once("reg %u out of range\n", n); 105 return -EINVAL; 106 } 107 108 wtmr = iwb_readl_relaxed(iwb_node, GICV5_IWB_WTMR + (4 * n)); 109 110 switch (type) { 111 case IRQ_TYPE_LEVEL_HIGH: 112 case IRQ_TYPE_LEVEL_LOW: 113 wtmr |= BIT(i); 114 break; 115 case IRQ_TYPE_EDGE_RISING: 116 case IRQ_TYPE_EDGE_FALLING: 117 wtmr &= ~BIT(i); 118 break; 119 default: 120 pr_debug("unexpected wire trigger mode"); 121 return -EINVAL; 122 } 123 124 iwb_writel_relaxed(iwb_node, wtmr, GICV5_IWB_WTMR + (4 * n)); 125 126 return 0; 127 } 128 129 static void gicv5_iwb_domain_set_desc(msi_alloc_info_t *alloc_info, struct msi_desc *desc) 130 { 131 alloc_info->desc = desc; 132 alloc_info->hwirq = (u32)desc->data.icookie.value; 133 } 134 135 static int gicv5_iwb_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, 136 irq_hw_number_t *hwirq, 137 unsigned int *type) 138 { 139 if (!is_of_node(fwspec->fwnode)) 140 return -EINVAL; 141 142 if (fwspec->param_count < 2) 143 return -EINVAL; 144 145 /* 146 * param[0] is be the wire 147 * param[1] is the interrupt type 148 */ 149 *hwirq = fwspec->param[0]; 150 *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; 151 152 return 0; 153 } 154 155 static void gicv5_iwb_write_msi_msg(struct irq_data *d, struct msi_msg *msg) {} 156 157 static const struct msi_domain_template iwb_msi_template = { 158 .chip = { 159 .name = "GICv5-IWB", 160 .irq_mask = irq_chip_mask_parent, 161 .irq_unmask = irq_chip_unmask_parent, 162 .irq_enable = gicv5_iwb_irq_enable, 163 .irq_disable = gicv5_iwb_irq_disable, 164 .irq_eoi = irq_chip_eoi_parent, 165 .irq_set_type = gicv5_iwb_set_type, 166 .irq_write_msi_msg = gicv5_iwb_write_msi_msg, 167 .irq_set_affinity = irq_chip_set_affinity_parent, 168 .irq_get_irqchip_state = irq_chip_get_parent_state, 169 .irq_set_irqchip_state = irq_chip_set_parent_state, 170 .flags = IRQCHIP_SET_TYPE_MASKED | 171 IRQCHIP_SKIP_SET_WAKE | 172 IRQCHIP_MASK_ON_SUSPEND, 173 }, 174 175 .ops = { 176 .set_desc = gicv5_iwb_domain_set_desc, 177 .msi_translate = gicv5_iwb_irq_domain_translate, 178 }, 179 180 .info = { 181 .bus_token = DOMAIN_BUS_WIRED_TO_MSI, 182 .flags = MSI_FLAG_USE_DEV_FWNODE, 183 }, 184 185 .alloc_info = { 186 .flags = MSI_ALLOC_FLAGS_FIXED_MSG_DATA, 187 }, 188 }; 189 190 static bool gicv5_iwb_create_device_domain(struct device *dev, unsigned int size, 191 struct gicv5_iwb_chip_data *iwb_node) 192 { 193 if (WARN_ON_ONCE(!dev->msi.domain)) 194 return false; 195 196 return msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN, 197 &iwb_msi_template, size, 198 NULL, iwb_node); 199 } 200 201 static struct gicv5_iwb_chip_data * 202 gicv5_iwb_init_bases(void __iomem *iwb_base, struct platform_device *pdev) 203 { 204 u32 nr_wires, idr0, cr0; 205 unsigned int n; 206 int ret; 207 208 struct gicv5_iwb_chip_data *iwb_node __free(kfree) = kzalloc(sizeof(*iwb_node), 209 GFP_KERNEL); 210 if (!iwb_node) 211 return ERR_PTR(-ENOMEM); 212 213 iwb_node->iwb_base = iwb_base; 214 215 idr0 = iwb_readl_relaxed(iwb_node, GICV5_IWB_IDR0); 216 nr_wires = (FIELD_GET(GICV5_IWB_IDR0_IW_RANGE, idr0) + 1) * 32; 217 218 cr0 = iwb_readl_relaxed(iwb_node, GICV5_IWB_CR0); 219 if (!FIELD_GET(GICV5_IWB_CR0_IWBEN, cr0)) { 220 dev_err(&pdev->dev, "IWB must be enabled in firmware\n"); 221 return ERR_PTR(-EINVAL); 222 } 223 224 iwb_node->nr_regs = FIELD_GET(GICV5_IWB_IDR0_IW_RANGE, idr0) + 1; 225 226 for (n = 0; n < iwb_node->nr_regs; n++) 227 iwb_writel_relaxed(iwb_node, 0, GICV5_IWB_WENABLER + (sizeof(u32) * n)); 228 229 ret = gicv5_iwb_wait_for_wenabler(iwb_node); 230 if (ret) 231 return ERR_PTR(ret); 232 233 if (!gicv5_iwb_create_device_domain(&pdev->dev, nr_wires, iwb_node)) 234 return ERR_PTR(-ENOMEM); 235 236 return_ptr(iwb_node); 237 } 238 239 static int gicv5_iwb_device_probe(struct platform_device *pdev) 240 { 241 struct gicv5_iwb_chip_data *iwb_node; 242 void __iomem *iwb_base; 243 struct resource *res; 244 245 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 246 if (!res) 247 return -EINVAL; 248 249 iwb_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 250 if (!iwb_base) { 251 dev_err(&pdev->dev, "failed to ioremap %pR\n", res); 252 return -ENOMEM; 253 } 254 255 iwb_node = gicv5_iwb_init_bases(iwb_base, pdev); 256 if (IS_ERR(iwb_node)) 257 return PTR_ERR(iwb_node); 258 259 return 0; 260 } 261 262 static const struct of_device_id gicv5_iwb_of_match[] = { 263 { .compatible = "arm,gic-v5-iwb" }, 264 { /* END */ } 265 }; 266 MODULE_DEVICE_TABLE(of, gicv5_iwb_of_match); 267 268 static struct platform_driver gicv5_iwb_platform_driver = { 269 .driver = { 270 .name = "GICv5 IWB", 271 .of_match_table = gicv5_iwb_of_match, 272 .suppress_bind_attrs = true, 273 }, 274 .probe = gicv5_iwb_device_probe, 275 }; 276 277 module_platform_driver(gicv5_iwb_platform_driver); 278