1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Renesas RZ/V2H(P) ICU Driver 4 * 5 * Based on irq-renesas-rzg2l.c 6 * 7 * Copyright (C) 2024 Renesas Electronics Corporation. 8 * 9 * Author: Fabrizio Castro <fabrizio.castro.jz@renesas.com> 10 */ 11 12 #include <linux/bitfield.h> 13 #include <linux/cleanup.h> 14 #include <linux/clk.h> 15 #include <linux/err.h> 16 #include <linux/io.h> 17 #include <linux/irqchip.h> 18 #include <linux/irqdomain.h> 19 #include <linux/of_address.h> 20 #include <linux/of_platform.h> 21 #include <linux/pm_runtime.h> 22 #include <linux/reset.h> 23 #include <linux/spinlock.h> 24 #include <linux/syscore_ops.h> 25 26 /* DT "interrupts" indexes */ 27 #define ICU_IRQ_START 1 28 #define ICU_IRQ_COUNT 16 29 #define ICU_TINT_START (ICU_IRQ_START + ICU_IRQ_COUNT) 30 #define ICU_TINT_COUNT 32 31 #define ICU_NUM_IRQ (ICU_TINT_START + ICU_TINT_COUNT) 32 33 /* Registers */ 34 #define ICU_NSCNT 0x00 35 #define ICU_NSCLR 0x04 36 #define ICU_NITSR 0x08 37 #define ICU_ISCTR 0x10 38 #define ICU_ISCLR 0x14 39 #define ICU_IITSR 0x18 40 #define ICU_TSCTR 0x20 41 #define ICU_TSCLR 0x24 42 #define ICU_TITSR(k) (0x28 + (k) * 4) 43 #define ICU_TSSR(k) (0x30 + (k) * 4) 44 45 /* NMI */ 46 #define ICU_NMI_EDGE_FALLING 0 47 #define ICU_NMI_EDGE_RISING 1 48 49 #define ICU_NSCLR_NCLR BIT(0) 50 51 /* IRQ */ 52 #define ICU_IRQ_LEVEL_LOW 0 53 #define ICU_IRQ_EDGE_FALLING 1 54 #define ICU_IRQ_EDGE_RISING 2 55 #define ICU_IRQ_EDGE_BOTH 3 56 57 #define ICU_IITSR_IITSEL_PREP(iitsel, n) ((iitsel) << ((n) * 2)) 58 #define ICU_IITSR_IITSEL_GET(iitsr, n) (((iitsr) >> ((n) * 2)) & 0x03) 59 #define ICU_IITSR_IITSEL_MASK(n) ICU_IITSR_IITSEL_PREP(0x03, n) 60 61 /* TINT */ 62 #define ICU_TINT_EDGE_RISING 0 63 #define ICU_TINT_EDGE_FALLING 1 64 #define ICU_TINT_LEVEL_HIGH 2 65 #define ICU_TINT_LEVEL_LOW 3 66 67 #define ICU_TSSR_K(tint_nr) ((tint_nr) / 4) 68 #define ICU_TSSR_TSSEL_N(tint_nr) ((tint_nr) % 4) 69 #define ICU_TSSR_TSSEL_PREP(tssel, n) ((tssel) << ((n) * 8)) 70 #define ICU_TSSR_TSSEL_MASK(n) ICU_TSSR_TSSEL_PREP(0x7F, n) 71 #define ICU_TSSR_TIEN(n) (BIT(7) << ((n) * 8)) 72 73 #define ICU_TITSR_K(tint_nr) ((tint_nr) / 16) 74 #define ICU_TITSR_TITSEL_N(tint_nr) ((tint_nr) % 16) 75 #define ICU_TITSR_TITSEL_PREP(titsel, n) ICU_IITSR_IITSEL_PREP(titsel, n) 76 #define ICU_TITSR_TITSEL_MASK(n) ICU_IITSR_IITSEL_MASK(n) 77 #define ICU_TITSR_TITSEL_GET(titsr, n) ICU_IITSR_IITSEL_GET(titsr, n) 78 79 #define ICU_TINT_EXTRACT_HWIRQ(x) FIELD_GET(GENMASK(15, 0), (x)) 80 #define ICU_TINT_EXTRACT_GPIOINT(x) FIELD_GET(GENMASK(31, 16), (x)) 81 #define ICU_PB5_TINT 0x55 82 83 /** 84 * struct rzv2h_icu_priv - Interrupt Control Unit controller private data structure. 85 * @base: Controller's base address 86 * @irqchip: Pointer to struct irq_chip 87 * @fwspec: IRQ firmware specific data 88 * @lock: Lock to serialize access to hardware registers 89 */ 90 struct rzv2h_icu_priv { 91 void __iomem *base; 92 const struct irq_chip *irqchip; 93 struct irq_fwspec fwspec[ICU_NUM_IRQ]; 94 raw_spinlock_t lock; 95 }; 96 97 static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data) 98 { 99 return data->domain->host_data; 100 } 101 102 static void rzv2h_icu_eoi(struct irq_data *d) 103 { 104 struct rzv2h_icu_priv *priv = irq_data_to_priv(d); 105 unsigned int hw_irq = irqd_to_hwirq(d); 106 unsigned int tintirq_nr; 107 u32 bit; 108 109 scoped_guard(raw_spinlock, &priv->lock) { 110 if (hw_irq >= ICU_TINT_START) { 111 tintirq_nr = hw_irq - ICU_TINT_START; 112 bit = BIT(tintirq_nr); 113 if (!irqd_is_level_type(d)) 114 writel_relaxed(bit, priv->base + ICU_TSCLR); 115 } else if (hw_irq >= ICU_IRQ_START) { 116 tintirq_nr = hw_irq - ICU_IRQ_START; 117 bit = BIT(tintirq_nr); 118 if (!irqd_is_level_type(d)) 119 writel_relaxed(bit, priv->base + ICU_ISCLR); 120 } else { 121 writel_relaxed(ICU_NSCLR_NCLR, priv->base + ICU_NSCLR); 122 } 123 } 124 125 irq_chip_eoi_parent(d); 126 } 127 128 static void rzv2h_tint_irq_endisable(struct irq_data *d, bool enable) 129 { 130 struct rzv2h_icu_priv *priv = irq_data_to_priv(d); 131 unsigned int hw_irq = irqd_to_hwirq(d); 132 u32 tint_nr, tssel_n, k, tssr; 133 134 if (hw_irq < ICU_TINT_START) 135 return; 136 137 tint_nr = hw_irq - ICU_TINT_START; 138 k = ICU_TSSR_K(tint_nr); 139 tssel_n = ICU_TSSR_TSSEL_N(tint_nr); 140 141 guard(raw_spinlock)(&priv->lock); 142 tssr = readl_relaxed(priv->base + ICU_TSSR(k)); 143 if (enable) 144 tssr |= ICU_TSSR_TIEN(tssel_n); 145 else 146 tssr &= ~ICU_TSSR_TIEN(tssel_n); 147 writel_relaxed(tssr, priv->base + ICU_TSSR(k)); 148 } 149 150 static void rzv2h_icu_irq_disable(struct irq_data *d) 151 { 152 irq_chip_disable_parent(d); 153 rzv2h_tint_irq_endisable(d, false); 154 } 155 156 static void rzv2h_icu_irq_enable(struct irq_data *d) 157 { 158 rzv2h_tint_irq_endisable(d, true); 159 irq_chip_enable_parent(d); 160 } 161 162 static int rzv2h_nmi_set_type(struct irq_data *d, unsigned int type) 163 { 164 struct rzv2h_icu_priv *priv = irq_data_to_priv(d); 165 u32 sense; 166 167 switch (type & IRQ_TYPE_SENSE_MASK) { 168 case IRQ_TYPE_EDGE_FALLING: 169 sense = ICU_NMI_EDGE_FALLING; 170 break; 171 172 case IRQ_TYPE_EDGE_RISING: 173 sense = ICU_NMI_EDGE_RISING; 174 break; 175 176 default: 177 return -EINVAL; 178 } 179 180 writel_relaxed(sense, priv->base + ICU_NITSR); 181 182 return 0; 183 } 184 185 static void rzv2h_clear_irq_int(struct rzv2h_icu_priv *priv, unsigned int hwirq) 186 { 187 unsigned int irq_nr = hwirq - ICU_IRQ_START; 188 u32 isctr, iitsr, iitsel; 189 u32 bit = BIT(irq_nr); 190 191 isctr = readl_relaxed(priv->base + ICU_ISCTR); 192 iitsr = readl_relaxed(priv->base + ICU_IITSR); 193 iitsel = ICU_IITSR_IITSEL_GET(iitsr, irq_nr); 194 195 /* 196 * When level sensing is used, the interrupt flag gets automatically cleared when the 197 * interrupt signal is de-asserted by the source of the interrupt request, therefore clear 198 * the interrupt only for edge triggered interrupts. 199 */ 200 if ((isctr & bit) && (iitsel != ICU_IRQ_LEVEL_LOW)) 201 writel_relaxed(bit, priv->base + ICU_ISCLR); 202 } 203 204 static int rzv2h_irq_set_type(struct irq_data *d, unsigned int type) 205 { 206 struct rzv2h_icu_priv *priv = irq_data_to_priv(d); 207 unsigned int hwirq = irqd_to_hwirq(d); 208 u32 irq_nr = hwirq - ICU_IRQ_START; 209 u32 iitsr, sense; 210 211 switch (type & IRQ_TYPE_SENSE_MASK) { 212 case IRQ_TYPE_LEVEL_LOW: 213 sense = ICU_IRQ_LEVEL_LOW; 214 break; 215 216 case IRQ_TYPE_EDGE_FALLING: 217 sense = ICU_IRQ_EDGE_FALLING; 218 break; 219 220 case IRQ_TYPE_EDGE_RISING: 221 sense = ICU_IRQ_EDGE_RISING; 222 break; 223 224 case IRQ_TYPE_EDGE_BOTH: 225 sense = ICU_IRQ_EDGE_BOTH; 226 break; 227 228 default: 229 return -EINVAL; 230 } 231 232 guard(raw_spinlock)(&priv->lock); 233 iitsr = readl_relaxed(priv->base + ICU_IITSR); 234 iitsr &= ~ICU_IITSR_IITSEL_MASK(irq_nr); 235 iitsr |= ICU_IITSR_IITSEL_PREP(sense, irq_nr); 236 rzv2h_clear_irq_int(priv, hwirq); 237 writel_relaxed(iitsr, priv->base + ICU_IITSR); 238 239 return 0; 240 } 241 242 static void rzv2h_clear_tint_int(struct rzv2h_icu_priv *priv, unsigned int hwirq) 243 { 244 unsigned int tint_nr = hwirq - ICU_TINT_START; 245 int titsel_n = ICU_TITSR_TITSEL_N(tint_nr); 246 u32 tsctr, titsr, titsel; 247 u32 bit = BIT(tint_nr); 248 int k = tint_nr / 16; 249 250 tsctr = readl_relaxed(priv->base + ICU_TSCTR); 251 titsr = readl_relaxed(priv->base + ICU_TITSR(k)); 252 titsel = ICU_TITSR_TITSEL_GET(titsr, titsel_n); 253 254 /* 255 * Writing 1 to the corresponding flag from register ICU_TSCTR only has effect if 256 * TSTATn = 1b and if it's a rising edge or a falling edge interrupt. 257 */ 258 if ((tsctr & bit) && ((titsel == ICU_TINT_EDGE_RISING) || 259 (titsel == ICU_TINT_EDGE_FALLING))) 260 writel_relaxed(bit, priv->base + ICU_TSCLR); 261 } 262 263 static int rzv2h_tint_set_type(struct irq_data *d, unsigned int type) 264 { 265 u32 titsr, titsr_k, titsel_n, tien; 266 struct rzv2h_icu_priv *priv; 267 u32 tssr, tssr_k, tssel_n; 268 unsigned int hwirq; 269 u32 tint, sense; 270 int tint_nr; 271 272 switch (type & IRQ_TYPE_SENSE_MASK) { 273 case IRQ_TYPE_LEVEL_LOW: 274 sense = ICU_TINT_LEVEL_LOW; 275 break; 276 277 case IRQ_TYPE_LEVEL_HIGH: 278 sense = ICU_TINT_LEVEL_HIGH; 279 break; 280 281 case IRQ_TYPE_EDGE_RISING: 282 sense = ICU_TINT_EDGE_RISING; 283 break; 284 285 case IRQ_TYPE_EDGE_FALLING: 286 sense = ICU_TINT_EDGE_FALLING; 287 break; 288 289 default: 290 return -EINVAL; 291 } 292 293 tint = (u32)(uintptr_t)irq_data_get_irq_chip_data(d); 294 if (tint > ICU_PB5_TINT) 295 return -EINVAL; 296 297 priv = irq_data_to_priv(d); 298 hwirq = irqd_to_hwirq(d); 299 300 tint_nr = hwirq - ICU_TINT_START; 301 302 tssr_k = ICU_TSSR_K(tint_nr); 303 tssel_n = ICU_TSSR_TSSEL_N(tint_nr); 304 305 titsr_k = ICU_TITSR_K(tint_nr); 306 titsel_n = ICU_TITSR_TITSEL_N(tint_nr); 307 tien = ICU_TSSR_TIEN(titsel_n); 308 309 guard(raw_spinlock)(&priv->lock); 310 311 tssr = readl_relaxed(priv->base + ICU_TSSR(tssr_k)); 312 tssr &= ~(ICU_TSSR_TSSEL_MASK(tssel_n) | tien); 313 tssr |= ICU_TSSR_TSSEL_PREP(tint, tssel_n); 314 315 writel_relaxed(tssr, priv->base + ICU_TSSR(tssr_k)); 316 317 titsr = readl_relaxed(priv->base + ICU_TITSR(titsr_k)); 318 titsr &= ~ICU_TITSR_TITSEL_MASK(titsel_n); 319 titsr |= ICU_TITSR_TITSEL_PREP(sense, titsel_n); 320 321 writel_relaxed(titsr, priv->base + ICU_TITSR(titsr_k)); 322 323 rzv2h_clear_tint_int(priv, hwirq); 324 325 writel_relaxed(tssr | tien, priv->base + ICU_TSSR(tssr_k)); 326 327 return 0; 328 } 329 330 static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type) 331 { 332 unsigned int hw_irq = irqd_to_hwirq(d); 333 int ret; 334 335 if (hw_irq >= ICU_TINT_START) 336 ret = rzv2h_tint_set_type(d, type); 337 else if (hw_irq >= ICU_IRQ_START) 338 ret = rzv2h_irq_set_type(d, type); 339 else 340 ret = rzv2h_nmi_set_type(d, type); 341 342 if (ret) 343 return ret; 344 345 return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH); 346 } 347 348 static const struct irq_chip rzv2h_icu_chip = { 349 .name = "rzv2h-icu", 350 .irq_eoi = rzv2h_icu_eoi, 351 .irq_mask = irq_chip_mask_parent, 352 .irq_unmask = irq_chip_unmask_parent, 353 .irq_disable = rzv2h_icu_irq_disable, 354 .irq_enable = rzv2h_icu_irq_enable, 355 .irq_get_irqchip_state = irq_chip_get_parent_state, 356 .irq_set_irqchip_state = irq_chip_set_parent_state, 357 .irq_retrigger = irq_chip_retrigger_hierarchy, 358 .irq_set_type = rzv2h_icu_set_type, 359 .irq_set_affinity = irq_chip_set_affinity_parent, 360 .flags = IRQCHIP_SET_TYPE_MASKED, 361 }; 362 363 static int rzv2h_icu_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, 364 void *arg) 365 { 366 struct rzv2h_icu_priv *priv = domain->host_data; 367 unsigned long tint = 0; 368 irq_hw_number_t hwirq; 369 unsigned int type; 370 int ret; 371 372 ret = irq_domain_translate_twocell(domain, arg, &hwirq, &type); 373 if (ret) 374 return ret; 375 376 /* 377 * For TINT interrupts the hwirq and TINT are encoded in 378 * fwspec->param[0]. 379 * hwirq is embedded in bits 0-15. 380 * TINT is embedded in bits 16-31. 381 */ 382 if (hwirq >= ICU_TINT_START) { 383 tint = ICU_TINT_EXTRACT_GPIOINT(hwirq); 384 hwirq = ICU_TINT_EXTRACT_HWIRQ(hwirq); 385 386 if (hwirq < ICU_TINT_START) 387 return -EINVAL; 388 } 389 390 if (hwirq > (ICU_NUM_IRQ - 1)) 391 return -EINVAL; 392 393 ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, priv->irqchip, 394 (void *)(uintptr_t)tint); 395 if (ret) 396 return ret; 397 398 return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &priv->fwspec[hwirq]); 399 } 400 401 static const struct irq_domain_ops rzv2h_icu_domain_ops = { 402 .alloc = rzv2h_icu_alloc, 403 .free = irq_domain_free_irqs_common, 404 .translate = irq_domain_translate_twocell, 405 }; 406 407 static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv *priv, struct device_node *np) 408 { 409 struct of_phandle_args map; 410 unsigned int i; 411 int ret; 412 413 for (i = 0; i < ICU_NUM_IRQ; i++) { 414 ret = of_irq_parse_one(np, i, &map); 415 if (ret) 416 return ret; 417 418 of_phandle_args_to_fwspec(np, map.args, map.args_count, &priv->fwspec[i]); 419 } 420 421 return 0; 422 } 423 424 static int rzv2h_icu_init(struct device_node *node, struct device_node *parent) 425 { 426 struct irq_domain *irq_domain, *parent_domain; 427 struct rzv2h_icu_priv *rzv2h_icu_data; 428 struct platform_device *pdev; 429 struct reset_control *resetn; 430 int ret; 431 432 pdev = of_find_device_by_node(node); 433 if (!pdev) 434 return -ENODEV; 435 436 parent_domain = irq_find_host(parent); 437 if (!parent_domain) { 438 dev_err(&pdev->dev, "cannot find parent domain\n"); 439 ret = -ENODEV; 440 goto put_dev; 441 } 442 443 rzv2h_icu_data = devm_kzalloc(&pdev->dev, sizeof(*rzv2h_icu_data), GFP_KERNEL); 444 if (!rzv2h_icu_data) { 445 ret = -ENOMEM; 446 goto put_dev; 447 } 448 449 rzv2h_icu_data->irqchip = &rzv2h_icu_chip; 450 451 rzv2h_icu_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL); 452 if (IS_ERR(rzv2h_icu_data->base)) { 453 ret = PTR_ERR(rzv2h_icu_data->base); 454 goto put_dev; 455 } 456 457 ret = rzv2h_icu_parse_interrupts(rzv2h_icu_data, node); 458 if (ret) { 459 dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret); 460 goto put_dev; 461 } 462 463 resetn = devm_reset_control_get_exclusive(&pdev->dev, NULL); 464 if (IS_ERR(resetn)) { 465 ret = PTR_ERR(resetn); 466 goto put_dev; 467 } 468 469 ret = reset_control_deassert(resetn); 470 if (ret) { 471 dev_err(&pdev->dev, "failed to deassert resetn pin, %d\n", ret); 472 goto put_dev; 473 } 474 475 pm_runtime_enable(&pdev->dev); 476 ret = pm_runtime_resume_and_get(&pdev->dev); 477 if (ret < 0) { 478 dev_err(&pdev->dev, "pm_runtime_resume_and_get failed: %d\n", ret); 479 goto pm_disable; 480 } 481 482 raw_spin_lock_init(&rzv2h_icu_data->lock); 483 484 irq_domain = irq_domain_add_hierarchy(parent_domain, 0, ICU_NUM_IRQ, node, 485 &rzv2h_icu_domain_ops, rzv2h_icu_data); 486 if (!irq_domain) { 487 dev_err(&pdev->dev, "failed to add irq domain\n"); 488 ret = -ENOMEM; 489 goto pm_put; 490 } 491 492 /* 493 * coccicheck complains about a missing put_device call before returning, but it's a false 494 * positive. We still need &pdev->dev after successfully returning from this function. 495 */ 496 return 0; 497 498 pm_put: 499 pm_runtime_put(&pdev->dev); 500 pm_disable: 501 pm_runtime_disable(&pdev->dev); 502 reset_control_assert(resetn); 503 put_dev: 504 put_device(&pdev->dev); 505 506 return ret; 507 } 508 509 IRQCHIP_PLATFORM_DRIVER_BEGIN(rzv2h_icu) 510 IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_init) 511 IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu) 512 MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro.jz@renesas.com>"); 513 MODULE_DESCRIPTION("Renesas RZ/V2H(P) ICU Driver"); 514