ARM64: DTS: Add rk3399-firefly uart4 device, node as /dev/ttyS1
[firefly-linux-kernel-4.4.55.git] / cpuidle.c
1 /*
2  * Copyright (C) 2012 ROCKCHIP, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 #define pr_fmt(fmt) "cpuidle: %s: " fmt, __func__
10
11 #include <linux/pm.h>
12 #include <linux/cpuidle.h>
13 #include <linux/suspend.h>
14 #include <linux/err.h>
15
16 #include <asm/hardware/gic.h>
17 #include <asm/io.h>
18
19 static bool rk30_gic_interrupt_pending(void)
20 {
21         return (readl_relaxed(RK30_GICC_BASE + GIC_CPU_HIGHPRI) != 0x3FF);
22 }
23
24 static void rk30_wfi_until_interrupt(void)
25 {
26 retry:
27         cpu_do_idle();
28
29         if (!rk30_gic_interrupt_pending())
30                 goto retry;
31 }
32
33 static int rk30_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
34 {
35         ktime_t preidle, postidle;
36
37         local_fiq_disable();
38
39         preidle = ktime_get();
40
41         rk30_wfi_until_interrupt();
42
43         postidle = ktime_get();
44
45         local_fiq_enable();
46         local_irq_enable();
47
48         return ktime_to_us(ktime_sub(postidle, preidle));
49 }
50
51 static DEFINE_PER_CPU(struct cpuidle_device, rk30_cpuidle_device);
52
53 static __initdata struct cpuidle_state rk30_cpuidle_states[] = {
54         {
55                 .name = "C1",
56                 .desc = "idle",
57                 .flags = CPUIDLE_FLAG_TIME_VALID,
58                 .exit_latency = 0,
59                 .target_residency = 0,
60                 .enter = rk30_idle,
61         },
62 };
63
64 static struct cpuidle_driver rk30_cpuidle_driver = {
65         .name = "rk30_cpuidle",
66         .owner = THIS_MODULE,
67 };
68
69 static int __init rk30_cpuidle_init(void)
70 {
71         struct cpuidle_device *dev;
72         unsigned int cpu;
73         int ret;
74
75         ret = cpuidle_register_driver(&rk30_cpuidle_driver);
76         if (ret) {
77                 pr_err("failed to register cpuidle driver: %d\n", ret);
78                 return ret;
79         }
80
81         for_each_possible_cpu(cpu) {
82                 dev = &per_cpu(rk30_cpuidle_device, cpu);
83                 dev->cpu = cpu;
84                 dev->state_count = ARRAY_SIZE(rk30_cpuidle_states);
85                 memcpy(dev->states, rk30_cpuidle_states, sizeof(rk30_cpuidle_states));
86                 dev->safe_state = &dev->states[0];
87
88                 ret = cpuidle_register_device(dev);
89                 if (ret) {
90                         pr_err("failed to register cpuidle device for cpu %u: %d\n", cpu, ret);
91                         return ret;
92                 }
93         }
94
95         return 0;
96 }
97 late_initcall(rk30_cpuidle_init);