root/drivers/irqchip/irq-vic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vic_init2
  2. resume_one_vic
  3. vic_resume
  4. suspend_one_vic
  5. vic_suspend
  6. vic_pm_init
  7. vic_irqdomain_map
  8. handle_one_vic
  9. vic_handle_irq_cascaded
  10. vic_handle_irq
  11. vic_register
  12. vic_ack_irq
  13. vic_mask_irq
  14. vic_unmask_irq
  15. vic_from_irq
  16. vic_set_wake
  17. vic_disable
  18. vic_clear_interrupts
  19. vic_init_st
  20. __vic_init
  21. vic_init
  22. vic_init_cascaded
  23. vic_of_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  linux/arch/arm/common/vic.c
   4  *
   5  *  Copyright (C) 1999 - 2003 ARM Limited
   6  *  Copyright (C) 2000 Deep Blue Solutions Ltd
   7  */
   8 
   9 #include <linux/export.h>
  10 #include <linux/init.h>
  11 #include <linux/list.h>
  12 #include <linux/io.h>
  13 #include <linux/irq.h>
  14 #include <linux/irqchip.h>
  15 #include <linux/irqchip/chained_irq.h>
  16 #include <linux/irqdomain.h>
  17 #include <linux/of.h>
  18 #include <linux/of_address.h>
  19 #include <linux/of_irq.h>
  20 #include <linux/syscore_ops.h>
  21 #include <linux/device.h>
  22 #include <linux/amba/bus.h>
  23 #include <linux/irqchip/arm-vic.h>
  24 
  25 #include <asm/exception.h>
  26 #include <asm/irq.h>
  27 
  28 #define VIC_IRQ_STATUS                  0x00
  29 #define VIC_FIQ_STATUS                  0x04
  30 #define VIC_INT_SELECT                  0x0c    /* 1 = FIQ, 0 = IRQ */
  31 #define VIC_INT_SOFT                    0x18
  32 #define VIC_INT_SOFT_CLEAR              0x1c
  33 #define VIC_PROTECT                     0x20
  34 #define VIC_PL190_VECT_ADDR             0x30    /* PL190 only */
  35 #define VIC_PL190_DEF_VECT_ADDR         0x34    /* PL190 only */
  36 
  37 #define VIC_VECT_ADDR0                  0x100   /* 0 to 15 (0..31 PL192) */
  38 #define VIC_VECT_CNTL0                  0x200   /* 0 to 15 (0..31 PL192) */
  39 #define VIC_ITCR                        0x300   /* VIC test control register */
  40 
  41 #define VIC_VECT_CNTL_ENABLE            (1 << 5)
  42 
  43 #define VIC_PL192_VECT_ADDR             0xF00
  44 
  45 /**
  46  * struct vic_device - VIC PM device
  47  * @parent_irq: The parent IRQ number of the VIC if cascaded, or 0.
  48  * @irq: The IRQ number for the base of the VIC.
  49  * @base: The register base for the VIC.
  50  * @valid_sources: A bitmask of valid interrupts
  51  * @resume_sources: A bitmask of interrupts for resume.
  52  * @resume_irqs: The IRQs enabled for resume.
  53  * @int_select: Save for VIC_INT_SELECT.
  54  * @int_enable: Save for VIC_INT_ENABLE.
  55  * @soft_int: Save for VIC_INT_SOFT.
  56  * @protect: Save for VIC_PROTECT.
  57  * @domain: The IRQ domain for the VIC.
  58  */
  59 struct vic_device {
  60         void __iomem    *base;
  61         int             irq;
  62         u32             valid_sources;
  63         u32             resume_sources;
  64         u32             resume_irqs;
  65         u32             int_select;
  66         u32             int_enable;
  67         u32             soft_int;
  68         u32             protect;
  69         struct irq_domain *domain;
  70 };
  71 
  72 /* we cannot allocate memory when VICs are initially registered */
  73 static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
  74 
  75 static int vic_id;
  76 
  77 static void vic_handle_irq(struct pt_regs *regs);
  78 
  79 /**
  80  * vic_init2 - common initialisation code
  81  * @base: Base of the VIC.
  82  *
  83  * Common initialisation code for registration
  84  * and resume.
  85 */
  86 static void vic_init2(void __iomem *base)
  87 {
  88         int i;
  89 
  90         for (i = 0; i < 16; i++) {
  91                 void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
  92                 writel(VIC_VECT_CNTL_ENABLE | i, reg);
  93         }
  94 
  95         writel(32, base + VIC_PL190_DEF_VECT_ADDR);
  96 }
  97 
  98 #ifdef CONFIG_PM
  99 static void resume_one_vic(struct vic_device *vic)
 100 {
 101         void __iomem *base = vic->base;
 102 
 103         printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base);
 104 
 105         /* re-initialise static settings */
 106         vic_init2(base);
 107 
 108         writel(vic->int_select, base + VIC_INT_SELECT);
 109         writel(vic->protect, base + VIC_PROTECT);
 110 
 111         /* set the enabled ints and then clear the non-enabled */
 112         writel(vic->int_enable, base + VIC_INT_ENABLE);
 113         writel(~vic->int_enable, base + VIC_INT_ENABLE_CLEAR);
 114 
 115         /* and the same for the soft-int register */
 116 
 117         writel(vic->soft_int, base + VIC_INT_SOFT);
 118         writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR);
 119 }
 120 
 121 static void vic_resume(void)
 122 {
 123         int id;
 124 
 125         for (id = vic_id - 1; id >= 0; id--)
 126                 resume_one_vic(vic_devices + id);
 127 }
 128 
 129 static void suspend_one_vic(struct vic_device *vic)
 130 {
 131         void __iomem *base = vic->base;
 132 
 133         printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base);
 134 
 135         vic->int_select = readl(base + VIC_INT_SELECT);
 136         vic->int_enable = readl(base + VIC_INT_ENABLE);
 137         vic->soft_int = readl(base + VIC_INT_SOFT);
 138         vic->protect = readl(base + VIC_PROTECT);
 139 
 140         /* set the interrupts (if any) that are used for
 141          * resuming the system */
 142 
 143         writel(vic->resume_irqs, base + VIC_INT_ENABLE);
 144         writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR);
 145 }
 146 
 147 static int vic_suspend(void)
 148 {
 149         int id;
 150 
 151         for (id = 0; id < vic_id; id++)
 152                 suspend_one_vic(vic_devices + id);
 153 
 154         return 0;
 155 }
 156 
 157 static struct syscore_ops vic_syscore_ops = {
 158         .suspend        = vic_suspend,
 159         .resume         = vic_resume,
 160 };
 161 
 162 /**
 163  * vic_pm_init - initicall to register VIC pm
 164  *
 165  * This is called via late_initcall() to register
 166  * the resources for the VICs due to the early
 167  * nature of the VIC's registration.
 168 */
 169 static int __init vic_pm_init(void)
 170 {
 171         if (vic_id > 0)
 172                 register_syscore_ops(&vic_syscore_ops);
 173 
 174         return 0;
 175 }
 176 late_initcall(vic_pm_init);
 177 #endif /* CONFIG_PM */
 178 
 179 static struct irq_chip vic_chip;
 180 
 181 static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq,
 182                              irq_hw_number_t hwirq)
 183 {
 184         struct vic_device *v = d->host_data;
 185 
 186         /* Skip invalid IRQs, only register handlers for the real ones */
 187         if (!(v->valid_sources & (1 << hwirq)))
 188                 return -EPERM;
 189         irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq);
 190         irq_set_chip_data(irq, v->base);
 191         irq_set_probe(irq);
 192         return 0;
 193 }
 194 
 195 /*
 196  * Handle each interrupt in a single VIC.  Returns non-zero if we've
 197  * handled at least one interrupt.  This reads the status register
 198  * before handling each interrupt, which is necessary given that
 199  * handle_IRQ may briefly re-enable interrupts for soft IRQ handling.
 200  */
 201 static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
 202 {
 203         u32 stat, irq;
 204         int handled = 0;
 205 
 206         while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
 207                 irq = ffs(stat) - 1;
 208                 handle_domain_irq(vic->domain, irq, regs);
 209                 handled = 1;
 210         }
 211 
 212         return handled;
 213 }
 214 
 215 static void vic_handle_irq_cascaded(struct irq_desc *desc)
 216 {
 217         u32 stat, hwirq;
 218         struct irq_chip *host_chip = irq_desc_get_chip(desc);
 219         struct vic_device *vic = irq_desc_get_handler_data(desc);
 220 
 221         chained_irq_enter(host_chip, desc);
 222 
 223         while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
 224                 hwirq = ffs(stat) - 1;
 225                 generic_handle_irq(irq_find_mapping(vic->domain, hwirq));
 226         }
 227 
 228         chained_irq_exit(host_chip, desc);
 229 }
 230 
 231 /*
 232  * Keep iterating over all registered VIC's until there are no pending
 233  * interrupts.
 234  */
 235 static void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
 236 {
 237         int i, handled;
 238 
 239         do {
 240                 for (i = 0, handled = 0; i < vic_id; ++i)
 241                         handled |= handle_one_vic(&vic_devices[i], regs);
 242         } while (handled);
 243 }
 244 
 245 static const struct irq_domain_ops vic_irqdomain_ops = {
 246         .map = vic_irqdomain_map,
 247         .xlate = irq_domain_xlate_onetwocell,
 248 };
 249 
 250 /**
 251  * vic_register() - Register a VIC.
 252  * @base: The base address of the VIC.
 253  * @parent_irq: The parent IRQ if cascaded, else 0.
 254  * @irq: The base IRQ for the VIC.
 255  * @valid_sources: bitmask of valid interrupts
 256  * @resume_sources: bitmask of interrupts allowed for resume sources.
 257  * @node: The device tree node associated with the VIC.
 258  *
 259  * Register the VIC with the system device tree so that it can be notified
 260  * of suspend and resume requests and ensure that the correct actions are
 261  * taken to re-instate the settings on resume.
 262  *
 263  * This also configures the IRQ domain for the VIC.
 264  */
 265 static void __init vic_register(void __iomem *base, unsigned int parent_irq,
 266                                 unsigned int irq,
 267                                 u32 valid_sources, u32 resume_sources,
 268                                 struct device_node *node)
 269 {
 270         struct vic_device *v;
 271         int i;
 272 
 273         if (vic_id >= ARRAY_SIZE(vic_devices)) {
 274                 printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
 275                 return;
 276         }
 277 
 278         v = &vic_devices[vic_id];
 279         v->base = base;
 280         v->valid_sources = valid_sources;
 281         v->resume_sources = resume_sources;
 282         set_handle_irq(vic_handle_irq);
 283         vic_id++;
 284 
 285         if (parent_irq) {
 286                 irq_set_chained_handler_and_data(parent_irq,
 287                                                  vic_handle_irq_cascaded, v);
 288         }
 289 
 290         v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
 291                                           &vic_irqdomain_ops, v);
 292         /* create an IRQ mapping for each valid IRQ */
 293         for (i = 0; i < fls(valid_sources); i++)
 294                 if (valid_sources & (1 << i))
 295                         irq_create_mapping(v->domain, i);
 296         /* If no base IRQ was passed, figure out our allocated base */
 297         if (irq)
 298                 v->irq = irq;
 299         else
 300                 v->irq = irq_find_mapping(v->domain, 0);
 301 }
 302 
 303 static void vic_ack_irq(struct irq_data *d)
 304 {
 305         void __iomem *base = irq_data_get_irq_chip_data(d);
 306         unsigned int irq = d->hwirq;
 307         writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
 308         /* moreover, clear the soft-triggered, in case it was the reason */
 309         writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
 310 }
 311 
 312 static void vic_mask_irq(struct irq_data *d)
 313 {
 314         void __iomem *base = irq_data_get_irq_chip_data(d);
 315         unsigned int irq = d->hwirq;
 316         writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
 317 }
 318 
 319 static void vic_unmask_irq(struct irq_data *d)
 320 {
 321         void __iomem *base = irq_data_get_irq_chip_data(d);
 322         unsigned int irq = d->hwirq;
 323         writel(1 << irq, base + VIC_INT_ENABLE);
 324 }
 325 
 326 #if defined(CONFIG_PM)
 327 static struct vic_device *vic_from_irq(unsigned int irq)
 328 {
 329         struct vic_device *v = vic_devices;
 330         unsigned int base_irq = irq & ~31;
 331         int id;
 332 
 333         for (id = 0; id < vic_id; id++, v++) {
 334                 if (v->irq == base_irq)
 335                         return v;
 336         }
 337 
 338         return NULL;
 339 }
 340 
 341 static int vic_set_wake(struct irq_data *d, unsigned int on)
 342 {
 343         struct vic_device *v = vic_from_irq(d->irq);
 344         unsigned int off = d->hwirq;
 345         u32 bit = 1 << off;
 346 
 347         if (!v)
 348                 return -EINVAL;
 349 
 350         if (!(bit & v->resume_sources))
 351                 return -EINVAL;
 352 
 353         if (on)
 354                 v->resume_irqs |= bit;
 355         else
 356                 v->resume_irqs &= ~bit;
 357 
 358         return 0;
 359 }
 360 #else
 361 #define vic_set_wake NULL
 362 #endif /* CONFIG_PM */
 363 
 364 static struct irq_chip vic_chip = {
 365         .name           = "VIC",
 366         .irq_ack        = vic_ack_irq,
 367         .irq_mask       = vic_mask_irq,
 368         .irq_unmask     = vic_unmask_irq,
 369         .irq_set_wake   = vic_set_wake,
 370 };
 371 
 372 static void __init vic_disable(void __iomem *base)
 373 {
 374         writel(0, base + VIC_INT_SELECT);
 375         writel(0, base + VIC_INT_ENABLE);
 376         writel(~0, base + VIC_INT_ENABLE_CLEAR);
 377         writel(0, base + VIC_ITCR);
 378         writel(~0, base + VIC_INT_SOFT_CLEAR);
 379 }
 380 
 381 static void __init vic_clear_interrupts(void __iomem *base)
 382 {
 383         unsigned int i;
 384 
 385         writel(0, base + VIC_PL190_VECT_ADDR);
 386         for (i = 0; i < 19; i++) {
 387                 unsigned int value;
 388 
 389                 value = readl(base + VIC_PL190_VECT_ADDR);
 390                 writel(value, base + VIC_PL190_VECT_ADDR);
 391         }
 392 }
 393 
 394 /*
 395  * The PL190 cell from ARM has been modified by ST to handle 64 interrupts.
 396  * The original cell has 32 interrupts, while the modified one has 64,
 397  * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case
 398  * the probe function is called twice, with base set to offset 000
 399  *  and 020 within the page. We call this "second block".
 400  */
 401 static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 402                                u32 vic_sources, struct device_node *node)
 403 {
 404         unsigned int i;
 405         int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0;
 406 
 407         /* Disable all interrupts initially. */
 408         vic_disable(base);
 409 
 410         /*
 411          * Make sure we clear all existing interrupts. The vector registers
 412          * in this cell are after the second block of general registers,
 413          * so we can address them using standard offsets, but only from
 414          * the second base address, which is 0x20 in the page
 415          */
 416         if (vic_2nd_block) {
 417                 vic_clear_interrupts(base);
 418 
 419                 /* ST has 16 vectors as well, but we don't enable them by now */
 420                 for (i = 0; i < 16; i++) {
 421                         void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4);
 422                         writel(0, reg);
 423                 }
 424 
 425                 writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 426         }
 427 
 428         vic_register(base, 0, irq_start, vic_sources, 0, node);
 429 }
 430 
 431 void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
 432                               u32 vic_sources, u32 resume_sources,
 433                               struct device_node *node)
 434 {
 435         unsigned int i;
 436         u32 cellid = 0;
 437         enum amba_vendor vendor;
 438 
 439         /* Identify which VIC cell this one is, by reading the ID */
 440         for (i = 0; i < 4; i++) {
 441                 void __iomem *addr;
 442                 addr = (void __iomem *)((u32)base & PAGE_MASK) + 0xfe0 + (i * 4);
 443                 cellid |= (readl(addr) & 0xff) << (8 * i);
 444         }
 445         vendor = (cellid >> 12) & 0xff;
 446         printk(KERN_INFO "VIC @%p: id 0x%08x, vendor 0x%02x\n",
 447                base, cellid, vendor);
 448 
 449         switch(vendor) {
 450         case AMBA_VENDOR_ST:
 451                 vic_init_st(base, irq_start, vic_sources, node);
 452                 return;
 453         default:
 454                 printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
 455                 /* fall through */
 456         case AMBA_VENDOR_ARM:
 457                 break;
 458         }
 459 
 460         /* Disable all interrupts initially. */
 461         vic_disable(base);
 462 
 463         /* Make sure we clear all existing interrupts */
 464         vic_clear_interrupts(base);
 465 
 466         vic_init2(base);
 467 
 468         vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node);
 469 }
 470 
 471 /**
 472  * vic_init() - initialise a vectored interrupt controller
 473  * @base: iomem base address
 474  * @irq_start: starting interrupt number, must be muliple of 32
 475  * @vic_sources: bitmask of interrupt sources to allow
 476  * @resume_sources: bitmask of interrupt sources to allow for resume
 477  */
 478 void __init vic_init(void __iomem *base, unsigned int irq_start,
 479                      u32 vic_sources, u32 resume_sources)
 480 {
 481         __vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
 482 }
 483 
 484 /**
 485  * vic_init_cascaded() - initialise a cascaded vectored interrupt controller
 486  * @base: iomem base address
 487  * @parent_irq: the parent IRQ we're cascaded off
 488  * @vic_sources: bitmask of interrupt sources to allow
 489  * @resume_sources: bitmask of interrupt sources to allow for resume
 490  *
 491  * This returns the base for the new interrupts or negative on error.
 492  */
 493 int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
 494                               u32 vic_sources, u32 resume_sources)
 495 {
 496         struct vic_device *v;
 497 
 498         v = &vic_devices[vic_id];
 499         __vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
 500         /* Return out acquired base */
 501         return v->irq;
 502 }
 503 EXPORT_SYMBOL_GPL(vic_init_cascaded);
 504 
 505 #ifdef CONFIG_OF
 506 static int __init vic_of_init(struct device_node *node,
 507                               struct device_node *parent)
 508 {
 509         void __iomem *regs;
 510         u32 interrupt_mask = ~0;
 511         u32 wakeup_mask = ~0;
 512 
 513         if (WARN(parent, "non-root VICs are not supported"))
 514                 return -EINVAL;
 515 
 516         regs = of_iomap(node, 0);
 517         if (WARN_ON(!regs))
 518                 return -EIO;
 519 
 520         of_property_read_u32(node, "valid-mask", &interrupt_mask);
 521         of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
 522 
 523         /*
 524          * Passing 0 as first IRQ makes the simple domain allocate descriptors
 525          */
 526         __vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
 527 
 528         return 0;
 529 }
 530 IRQCHIP_DECLARE(arm_pl190_vic, "arm,pl190-vic", vic_of_init);
 531 IRQCHIP_DECLARE(arm_pl192_vic, "arm,pl192-vic", vic_of_init);
 532 IRQCHIP_DECLARE(arm_versatile_vic, "arm,versatile-vic", vic_of_init);
 533 #endif /* CONFIG OF */

/* [<][>][^][v][top][bottom][index][help] */