2 * Copyright (C) 2013 ROCKCHIP, Inc.
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.
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>
15 #include <linux/delay.h>
16 #include <linux/mutex.h>
17 #include <linux/rockchip/iomap.h>
18 #include <linux/rockchip/cpu.h>
20 #include <linux/mfd/syscon.h>
21 #include <linux/regmap.h>
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)
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)
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)
46 #define RK3368_PMUPVTM_CON0 (0x180)
47 #define RK3368_PMUPVTM_CON1 (0x184)
48 #define RK3368_PMUPVTM_STATUS0 (0x190)
49 #define RK3368_PMUPVTM_STATUS1 (0x194)
51 #define grf_readl(offset) readl_relaxed(RK_GRF_VIRT+offset)
52 #define grf_writel(val, offset) writel_relaxed(val, RK_GRF_VIRT+offset)
54 #define wr_msk_bit(v, off, msk) ((v)<<(off)|(msk<<(16+(off))))
56 static struct clk *ch_clk[3];
58 struct rockchip_pvtm {
59 u32 (*get_value)(u32 ch , u32 time_us);
61 static struct rockchip_pvtm pvtm;
63 static struct regmap *grf_regmap;
64 static struct regmap *pmugrf_regmap;
66 static DEFINE_MUTEX(pvtm_mutex);
68 /* 0 core, 1 gpu, 2 pmu */
69 static u32 rk3368_pvtm_get_value(u32 ch , u32 time_us)
71 u32 val = 0, clk_cnt, check_cnt, pvtm_done_bit;
76 /* 24m clk ,24cnt=1us */
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));
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));
90 mdelay(time_us / 1000);
91 udelay(time_us % 1000);
100 while (check_cnt--) {
101 regmap_read(pmugrf_regmap, RK3368_PMUPVTM_STATUS0,
109 while (check_cnt--) {
110 regmap_read(grf_regmap, RK3368_PVTM_STATUS0, &sta);
111 if (sta & (1 << pvtm_done_bit))
119 regmap_read(pmugrf_regmap, RK3368_PMUPVTM_STATUS1,
122 regmap_read(grf_regmap, RK3368_PVTM_STATUS0+(ch+1)*4,
125 pr_err("%s: wait pvtm_done timeout!\n", __func__);
130 regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON0,
131 wr_msk_bit(0, 0, 0x3));
133 regmap_write(grf_regmap, RK3368_PVTM_CON0,
134 wr_msk_bit(0, ch*8, 0x3));
140 static u32 rk3288_pvtm_get_value(u32 ch , u32 time_us)
142 u32 val = 0, clk_cnt, check_cnt, pvtm_done_bit;
147 /*24m clk ,24cnt=1us*/
148 clk_cnt = time_us*24;
150 grf_writel(clk_cnt, RK3288_PVTM_CON0+(ch+1)*4);
151 grf_writel(wr_msk_bit(3, ch*8, 0x3), RK3288_PVTM_CON0);
154 mdelay(time_us / 1000);
155 udelay(time_us % 1000);
163 while (!(grf_readl(RK3288_PVTM_STATUS0) & (1 << pvtm_done_bit))) {
171 val = grf_readl(RK3288_PVTM_STATUS0+(ch+1)*4);
173 grf_writel(wr_msk_bit(0, ch*8, 0x3), RK3288_PVTM_CON0);
178 /*0 core, 1 gpu, 2 func*/
179 static u32 rk312x_pvtm_get_value(u32 ch , u32 time_us)
181 u32 val = 0, clk_cnt, check_cnt, pvtm_done_bit;
186 /*24m clk ,24cnt=1us*/
187 clk_cnt = time_us*24;
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);
193 grf_writel(wr_msk_bit(3, 12, 0x3), RK312X_PVTM_CON0);
196 mdelay(time_us / 1000);
197 udelay(time_us % 1000);
207 while (!(grf_readl(RK312X_PVTM_STATUS0) & (1 << pvtm_done_bit))) {
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);
219 grf_writel(wr_msk_bit(0, 12, 0x3), RK312X_PVTM_CON0);
224 u32 pvtm_get_value(u32 ch, u32 time_us)
228 if (IS_ERR_OR_NULL(ch_clk[ch]))
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]);
240 static int __init rk3368_pmupvtm_clk_init(void)
242 u32 pvtm_cnt = 0, div, val, time_us;
243 unsigned long rate = 32;/* KHZ */
246 pr_info("%s\n", __func__);
249 pvtm_cnt = pvtm_get_value(2, time_us);
250 pr_debug("get pvtm_cnt = %d\n", pvtm_cnt);
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);
257 pr_err("need pvtm_div out of bounary! set max instead\n");
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));
267 /* pvtm oscilator enable */
268 ret = regmap_write(pmugrf_regmap, RK3368_PMUPVTM_CON0,
269 wr_msk_bit(1, 1, 0x1));
272 pr_err("%s: fail to write register\n", __func__);
277 static int __init pvtm_init(void)
279 struct device_node *np;
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,
287 if (IS_ERR(grf_regmap)) {
288 pr_err("pvtm: dts couldn't find grf regmap\n");
289 return PTR_ERR(grf_regmap);
291 pmugrf_regmap = syscon_regmap_lookup_by_phandle(np,
293 if (IS_ERR(pmugrf_regmap)) {
294 pr_err("pvtm: dts couldn't find pmugrf regmap\n");
295 return PTR_ERR(pmugrf_regmap);
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",
305 if (!ret && clk_out) {
306 ret = rk3368_pmupvtm_clk_init();
308 pr_err("rk3368_pmupvtm_clk_init failed\n");
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");
322 pvtm.get_value = rk3288_pvtm_get_value;
323 else if (cpu_is_rk312x())
324 pvtm.get_value = rk312x_pvtm_get_value;
330 arch_initcall_sync(pvtm_init);
332 core_initcall(pvtm_init);