Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'irq-core-2024-01-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq subsystem updates from Ingo Molnar:

- Add support for the IA55 interrupt controller on RZ/G3S SoC's

- Update/fix the Qualcom MPM Interrupt Controller driver's register
enumeration within the somewhat exotic "RPM Message RAM" MMIO-mapped
shared memory region that is used for other purposes as well

- Clean up the Xtensa built-in Programmable Interrupt Controller driver
(xtensa-pic) a bit

* tag 'irq-core-2024-01-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
irqchip/irq-xtensa-pic: Clean up
irqchip/qcom-mpm: Support passing a slice of SRAM as reg space
dt-bindings: interrupt-controller: mpm: Pass MSG RAM slice through phandle
dt-bindings: interrupt-controller: renesas,rzg2l-irqc: Document RZ/G3S
irqchip/renesas-rzg2l: Add support for suspend to RAM
irqchip/renesas-rzg2l: Add macro to retrieve TITSR register offset based on register's index
irqchip/renesas-rzg2l: Implement restriction when writing ISCR register
irqchip/renesas-rzg2l: Document structure members
irqchip/renesas-rzg2l: Align struct member names to tabs
irqchip/renesas-rzg2l: Use tabs instead of spaces

+158 -68
+36 -18
Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml
··· 29 29 maxItems: 1 30 30 description: 31 31 Specifies the base address and size of vMPM registers in RPM MSG RAM. 32 + deprecated: true 33 + 34 + qcom,rpm-msg-ram: 35 + $ref: /schemas/types.yaml#/definitions/phandle 36 + description: 37 + Phandle to the APSS MPM slice of the RPM Message RAM 32 38 33 39 interrupts: 34 40 maxItems: 1 ··· 73 67 74 68 required: 75 69 - compatible 76 - - reg 77 70 - interrupts 78 71 - mboxes 79 72 - interrupt-controller 80 73 - '#interrupt-cells' 81 74 - qcom,mpm-pin-count 82 75 - qcom,mpm-pin-map 76 + - qcom,rpm-msg-ram 83 77 84 78 additionalProperties: false 85 79 86 80 examples: 87 81 - | 88 82 #include <dt-bindings/interrupt-controller/arm-gic.h> 89 - mpm: interrupt-controller@45f01b8 { 90 - compatible = "qcom,mpm"; 91 - interrupts = <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>; 92 - reg = <0x45f01b8 0x1000>; 93 - mboxes = <&apcs_glb 1>; 94 - interrupt-controller; 95 - #interrupt-cells = <2>; 96 - interrupt-parent = <&intc>; 97 - qcom,mpm-pin-count = <96>; 98 - qcom,mpm-pin-map = <2 275>, 99 - <5 296>, 100 - <12 422>, 101 - <24 79>, 102 - <86 183>, 103 - <90 260>, 104 - <91 260>; 105 - #power-domain-cells = <0>; 83 + 84 + remoteproc-rpm { 85 + compatible = "qcom,msm8998-rpm-proc", "qcom,rpm-proc"; 86 + 87 + glink-edge { 88 + compatible = "qcom,glink-rpm"; 89 + 90 + interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>; 91 + qcom,rpm-msg-ram = <&rpm_msg_ram>; 92 + mboxes = <&apcs_glb 0>; 93 + }; 94 + 95 + mpm: interrupt-controller { 96 + compatible = "qcom,mpm"; 97 + qcom,rpm-msg-ram = <&apss_mpm>; 98 + interrupts = <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>; 99 + mboxes = <&apcs_glb 1>; 100 + interrupt-controller; 101 + #interrupt-cells = <2>; 102 + interrupt-parent = <&intc>; 103 + qcom,mpm-pin-count = <96>; 104 + qcom,mpm-pin-map = <2 275>, 105 + <5 296>, 106 + <12 422>, 107 + <24 79>, 108 + <86 183>, 109 + <91 260>; 110 + #power-domain-cells = <0>; 111 + }; 106 112 };
+4 -1
Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml
··· 26 26 - renesas,r9a07g043u-irqc # RZ/G2UL 27 27 - renesas,r9a07g044-irqc # RZ/G2{L,LC} 28 28 - renesas,r9a07g054-irqc # RZ/V2L 29 + - renesas,r9a08g045-irqc # RZ/G3S 29 30 - const: renesas,rzg2l-irqc 30 31 31 32 '#interrupt-cells': ··· 168 167 properties: 169 168 compatible: 170 169 contains: 171 - const: renesas,r9a07g043u-irqc 170 + enum: 171 + - renesas,r9a07g043u-irqc 172 + - renesas,r9a08g045-irqc 172 173 then: 173 174 properties: 174 175 interrupts:
+23 -3
drivers/irqchip/irq-qcom-mpm.c
··· 14 14 #include <linux/mailbox_client.h> 15 15 #include <linux/module.h> 16 16 #include <linux/of.h> 17 + #include <linux/of_address.h> 17 18 #include <linux/of_platform.h> 18 19 #include <linux/platform_device.h> 19 20 #include <linux/pm_domain.h> ··· 323 322 struct device *dev = &pdev->dev; 324 323 struct irq_domain *parent_domain; 325 324 struct generic_pm_domain *genpd; 325 + struct device_node *msgram_np; 326 326 struct qcom_mpm_priv *priv; 327 327 unsigned int pin_cnt; 328 + struct resource res; 328 329 int i, irq; 329 330 int ret; 330 331 ··· 377 374 378 375 raw_spin_lock_init(&priv->lock); 379 376 380 - priv->base = devm_platform_ioremap_resource(pdev, 0); 381 - if (IS_ERR(priv->base)) 382 - return PTR_ERR(priv->base); 377 + /* If we have a handle to an RPM message ram partition, use it. */ 378 + msgram_np = of_parse_phandle(np, "qcom,rpm-msg-ram", 0); 379 + if (msgram_np) { 380 + ret = of_address_to_resource(msgram_np, 0, &res); 381 + if (ret) { 382 + of_node_put(msgram_np); 383 + return ret; 384 + } 385 + 386 + /* Don't use devm_ioremap_resource, as we're accessing a shared region. */ 387 + priv->base = devm_ioremap(dev, res.start, resource_size(&res)); 388 + of_node_put(msgram_np); 389 + if (IS_ERR(priv->base)) 390 + return PTR_ERR(priv->base); 391 + } else { 392 + /* Otherwise, fall back to simple MMIO. */ 393 + priv->base = devm_platform_ioremap_resource(pdev, 0); 394 + if (IS_ERR(priv->base)) 395 + return PTR_ERR(priv->base); 396 + } 383 397 384 398 for (i = 0; i < priv->reg_stride; i++) { 385 399 qcom_mpm_write(priv, MPM_REG_ENABLE, i, 0);
+83 -27
drivers/irqchip/irq-renesas-rzg2l.c
··· 18 18 #include <linux/pm_runtime.h> 19 19 #include <linux/reset.h> 20 20 #include <linux/spinlock.h> 21 + #include <linux/syscore_ops.h> 21 22 22 23 #define IRQC_IRQ_START 1 23 24 #define IRQC_IRQ_COUNT 8 ··· 29 28 #define ISCR 0x10 30 29 #define IITSR 0x14 31 30 #define TSCR 0x20 32 - #define TITSR0 0x24 33 - #define TITSR1 0x28 31 + #define TITSR(n) (0x24 + (n) * 4) 34 32 #define TITSR0_MAX_INT 16 35 33 #define TITSEL_WIDTH 0x2 36 34 #define TSSR(n) (0x30 + ((n) * 4)) ··· 53 53 #define IITSR_IITSEL_EDGE_BOTH 3 54 54 #define IITSR_IITSEL_MASK(n) IITSR_IITSEL((n), 3) 55 55 56 - #define TINT_EXTRACT_HWIRQ(x) FIELD_GET(GENMASK(15, 0), (x)) 57 - #define TINT_EXTRACT_GPIOINT(x) FIELD_GET(GENMASK(31, 16), (x)) 56 + #define TINT_EXTRACT_HWIRQ(x) FIELD_GET(GENMASK(15, 0), (x)) 57 + #define TINT_EXTRACT_GPIOINT(x) FIELD_GET(GENMASK(31, 16), (x)) 58 58 59 - struct rzg2l_irqc_priv { 60 - void __iomem *base; 61 - struct irq_fwspec fwspec[IRQC_NUM_IRQ]; 62 - raw_spinlock_t lock; 59 + /** 60 + * struct rzg2l_irqc_reg_cache - registers cache (necessary for suspend/resume) 61 + * @iitsr: IITSR register 62 + * @titsr: TITSR registers 63 + */ 64 + struct rzg2l_irqc_reg_cache { 65 + u32 iitsr; 66 + u32 titsr[2]; 63 67 }; 68 + 69 + /** 70 + * struct rzg2l_irqc_priv - IRQ controller private data structure 71 + * @base: Controller's base address 72 + * @fwspec: IRQ firmware specific data 73 + * @lock: Lock to serialize access to hardware registers 74 + * @cache: Registers cache for suspend/resume 75 + */ 76 + static struct rzg2l_irqc_priv { 77 + void __iomem *base; 78 + struct irq_fwspec fwspec[IRQC_NUM_IRQ]; 79 + raw_spinlock_t lock; 80 + struct rzg2l_irqc_reg_cache cache; 81 + } *rzg2l_irqc_data; 64 82 65 83 static struct rzg2l_irqc_priv *irq_data_to_priv(struct irq_data *data) 66 84 { ··· 90 72 unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START; 91 73 struct rzg2l_irqc_priv *priv = irq_data_to_priv(d); 92 74 u32 bit = BIT(hw_irq); 93 - u32 reg; 75 + u32 iitsr, iscr; 94 76 95 - reg = readl_relaxed(priv->base + ISCR); 96 - if (reg & bit) 97 - writel_relaxed(reg & ~bit, priv->base + ISCR); 77 + iscr = readl_relaxed(priv->base + ISCR); 78 + iitsr = readl_relaxed(priv->base + IITSR); 79 + 80 + /* 81 + * ISCR can only be cleared if the type is falling-edge, rising-edge or 82 + * falling/rising-edge. 83 + */ 84 + if ((iscr & bit) && (iitsr & IITSR_IITSEL_MASK(hw_irq))) 85 + writel_relaxed(iscr & ~bit, priv->base + ISCR); 98 86 } 99 87 100 88 static void rzg2l_tint_eoi(struct irq_data *d) ··· 212 188 struct rzg2l_irqc_priv *priv = irq_data_to_priv(d); 213 189 unsigned int hwirq = irqd_to_hwirq(d); 214 190 u32 titseln = hwirq - IRQC_TINT_START; 215 - u32 offset; 216 - u8 sense; 191 + u8 index, sense; 217 192 u32 reg; 218 193 219 194 switch (type & IRQ_TYPE_SENSE_MASK) { ··· 228 205 return -EINVAL; 229 206 } 230 207 231 - offset = TITSR0; 208 + index = 0; 232 209 if (titseln >= TITSR0_MAX_INT) { 233 210 titseln -= TITSR0_MAX_INT; 234 - offset = TITSR1; 211 + index = 1; 235 212 } 236 213 237 214 raw_spin_lock(&priv->lock); 238 - reg = readl_relaxed(priv->base + offset); 215 + reg = readl_relaxed(priv->base + TITSR(index)); 239 216 reg &= ~(IRQ_MASK << (titseln * TITSEL_WIDTH)); 240 217 reg |= sense << (titseln * TITSEL_WIDTH); 241 - writel_relaxed(reg, priv->base + offset); 218 + writel_relaxed(reg, priv->base + TITSR(index)); 242 219 raw_spin_unlock(&priv->lock); 243 220 244 221 return 0; ··· 258 235 259 236 return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH); 260 237 } 238 + 239 + static int rzg2l_irqc_irq_suspend(void) 240 + { 241 + struct rzg2l_irqc_reg_cache *cache = &rzg2l_irqc_data->cache; 242 + void __iomem *base = rzg2l_irqc_data->base; 243 + 244 + cache->iitsr = readl_relaxed(base + IITSR); 245 + for (u8 i = 0; i < 2; i++) 246 + cache->titsr[i] = readl_relaxed(base + TITSR(i)); 247 + 248 + return 0; 249 + } 250 + 251 + static void rzg2l_irqc_irq_resume(void) 252 + { 253 + struct rzg2l_irqc_reg_cache *cache = &rzg2l_irqc_data->cache; 254 + void __iomem *base = rzg2l_irqc_data->base; 255 + 256 + /* 257 + * Restore only interrupt type. TSSRx will be restored at the 258 + * request of pin controller to avoid spurious interrupts due 259 + * to invalid PIN states. 260 + */ 261 + for (u8 i = 0; i < 2; i++) 262 + writel_relaxed(cache->titsr[i], base + TITSR(i)); 263 + writel_relaxed(cache->iitsr, base + IITSR); 264 + } 265 + 266 + static struct syscore_ops rzg2l_irqc_syscore_ops = { 267 + .suspend = rzg2l_irqc_irq_suspend, 268 + .resume = rzg2l_irqc_irq_resume, 269 + }; 261 270 262 271 static const struct irq_chip irqc_chip = { 263 272 .name = "rzg2l-irqc", ··· 376 321 struct irq_domain *irq_domain, *parent_domain; 377 322 struct platform_device *pdev; 378 323 struct reset_control *resetn; 379 - struct rzg2l_irqc_priv *priv; 380 324 int ret; 381 325 382 326 pdev = of_find_device_by_node(node); ··· 388 334 return -ENODEV; 389 335 } 390 336 391 - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 392 - if (!priv) 337 + rzg2l_irqc_data = devm_kzalloc(&pdev->dev, sizeof(*rzg2l_irqc_data), GFP_KERNEL); 338 + if (!rzg2l_irqc_data) 393 339 return -ENOMEM; 394 340 395 - priv->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL); 396 - if (IS_ERR(priv->base)) 397 - return PTR_ERR(priv->base); 341 + rzg2l_irqc_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL); 342 + if (IS_ERR(rzg2l_irqc_data->base)) 343 + return PTR_ERR(rzg2l_irqc_data->base); 398 344 399 - ret = rzg2l_irqc_parse_interrupts(priv, node); 345 + ret = rzg2l_irqc_parse_interrupts(rzg2l_irqc_data, node); 400 346 if (ret) { 401 347 dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret); 402 348 return ret; ··· 419 365 goto pm_disable; 420 366 } 421 367 422 - raw_spin_lock_init(&priv->lock); 368 + raw_spin_lock_init(&rzg2l_irqc_data->lock); 423 369 424 370 irq_domain = irq_domain_add_hierarchy(parent_domain, 0, IRQC_NUM_IRQ, 425 371 node, &rzg2l_irqc_domain_ops, 426 - priv); 372 + rzg2l_irqc_data); 427 373 if (!irq_domain) { 428 374 dev_err(&pdev->dev, "failed to add irq domain\n"); 429 375 ret = -ENOMEM; 430 376 goto pm_put; 431 377 } 378 + 379 + register_syscore_ops(&rzg2l_irqc_syscore_ops); 432 380 433 381 return 0; 434 382
+12 -19
drivers/irqchip/irq-xtensa-pic.c
··· 12 12 * Kevin Chea 13 13 */ 14 14 15 + #include <linux/bits.h> 15 16 #include <linux/interrupt.h> 16 17 #include <linux/irqdomain.h> 17 18 #include <linux/irq.h> 18 19 #include <linux/irqchip.h> 19 20 #include <linux/irqchip/xtensa-pic.h> 20 21 #include <linux/of.h> 21 - 22 - unsigned int cached_irq_mask; 23 22 24 23 /* 25 24 * Device Tree IRQ specifier translation function which works with one or ··· 43 44 44 45 static void xtensa_irq_mask(struct irq_data *d) 45 46 { 46 - cached_irq_mask &= ~(1 << d->hwirq); 47 - xtensa_set_sr(cached_irq_mask, intenable); 47 + u32 irq_mask; 48 + 49 + irq_mask = xtensa_get_sr(intenable); 50 + irq_mask &= ~BIT(d->hwirq); 51 + xtensa_set_sr(irq_mask, intenable); 48 52 } 49 53 50 54 static void xtensa_irq_unmask(struct irq_data *d) 51 55 { 52 - cached_irq_mask |= 1 << d->hwirq; 53 - xtensa_set_sr(cached_irq_mask, intenable); 54 - } 56 + u32 irq_mask; 55 57 56 - static void xtensa_irq_enable(struct irq_data *d) 57 - { 58 - xtensa_irq_unmask(d); 59 - } 60 - 61 - static void xtensa_irq_disable(struct irq_data *d) 62 - { 63 - xtensa_irq_mask(d); 58 + irq_mask = xtensa_get_sr(intenable); 59 + irq_mask |= BIT(d->hwirq); 60 + xtensa_set_sr(irq_mask, intenable); 64 61 } 65 62 66 63 static void xtensa_irq_ack(struct irq_data *d) 67 64 { 68 - xtensa_set_sr(1 << d->hwirq, intclear); 65 + xtensa_set_sr(BIT(d->hwirq), intclear); 69 66 } 70 67 71 68 static int xtensa_irq_retrigger(struct irq_data *d) 72 69 { 73 - unsigned int mask = 1u << d->hwirq; 70 + unsigned int mask = BIT(d->hwirq); 74 71 75 72 if (WARN_ON(mask & ~XCHAL_INTTYPE_MASK_SOFTWARE)) 76 73 return 0; ··· 76 81 77 82 static struct irq_chip xtensa_irq_chip = { 78 83 .name = "xtensa", 79 - .irq_enable = xtensa_irq_enable, 80 - .irq_disable = xtensa_irq_disable, 81 84 .irq_mask = xtensa_irq_mask, 82 85 .irq_unmask = xtensa_irq_unmask, 83 86 .irq_ack = xtensa_irq_ack,