// SPDX-License-Identifier: BSD-3-Clause /* * Copyright (c) 2025, Rockchip Electronics Co., Ltd. */ #include #include #include #include #include #include #include #include #include #include #include #include enum pll_type_sel { PLL_SEL_AUTO, /* all plls (normal pll or pvtpll) */ PLL_SEL_PVT, PLL_SEL_NOR, PLL_SEL_AUTO_NOR /* all normal plls (apll/gpll/npll) */ }; #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) #define RK3576_PVTPLL_RING_EN 0x00 #define RK3576_PVTPLL_RING0_LENGTH 0x04 #define RK3576_PVTPLL_RING1_LENGTH 0x08 #define RK3576_PVTPLL_RING2_LENGTH 0x0c #define RK3576_PVTPLL_RING3_LENGTH 0x10 #define RK3576_PVTPLL_GCK_CFG 0x20 #define RK3576_PVTPLL_GCK_LEN 0x24 #define RK3576_PVTPLL_GCK_DIV 0x28 #define RK3576_PVTPLL_GCK_CAL_CNT 0x2c #define RK3576_PVTPLL_GCK_REF_VAL 0x30 #define RK3576_PVTPLL_GCK_CFG_VAL 0x34 #define RK3576_PVTPLL_GCK_THR 0x38 #define RK3576_PVTPLL_GFREE_CON 0x3c #define RK3576_PVTPLL_ADC_CFG 0x40 #define RK3576_PVTPLL_ADC_CAL_CNT 0x48 #define RK3576_PVTPLL_GCK_CNT 0x50 #define RK3576_PVTPLL_GCK_CNT_AVG 0x54 #define RK3576_PVTPLL_GCK_STATE 0x5c #define RK3576_PVTPLL_ADC_CNT 0x60 #define RK3576_PVTPLL_ADC_CNT_AVG 0x68 #define RK3576_PVTPLL_VERSION 0x70 #define RK3576_PVTPLL_MAX_LENGTH 0x3f #define GPLL_RATE 1188000000 #define CPLL_RATE 1000000000 #define SPLL_RATE 702000000 #define AUPLL_RATE 786431952 #define MAX_RATE_TABLE 16 #define CLKDIV_6BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0x3fU, shift) #define CLKDIV_5BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0x1fU, shift) #define CLKDIV_4BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0xfU, shift) #define CLKDIV_3BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0x7U, shift) #define CLKDIV_2BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0x3U, shift) #define CLKDIV_1BITS_SHF(div, shift) BITS_WITH_WMASK(div, 0x1U, shift) #define CPU_PLL_PATH_SLOWMODE BITS_WITH_WMASK(0U, 0x3U, 0) #define CPU_PLL_PATH_NORMAL BITS_WITH_WMASK(1U, 0x3U, 0) #define CPU_PLL_PATH_DEEP_SLOW BITS_WITH_WMASK(2U, 0x3U, 0) #define CRU_PLL_POWER_DOWN BIT_WITH_WMSK(13) #define CRU_PLL_POWER_UP WMSK_BIT(13) /* clk_core: * from normal pll(core_i: gpll or apll) path or direct pass from apll */ /* cpul clk path */ #define CPUL_CLK_PATH_NOR_GPLL BITS_WITH_WMASK(1U, 0x3U, 12) #define CPUL_CLK_PATH_NOR_LPLL BITS_WITH_WMASK(0U, 0x3U, 12) #define CPUL_CLK_PATH_NOR_PVTPLL BITS_WITH_WMASK(2U, 0x3U, 12) #define CPUL_CLK_PATH_LPLL BITS_WITH_WMASK(0U, 0x3U, 6) #define CPUL_CLK_PATH_DIR_LPLL BITS_WITH_WMASK(2U, 0x3U, 6) #define CPUL_CLK_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x3U, 6) #define CPUL_PVTPLL_PATH_DEEP_SLOW BITS_WITH_WMASK(0U, 0x1U, 13) #define CPUL_PVTPLL_PATH_PVTPLL BITS_WITH_WMASK(0x1, 0x1U, 13) /* cpub clk path */ #define CPUB_CLK_PATH_NOR_GPLL BITS_WITH_WMASK(1U, 0x3U, 12) #define CPUB_CLK_PATH_NOR_BPLL BITS_WITH_WMASK(0U, 0x3U, 12) #define CPUB_CLK_PATH_NOR_PVTPLL BITS_WITH_WMASK(2U, 0x3U, 12) #define CPUB_CLK_PATH_BPLL BITS_WITH_WMASK(0U, 0x3U, 14) #define CPUB_CLK_PATH_DIR_BPLL BITS_WITH_WMASK(2U, 0x3U, 14) #define CPUB_CLK_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x3U, 14) #define CPUB_PVTPLL_PATH_DEEP_SLOW BITS_WITH_WMASK(0U, 0x1U, 5) #define CPUB_PVTPLL_PATH_PVTPLL BITS_WITH_WMASK(0x1, 0x1U, 5) #define CPUB_PCLK_PATH_100M BITS_WITH_WMASK(0U, 0x3U, 0) #define CPUB_PCLK_PATH_50M BITS_WITH_WMASK(1U, 0x3U, 0) #define CPUB_PCLK_PATH_24M BITS_WITH_WMASK(2U, 0x3U, 0) /* cci clk path */ #define SCLK_CCI_PATH_XIN BITS_WITH_WMASK(0U, 0x3U, 12) #define SCLK_CCI_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x3U, 12) #define SCLK_CCI_PATH_NOR_LPLL BITS_WITH_WMASK(3U, 0x3U, 12) #define SCLK_CCI_PATH_NOR_GPLL BITS_WITH_WMASK(2U, 0x3U, 12) #define CCI_PVTPLL_PATH_DEEP_SLOW BITS_WITH_WMASK(0U, 0x1U, 14) #define CCI_PVTPLL_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x1U, 14) /* npu clk path */ #define NPU_CLK_PATH_NOR_GPLL BITS_WITH_WMASK(0U, 0x7U, 7) #define NPU_CLK_PATH_NOR_CPLL BITS_WITH_WMASK(1U, 0x7U, 7) #define NPU_CLK_PATH_NOR_AUPLL BITS_WITH_WMASK(2U, 0x7U, 7) #define NPU_CLK_PATH_NOR_SPLL BITS_WITH_WMASK(3U, 0x7U, 7) #define NPU_CLK_PATH_NOR_PLL WMSK_BIT(15) #define NPU_CLK_PATH_PVTPLL BIT_WITH_WMSK(15) #define NPU_PVTPLL_PATH_DEEP_SLOW BITS_WITH_WMASK(0U, 0x1U, 9) #define NPU_PVTPLL_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x1U, 9) /* gpu clk path */ #define GPU_CLK_PATH_NOR_GPLL BITS_WITH_WMASK(0U, 0x7U, 5) #define GPU_CLK_PATH_NOR_CPLL BITS_WITH_WMASK(1U, 0x7U, 5) #define GPU_CLK_PATH_NOR_AUPLL BITS_WITH_WMASK(2U, 0x7U, 5) #define GPU_CLK_PATH_NOR_SPLL BITS_WITH_WMASK(3U, 0x7U, 5) #define GPU_CLK_PATH_NOR_LPLL BITS_WITH_WMASK(4U, 0x7U, 5) #define GPU_CLK_PATH_NOR_PLL WMSK_BIT(8) #define GPU_CLK_PATH_PVTPLL BIT_WITH_WMSK(8) #define GPU_PVTPLL_PATH_DEEP_SLOW BITS_WITH_WMASK(0U, 0x1U, 9) #define GPU_PVTPLL_PATH_PVTPLL BITS_WITH_WMASK(1U, 0x1U, 9) #define PVTPLL_NEED(type, length) (((type) == PLL_SEL_PVT || \ (type) == PLL_SEL_AUTO) && \ (length)) /* * [0]: set intermediate rate * [1]: scaling up rate or scaling down rate * [1]: add length for pvtpll * [2:5]: length * [2]: use low length for pvtpll * [3:5]: reserved */ #define OPP_RATE_MASK 0x3f #define OPP_INTERMEDIATE_RATE BIT(0) #define OPP_SCALING_UP_RATE BIT(1) #define OPP_ADD_LENGTH BIT(1) #define OPP_LENGTH_MASK GENMASK_32(5, 2) #define OPP_LENGTH_SHIFT 2 #define OPP_LENGTH_LOW BIT(2) #define PRATE(x) static const unsigned long const x[] #define PINFO(x) static const uint32_t const x[] PRATE(p_24m) = { OSC_HZ }; PRATE(p_100m_24m) = { 100 * MHz, OSC_HZ }; PRATE(p_350m_175m_116m_24m) = { 350 * MHz, 175 * MHz, 116 * MHz, OSC_HZ }; PRATE(p_175m_116m_58m_24m) = { 175 * MHz, 116 * MHz, 58 * MHz, OSC_HZ }; PRATE(p_116m_58m_24m) = { 116 * MHz, 58 * MHz, OSC_HZ }; PRATE(p_pclk_secure_s) = { PCLK_SECURE_S }; PRATE(p_hclk_secure_s) = { HCLK_SECURE_S }; PRATE(p_aclk_secure_s) = { ACLK_SECURE_S }; PRATE(p_hclk_vo0_s) = { HCLK_VO0_S }; PRATE(p_pclk_vo0_s) = { PCLK_VO0_S }; PRATE(p_hclk_vo1_s) = { HCLK_VO1_S }; PRATE(p_pclk_vo1_s) = { PCLK_VO1_S }; PINFO(clk_stimer0_root_info) = { 0x27214004, 6, 1, 0, 0, 0, 0x27214028, 9 }; PINFO(clk_stimer1_root_info) = { 0x27214004, 7, 1, 0, 0, 0, 0x2721402c, 1 }; PINFO(pclk_secure_s_info) = { 0x27214004, 4, 2, 0, 0, 0, 0x27214028, 2 }; PINFO(hclk_secure_s_info) = { 0x27214004, 2, 2, 0, 0, 0, 0x27214028, 1 }; PINFO(aclk_secure_s_info) = { 0x27214004, 0, 2, 0, 0, 0, 0x27214028, 0 }; PINFO(clk_pka_crypto_s_info) = { 0x27214004, 11, 2, 0, 0, 0, 0x27214030, 11 }; PINFO(hclk_vo1_s_info) = { 0x27214010, 0, 2, 0, 0, 0, 0x27214038, 1 }; PINFO(pclk_vo1_s_info) = { 0x27214010, 2, 2, 0, 0, 0, 0x27214038, 4 }; PINFO(hclk_vo0_s_info) = { 0x27214018, 0, 2, 0, 0, 0, 0x2721403c, 1 }; PINFO(pclk_vo0_s_info) = { 0x27214018, 2, 2, 0, 0, 0, 0x2721403c, 4 }; PINFO(pclk_klad_info) = { 0, 0, 0, 0, 0, 0, 0x27214030, 7 }; PINFO(hclk_crypto_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214030, 8 }; PINFO(hclk_klad_info) = { 0, 0, 0, 0, 0, 0, 0x27214030, 9 }; PINFO(aclk_crypto_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214030, 12 }; PINFO(hclk_trng_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214034, 0 }; PINFO(pclk_otpc_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214034, 3 }; PINFO(clk_otpc_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214034, 4 }; PINFO(pclk_wdt_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214034, 9 }; PINFO(tclk_wdt_s_info) = { 0, 0, 0, 0, 0, 0, 0x27214034, 10 }; PINFO(pclk_hdcp1_trng_info) = { 0, 0, 0, 0, 0, 0, 0x27214038, 0 }; PINFO(hclk_hdcp_key1_info) = { 0, 0, 0, 0, 0, 0, 0x27214038, 3 }; PINFO(pclk_hdcp0_trng_info) = { 0, 0, 0, 0, 0, 0, 0x2721403c, 0 }; PINFO(hclk_hdcp_key0_info) = { 0, 0, 0, 0, 0, 0, 0x2721403c, 3 }; PINFO(pclk_edp_s_info) = { 0, 0, 0, 0, 0, 0, 0x2721403c, 5 }; struct pvtpll_table { unsigned int rate; uint32_t length; uint32_t length_frac; uint32_t length_low; uint32_t length_low_frac; uint32_t ring_sel; uint32_t volt_sel_thr; }; struct sys_clk_info_t { struct pvtpll_table *cpul_table; struct pvtpll_table *cci_table; struct pvtpll_table *cpub_table; struct pvtpll_table *gpu_table; struct pvtpll_table *npu_table; unsigned int cpul_rate_count; unsigned int cci_rate_count; unsigned int cpub_rate_count; unsigned int gpu_rate_count; unsigned int npu_rate_count; unsigned long cpul_rate; unsigned long cci_rate; unsigned long cpub_rate; unsigned long gpu_rate; unsigned long npu_rate; }; struct otp_opp_info { uint16_t min_freq; uint16_t max_freq; uint8_t volt; uint8_t length; } __packed; #define RK3576_SCMI_CLOCK(_id, _name, _data, _table, _cnt, _is_s) \ rk_scmi_clock_t _name = { \ .id = _id, \ .name = #_name, \ .clk_ops = _data, \ .rate_table = _table, \ .rate_cnt = _cnt, \ .is_security = _is_s, \ } #define RK3576_SCMI_CLOCK_COM(_id, _name, _parent_table, _info, _data, \ _table, is_d, _is_s) \ rk_scmi_clock_t _name = { \ .id = _id, \ .name = #_name, \ .parent_table = _parent_table, \ .info = _info, \ .clk_ops = _data, \ .rate_table = _table, \ .rate_cnt = ARRAY_SIZE(_table), \ .is_dynamic_prate = is_d, \ .is_security = _is_s, \ } #define ROCKCHIP_PVTPLL(_rate, _sel, _len, _len_frac) \ { \ .rate = _rate##U, \ .ring_sel = _sel, \ .length = _len, \ .length_frac = _len_frac, \ } static struct pvtpll_table rk3576_cpul_pvtpll_table[] = { /* rate_hz, ring_sel, length, length_frac */ ROCKCHIP_PVTPLL(2016000000, 0, 6, 0), ROCKCHIP_PVTPLL(1920000000, 0, 6, 1), ROCKCHIP_PVTPLL(1800000000, 0, 6, 1), ROCKCHIP_PVTPLL(1608000000, 0, 6, 1), ROCKCHIP_PVTPLL(1416000000, 0, 8, 0), ROCKCHIP_PVTPLL(1200000000, 0, 11, 0), ROCKCHIP_PVTPLL(1008000000, 0, 17, 0), ROCKCHIP_PVTPLL(816000000, 0, 26, 0), ROCKCHIP_PVTPLL(600000000, 0, 0, 0), ROCKCHIP_PVTPLL(408000000, 0, 0, 0), { /* sentinel */ }, }; static struct pvtpll_table rk3576_cci_pvtpll_table[] = { /* cpul_rate_hz, ring_sel, length, length_frac */ ROCKCHIP_PVTPLL(2016000000 / 2, 0, 27, 0), ROCKCHIP_PVTPLL(1920000000 / 2, 0, 28, 0), ROCKCHIP_PVTPLL(1800000000 / 2, 0, 28, 0), ROCKCHIP_PVTPLL(1608000000 / 2, 0, 30, 0), ROCKCHIP_PVTPLL(1416000000 / 2, 0, 34, 0), ROCKCHIP_PVTPLL(1200000000 / 2, 0, 34, 0), { /* sentinel */ }, }; static struct pvtpll_table rk3576_cpub_pvtpll_table[] = { /* rate_hz, ring_sel, length, length_frac, length_low, length_low_frac */ ROCKCHIP_PVTPLL(2208000000, 0, 4, 3), ROCKCHIP_PVTPLL(2112000000, 0, 5, 0), ROCKCHIP_PVTPLL(2016000000, 0, 5, 0), ROCKCHIP_PVTPLL(1800000000, 0, 5, 0), ROCKCHIP_PVTPLL(1608000000, 0, 5, 0), ROCKCHIP_PVTPLL(1416000000, 0, 7, 0), ROCKCHIP_PVTPLL(1200000000, 0, 11, 0), ROCKCHIP_PVTPLL(1008000000, 0, 17, 0), ROCKCHIP_PVTPLL(816000000, 0, 26, 0), ROCKCHIP_PVTPLL(600000000, 0, 0, 0), ROCKCHIP_PVTPLL(408000000, 0, 0, 0), { /* sentinel */ }, }; static struct pvtpll_table rk3576_gpu_pvtpll_table[] = { /* rate_hz, ring_sel, length, length_frac, length_low, length_low_frac */ ROCKCHIP_PVTPLL(900000000, 0, 20, 0), ROCKCHIP_PVTPLL(800000000, 0, 21, 0), ROCKCHIP_PVTPLL(700000000, 0, 21, 0), ROCKCHIP_PVTPLL(600000000, 0, 23, 0), ROCKCHIP_PVTPLL(500000000, 0, 32, 0), ROCKCHIP_PVTPLL(400000000, 0, 48, 0), ROCKCHIP_PVTPLL(300000000, 0, 63, 0), ROCKCHIP_PVTPLL(200000000, 0, 0, 0), { /* sentinel */ }, }; static struct pvtpll_table rk3576_npu_pvtpll_table[] = { /* rate_hz, ring_sel, length, length_frac, length_low, length_low_frac */ ROCKCHIP_PVTPLL(950000000, 0, 16, 0), ROCKCHIP_PVTPLL(900000000, 0, 17, 0), ROCKCHIP_PVTPLL(800000000, 0, 18, 0), ROCKCHIP_PVTPLL(700000000, 0, 22, 0), ROCKCHIP_PVTPLL(600000000, 0, 25, 0), ROCKCHIP_PVTPLL(500000000, 0, 35, 0), ROCKCHIP_PVTPLL(400000000, 0, 46, 0), ROCKCHIP_PVTPLL(300000000, 0, 63, 0), ROCKCHIP_PVTPLL(200000000, 0, 0, 0), { /* sentinel */ }, }; static unsigned long rk3576_cpul_rates[] = { 408000000, 600000000, 816000000, 1008000000, 1200000000, 1416000000, 1608000000, 1800000000, 2016000000, 2208000000, 2304000063 }; static unsigned long rk3576_cpub_rates[] = { 408000000, 600000000, 816000000, 1008000000, 1200000000, 1416000000, 1608000000, 1800000000, 2016000000, 2208000000, 2304000000, 2400000063 }; static unsigned long rk3576_gpu_rates[] = { 200000000, 300000000, 400000000, 500000000, 600000000, 700000000, 800000000, 900000000, 1000000063 }; static unsigned long rk3576_npu_rates[] = { 200000000, 300000000, 400000000, 500000000, 600000000, 700000000, 800000000, 900000000, 1000000063 }; static unsigned long rk3576_common_rates[] = { 400000, 24000000, 58000000, 100000000, 116000000, 175000000, 350000000, }; static unsigned long rk3576_aclk_secure_s_rates[] = { 116000000, 175000000, 350000000, }; static int aclk_crypto_s_enable; static int aclk_klad_enable; static spinlock_t crypto_lock; static bool cpub_suspended; static struct sys_clk_info_t sys_clk_info; static int clk_scmi_cci_set_rate(rk_scmi_clock_t *clock, unsigned long rate); static struct pvtpll_table *rkclk_get_pvtpll_config(struct pvtpll_table *table, unsigned int count, unsigned int freq_hz) { int i; for (i = 0; i < count; i++) { if (freq_hz == table[i].rate) return &table[i]; } return NULL; } static int clk_scmi_set_low_length(struct pvtpll_table *pvtpll, unsigned int count) { int i; for (i = 0; i < count; i++) { if (pvtpll[i].length_low) { pvtpll[i].length = pvtpll[i].length_low; pvtpll[i].length_frac = pvtpll[i].length_low_frac; } } return 0; } static int clk_cpul_set_rate(unsigned long rate, enum pll_type_sel type) { struct pvtpll_table *pvtpll; int div; if (rate == 0) return SCMI_INVALID_PARAMETERS; pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cpul_table, sys_clk_info.cpul_rate_count, rate); if (pvtpll == NULL) return SCMI_INVALID_PARAMETERS; /* * |-\ * -----lpll-----| \ * | \ |-\ * -----gpll-----|mux|--litcore unclean src--[div]--[autocs]--| \ * | / | \ * --pvtpll src--| / --pvtpll src--|mux|--litcore-- * |-/ | / * --litcore clean src--| / * |-/ */ if (PVTPLL_NEED(type, pvtpll->length)) { /* set ring sel and length */ mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_LEN, 0x1dff0000 | (pvtpll->ring_sel << 10) | (pvtpll->length << 2) | (pvtpll->length_frac)); /* set cal cnt = 24, T = 1us */ mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18); /* enable pvtpll */ mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022); /* start pvtpll */ mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023); /* set pvtpll_src parent from 24MHz/32KHz to pvtpll */ mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1), CPUL_PVTPLL_PATH_PVTPLL); /* set litcore unclean_src parent to pvtpll_src */ mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0), CPUL_CLK_PATH_NOR_PVTPLL); /* * set litcore parent from pvtpll_src to unclean_src, * because autocs is on litcore unclean_src. */ mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1), CPUL_CLK_PATH_LPLL); /* set litcore unclean_src div to 0 */ mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0), CLKDIV_5BITS_SHF(0, 7)); return 0; } /* set litcore unclean_src div */ div = DIV_ROUND_UP(GPLL_RATE, rate) - 1; mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0), CLKDIV_5BITS_SHF(div, 7)); /* set litcore unclean_src parent to gpll */ mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0), CPUL_CLK_PATH_NOR_GPLL); /* set litcore parent to unclean_src */ mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1), CPUL_CLK_PATH_LPLL); return 0; } static int clk_scmi_cpul_set_rate(rk_scmi_clock_t *clock, unsigned long rate) { int ret; if (rate == 0) return SCMI_INVALID_PARAMETERS; ret = clk_cpul_set_rate(rate, PLL_SEL_AUTO); if (ret == 0) { sys_clk_info.cpul_rate = rate; ret = clk_scmi_cci_set_rate(clock, rate / 2); } return ret; } static unsigned long rk3576_lpll_get_rate(void) { unsigned int m, p, s, k; uint64_t rate64 = 24000000, postdiv; int mode; mode = mmio_read_32(LITTLE_CRU_BASE + CRU_MODE_CON) & 0x3; if (mode == 0) return rate64; m = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(16)) >> CRU_PLLCON0_M_SHIFT) & CRU_PLLCON0_M_MASK; p = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(17)) >> CRU_PLLCON1_P_SHIFT) & CRU_PLLCON1_P_MASK; s = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(17)) >> CRU_PLLCON1_S_SHIFT) & CRU_PLLCON1_S_MASK; k = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(18)) >> CRU_PLLCON2_K_SHIFT) & CRU_PLLCON2_K_MASK; rate64 *= m; rate64 = rate64 / p; if (k != 0) { /* fractional mode */ uint64_t frac_rate64 = 24000000 * k; postdiv = p * 65536; frac_rate64 = frac_rate64 / postdiv; rate64 += frac_rate64; } rate64 = rate64 >> s; return (unsigned long)rate64; } static unsigned long clk_scmi_cpul_get_rate(rk_scmi_clock_t *clock) { int src, div; src = mmio_read_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1)) & 0x00c0; src = src >> 6; if (src == 1) return sys_clk_info.cpul_rate; src = mmio_read_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0)) & 0x3000; src = src >> 12; div = mmio_read_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(6)) & 0x0f80; div = div >> 7; switch (src) { case 0: return rk3576_lpll_get_rate(); case 1: /* Make the return rate is equal to the set rate */ if (sys_clk_info.cpul_rate != 0) return sys_clk_info.cpul_rate; else return GPLL_RATE / (div + 1); case 2: return sys_clk_info.cpul_rate; default: return 0; } } static int clk_scmi_cpul_set_status(rk_scmi_clock_t *clock, bool status) { return 0; } static int clk_cpub_set_rate(unsigned long rate, enum pll_type_sel type) { struct pvtpll_table *pvtpll; int div; if (rate == 0) return SCMI_INVALID_PARAMETERS; pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cpub_table, sys_clk_info.cpub_rate_count, rate); if (pvtpll == NULL) return SCMI_INVALID_PARAMETERS; /* * |-\ * -----bpll-----| \ * | \ |-\ * -----gpll-----|mux|--bigcore unclean src--[div]--[autocs]--| \ * | / | \ * --pvtpll src--| / --pvtpll src--|mux|--bigcore-- * |-/ | / * --bigcore clean src--| / * |-/ */ if (PVTPLL_NEED(type, pvtpll->length) != 0) { /* set ring sel and length */ mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_LEN, 0x1dff0000 | (pvtpll->ring_sel << 10) | (pvtpll->length << 2) | (pvtpll->length_frac)); /* set cal cnt = 24, T = 1us */ mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18); /* enable pvtpll */ mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022); /* start pvtpll */ mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023); /* set pvtpll_src parent from 24MHz/32KHz to pvtpll */ mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(2), CPUB_PVTPLL_PATH_PVTPLL); /* set bigcore unclean_src parent to pvtpll_src */ mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1), CPUB_CLK_PATH_NOR_PVTPLL); /* * set bigcore parent from pvtpll_src to unclean_src, * because autocs is on bigcore unclean_src. */ mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1), CPUB_CLK_PATH_BPLL); /* set bigcore unclean_src div to 0 */ mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1), CLKDIV_5BITS_SHF(0, 7)); return 0; } /* set bigcore unclean_src div */ div = DIV_ROUND_UP(GPLL_RATE, rate) - 1; mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1), CLKDIV_5BITS_SHF(div, 7)); /* set bigcore unclean_src parent to gpll */ mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1), CPUB_CLK_PATH_NOR_GPLL); /* set bigcore parent to unclean_src */ mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1), CPUB_CLK_PATH_BPLL); return 0; } static int clk_scmi_cpub_set_rate(rk_scmi_clock_t *clock, unsigned long rate) { int ret; if (rate == 0) return SCMI_INVALID_PARAMETERS; if ((rate & OPP_LENGTH_LOW) != 0) { clk_scmi_set_low_length(sys_clk_info.cpub_table, sys_clk_info.cpub_rate_count); return 0; } ret = clk_cpub_set_rate(rate, PLL_SEL_AUTO); if (ret == 0) sys_clk_info.cpub_rate = rate; return ret; } static unsigned long rk3576_bpll_get_rate(void) { unsigned int m, p, s, k; uint64_t rate64 = 24000000, postdiv; int mode; mode = mmio_read_32(CRU_BASE + CRU_MODE_CON) & 0x3; if (mode == 0) return rate64; m = (mmio_read_32(CRU_BASE + CRU_PLL_CON(0)) >> CRU_PLLCON0_M_SHIFT) & CRU_PLLCON0_M_MASK; p = (mmio_read_32(CRU_BASE + CRU_PLL_CON(1)) >> CRU_PLLCON1_P_SHIFT) & CRU_PLLCON1_P_MASK; s = (mmio_read_32(CRU_BASE + CRU_PLL_CON(1)) >> CRU_PLLCON1_S_SHIFT) & CRU_PLLCON1_S_MASK; k = (mmio_read_32(CRU_BASE + CRU_PLL_CON(2)) >> CRU_PLLCON2_K_SHIFT) & CRU_PLLCON2_K_MASK; rate64 *= m; rate64 = rate64 / p; if (k != 0) { /* fractional mode */ uint64_t frac_rate64 = 24000000 * k; postdiv = p * 65536; frac_rate64 = frac_rate64 / postdiv; rate64 += frac_rate64; } rate64 = rate64 >> s; return (unsigned long)rate64; } static unsigned long clk_scmi_cpub_get_rate(rk_scmi_clock_t *clock) { int value, src, div; if (cpub_suspended != 0) return sys_clk_info.cpub_rate; value = mmio_read_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1)); src = (value & 0xc000) >> 14; if (src == 1) return sys_clk_info.cpub_rate; value = mmio_read_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1)); src = (value & 0x3000) >> 12; div = (value & 0x0f80) >> 7; switch (src) { case 0: return rk3576_bpll_get_rate(); case 1: /* Make the return rate is equal to the set rate */ if (sys_clk_info.cpub_rate != 0) return sys_clk_info.cpub_rate; else return GPLL_RATE / (div + 1); case 2: return sys_clk_info.cpub_rate; default: return 0; } } static int clk_scmi_cpub_set_status(rk_scmi_clock_t *clock, bool status) { return 0; } static unsigned long clk_scmi_cci_get_rate(rk_scmi_clock_t *clock) { int src, div; src = mmio_read_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4)) & 0x3000; src = src >> 12; if (src == 1) return sys_clk_info.cci_rate; div = mmio_read_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4)) & 0xf80; div = div >> 7; switch (src) { case 0: return OSC_HZ; case 1: return sys_clk_info.cci_rate; case 2: return GPLL_RATE / (div + 1); case 3: return rk3576_lpll_get_rate() / (div + 1); default: return 0; } } static int clk_cci_set_rate(unsigned long rate, enum pll_type_sel type) { struct pvtpll_table *pvtpll; uint32_t pvtpll_en = 0; if (rate == 0) return SCMI_INVALID_PARAMETERS; pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cci_table, sys_clk_info.cci_rate_count, rate); /* set pvtpll */ if ((pvtpll != 0) && (PVTPLL_NEED(type, pvtpll->length) != 0)) { /* set ring sel and length */ mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_LEN, 0x1dff0000 | (pvtpll->ring_sel << 10) | (pvtpll->length << 2) | (pvtpll->length_frac)); /* set cal cnt = 24, T = 1us */ mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18); /* enable pvtpll */ pvtpll_en = mmio_read_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CFG); if (pvtpll_en && 0x22 != 0x22) mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022); /* start pvtpll */ mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023); /* set cci mux pvtpll */ mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4), CCI_PVTPLL_PATH_PVTPLL); mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4), SCLK_CCI_PATH_PVTPLL); mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4), CLKDIV_5BITS_SHF(0, 7)); sys_clk_info.cci_rate = rate; return 0; } sys_clk_info.cci_rate = 594000000; /* set cci div */ mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4), CLKDIV_5BITS_SHF(1, 7)); /* set cci mux gpll */ mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4), SCLK_CCI_PATH_NOR_GPLL); return 0; } static int clk_scmi_cci_set_rate(rk_scmi_clock_t *clock, unsigned long rate) { if (rate == 0) return SCMI_INVALID_PARAMETERS; return clk_cci_set_rate(rate, PLL_SEL_AUTO); } static int clk_scmi_cci_set_status(rk_scmi_clock_t *clock, bool status) { return 0; } static unsigned long clk_scmi_gpu_get_rate(rk_scmi_clock_t *clock) { int div, src; if ((mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(165)) & 0x100) != 0) return sys_clk_info.gpu_rate; div = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(165)) & 0x1f; src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(165)) & 0x00e0; src = src >> 5; switch (src) { case 0: /* Make the return rate is equal to the set rate */ if (sys_clk_info.gpu_rate != 0) return sys_clk_info.gpu_rate; else return GPLL_RATE / (div + 1); case 1: return CPLL_RATE / (div + 1); case 2: return AUPLL_RATE / (div + 1); case 3: return SPLL_RATE / (div + 1); case 4: return rk3576_lpll_get_rate() / (div + 1); default: return 0; } } static int clk_gpu_set_rate(unsigned long rate, enum pll_type_sel type) { struct pvtpll_table *pvtpll; int div; pvtpll = rkclk_get_pvtpll_config(sys_clk_info.gpu_table, sys_clk_info.gpu_rate_count, rate); if (pvtpll == NULL) return SCMI_INVALID_PARAMETERS; if (PVTPLL_NEED(type, pvtpll->length) != 0) { /* set ring sel and length */ mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_LEN, 0x1dff0000 | (pvtpll->ring_sel << 10) | (pvtpll->length << 2) | (pvtpll->length_frac)); /* set cal cnt = 24, T = 1us */ mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18); /* enable pvtpll */ mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022); /* start pvtpll */ mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023); /* set gpu mux pvtpll */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165), GPU_PVTPLL_PATH_PVTPLL); mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165), GPU_CLK_PATH_PVTPLL); return 0; } /* set gpu div */ div = DIV_ROUND_UP(GPLL_RATE, rate); mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165), CLKDIV_5BITS_SHF(div - 1, 0)); /* set gpu mux gpll */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165), GPU_CLK_PATH_NOR_GPLL); mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165), GPU_CLK_PATH_NOR_PLL); return 0; } static int clk_scmi_gpu_set_rate(rk_scmi_clock_t *clock, unsigned long rate) { int ret; if (rate == 0) return SCMI_INVALID_PARAMETERS; if ((rate & OPP_LENGTH_LOW) != 0) { clk_scmi_set_low_length(sys_clk_info.gpu_table, sys_clk_info.gpu_rate_count); return 0; } ret = clk_gpu_set_rate(rate, PLL_SEL_AUTO); if (ret == 0) sys_clk_info.gpu_rate = rate; return ret; } static int clk_scmi_gpu_set_status(rk_scmi_clock_t *clock, bool status) { return 0; } static unsigned long clk_scmi_npu_get_rate(rk_scmi_clock_t *clock) { int div, src, div_src; if ((mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x8000) != 0) return sys_clk_info.npu_rate; div_src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x07c; div_src = div_src >> 2; src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x0180; src = src >> 7; div = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x7c00; div = div >> 10; switch (src) { case 0: /* Make the return rate is equal to the set rate */ if (sys_clk_info.npu_rate != 0) return sys_clk_info.npu_rate; else return GPLL_RATE / (div_src + 1) / (div + 1); case 1: return CPLL_RATE / (div_src + 1) / (div + 1); case 2: return AUPLL_RATE / (div_src + 1) / (div + 1); case 3: return SPLL_RATE / (div_src + 1) / (div + 1); default: return 0; } } static int clk_npu_set_rate(unsigned long rate, enum pll_type_sel type) { struct pvtpll_table *pvtpll; int div; pvtpll = rkclk_get_pvtpll_config(sys_clk_info.npu_table, sys_clk_info.npu_rate_count, rate); if (pvtpll == NULL) return SCMI_INVALID_PARAMETERS; if (PVTPLL_NEED(type, pvtpll->length) != 0) { /* set ring sel and length */ mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_LEN, 0x1dff0000 | (pvtpll->ring_sel << 10) | (pvtpll->length << 2) | (pvtpll->length_frac)); /* set cal cnt = 24, T = 1us */ mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18); /* enable pvtpll */ mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022); /* start pvtpll */ mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023); /* set npu mux pvtpll */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86), NPU_PVTPLL_PATH_PVTPLL); mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86), NPU_CLK_PATH_PVTPLL); mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86), CLKDIV_5BITS_SHF(0, 10)); return 0; } /* set npu div */ div = DIV_ROUND_UP(GPLL_RATE, rate); mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86), CLKDIV_5BITS_SHF(div - 1, 2)); mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86), CLKDIV_5BITS_SHF(0, 10)); /* set npu mux gpll */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86), NPU_CLK_PATH_NOR_GPLL); mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86), NPU_CLK_PATH_NOR_PLL); return 0; } static int clk_scmi_npu_set_rate(rk_scmi_clock_t *clock, unsigned long rate) { int ret; if (rate == 0) return SCMI_INVALID_PARAMETERS; if ((rate & OPP_LENGTH_LOW) != 0) { clk_scmi_set_low_length(sys_clk_info.npu_table, sys_clk_info.npu_rate_count); return 0; } ret = clk_npu_set_rate(rate, PLL_SEL_AUTO); if (ret == 0) sys_clk_info.npu_rate = rate; return ret; } static int clk_scmi_npu_set_status(rk_scmi_clock_t *clock, bool status) { return 0; } int clk_scmi_crypto_set_status(rk_scmi_clock_t *clock, bool status) { spin_lock(&crypto_lock); if (clock->id == ACLK_CRYPTO_S) aclk_crypto_s_enable = status; else aclk_klad_enable = status; if ((aclk_crypto_s_enable != 0) || (aclk_klad_enable != 0)) clk_scmi_common_set_status(clock, 1); else clk_scmi_common_set_status(clock, 0); spin_unlock(&crypto_lock); return 0; } static int clk_scmi_common_set_status_critical(rk_scmi_clock_t *clock, bool status) { return 0; } static const struct rk_clk_ops clk_scmi_cpul_ops = { .get_rate = clk_scmi_cpul_get_rate, .set_rate = clk_scmi_cpul_set_rate, .set_status = clk_scmi_cpul_set_status, }; static const struct rk_clk_ops clk_scmi_cci_ops = { .get_rate = clk_scmi_cci_get_rate, .set_rate = clk_scmi_cci_set_rate, .set_status = clk_scmi_cci_set_status, }; static const struct rk_clk_ops clk_scmi_cpub_ops = { .get_rate = clk_scmi_cpub_get_rate, .set_rate = clk_scmi_cpub_set_rate, .set_status = clk_scmi_cpub_set_status, }; static const struct rk_clk_ops clk_scmi_gpu_ops = { .get_rate = clk_scmi_gpu_get_rate, .set_rate = clk_scmi_gpu_set_rate, .set_status = clk_scmi_gpu_set_status, }; static const struct rk_clk_ops clk_scmi_npu_ops = { .get_rate = clk_scmi_npu_get_rate, .set_rate = clk_scmi_npu_set_rate, .set_status = clk_scmi_npu_set_status, }; static const struct rk_clk_ops clk_scmi_ops_com_critical = { .get_rate = clk_scmi_common_get_rate, .set_rate = clk_scmi_common_set_rate, .set_status = clk_scmi_common_set_status_critical, }; static const struct rk_clk_ops clk_scmi_ops_com = { .get_rate = clk_scmi_common_get_rate, .set_rate = clk_scmi_common_set_rate, .set_status = clk_scmi_common_set_status, }; static const struct rk_clk_ops clk_scmi_ops_gate = { .get_rate = clk_scmi_common_get_rate, .set_status = clk_scmi_common_set_status, }; static const struct rk_clk_ops clk_scmi_ops_crypto = { .get_rate = clk_scmi_common_get_rate, .set_status = clk_scmi_crypto_set_status, }; RK3576_SCMI_CLOCK(ARMCLK_L, scmi_armclkl, &clk_scmi_cpul_ops, rk3576_cpul_rates, ARRAY_SIZE(rk3576_cpul_rates), false); RK3576_SCMI_CLOCK(ACLK_CCI_ROOT, scmi_aclk_cci, &clk_scmi_cci_ops, rk3576_cpul_rates, ARRAY_SIZE(rk3576_cpul_rates), false); RK3576_SCMI_CLOCK(ARMCLK_B, scmi_armclkb, &clk_scmi_cpub_ops, rk3576_cpub_rates, ARRAY_SIZE(rk3576_cpub_rates), false); RK3576_SCMI_CLOCK(CLK_GPU, scmi_clk_gpu, &clk_scmi_gpu_ops, rk3576_gpu_rates, ARRAY_SIZE(rk3576_gpu_rates), false); RK3576_SCMI_CLOCK(CLK_RKNN_DSU0, scmi_clk_npu, &clk_scmi_npu_ops, rk3576_npu_rates, ARRAY_SIZE(rk3576_npu_rates), false); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); RK3576_SCMI_CLOCK_COM(PCLK_KLAD, pclk_klad, p_pclk_secure_s, pclk_klad_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true); 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); RK3576_SCMI_CLOCK_COM(HCLK_KLAD, hclk_klad, p_hclk_secure_s, hclk_klad_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); rk_scmi_clock_t *clock_table[] = { [ARMCLK_L] = &scmi_armclkl, [ACLK_CCI_ROOT] = &scmi_aclk_cci, [ARMCLK_B] = &scmi_armclkb, [CLK_GPU] = &scmi_clk_gpu, [CLK_RKNN_DSU0] = &scmi_clk_npu, [CLK_STIMER0_ROOT] = &clk_stimer0_root, [CLK_STIMER1_ROOT] = &clk_stimer1_root, [PCLK_SECURE_S] = &pclk_secure_s, [HCLK_SECURE_S] = &hclk_secure_s, [ACLK_SECURE_S] = &aclk_secure_s, [CLK_PKA_CRYPTO_S] = &clk_pka_crypto_s, [HCLK_VO1_S] = &hclk_vo1_s, [PCLK_VO1_S] = &pclk_vo1_s, [HCLK_VO0_S] = &hclk_vo0_s, [PCLK_VO0_S] = &pclk_vo0_s, [PCLK_KLAD] = &pclk_klad, [HCLK_CRYPTO_S] = &hclk_crypto_s, [HCLK_KLAD] = &hclk_klad, [ACLK_CRYPTO_S] = &aclk_crypto_s, [HCLK_TRNG_S] = &hclk_trng_s, [PCLK_OTPC_S] = &plk_otpc_s, [CLK_OTPC_S] = &clk_otpc_s, [PCLK_WDT_S] = &pclk_wdt_s, [TCLK_WDT_S] = &tclk_wdt_s, [PCLK_HDCP0_TRNG] = &pclk_hdcp0_trng, [PCLK_HDCP1_TRNG] = &pclk_hdcp1_trng, [HCLK_HDCP_KEY0] = &hclk_hdcp_key0, [HCLK_HDCP_KEY1] = &hclk_hdcp_key1, [PCLK_EDP_S] = &pclk_edp_s, [ACLK_KLAD] = &aclk_klad, }; size_t rockchip_scmi_clock_count(unsigned int agent_id __unused) { return CLK_NR_CLKS; } rk_scmi_clock_t *rockchip_scmi_get_clock(uint32_t agent_id __unused, uint32_t clock_id) { rk_scmi_clock_t *table = NULL; if (clock_id < ARRAY_SIZE(clock_table)) { table = clock_table[clock_id]; if (table == NULL) return NULL; } if ((table != NULL) && (table->is_security == 0)) return table; else return NULL; return NULL; } void pvtplls_cpub_suspend(void) { clk_cpub_set_rate(408000000, PLL_SEL_NOR); cpub_suspended = true; } void pvtplls_cpub_resume(void) { cpub_suspended = false; clk_cpub_set_rate(sys_clk_info.cpub_rate, PLL_SEL_AUTO); } void pvtplls_suspend(void) { clk_cpul_set_rate(408000000, PLL_SEL_NOR); clk_cci_set_rate(408000000, PLL_SEL_NOR); clk_cpub_set_rate(408000000, PLL_SEL_NOR); } void pvtplls_resume(void) { clk_cpul_set_rate(sys_clk_info.cpul_rate, PLL_SEL_AUTO); clk_cci_set_rate(sys_clk_info.cci_rate, PLL_SEL_AUTO); clk_cpub_set_rate(sys_clk_info.cpub_rate, PLL_SEL_AUTO); } void sys_reset_pvtplls_prepare(void) { clk_gpu_set_rate(200000000, PLL_SEL_NOR); clk_npu_set_rate(200000000, PLL_SEL_NOR); clk_cpul_set_rate(408000000, PLL_SEL_NOR); clk_cci_set_rate(408000000, PLL_SEL_NOR); clk_cpub_set_rate(408000000, PLL_SEL_NOR); } int rockchip_opteed_clk_set_rate(uint64_t clk_idx, uint64_t rate) { rk_scmi_clock_t *table; if (clk_idx > CLK_NR_CLKS) { INFO("%s: clk-%ld, %ld not supported\n", __func__, clk_idx, rate); return SCMI_INVALID_PARAMETERS; } table = rockchip_scmi_get_clock(0, clk_idx); if (table != NULL) table->clk_ops->set_rate(table, rate); return 0; } int rockchip_opteed_clk_get_rate(uint64_t clk_idx, uint64_t *rate) { rk_scmi_clock_t *table; if (clk_idx > CLK_NR_CLKS) { INFO("%s: clk-%ld not supported\n", __func__, clk_idx); return SCMI_INVALID_PARAMETERS; } table = rockchip_scmi_get_clock(0, clk_idx); if (table != NULL) *rate = (uint64_t)table->clk_ops->get_rate(table); return 0; } int rockchip_opteed_clk_enable(uint64_t clk_idx, uint64_t enable) { rk_scmi_clock_t *table; if (clk_idx > CLK_NR_CLKS) { INFO("%s: clk-%ld, %ld not supported\n", __func__, clk_idx, enable); return SCMI_INVALID_PARAMETERS; } table = rockchip_scmi_get_clock(0, clk_idx); if (table != NULL) { if (enable != 0) { table->clk_ops->set_status(table, enable); table->enable_count++; } else { if (table->enable_count == 0) return 0; if (--table->enable_count > 0) return 0; table->clk_ops->set_status(table, enable); } } return 0; } #define RK3576_CPUB_OPP_INFO_OFFSET 48 #define RK3576_CPUL_OPP_INFO_OFFSET 54 #define RK3576_CCI_OPP_INFO_OFFSET 60 #define RK3576_NPU_OPP_INFO_OFFSET 66 #define RK3576_GPU_OPP_INFO_OFFSET 72 static void rockchip_init_pvtpll_table(void) { sys_clk_info.cpul_table = rk3576_cpul_pvtpll_table; sys_clk_info.cpul_rate_count = ARRAY_SIZE(rk3576_cpul_pvtpll_table); sys_clk_info.cci_table = rk3576_cci_pvtpll_table; sys_clk_info.cci_rate_count = ARRAY_SIZE(rk3576_cci_pvtpll_table); sys_clk_info.cpub_table = rk3576_cpub_pvtpll_table; sys_clk_info.cpub_rate_count = ARRAY_SIZE(rk3576_cpub_pvtpll_table); sys_clk_info.gpu_table = rk3576_gpu_pvtpll_table; sys_clk_info.gpu_rate_count = ARRAY_SIZE(rk3576_gpu_pvtpll_table); sys_clk_info.npu_table = rk3576_npu_pvtpll_table; sys_clk_info.npu_rate_count = ARRAY_SIZE(rk3576_npu_pvtpll_table); } void rockchip_clock_init(void) { rockchip_init_pvtpll_table(); } static int pvtpll_get_clk(uint64_t clock_id, struct pvtpll_table **table, unsigned int *count) { switch (clock_id) { case ARMCLK_L: *table = sys_clk_info.cpul_table; *count = sys_clk_info.cpul_rate_count; break; case ARMCLK_B: *table = sys_clk_info.cpub_table; *count = sys_clk_info.cpub_rate_count; break; case CLK_GPU: *table = sys_clk_info.gpu_table; *count = sys_clk_info.gpu_rate_count; break; case CLK_RKNN_DSU0: *table = sys_clk_info.npu_table; *count = sys_clk_info.npu_rate_count; break; default: return -1; } if ((*table == NULL) || (*count == 0)) return -1; return 0; } int pvtpll_volt_sel_adjust(uint64_t clock_id, uint64_t volt_sel) { struct pvtpll_table *table = NULL; uint32_t delta_len = 0; unsigned int count = 0; int i; if (pvtpll_get_clk(clock_id, &table, &count) != 0) return -1; for (i = 0; i < count; i++) { if (table[i].volt_sel_thr == 0) continue; if (volt_sel >= table[i].volt_sel_thr) { delta_len = volt_sel - table[i].volt_sel_thr + 1; table[i].length += delta_len; if (table[i].length > RK3576_PVTPLL_MAX_LENGTH) table[i].length = RK3576_PVTPLL_MAX_LENGTH; } } return 0; }