1 /* 2 * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch.h> 8 #include <arch_helpers.h> 9 #include <common/debug.h> 10 #include <denver.h> 11 #include <errno.h> 12 #include <lib/mmio.h> 13 #include <mce_private.h> 14 #include <platform_def.h> 15 #include <t194_nvg.h> 16 #include <tegra_private.h> 17 18 extern void nvg_set_request_data(uint64_t req, uint64_t data); 19 extern void nvg_set_request(uint64_t req); 20 extern uint64_t nvg_get_result(void); 21 22 /* 23 * Reports the major and minor version of this interface. 24 * 25 * NVGDATA[0:31]: SW(R) Minor Version 26 * NVGDATA[32:63]: SW(R) Major Version 27 */ 28 uint64_t nvg_get_version(void) 29 { 30 nvg_set_request(TEGRA_NVG_CHANNEL_VERSION); 31 32 return (uint64_t)nvg_get_result(); 33 } 34 35 /* 36 * Enable the perf per watt mode. 37 * 38 * NVGDATA[0]: SW(RW), 1 = enable perf per watt mode 39 */ 40 int32_t nvg_enable_power_perf_mode(void) 41 { 42 nvg_set_request_data(TEGRA_NVG_CHANNEL_POWER_PERF, 1U); 43 44 return 0; 45 } 46 47 /* 48 * Disable the perf per watt mode. 49 * 50 * NVGDATA[0]: SW(RW), 0 = disable perf per watt mode 51 */ 52 int32_t nvg_disable_power_perf_mode(void) 53 { 54 nvg_set_request_data(TEGRA_NVG_CHANNEL_POWER_PERF, 0U); 55 56 return 0; 57 } 58 59 /* 60 * Enable the battery saver mode. 61 * 62 * NVGDATA[2]: SW(RW), 1 = enable battery saver mode 63 */ 64 int32_t nvg_enable_power_saver_modes(void) 65 { 66 nvg_set_request_data(TEGRA_NVG_CHANNEL_POWER_MODES, 1U); 67 68 return 0; 69 } 70 71 /* 72 * Disable the battery saver mode. 73 * 74 * NVGDATA[2]: SW(RW), 0 = disable battery saver mode 75 */ 76 int32_t nvg_disable_power_saver_modes(void) 77 { 78 nvg_set_request_data(TEGRA_NVG_CHANNEL_POWER_MODES, 0U); 79 80 return 0; 81 } 82 83 /* 84 * Set the expected wake time in TSC ticks for the next low-power state the 85 * core enters. 86 * 87 * NVGDATA[0:31]: SW(RW), WAKE_TIME 88 */ 89 void nvg_set_wake_time(uint32_t wake_time) 90 { 91 /* time (TSC ticks) until the core is expected to get a wake event */ 92 nvg_set_request_data(TEGRA_NVG_CHANNEL_WAKE_TIME, (uint64_t)wake_time); 93 } 94 95 /* 96 * This request allows updating of CLUSTER_CSTATE, CCPLEX_CSTATE and 97 * SYSTEM_CSTATE values. 98 * 99 * NVGDATA[0:2]: SW(RW), CLUSTER_CSTATE 100 * NVGDATA[7]: SW(W), update cluster flag 101 * NVGDATA[8:9]: SW(RW), CG_CSTATE 102 * NVGDATA[15]: SW(W), update ccplex flag 103 * NVGDATA[16:19]: SW(RW), SYSTEM_CSTATE 104 * NVGDATA[23]: SW(W), update system flag 105 * NVGDATA[31]: SW(W), update wake mask flag 106 * NVGDATA[32:63]: SW(RW), WAKE_MASK 107 */ 108 void nvg_update_cstate_info(uint32_t cluster, uint32_t ccplex, 109 uint32_t system, uint32_t wake_mask, uint8_t update_wake_mask) 110 { 111 uint64_t val = 0; 112 113 /* update CLUSTER_CSTATE? */ 114 if (cluster != 0U) { 115 val |= ((uint64_t)cluster & CLUSTER_CSTATE_MASK) | 116 CLUSTER_CSTATE_UPDATE_BIT; 117 } 118 119 /* update CCPLEX_CSTATE? */ 120 if (ccplex != 0U) { 121 val |= (((uint64_t)ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) | 122 CCPLEX_CSTATE_UPDATE_BIT; 123 } 124 125 /* update SYSTEM_CSTATE? */ 126 if (system != 0U) { 127 val |= (((uint64_t)system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) | 128 SYSTEM_CSTATE_UPDATE_BIT; 129 } 130 131 /* update wake mask value? */ 132 if (update_wake_mask != 0U) { 133 val |= CSTATE_WAKE_MASK_UPDATE_BIT; 134 } 135 136 /* set the wake mask */ 137 val |= ((uint64_t)wake_mask & CSTATE_WAKE_MASK_CLEAR) << CSTATE_WAKE_MASK_SHIFT; 138 139 /* set the updated cstate info */ 140 nvg_set_request_data(TEGRA_NVG_CHANNEL_CSTATE_INFO, val); 141 } 142 143 /* 144 * Indices gives MTS the crossover point in TSC ticks for when it becomes 145 * no longer viable to enter the named state 146 * 147 * Type 0 : NVGDATA[0:31]: C6 Lower bound 148 * Type 1 : NVGDATA[0:31]: CC6 Lower bound 149 * Type 2 : NVGDATA[0:31]: CG7 Lower bound 150 */ 151 int32_t nvg_update_crossover_time(uint32_t type, uint32_t time) 152 { 153 int32_t ret = 0; 154 155 switch (type) { 156 case TEGRA_NVG_CROSSOVER_C6: 157 nvg_set_request_data(TEGRA_NVG_CHANNEL_CROSSOVER_C6_LOWER_BOUND, 158 (uint64_t)time); 159 break; 160 161 case TEGRA_NVG_CROSSOVER_CC6: 162 nvg_set_request_data(TEGRA_NVG_CHANNEL_CROSSOVER_CC6_LOWER_BOUND, 163 (uint64_t)time); 164 break; 165 166 case TEGRA_NVG_CROSSOVER_CG7: 167 nvg_set_request_data(TEGRA_NVG_CHANNEL_CROSSOVER_CG7_LOWER_BOUND, 168 (uint64_t)time); 169 break; 170 171 default: 172 ERROR("%s: unknown crossover type (%d)\n", __func__, type); 173 ret = EINVAL; 174 break; 175 } 176 177 return ret; 178 } 179 180 /* 181 * These NVG calls allow ARM SW to access CSTATE statistical information 182 * 183 * NVGDATA[0:3]: SW(RW) Core/cluster/cg id 184 * NVGDATA[16:31]: SW(RW) Stat id 185 */ 186 int32_t nvg_set_cstate_stat_query_value(uint64_t data) 187 { 188 int32_t ret = 0; 189 190 /* sanity check stat id and core id*/ 191 if ((data >> MCE_STAT_ID_SHIFT) > 192 (uint64_t)NVG_STAT_QUERY_C7_RESIDENCY_SUM) { 193 ERROR("%s: unknown stat id (%d)\n", __func__, 194 (uint32_t)(data >> MCE_STAT_ID_SHIFT)); 195 ret = EINVAL; 196 } else if ((data & MCE_CORE_ID_MASK) > (uint64_t)PLATFORM_CORE_COUNT) { 197 ERROR("%s: unknown core id (%d)\n", __func__, 198 (uint32_t)(data & MCE_CORE_ID_MASK)); 199 ret = EINVAL; 200 } else { 201 nvg_set_request_data(TEGRA_NVG_CHANNEL_CSTATE_STAT_QUERY_REQUEST, data); 202 } 203 204 return ret; 205 } 206 207 /* 208 * The read-only value associated with the CSTATE_STAT_QUERY_REQUEST 209 * 210 * NVGDATA[0:63]: SW(R) Stat count 211 */ 212 uint64_t nvg_get_cstate_stat_query_value(void) 213 { 214 nvg_set_request(TEGRA_NVG_CHANNEL_CSTATE_STAT_QUERY_VALUE); 215 216 return (uint64_t)nvg_get_result(); 217 } 218 219 /* 220 * Return a non-zero value if the CCPLEX is able to enter SC7 221 * 222 * NVGDATA[0]: SW(R), Is allowed result 223 */ 224 int32_t nvg_is_sc7_allowed(void) 225 { 226 /* issue command to check if SC7 is allowed */ 227 nvg_set_request(TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED); 228 229 /* 1 = SC7 allowed, 0 = SC7 not allowed */ 230 return (int32_t)nvg_get_result(); 231 } 232 233 /* 234 * Wake an offlined logical core. Note that a core is offlined by entering 235 * a C-state where the WAKE_MASK is all 0. 236 * 237 * NVGDATA[0:3]: SW(W) logical core to online 238 */ 239 int32_t nvg_online_core(uint32_t core) 240 { 241 int32_t ret = 0; 242 243 /* sanity check the core ID value */ 244 if (core > (uint32_t)PLATFORM_CORE_COUNT) { 245 ERROR("%s: unknown core id (%d)\n", __func__, core); 246 ret = EINVAL; 247 } else { 248 /* get a core online */ 249 nvg_set_request_data(TEGRA_NVG_CHANNEL_ONLINE_CORE, 250 (uint64_t)core & MCE_CORE_ID_MASK); 251 } 252 253 return ret; 254 } 255 256 /* 257 * Enables and controls the voltage/frequency hint for CC3. CC3 is disabled 258 * by default. 259 * 260 * NVGDATA[7:0] SW(RW) frequency request 261 * NVGDATA[31:31] SW(RW) enable bit 262 */ 263 int32_t nvg_cc3_ctrl(uint32_t freq, uint8_t enable) 264 { 265 uint64_t val = 0; 266 267 /* 268 * If the enable bit is cleared, Auto-CC3 will be disabled by setting 269 * the SW visible frequency request registers for all non 270 * floorswept cores valid independent of StandbyWFI and disabling 271 * the IDLE frequency request register. If set, Auto-CC3 272 * will be enabled by setting the ARM SW visible frequency 273 * request registers for all non floorswept cores to be enabled by 274 * StandbyWFI or the equivalent signal, and always keeping the IDLE 275 * frequency request register enabled. 276 */ 277 if (enable != 0U) { 278 val = ((uint64_t)freq & MCE_AUTO_CC3_FREQ_MASK) | MCE_AUTO_CC3_ENABLE_BIT; 279 } 280 nvg_set_request_data(TEGRA_NVG_CHANNEL_CC3_CTRL, val); 281 282 return 0; 283 } 284 285 /* 286 * MC GSC (General Security Carveout) register values are expected to be 287 * changed by TrustZone ARM code after boot. 288 * 289 * NVGDATA[0:15] SW(R) GSC enun 290 */ 291 int32_t nvg_update_ccplex_gsc(uint32_t gsc_idx) 292 { 293 int32_t ret = 0; 294 295 /* sanity check GSC ID */ 296 if (gsc_idx > (uint32_t)TEGRA_NVG_GSC_VPR_IDX) { 297 ERROR("%s: unknown gsc_idx (%d)\n", __func__, gsc_idx); 298 ret = EINVAL; 299 } else { 300 nvg_set_request_data(TEGRA_NVG_CHANNEL_UPDATE_CCPLEX_GSC, 301 (uint64_t)gsc_idx); 302 } 303 304 return ret; 305 } 306 307 /* 308 * Cache clean operation for all CCPLEX caches. 309 * 310 * NVGDATA[0] cache_clean 311 */ 312 int32_t nvg_roc_clean_cache(void) 313 { 314 nvg_set_request_data(TEGRA_NVG_CHANNEL_CCPLEX_CACHE_INVAL, 315 (uint64_t)CACHE_CLEAN_SET); 316 317 return 0; 318 } 319 320 /* 321 * Cache clean and invalidate operation for all CCPLEX caches. 322 * 323 * NVGDATA[1] cache_clean_inval 324 */ 325 int32_t nvg_roc_flush_cache(void) 326 { 327 nvg_set_request_data(TEGRA_NVG_CHANNEL_CCPLEX_CACHE_INVAL, 328 (uint64_t)CACHE_CLEAN_INVAL_SET); 329 330 return 0; 331 } 332 333 /* 334 * Cache clean and invalidate, clear TR-bit operation for all CCPLEX caches. 335 * 336 * NVGDATA[2] cache_clean_inval_tr 337 */ 338 int32_t nvg_roc_clean_cache_trbits(void) 339 { 340 nvg_set_request_data(TEGRA_NVG_CHANNEL_CCPLEX_CACHE_INVAL, 341 (uint64_t)CACHE_CLEAN_INVAL_TR_SET); 342 343 return 0; 344 } 345 346 /* 347 * Set the power state for a core 348 */ 349 int32_t nvg_enter_cstate(uint32_t state, uint32_t wake_time) 350 { 351 int32_t ret = 0; 352 uint64_t val = 0ULL; 353 354 /* check for allowed power state */ 355 if ((state != (uint32_t)TEGRA_NVG_CORE_C0) && 356 (state != (uint32_t)TEGRA_NVG_CORE_C1) && 357 (state != (uint32_t)TEGRA_NVG_CORE_C6) && 358 (state != (uint32_t)TEGRA_NVG_CORE_C7)) 359 { 360 ERROR("%s: unknown cstate (%d)\n", __func__, state); 361 ret = EINVAL; 362 } else { 363 /* time (TSC ticks) until the core is expected to get a wake event */ 364 nvg_set_wake_time(wake_time); 365 366 /* set the core cstate */ 367 val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK; 368 write_actlr_el1(val | (uint64_t)state); 369 } 370 371 return ret; 372 } 373