26
26
#include <linux/kernel.h>
27
27
#include <linux/list.h>
28
28
#include <linux/smp.h>
29
+ #include <linux/cpu_pm.h>
29
30
#include <linux/cpumask.h>
30
31
#include <linux/io.h>
31
32
@@ -276,6 +277,8 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
276
277
if (gic_irqs > 1020 )
277
278
gic_irqs = 1020 ;
278
279
280
+ gic -> gic_irqs = gic_irqs ;
281
+
279
282
/*
280
283
* Set all global interrupts to be level triggered, active low.
281
284
*/
@@ -343,6 +346,189 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
343
346
writel_relaxed (1 , base + GIC_CPU_CTRL );
344
347
}
345
348
349
+ #ifdef CONFIG_CPU_PM
350
+ /*
351
+ * Saves the GIC distributor registers during suspend or idle. Must be called
352
+ * with interrupts disabled but before powering down the GIC. After calling
353
+ * this function, no interrupts will be delivered by the GIC, and another
354
+ * platform-specific wakeup source must be enabled.
355
+ */
356
+ static void gic_dist_save (unsigned int gic_nr )
357
+ {
358
+ unsigned int gic_irqs ;
359
+ void __iomem * dist_base ;
360
+ int i ;
361
+
362
+ if (gic_nr >= MAX_GIC_NR )
363
+ BUG ();
364
+
365
+ gic_irqs = gic_data [gic_nr ].gic_irqs ;
366
+ dist_base = gic_data [gic_nr ].dist_base ;
367
+
368
+ if (!dist_base )
369
+ return ;
370
+
371
+ for (i = 0 ; i < DIV_ROUND_UP (gic_irqs , 16 ); i ++ )
372
+ gic_data [gic_nr ].saved_spi_conf [i ] =
373
+ readl_relaxed (dist_base + GIC_DIST_CONFIG + i * 4 );
374
+
375
+ for (i = 0 ; i < DIV_ROUND_UP (gic_irqs , 4 ); i ++ )
376
+ gic_data [gic_nr ].saved_spi_target [i ] =
377
+ readl_relaxed (dist_base + GIC_DIST_TARGET + i * 4 );
378
+
379
+ for (i = 0 ; i < DIV_ROUND_UP (gic_irqs , 32 ); i ++ )
380
+ gic_data [gic_nr ].saved_spi_enable [i ] =
381
+ readl_relaxed (dist_base + GIC_DIST_ENABLE_SET + i * 4 );
382
+ }
383
+
384
+ /*
385
+ * Restores the GIC distributor registers during resume or when coming out of
386
+ * idle. Must be called before enabling interrupts. If a level interrupt
387
+ * that occured while the GIC was suspended is still present, it will be
388
+ * handled normally, but any edge interrupts that occured will not be seen by
389
+ * the GIC and need to be handled by the platform-specific wakeup source.
390
+ */
391
+ static void gic_dist_restore (unsigned int gic_nr )
392
+ {
393
+ unsigned int gic_irqs ;
394
+ unsigned int i ;
395
+ void __iomem * dist_base ;
396
+
397
+ if (gic_nr >= MAX_GIC_NR )
398
+ BUG ();
399
+
400
+ gic_irqs = gic_data [gic_nr ].gic_irqs ;
401
+ dist_base = gic_data [gic_nr ].dist_base ;
402
+
403
+ if (!dist_base )
404
+ return ;
405
+
406
+ writel_relaxed (0 , dist_base + GIC_DIST_CTRL );
407
+
408
+ for (i = 0 ; i < DIV_ROUND_UP (gic_irqs , 16 ); i ++ )
409
+ writel_relaxed (gic_data [gic_nr ].saved_spi_conf [i ],
410
+ dist_base + GIC_DIST_CONFIG + i * 4 );
411
+
412
+ for (i = 0 ; i < DIV_ROUND_UP (gic_irqs , 4 ); i ++ )
413
+ writel_relaxed (0xa0a0a0a0 ,
414
+ dist_base + GIC_DIST_PRI + i * 4 );
415
+
416
+ for (i = 0 ; i < DIV_ROUND_UP (gic_irqs , 4 ); i ++ )
417
+ writel_relaxed (gic_data [gic_nr ].saved_spi_target [i ],
418
+ dist_base + GIC_DIST_TARGET + i * 4 );
419
+
420
+ for (i = 0 ; i < DIV_ROUND_UP (gic_irqs , 32 ); i ++ )
421
+ writel_relaxed (gic_data [gic_nr ].saved_spi_enable [i ],
422
+ dist_base + GIC_DIST_ENABLE_SET + i * 4 );
423
+
424
+ writel_relaxed (1 , dist_base + GIC_DIST_CTRL );
425
+ }
426
+
427
+ static void gic_cpu_save (unsigned int gic_nr )
428
+ {
429
+ int i ;
430
+ u32 * ptr ;
431
+ void __iomem * dist_base ;
432
+ void __iomem * cpu_base ;
433
+
434
+ if (gic_nr >= MAX_GIC_NR )
435
+ BUG ();
436
+
437
+ dist_base = gic_data [gic_nr ].dist_base ;
438
+ cpu_base = gic_data [gic_nr ].cpu_base ;
439
+
440
+ if (!dist_base || !cpu_base )
441
+ return ;
442
+
443
+ ptr = __this_cpu_ptr (gic_data [gic_nr ].saved_ppi_enable );
444
+ for (i = 0 ; i < DIV_ROUND_UP (32 , 32 ); i ++ )
445
+ ptr [i ] = readl_relaxed (dist_base + GIC_DIST_ENABLE_SET + i * 4 );
446
+
447
+ ptr = __this_cpu_ptr (gic_data [gic_nr ].saved_ppi_conf );
448
+ for (i = 0 ; i < DIV_ROUND_UP (32 , 16 ); i ++ )
449
+ ptr [i ] = readl_relaxed (dist_base + GIC_DIST_CONFIG + i * 4 );
450
+
451
+ }
452
+
453
+ static void gic_cpu_restore (unsigned int gic_nr )
454
+ {
455
+ int i ;
456
+ u32 * ptr ;
457
+ void __iomem * dist_base ;
458
+ void __iomem * cpu_base ;
459
+
460
+ if (gic_nr >= MAX_GIC_NR )
461
+ BUG ();
462
+
463
+ dist_base = gic_data [gic_nr ].dist_base ;
464
+ cpu_base = gic_data [gic_nr ].cpu_base ;
465
+
466
+ if (!dist_base || !cpu_base )
467
+ return ;
468
+
469
+ ptr = __this_cpu_ptr (gic_data [gic_nr ].saved_ppi_enable );
470
+ for (i = 0 ; i < DIV_ROUND_UP (32 , 32 ); i ++ )
471
+ writel_relaxed (ptr [i ], dist_base + GIC_DIST_ENABLE_SET + i * 4 );
472
+
473
+ ptr = __this_cpu_ptr (gic_data [gic_nr ].saved_ppi_conf );
474
+ for (i = 0 ; i < DIV_ROUND_UP (32 , 16 ); i ++ )
475
+ writel_relaxed (ptr [i ], dist_base + GIC_DIST_CONFIG + i * 4 );
476
+
477
+ for (i = 0 ; i < DIV_ROUND_UP (32 , 4 ); i ++ )
478
+ writel_relaxed (0xa0a0a0a0 , dist_base + GIC_DIST_PRI + i * 4 );
479
+
480
+ writel_relaxed (0xf0 , cpu_base + GIC_CPU_PRIMASK );
481
+ writel_relaxed (1 , cpu_base + GIC_CPU_CTRL );
482
+ }
483
+
484
+ static int gic_notifier (struct notifier_block * self , unsigned long cmd , void * v )
485
+ {
486
+ int i ;
487
+
488
+ for (i = 0 ; i < MAX_GIC_NR ; i ++ ) {
489
+ switch (cmd ) {
490
+ case CPU_PM_ENTER :
491
+ gic_cpu_save (i );
492
+ break ;
493
+ case CPU_PM_ENTER_FAILED :
494
+ case CPU_PM_EXIT :
495
+ gic_cpu_restore (i );
496
+ break ;
497
+ case CPU_CLUSTER_PM_ENTER :
498
+ gic_dist_save (i );
499
+ break ;
500
+ case CPU_CLUSTER_PM_ENTER_FAILED :
501
+ case CPU_CLUSTER_PM_EXIT :
502
+ gic_dist_restore (i );
503
+ break ;
504
+ }
505
+ }
506
+
507
+ return NOTIFY_OK ;
508
+ }
509
+
510
+ static struct notifier_block gic_notifier_block = {
511
+ .notifier_call = gic_notifier ,
512
+ };
513
+
514
+ static void __init gic_pm_init (struct gic_chip_data * gic )
515
+ {
516
+ gic -> saved_ppi_enable = __alloc_percpu (DIV_ROUND_UP (32 , 32 ) * 4 ,
517
+ sizeof (u32 ));
518
+ BUG_ON (!gic -> saved_ppi_enable );
519
+
520
+ gic -> saved_ppi_conf = __alloc_percpu (DIV_ROUND_UP (32 , 16 ) * 4 ,
521
+ sizeof (u32 ));
522
+ BUG_ON (!gic -> saved_ppi_conf );
523
+
524
+ cpu_pm_register_notifier (& gic_notifier_block );
525
+ }
526
+ #else
527
+ static void __init gic_pm_init (struct gic_chip_data * gic )
528
+ {
529
+ }
530
+ #endif
531
+
346
532
void __init gic_init (unsigned int gic_nr , unsigned int irq_start ,
347
533
void __iomem * dist_base , void __iomem * cpu_base )
348
534
{
@@ -358,8 +544,10 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
358
544
if (gic_nr == 0 )
359
545
gic_cpu_base_addr = cpu_base ;
360
546
547
+ gic_chip .flags |= gic_arch_extn .flags ;
361
548
gic_dist_init (gic , irq_start );
362
549
gic_cpu_init (gic );
550
+ gic_pm_init (gic );
363
551
}
364
552
365
553
void __cpuinit gic_secondary_init (unsigned int gic_nr )
0 commit comments