soc: rockchip: add virtual poweroff support
[firefly-linux-kernel-4.4.55.git] / drivers / firmware / rockchip_sip.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License version 2 as
4  * published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  * GNU General Public License for more details.
10  *
11  * Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd
12  */
13
14 #include <linux/arm-smccc.h>
15 #include <linux/io.h>
16 #include <linux/rockchip/rockchip_sip.h>
17 #include <asm/cputype.h>
18 #include <asm/smp_plat.h>
19 #include <uapi/linux/psci.h>
20
21 #ifdef CONFIG_64BIT
22 #define PSCI_FN_NATIVE(version, name)   PSCI_##version##_FN64_##name
23 #else
24 #define PSCI_FN_NATIVE(version, name)   PSCI_##version##_FN_##name
25 #endif
26
27 #define SIZE_PAGE(n)    ((n) << 12)
28
29 static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id,
30                                                 unsigned long arg0,
31                                                 unsigned long arg1,
32                                                 unsigned long arg2)
33 {
34         struct arm_smccc_res res;
35
36         arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
37         return res;
38 }
39
40 struct arm_smccc_res sip_smc_ddr_cfg(u32 arg0, u32 arg1,
41                                      u32 arg2)
42 {
43         return __invoke_sip_fn_smc(SIP_DDR_CFG32, arg0, arg1, arg2);
44 }
45
46 struct arm_smccc_res sip_smc_get_atf_version(void)
47 {
48         return __invoke_sip_fn_smc(SIP_ATF_VERSION32, 0, 0, 0);
49 }
50
51 struct arm_smccc_res sip_smc_get_sip_version(void)
52 {
53         return __invoke_sip_fn_smc(SIP_SIP_VERSION32, 0, 0, 0);
54 }
55
56 int sip_smc_set_suspend_mode(u32 ctrl,
57                              u32 config1,
58                              u32 config2)
59 {
60         struct arm_smccc_res res;
61
62         res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE32, ctrl,
63                                   config1, config2);
64
65         return res.a0;
66 }
67
68 int rk_psci_virtual_poweroff(void)
69 {
70         struct arm_smccc_res res;
71
72         res = __invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND),
73                                   0, 0, 0);
74         return res.a0;
75 }
76
77 static u64 ft_fiq_mem_phy;
78 static void __iomem *ft_fiq_mem_base;
79 static void (*psci_fiq_debugger_uart_irq_tf)(void *reg_base, u64 sp_el1);
80 static u32 fig_init_flag;
81
82 u32 rockchip_psci_smc_get_tf_ver(void)
83 {
84         struct arm_smccc_res res;
85
86         arm_smccc_smc(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
87         return 0x00010005;
88 }
89
90 void psci_fiq_debugger_uart_irq_tf_cb(u64 sp_el1, u64 offset)
91 {
92         psci_fiq_debugger_uart_irq_tf((char *)ft_fiq_mem_base + offset, sp_el1);
93         __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, 0, 0,
94                             UARTDBG_CFG_OSHDL_TO_OS);
95 }
96
97 void psci_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback)
98 {
99         struct arm_smccc_res sip_smmc;
100
101         psci_fiq_debugger_uart_irq_tf = callback;
102         sip_smmc = __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, irq_id,
103                                        (u64)psci_fiq_debugger_uart_irq_tf_cb,
104                                        UARTDBG_CFG_INIT);
105         ft_fiq_mem_phy = sip_smmc.a0;
106         ft_fiq_mem_base = ioremap(ft_fiq_mem_phy, 8 * 1024);
107         fig_init_flag = 1;
108 }
109
110 void psci_enable_fiq(void)
111 {
112         int irq_flag;
113         int cpu_id;
114
115         if (fig_init_flag != 1)
116                 return;
117         irq_flag = *((char *)(ft_fiq_mem_base) + 8 * 1024 - 0x04);
118
119         cpu_id = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
120         if ((irq_flag == 0xAA) && (cpu_id == 0))
121                 __invoke_sip_fn_smc(RK_SIP_ENABLE_FIQ, 0, 0, 0);
122 }
123
124 u32 psci_fiq_debugger_switch_cpu(u32 cpu)
125 {
126         struct arm_smccc_res sip_smmc;
127
128                 sip_smmc = __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64,
129                                                cpu_logical_map(cpu),
130                                                0, UARTDBG_CFG_OSHDL_CPUSW);
131         return sip_smmc.a0;
132 }
133
134 void psci_fiq_debugger_enable_debug(bool val)
135 {
136         if (val)
137                 __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, 0,
138                                     0, UARTDBG_CFG_OSHDL_DEBUG_ENABLE);
139         else
140                 __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, 0,
141                                     0, UARTDBG_CFG_OSHDL_DEBUG_DISABLE);
142 }
143
144 int psci_fiq_debugger_set_print_port(u32 port, u32 baudrate)
145 {
146         struct arm_smccc_res res;
147
148         res = __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, port, baudrate,
149                                   UARTDBG_CFG_PRINT_PORT);
150         return res.a0;
151 }
152
153 struct arm_smccc_res sip_smc_get_share_mem_page(u32 page_num,
154                                                 share_page_type_t page_type)
155 {
156         struct arm_smccc_res res;
157         unsigned long share_mem_phy;
158
159         res = __invoke_sip_fn_smc(SIP_SHARE_MEM32, page_num, page_type, 0);
160         if (res.a0)
161                 goto error;
162
163         share_mem_phy = res.a1;
164         res.a1 = (unsigned long)ioremap(share_mem_phy, SIZE_PAGE(page_num));
165
166 error:
167         return res;
168 }
169
170 struct arm_smccc_res sip_smc_get_call_count(void)
171 {
172         return __invoke_sip_fn_smc(SIP_SVC_CALL_COUNT, 0, 0, 0);
173 }