1*036935a8SXiaoDong Huang // SPDX-License-Identifier: BSD-3-Clause
2*036935a8SXiaoDong Huang /*
3*036935a8SXiaoDong Huang * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
4*036935a8SXiaoDong Huang */
5*036935a8SXiaoDong Huang
6*036935a8SXiaoDong Huang #include <assert.h>
7*036935a8SXiaoDong Huang #include <errno.h>
8*036935a8SXiaoDong Huang
9*036935a8SXiaoDong Huang #include <drivers/delay_timer.h>
10*036935a8SXiaoDong Huang #include <drivers/scmi.h>
11*036935a8SXiaoDong Huang #include <lib/mmio.h>
12*036935a8SXiaoDong Huang #include <lib/spinlock.h>
13*036935a8SXiaoDong Huang #include <platform_def.h>
14*036935a8SXiaoDong Huang
15*036935a8SXiaoDong Huang #include <plat_private.h>
16*036935a8SXiaoDong Huang #include <rk3576_clk.h>
17*036935a8SXiaoDong Huang #include <rockchip_sip_svc.h>
18*036935a8SXiaoDong Huang #include <scmi_clock.h>
19*036935a8SXiaoDong Huang #include <soc.h>
20*036935a8SXiaoDong Huang
21*036935a8SXiaoDong Huang enum pll_type_sel {
22*036935a8SXiaoDong Huang PLL_SEL_AUTO, /* all plls (normal pll or pvtpll) */
23*036935a8SXiaoDong Huang PLL_SEL_PVT,
24*036935a8SXiaoDong Huang PLL_SEL_NOR,
25*036935a8SXiaoDong Huang PLL_SEL_AUTO_NOR /* all normal plls (apll/gpll/npll) */
26*036935a8SXiaoDong Huang };
27*036935a8SXiaoDong Huang
28*036935a8SXiaoDong Huang #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
29*036935a8SXiaoDong Huang
30*036935a8SXiaoDong Huang #define RK3576_PVTPLL_RING_EN 0x00
31*036935a8SXiaoDong Huang #define RK3576_PVTPLL_RING0_LENGTH 0x04
32*036935a8SXiaoDong Huang #define RK3576_PVTPLL_RING1_LENGTH 0x08
33*036935a8SXiaoDong Huang #define RK3576_PVTPLL_RING2_LENGTH 0x0c
34*036935a8SXiaoDong Huang #define RK3576_PVTPLL_RING3_LENGTH 0x10
35*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GCK_CFG 0x20
36*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GCK_LEN 0x24
37*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GCK_DIV 0x28
38*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GCK_CAL_CNT 0x2c
39*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GCK_REF_VAL 0x30
40*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GCK_CFG_VAL 0x34
41*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GCK_THR 0x38
42*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GFREE_CON 0x3c
43*036935a8SXiaoDong Huang #define RK3576_PVTPLL_ADC_CFG 0x40
44*036935a8SXiaoDong Huang #define RK3576_PVTPLL_ADC_CAL_CNT 0x48
45*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GCK_CNT 0x50
46*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GCK_CNT_AVG 0x54
47*036935a8SXiaoDong Huang #define RK3576_PVTPLL_GCK_STATE 0x5c
48*036935a8SXiaoDong Huang #define RK3576_PVTPLL_ADC_CNT 0x60
49*036935a8SXiaoDong Huang #define RK3576_PVTPLL_ADC_CNT_AVG 0x68
50*036935a8SXiaoDong Huang #define RK3576_PVTPLL_VERSION 0x70
51*036935a8SXiaoDong Huang #define RK3576_PVTPLL_MAX_LENGTH 0x3f
52*036935a8SXiaoDong Huang
53*036935a8SXiaoDong Huang #define GPLL_RATE 1188000000
54*036935a8SXiaoDong Huang #define CPLL_RATE 1000000000
55*036935a8SXiaoDong Huang #define SPLL_RATE 702000000
56*036935a8SXiaoDong Huang #define AUPLL_RATE 786431952
57*036935a8SXiaoDong Huang
58*036935a8SXiaoDong Huang #define MAX_RATE_TABLE 16
59*036935a8SXiaoDong Huang
60*036935a8SXiaoDong Huang #define CLKDIV_6BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0x3fU, shift)
61*036935a8SXiaoDong Huang #define CLKDIV_5BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0x1fU, shift)
62*036935a8SXiaoDong Huang #define CLKDIV_4BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0xfU, shift)
63*036935a8SXiaoDong Huang #define CLKDIV_3BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0x7U, shift)
64*036935a8SXiaoDong Huang #define CLKDIV_2BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0x3U, shift)
65*036935a8SXiaoDong Huang #define CLKDIV_1BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0x1U, shift)
66*036935a8SXiaoDong Huang
67*036935a8SXiaoDong Huang #define CPU_PLL_PATH_SLOWMODE BITS_WITH_WMASK(0U, 0x3U, 0)
68*036935a8SXiaoDong Huang #define CPU_PLL_PATH_NORMAL BITS_WITH_WMASK(1U, 0x3U, 0)
69*036935a8SXiaoDong Huang #define CPU_PLL_PATH_DEEP_SLOW BITS_WITH_WMASK(2U, 0x3U, 0)
70*036935a8SXiaoDong Huang
71*036935a8SXiaoDong Huang #define CRU_PLL_POWER_DOWN BIT_WITH_WMSK(13)
72*036935a8SXiaoDong Huang #define CRU_PLL_POWER_UP WMSK_BIT(13)
73*036935a8SXiaoDong Huang
74*036935a8SXiaoDong Huang /* clk_core:
75*036935a8SXiaoDong Huang * from normal pll(core_i: gpll or apll) path or direct pass from apll
76*036935a8SXiaoDong Huang */
77*036935a8SXiaoDong Huang
78*036935a8SXiaoDong Huang /* cpul clk path */
79*036935a8SXiaoDong Huang #define CPUL_CLK_PATH_NOR_GPLL BITS_WITH_WMASK(1U, 0x3U, 12)
80*036935a8SXiaoDong Huang #define CPUL_CLK_PATH_NOR_LPLL BITS_WITH_WMASK(0U, 0x3U, 12)
81*036935a8SXiaoDong Huang #define CPUL_CLK_PATH_NOR_PVTPLL BITS_WITH_WMASK(2U, 0x3U, 12)
82*036935a8SXiaoDong Huang
83*036935a8SXiaoDong Huang #define CPUL_CLK_PATH_LPLL BITS_WITH_WMASK(0U, 0x3U, 6)
84*036935a8SXiaoDong Huang #define CPUL_CLK_PATH_DIR_LPLL BITS_WITH_WMASK(2U, 0x3U, 6)
85*036935a8SXiaoDong Huang #define CPUL_CLK_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x3U, 6)
86*036935a8SXiaoDong Huang
87*036935a8SXiaoDong Huang #define CPUL_PVTPLL_PATH_DEEP_SLOW BITS_WITH_WMASK(0U, 0x1U, 13)
88*036935a8SXiaoDong Huang #define CPUL_PVTPLL_PATH_PVTPLL BITS_WITH_WMASK(0x1, 0x1U, 13)
89*036935a8SXiaoDong Huang
90*036935a8SXiaoDong Huang /* cpub clk path */
91*036935a8SXiaoDong Huang #define CPUB_CLK_PATH_NOR_GPLL BITS_WITH_WMASK(1U, 0x3U, 12)
92*036935a8SXiaoDong Huang #define CPUB_CLK_PATH_NOR_BPLL BITS_WITH_WMASK(0U, 0x3U, 12)
93*036935a8SXiaoDong Huang #define CPUB_CLK_PATH_NOR_PVTPLL BITS_WITH_WMASK(2U, 0x3U, 12)
94*036935a8SXiaoDong Huang
95*036935a8SXiaoDong Huang #define CPUB_CLK_PATH_BPLL BITS_WITH_WMASK(0U, 0x3U, 14)
96*036935a8SXiaoDong Huang #define CPUB_CLK_PATH_DIR_BPLL BITS_WITH_WMASK(2U, 0x3U, 14)
97*036935a8SXiaoDong Huang #define CPUB_CLK_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x3U, 14)
98*036935a8SXiaoDong Huang
99*036935a8SXiaoDong Huang #define CPUB_PVTPLL_PATH_DEEP_SLOW BITS_WITH_WMASK(0U, 0x1U, 5)
100*036935a8SXiaoDong Huang #define CPUB_PVTPLL_PATH_PVTPLL BITS_WITH_WMASK(0x1, 0x1U, 5)
101*036935a8SXiaoDong Huang
102*036935a8SXiaoDong Huang #define CPUB_PCLK_PATH_100M BITS_WITH_WMASK(0U, 0x3U, 0)
103*036935a8SXiaoDong Huang #define CPUB_PCLK_PATH_50M BITS_WITH_WMASK(1U, 0x3U, 0)
104*036935a8SXiaoDong Huang #define CPUB_PCLK_PATH_24M BITS_WITH_WMASK(2U, 0x3U, 0)
105*036935a8SXiaoDong Huang
106*036935a8SXiaoDong Huang /* cci clk path */
107*036935a8SXiaoDong Huang #define SCLK_CCI_PATH_XIN BITS_WITH_WMASK(0U, 0x3U, 12)
108*036935a8SXiaoDong Huang #define SCLK_CCI_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x3U, 12)
109*036935a8SXiaoDong Huang #define SCLK_CCI_PATH_NOR_LPLL BITS_WITH_WMASK(3U, 0x3U, 12)
110*036935a8SXiaoDong Huang #define SCLK_CCI_PATH_NOR_GPLL BITS_WITH_WMASK(2U, 0x3U, 12)
111*036935a8SXiaoDong Huang
112*036935a8SXiaoDong Huang #define CCI_PVTPLL_PATH_DEEP_SLOW BITS_WITH_WMASK(0U, 0x1U, 14)
113*036935a8SXiaoDong Huang #define CCI_PVTPLL_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x1U, 14)
114*036935a8SXiaoDong Huang
115*036935a8SXiaoDong Huang /* npu clk path */
116*036935a8SXiaoDong Huang #define NPU_CLK_PATH_NOR_GPLL BITS_WITH_WMASK(0U, 0x7U, 7)
117*036935a8SXiaoDong Huang #define NPU_CLK_PATH_NOR_CPLL BITS_WITH_WMASK(1U, 0x7U, 7)
118*036935a8SXiaoDong Huang #define NPU_CLK_PATH_NOR_AUPLL BITS_WITH_WMASK(2U, 0x7U, 7)
119*036935a8SXiaoDong Huang #define NPU_CLK_PATH_NOR_SPLL BITS_WITH_WMASK(3U, 0x7U, 7)
120*036935a8SXiaoDong Huang
121*036935a8SXiaoDong Huang #define NPU_CLK_PATH_NOR_PLL WMSK_BIT(15)
122*036935a8SXiaoDong Huang #define NPU_CLK_PATH_PVTPLL BIT_WITH_WMSK(15)
123*036935a8SXiaoDong Huang #define NPU_PVTPLL_PATH_DEEP_SLOW BITS_WITH_WMASK(0U, 0x1U, 9)
124*036935a8SXiaoDong Huang #define NPU_PVTPLL_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x1U, 9)
125*036935a8SXiaoDong Huang
126*036935a8SXiaoDong Huang /* gpu clk path */
127*036935a8SXiaoDong Huang #define GPU_CLK_PATH_NOR_GPLL BITS_WITH_WMASK(0U, 0x7U, 5)
128*036935a8SXiaoDong Huang #define GPU_CLK_PATH_NOR_CPLL BITS_WITH_WMASK(1U, 0x7U, 5)
129*036935a8SXiaoDong Huang #define GPU_CLK_PATH_NOR_AUPLL BITS_WITH_WMASK(2U, 0x7U, 5)
130*036935a8SXiaoDong Huang #define GPU_CLK_PATH_NOR_SPLL BITS_WITH_WMASK(3U, 0x7U, 5)
131*036935a8SXiaoDong Huang #define GPU_CLK_PATH_NOR_LPLL BITS_WITH_WMASK(4U, 0x7U, 5)
132*036935a8SXiaoDong Huang #define GPU_CLK_PATH_NOR_PLL WMSK_BIT(8)
133*036935a8SXiaoDong Huang #define GPU_CLK_PATH_PVTPLL BIT_WITH_WMSK(8)
134*036935a8SXiaoDong Huang #define GPU_PVTPLL_PATH_DEEP_SLOW BITS_WITH_WMASK(0U, 0x1U, 9)
135*036935a8SXiaoDong Huang #define GPU_PVTPLL_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x1U, 9)
136*036935a8SXiaoDong Huang
137*036935a8SXiaoDong Huang #define PVTPLL_NEED(type, length) (((type) == PLL_SEL_PVT || \
138*036935a8SXiaoDong Huang (type) == PLL_SEL_AUTO) && \
139*036935a8SXiaoDong Huang (length))
140*036935a8SXiaoDong Huang /*
141*036935a8SXiaoDong Huang * [0]: set intermediate rate
142*036935a8SXiaoDong Huang * [1]: scaling up rate or scaling down rate
143*036935a8SXiaoDong Huang * [1]: add length for pvtpll
144*036935a8SXiaoDong Huang * [2:5]: length
145*036935a8SXiaoDong Huang * [2]: use low length for pvtpll
146*036935a8SXiaoDong Huang * [3:5]: reserved
147*036935a8SXiaoDong Huang */
148*036935a8SXiaoDong Huang #define OPP_RATE_MASK 0x3f
149*036935a8SXiaoDong Huang #define OPP_INTERMEDIATE_RATE BIT(0)
150*036935a8SXiaoDong Huang #define OPP_SCALING_UP_RATE BIT(1)
151*036935a8SXiaoDong Huang #define OPP_ADD_LENGTH BIT(1)
152*036935a8SXiaoDong Huang #define OPP_LENGTH_MASK GENMASK_32(5, 2)
153*036935a8SXiaoDong Huang #define OPP_LENGTH_SHIFT 2
154*036935a8SXiaoDong Huang #define OPP_LENGTH_LOW BIT(2)
155*036935a8SXiaoDong Huang
156*036935a8SXiaoDong Huang #define PRATE(x) static const unsigned long const x[]
157*036935a8SXiaoDong Huang #define PINFO(x) static const uint32_t const x[]
158*036935a8SXiaoDong Huang
159*036935a8SXiaoDong Huang PRATE(p_24m) = { OSC_HZ };
160*036935a8SXiaoDong Huang PRATE(p_100m_24m) = { 100 * MHz, OSC_HZ };
161*036935a8SXiaoDong Huang PRATE(p_350m_175m_116m_24m) = { 350 * MHz, 175 * MHz, 116 * MHz, OSC_HZ };
162*036935a8SXiaoDong Huang PRATE(p_175m_116m_58m_24m) = { 175 * MHz, 116 * MHz, 58 * MHz, OSC_HZ };
163*036935a8SXiaoDong Huang PRATE(p_116m_58m_24m) = { 116 * MHz, 58 * MHz, OSC_HZ };
164*036935a8SXiaoDong Huang PRATE(p_pclk_secure_s) = { PCLK_SECURE_S };
165*036935a8SXiaoDong Huang PRATE(p_hclk_secure_s) = { HCLK_SECURE_S };
166*036935a8SXiaoDong Huang PRATE(p_aclk_secure_s) = { ACLK_SECURE_S };
167*036935a8SXiaoDong Huang PRATE(p_hclk_vo0_s) = { HCLK_VO0_S };
168*036935a8SXiaoDong Huang PRATE(p_pclk_vo0_s) = { PCLK_VO0_S };
169*036935a8SXiaoDong Huang PRATE(p_hclk_vo1_s) = { HCLK_VO1_S };
170*036935a8SXiaoDong Huang PRATE(p_pclk_vo1_s) = { PCLK_VO1_S };
171*036935a8SXiaoDong Huang
172*036935a8SXiaoDong Huang PINFO(clk_stimer0_root_info) = { 0x27214004, 6, 1, 0, 0, 0, 0x27214028, 9 };
173*036935a8SXiaoDong Huang PINFO(clk_stimer1_root_info) = { 0x27214004, 7, 1, 0, 0, 0, 0x2721402c, 1 };
174*036935a8SXiaoDong Huang PINFO(pclk_secure_s_info) = { 0x27214004, 4, 2, 0, 0, 0, 0x27214028, 2 };
175*036935a8SXiaoDong Huang PINFO(hclk_secure_s_info) = { 0x27214004, 2, 2, 0, 0, 0, 0x27214028, 1 };
176*036935a8SXiaoDong Huang PINFO(aclk_secure_s_info) = { 0x27214004, 0, 2, 0, 0, 0, 0x27214028, 0 };
177*036935a8SXiaoDong Huang PINFO(clk_pka_crypto_s_info) = { 0x27214004, 11, 2, 0, 0, 0, 0x27214030, 11 };
178*036935a8SXiaoDong Huang PINFO(hclk_vo1_s_info) = { 0x27214010, 0, 2, 0, 0, 0, 0x27214038, 1 };
179*036935a8SXiaoDong Huang PINFO(pclk_vo1_s_info) = { 0x27214010, 2, 2, 0, 0, 0, 0x27214038, 4 };
180*036935a8SXiaoDong Huang PINFO(hclk_vo0_s_info) = { 0x27214018, 0, 2, 0, 0, 0, 0x2721403c, 1 };
181*036935a8SXiaoDong Huang PINFO(pclk_vo0_s_info) = { 0x27214018, 2, 2, 0, 0, 0, 0x2721403c, 4 };
182*036935a8SXiaoDong Huang PINFO(pclk_klad_info) = { 0, 0, 0, 0, 0, 0, 0x27214030, 7 };
183*036935a8SXiaoDong Huang PINFO(hclk_crypto_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214030, 8 };
184*036935a8SXiaoDong Huang PINFO(hclk_klad_info) = { 0, 0, 0, 0, 0, 0, 0x27214030, 9 };
185*036935a8SXiaoDong Huang PINFO(aclk_crypto_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214030, 12 };
186*036935a8SXiaoDong Huang PINFO(hclk_trng_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214034, 0 };
187*036935a8SXiaoDong Huang PINFO(pclk_otpc_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214034, 3 };
188*036935a8SXiaoDong Huang PINFO(clk_otpc_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214034, 4 };
189*036935a8SXiaoDong Huang PINFO(pclk_wdt_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214034, 9 };
190*036935a8SXiaoDong Huang PINFO(tclk_wdt_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214034, 10 };
191*036935a8SXiaoDong Huang PINFO(pclk_hdcp1_trng_info) = { 0, 0, 0, 0, 0, 0, 0x27214038, 0 };
192*036935a8SXiaoDong Huang PINFO(hclk_hdcp_key1_info) = { 0, 0, 0, 0, 0, 0, 0x27214038, 3 };
193*036935a8SXiaoDong Huang PINFO(pclk_hdcp0_trng_info) = { 0, 0, 0, 0, 0, 0, 0x2721403c, 0 };
194*036935a8SXiaoDong Huang PINFO(hclk_hdcp_key0_info) = { 0, 0, 0, 0, 0, 0, 0x2721403c, 3 };
195*036935a8SXiaoDong Huang PINFO(pclk_edp_s_info) = { 0, 0, 0, 0, 0, 0, 0x2721403c, 5 };
196*036935a8SXiaoDong Huang
197*036935a8SXiaoDong Huang struct pvtpll_table {
198*036935a8SXiaoDong Huang unsigned int rate;
199*036935a8SXiaoDong Huang uint32_t length;
200*036935a8SXiaoDong Huang uint32_t length_frac;
201*036935a8SXiaoDong Huang uint32_t length_low;
202*036935a8SXiaoDong Huang uint32_t length_low_frac;
203*036935a8SXiaoDong Huang uint32_t ring_sel;
204*036935a8SXiaoDong Huang uint32_t volt_sel_thr;
205*036935a8SXiaoDong Huang };
206*036935a8SXiaoDong Huang
207*036935a8SXiaoDong Huang struct sys_clk_info_t {
208*036935a8SXiaoDong Huang struct pvtpll_table *cpul_table;
209*036935a8SXiaoDong Huang struct pvtpll_table *cci_table;
210*036935a8SXiaoDong Huang struct pvtpll_table *cpub_table;
211*036935a8SXiaoDong Huang struct pvtpll_table *gpu_table;
212*036935a8SXiaoDong Huang struct pvtpll_table *npu_table;
213*036935a8SXiaoDong Huang unsigned int cpul_rate_count;
214*036935a8SXiaoDong Huang unsigned int cci_rate_count;
215*036935a8SXiaoDong Huang unsigned int cpub_rate_count;
216*036935a8SXiaoDong Huang unsigned int gpu_rate_count;
217*036935a8SXiaoDong Huang unsigned int npu_rate_count;
218*036935a8SXiaoDong Huang unsigned long cpul_rate;
219*036935a8SXiaoDong Huang unsigned long cci_rate;
220*036935a8SXiaoDong Huang unsigned long cpub_rate;
221*036935a8SXiaoDong Huang unsigned long gpu_rate;
222*036935a8SXiaoDong Huang unsigned long npu_rate;
223*036935a8SXiaoDong Huang };
224*036935a8SXiaoDong Huang
225*036935a8SXiaoDong Huang struct otp_opp_info {
226*036935a8SXiaoDong Huang uint16_t min_freq;
227*036935a8SXiaoDong Huang uint16_t max_freq;
228*036935a8SXiaoDong Huang uint8_t volt;
229*036935a8SXiaoDong Huang uint8_t length;
230*036935a8SXiaoDong Huang } __packed;
231*036935a8SXiaoDong Huang
232*036935a8SXiaoDong Huang #define RK3576_SCMI_CLOCK(_id, _name, _data, _table, _cnt, _is_s) \
233*036935a8SXiaoDong Huang rk_scmi_clock_t _name = { \
234*036935a8SXiaoDong Huang .id = _id, \
235*036935a8SXiaoDong Huang .name = #_name, \
236*036935a8SXiaoDong Huang .clk_ops = _data, \
237*036935a8SXiaoDong Huang .rate_table = _table, \
238*036935a8SXiaoDong Huang .rate_cnt = _cnt, \
239*036935a8SXiaoDong Huang .is_security = _is_s, \
240*036935a8SXiaoDong Huang }
241*036935a8SXiaoDong Huang
242*036935a8SXiaoDong Huang #define RK3576_SCMI_CLOCK_COM(_id, _name, _parent_table, _info, _data, \
243*036935a8SXiaoDong Huang _table, is_d, _is_s) \
244*036935a8SXiaoDong Huang rk_scmi_clock_t _name = { \
245*036935a8SXiaoDong Huang .id = _id, \
246*036935a8SXiaoDong Huang .name = #_name, \
247*036935a8SXiaoDong Huang .parent_table = _parent_table, \
248*036935a8SXiaoDong Huang .info = _info, \
249*036935a8SXiaoDong Huang .clk_ops = _data, \
250*036935a8SXiaoDong Huang .rate_table = _table, \
251*036935a8SXiaoDong Huang .rate_cnt = ARRAY_SIZE(_table), \
252*036935a8SXiaoDong Huang .is_dynamic_prate = is_d, \
253*036935a8SXiaoDong Huang .is_security = _is_s, \
254*036935a8SXiaoDong Huang }
255*036935a8SXiaoDong Huang
256*036935a8SXiaoDong Huang #define ROCKCHIP_PVTPLL(_rate, _sel, _len, _len_frac) \
257*036935a8SXiaoDong Huang { \
258*036935a8SXiaoDong Huang .rate = _rate##U, \
259*036935a8SXiaoDong Huang .ring_sel = _sel, \
260*036935a8SXiaoDong Huang .length = _len, \
261*036935a8SXiaoDong Huang .length_frac = _len_frac, \
262*036935a8SXiaoDong Huang }
263*036935a8SXiaoDong Huang
264*036935a8SXiaoDong Huang static struct pvtpll_table rk3576_cpul_pvtpll_table[] = {
265*036935a8SXiaoDong Huang /* rate_hz, ring_sel, length, length_frac */
266*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(2016000000, 0, 6, 0),
267*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1920000000, 0, 6, 1),
268*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1800000000, 0, 6, 1),
269*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1608000000, 0, 6, 1),
270*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1416000000, 0, 8, 0),
271*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1200000000, 0, 11, 0),
272*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1008000000, 0, 17, 0),
273*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(816000000, 0, 26, 0),
274*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(600000000, 0, 0, 0),
275*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(408000000, 0, 0, 0),
276*036935a8SXiaoDong Huang { /* sentinel */ },
277*036935a8SXiaoDong Huang };
278*036935a8SXiaoDong Huang
279*036935a8SXiaoDong Huang static struct pvtpll_table rk3576_cci_pvtpll_table[] = {
280*036935a8SXiaoDong Huang /* cpul_rate_hz, ring_sel, length, length_frac */
281*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(2016000000 / 2, 0, 27, 0),
282*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1920000000 / 2, 0, 28, 0),
283*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1800000000 / 2, 0, 28, 0),
284*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1608000000 / 2, 0, 30, 0),
285*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1416000000 / 2, 0, 34, 0),
286*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1200000000 / 2, 0, 34, 0),
287*036935a8SXiaoDong Huang { /* sentinel */ },
288*036935a8SXiaoDong Huang };
289*036935a8SXiaoDong Huang
290*036935a8SXiaoDong Huang static struct pvtpll_table rk3576_cpub_pvtpll_table[] = {
291*036935a8SXiaoDong Huang /* rate_hz, ring_sel, length, length_frac, length_low, length_low_frac */
292*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(2208000000, 0, 4, 3),
293*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(2112000000, 0, 5, 0),
294*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(2016000000, 0, 5, 0),
295*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1800000000, 0, 5, 0),
296*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1608000000, 0, 5, 0),
297*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1416000000, 0, 7, 0),
298*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1200000000, 0, 11, 0),
299*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(1008000000, 0, 17, 0),
300*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(816000000, 0, 26, 0),
301*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(600000000, 0, 0, 0),
302*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(408000000, 0, 0, 0),
303*036935a8SXiaoDong Huang { /* sentinel */ },
304*036935a8SXiaoDong Huang };
305*036935a8SXiaoDong Huang
306*036935a8SXiaoDong Huang static struct pvtpll_table rk3576_gpu_pvtpll_table[] = {
307*036935a8SXiaoDong Huang /* rate_hz, ring_sel, length, length_frac, length_low, length_low_frac */
308*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(900000000, 0, 20, 0),
309*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(800000000, 0, 21, 0),
310*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(700000000, 0, 21, 0),
311*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(600000000, 0, 23, 0),
312*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(500000000, 0, 32, 0),
313*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(400000000, 0, 48, 0),
314*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(300000000, 0, 63, 0),
315*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(200000000, 0, 0, 0),
316*036935a8SXiaoDong Huang { /* sentinel */ },
317*036935a8SXiaoDong Huang };
318*036935a8SXiaoDong Huang
319*036935a8SXiaoDong Huang static struct pvtpll_table rk3576_npu_pvtpll_table[] = {
320*036935a8SXiaoDong Huang /* rate_hz, ring_sel, length, length_frac, length_low, length_low_frac */
321*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(950000000, 0, 16, 0),
322*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(900000000, 0, 17, 0),
323*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(800000000, 0, 18, 0),
324*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(700000000, 0, 22, 0),
325*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(600000000, 0, 25, 0),
326*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(500000000, 0, 35, 0),
327*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(400000000, 0, 46, 0),
328*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(300000000, 0, 63, 0),
329*036935a8SXiaoDong Huang ROCKCHIP_PVTPLL(200000000, 0, 0, 0),
330*036935a8SXiaoDong Huang { /* sentinel */ },
331*036935a8SXiaoDong Huang };
332*036935a8SXiaoDong Huang
333*036935a8SXiaoDong Huang static unsigned long rk3576_cpul_rates[] = {
334*036935a8SXiaoDong Huang 408000000, 600000000, 816000000, 1008000000,
335*036935a8SXiaoDong Huang 1200000000, 1416000000, 1608000000, 1800000000,
336*036935a8SXiaoDong Huang 2016000000, 2208000000, 2304000063
337*036935a8SXiaoDong Huang };
338*036935a8SXiaoDong Huang
339*036935a8SXiaoDong Huang static unsigned long rk3576_cpub_rates[] = {
340*036935a8SXiaoDong Huang 408000000, 600000000, 816000000, 1008000000,
341*036935a8SXiaoDong Huang 1200000000, 1416000000, 1608000000, 1800000000,
342*036935a8SXiaoDong Huang 2016000000, 2208000000, 2304000000, 2400000063
343*036935a8SXiaoDong Huang };
344*036935a8SXiaoDong Huang
345*036935a8SXiaoDong Huang static unsigned long rk3576_gpu_rates[] = {
346*036935a8SXiaoDong Huang 200000000, 300000000, 400000000, 500000000,
347*036935a8SXiaoDong Huang 600000000, 700000000, 800000000, 900000000,
348*036935a8SXiaoDong Huang 1000000063
349*036935a8SXiaoDong Huang };
350*036935a8SXiaoDong Huang
351*036935a8SXiaoDong Huang static unsigned long rk3576_npu_rates[] = {
352*036935a8SXiaoDong Huang 200000000, 300000000, 400000000, 500000000,
353*036935a8SXiaoDong Huang 600000000, 700000000, 800000000, 900000000,
354*036935a8SXiaoDong Huang 1000000063
355*036935a8SXiaoDong Huang };
356*036935a8SXiaoDong Huang
357*036935a8SXiaoDong Huang static unsigned long rk3576_common_rates[] = {
358*036935a8SXiaoDong Huang 400000, 24000000, 58000000, 100000000, 116000000, 175000000, 350000000,
359*036935a8SXiaoDong Huang };
360*036935a8SXiaoDong Huang
361*036935a8SXiaoDong Huang static unsigned long rk3576_aclk_secure_s_rates[] = {
362*036935a8SXiaoDong Huang 116000000, 175000000, 350000000,
363*036935a8SXiaoDong Huang };
364*036935a8SXiaoDong Huang
365*036935a8SXiaoDong Huang static int aclk_crypto_s_enable;
366*036935a8SXiaoDong Huang static int aclk_klad_enable;
367*036935a8SXiaoDong Huang static spinlock_t crypto_lock;
368*036935a8SXiaoDong Huang static bool cpub_suspended;
369*036935a8SXiaoDong Huang
370*036935a8SXiaoDong Huang static struct sys_clk_info_t sys_clk_info;
371*036935a8SXiaoDong Huang static int clk_scmi_cci_set_rate(rk_scmi_clock_t *clock, unsigned long rate);
372*036935a8SXiaoDong Huang
rkclk_get_pvtpll_config(struct pvtpll_table * table,unsigned int count,unsigned int freq_hz)373*036935a8SXiaoDong Huang static struct pvtpll_table *rkclk_get_pvtpll_config(struct pvtpll_table *table,
374*036935a8SXiaoDong Huang unsigned int count,
375*036935a8SXiaoDong Huang unsigned int freq_hz)
376*036935a8SXiaoDong Huang {
377*036935a8SXiaoDong Huang int i;
378*036935a8SXiaoDong Huang
379*036935a8SXiaoDong Huang for (i = 0; i < count; i++) {
380*036935a8SXiaoDong Huang if (freq_hz == table[i].rate)
381*036935a8SXiaoDong Huang return &table[i];
382*036935a8SXiaoDong Huang }
383*036935a8SXiaoDong Huang return NULL;
384*036935a8SXiaoDong Huang }
385*036935a8SXiaoDong Huang
clk_scmi_set_low_length(struct pvtpll_table * pvtpll,unsigned int count)386*036935a8SXiaoDong Huang static int clk_scmi_set_low_length(struct pvtpll_table *pvtpll, unsigned int count)
387*036935a8SXiaoDong Huang {
388*036935a8SXiaoDong Huang int i;
389*036935a8SXiaoDong Huang
390*036935a8SXiaoDong Huang for (i = 0; i < count; i++) {
391*036935a8SXiaoDong Huang if (pvtpll[i].length_low) {
392*036935a8SXiaoDong Huang pvtpll[i].length = pvtpll[i].length_low;
393*036935a8SXiaoDong Huang pvtpll[i].length_frac = pvtpll[i].length_low_frac;
394*036935a8SXiaoDong Huang }
395*036935a8SXiaoDong Huang }
396*036935a8SXiaoDong Huang
397*036935a8SXiaoDong Huang return 0;
398*036935a8SXiaoDong Huang }
399*036935a8SXiaoDong Huang
clk_cpul_set_rate(unsigned long rate,enum pll_type_sel type)400*036935a8SXiaoDong Huang static int clk_cpul_set_rate(unsigned long rate, enum pll_type_sel type)
401*036935a8SXiaoDong Huang {
402*036935a8SXiaoDong Huang struct pvtpll_table *pvtpll;
403*036935a8SXiaoDong Huang int div;
404*036935a8SXiaoDong Huang
405*036935a8SXiaoDong Huang if (rate == 0)
406*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
407*036935a8SXiaoDong Huang
408*036935a8SXiaoDong Huang pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cpul_table,
409*036935a8SXiaoDong Huang sys_clk_info.cpul_rate_count, rate);
410*036935a8SXiaoDong Huang if (pvtpll == NULL)
411*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
412*036935a8SXiaoDong Huang
413*036935a8SXiaoDong Huang /*
414*036935a8SXiaoDong Huang * |-\
415*036935a8SXiaoDong Huang * -----lpll-----| \
416*036935a8SXiaoDong Huang * | \ |-\
417*036935a8SXiaoDong Huang * -----gpll-----|mux|--litcore unclean src--[div]--[autocs]--| \
418*036935a8SXiaoDong Huang * | / | \
419*036935a8SXiaoDong Huang * --pvtpll src--| / --pvtpll src--|mux|--litcore--
420*036935a8SXiaoDong Huang * |-/ | /
421*036935a8SXiaoDong Huang * --litcore clean src--| /
422*036935a8SXiaoDong Huang * |-/
423*036935a8SXiaoDong Huang */
424*036935a8SXiaoDong Huang if (PVTPLL_NEED(type, pvtpll->length)) {
425*036935a8SXiaoDong Huang /* set ring sel and length */
426*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_LEN,
427*036935a8SXiaoDong Huang 0x1dff0000 |
428*036935a8SXiaoDong Huang (pvtpll->ring_sel << 10) |
429*036935a8SXiaoDong Huang (pvtpll->length << 2) |
430*036935a8SXiaoDong Huang (pvtpll->length_frac));
431*036935a8SXiaoDong Huang /* set cal cnt = 24, T = 1us */
432*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18);
433*036935a8SXiaoDong Huang /* enable pvtpll */
434*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022);
435*036935a8SXiaoDong Huang /* start pvtpll */
436*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023);
437*036935a8SXiaoDong Huang
438*036935a8SXiaoDong Huang /* set pvtpll_src parent from 24MHz/32KHz to pvtpll */
439*036935a8SXiaoDong Huang mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1),
440*036935a8SXiaoDong Huang CPUL_PVTPLL_PATH_PVTPLL);
441*036935a8SXiaoDong Huang
442*036935a8SXiaoDong Huang /* set litcore unclean_src parent to pvtpll_src */
443*036935a8SXiaoDong Huang mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0),
444*036935a8SXiaoDong Huang CPUL_CLK_PATH_NOR_PVTPLL);
445*036935a8SXiaoDong Huang /*
446*036935a8SXiaoDong Huang * set litcore parent from pvtpll_src to unclean_src,
447*036935a8SXiaoDong Huang * because autocs is on litcore unclean_src.
448*036935a8SXiaoDong Huang */
449*036935a8SXiaoDong Huang mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1),
450*036935a8SXiaoDong Huang CPUL_CLK_PATH_LPLL);
451*036935a8SXiaoDong Huang /* set litcore unclean_src div to 0 */
452*036935a8SXiaoDong Huang mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0),
453*036935a8SXiaoDong Huang CLKDIV_5BITS_SHF(0, 7));
454*036935a8SXiaoDong Huang
455*036935a8SXiaoDong Huang return 0;
456*036935a8SXiaoDong Huang }
457*036935a8SXiaoDong Huang /* set litcore unclean_src div */
458*036935a8SXiaoDong Huang div = DIV_ROUND_UP(GPLL_RATE, rate) - 1;
459*036935a8SXiaoDong Huang mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0),
460*036935a8SXiaoDong Huang CLKDIV_5BITS_SHF(div, 7));
461*036935a8SXiaoDong Huang /* set litcore unclean_src parent to gpll */
462*036935a8SXiaoDong Huang mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0),
463*036935a8SXiaoDong Huang CPUL_CLK_PATH_NOR_GPLL);
464*036935a8SXiaoDong Huang /* set litcore parent to unclean_src */
465*036935a8SXiaoDong Huang mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1),
466*036935a8SXiaoDong Huang CPUL_CLK_PATH_LPLL);
467*036935a8SXiaoDong Huang
468*036935a8SXiaoDong Huang return 0;
469*036935a8SXiaoDong Huang }
470*036935a8SXiaoDong Huang
clk_scmi_cpul_set_rate(rk_scmi_clock_t * clock,unsigned long rate)471*036935a8SXiaoDong Huang static int clk_scmi_cpul_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
472*036935a8SXiaoDong Huang {
473*036935a8SXiaoDong Huang int ret;
474*036935a8SXiaoDong Huang
475*036935a8SXiaoDong Huang if (rate == 0)
476*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
477*036935a8SXiaoDong Huang
478*036935a8SXiaoDong Huang ret = clk_cpul_set_rate(rate, PLL_SEL_AUTO);
479*036935a8SXiaoDong Huang if (ret == 0) {
480*036935a8SXiaoDong Huang sys_clk_info.cpul_rate = rate;
481*036935a8SXiaoDong Huang ret = clk_scmi_cci_set_rate(clock, rate / 2);
482*036935a8SXiaoDong Huang }
483*036935a8SXiaoDong Huang
484*036935a8SXiaoDong Huang return ret;
485*036935a8SXiaoDong Huang }
486*036935a8SXiaoDong Huang
rk3576_lpll_get_rate(void)487*036935a8SXiaoDong Huang static unsigned long rk3576_lpll_get_rate(void)
488*036935a8SXiaoDong Huang {
489*036935a8SXiaoDong Huang unsigned int m, p, s, k;
490*036935a8SXiaoDong Huang uint64_t rate64 = 24000000, postdiv;
491*036935a8SXiaoDong Huang int mode;
492*036935a8SXiaoDong Huang
493*036935a8SXiaoDong Huang mode = mmio_read_32(LITTLE_CRU_BASE + CRU_MODE_CON) &
494*036935a8SXiaoDong Huang 0x3;
495*036935a8SXiaoDong Huang
496*036935a8SXiaoDong Huang if (mode == 0)
497*036935a8SXiaoDong Huang return rate64;
498*036935a8SXiaoDong Huang
499*036935a8SXiaoDong Huang m = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(16)) >>
500*036935a8SXiaoDong Huang CRU_PLLCON0_M_SHIFT) &
501*036935a8SXiaoDong Huang CRU_PLLCON0_M_MASK;
502*036935a8SXiaoDong Huang p = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(17)) >>
503*036935a8SXiaoDong Huang CRU_PLLCON1_P_SHIFT) &
504*036935a8SXiaoDong Huang CRU_PLLCON1_P_MASK;
505*036935a8SXiaoDong Huang s = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(17)) >>
506*036935a8SXiaoDong Huang CRU_PLLCON1_S_SHIFT) &
507*036935a8SXiaoDong Huang CRU_PLLCON1_S_MASK;
508*036935a8SXiaoDong Huang k = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(18)) >>
509*036935a8SXiaoDong Huang CRU_PLLCON2_K_SHIFT) &
510*036935a8SXiaoDong Huang CRU_PLLCON2_K_MASK;
511*036935a8SXiaoDong Huang
512*036935a8SXiaoDong Huang rate64 *= m;
513*036935a8SXiaoDong Huang rate64 = rate64 / p;
514*036935a8SXiaoDong Huang
515*036935a8SXiaoDong Huang if (k != 0) {
516*036935a8SXiaoDong Huang /* fractional mode */
517*036935a8SXiaoDong Huang uint64_t frac_rate64 = 24000000 * k;
518*036935a8SXiaoDong Huang
519*036935a8SXiaoDong Huang postdiv = p * 65536;
520*036935a8SXiaoDong Huang frac_rate64 = frac_rate64 / postdiv;
521*036935a8SXiaoDong Huang rate64 += frac_rate64;
522*036935a8SXiaoDong Huang }
523*036935a8SXiaoDong Huang rate64 = rate64 >> s;
524*036935a8SXiaoDong Huang
525*036935a8SXiaoDong Huang return (unsigned long)rate64;
526*036935a8SXiaoDong Huang }
527*036935a8SXiaoDong Huang
clk_scmi_cpul_get_rate(rk_scmi_clock_t * clock)528*036935a8SXiaoDong Huang static unsigned long clk_scmi_cpul_get_rate(rk_scmi_clock_t *clock)
529*036935a8SXiaoDong Huang {
530*036935a8SXiaoDong Huang int src, div;
531*036935a8SXiaoDong Huang
532*036935a8SXiaoDong Huang src = mmio_read_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1)) & 0x00c0;
533*036935a8SXiaoDong Huang src = src >> 6;
534*036935a8SXiaoDong Huang if (src == 1)
535*036935a8SXiaoDong Huang return sys_clk_info.cpul_rate;
536*036935a8SXiaoDong Huang
537*036935a8SXiaoDong Huang src = mmio_read_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0)) & 0x3000;
538*036935a8SXiaoDong Huang src = src >> 12;
539*036935a8SXiaoDong Huang div = mmio_read_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(6)) & 0x0f80;
540*036935a8SXiaoDong Huang div = div >> 7;
541*036935a8SXiaoDong Huang switch (src) {
542*036935a8SXiaoDong Huang case 0:
543*036935a8SXiaoDong Huang return rk3576_lpll_get_rate();
544*036935a8SXiaoDong Huang case 1:
545*036935a8SXiaoDong Huang /* Make the return rate is equal to the set rate */
546*036935a8SXiaoDong Huang if (sys_clk_info.cpul_rate != 0)
547*036935a8SXiaoDong Huang return sys_clk_info.cpul_rate;
548*036935a8SXiaoDong Huang else
549*036935a8SXiaoDong Huang return GPLL_RATE / (div + 1);
550*036935a8SXiaoDong Huang case 2:
551*036935a8SXiaoDong Huang return sys_clk_info.cpul_rate;
552*036935a8SXiaoDong Huang default:
553*036935a8SXiaoDong Huang return 0;
554*036935a8SXiaoDong Huang }
555*036935a8SXiaoDong Huang }
556*036935a8SXiaoDong Huang
clk_scmi_cpul_set_status(rk_scmi_clock_t * clock,bool status)557*036935a8SXiaoDong Huang static int clk_scmi_cpul_set_status(rk_scmi_clock_t *clock, bool status)
558*036935a8SXiaoDong Huang {
559*036935a8SXiaoDong Huang return 0;
560*036935a8SXiaoDong Huang }
561*036935a8SXiaoDong Huang
clk_cpub_set_rate(unsigned long rate,enum pll_type_sel type)562*036935a8SXiaoDong Huang static int clk_cpub_set_rate(unsigned long rate, enum pll_type_sel type)
563*036935a8SXiaoDong Huang {
564*036935a8SXiaoDong Huang struct pvtpll_table *pvtpll;
565*036935a8SXiaoDong Huang int div;
566*036935a8SXiaoDong Huang
567*036935a8SXiaoDong Huang if (rate == 0)
568*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
569*036935a8SXiaoDong Huang
570*036935a8SXiaoDong Huang pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cpub_table,
571*036935a8SXiaoDong Huang sys_clk_info.cpub_rate_count, rate);
572*036935a8SXiaoDong Huang if (pvtpll == NULL)
573*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
574*036935a8SXiaoDong Huang
575*036935a8SXiaoDong Huang /*
576*036935a8SXiaoDong Huang * |-\
577*036935a8SXiaoDong Huang * -----bpll-----| \
578*036935a8SXiaoDong Huang * | \ |-\
579*036935a8SXiaoDong Huang * -----gpll-----|mux|--bigcore unclean src--[div]--[autocs]--| \
580*036935a8SXiaoDong Huang * | / | \
581*036935a8SXiaoDong Huang * --pvtpll src--| / --pvtpll src--|mux|--bigcore--
582*036935a8SXiaoDong Huang * |-/ | /
583*036935a8SXiaoDong Huang * --bigcore clean src--| /
584*036935a8SXiaoDong Huang * |-/
585*036935a8SXiaoDong Huang */
586*036935a8SXiaoDong Huang if (PVTPLL_NEED(type, pvtpll->length) != 0) {
587*036935a8SXiaoDong Huang /* set ring sel and length */
588*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_LEN,
589*036935a8SXiaoDong Huang 0x1dff0000 |
590*036935a8SXiaoDong Huang (pvtpll->ring_sel << 10) |
591*036935a8SXiaoDong Huang (pvtpll->length << 2) |
592*036935a8SXiaoDong Huang (pvtpll->length_frac));
593*036935a8SXiaoDong Huang /* set cal cnt = 24, T = 1us */
594*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18);
595*036935a8SXiaoDong Huang /* enable pvtpll */
596*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022);
597*036935a8SXiaoDong Huang /* start pvtpll */
598*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023);
599*036935a8SXiaoDong Huang
600*036935a8SXiaoDong Huang /* set pvtpll_src parent from 24MHz/32KHz to pvtpll */
601*036935a8SXiaoDong Huang mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(2),
602*036935a8SXiaoDong Huang CPUB_PVTPLL_PATH_PVTPLL);
603*036935a8SXiaoDong Huang
604*036935a8SXiaoDong Huang /* set bigcore unclean_src parent to pvtpll_src */
605*036935a8SXiaoDong Huang mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
606*036935a8SXiaoDong Huang CPUB_CLK_PATH_NOR_PVTPLL);
607*036935a8SXiaoDong Huang /*
608*036935a8SXiaoDong Huang * set bigcore parent from pvtpll_src to unclean_src,
609*036935a8SXiaoDong Huang * because autocs is on bigcore unclean_src.
610*036935a8SXiaoDong Huang */
611*036935a8SXiaoDong Huang mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
612*036935a8SXiaoDong Huang CPUB_CLK_PATH_BPLL);
613*036935a8SXiaoDong Huang
614*036935a8SXiaoDong Huang /* set bigcore unclean_src div to 0 */
615*036935a8SXiaoDong Huang mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
616*036935a8SXiaoDong Huang CLKDIV_5BITS_SHF(0, 7));
617*036935a8SXiaoDong Huang
618*036935a8SXiaoDong Huang return 0;
619*036935a8SXiaoDong Huang }
620*036935a8SXiaoDong Huang
621*036935a8SXiaoDong Huang /* set bigcore unclean_src div */
622*036935a8SXiaoDong Huang div = DIV_ROUND_UP(GPLL_RATE, rate) - 1;
623*036935a8SXiaoDong Huang mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
624*036935a8SXiaoDong Huang CLKDIV_5BITS_SHF(div, 7));
625*036935a8SXiaoDong Huang /* set bigcore unclean_src parent to gpll */
626*036935a8SXiaoDong Huang mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
627*036935a8SXiaoDong Huang CPUB_CLK_PATH_NOR_GPLL);
628*036935a8SXiaoDong Huang /* set bigcore parent to unclean_src */
629*036935a8SXiaoDong Huang mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
630*036935a8SXiaoDong Huang CPUB_CLK_PATH_BPLL);
631*036935a8SXiaoDong Huang
632*036935a8SXiaoDong Huang return 0;
633*036935a8SXiaoDong Huang }
634*036935a8SXiaoDong Huang
clk_scmi_cpub_set_rate(rk_scmi_clock_t * clock,unsigned long rate)635*036935a8SXiaoDong Huang static int clk_scmi_cpub_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
636*036935a8SXiaoDong Huang {
637*036935a8SXiaoDong Huang int ret;
638*036935a8SXiaoDong Huang
639*036935a8SXiaoDong Huang if (rate == 0)
640*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
641*036935a8SXiaoDong Huang
642*036935a8SXiaoDong Huang if ((rate & OPP_LENGTH_LOW) != 0) {
643*036935a8SXiaoDong Huang clk_scmi_set_low_length(sys_clk_info.cpub_table,
644*036935a8SXiaoDong Huang sys_clk_info.cpub_rate_count);
645*036935a8SXiaoDong Huang return 0;
646*036935a8SXiaoDong Huang }
647*036935a8SXiaoDong Huang
648*036935a8SXiaoDong Huang ret = clk_cpub_set_rate(rate, PLL_SEL_AUTO);
649*036935a8SXiaoDong Huang if (ret == 0)
650*036935a8SXiaoDong Huang sys_clk_info.cpub_rate = rate;
651*036935a8SXiaoDong Huang
652*036935a8SXiaoDong Huang return ret;
653*036935a8SXiaoDong Huang }
654*036935a8SXiaoDong Huang
rk3576_bpll_get_rate(void)655*036935a8SXiaoDong Huang static unsigned long rk3576_bpll_get_rate(void)
656*036935a8SXiaoDong Huang {
657*036935a8SXiaoDong Huang unsigned int m, p, s, k;
658*036935a8SXiaoDong Huang uint64_t rate64 = 24000000, postdiv;
659*036935a8SXiaoDong Huang int mode;
660*036935a8SXiaoDong Huang
661*036935a8SXiaoDong Huang mode = mmio_read_32(CRU_BASE + CRU_MODE_CON) &
662*036935a8SXiaoDong Huang 0x3;
663*036935a8SXiaoDong Huang
664*036935a8SXiaoDong Huang if (mode == 0)
665*036935a8SXiaoDong Huang return rate64;
666*036935a8SXiaoDong Huang
667*036935a8SXiaoDong Huang m = (mmio_read_32(CRU_BASE + CRU_PLL_CON(0)) >>
668*036935a8SXiaoDong Huang CRU_PLLCON0_M_SHIFT) &
669*036935a8SXiaoDong Huang CRU_PLLCON0_M_MASK;
670*036935a8SXiaoDong Huang p = (mmio_read_32(CRU_BASE + CRU_PLL_CON(1)) >>
671*036935a8SXiaoDong Huang CRU_PLLCON1_P_SHIFT) &
672*036935a8SXiaoDong Huang CRU_PLLCON1_P_MASK;
673*036935a8SXiaoDong Huang s = (mmio_read_32(CRU_BASE + CRU_PLL_CON(1)) >>
674*036935a8SXiaoDong Huang CRU_PLLCON1_S_SHIFT) &
675*036935a8SXiaoDong Huang CRU_PLLCON1_S_MASK;
676*036935a8SXiaoDong Huang k = (mmio_read_32(CRU_BASE + CRU_PLL_CON(2)) >>
677*036935a8SXiaoDong Huang CRU_PLLCON2_K_SHIFT) &
678*036935a8SXiaoDong Huang CRU_PLLCON2_K_MASK;
679*036935a8SXiaoDong Huang
680*036935a8SXiaoDong Huang rate64 *= m;
681*036935a8SXiaoDong Huang rate64 = rate64 / p;
682*036935a8SXiaoDong Huang
683*036935a8SXiaoDong Huang if (k != 0) {
684*036935a8SXiaoDong Huang /* fractional mode */
685*036935a8SXiaoDong Huang uint64_t frac_rate64 = 24000000 * k;
686*036935a8SXiaoDong Huang
687*036935a8SXiaoDong Huang postdiv = p * 65536;
688*036935a8SXiaoDong Huang frac_rate64 = frac_rate64 / postdiv;
689*036935a8SXiaoDong Huang rate64 += frac_rate64;
690*036935a8SXiaoDong Huang }
691*036935a8SXiaoDong Huang rate64 = rate64 >> s;
692*036935a8SXiaoDong Huang
693*036935a8SXiaoDong Huang return (unsigned long)rate64;
694*036935a8SXiaoDong Huang }
695*036935a8SXiaoDong Huang
clk_scmi_cpub_get_rate(rk_scmi_clock_t * clock)696*036935a8SXiaoDong Huang static unsigned long clk_scmi_cpub_get_rate(rk_scmi_clock_t *clock)
697*036935a8SXiaoDong Huang {
698*036935a8SXiaoDong Huang int value, src, div;
699*036935a8SXiaoDong Huang
700*036935a8SXiaoDong Huang if (cpub_suspended != 0)
701*036935a8SXiaoDong Huang return sys_clk_info.cpub_rate;
702*036935a8SXiaoDong Huang
703*036935a8SXiaoDong Huang value = mmio_read_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1));
704*036935a8SXiaoDong Huang src = (value & 0xc000) >> 14;
705*036935a8SXiaoDong Huang if (src == 1)
706*036935a8SXiaoDong Huang return sys_clk_info.cpub_rate;
707*036935a8SXiaoDong Huang
708*036935a8SXiaoDong Huang value = mmio_read_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1));
709*036935a8SXiaoDong Huang src = (value & 0x3000) >> 12;
710*036935a8SXiaoDong Huang div = (value & 0x0f80) >> 7;
711*036935a8SXiaoDong Huang switch (src) {
712*036935a8SXiaoDong Huang case 0:
713*036935a8SXiaoDong Huang return rk3576_bpll_get_rate();
714*036935a8SXiaoDong Huang case 1:
715*036935a8SXiaoDong Huang /* Make the return rate is equal to the set rate */
716*036935a8SXiaoDong Huang if (sys_clk_info.cpub_rate != 0)
717*036935a8SXiaoDong Huang return sys_clk_info.cpub_rate;
718*036935a8SXiaoDong Huang else
719*036935a8SXiaoDong Huang return GPLL_RATE / (div + 1);
720*036935a8SXiaoDong Huang case 2:
721*036935a8SXiaoDong Huang return sys_clk_info.cpub_rate;
722*036935a8SXiaoDong Huang default:
723*036935a8SXiaoDong Huang return 0;
724*036935a8SXiaoDong Huang }
725*036935a8SXiaoDong Huang }
726*036935a8SXiaoDong Huang
clk_scmi_cpub_set_status(rk_scmi_clock_t * clock,bool status)727*036935a8SXiaoDong Huang static int clk_scmi_cpub_set_status(rk_scmi_clock_t *clock, bool status)
728*036935a8SXiaoDong Huang {
729*036935a8SXiaoDong Huang return 0;
730*036935a8SXiaoDong Huang }
731*036935a8SXiaoDong Huang
clk_scmi_cci_get_rate(rk_scmi_clock_t * clock)732*036935a8SXiaoDong Huang static unsigned long clk_scmi_cci_get_rate(rk_scmi_clock_t *clock)
733*036935a8SXiaoDong Huang {
734*036935a8SXiaoDong Huang int src, div;
735*036935a8SXiaoDong Huang
736*036935a8SXiaoDong Huang src = mmio_read_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4)) & 0x3000;
737*036935a8SXiaoDong Huang src = src >> 12;
738*036935a8SXiaoDong Huang if (src == 1)
739*036935a8SXiaoDong Huang return sys_clk_info.cci_rate;
740*036935a8SXiaoDong Huang
741*036935a8SXiaoDong Huang div = mmio_read_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4)) & 0xf80;
742*036935a8SXiaoDong Huang div = div >> 7;
743*036935a8SXiaoDong Huang switch (src) {
744*036935a8SXiaoDong Huang case 0:
745*036935a8SXiaoDong Huang return OSC_HZ;
746*036935a8SXiaoDong Huang case 1:
747*036935a8SXiaoDong Huang return sys_clk_info.cci_rate;
748*036935a8SXiaoDong Huang case 2:
749*036935a8SXiaoDong Huang return GPLL_RATE / (div + 1);
750*036935a8SXiaoDong Huang case 3:
751*036935a8SXiaoDong Huang return rk3576_lpll_get_rate() / (div + 1);
752*036935a8SXiaoDong Huang default:
753*036935a8SXiaoDong Huang return 0;
754*036935a8SXiaoDong Huang }
755*036935a8SXiaoDong Huang }
756*036935a8SXiaoDong Huang
clk_cci_set_rate(unsigned long rate,enum pll_type_sel type)757*036935a8SXiaoDong Huang static int clk_cci_set_rate(unsigned long rate, enum pll_type_sel type)
758*036935a8SXiaoDong Huang {
759*036935a8SXiaoDong Huang struct pvtpll_table *pvtpll;
760*036935a8SXiaoDong Huang uint32_t pvtpll_en = 0;
761*036935a8SXiaoDong Huang
762*036935a8SXiaoDong Huang if (rate == 0)
763*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
764*036935a8SXiaoDong Huang
765*036935a8SXiaoDong Huang pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cci_table,
766*036935a8SXiaoDong Huang sys_clk_info.cci_rate_count, rate);
767*036935a8SXiaoDong Huang
768*036935a8SXiaoDong Huang /* set pvtpll */
769*036935a8SXiaoDong Huang if ((pvtpll != 0) && (PVTPLL_NEED(type, pvtpll->length) != 0)) {
770*036935a8SXiaoDong Huang /* set ring sel and length */
771*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_LEN,
772*036935a8SXiaoDong Huang 0x1dff0000 |
773*036935a8SXiaoDong Huang (pvtpll->ring_sel << 10) |
774*036935a8SXiaoDong Huang (pvtpll->length << 2) |
775*036935a8SXiaoDong Huang (pvtpll->length_frac));
776*036935a8SXiaoDong Huang /* set cal cnt = 24, T = 1us */
777*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18);
778*036935a8SXiaoDong Huang /* enable pvtpll */
779*036935a8SXiaoDong Huang pvtpll_en = mmio_read_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CFG);
780*036935a8SXiaoDong Huang if (pvtpll_en && 0x22 != 0x22)
781*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022);
782*036935a8SXiaoDong Huang /* start pvtpll */
783*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023);
784*036935a8SXiaoDong Huang
785*036935a8SXiaoDong Huang /* set cci mux pvtpll */
786*036935a8SXiaoDong Huang mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4),
787*036935a8SXiaoDong Huang CCI_PVTPLL_PATH_PVTPLL);
788*036935a8SXiaoDong Huang mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4),
789*036935a8SXiaoDong Huang SCLK_CCI_PATH_PVTPLL);
790*036935a8SXiaoDong Huang mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4),
791*036935a8SXiaoDong Huang CLKDIV_5BITS_SHF(0, 7));
792*036935a8SXiaoDong Huang sys_clk_info.cci_rate = rate;
793*036935a8SXiaoDong Huang return 0;
794*036935a8SXiaoDong Huang }
795*036935a8SXiaoDong Huang sys_clk_info.cci_rate = 594000000;
796*036935a8SXiaoDong Huang /* set cci div */
797*036935a8SXiaoDong Huang mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4),
798*036935a8SXiaoDong Huang CLKDIV_5BITS_SHF(1, 7));
799*036935a8SXiaoDong Huang /* set cci mux gpll */
800*036935a8SXiaoDong Huang mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4),
801*036935a8SXiaoDong Huang SCLK_CCI_PATH_NOR_GPLL);
802*036935a8SXiaoDong Huang
803*036935a8SXiaoDong Huang return 0;
804*036935a8SXiaoDong Huang }
805*036935a8SXiaoDong Huang
clk_scmi_cci_set_rate(rk_scmi_clock_t * clock,unsigned long rate)806*036935a8SXiaoDong Huang static int clk_scmi_cci_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
807*036935a8SXiaoDong Huang {
808*036935a8SXiaoDong Huang if (rate == 0)
809*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
810*036935a8SXiaoDong Huang
811*036935a8SXiaoDong Huang return clk_cci_set_rate(rate, PLL_SEL_AUTO);
812*036935a8SXiaoDong Huang }
813*036935a8SXiaoDong Huang
clk_scmi_cci_set_status(rk_scmi_clock_t * clock,bool status)814*036935a8SXiaoDong Huang static int clk_scmi_cci_set_status(rk_scmi_clock_t *clock, bool status)
815*036935a8SXiaoDong Huang {
816*036935a8SXiaoDong Huang return 0;
817*036935a8SXiaoDong Huang }
818*036935a8SXiaoDong Huang
clk_scmi_gpu_get_rate(rk_scmi_clock_t * clock)819*036935a8SXiaoDong Huang static unsigned long clk_scmi_gpu_get_rate(rk_scmi_clock_t *clock)
820*036935a8SXiaoDong Huang {
821*036935a8SXiaoDong Huang int div, src;
822*036935a8SXiaoDong Huang
823*036935a8SXiaoDong Huang if ((mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(165)) & 0x100) != 0)
824*036935a8SXiaoDong Huang return sys_clk_info.gpu_rate;
825*036935a8SXiaoDong Huang
826*036935a8SXiaoDong Huang div = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(165)) & 0x1f;
827*036935a8SXiaoDong Huang src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(165)) & 0x00e0;
828*036935a8SXiaoDong Huang src = src >> 5;
829*036935a8SXiaoDong Huang switch (src) {
830*036935a8SXiaoDong Huang case 0:
831*036935a8SXiaoDong Huang /* Make the return rate is equal to the set rate */
832*036935a8SXiaoDong Huang if (sys_clk_info.gpu_rate != 0)
833*036935a8SXiaoDong Huang return sys_clk_info.gpu_rate;
834*036935a8SXiaoDong Huang else
835*036935a8SXiaoDong Huang return GPLL_RATE / (div + 1);
836*036935a8SXiaoDong Huang case 1:
837*036935a8SXiaoDong Huang return CPLL_RATE / (div + 1);
838*036935a8SXiaoDong Huang case 2:
839*036935a8SXiaoDong Huang return AUPLL_RATE / (div + 1);
840*036935a8SXiaoDong Huang case 3:
841*036935a8SXiaoDong Huang return SPLL_RATE / (div + 1);
842*036935a8SXiaoDong Huang case 4:
843*036935a8SXiaoDong Huang return rk3576_lpll_get_rate() / (div + 1);
844*036935a8SXiaoDong Huang default:
845*036935a8SXiaoDong Huang return 0;
846*036935a8SXiaoDong Huang }
847*036935a8SXiaoDong Huang }
848*036935a8SXiaoDong Huang
clk_gpu_set_rate(unsigned long rate,enum pll_type_sel type)849*036935a8SXiaoDong Huang static int clk_gpu_set_rate(unsigned long rate, enum pll_type_sel type)
850*036935a8SXiaoDong Huang {
851*036935a8SXiaoDong Huang struct pvtpll_table *pvtpll;
852*036935a8SXiaoDong Huang int div;
853*036935a8SXiaoDong Huang
854*036935a8SXiaoDong Huang pvtpll = rkclk_get_pvtpll_config(sys_clk_info.gpu_table,
855*036935a8SXiaoDong Huang sys_clk_info.gpu_rate_count, rate);
856*036935a8SXiaoDong Huang if (pvtpll == NULL)
857*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
858*036935a8SXiaoDong Huang
859*036935a8SXiaoDong Huang if (PVTPLL_NEED(type, pvtpll->length) != 0) {
860*036935a8SXiaoDong Huang /* set ring sel and length */
861*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_LEN,
862*036935a8SXiaoDong Huang 0x1dff0000 |
863*036935a8SXiaoDong Huang (pvtpll->ring_sel << 10) |
864*036935a8SXiaoDong Huang (pvtpll->length << 2) |
865*036935a8SXiaoDong Huang (pvtpll->length_frac));
866*036935a8SXiaoDong Huang /* set cal cnt = 24, T = 1us */
867*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18);
868*036935a8SXiaoDong Huang /* enable pvtpll */
869*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022);
870*036935a8SXiaoDong Huang /* start pvtpll */
871*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023);
872*036935a8SXiaoDong Huang /* set gpu mux pvtpll */
873*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165),
874*036935a8SXiaoDong Huang GPU_PVTPLL_PATH_PVTPLL);
875*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165),
876*036935a8SXiaoDong Huang GPU_CLK_PATH_PVTPLL);
877*036935a8SXiaoDong Huang return 0;
878*036935a8SXiaoDong Huang }
879*036935a8SXiaoDong Huang
880*036935a8SXiaoDong Huang /* set gpu div */
881*036935a8SXiaoDong Huang div = DIV_ROUND_UP(GPLL_RATE, rate);
882*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165),
883*036935a8SXiaoDong Huang CLKDIV_5BITS_SHF(div - 1, 0));
884*036935a8SXiaoDong Huang /* set gpu mux gpll */
885*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165),
886*036935a8SXiaoDong Huang GPU_CLK_PATH_NOR_GPLL);
887*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165),
888*036935a8SXiaoDong Huang GPU_CLK_PATH_NOR_PLL);
889*036935a8SXiaoDong Huang
890*036935a8SXiaoDong Huang return 0;
891*036935a8SXiaoDong Huang }
892*036935a8SXiaoDong Huang
clk_scmi_gpu_set_rate(rk_scmi_clock_t * clock,unsigned long rate)893*036935a8SXiaoDong Huang static int clk_scmi_gpu_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
894*036935a8SXiaoDong Huang {
895*036935a8SXiaoDong Huang int ret;
896*036935a8SXiaoDong Huang
897*036935a8SXiaoDong Huang if (rate == 0)
898*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
899*036935a8SXiaoDong Huang
900*036935a8SXiaoDong Huang if ((rate & OPP_LENGTH_LOW) != 0) {
901*036935a8SXiaoDong Huang clk_scmi_set_low_length(sys_clk_info.gpu_table,
902*036935a8SXiaoDong Huang sys_clk_info.gpu_rate_count);
903*036935a8SXiaoDong Huang return 0;
904*036935a8SXiaoDong Huang }
905*036935a8SXiaoDong Huang
906*036935a8SXiaoDong Huang ret = clk_gpu_set_rate(rate, PLL_SEL_AUTO);
907*036935a8SXiaoDong Huang if (ret == 0)
908*036935a8SXiaoDong Huang sys_clk_info.gpu_rate = rate;
909*036935a8SXiaoDong Huang
910*036935a8SXiaoDong Huang return ret;
911*036935a8SXiaoDong Huang }
912*036935a8SXiaoDong Huang
clk_scmi_gpu_set_status(rk_scmi_clock_t * clock,bool status)913*036935a8SXiaoDong Huang static int clk_scmi_gpu_set_status(rk_scmi_clock_t *clock, bool status)
914*036935a8SXiaoDong Huang {
915*036935a8SXiaoDong Huang return 0;
916*036935a8SXiaoDong Huang }
917*036935a8SXiaoDong Huang
clk_scmi_npu_get_rate(rk_scmi_clock_t * clock)918*036935a8SXiaoDong Huang static unsigned long clk_scmi_npu_get_rate(rk_scmi_clock_t *clock)
919*036935a8SXiaoDong Huang {
920*036935a8SXiaoDong Huang int div, src, div_src;
921*036935a8SXiaoDong Huang
922*036935a8SXiaoDong Huang if ((mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x8000) != 0)
923*036935a8SXiaoDong Huang return sys_clk_info.npu_rate;
924*036935a8SXiaoDong Huang
925*036935a8SXiaoDong Huang div_src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x07c;
926*036935a8SXiaoDong Huang div_src = div_src >> 2;
927*036935a8SXiaoDong Huang src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x0180;
928*036935a8SXiaoDong Huang src = src >> 7;
929*036935a8SXiaoDong Huang div = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x7c00;
930*036935a8SXiaoDong Huang div = div >> 10;
931*036935a8SXiaoDong Huang switch (src) {
932*036935a8SXiaoDong Huang case 0:
933*036935a8SXiaoDong Huang /* Make the return rate is equal to the set rate */
934*036935a8SXiaoDong Huang if (sys_clk_info.npu_rate != 0)
935*036935a8SXiaoDong Huang return sys_clk_info.npu_rate;
936*036935a8SXiaoDong Huang else
937*036935a8SXiaoDong Huang return GPLL_RATE / (div_src + 1) / (div + 1);
938*036935a8SXiaoDong Huang case 1:
939*036935a8SXiaoDong Huang return CPLL_RATE / (div_src + 1) / (div + 1);
940*036935a8SXiaoDong Huang case 2:
941*036935a8SXiaoDong Huang return AUPLL_RATE / (div_src + 1) / (div + 1);
942*036935a8SXiaoDong Huang case 3:
943*036935a8SXiaoDong Huang return SPLL_RATE / (div_src + 1) / (div + 1);
944*036935a8SXiaoDong Huang default:
945*036935a8SXiaoDong Huang return 0;
946*036935a8SXiaoDong Huang }
947*036935a8SXiaoDong Huang }
948*036935a8SXiaoDong Huang
clk_npu_set_rate(unsigned long rate,enum pll_type_sel type)949*036935a8SXiaoDong Huang static int clk_npu_set_rate(unsigned long rate, enum pll_type_sel type)
950*036935a8SXiaoDong Huang {
951*036935a8SXiaoDong Huang struct pvtpll_table *pvtpll;
952*036935a8SXiaoDong Huang int div;
953*036935a8SXiaoDong Huang
954*036935a8SXiaoDong Huang pvtpll = rkclk_get_pvtpll_config(sys_clk_info.npu_table,
955*036935a8SXiaoDong Huang sys_clk_info.npu_rate_count, rate);
956*036935a8SXiaoDong Huang if (pvtpll == NULL)
957*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
958*036935a8SXiaoDong Huang
959*036935a8SXiaoDong Huang if (PVTPLL_NEED(type, pvtpll->length) != 0) {
960*036935a8SXiaoDong Huang /* set ring sel and length */
961*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_LEN,
962*036935a8SXiaoDong Huang 0x1dff0000 |
963*036935a8SXiaoDong Huang (pvtpll->ring_sel << 10) |
964*036935a8SXiaoDong Huang (pvtpll->length << 2) |
965*036935a8SXiaoDong Huang (pvtpll->length_frac));
966*036935a8SXiaoDong Huang /* set cal cnt = 24, T = 1us */
967*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18);
968*036935a8SXiaoDong Huang /* enable pvtpll */
969*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022);
970*036935a8SXiaoDong Huang /* start pvtpll */
971*036935a8SXiaoDong Huang mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023);
972*036935a8SXiaoDong Huang /* set npu mux pvtpll */
973*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
974*036935a8SXiaoDong Huang NPU_PVTPLL_PATH_PVTPLL);
975*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
976*036935a8SXiaoDong Huang NPU_CLK_PATH_PVTPLL);
977*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
978*036935a8SXiaoDong Huang CLKDIV_5BITS_SHF(0, 10));
979*036935a8SXiaoDong Huang return 0;
980*036935a8SXiaoDong Huang }
981*036935a8SXiaoDong Huang
982*036935a8SXiaoDong Huang /* set npu div */
983*036935a8SXiaoDong Huang div = DIV_ROUND_UP(GPLL_RATE, rate);
984*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
985*036935a8SXiaoDong Huang CLKDIV_5BITS_SHF(div - 1, 2));
986*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
987*036935a8SXiaoDong Huang CLKDIV_5BITS_SHF(0, 10));
988*036935a8SXiaoDong Huang /* set npu mux gpll */
989*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
990*036935a8SXiaoDong Huang NPU_CLK_PATH_NOR_GPLL);
991*036935a8SXiaoDong Huang mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
992*036935a8SXiaoDong Huang NPU_CLK_PATH_NOR_PLL);
993*036935a8SXiaoDong Huang
994*036935a8SXiaoDong Huang return 0;
995*036935a8SXiaoDong Huang }
996*036935a8SXiaoDong Huang
clk_scmi_npu_set_rate(rk_scmi_clock_t * clock,unsigned long rate)997*036935a8SXiaoDong Huang static int clk_scmi_npu_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
998*036935a8SXiaoDong Huang {
999*036935a8SXiaoDong Huang int ret;
1000*036935a8SXiaoDong Huang
1001*036935a8SXiaoDong Huang if (rate == 0)
1002*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
1003*036935a8SXiaoDong Huang
1004*036935a8SXiaoDong Huang if ((rate & OPP_LENGTH_LOW) != 0) {
1005*036935a8SXiaoDong Huang clk_scmi_set_low_length(sys_clk_info.npu_table,
1006*036935a8SXiaoDong Huang sys_clk_info.npu_rate_count);
1007*036935a8SXiaoDong Huang return 0;
1008*036935a8SXiaoDong Huang }
1009*036935a8SXiaoDong Huang
1010*036935a8SXiaoDong Huang ret = clk_npu_set_rate(rate, PLL_SEL_AUTO);
1011*036935a8SXiaoDong Huang if (ret == 0)
1012*036935a8SXiaoDong Huang sys_clk_info.npu_rate = rate;
1013*036935a8SXiaoDong Huang
1014*036935a8SXiaoDong Huang return ret;
1015*036935a8SXiaoDong Huang }
1016*036935a8SXiaoDong Huang
clk_scmi_npu_set_status(rk_scmi_clock_t * clock,bool status)1017*036935a8SXiaoDong Huang static int clk_scmi_npu_set_status(rk_scmi_clock_t *clock, bool status)
1018*036935a8SXiaoDong Huang {
1019*036935a8SXiaoDong Huang return 0;
1020*036935a8SXiaoDong Huang }
1021*036935a8SXiaoDong Huang
clk_scmi_crypto_set_status(rk_scmi_clock_t * clock,bool status)1022*036935a8SXiaoDong Huang int clk_scmi_crypto_set_status(rk_scmi_clock_t *clock, bool status)
1023*036935a8SXiaoDong Huang {
1024*036935a8SXiaoDong Huang spin_lock(&crypto_lock);
1025*036935a8SXiaoDong Huang
1026*036935a8SXiaoDong Huang if (clock->id == ACLK_CRYPTO_S)
1027*036935a8SXiaoDong Huang aclk_crypto_s_enable = status;
1028*036935a8SXiaoDong Huang else
1029*036935a8SXiaoDong Huang aclk_klad_enable = status;
1030*036935a8SXiaoDong Huang
1031*036935a8SXiaoDong Huang if ((aclk_crypto_s_enable != 0) || (aclk_klad_enable != 0))
1032*036935a8SXiaoDong Huang clk_scmi_common_set_status(clock, 1);
1033*036935a8SXiaoDong Huang else
1034*036935a8SXiaoDong Huang clk_scmi_common_set_status(clock, 0);
1035*036935a8SXiaoDong Huang
1036*036935a8SXiaoDong Huang spin_unlock(&crypto_lock);
1037*036935a8SXiaoDong Huang return 0;
1038*036935a8SXiaoDong Huang }
1039*036935a8SXiaoDong Huang
clk_scmi_common_set_status_critical(rk_scmi_clock_t * clock,bool status)1040*036935a8SXiaoDong Huang static int clk_scmi_common_set_status_critical(rk_scmi_clock_t *clock, bool status)
1041*036935a8SXiaoDong Huang {
1042*036935a8SXiaoDong Huang return 0;
1043*036935a8SXiaoDong Huang }
1044*036935a8SXiaoDong Huang
1045*036935a8SXiaoDong Huang static const struct rk_clk_ops clk_scmi_cpul_ops = {
1046*036935a8SXiaoDong Huang .get_rate = clk_scmi_cpul_get_rate,
1047*036935a8SXiaoDong Huang .set_rate = clk_scmi_cpul_set_rate,
1048*036935a8SXiaoDong Huang .set_status = clk_scmi_cpul_set_status,
1049*036935a8SXiaoDong Huang };
1050*036935a8SXiaoDong Huang
1051*036935a8SXiaoDong Huang static const struct rk_clk_ops clk_scmi_cci_ops = {
1052*036935a8SXiaoDong Huang .get_rate = clk_scmi_cci_get_rate,
1053*036935a8SXiaoDong Huang .set_rate = clk_scmi_cci_set_rate,
1054*036935a8SXiaoDong Huang .set_status = clk_scmi_cci_set_status,
1055*036935a8SXiaoDong Huang };
1056*036935a8SXiaoDong Huang
1057*036935a8SXiaoDong Huang static const struct rk_clk_ops clk_scmi_cpub_ops = {
1058*036935a8SXiaoDong Huang .get_rate = clk_scmi_cpub_get_rate,
1059*036935a8SXiaoDong Huang .set_rate = clk_scmi_cpub_set_rate,
1060*036935a8SXiaoDong Huang .set_status = clk_scmi_cpub_set_status,
1061*036935a8SXiaoDong Huang };
1062*036935a8SXiaoDong Huang
1063*036935a8SXiaoDong Huang static const struct rk_clk_ops clk_scmi_gpu_ops = {
1064*036935a8SXiaoDong Huang .get_rate = clk_scmi_gpu_get_rate,
1065*036935a8SXiaoDong Huang .set_rate = clk_scmi_gpu_set_rate,
1066*036935a8SXiaoDong Huang .set_status = clk_scmi_gpu_set_status,
1067*036935a8SXiaoDong Huang };
1068*036935a8SXiaoDong Huang
1069*036935a8SXiaoDong Huang static const struct rk_clk_ops clk_scmi_npu_ops = {
1070*036935a8SXiaoDong Huang .get_rate = clk_scmi_npu_get_rate,
1071*036935a8SXiaoDong Huang .set_rate = clk_scmi_npu_set_rate,
1072*036935a8SXiaoDong Huang .set_status = clk_scmi_npu_set_status,
1073*036935a8SXiaoDong Huang };
1074*036935a8SXiaoDong Huang
1075*036935a8SXiaoDong Huang static const struct rk_clk_ops clk_scmi_ops_com_critical = {
1076*036935a8SXiaoDong Huang .get_rate = clk_scmi_common_get_rate,
1077*036935a8SXiaoDong Huang .set_rate = clk_scmi_common_set_rate,
1078*036935a8SXiaoDong Huang .set_status = clk_scmi_common_set_status_critical,
1079*036935a8SXiaoDong Huang };
1080*036935a8SXiaoDong Huang
1081*036935a8SXiaoDong Huang static const struct rk_clk_ops clk_scmi_ops_com = {
1082*036935a8SXiaoDong Huang .get_rate = clk_scmi_common_get_rate,
1083*036935a8SXiaoDong Huang .set_rate = clk_scmi_common_set_rate,
1084*036935a8SXiaoDong Huang .set_status = clk_scmi_common_set_status,
1085*036935a8SXiaoDong Huang };
1086*036935a8SXiaoDong Huang
1087*036935a8SXiaoDong Huang static const struct rk_clk_ops clk_scmi_ops_gate = {
1088*036935a8SXiaoDong Huang .get_rate = clk_scmi_common_get_rate,
1089*036935a8SXiaoDong Huang .set_status = clk_scmi_common_set_status,
1090*036935a8SXiaoDong Huang };
1091*036935a8SXiaoDong Huang
1092*036935a8SXiaoDong Huang static const struct rk_clk_ops clk_scmi_ops_crypto = {
1093*036935a8SXiaoDong Huang .get_rate = clk_scmi_common_get_rate,
1094*036935a8SXiaoDong Huang .set_status = clk_scmi_crypto_set_status,
1095*036935a8SXiaoDong Huang };
1096*036935a8SXiaoDong Huang
1097*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK(ARMCLK_L, scmi_armclkl, &clk_scmi_cpul_ops, rk3576_cpul_rates, ARRAY_SIZE(rk3576_cpul_rates), false);
1098*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK(ACLK_CCI_ROOT, scmi_aclk_cci, &clk_scmi_cci_ops, rk3576_cpul_rates, ARRAY_SIZE(rk3576_cpul_rates), false);
1099*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK(ARMCLK_B, scmi_armclkb, &clk_scmi_cpub_ops, rk3576_cpub_rates, ARRAY_SIZE(rk3576_cpub_rates), false);
1100*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK(CLK_GPU, scmi_clk_gpu, &clk_scmi_gpu_ops, rk3576_gpu_rates, ARRAY_SIZE(rk3576_gpu_rates), false);
1101*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK(CLK_RKNN_DSU0, scmi_clk_npu, &clk_scmi_npu_ops, rk3576_npu_rates, ARRAY_SIZE(rk3576_npu_rates), false);
1102*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(CLK_STIMER0_ROOT, clk_stimer0_root, p_100m_24m, clk_stimer0_root_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
1103*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(CLK_STIMER1_ROOT, clk_stimer1_root, p_100m_24m, clk_stimer1_root_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
1104*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(PCLK_SECURE_S, pclk_secure_s, p_116m_58m_24m, pclk_secure_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
1105*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(HCLK_SECURE_S, hclk_secure_s, p_175m_116m_58m_24m, hclk_secure_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
1106*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(ACLK_SECURE_S, aclk_secure_s, p_350m_175m_116m_24m, aclk_secure_s_info, &clk_scmi_ops_com_critical, rk3576_aclk_secure_s_rates, false, false);
1107*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(CLK_PKA_CRYPTO_S, clk_pka_crypto_s, p_350m_175m_116m_24m, clk_pka_crypto_s_info, &clk_scmi_ops_com, rk3576_common_rates, false, true);
1108*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(HCLK_VO1_S, hclk_vo1_s, p_175m_116m_58m_24m, hclk_vo1_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
1109*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(PCLK_VO1_S, pclk_vo1_s, p_116m_58m_24m, pclk_vo1_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
1110*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(HCLK_VO0_S, hclk_vo0_s, p_175m_116m_58m_24m, hclk_vo0_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
1111*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(PCLK_VO0_S, pclk_vo0_s, p_116m_58m_24m, pclk_vo0_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
1112*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(PCLK_KLAD, pclk_klad, p_pclk_secure_s, pclk_klad_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1113*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(HCLK_CRYPTO_S, hclk_crypto_s, p_hclk_secure_s, hclk_crypto_s_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1114*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(HCLK_KLAD, hclk_klad, p_hclk_secure_s, hclk_klad_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1115*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(ACLK_CRYPTO_S, aclk_crypto_s, p_aclk_secure_s, aclk_crypto_s_info, &clk_scmi_ops_crypto, rk3576_common_rates, true, true);
1116*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(HCLK_TRNG_S, hclk_trng_s, p_hclk_secure_s, hclk_trng_s_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1117*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(PCLK_OTPC_S, plk_otpc_s, p_pclk_secure_s, pclk_otpc_s_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1118*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(CLK_OTPC_S, clk_otpc_s, p_24m, clk_otpc_s_info, &clk_scmi_ops_gate, rk3576_common_rates, false, true);
1119*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(PCLK_WDT_S, pclk_wdt_s, p_pclk_secure_s, pclk_wdt_s_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1120*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(TCLK_WDT_S, tclk_wdt_s, p_24m, tclk_wdt_s_info, &clk_scmi_ops_gate, rk3576_common_rates, false, true);
1121*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(PCLK_HDCP0_TRNG, pclk_hdcp0_trng, p_pclk_vo0_s, pclk_hdcp0_trng_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1122*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(PCLK_HDCP1_TRNG, pclk_hdcp1_trng, p_pclk_vo1_s, pclk_hdcp1_trng_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1123*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(HCLK_HDCP_KEY0, hclk_hdcp_key0, p_hclk_vo0_s, hclk_hdcp_key0_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1124*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(HCLK_HDCP_KEY1, hclk_hdcp_key1, p_hclk_vo1_s, hclk_hdcp_key1_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1125*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(PCLK_EDP_S, pclk_edp_s, p_pclk_vo0_s, pclk_edp_s_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
1126*036935a8SXiaoDong Huang RK3576_SCMI_CLOCK_COM(ACLK_KLAD, aclk_klad, p_aclk_secure_s, aclk_crypto_s_info, &clk_scmi_ops_crypto, rk3576_common_rates, true, true);
1127*036935a8SXiaoDong Huang
1128*036935a8SXiaoDong Huang rk_scmi_clock_t *clock_table[] = {
1129*036935a8SXiaoDong Huang [ARMCLK_L] = &scmi_armclkl,
1130*036935a8SXiaoDong Huang [ACLK_CCI_ROOT] = &scmi_aclk_cci,
1131*036935a8SXiaoDong Huang [ARMCLK_B] = &scmi_armclkb,
1132*036935a8SXiaoDong Huang [CLK_GPU] = &scmi_clk_gpu,
1133*036935a8SXiaoDong Huang [CLK_RKNN_DSU0] = &scmi_clk_npu,
1134*036935a8SXiaoDong Huang [CLK_STIMER0_ROOT] = &clk_stimer0_root,
1135*036935a8SXiaoDong Huang [CLK_STIMER1_ROOT] = &clk_stimer1_root,
1136*036935a8SXiaoDong Huang [PCLK_SECURE_S] = &pclk_secure_s,
1137*036935a8SXiaoDong Huang [HCLK_SECURE_S] = &hclk_secure_s,
1138*036935a8SXiaoDong Huang [ACLK_SECURE_S] = &aclk_secure_s,
1139*036935a8SXiaoDong Huang [CLK_PKA_CRYPTO_S] = &clk_pka_crypto_s,
1140*036935a8SXiaoDong Huang [HCLK_VO1_S] = &hclk_vo1_s,
1141*036935a8SXiaoDong Huang [PCLK_VO1_S] = &pclk_vo1_s,
1142*036935a8SXiaoDong Huang [HCLK_VO0_S] = &hclk_vo0_s,
1143*036935a8SXiaoDong Huang [PCLK_VO0_S] = &pclk_vo0_s,
1144*036935a8SXiaoDong Huang [PCLK_KLAD] = &pclk_klad,
1145*036935a8SXiaoDong Huang [HCLK_CRYPTO_S] = &hclk_crypto_s,
1146*036935a8SXiaoDong Huang [HCLK_KLAD] = &hclk_klad,
1147*036935a8SXiaoDong Huang [ACLK_CRYPTO_S] = &aclk_crypto_s,
1148*036935a8SXiaoDong Huang [HCLK_TRNG_S] = &hclk_trng_s,
1149*036935a8SXiaoDong Huang [PCLK_OTPC_S] = &plk_otpc_s,
1150*036935a8SXiaoDong Huang [CLK_OTPC_S] = &clk_otpc_s,
1151*036935a8SXiaoDong Huang [PCLK_WDT_S] = &pclk_wdt_s,
1152*036935a8SXiaoDong Huang [TCLK_WDT_S] = &tclk_wdt_s,
1153*036935a8SXiaoDong Huang [PCLK_HDCP0_TRNG] = &pclk_hdcp0_trng,
1154*036935a8SXiaoDong Huang [PCLK_HDCP1_TRNG] = &pclk_hdcp1_trng,
1155*036935a8SXiaoDong Huang [HCLK_HDCP_KEY0] = &hclk_hdcp_key0,
1156*036935a8SXiaoDong Huang [HCLK_HDCP_KEY1] = &hclk_hdcp_key1,
1157*036935a8SXiaoDong Huang [PCLK_EDP_S] = &pclk_edp_s,
1158*036935a8SXiaoDong Huang [ACLK_KLAD] = &aclk_klad,
1159*036935a8SXiaoDong Huang };
1160*036935a8SXiaoDong Huang
rockchip_scmi_clock_count(unsigned int agent_id __unused)1161*036935a8SXiaoDong Huang size_t rockchip_scmi_clock_count(unsigned int agent_id __unused)
1162*036935a8SXiaoDong Huang {
1163*036935a8SXiaoDong Huang return CLK_NR_CLKS;
1164*036935a8SXiaoDong Huang }
1165*036935a8SXiaoDong Huang
rockchip_scmi_get_clock(uint32_t agent_id __unused,uint32_t clock_id)1166*036935a8SXiaoDong Huang rk_scmi_clock_t *rockchip_scmi_get_clock(uint32_t agent_id __unused,
1167*036935a8SXiaoDong Huang uint32_t clock_id)
1168*036935a8SXiaoDong Huang {
1169*036935a8SXiaoDong Huang rk_scmi_clock_t *table = NULL;
1170*036935a8SXiaoDong Huang
1171*036935a8SXiaoDong Huang if (clock_id < ARRAY_SIZE(clock_table)) {
1172*036935a8SXiaoDong Huang table = clock_table[clock_id];
1173*036935a8SXiaoDong Huang if (table == NULL)
1174*036935a8SXiaoDong Huang return NULL;
1175*036935a8SXiaoDong Huang }
1176*036935a8SXiaoDong Huang
1177*036935a8SXiaoDong Huang if ((table != NULL) && (table->is_security == 0))
1178*036935a8SXiaoDong Huang return table;
1179*036935a8SXiaoDong Huang else
1180*036935a8SXiaoDong Huang return NULL;
1181*036935a8SXiaoDong Huang
1182*036935a8SXiaoDong Huang return NULL;
1183*036935a8SXiaoDong Huang }
1184*036935a8SXiaoDong Huang
pvtplls_cpub_suspend(void)1185*036935a8SXiaoDong Huang void pvtplls_cpub_suspend(void)
1186*036935a8SXiaoDong Huang {
1187*036935a8SXiaoDong Huang clk_cpub_set_rate(408000000, PLL_SEL_NOR);
1188*036935a8SXiaoDong Huang cpub_suspended = true;
1189*036935a8SXiaoDong Huang }
1190*036935a8SXiaoDong Huang
pvtplls_cpub_resume(void)1191*036935a8SXiaoDong Huang void pvtplls_cpub_resume(void)
1192*036935a8SXiaoDong Huang {
1193*036935a8SXiaoDong Huang cpub_suspended = false;
1194*036935a8SXiaoDong Huang clk_cpub_set_rate(sys_clk_info.cpub_rate, PLL_SEL_AUTO);
1195*036935a8SXiaoDong Huang }
1196*036935a8SXiaoDong Huang
pvtplls_suspend(void)1197*036935a8SXiaoDong Huang void pvtplls_suspend(void)
1198*036935a8SXiaoDong Huang {
1199*036935a8SXiaoDong Huang clk_cpul_set_rate(408000000, PLL_SEL_NOR);
1200*036935a8SXiaoDong Huang clk_cci_set_rate(408000000, PLL_SEL_NOR);
1201*036935a8SXiaoDong Huang clk_cpub_set_rate(408000000, PLL_SEL_NOR);
1202*036935a8SXiaoDong Huang }
1203*036935a8SXiaoDong Huang
pvtplls_resume(void)1204*036935a8SXiaoDong Huang void pvtplls_resume(void)
1205*036935a8SXiaoDong Huang {
1206*036935a8SXiaoDong Huang clk_cpul_set_rate(sys_clk_info.cpul_rate, PLL_SEL_AUTO);
1207*036935a8SXiaoDong Huang clk_cci_set_rate(sys_clk_info.cci_rate, PLL_SEL_AUTO);
1208*036935a8SXiaoDong Huang clk_cpub_set_rate(sys_clk_info.cpub_rate, PLL_SEL_AUTO);
1209*036935a8SXiaoDong Huang }
1210*036935a8SXiaoDong Huang
sys_reset_pvtplls_prepare(void)1211*036935a8SXiaoDong Huang void sys_reset_pvtplls_prepare(void)
1212*036935a8SXiaoDong Huang {
1213*036935a8SXiaoDong Huang clk_gpu_set_rate(200000000, PLL_SEL_NOR);
1214*036935a8SXiaoDong Huang clk_npu_set_rate(200000000, PLL_SEL_NOR);
1215*036935a8SXiaoDong Huang clk_cpul_set_rate(408000000, PLL_SEL_NOR);
1216*036935a8SXiaoDong Huang clk_cci_set_rate(408000000, PLL_SEL_NOR);
1217*036935a8SXiaoDong Huang clk_cpub_set_rate(408000000, PLL_SEL_NOR);
1218*036935a8SXiaoDong Huang }
1219*036935a8SXiaoDong Huang
rockchip_opteed_clk_set_rate(uint64_t clk_idx,uint64_t rate)1220*036935a8SXiaoDong Huang int rockchip_opteed_clk_set_rate(uint64_t clk_idx, uint64_t rate)
1221*036935a8SXiaoDong Huang {
1222*036935a8SXiaoDong Huang rk_scmi_clock_t *table;
1223*036935a8SXiaoDong Huang
1224*036935a8SXiaoDong Huang if (clk_idx > CLK_NR_CLKS) {
1225*036935a8SXiaoDong Huang INFO("%s: clk-%ld, %ld not supported\n", __func__, clk_idx, rate);
1226*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
1227*036935a8SXiaoDong Huang }
1228*036935a8SXiaoDong Huang
1229*036935a8SXiaoDong Huang table = rockchip_scmi_get_clock(0, clk_idx);
1230*036935a8SXiaoDong Huang if (table != NULL)
1231*036935a8SXiaoDong Huang table->clk_ops->set_rate(table, rate);
1232*036935a8SXiaoDong Huang
1233*036935a8SXiaoDong Huang return 0;
1234*036935a8SXiaoDong Huang }
1235*036935a8SXiaoDong Huang
rockchip_opteed_clk_get_rate(uint64_t clk_idx,uint64_t * rate)1236*036935a8SXiaoDong Huang int rockchip_opteed_clk_get_rate(uint64_t clk_idx, uint64_t *rate)
1237*036935a8SXiaoDong Huang {
1238*036935a8SXiaoDong Huang rk_scmi_clock_t *table;
1239*036935a8SXiaoDong Huang
1240*036935a8SXiaoDong Huang if (clk_idx > CLK_NR_CLKS) {
1241*036935a8SXiaoDong Huang INFO("%s: clk-%ld not supported\n", __func__, clk_idx);
1242*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
1243*036935a8SXiaoDong Huang }
1244*036935a8SXiaoDong Huang
1245*036935a8SXiaoDong Huang table = rockchip_scmi_get_clock(0, clk_idx);
1246*036935a8SXiaoDong Huang if (table != NULL)
1247*036935a8SXiaoDong Huang *rate = (uint64_t)table->clk_ops->get_rate(table);
1248*036935a8SXiaoDong Huang return 0;
1249*036935a8SXiaoDong Huang }
1250*036935a8SXiaoDong Huang
rockchip_opteed_clk_enable(uint64_t clk_idx,uint64_t enable)1251*036935a8SXiaoDong Huang int rockchip_opteed_clk_enable(uint64_t clk_idx, uint64_t enable)
1252*036935a8SXiaoDong Huang {
1253*036935a8SXiaoDong Huang rk_scmi_clock_t *table;
1254*036935a8SXiaoDong Huang
1255*036935a8SXiaoDong Huang if (clk_idx > CLK_NR_CLKS) {
1256*036935a8SXiaoDong Huang INFO("%s: clk-%ld, %ld not supported\n", __func__, clk_idx, enable);
1257*036935a8SXiaoDong Huang return SCMI_INVALID_PARAMETERS;
1258*036935a8SXiaoDong Huang }
1259*036935a8SXiaoDong Huang
1260*036935a8SXiaoDong Huang table = rockchip_scmi_get_clock(0, clk_idx);
1261*036935a8SXiaoDong Huang if (table != NULL) {
1262*036935a8SXiaoDong Huang if (enable != 0) {
1263*036935a8SXiaoDong Huang table->clk_ops->set_status(table, enable);
1264*036935a8SXiaoDong Huang table->enable_count++;
1265*036935a8SXiaoDong Huang } else {
1266*036935a8SXiaoDong Huang if (table->enable_count == 0)
1267*036935a8SXiaoDong Huang return 0;
1268*036935a8SXiaoDong Huang if (--table->enable_count > 0)
1269*036935a8SXiaoDong Huang return 0;
1270*036935a8SXiaoDong Huang table->clk_ops->set_status(table, enable);
1271*036935a8SXiaoDong Huang }
1272*036935a8SXiaoDong Huang }
1273*036935a8SXiaoDong Huang return 0;
1274*036935a8SXiaoDong Huang }
1275*036935a8SXiaoDong Huang
1276*036935a8SXiaoDong Huang #define RK3576_CPUB_OPP_INFO_OFFSET 48
1277*036935a8SXiaoDong Huang #define RK3576_CPUL_OPP_INFO_OFFSET 54
1278*036935a8SXiaoDong Huang #define RK3576_CCI_OPP_INFO_OFFSET 60
1279*036935a8SXiaoDong Huang #define RK3576_NPU_OPP_INFO_OFFSET 66
1280*036935a8SXiaoDong Huang #define RK3576_GPU_OPP_INFO_OFFSET 72
1281*036935a8SXiaoDong Huang
rockchip_init_pvtpll_table(void)1282*036935a8SXiaoDong Huang static void rockchip_init_pvtpll_table(void)
1283*036935a8SXiaoDong Huang {
1284*036935a8SXiaoDong Huang sys_clk_info.cpul_table = rk3576_cpul_pvtpll_table;
1285*036935a8SXiaoDong Huang sys_clk_info.cpul_rate_count = ARRAY_SIZE(rk3576_cpul_pvtpll_table);
1286*036935a8SXiaoDong Huang sys_clk_info.cci_table = rk3576_cci_pvtpll_table;
1287*036935a8SXiaoDong Huang sys_clk_info.cci_rate_count = ARRAY_SIZE(rk3576_cci_pvtpll_table);
1288*036935a8SXiaoDong Huang sys_clk_info.cpub_table = rk3576_cpub_pvtpll_table;
1289*036935a8SXiaoDong Huang sys_clk_info.cpub_rate_count = ARRAY_SIZE(rk3576_cpub_pvtpll_table);
1290*036935a8SXiaoDong Huang sys_clk_info.gpu_table = rk3576_gpu_pvtpll_table;
1291*036935a8SXiaoDong Huang sys_clk_info.gpu_rate_count = ARRAY_SIZE(rk3576_gpu_pvtpll_table);
1292*036935a8SXiaoDong Huang sys_clk_info.npu_table = rk3576_npu_pvtpll_table;
1293*036935a8SXiaoDong Huang sys_clk_info.npu_rate_count = ARRAY_SIZE(rk3576_npu_pvtpll_table);
1294*036935a8SXiaoDong Huang }
1295*036935a8SXiaoDong Huang
rockchip_clock_init(void)1296*036935a8SXiaoDong Huang void rockchip_clock_init(void)
1297*036935a8SXiaoDong Huang {
1298*036935a8SXiaoDong Huang rockchip_init_pvtpll_table();
1299*036935a8SXiaoDong Huang }
1300*036935a8SXiaoDong Huang
pvtpll_get_clk(uint64_t clock_id,struct pvtpll_table ** table,unsigned int * count)1301*036935a8SXiaoDong Huang static int pvtpll_get_clk(uint64_t clock_id, struct pvtpll_table **table,
1302*036935a8SXiaoDong Huang unsigned int *count)
1303*036935a8SXiaoDong Huang {
1304*036935a8SXiaoDong Huang switch (clock_id) {
1305*036935a8SXiaoDong Huang case ARMCLK_L:
1306*036935a8SXiaoDong Huang *table = sys_clk_info.cpul_table;
1307*036935a8SXiaoDong Huang *count = sys_clk_info.cpul_rate_count;
1308*036935a8SXiaoDong Huang break;
1309*036935a8SXiaoDong Huang case ARMCLK_B:
1310*036935a8SXiaoDong Huang *table = sys_clk_info.cpub_table;
1311*036935a8SXiaoDong Huang *count = sys_clk_info.cpub_rate_count;
1312*036935a8SXiaoDong Huang break;
1313*036935a8SXiaoDong Huang case CLK_GPU:
1314*036935a8SXiaoDong Huang *table = sys_clk_info.gpu_table;
1315*036935a8SXiaoDong Huang *count = sys_clk_info.gpu_rate_count;
1316*036935a8SXiaoDong Huang break;
1317*036935a8SXiaoDong Huang case CLK_RKNN_DSU0:
1318*036935a8SXiaoDong Huang *table = sys_clk_info.npu_table;
1319*036935a8SXiaoDong Huang *count = sys_clk_info.npu_rate_count;
1320*036935a8SXiaoDong Huang break;
1321*036935a8SXiaoDong Huang default:
1322*036935a8SXiaoDong Huang return -1;
1323*036935a8SXiaoDong Huang }
1324*036935a8SXiaoDong Huang
1325*036935a8SXiaoDong Huang if ((*table == NULL) || (*count == 0))
1326*036935a8SXiaoDong Huang return -1;
1327*036935a8SXiaoDong Huang
1328*036935a8SXiaoDong Huang return 0;
1329*036935a8SXiaoDong Huang }
1330*036935a8SXiaoDong Huang
pvtpll_volt_sel_adjust(uint64_t clock_id,uint64_t volt_sel)1331*036935a8SXiaoDong Huang int pvtpll_volt_sel_adjust(uint64_t clock_id, uint64_t volt_sel)
1332*036935a8SXiaoDong Huang {
1333*036935a8SXiaoDong Huang struct pvtpll_table *table = NULL;
1334*036935a8SXiaoDong Huang uint32_t delta_len = 0;
1335*036935a8SXiaoDong Huang unsigned int count = 0;
1336*036935a8SXiaoDong Huang int i;
1337*036935a8SXiaoDong Huang
1338*036935a8SXiaoDong Huang if (pvtpll_get_clk(clock_id, &table, &count) != 0)
1339*036935a8SXiaoDong Huang return -1;
1340*036935a8SXiaoDong Huang
1341*036935a8SXiaoDong Huang for (i = 0; i < count; i++) {
1342*036935a8SXiaoDong Huang if (table[i].volt_sel_thr == 0)
1343*036935a8SXiaoDong Huang continue;
1344*036935a8SXiaoDong Huang if (volt_sel >= table[i].volt_sel_thr) {
1345*036935a8SXiaoDong Huang delta_len = volt_sel - table[i].volt_sel_thr + 1;
1346*036935a8SXiaoDong Huang table[i].length += delta_len;
1347*036935a8SXiaoDong Huang if (table[i].length > RK3576_PVTPLL_MAX_LENGTH)
1348*036935a8SXiaoDong Huang table[i].length = RK3576_PVTPLL_MAX_LENGTH;
1349*036935a8SXiaoDong Huang }
1350*036935a8SXiaoDong Huang }
1351*036935a8SXiaoDong Huang
1352*036935a8SXiaoDong Huang return 0;
1353*036935a8SXiaoDong Huang }
1354