linux os can config sleep mode
[firefly-linux-kernel-4.4.55.git] / arch / arm64 / mach-rockchip / pm-rk3368.c
1 /*
2  *
3  * Copyright (C) 2015, Fuzhou Rockchip Electronics Co., Ltd
4  * Author: Tony.Xie
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19 #include <linux/module.h>
20 #include <linux/of.h>
21 #include <asm/io.h>
22 #include <linux/of.h>
23 #include <linux/of_address.h>
24 #include <asm/compiler.h>
25
26 #define PSCI_OS_SUSPEND_CTRBITS (0xa600ffc0)
27
28 #define SEC_REG_RW_SHT (0x0)
29 #define SEC_REG_RD (0x0)
30 #define SEC_REG_WR (0x1)
31
32 #define SEC_REG_BITS_SHT (0x1)
33 #define SEC_REG_32 (0x0)
34 #define SEC_REG_64 (0x2)
35
36 #define SEC_REG_RD_32 (SEC_REG_RD | SEC_REG_32)
37 #define SEC_REG_RD_64 (SEC_REG_RD | SEC_REG_64)
38 #define SEC_REG_WR_32 (SEC_REG_WR | SEC_REG_32)
39 #define SEC_REG_WR_64 (SEC_REG_WR | SEC_REG_64)
40
41 /*
42  * arg2: rd/wr control, bit[0] 0-rd 1-rt, bit[1] 0-32bit, 1-64bit
43  * arg1: base addr
44  * arg0: read or write val
45  * function_id: return fail/succes
46  */
47 static noinline int __invoke_reg_pm_wr_fn_smc(u64 function_id, u64 arg0, u64 arg1,
48                                          u64 arg2)
49 {
50         asm volatile(
51                         __asmeq("%0", "x0")
52                         __asmeq("%1", "x1")
53                         __asmeq("%2", "x2")
54                         __asmeq("%3", "x3")
55                         "smc    #0\n"
56                 : "+r" (function_id) ,"+r" (arg0)
57                 : "r" (arg1), "r" (arg2));
58
59         return function_id;
60 }
61 static noinline int __invoke_reg_pm_rd_fn_smc(u64 function_id, u64 arg0, u64 arg1,
62                                          u64 arg2, u64 *val)
63 {
64         asm volatile(
65                         __asmeq("%0", "x0")
66                         __asmeq("%1", "x1")
67                         __asmeq("%2", "x2")
68                         __asmeq("%3", "x3")
69                         "smc    #0\n"
70                 : "+r" (function_id) ,"+r" (arg0)
71                 : "r" (arg1), "r" (arg2));
72
73                 *val = arg0;
74
75         return function_id;
76 }
77
78 static int (*invoke_regs_pm_wr_fn)(u64, u64 , u64, u64) = __invoke_reg_pm_wr_fn_smc;
79 static int (*invoke_regs_pm_rd_fn)(u64, u64 , u64, u64, u64 *) = __invoke_reg_pm_rd_fn_smc;
80
81 static int pmu_ctlbits_rd_32(u32 *val)
82 {
83         u64 val_64;
84         int ret;
85         ret = invoke_regs_pm_rd_fn(PSCI_OS_SUSPEND_CTRBITS, 0, 0, SEC_REG_RD, &val_64);
86         *val = val_64;
87
88         return ret;
89 }
90
91 static int pmu_ctlbits_wr_32(u32 val)
92 {
93         u64 val_64 = val;
94         return invoke_regs_pm_wr_fn(PSCI_OS_SUSPEND_CTRBITS, val_64, 0, SEC_REG_WR);
95 }
96
97 static int __init  rk3688_suspend_init(void)
98 {
99         struct device_node *parent;
100         u32 pm_ctrbits, rd_ctrbits = 0;
101
102         parent = of_find_node_by_name(NULL, "rockchip_suspend");
103
104         if (IS_ERR_OR_NULL(parent)) {
105                 printk(KERN_ERR "%s dev node err\n", __func__);
106                 return -1;
107         }
108
109         if(of_property_read_u32_array(parent,"rockchip,ctrbits",&pm_ctrbits,1)) {
110             printk(KERN_ERR "%s:get pm ctr error\n",__func__);
111             return -1;
112         }
113
114         pmu_ctlbits_wr_32(pm_ctrbits);
115         pmu_ctlbits_rd_32(&rd_ctrbits);
116
117         if (rd_ctrbits != pm_ctrbits) {
118                 printk(KERN_ERR "%s read val error\n", __func__);
119                 return 0;
120         }
121
122         printk(KERN_INFO "%s: pm_ctrbits =0x%x\n", __func__, pm_ctrbits);
123
124         return 0;
125 }
126
127 late_initcall_sync(rk3688_suspend_init);