1 /* 2 * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <errno.h> 8 9 #include <arch_helpers.h> 10 #include <common/debug.h> 11 #include <drivers/delay_timer.h> 12 13 #include <apupwr_clkctl.h> 14 #include <apupwr_clkctl_def.h> 15 #include <mtk_plat_common.h> 16 #include <platform_def.h> 17 18 /* 8195 use PCW mode to change freq directly */ 19 enum pll_set_rate_mode PLL_MODE = CON0_PCW; 20 21 char *buck_domain_str[APUSYS_BUCK_DOMAIN_NUM] = { 22 "V_VPU0", 23 "V_VPU1", 24 "V_MDLA0", 25 "V_MDLA1", 26 "V_APU_CONN", 27 "V_TOP_IOMMU", 28 "V_VCORE", 29 }; 30 31 uint32_t aacc_set[APUSYS_BUCK_DOMAIN_NUM] = { 32 APU_ACC_CONFG_SET1, APU_ACC_CONFG_SET2, 33 APU_ACC_CONFG_SET4, APU_ACC_CONFG_SET5, 34 APU_ACC_CONFG_SET0, APU_ACC_CONFG_SET7 35 }; 36 37 uint32_t aacc_clr[APUSYS_BUCK_DOMAIN_NUM] = { 38 APU_ACC_CONFG_CLR1, APU_ACC_CONFG_CLR2, 39 APU_ACC_CONFG_CLR4, APU_ACC_CONFG_CLR5, 40 APU_ACC_CONFG_CLR0, APU_ACC_CONFG_CLR7 41 }; 42 43 struct reg_seq { 44 uint32_t address; 45 uint32_t val; 46 }; 47 48 static const struct reg_seq init_acc_cfg[] = { 49 { APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU) }, 50 { APU_ACC_CONFG_CLR0, BIT(BIT_CGEN_SOC) }, 51 { APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU_DIV2) }, 52 { APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU) }, 53 { APU_ACC_CONFG_CLR7, BIT(BIT_CGEN_SOC) }, 54 { APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU_DIV2) }, 55 { APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU) }, 56 { APU_ACC_CONFG_CLR1, BIT(BIT_CGEN_SOC) }, 57 { APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU_DIV2) }, 58 { APU_ACC_CONFG_SET2, BIT(BIT_INVEN_OUT) }, 59 { APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU) }, 60 { APU_ACC_CONFG_CLR2, BIT(BIT_CGEN_SOC) }, 61 { APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU_DIV2) }, 62 { APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU) }, 63 { APU_ACC_CONFG_CLR4, BIT(BIT_CGEN_SOC) }, 64 { APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU_DIV2) }, 65 { APU_ACC_CONFG_SET5, BIT(BIT_INVEN_OUT) }, 66 { APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU) }, 67 { APU_ACC_CONFG_CLR5, BIT(BIT_CGEN_SOC) }, 68 { APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU_DIV2) }, 69 }; 70 71 int32_t apupwr_smc_acc_init_all(void) 72 { 73 int32_t i; 74 75 for (i = 0; i < ARRAY_SIZE(init_acc_cfg); i++) { 76 apupwr_writel(init_acc_cfg[i].val, 77 init_acc_cfg[i].address); 78 } 79 80 /* Deault ACC will raise APU_DIV_2 */ 81 apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ, 82 true, V_APU_CONN); 83 84 apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ, 85 true, V_TOP_IOMMU); 86 87 apupwr_smc_pll_set_rate(BUCK_VVPU_DOMAIN_DEFAULT_FREQ, 88 true, V_VPU0); 89 90 apupwr_smc_pll_set_rate(BUCK_VMDLA_DOMAIN_DEFAULT_FREQ, 91 true, V_MDLA0); 92 93 return 0; 94 } 95 96 void apupwr_smc_acc_top(bool enable) 97 { 98 if (enable) { 99 apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_APU_CONN]); 100 apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_TOP_IOMMU]); 101 } else { 102 apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_APU_CONN]); 103 apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_TOP_IOMMU]); 104 } 105 } 106 107 /* 108 * acc_clk_set_parent:ACC MUX select 109 * 0. freq parameters here, only ACC clksrc is valid 110 * 1. Switch between APUPLL <=> Parking (F26M, PARK) 111 * 2. Turn on/off CG_F26M, CG_PARK, CG_SOC, but no CG_APU 112 * 3. Clear APU Div2 while Parking 113 * 4. Only use clksrc of APUPLL while ACC CG_APU is on 114 */ 115 int32_t apupwr_smc_acc_set_parent(uint32_t freq, uint32_t domain) 116 { 117 uint32_t acc_set = 0; 118 uint32_t acc_clr = 0; 119 int32_t ret = 0; 120 121 if (freq > DVFS_FREQ_ACC_APUPLL) { 122 ERROR("%s wrong clksrc: %d\n", __func__, freq); 123 ret = -EIO; 124 goto err; 125 } 126 127 switch (domain) { 128 case V_VPU1: 129 case V_VPU0: 130 case V_MDLA1: 131 case V_MDLA0: 132 case V_APU_CONN: 133 case V_TOP_IOMMU: 134 acc_set = aacc_set[domain]; 135 acc_clr = aacc_clr[domain]; 136 break; 137 default: 138 ret = -EIO; 139 break; 140 } 141 142 /* Select park source */ 143 switch (freq) { 144 case DVFS_FREQ_ACC_PARKING: 145 /* Select park source */ 146 apupwr_writel(BIT(BIT_SEL_PARK), acc_set); 147 apupwr_writel(BIT(BIT_SEL_F26M), acc_clr); 148 /* Enable park cg */ 149 apupwr_writel(BIT(BIT_CGEN_PARK), acc_set); 150 apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_SOC), acc_clr); 151 /* Select park path */ 152 apupwr_writel(BIT(BIT_SEL_APU), acc_clr); 153 /* clear apu div 2 */ 154 apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr); 155 break; 156 157 case DVFS_FREQ_ACC_APUPLL: 158 /* Select park path */ 159 apupwr_writel(BIT(BIT_SEL_APU), acc_set); 160 /* Clear park cg */ 161 apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_F26M) | 162 BIT(BIT_CGEN_SOC), acc_clr); 163 break; 164 165 case DVFS_FREQ_ACC_SOC: 166 /* Select park source */ 167 apupwr_writel(BIT(BIT_SEL_PARK), acc_clr); 168 apupwr_writel(BIT(BIT_SEL_F26M), acc_clr); 169 /* Enable park cg */ 170 apupwr_writel(BIT(BIT_CGEN_SOC), acc_set); 171 apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_PARK), acc_clr); 172 /* Select park path */ 173 apupwr_writel(BIT(BIT_SEL_APU), acc_clr); 174 /* clear apu div 2 */ 175 apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr); 176 break; 177 178 case DVFS_FREQ_ACC_26M: 179 case DVFS_FREQ_NOT_SUPPORT: 180 default: 181 /* Select park source */ 182 apupwr_writel(BIT(BIT_SEL_F26M), acc_set); 183 apupwr_writel(BIT(BIT_SEL_PARK), acc_clr); 184 /* Enable park cg */ 185 apupwr_writel(BIT(BIT_CGEN_F26M), acc_set); 186 apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_SOC), acc_clr); 187 /* Select park path */ 188 apupwr_writel(BIT(BIT_SEL_APU), acc_clr); 189 /* clear apu div 2 */ 190 apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr); 191 ERROR("[APUPWR] %s wrong ACC clksrc : %d, force assign 26M\n", 192 __func__, freq); 193 break; 194 } 195 196 err: 197 return ret; 198 } 199 200 int32_t apupwr_smc_pll_set_rate(uint32_t freq, bool div2, uint32_t domain) 201 { 202 int32_t ret = 0; 203 uint32_t acc_set0 = 0, acc_set1 = 0; 204 205 if (freq > DVFS_FREQ_MAX) { 206 ERROR("%s wrong freq: %d\n", __func__, freq); 207 ret = -EIO; 208 goto err; 209 } 210 211 /* 212 * Switch to Parking src 213 * 1. Need to switch out all ACCs sharing the same apupll 214 */ 215 switch (domain) { 216 case V_MDLA0: 217 case V_MDLA1: 218 acc_set0 = APU_ACC_CONFG_SET4; 219 acc_set1 = APU_ACC_CONFG_SET5; 220 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, 221 V_MDLA0); 222 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, 223 V_MDLA1); 224 break; 225 case V_VPU0: 226 case V_VPU1: 227 acc_set0 = APU_ACC_CONFG_SET1; 228 acc_set1 = APU_ACC_CONFG_SET2; 229 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, 230 V_VPU0); 231 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, 232 V_VPU1); 233 break; 234 case V_APU_CONN: 235 acc_set0 = APU_ACC_CONFG_SET0; 236 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, 237 V_APU_CONN); 238 break; 239 case V_TOP_IOMMU: 240 acc_set0 = APU_ACC_CONFG_SET7; 241 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING, 242 V_TOP_IOMMU); 243 break; 244 default: 245 ERROR("[APUPWR] %s %d invalid domain (%d)\n", 246 __func__, __LINE__, domain); 247 ret = -EIO; 248 goto err; 249 } 250 251 anpu_pll_set_rate(domain, PLL_MODE, (div2) ? (freq * 2) : freq); 252 253 if (div2) { 254 apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set0); 255 if (acc_set1) { 256 apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set1); 257 } 258 } 259 260 /* 261 * Switch back to APUPLL 262 * Only switch back to APUPLL while CG_APU on 263 * And clksrc is not APUPLL 264 */ 265 switch (domain) { 266 case V_VPU0: 267 case V_VPU1: 268 if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) && 269 !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) { 270 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL, 271 V_VPU0); 272 } 273 if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) && 274 !(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) { 275 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL, 276 V_VPU1); 277 } 278 break; 279 case V_MDLA0: 280 case V_MDLA1: 281 if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) && 282 !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) { 283 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL, 284 V_MDLA0); 285 } 286 if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) && 287 !(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) { 288 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL, 289 V_MDLA1); 290 } 291 break; 292 case V_APU_CONN: 293 case V_TOP_IOMMU: 294 if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) && 295 !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) { 296 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL, 297 domain); 298 } 299 break; 300 default: 301 ERROR("[APUPWR] %s %d invalid domain (%d)\n", 302 __func__, __LINE__, domain); 303 ret = -EIO; 304 break; 305 } 306 INFO("[%s][%d] set domain %d to freq %d\n", 307 __func__, __LINE__, domain, (div2) ? (freq * 2) : freq); 308 309 err: 310 return ret; 311 } 312 313 int32_t apupwr_smc_bulk_pll(bool enable) 314 { 315 int32_t ret = 0; 316 int32_t pll_idx; 317 318 if (enable) { 319 for (pll_idx = APUPLL; pll_idx < APUPLL_MAX; pll_idx++) { 320 ret = apu_pll_enable(pll_idx, enable, false); 321 if (ret != 0) { 322 goto err; 323 } 324 } 325 } else { 326 for (pll_idx = APUPLL2; pll_idx >= APUPLL; pll_idx--) { 327 ret = apu_pll_enable(pll_idx, enable, false); 328 if (ret != 0) { 329 goto err; 330 } 331 } 332 } 333 334 err: 335 return ret; 336 } 337 338 void apupwr_smc_bus_prot_cg_on(void) 339 { 340 apupwr_clrbits(AO_MD32_MNOC_MASK, APU_CSR_DUMMY_0); 341 } 342