This source file includes following definitions.
- vic_init2
- resume_one_vic
- vic_resume
- suspend_one_vic
- vic_suspend
- vic_pm_init
- vic_irqdomain_map
- handle_one_vic
- vic_handle_irq_cascaded
- vic_handle_irq
- vic_register
- vic_ack_irq
- vic_mask_irq
- vic_unmask_irq
- vic_from_irq
- vic_set_wake
- vic_disable
- vic_clear_interrupts
- vic_init_st
- __vic_init
- vic_init
- vic_init_cascaded
- vic_of_init
   1 
   2 
   3 
   4 
   5 
   6 
   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    
  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    
  35 #define VIC_PL190_DEF_VECT_ADDR         0x34    
  36 
  37 #define VIC_VECT_ADDR0                  0x100   
  38 #define VIC_VECT_CNTL0                  0x200   
  39 #define VIC_ITCR                        0x300   
  40 
  41 #define VIC_VECT_CNTL_ENABLE            (1 << 5)
  42 
  43 #define VIC_PL192_VECT_ADDR             0xF00
  44 
  45 
  46 
  47 
  48 
  49 
  50 
  51 
  52 
  53 
  54 
  55 
  56 
  57 
  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 
  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 
  81 
  82 
  83 
  84 
  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         
 106         vic_init2(base);
 107 
 108         writel(vic->int_select, base + VIC_INT_SELECT);
 109         writel(vic->protect, base + VIC_PROTECT);
 110 
 111         
 112         writel(vic->int_enable, base + VIC_INT_ENABLE);
 113         writel(~vic->int_enable, base + VIC_INT_ENABLE_CLEAR);
 114 
 115         
 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         
 141 
 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 
 164 
 165 
 166 
 167 
 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 
 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         
 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 
 197 
 198 
 199 
 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 
 233 
 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 
 252 
 253 
 254 
 255 
 256 
 257 
 258 
 259 
 260 
 261 
 262 
 263 
 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         
 293         for (i = 0; i < fls(valid_sources); i++)
 294                 if (valid_sources & (1 << i))
 295                         irq_create_mapping(v->domain, i);
 296         
 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         
 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 
 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 
 396 
 397 
 398 
 399 
 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         
 408         vic_disable(base);
 409 
 410         
 411 
 412 
 413 
 414 
 415 
 416         if (vic_2nd_block) {
 417                 vic_clear_interrupts(base);
 418 
 419                 
 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         
 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                 
 456         case AMBA_VENDOR_ARM:
 457                 break;
 458         }
 459 
 460         
 461         vic_disable(base);
 462 
 463         
 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 
 473 
 474 
 475 
 476 
 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 
 486 
 487 
 488 
 489 
 490 
 491 
 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         
 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 
 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