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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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