1*4e1ccc60SShengfei Xu /*
2*4e1ccc60SShengfei Xu * Copyright (c) 2024-2025, Rockchip Electronics Co., Ltd. All rights reserved.
3*4e1ccc60SShengfei Xu *
4*4e1ccc60SShengfei Xu * SPDX-License-Identifier: BSD-3-Clause
5*4e1ccc60SShengfei Xu */
6*4e1ccc60SShengfei Xu
7*4e1ccc60SShengfei Xu #include <drivers/delay_timer.h>
8*4e1ccc60SShengfei Xu #include <drivers/scmi.h>
9*4e1ccc60SShengfei Xu
10*4e1ccc60SShengfei Xu #include "otp.h"
11*4e1ccc60SShengfei Xu #include <plat_private.h>
12*4e1ccc60SShengfei Xu #include <platform_def.h>
13*4e1ccc60SShengfei Xu #include <rk3568_clk.h>
14*4e1ccc60SShengfei Xu #include <scmi_clock.h>
15*4e1ccc60SShengfei Xu
16*4e1ccc60SShengfei Xu enum pll_type_sel {
17*4e1ccc60SShengfei Xu PLL_SEL_AUTO, /* all plls (normal pll or pvtpll) */
18*4e1ccc60SShengfei Xu PLL_SEL_PVT,
19*4e1ccc60SShengfei Xu PLL_SEL_NOR,
20*4e1ccc60SShengfei Xu PLL_SEL_AUTO_NOR /* all normal plls (apll/gpll/npll) */
21*4e1ccc60SShengfei Xu };
22*4e1ccc60SShengfei Xu
23*4e1ccc60SShengfei Xu #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
24*4e1ccc60SShengfei Xu
25*4e1ccc60SShengfei Xu #define RK3568_CPU_PVTPLL_CON0 0x10
26*4e1ccc60SShengfei Xu #define RK3568_GPU_PVTPLL_CON0 0x700
27*4e1ccc60SShengfei Xu #define RK3568_NPU_PVTPLL_CON0 0x740
28*4e1ccc60SShengfei Xu
29*4e1ccc60SShengfei Xu #define GPLL_RATE 1188000000
30*4e1ccc60SShengfei Xu #define MAX_RATE_TABLE 16
31*4e1ccc60SShengfei Xu
32*4e1ccc60SShengfei Xu #define CLKDIV_5BITS_SHF0(div) BITS_WITH_WMASK(div, 0x1f, 0)
33*4e1ccc60SShengfei Xu #define CLKDIV_5BITS_SHF8(div) BITS_WITH_WMASK(div, 0x1f, 8)
34*4e1ccc60SShengfei Xu
35*4e1ccc60SShengfei Xu #define CLKDIV_4BITS_SHF0(div) BITS_WITH_WMASK(div, 0xf, 0)
36*4e1ccc60SShengfei Xu #define CLKDIV_2BITS_SHF4(div) BITS_WITH_WMASK(div, 0x3, 4)
37*4e1ccc60SShengfei Xu
38*4e1ccc60SShengfei Xu /* core_i: from gpll or apll */
39*4e1ccc60SShengfei Xu #define CLK_CORE_I_SEL_APLL WMSK_BIT(6)
40*4e1ccc60SShengfei Xu #define CLK_CORE_I_SEL_GPLL BIT_WITH_WMSK(6)
41*4e1ccc60SShengfei Xu
42*4e1ccc60SShengfei Xu /* clk_core:
43*4e1ccc60SShengfei Xu * from normal pll(core_i: gpll or apll) path or direct pass from apll
44*4e1ccc60SShengfei Xu */
45*4e1ccc60SShengfei Xu #define CLK_CORE_SEL_CORE_I WMSK_BIT(7)
46*4e1ccc60SShengfei Xu #define CLK_CORE_SEL_APLL BIT_WITH_WMSK(7)
47*4e1ccc60SShengfei Xu
48*4e1ccc60SShengfei Xu /* cpu clk: form clk_core or pvtpll */
49*4e1ccc60SShengfei Xu #define CLK_CORE_NDFT_CLK_CORE WMSK_BIT(15)
50*4e1ccc60SShengfei Xu #define CLK_CORE_NDFT_CLK_PVTPLL BIT_WITH_WMSK(15)
51*4e1ccc60SShengfei Xu
52*4e1ccc60SShengfei Xu /* clk_core_ndft path */
53*4e1ccc60SShengfei Xu #define CLK_CORE_PATH_NOR_GPLL (CLK_CORE_I_SEL_GPLL | CLK_CORE_SEL_CORE_I)
54*4e1ccc60SShengfei Xu #define CLK_CORE_PATH_NOR_APLL (CLK_CORE_I_SEL_APLL | CLK_CORE_SEL_CORE_I)
55*4e1ccc60SShengfei Xu #define CLK_CORE_PATH_DIR_APLL (CLK_CORE_SEL_APLL) /* from apll directly*/
56*4e1ccc60SShengfei Xu
57*4e1ccc60SShengfei Xu /* cpu clk path */
58*4e1ccc60SShengfei Xu #define CPU_CLK_PATH_NOR_GPLL (CLK_CORE_PATH_NOR_GPLL | \
59*4e1ccc60SShengfei Xu CLK_CORE_NDFT_CLK_CORE)
60*4e1ccc60SShengfei Xu #define CPU_CLK_PATH_NOR_APLL (CLK_CORE_PATH_NOR_APLL | \
61*4e1ccc60SShengfei Xu CLK_CORE_NDFT_CLK_CORE)
62*4e1ccc60SShengfei Xu #define CPU_CLK_PATH_DIR_APLL (CLK_CORE_PATH_DIR_APLL | \
63*4e1ccc60SShengfei Xu CLK_CORE_NDFT_CLK_CORE)
64*4e1ccc60SShengfei Xu #define CPU_CLK_PATH_PVTPLL CLK_CORE_NDFT_CLK_PVTPLL
65*4e1ccc60SShengfei Xu
66*4e1ccc60SShengfei Xu /* dsu clk path */
67*4e1ccc60SShengfei Xu #define SCLK_PATH_NOR_APLL (BITS_WITH_WMASK(0, 0x3, 8) | WMSK_BIT(15))
68*4e1ccc60SShengfei Xu #define SCLK_PATH_NOR_GPLL (BITS_WITH_WMASK(0x1, 0x3, 8) | WMSK_BIT(15))
69*4e1ccc60SShengfei Xu #define SCLK_PATH_NOR_NPLL BITS_WITH_WMASK(0x2, 0x3, 8) | WMSK_BIT(15)
70*4e1ccc60SShengfei Xu #define SCLK_PATH_DIR_NPLL BIT_WITH_WMSK(15)
71*4e1ccc60SShengfei Xu
72*4e1ccc60SShengfei Xu /* npu clk path */
73*4e1ccc60SShengfei Xu #define CLK_NPU_SRC_NPLL WMSK_BIT(6)
74*4e1ccc60SShengfei Xu #define CLK_NPU_SRC_GPLL BIT_WITH_WMSK(6)
75*4e1ccc60SShengfei Xu
76*4e1ccc60SShengfei Xu #define CLK_NPU_NP5_SRC_NPLL WMSK_BIT(7)
77*4e1ccc60SShengfei Xu #define CLK_NPU_NP5_SRC_GPLL BIT_WITH_WMSK(7)
78*4e1ccc60SShengfei Xu
79*4e1ccc60SShengfei Xu #define NPU_PRE_CLK_SEL_PLL_SRC WMSK_BIT(8)
80*4e1ccc60SShengfei Xu #define NPU_PRE_CLK_SEL_NP5 BIT_WITH_WMSK(8)
81*4e1ccc60SShengfei Xu
82*4e1ccc60SShengfei Xu #define CLK_NPU_MUX_PLL_SRC WMSK_BIT(15)
83*4e1ccc60SShengfei Xu #define CLK_NPU_MUX_PVTPLL BIT_WITH_WMSK(15)
84*4e1ccc60SShengfei Xu
85*4e1ccc60SShengfei Xu #define NPU_PRE_CLK_PATH_NPLL (CLK_NPU_SRC_NPLL | NPU_PRE_CLK_SEL_PLL_SRC)
86*4e1ccc60SShengfei Xu #define NPU_PRE_CLK_PATH_GPLL (CLK_NPU_SRC_GPLL | NPU_PRE_CLK_SEL_PLL_SRC)
87*4e1ccc60SShengfei Xu #define NPU_PRE_CLK_PATH_NP5_NPLL (CLK_NPU_NP5_SRC_NPLL | \
88*4e1ccc60SShengfei Xu NPU_PRE_CLK_SEL_NP5)
89*4e1ccc60SShengfei Xu #define NPU_PRE_CLK_PATH_NP5_GPLL (CLK_NPU_NP5_SRC_GPLL | \
90*4e1ccc60SShengfei Xu NPU_PRE_CLK_SEL_NP5)
91*4e1ccc60SShengfei Xu
92*4e1ccc60SShengfei Xu #define NPU_CLK_PATH_NOR_NPLL (NPU_PRE_CLK_PATH_NPLL | CLK_NPU_MUX_PLL_SRC)
93*4e1ccc60SShengfei Xu #define NPU_CLK_PATH_NOR_GPLL (NPU_PRE_CLK_PATH_GPLL | CLK_NPU_MUX_PLL_SRC)
94*4e1ccc60SShengfei Xu #define NPU_CLK_PATH_NP5_NPLL (NPU_PRE_CLK_PATH_NP5_NPLL | \
95*4e1ccc60SShengfei Xu CLK_NPU_MUX_PLL_SRC)
96*4e1ccc60SShengfei Xu #define NPU_CLK_PATH_NP5_GPLL (NPU_PRE_CLK_PATH_NP5_GPLL | \
97*4e1ccc60SShengfei Xu CLK_NPU_MUX_PLL_SRC)
98*4e1ccc60SShengfei Xu #define NPU_CLK_PATH_PVTPLL CLK_NPU_MUX_PVTPLL
99*4e1ccc60SShengfei Xu
100*4e1ccc60SShengfei Xu /* gpu clk path */
101*4e1ccc60SShengfei Xu #define GPU_CLK_PATH_NOR_MPLL (WMSK_BIT(11) | BITS_WITH_WMASK(0, 0x3, 6))
102*4e1ccc60SShengfei Xu #define GPU_CLK_PATH_NOR_GPLL (WMSK_BIT(11) | BITS_WITH_WMASK(0x1, 0x3, 6))
103*4e1ccc60SShengfei Xu #define GPU_CLK_PATH_NOR_CPLL (WMSK_BIT(11) | BITS_WITH_WMASK(0x2, 0x3, 6))
104*4e1ccc60SShengfei Xu #define GPU_CLK_PATH_NOR_NPLL (WMSK_BIT(11) | BITS_WITH_WMASK(0x3, 0x3, 6))
105*4e1ccc60SShengfei Xu #define GPU_CLK_PATH_PVTPLL BIT_WITH_WMSK(11)
106*4e1ccc60SShengfei Xu
107*4e1ccc60SShengfei Xu #define PVTPLL_NEED(type, length) (((type) == PLL_SEL_PVT || \
108*4e1ccc60SShengfei Xu (type) == PLL_SEL_AUTO) && \
109*4e1ccc60SShengfei Xu (length))
110*4e1ccc60SShengfei Xu
111*4e1ccc60SShengfei Xu #define RK3568_CPU_OPP_INFO_OFFSET (OTP_S_BYTE_SIZE + 54)
112*4e1ccc60SShengfei Xu #define RK3568_GPU_OPP_INFO_OFFSET (OTP_S_BYTE_SIZE + 60)
113*4e1ccc60SShengfei Xu #define RK3568_NPU_OPP_INFO_OFFSET (OTP_S_BYTE_SIZE + 66)
114*4e1ccc60SShengfei Xu
115*4e1ccc60SShengfei Xu struct sys_clk_info_t {
116*4e1ccc60SShengfei Xu unsigned long cpu_rate;
117*4e1ccc60SShengfei Xu unsigned long gpu_rate;
118*4e1ccc60SShengfei Xu unsigned long npu_rate;
119*4e1ccc60SShengfei Xu };
120*4e1ccc60SShengfei Xu
121*4e1ccc60SShengfei Xu struct otp_opp_info {
122*4e1ccc60SShengfei Xu uint16_t min_freq;
123*4e1ccc60SShengfei Xu uint16_t max_freq;
124*4e1ccc60SShengfei Xu uint8_t volt;
125*4e1ccc60SShengfei Xu uint8_t length;
126*4e1ccc60SShengfei Xu } __packed __aligned(2);
127*4e1ccc60SShengfei Xu
128*4e1ccc60SShengfei Xu struct pvtpll_table {
129*4e1ccc60SShengfei Xu unsigned int rate;
130*4e1ccc60SShengfei Xu uint32_t refdiv;
131*4e1ccc60SShengfei Xu uint32_t fbdiv;
132*4e1ccc60SShengfei Xu uint32_t postdiv1;
133*4e1ccc60SShengfei Xu uint32_t postdiv2;
134*4e1ccc60SShengfei Xu uint32_t dsmpd;
135*4e1ccc60SShengfei Xu uint32_t frac;
136*4e1ccc60SShengfei Xu uint32_t length;
137*4e1ccc60SShengfei Xu };
138*4e1ccc60SShengfei Xu
139*4e1ccc60SShengfei Xu #define ROCKCHIP_CPU_PVTPLL(_rate, _refdiv, _fbdiv, _postdiv1, \
140*4e1ccc60SShengfei Xu _postdiv2, _dsmpd, _frac, _length) \
141*4e1ccc60SShengfei Xu { \
142*4e1ccc60SShengfei Xu .rate = _rate##U, \
143*4e1ccc60SShengfei Xu .refdiv = _refdiv, \
144*4e1ccc60SShengfei Xu .fbdiv = _fbdiv, \
145*4e1ccc60SShengfei Xu .postdiv1 = _postdiv1, \
146*4e1ccc60SShengfei Xu .postdiv2 = _postdiv2, \
147*4e1ccc60SShengfei Xu .dsmpd = _dsmpd, \
148*4e1ccc60SShengfei Xu .frac = _frac, \
149*4e1ccc60SShengfei Xu .length = _length, \
150*4e1ccc60SShengfei Xu }
151*4e1ccc60SShengfei Xu
152*4e1ccc60SShengfei Xu #define ROCKCHIP_GPU_PVTPLL(_rate, _length) \
153*4e1ccc60SShengfei Xu { \
154*4e1ccc60SShengfei Xu .rate = _rate##U, \
155*4e1ccc60SShengfei Xu .length = _length, \
156*4e1ccc60SShengfei Xu }
157*4e1ccc60SShengfei Xu
158*4e1ccc60SShengfei Xu static struct pvtpll_table rk3568_cpu_pvtpll_table[] = {
159*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(1992000000, 1, 83, 1, 1, 1, 0, 0x33),
160*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(1800000000, 1, 75, 1, 1, 1, 0, 0x33),
161*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(1608000000, 1, 67, 1, 1, 1, 0, 0x3b),
162*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(1416000000, 1, 118, 2, 1, 1, 0, 0x43),
163*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(1200000000, 1, 100, 2, 1, 1, 0, 0x53),
164*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(1104000000, 1, 92, 2, 1, 1, 0, 0x53),
165*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(1008000000, 1, 84, 2, 1, 1, 0, 0x5b),
166*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(816000000, 1, 68, 2, 1, 1, 0, 0),
167*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(600000000, 1, 100, 4, 1, 1, 0, 0),
168*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(408000000, 1, 68, 2, 2, 1, 0, 0),
169*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(312000000, 1, 78, 6, 1, 1, 0, 0),
170*4e1ccc60SShengfei Xu ROCKCHIP_CPU_PVTPLL(216000000, 1, 72, 4, 2, 1, 0, 0),
171*4e1ccc60SShengfei Xu { /* sentinel */ },
172*4e1ccc60SShengfei Xu };
173*4e1ccc60SShengfei Xu
174*4e1ccc60SShengfei Xu static struct pvtpll_table rk3568_gpu_pvtpll_table[] = {
175*4e1ccc60SShengfei Xu /* rate_hz, length */
176*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(800000000, 0x1db),
177*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(700000000, 0x1db),
178*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(600000000, 0x1db),
179*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(400000000, 0),
180*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(300000000, 0),
181*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(200000000, 0),
182*4e1ccc60SShengfei Xu { /* sentinel */ },
183*4e1ccc60SShengfei Xu };
184*4e1ccc60SShengfei Xu
185*4e1ccc60SShengfei Xu static struct pvtpll_table rk3568_npu_pvtpll_table[] = {
186*4e1ccc60SShengfei Xu /* rate_hz, length */
187*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(1000000000, 0xd3),
188*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(900000000, 0xd3),
189*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(800000000, 0xd3),
190*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(700000000, 0xdb),
191*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(600000000, 0xfb),
192*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(400000000, 0),
193*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(300000000, 0),
194*4e1ccc60SShengfei Xu ROCKCHIP_GPU_PVTPLL(200000000, 0),
195*4e1ccc60SShengfei Xu { /* sentinel */ },
196*4e1ccc60SShengfei Xu };
197*4e1ccc60SShengfei Xu
198*4e1ccc60SShengfei Xu static unsigned long rk3568_cpu_rates[] = {
199*4e1ccc60SShengfei Xu 216000000, 312000000, 408000000, 816000000,
200*4e1ccc60SShengfei Xu 1008000000, 1200000000, 1416000000, 1608000000,
201*4e1ccc60SShengfei Xu 1800000000, 1992000000
202*4e1ccc60SShengfei Xu };
203*4e1ccc60SShengfei Xu
204*4e1ccc60SShengfei Xu static unsigned long rk3568_gpu_rates[] = {
205*4e1ccc60SShengfei Xu 100000000, 200000000, 300000000, 400000000,
206*4e1ccc60SShengfei Xu 500000000, 600000000, 700000000, 800000000,
207*4e1ccc60SShengfei Xu 900000000, 1000000000, 1100000000, 1200000000
208*4e1ccc60SShengfei Xu };
209*4e1ccc60SShengfei Xu
210*4e1ccc60SShengfei Xu static struct sys_clk_info_t sys_clk_info;
211*4e1ccc60SShengfei Xu
check_otp_ecc_ok(uint32_t addr)212*4e1ccc60SShengfei Xu static bool check_otp_ecc_ok(uint32_t addr)
213*4e1ccc60SShengfei Xu {
214*4e1ccc60SShengfei Xu int i;
215*4e1ccc60SShengfei Xu
216*4e1ccc60SShengfei Xu for (i = 0; i < sizeof(struct otp_opp_info); i++) {
217*4e1ccc60SShengfei Xu if (rk_otp_ns_ecc_flag(addr + i))
218*4e1ccc60SShengfei Xu return false;
219*4e1ccc60SShengfei Xu }
220*4e1ccc60SShengfei Xu
221*4e1ccc60SShengfei Xu return true;
222*4e1ccc60SShengfei Xu }
223*4e1ccc60SShengfei Xu
rk3568_adjust_pvtpll_table(struct pvtpll_table * pvtpll,unsigned int count,uint16_t min_freq,uint16_t max_freq,uint8_t length)224*4e1ccc60SShengfei Xu static void rk3568_adjust_pvtpll_table(struct pvtpll_table *pvtpll,
225*4e1ccc60SShengfei Xu unsigned int count,
226*4e1ccc60SShengfei Xu uint16_t min_freq,
227*4e1ccc60SShengfei Xu uint16_t max_freq,
228*4e1ccc60SShengfei Xu uint8_t length)
229*4e1ccc60SShengfei Xu {
230*4e1ccc60SShengfei Xu uint16_t freq;
231*4e1ccc60SShengfei Xu uint8_t cur_length;
232*4e1ccc60SShengfei Xu int i;
233*4e1ccc60SShengfei Xu
234*4e1ccc60SShengfei Xu if (length > 31)
235*4e1ccc60SShengfei Xu return;
236*4e1ccc60SShengfei Xu
237*4e1ccc60SShengfei Xu for (i = 0; i < count; i++) {
238*4e1ccc60SShengfei Xu if (!pvtpll[i].length)
239*4e1ccc60SShengfei Xu continue;
240*4e1ccc60SShengfei Xu cur_length = (pvtpll[i].length >> 3) & 0x1f;
241*4e1ccc60SShengfei Xu
242*4e1ccc60SShengfei Xu /*
243*4e1ccc60SShengfei Xu * Max value of length is 31, so adjust length to
244*4e1ccc60SShengfei Xu * make sure (cur_length + length) <= 31.
245*4e1ccc60SShengfei Xu */
246*4e1ccc60SShengfei Xu if ((cur_length + length) > 31)
247*4e1ccc60SShengfei Xu length = 31 - cur_length;
248*4e1ccc60SShengfei Xu freq = pvtpll[i].rate / 1000000;
249*4e1ccc60SShengfei Xu if ((freq >= min_freq) && (freq <= max_freq))
250*4e1ccc60SShengfei Xu pvtpll[i].length += (length << 3);
251*4e1ccc60SShengfei Xu }
252*4e1ccc60SShengfei Xu }
253*4e1ccc60SShengfei Xu
254*4e1ccc60SShengfei Xu static unsigned int
rockchip_get_pvtpll_length(struct pvtpll_table * table,int count,unsigned long rate)255*4e1ccc60SShengfei Xu rockchip_get_pvtpll_length(struct pvtpll_table *table, int count,
256*4e1ccc60SShengfei Xu unsigned long rate)
257*4e1ccc60SShengfei Xu {
258*4e1ccc60SShengfei Xu int i;
259*4e1ccc60SShengfei Xu
260*4e1ccc60SShengfei Xu for (i = 0; i < count; i++) {
261*4e1ccc60SShengfei Xu if (rate == table[i].rate)
262*4e1ccc60SShengfei Xu return table[i].length;
263*4e1ccc60SShengfei Xu }
264*4e1ccc60SShengfei Xu return 0;
265*4e1ccc60SShengfei Xu }
266*4e1ccc60SShengfei Xu
rkclk_get_pll_config(unsigned int freq_hz)267*4e1ccc60SShengfei Xu static struct pvtpll_table *rkclk_get_pll_config(unsigned int freq_hz)
268*4e1ccc60SShengfei Xu {
269*4e1ccc60SShengfei Xu unsigned int rate_count = ARRAY_SIZE(rk3568_cpu_pvtpll_table);
270*4e1ccc60SShengfei Xu int i;
271*4e1ccc60SShengfei Xu
272*4e1ccc60SShengfei Xu for (i = 0; i < rate_count; i++) {
273*4e1ccc60SShengfei Xu if (freq_hz == rk3568_cpu_pvtpll_table[i].rate)
274*4e1ccc60SShengfei Xu return &rk3568_cpu_pvtpll_table[i];
275*4e1ccc60SShengfei Xu }
276*4e1ccc60SShengfei Xu return NULL;
277*4e1ccc60SShengfei Xu }
278*4e1ccc60SShengfei Xu
rk3568_apll_set_rate(unsigned long rate,enum pll_type_sel type)279*4e1ccc60SShengfei Xu static int rk3568_apll_set_rate(unsigned long rate, enum pll_type_sel type)
280*4e1ccc60SShengfei Xu {
281*4e1ccc60SShengfei Xu struct pvtpll_table *div;
282*4e1ccc60SShengfei Xu int delay = 2400;
283*4e1ccc60SShengfei Xu
284*4e1ccc60SShengfei Xu div = rkclk_get_pll_config(rate);
285*4e1ccc60SShengfei Xu if (div == NULL)
286*4e1ccc60SShengfei Xu return SCMI_INVALID_PARAMETERS;
287*4e1ccc60SShengfei Xu
288*4e1ccc60SShengfei Xu if (PVTPLL_NEED(type, div->length)) {
289*4e1ccc60SShengfei Xu /* set pvtpll length */
290*4e1ccc60SShengfei Xu mmio_write_32(CPUGRF_BASE + RK3568_CPU_PVTPLL_CON0,
291*4e1ccc60SShengfei Xu 0xffff0000);
292*4e1ccc60SShengfei Xu udelay(1);
293*4e1ccc60SShengfei Xu mmio_write_32(CPUGRF_BASE + RK3568_CPU_PVTPLL_CON0,
294*4e1ccc60SShengfei Xu 0xffff0000 | div->length);
295*4e1ccc60SShengfei Xu udelay(1);
296*4e1ccc60SShengfei Xu /* set core mux pvtpll */
297*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(0),
298*4e1ccc60SShengfei Xu CPU_CLK_PATH_PVTPLL);
299*4e1ccc60SShengfei Xu }
300*4e1ccc60SShengfei Xu
301*4e1ccc60SShengfei Xu /* pll enter slow mode */
302*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + 0xc0,
303*4e1ccc60SShengfei Xu (RK3568_PLL_MODE_MASK <<
304*4e1ccc60SShengfei Xu (16 + RK3568_PLL_MODE_SHIFT)) |
305*4e1ccc60SShengfei Xu (RK3568_PLL_MODE_SLOWMODE << RK3568_PLL_MODE_SHIFT));
306*4e1ccc60SShengfei Xu /* update pll values */
307*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_PLLCON(0),
308*4e1ccc60SShengfei Xu (RK3568_PLLCON0_FBDIV_MASK <<
309*4e1ccc60SShengfei Xu (16 + RK3568_PLLCON0_FBDIV_SHIFT)) |
310*4e1ccc60SShengfei Xu (div->fbdiv << RK3568_PLLCON0_FBDIV_SHIFT));
311*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_PLLCON(0),
312*4e1ccc60SShengfei Xu (RK3568_PLLCON0_POSTDIV1_MASK <<
313*4e1ccc60SShengfei Xu (16 + RK3568_PLLCON0_POSTDIV1_SHIFT)) |
314*4e1ccc60SShengfei Xu (div->postdiv1 << RK3568_PLLCON0_POSTDIV1_SHIFT));
315*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_PLLCON(1),
316*4e1ccc60SShengfei Xu (RK3568_PLLCON1_REFDIV_MASK <<
317*4e1ccc60SShengfei Xu (16 + RK3568_PLLCON1_REFDIV_SHIFT)) |
318*4e1ccc60SShengfei Xu (div->refdiv << RK3568_PLLCON1_REFDIV_SHIFT));
319*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_PLLCON(1),
320*4e1ccc60SShengfei Xu (RK3568_PLLCON1_POSTDIV2_MASK <<
321*4e1ccc60SShengfei Xu (16 + RK3568_PLLCON1_POSTDIV2_SHIFT)) |
322*4e1ccc60SShengfei Xu (div->postdiv2 << RK3568_PLLCON1_POSTDIV2_SHIFT));
323*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_PLLCON(1),
324*4e1ccc60SShengfei Xu (RK3568_PLLCON1_DSMPD_MASK <<
325*4e1ccc60SShengfei Xu (16 + RK3568_PLLCON1_DSMPD_SHIFT)) |
326*4e1ccc60SShengfei Xu (div->dsmpd << RK3568_PLLCON1_DSMPD_SHIFT));
327*4e1ccc60SShengfei Xu
328*4e1ccc60SShengfei Xu /* wait for the pll to lock */
329*4e1ccc60SShengfei Xu while (delay > 0) {
330*4e1ccc60SShengfei Xu if (mmio_read_32(CRU_BASE + RK3568_PLLCON(1)) &
331*4e1ccc60SShengfei Xu RK3568_PLLCON1_LOCK_STATUS)
332*4e1ccc60SShengfei Xu break;
333*4e1ccc60SShengfei Xu udelay(1);
334*4e1ccc60SShengfei Xu delay--;
335*4e1ccc60SShengfei Xu }
336*4e1ccc60SShengfei Xu if (delay == 0)
337*4e1ccc60SShengfei Xu INFO("%s:ERROR: PLL WAIT LOCK FAILED\n", __func__);
338*4e1ccc60SShengfei Xu
339*4e1ccc60SShengfei Xu /* pll enter normal mode */
340*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + 0xc0,
341*4e1ccc60SShengfei Xu (RK3568_PLL_MODE_MASK << (16 + RK3568_PLL_MODE_SHIFT)) |
342*4e1ccc60SShengfei Xu (RK3568_PLL_MODE_NORMAL << RK3568_PLL_MODE_SHIFT));
343*4e1ccc60SShengfei Xu
344*4e1ccc60SShengfei Xu return 0;
345*4e1ccc60SShengfei Xu }
346*4e1ccc60SShengfei Xu
rk3568_apll_get_rate(void)347*4e1ccc60SShengfei Xu static unsigned long rk3568_apll_get_rate(void)
348*4e1ccc60SShengfei Xu {
349*4e1ccc60SShengfei Xu unsigned int fbdiv, postdiv1, refdiv, postdiv2;
350*4e1ccc60SShengfei Xu uint64_t rate64 = 24000000;
351*4e1ccc60SShengfei Xu int mode;
352*4e1ccc60SShengfei Xu
353*4e1ccc60SShengfei Xu mode = (mmio_read_32(CRU_BASE + 0xc0) >> RK3568_PLL_MODE_SHIFT) &
354*4e1ccc60SShengfei Xu RK3568_PLL_MODE_MASK;
355*4e1ccc60SShengfei Xu
356*4e1ccc60SShengfei Xu if (mode == RK3568_PLL_MODE_SLOWMODE)
357*4e1ccc60SShengfei Xu return rate64;
358*4e1ccc60SShengfei Xu
359*4e1ccc60SShengfei Xu fbdiv = (mmio_read_32(CRU_BASE + RK3568_PLLCON(0)) >>
360*4e1ccc60SShengfei Xu RK3568_PLLCON0_FBDIV_SHIFT) &
361*4e1ccc60SShengfei Xu RK3568_PLLCON0_FBDIV_MASK;
362*4e1ccc60SShengfei Xu postdiv1 = (mmio_read_32(CRU_BASE + RK3568_PLLCON(0)) >>
363*4e1ccc60SShengfei Xu RK3568_PLLCON0_POSTDIV1_SHIFT) &
364*4e1ccc60SShengfei Xu RK3568_PLLCON0_POSTDIV1_MASK;
365*4e1ccc60SShengfei Xu refdiv = (mmio_read_32(CRU_BASE + RK3568_PLLCON(1)) >>
366*4e1ccc60SShengfei Xu RK3568_PLLCON1_REFDIV_SHIFT) &
367*4e1ccc60SShengfei Xu RK3568_PLLCON1_REFDIV_MASK;
368*4e1ccc60SShengfei Xu postdiv2 = (mmio_read_32(CRU_BASE + RK3568_PLLCON(1)) >>
369*4e1ccc60SShengfei Xu RK3568_PLLCON1_POSTDIV2_SHIFT) &
370*4e1ccc60SShengfei Xu RK3568_PLLCON1_POSTDIV2_MASK;
371*4e1ccc60SShengfei Xu
372*4e1ccc60SShengfei Xu rate64 *= fbdiv;
373*4e1ccc60SShengfei Xu rate64 = rate64 / refdiv;
374*4e1ccc60SShengfei Xu rate64 = rate64 / postdiv1;
375*4e1ccc60SShengfei Xu rate64 = rate64 / postdiv2;
376*4e1ccc60SShengfei Xu
377*4e1ccc60SShengfei Xu return (unsigned long)rate64;
378*4e1ccc60SShengfei Xu }
379*4e1ccc60SShengfei Xu
clk_cpu_set_rate(unsigned long rate,enum pll_type_sel type)380*4e1ccc60SShengfei Xu static int clk_cpu_set_rate(unsigned long rate, enum pll_type_sel type)
381*4e1ccc60SShengfei Xu {
382*4e1ccc60SShengfei Xu int div = 0, ret = 0;
383*4e1ccc60SShengfei Xu
384*4e1ccc60SShengfei Xu if (!rate)
385*4e1ccc60SShengfei Xu return SCMI_INVALID_PARAMETERS;
386*4e1ccc60SShengfei Xu
387*4e1ccc60SShengfei Xu /* set clk core div to 3 */
388*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(0),
389*4e1ccc60SShengfei Xu CLKDIV_5BITS_SHF8(2) | CLKDIV_5BITS_SHF0(2));
390*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(1),
391*4e1ccc60SShengfei Xu CLKDIV_5BITS_SHF8(2) | CLKDIV_5BITS_SHF0(2));
392*4e1ccc60SShengfei Xu /* set atcore/gicclk div */
393*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(3),
394*4e1ccc60SShengfei Xu CLKDIV_5BITS_SHF8(7) | CLKDIV_5BITS_SHF0(7));
395*4e1ccc60SShengfei Xu /* set pclk/periph div */
396*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(4),
397*4e1ccc60SShengfei Xu CLKDIV_5BITS_SHF8(9) | CLKDIV_5BITS_SHF0(9));
398*4e1ccc60SShengfei Xu
399*4e1ccc60SShengfei Xu /* set dsu div to 4 */
400*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(2), CLKDIV_4BITS_SHF0(3));
401*4e1ccc60SShengfei Xu
402*4e1ccc60SShengfei Xu /* set core mux gpll */
403*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(0), CPU_CLK_PATH_NOR_GPLL);
404*4e1ccc60SShengfei Xu /* set dsu mux gpll */
405*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(2), SCLK_PATH_NOR_GPLL);
406*4e1ccc60SShengfei Xu
407*4e1ccc60SShengfei Xu /* set apll */
408*4e1ccc60SShengfei Xu ret = rk3568_apll_set_rate(rate, type);
409*4e1ccc60SShengfei Xu if (ret < 0)
410*4e1ccc60SShengfei Xu return ret;
411*4e1ccc60SShengfei Xu
412*4e1ccc60SShengfei Xu /* set t core mux apll */
413*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(0), CLK_CORE_PATH_DIR_APLL);
414*4e1ccc60SShengfei Xu
415*4e1ccc60SShengfei Xu div = DIV_ROUND_UP(rate, 300000000);
416*4e1ccc60SShengfei Xu div = div - 1;
417*4e1ccc60SShengfei Xu /* set atcore/gicclk div */
418*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(3),
419*4e1ccc60SShengfei Xu CLKDIV_5BITS_SHF8(div) | CLKDIV_5BITS_SHF0(div));
420*4e1ccc60SShengfei Xu /* set pclk/periph div */
421*4e1ccc60SShengfei Xu div = DIV_ROUND_UP(rate, 300000000);
422*4e1ccc60SShengfei Xu div = div - 1;
423*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(4),
424*4e1ccc60SShengfei Xu CLKDIV_5BITS_SHF8(div) | CLKDIV_5BITS_SHF0(div));
425*4e1ccc60SShengfei Xu
426*4e1ccc60SShengfei Xu if (rate >= 1608000000) {
427*4e1ccc60SShengfei Xu /* set dsu mux npll */
428*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(2),
429*4e1ccc60SShengfei Xu SCLK_PATH_DIR_NPLL);
430*4e1ccc60SShengfei Xu /* set dsu div to 1 */
431*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(2),
432*4e1ccc60SShengfei Xu CLKDIV_4BITS_SHF0(0));
433*4e1ccc60SShengfei Xu } else {
434*4e1ccc60SShengfei Xu /* set dsu mux apll */
435*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(2),
436*4e1ccc60SShengfei Xu SCLK_PATH_NOR_APLL);
437*4e1ccc60SShengfei Xu /* set dsu div to 2 */
438*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(2),
439*4e1ccc60SShengfei Xu CLKDIV_4BITS_SHF0(1));
440*4e1ccc60SShengfei Xu }
441*4e1ccc60SShengfei Xu
442*4e1ccc60SShengfei Xu /* set clk core div to 1 */
443*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(0),
444*4e1ccc60SShengfei Xu CLKDIV_5BITS_SHF8(0) | CLKDIV_5BITS_SHF0(0));
445*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(1),
446*4e1ccc60SShengfei Xu CLKDIV_5BITS_SHF8(0) | CLKDIV_5BITS_SHF0(0));
447*4e1ccc60SShengfei Xu return ret;
448*4e1ccc60SShengfei Xu }
449*4e1ccc60SShengfei Xu
clk_scmi_cpu_set_rate(struct rk_scmi_clock * clock,unsigned long rate)450*4e1ccc60SShengfei Xu static int clk_scmi_cpu_set_rate(struct rk_scmi_clock *clock, unsigned long rate)
451*4e1ccc60SShengfei Xu {
452*4e1ccc60SShengfei Xu int ret;
453*4e1ccc60SShengfei Xu
454*4e1ccc60SShengfei Xu ret = clk_cpu_set_rate(rate, PLL_SEL_AUTO);
455*4e1ccc60SShengfei Xu
456*4e1ccc60SShengfei Xu if (!ret)
457*4e1ccc60SShengfei Xu sys_clk_info.cpu_rate = rate;
458*4e1ccc60SShengfei Xu
459*4e1ccc60SShengfei Xu return ret;
460*4e1ccc60SShengfei Xu }
461*4e1ccc60SShengfei Xu
clk_scmi_cpu_get_rate(struct rk_scmi_clock * clock)462*4e1ccc60SShengfei Xu static unsigned long clk_scmi_cpu_get_rate(struct rk_scmi_clock *clock)
463*4e1ccc60SShengfei Xu {
464*4e1ccc60SShengfei Xu return rk3568_apll_get_rate();
465*4e1ccc60SShengfei Xu }
466*4e1ccc60SShengfei Xu
clk_scmi_cpu_set_status(struct rk_scmi_clock * clock,bool status)467*4e1ccc60SShengfei Xu static int clk_scmi_cpu_set_status(struct rk_scmi_clock *clock, bool status)
468*4e1ccc60SShengfei Xu {
469*4e1ccc60SShengfei Xu return 0;
470*4e1ccc60SShengfei Xu }
471*4e1ccc60SShengfei Xu
clk_scmi_gpu_get_rate(struct rk_scmi_clock * clock)472*4e1ccc60SShengfei Xu static unsigned long clk_scmi_gpu_get_rate(struct rk_scmi_clock *clock)
473*4e1ccc60SShengfei Xu {
474*4e1ccc60SShengfei Xu int div;
475*4e1ccc60SShengfei Xu
476*4e1ccc60SShengfei Xu if (mmio_read_32(CRU_BASE + RK3568_CLK_SEL(6)) & 0x0800) {
477*4e1ccc60SShengfei Xu return 0;
478*4e1ccc60SShengfei Xu } else {
479*4e1ccc60SShengfei Xu div = mmio_read_32(CRU_BASE + RK3568_CLK_SEL(6));
480*4e1ccc60SShengfei Xu div = div & 0x000f;
481*4e1ccc60SShengfei Xu return GPLL_RATE / (div + 1);
482*4e1ccc60SShengfei Xu }
483*4e1ccc60SShengfei Xu }
484*4e1ccc60SShengfei Xu
clk_gpu_set_rate(unsigned long rate,enum pll_type_sel type)485*4e1ccc60SShengfei Xu static int clk_gpu_set_rate(unsigned long rate, enum pll_type_sel type)
486*4e1ccc60SShengfei Xu {
487*4e1ccc60SShengfei Xu unsigned int length;
488*4e1ccc60SShengfei Xu int div;
489*4e1ccc60SShengfei Xu
490*4e1ccc60SShengfei Xu if (!rate)
491*4e1ccc60SShengfei Xu return SCMI_INVALID_PARAMETERS;
492*4e1ccc60SShengfei Xu
493*4e1ccc60SShengfei Xu /* set gpu div 6 */
494*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(6), CLKDIV_4BITS_SHF0(5));
495*4e1ccc60SShengfei Xu /* set gpu mux gpll */
496*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(6), GPU_CLK_PATH_NOR_GPLL);
497*4e1ccc60SShengfei Xu
498*4e1ccc60SShengfei Xu /* set pvtpll ring */
499*4e1ccc60SShengfei Xu length = rockchip_get_pvtpll_length(rk3568_gpu_pvtpll_table,
500*4e1ccc60SShengfei Xu ARRAY_SIZE(rk3568_gpu_pvtpll_table),
501*4e1ccc60SShengfei Xu rate);
502*4e1ccc60SShengfei Xu if (PVTPLL_NEED(type, length)) {
503*4e1ccc60SShengfei Xu mmio_write_32(GRF_BASE + RK3568_GPU_PVTPLL_CON0,
504*4e1ccc60SShengfei Xu 0xffff0000);
505*4e1ccc60SShengfei Xu udelay(1);
506*4e1ccc60SShengfei Xu mmio_write_32(GRF_BASE + RK3568_GPU_PVTPLL_CON0,
507*4e1ccc60SShengfei Xu 0xffff0000 | length);
508*4e1ccc60SShengfei Xu udelay(1);
509*4e1ccc60SShengfei Xu /* set gpu mux pvtpll */
510*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(6),
511*4e1ccc60SShengfei Xu GPU_CLK_PATH_PVTPLL);
512*4e1ccc60SShengfei Xu }
513*4e1ccc60SShengfei Xu
514*4e1ccc60SShengfei Xu div = DIV_ROUND_UP(GPLL_RATE, rate);
515*4e1ccc60SShengfei Xu /* set gpu div */
516*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(6), CLKDIV_4BITS_SHF0((div - 1)));
517*4e1ccc60SShengfei Xu
518*4e1ccc60SShengfei Xu return 0;
519*4e1ccc60SShengfei Xu }
520*4e1ccc60SShengfei Xu
clk_scmi_gpu_set_rate(struct rk_scmi_clock * clock,unsigned long rate)521*4e1ccc60SShengfei Xu static int clk_scmi_gpu_set_rate(struct rk_scmi_clock *clock, unsigned long rate)
522*4e1ccc60SShengfei Xu {
523*4e1ccc60SShengfei Xu int ret;
524*4e1ccc60SShengfei Xu
525*4e1ccc60SShengfei Xu ret = clk_gpu_set_rate(rate, PLL_SEL_AUTO);
526*4e1ccc60SShengfei Xu
527*4e1ccc60SShengfei Xu if (!ret)
528*4e1ccc60SShengfei Xu sys_clk_info.gpu_rate = rate;
529*4e1ccc60SShengfei Xu return ret;
530*4e1ccc60SShengfei Xu }
531*4e1ccc60SShengfei Xu
clk_scmi_gpu_set_status(struct rk_scmi_clock * clock,bool status)532*4e1ccc60SShengfei Xu static int clk_scmi_gpu_set_status(struct rk_scmi_clock *clock, bool status)
533*4e1ccc60SShengfei Xu {
534*4e1ccc60SShengfei Xu return 0;
535*4e1ccc60SShengfei Xu }
536*4e1ccc60SShengfei Xu
clk_scmi_npu_get_rate(struct rk_scmi_clock * clock)537*4e1ccc60SShengfei Xu static unsigned long clk_scmi_npu_get_rate(struct rk_scmi_clock *clock)
538*4e1ccc60SShengfei Xu {
539*4e1ccc60SShengfei Xu int div;
540*4e1ccc60SShengfei Xu
541*4e1ccc60SShengfei Xu if (mmio_read_32(CRU_BASE + RK3568_CLK_SEL(7)) & 0x8000) {
542*4e1ccc60SShengfei Xu return 0;
543*4e1ccc60SShengfei Xu } else {
544*4e1ccc60SShengfei Xu div = mmio_read_32(CRU_BASE + RK3568_CLK_SEL(7));
545*4e1ccc60SShengfei Xu div = div & 0x000f;
546*4e1ccc60SShengfei Xu return GPLL_RATE / (div + 1);
547*4e1ccc60SShengfei Xu }
548*4e1ccc60SShengfei Xu }
549*4e1ccc60SShengfei Xu
clk_npu_set_rate(unsigned long rate,enum pll_type_sel type)550*4e1ccc60SShengfei Xu static int clk_npu_set_rate(unsigned long rate, enum pll_type_sel type)
551*4e1ccc60SShengfei Xu {
552*4e1ccc60SShengfei Xu unsigned int length;
553*4e1ccc60SShengfei Xu int div;
554*4e1ccc60SShengfei Xu
555*4e1ccc60SShengfei Xu if (!rate)
556*4e1ccc60SShengfei Xu return SCMI_INVALID_PARAMETERS;
557*4e1ccc60SShengfei Xu
558*4e1ccc60SShengfei Xu /* set npu div 6 */
559*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(7),
560*4e1ccc60SShengfei Xu CLKDIV_2BITS_SHF4(2) | CLKDIV_4BITS_SHF0(5));
561*4e1ccc60SShengfei Xu /* set npu mux gpll */
562*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(7),
563*4e1ccc60SShengfei Xu NPU_CLK_PATH_NOR_GPLL | CLK_NPU_NP5_SRC_GPLL);
564*4e1ccc60SShengfei Xu
565*4e1ccc60SShengfei Xu /* set pvtpll ring */
566*4e1ccc60SShengfei Xu length = rockchip_get_pvtpll_length(rk3568_npu_pvtpll_table,
567*4e1ccc60SShengfei Xu ARRAY_SIZE(rk3568_npu_pvtpll_table),
568*4e1ccc60SShengfei Xu rate);
569*4e1ccc60SShengfei Xu if (PVTPLL_NEED(type, length)) {
570*4e1ccc60SShengfei Xu mmio_write_32(GRF_BASE + RK3568_NPU_PVTPLL_CON0,
571*4e1ccc60SShengfei Xu 0xffff0000);
572*4e1ccc60SShengfei Xu udelay(1);
573*4e1ccc60SShengfei Xu mmio_write_32(GRF_BASE + RK3568_NPU_PVTPLL_CON0,
574*4e1ccc60SShengfei Xu 0xffff0000 | length);
575*4e1ccc60SShengfei Xu udelay(1);
576*4e1ccc60SShengfei Xu /* set npu mux pvtpll */
577*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(7),
578*4e1ccc60SShengfei Xu NPU_CLK_PATH_PVTPLL);
579*4e1ccc60SShengfei Xu } else {
580*4e1ccc60SShengfei Xu div = DIV_ROUND_UP(GPLL_RATE, rate);
581*4e1ccc60SShengfei Xu /* set gpu div */
582*4e1ccc60SShengfei Xu mmio_write_32(CRU_BASE + RK3568_CLK_SEL(7),
583*4e1ccc60SShengfei Xu CLKDIV_4BITS_SHF0((div - 1)));
584*4e1ccc60SShengfei Xu }
585*4e1ccc60SShengfei Xu
586*4e1ccc60SShengfei Xu return 0;
587*4e1ccc60SShengfei Xu }
588*4e1ccc60SShengfei Xu
clk_scmi_npu_set_rate(struct rk_scmi_clock * clock,unsigned long rate)589*4e1ccc60SShengfei Xu static int clk_scmi_npu_set_rate(struct rk_scmi_clock *clock, unsigned long rate)
590*4e1ccc60SShengfei Xu {
591*4e1ccc60SShengfei Xu int ret;
592*4e1ccc60SShengfei Xu
593*4e1ccc60SShengfei Xu ret = clk_npu_set_rate(rate, PLL_SEL_AUTO);
594*4e1ccc60SShengfei Xu
595*4e1ccc60SShengfei Xu if (!ret)
596*4e1ccc60SShengfei Xu sys_clk_info.npu_rate = rate;
597*4e1ccc60SShengfei Xu
598*4e1ccc60SShengfei Xu return ret;
599*4e1ccc60SShengfei Xu }
600*4e1ccc60SShengfei Xu
clk_scmi_npu_set_status(struct rk_scmi_clock * clock,bool status)601*4e1ccc60SShengfei Xu static int clk_scmi_npu_set_status(struct rk_scmi_clock *clock, bool status)
602*4e1ccc60SShengfei Xu {
603*4e1ccc60SShengfei Xu return 0;
604*4e1ccc60SShengfei Xu }
605*4e1ccc60SShengfei Xu
606*4e1ccc60SShengfei Xu static const struct rk_clk_ops clk_scmi_cpu_ops = {
607*4e1ccc60SShengfei Xu .get_rate = clk_scmi_cpu_get_rate,
608*4e1ccc60SShengfei Xu .set_rate = clk_scmi_cpu_set_rate,
609*4e1ccc60SShengfei Xu .set_status = clk_scmi_cpu_set_status,
610*4e1ccc60SShengfei Xu };
611*4e1ccc60SShengfei Xu
612*4e1ccc60SShengfei Xu static const struct rk_clk_ops clk_scmi_gpu_ops = {
613*4e1ccc60SShengfei Xu .get_rate = clk_scmi_gpu_get_rate,
614*4e1ccc60SShengfei Xu .set_rate = clk_scmi_gpu_set_rate,
615*4e1ccc60SShengfei Xu .set_status = clk_scmi_gpu_set_status,
616*4e1ccc60SShengfei Xu };
617*4e1ccc60SShengfei Xu
618*4e1ccc60SShengfei Xu static const struct rk_clk_ops clk_scmi_npu_ops = {
619*4e1ccc60SShengfei Xu .get_rate = clk_scmi_npu_get_rate,
620*4e1ccc60SShengfei Xu .set_rate = clk_scmi_npu_set_rate,
621*4e1ccc60SShengfei Xu .set_status = clk_scmi_npu_set_status,
622*4e1ccc60SShengfei Xu };
623*4e1ccc60SShengfei Xu
624*4e1ccc60SShengfei Xu struct rk_scmi_clock clock_table[] = {
625*4e1ccc60SShengfei Xu {
626*4e1ccc60SShengfei Xu .id = 0,
627*4e1ccc60SShengfei Xu .name = "clk_scmi_cpu",
628*4e1ccc60SShengfei Xu .clk_ops = &clk_scmi_cpu_ops,
629*4e1ccc60SShengfei Xu .rate_table = rk3568_cpu_rates,
630*4e1ccc60SShengfei Xu .rate_cnt = ARRAY_SIZE(rk3568_cpu_rates),
631*4e1ccc60SShengfei Xu },
632*4e1ccc60SShengfei Xu {
633*4e1ccc60SShengfei Xu .id = 1,
634*4e1ccc60SShengfei Xu .name = "clk_scmi_gpu",
635*4e1ccc60SShengfei Xu .clk_ops = &clk_scmi_gpu_ops,
636*4e1ccc60SShengfei Xu .rate_table = rk3568_gpu_rates,
637*4e1ccc60SShengfei Xu .rate_cnt = ARRAY_SIZE(rk3568_gpu_rates),
638*4e1ccc60SShengfei Xu },
639*4e1ccc60SShengfei Xu {
640*4e1ccc60SShengfei Xu .id = 2,
641*4e1ccc60SShengfei Xu .name = "clk_scmi_npu",
642*4e1ccc60SShengfei Xu .clk_ops = &clk_scmi_npu_ops,
643*4e1ccc60SShengfei Xu .rate_table = rk3568_gpu_rates,
644*4e1ccc60SShengfei Xu .rate_cnt = ARRAY_SIZE(rk3568_gpu_rates),
645*4e1ccc60SShengfei Xu },
646*4e1ccc60SShengfei Xu };
647*4e1ccc60SShengfei Xu
rockchip_scmi_clock_count(unsigned int agent_id __unused)648*4e1ccc60SShengfei Xu size_t rockchip_scmi_clock_count(unsigned int agent_id __unused)
649*4e1ccc60SShengfei Xu {
650*4e1ccc60SShengfei Xu return ARRAY_SIZE(clock_table);
651*4e1ccc60SShengfei Xu }
652*4e1ccc60SShengfei Xu
rockchip_scmi_get_clock(uint32_t agent_id __unused,uint32_t clock_id)653*4e1ccc60SShengfei Xu rk_scmi_clock_t *rockchip_scmi_get_clock(uint32_t agent_id __unused,
654*4e1ccc60SShengfei Xu uint32_t clock_id)
655*4e1ccc60SShengfei Xu {
656*4e1ccc60SShengfei Xu if (clock_id < ARRAY_SIZE(clock_table))
657*4e1ccc60SShengfei Xu return &clock_table[clock_id];
658*4e1ccc60SShengfei Xu
659*4e1ccc60SShengfei Xu return NULL;
660*4e1ccc60SShengfei Xu }
661*4e1ccc60SShengfei Xu
pvtplls_suspend(void)662*4e1ccc60SShengfei Xu void pvtplls_suspend(void)
663*4e1ccc60SShengfei Xu {
664*4e1ccc60SShengfei Xu clk_gpu_set_rate(100000000, PLL_SEL_NOR);
665*4e1ccc60SShengfei Xu clk_npu_set_rate(100000000, PLL_SEL_NOR);
666*4e1ccc60SShengfei Xu clk_cpu_set_rate(408000000, PLL_SEL_NOR);
667*4e1ccc60SShengfei Xu }
668*4e1ccc60SShengfei Xu
pvtplls_resume(void)669*4e1ccc60SShengfei Xu void pvtplls_resume(void)
670*4e1ccc60SShengfei Xu {
671*4e1ccc60SShengfei Xu clk_cpu_set_rate(sys_clk_info.cpu_rate, PLL_SEL_AUTO);
672*4e1ccc60SShengfei Xu clk_gpu_set_rate(sys_clk_info.gpu_rate, PLL_SEL_AUTO);
673*4e1ccc60SShengfei Xu clk_npu_set_rate(sys_clk_info.npu_rate, PLL_SEL_AUTO);
674*4e1ccc60SShengfei Xu }
675*4e1ccc60SShengfei Xu
sys_reset_pvtplls_prepare(void)676*4e1ccc60SShengfei Xu void sys_reset_pvtplls_prepare(void)
677*4e1ccc60SShengfei Xu {
678*4e1ccc60SShengfei Xu clk_gpu_set_rate(100000000, PLL_SEL_NOR);
679*4e1ccc60SShengfei Xu clk_npu_set_rate(100000000, PLL_SEL_NOR);
680*4e1ccc60SShengfei Xu clk_cpu_set_rate(408000000, PLL_SEL_NOR);
681*4e1ccc60SShengfei Xu }
682*4e1ccc60SShengfei Xu
rockchip_clock_init(void)683*4e1ccc60SShengfei Xu void rockchip_clock_init(void)
684*4e1ccc60SShengfei Xu {
685*4e1ccc60SShengfei Xu struct otp_opp_info cpu_opp_info, gpu_opp_info, npu_opp_info;
686*4e1ccc60SShengfei Xu int ret;
687*4e1ccc60SShengfei Xu
688*4e1ccc60SShengfei Xu ret = rk_otp_read(RK3568_CPU_OPP_INFO_OFFSET,
689*4e1ccc60SShengfei Xu sizeof(cpu_opp_info),
690*4e1ccc60SShengfei Xu (uint16_t *)&cpu_opp_info,
691*4e1ccc60SShengfei Xu true);
692*4e1ccc60SShengfei Xu if (ret || !check_otp_ecc_ok(RK3568_CPU_OPP_INFO_OFFSET)) {
693*4e1ccc60SShengfei Xu INFO("get cpu_opp_info fail, use default config!\n");
694*4e1ccc60SShengfei Xu cpu_opp_info.min_freq = 1008;
695*4e1ccc60SShengfei Xu cpu_opp_info.max_freq = 1992;
696*4e1ccc60SShengfei Xu cpu_opp_info.volt = 50;
697*4e1ccc60SShengfei Xu cpu_opp_info.length = 4;
698*4e1ccc60SShengfei Xu }
699*4e1ccc60SShengfei Xu if (cpu_opp_info.length) {
700*4e1ccc60SShengfei Xu INFO("adjust cpu pvtpll: min=%uM, max=%uM, length=%u\n",
701*4e1ccc60SShengfei Xu cpu_opp_info.min_freq, cpu_opp_info.max_freq, cpu_opp_info.length);
702*4e1ccc60SShengfei Xu
703*4e1ccc60SShengfei Xu rk3568_adjust_pvtpll_table(rk3568_cpu_pvtpll_table,
704*4e1ccc60SShengfei Xu ARRAY_SIZE(rk3568_cpu_pvtpll_table),
705*4e1ccc60SShengfei Xu cpu_opp_info.min_freq,
706*4e1ccc60SShengfei Xu cpu_opp_info.max_freq,
707*4e1ccc60SShengfei Xu cpu_opp_info.length);
708*4e1ccc60SShengfei Xu }
709*4e1ccc60SShengfei Xu
710*4e1ccc60SShengfei Xu ret = rk_otp_read(RK3568_GPU_OPP_INFO_OFFSET,
711*4e1ccc60SShengfei Xu sizeof(gpu_opp_info),
712*4e1ccc60SShengfei Xu (uint16_t *)&gpu_opp_info,
713*4e1ccc60SShengfei Xu true);
714*4e1ccc60SShengfei Xu if (ret || !check_otp_ecc_ok(RK3568_GPU_OPP_INFO_OFFSET)) {
715*4e1ccc60SShengfei Xu INFO("get gpu_opp_info fail, use default config!\n");
716*4e1ccc60SShengfei Xu gpu_opp_info.min_freq = 600;
717*4e1ccc60SShengfei Xu gpu_opp_info.max_freq = 800;
718*4e1ccc60SShengfei Xu gpu_opp_info.volt = 50;
719*4e1ccc60SShengfei Xu gpu_opp_info.length = 6;
720*4e1ccc60SShengfei Xu }
721*4e1ccc60SShengfei Xu if (gpu_opp_info.length) {
722*4e1ccc60SShengfei Xu INFO("adjust gpu pvtpll: min=%uM, max=%uM, length=%u\n",
723*4e1ccc60SShengfei Xu gpu_opp_info.min_freq, gpu_opp_info.max_freq, gpu_opp_info.length);
724*4e1ccc60SShengfei Xu
725*4e1ccc60SShengfei Xu rk3568_adjust_pvtpll_table(rk3568_gpu_pvtpll_table,
726*4e1ccc60SShengfei Xu ARRAY_SIZE(rk3568_gpu_pvtpll_table),
727*4e1ccc60SShengfei Xu gpu_opp_info.min_freq,
728*4e1ccc60SShengfei Xu gpu_opp_info.max_freq,
729*4e1ccc60SShengfei Xu gpu_opp_info.length);
730*4e1ccc60SShengfei Xu }
731*4e1ccc60SShengfei Xu
732*4e1ccc60SShengfei Xu ret = rk_otp_read(RK3568_NPU_OPP_INFO_OFFSET,
733*4e1ccc60SShengfei Xu sizeof(npu_opp_info),
734*4e1ccc60SShengfei Xu (uint16_t *)&npu_opp_info,
735*4e1ccc60SShengfei Xu true);
736*4e1ccc60SShengfei Xu if (ret || !check_otp_ecc_ok(RK3568_NPU_OPP_INFO_OFFSET)) {
737*4e1ccc60SShengfei Xu INFO("get npu_opp_info fail, use default config!\n");
738*4e1ccc60SShengfei Xu npu_opp_info.min_freq = 600;
739*4e1ccc60SShengfei Xu npu_opp_info.max_freq = 1000;
740*4e1ccc60SShengfei Xu npu_opp_info.volt = 50;
741*4e1ccc60SShengfei Xu npu_opp_info.length = 6;
742*4e1ccc60SShengfei Xu }
743*4e1ccc60SShengfei Xu if (npu_opp_info.length) {
744*4e1ccc60SShengfei Xu INFO("adjust npu pvtpll: min=%uM, max=%uM, length=%u\n",
745*4e1ccc60SShengfei Xu npu_opp_info.min_freq, npu_opp_info.max_freq, npu_opp_info.length);
746*4e1ccc60SShengfei Xu
747*4e1ccc60SShengfei Xu rk3568_adjust_pvtpll_table(rk3568_npu_pvtpll_table,
748*4e1ccc60SShengfei Xu ARRAY_SIZE(rk3568_npu_pvtpll_table),
749*4e1ccc60SShengfei Xu npu_opp_info.min_freq,
750*4e1ccc60SShengfei Xu npu_opp_info.max_freq,
751*4e1ccc60SShengfei Xu npu_opp_info.length);
752*4e1ccc60SShengfei Xu }
753*4e1ccc60SShengfei Xu }
754