arm64: configs: synchronize with other 3399 config for 3399 linux
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rockchip / pvtm.c
1 /*
2  * Copyright (C) 2013 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 as published by
6  * the Free Software Foundation; either version 2 of the License.
7  */
8
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/err.h>
12 #include <linux/clk.h>
13 #include <linux/clk-provider.h>
14 #include <linux/io.h>
15 #include <linux/delay.h>
16 #include <linux/mutex.h>
17 #include <linux/rockchip/iomap.h>
18 #include <linux/rockchip/cpu.h>
19 #include <linux/of.h>
20 #include <linux/mfd/syscon.h>
21 #include <linux/regmap.h>
22
23 #define RK3288_PVTM_CON0 (0x368)
24 #define RK3288_PVTM_CON1 (0x36c)
25 #define RK3288_PVTM_CON2 (0x370)
26 #define RK3288_PVTM_STATUS0 (0x374)
27 #define RK3288_PVTM_STATUS1 (0x378)
28 #define RK3288_PVTM_STATUS2 (0x37c)
29
30 #define RK312X_PVTM_CON0 (0x200)
31 #define RK312X_PVTM_CON1 (0x204)
32 #define RK312X_PVTM_CON2 (0x208)
33 #define RK312X_PVTM_CON3 (0x20c)
34 #define RK312X_PVTM_STATUS0 (0x210)
35 #define RK312X_PVTM_STATUS1 (0x214)
36 #define RK312X_PVTM_STATUS2 (0x218)
37 #define RK312X_PVTM_STATUS3 (0x21c)
38
39 #define RK3368_PVTM_CON0 (0x800)
40 #define RK3368_PVTM_CON1 (0x804)
41 #define RK3368_PVTM_CON2 (0x808)
42 #define RK3368_PVTM_STATUS0 (0x80c)
43 #define RK3368_PVTM_STATUS1 (0x810)
44 #define RK3368_PVTM_STATUS2 (0x814)
45
46 #define RK3368_PMUPVTM_CON0 (0x180)
47 #define RK3368_PMUPVTM_CON1 (0x184)
48 #define RK3368_PMUPVTM_STATUS0 (0x190)
49 #define RK3368_PMUPVTM_STATUS1 (0x194)
50
51 #define grf_readl(offset)       readl_relaxed(RK_GRF_VIRT+offset)
52 #define grf_writel(val, offset) writel_relaxed(val, RK_GRF_VIRT+offset)
53
54 #define wr_msk_bit(v, off, msk)  ((v)<<(off)|(msk<<(16+(off))))
55
56 static struct clk *ch_clk[3];
57
58 struct rockchip_pvtm {
59         u32 (*get_value)(u32 ch , u32 time_us);
60 };
61 static struct rockchip_pvtm pvtm;
62
63 static struct regmap *grf_regmap;
64 static struct regmap *pmugrf_regmap;
65
66 static DEFINE_MUTEX(pvtm_mutex);
67
68 /* 0 core, 1 gpu, 2 pmu */
69 static u32 rk3368_pvtm_get_value(u32 ch , u32 time_us)
70 {
71         u32 val = 0, clk_cnt, check_cnt, pvtm_done_bit;
72         u32 sta = 0;
73
74         if (ch > 2)
75                 return 0;
76         /* 24m clk ,24cnt=1us */
77         clk_cnt = time_us*24;
78
79         if (ch == 2) {
80                 regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON1, clk_cnt);
81                 regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON0,
82                              wr_msk_bit(3, 0, 0x3));
83         } else {
84                 regmap_write(grf_regmap, RK3368_PVTM_CON0+(ch+1)*4, clk_cnt);
85                 regmap_write(grf_regmap, RK3368_PVTM_CON0,
86                              wr_msk_bit(3, ch*8, 0x3));
87         }
88
89         if (time_us >= 1000)
90                 mdelay(time_us / 1000);
91         udelay(time_us % 1000);
92
93         if (ch == 0)
94                 pvtm_done_bit = 0;
95         else if (ch == 1)
96                 pvtm_done_bit = 1;
97
98         check_cnt = 100;
99         if (ch == 2) {
100                 while (check_cnt--) {
101                         regmap_read(pmugrf_regmap, RK3368_PMUPVTM_STATUS0,
102                                     &sta);
103                         if (sta & 0x1)
104                                 break;
105                         udelay(4);
106                 }
107
108         } else {
109                 while (check_cnt--) {
110                         regmap_read(grf_regmap, RK3368_PVTM_STATUS0, &sta);
111                         if (sta & (1 << pvtm_done_bit))
112                                 break;
113                         udelay(4);
114                 }
115         }
116
117         if (check_cnt)
118                 if (ch == 2)
119                         regmap_read(pmugrf_regmap, RK3368_PMUPVTM_STATUS1,
120                                     &val);
121                 else
122                         regmap_read(grf_regmap, RK3368_PVTM_STATUS0+(ch+1)*4,
123                                     &val);
124         else {
125                 pr_err("%s: wait pvtm_done timeout!\n", __func__);
126                 val = 0;
127         }
128
129         if (ch == 2)
130                 regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON0,
131                              wr_msk_bit(0, 0, 0x3));
132         else
133                 regmap_write(grf_regmap, RK3368_PVTM_CON0,
134                              wr_msk_bit(0, ch*8, 0x3));
135
136         return val;
137 }
138
139 /* 0 core, 1 gpu*/
140 static u32 rk3288_pvtm_get_value(u32 ch , u32 time_us)
141 {
142         u32 val = 0, clk_cnt, check_cnt, pvtm_done_bit;
143
144         if (ch > 1)
145                 return 0;
146
147         /*24m clk ,24cnt=1us*/
148         clk_cnt = time_us*24;
149
150         grf_writel(clk_cnt, RK3288_PVTM_CON0+(ch+1)*4);
151         grf_writel(wr_msk_bit(3, ch*8, 0x3), RK3288_PVTM_CON0);
152
153         if (time_us >= 1000)
154                 mdelay(time_us / 1000);
155         udelay(time_us % 1000);
156
157         if (ch == 0)
158                 pvtm_done_bit = 1;
159         else if (ch == 1)
160                 pvtm_done_bit = 0;
161
162         check_cnt = 100;
163         while (!(grf_readl(RK3288_PVTM_STATUS0) & (1 << pvtm_done_bit))) {
164                 udelay(4);
165                 check_cnt--;
166                 if (!check_cnt)
167                         break;
168         }
169
170         if (check_cnt)
171                 val = grf_readl(RK3288_PVTM_STATUS0+(ch+1)*4);
172
173         grf_writel(wr_msk_bit(0, ch*8, 0x3), RK3288_PVTM_CON0);
174
175         return val;
176 }
177
178 /*0 core, 1 gpu, 2 func*/
179 static u32 rk312x_pvtm_get_value(u32 ch , u32 time_us)
180 {
181         u32 val = 0, clk_cnt, check_cnt, pvtm_done_bit;
182
183         if (ch > 2)
184                 return 0;
185
186         /*24m clk ,24cnt=1us*/
187         clk_cnt = time_us*24;
188
189         grf_writel(clk_cnt, RK312X_PVTM_CON0+(ch+1)*4);
190         if ((ch == 0) || (ch == 1))
191                 grf_writel(wr_msk_bit(3, ch*8, 0x3), RK312X_PVTM_CON0);
192         else if (ch == 2)
193                 grf_writel(wr_msk_bit(3, 12, 0x3), RK312X_PVTM_CON0);
194
195         if (time_us >= 1000)
196                 mdelay(time_us / 1000);
197         udelay(time_us % 1000);
198
199         if (ch == 0)
200                 pvtm_done_bit = 1;
201         else if (ch == 1)
202                 pvtm_done_bit = 0;
203         else if (ch == 2)
204                 pvtm_done_bit = 2;
205
206         check_cnt = 100;
207         while (!(grf_readl(RK312X_PVTM_STATUS0) & (1 << pvtm_done_bit))) {
208                 udelay(4);
209                 check_cnt--;
210                 if (!check_cnt)
211                         break;
212         }
213
214         if (check_cnt)
215                 val = grf_readl(RK312X_PVTM_STATUS0+(ch+1)*4);
216         if ((ch == 0) || (ch == 1))
217                 grf_writel(wr_msk_bit(0, ch*8, 0x3), RK312X_PVTM_CON0);
218         else if (ch == 2)
219                 grf_writel(wr_msk_bit(0, 12, 0x3), RK312X_PVTM_CON0);
220
221         return val;
222 }
223
224 u32 pvtm_get_value(u32 ch, u32 time_us)
225 {
226         u32 val = 0;
227
228         if (IS_ERR_OR_NULL(ch_clk[ch]))
229                 return 0;
230
231         clk_prepare_enable(ch_clk[ch]);
232         mutex_lock(&pvtm_mutex);
233         val = pvtm.get_value(ch, time_us);
234         mutex_unlock(&pvtm_mutex);
235         clk_disable_unprepare(ch_clk[ch]);
236
237         return val;
238 }
239
240 static int __init rk3368_pmupvtm_clk_init(void)
241 {
242         u32 pvtm_cnt = 0, div, val, time_us;
243         unsigned long rate = 32;/* KHZ */
244         int ret = 0;
245
246         pr_info("%s\n", __func__);
247
248         time_us = 1000;
249         pvtm_cnt = pvtm_get_value(2, time_us);
250         pr_debug("get pvtm_cnt = %d\n", pvtm_cnt);
251
252         /* set pvtm_div to get rate */
253         div = DIV_ROUND_UP(1000*pvtm_cnt, time_us*rate);
254         val = DIV_ROUND_UP(div-1, 4);
255
256         if (val > 0x3f) {
257                 pr_err("need pvtm_div out of bounary! set max instead\n");
258                 val = 0x3f;
259         }
260
261         pr_debug("will set div %d, val %d, rate %luKHZ\n", div, val, rate);
262         ret = regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON0,
263                            wr_msk_bit(val, 2, 0x3f));
264         if (ret != 0)
265                 goto out;
266
267         /* pvtm oscilator enable */
268         ret = regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON0,
269                            wr_msk_bit(1, 1, 0x1));
270 out:
271         if (ret != 0)
272                 pr_err("%s: fail to write register\n", __func__);
273
274         return ret;
275 }
276
277 static int __init pvtm_init(void)
278 {
279         struct device_node *np;
280         int ret;
281         u32 clk_out;
282
283         np = of_find_node_by_name(NULL, "pvtm");
284         if (!IS_ERR_OR_NULL(np)) {
285                 grf_regmap = syscon_regmap_lookup_by_phandle(np,
286                                                              "rockchip,grf");
287                 if (IS_ERR(grf_regmap)) {
288                         pr_err("pvtm: dts couldn't find grf regmap\n");
289                         return PTR_ERR(grf_regmap);
290                 }
291                 pmugrf_regmap = syscon_regmap_lookup_by_phandle(np,
292                                                                 "rockchip,pmugrf");
293                 if (IS_ERR(pmugrf_regmap)) {
294                         pr_err("pvtm: dts couldn't find pmugrf regmap\n");
295                         return PTR_ERR(pmugrf_regmap);
296                 }
297
298                 if (of_device_is_compatible(np, "rockchip,rk3368-pvtm")) {
299                         ch_clk[0] = clk_get(NULL, "clk_pvtm_core");
300                         ch_clk[1] = clk_get(NULL, "clk_pvtm_gpu");
301                         ch_clk[2] = clk_get(NULL, "clk_pvtm_pmu");
302                         pvtm.get_value = rk3368_pvtm_get_value;
303                         ret = of_property_read_u32(np, "rockchip,pvtm-clk-out",
304                                                    &clk_out);
305                         if (!ret && clk_out) {
306                                 ret = rk3368_pmupvtm_clk_init();
307                                 if (ret != 0) {
308                                         pr_err("rk3368_pmupvtm_clk_init failed\n");
309                                         return ret;
310                                 }
311                         }
312                 }
313
314                 return 0;
315         }
316
317         if (cpu_is_rk3288() || cpu_is_rk312x()) {
318                 ch_clk[0] = clk_get(NULL, "g_clk_pvtm_core");
319                 ch_clk[1] = clk_get(NULL, "g_clk_pvtm_gpu");
320                 ch_clk[2] = clk_get(NULL, "g_clk_pvtm_func");
321                 if (cpu_is_rk3288())
322                         pvtm.get_value = rk3288_pvtm_get_value;
323                 else if (cpu_is_rk312x())
324                         pvtm.get_value = rk312x_pvtm_get_value;
325         }
326         return 0;
327 }
328
329 #ifdef CONFIG_ARM64
330 arch_initcall_sync(pvtm_init);
331 #else
332 core_initcall(pvtm_init);
333 #endif
334