avs.c (16717B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: avs.c 8 * Purpose: AVS (Adaptive Voltage Scaling) commands. 9 * AVS is a power-saving technique of the digital 1.0V supply while maintaining 10 * performance under various process and operating conditions. 11 * Commands in this file are provided for AVS algorithm. Also some helper commands 12 * are also provided for the AVS algorithm verificatiion/validation. 13 * AVS algorithm commands: 14 * avs init : the first command should be invoked to setup the software data 15 * and chip specific information for AVS algorithm. 16 * avs openloop : read the device otp to get the working voltage and set to the 17 * vrm. 18 * avs start :(close-loop) perform the predict algorithm to get the converged 19 * voltage w/ margin and then set the value to external voltage supply. 20 * avs track :(close-loop) perform track algorithm to monitor the ROSC count 21 * then adjust the voltage accordingly. Interval value here is used to 22 * determine to do the track periodically or just one time. 23 * AVS helper commands: 24 * avs vrm : Add default vrm profile. 25 * avs xbmp : Not all the ROSC counts are required for the algorithm 26 * calculation to derive the converged voltage. xbmp specify the ROSCs 27 * which will be excluded from the algorithm. This command is usually used 28 * during the algorithm validation for new chip support. 29 * avs CoreVoltage : Set or get the CoreVoltage which is the main voltage 30 * supply for the chip. 31 * avs margin : Specify the margin value used for the converged method. 32 * This command is usually used during the algorithm validation 33 * for new chip support. 34 * avs vpred : get the predicted voltage according to the specific v1 and v2. 35 * This command is usually used during the algorithm validation. 36 * avs Count : get the ROSC count. 37 * This command is usually used during the algorithm validation. 38 * avs SHow : dump the chip specific avs information. 39 * avs PVTmon : get core voltage (0.1 mV), temperature (mC) using pvtmon. 40 * avs deinit : release avs related software resources. 41 * Requires: 42 */ 43 44 45 #include <appl/diag/system.h> 46 #include <appl/diag/parse.h> 47 #include <shared/bsl.h> 48 49 #ifdef INCLUDE_AVS 50 #include <soc/avs.h> 51 52 char cmd_avs_usage[] = 53 "avs command usages:\n\t" 54 #ifdef COMPILER_STRING_CONST_LIMIT 55 " avs <option> [args...] \n" 56 #else 57 "avs init \n\t" 58 " - initialize the avs software resource \n\t" 59 "avs vrm dev=<dev_name> [mux=<mux_dev_name> mux_value=<enable value>]\n\t" 60 " - specify the default vrm profile.\n\t" 61 " Note : Only support the pmbus compatiable device as default vrm.\n\t" 62 "avs openloop \n\t" 63 " - Set the otp specified voltage to the system." 64 "avs start \n\t" 65 " - start the avs close loop processing \n\t" 66 "avs track [Interval=<usec>] \n\t" 67 " - start to adjust voltage with interval value. default is 1 sec \n\t" 68 " if Interval = 0, avs track will be stopped. \n\t" 69 " if Interval = -1, avs track will be invoked once. \n\t" 70 "avs xbmp Osc=Central|Remote [StartOsc=<osc> [NumOsc=<num>]]" 71 " [Value=<val>]\n\t" 72 " - set/get the Central or Remote Oscillator exclude bitmap \n\t" 73 " for example: \n\t" 74 " avs xbmp o=c ==> show cen_osc_xbmp\n\t" 75 " avs xbmp o=c so=5 no=3 v=1 ==> cen_osc_xbmp[5,6,7]=0x1\n\t" 76 "avs CoreVoltage [Voltage=<voltage>] [StepSize=<step_size>]]\n\t" 77 " - set/get the core voltage in 0.1mV units \n\t" 78 " if step_size is specified, the core voltage will be inc/dec by step_size\n\t" 79 " if step_size = -1, the core voltage will be set directly.\n\t" 80 " if step_size is omitted, the default step size (10mV) will be taken\n\t" 81 " continuously up to the target voltage.\n\t" 82 "avs Margin [High=<hval> Low=<lval>] \n\t" 83 " - set/get margin high and margin low \n\t" 84 "avs RESetOSCillators\n\t" 85 " - Reset all the oscillators.\n\t" 86 "avs Vpred <v1s> <v2s> \n\t" 87 " - compute Vpred(v3) for given v1s, v2s \n\t" 88 "avs Count Osc=Central|Remote\n\t" 89 " - Get the Central or Remote Oscillator count \n\t" 90 "avs SHow \n\t" 91 "avs PVTmon Type=Voltage|Temperature\n\t" 92 " - Read the core voltage (0.1 mV), temperature (mC) using pvtmon\n\t" 93 "avs deinit \n\t" 94 " - release avs related software resource \n" 95 #endif 96 ; 97 #define AVS_ERROR_RETURN(op) \ 98 do { \ 99 int _rv; \ 100 if (SOC_FAILURE((_rv = (op)))) { \ 101 cli_out("Error: %s\n", soc_errmsg(_rv));\ 102 return CMD_FAIL; \ 103 } \ 104 } while (0) 105 106 /* 0.84 V */ 107 #define AVS_ABS_MIN_CVOLT SOC_AVS_UINT(8400) 108 /* 1.10 V */ 109 #define AVS_ABS_MAX_CVOLT SOC_AVS_UINT(11000) 110 111 /* 0.01 V = 10 mV */ 112 #define AVS_DEFAULT_CVOLT_INC_STEP_SIZE SOC_AVS_UINT(100) 113 #define AVS_DEFAULT_CVOLT_DEC_STEP_SIZE SOC_AVS_UINT(100) 114 115 STATIC int 116 _avs_core_voltage_step (int unit, uint32 req_cvolt, uint32 svolt) 117 { 118 uint32 cur_cvolt; 119 uint32 inc_svolt, dec_svolt; 120 121 if (svolt == 0) { 122 inc_svolt = AVS_DEFAULT_CVOLT_INC_STEP_SIZE; 123 dec_svolt = AVS_DEFAULT_CVOLT_DEC_STEP_SIZE; 124 } else { 125 inc_svolt = svolt; 126 dec_svolt = svolt; 127 } 128 SOC_IF_ERROR_RETURN(soc_avs_voltage_get(unit, &cur_cvolt)); 129 if (req_cvolt >= cur_cvolt) { 130 while (req_cvolt >= (cur_cvolt + inc_svolt)) { 131 SOC_IF_ERROR_RETURN( 132 soc_avs_voltage_set(unit, cur_cvolt + inc_svolt)); 133 SOC_IF_ERROR_RETURN( 134 soc_avs_voltage_get(unit, &cur_cvolt)); 135 } 136 } else { /* req_cvolt < cur_cvolt */ 137 while (cur_cvolt >= (req_cvolt + dec_svolt)) { 138 SOC_IF_ERROR_RETURN( 139 soc_avs_voltage_set(unit, cur_cvolt - dec_svolt)); 140 SOC_IF_ERROR_RETURN( 141 soc_avs_voltage_get(unit, &cur_cvolt)); 142 } 143 } 144 if (req_cvolt != cur_cvolt) { 145 SOC_IF_ERROR_RETURN( 146 soc_avs_voltage_set(unit, req_cvolt)); 147 } 148 149 return (SOC_E_NONE); 150 } 151 const char *diag_parse_osc_type[] = { 152 "Central", 153 "Remote", 154 NULL 155 }; 156 const char *diag_parse_pvt_type[] = { 157 "Voltage", 158 "Temperature", 159 NULL 160 }; 161 162 cmd_result_t 163 cmd_avs(int unit, args_t *a) 164 { 165 char *subcmd; 166 parse_table_t pt; 167 if (!sh_check_attached(ARG_CMD(a), unit)) { 168 return CMD_FAIL; 169 } 170 if ((subcmd = ARG_GET(a)) == NULL) { 171 return CMD_USAGE; 172 } 173 if (sal_strcasecmp(subcmd, "init") == 0) { 174 AVS_ERROR_RETURN( 175 soc_avs_init(unit)); 176 return CMD_OK; 177 } 178 if (sal_strcasecmp(subcmd, "deinit") == 0) { 179 AVS_ERROR_RETURN( 180 soc_avs_deinit(unit)); 181 return CMD_OK; 182 } 183 if (sal_strcasecmp(subcmd, "start") == 0) { 184 AVS_ERROR_RETURN( 185 soc_avs_start(unit)); 186 return CMD_OK; 187 } 188 if (sal_strcasecmp(subcmd, "track") == 0) { 189 int usec = 1000000; 190 parse_table_init(unit, &pt); 191 parse_table_add(&pt, "Interval", PQ_DFL | PQ_INT, 192 (void *)( 0), &usec, NULL); 193 if (parse_arg_eq(a, &pt) <= 0) { 194 cli_out("%s: Error: Unknown option: %s\n", ARG_CMD(a), ARG_CUR(a)); 195 parse_arg_eq_done(&pt); 196 return(CMD_FAIL); 197 } 198 parse_arg_eq_done(&pt); 199 if (usec == -1) { 200 AVS_ERROR_RETURN( 201 soc_avs_track(unit)); 202 cli_out("soc_avs_track once\n"); 203 } else if (usec < 0) { 204 cli_out("Error: Invalid interval: %d\n", usec); 205 return CMD_USAGE; 206 } else if (usec == 0) { 207 AVS_ERROR_RETURN( 208 soc_avs_track_stop(unit)); 209 cli_out("soc_avs_track stopped !\n"); 210 } else { 211 AVS_ERROR_RETURN( 212 soc_avs_track_start(unit, usec)); 213 cli_out("soc_avs_track start with interval=%d usec\n",usec); 214 } 215 return CMD_OK; 216 } 217 if (sal_strcasecmp(subcmd, "xbmp") == 0) { 218 int osc_type, start_osc, num_osc, value; 219 if ((ARG_CNT(a)) == 0) { 220 AVS_ERROR_RETURN( 221 soc_avs_xbmp_dump(unit, SOC_AVS_ROSC_TYPE_CENTRAL)); 222 AVS_ERROR_RETURN( 223 soc_avs_xbmp_dump(unit, SOC_AVS_ROSC_TYPE_REMOTE)); 224 return CMD_OK; 225 } 226 osc_type = -1; 227 start_osc = -1; 228 num_osc = 1; 229 value = 1; 230 parse_table_init(unit, &pt); 231 parse_table_add(&pt, "Osc", PQ_MULTI | PQ_DFL, 0, &osc_type, 232 diag_parse_osc_type); 233 parse_table_add(&pt, "StartOsc", PQ_INT | PQ_DFL, 0, &start_osc, NULL); 234 parse_table_add(&pt, "NumOsc", PQ_INT | PQ_DFL, 0, &num_osc, NULL); 235 parse_table_add(&pt, "Value", PQ_INT | PQ_DFL, 0, &value, NULL); 236 237 if (parse_arg_eq(a, &pt) <= 0) { 238 cli_out("Error: invalid option %s\n", ARG_CUR(a)); 239 parse_arg_eq_done(&pt); 240 return CMD_USAGE; 241 } 242 if (osc_type == -1) { 243 parse_arg_eq_done(&pt); 244 return CMD_USAGE; 245 } 246 parse_arg_eq_done(&pt); 247 248 if (start_osc == -1) { 249 AVS_ERROR_RETURN( 250 soc_avs_xbmp_dump(unit, osc_type)); 251 return CMD_OK; 252 } 253 AVS_ERROR_RETURN( 254 soc_avs_xbmp_set(unit, osc_type, start_osc, num_osc, value)); 255 return CMD_OK; 256 } 257 if (parse_cmp("CoreVoltage", subcmd, 0)) { 258 uint32 voltage = 0; 259 int step = 0; 260 if ((ARG_CNT(a)) == 0) { 261 AVS_ERROR_RETURN( 262 soc_avs_voltage_get(unit, &voltage)); 263 cli_out("avs corevoltage get (in 0.1mV): %d\n", 264 voltage); 265 return CMD_OK; 266 } 267 parse_table_init(unit, &pt); 268 parse_table_add(&pt, "Voltage", PQ_INT | PQ_DFL, 0, &voltage, NULL); 269 parse_table_add(&pt, "StepSize", PQ_INT | PQ_DFL, 0, &step, NULL); 270 271 if (parse_arg_eq(a, &pt) <= 0) { 272 cli_out("Error: invalid option %s\n", ARG_CUR(a)); 273 parse_arg_eq_done(&pt); 274 return CMD_USAGE; 275 } 276 parse_arg_eq_done(&pt); 277 278 if (voltage == 0) { 279 cli_out("Error: voltage is not specified %s\n", ARG_CUR(a)); 280 return CMD_USAGE; 281 } 282 if (step == -1) { 283 AVS_ERROR_RETURN( 284 soc_avs_voltage_set(unit, voltage)); 285 cli_out("avs corevoltage set (in 0.1mV): %d\n", 286 voltage); 287 } else { 288 AVS_ERROR_RETURN( 289 _avs_core_voltage_step(unit, voltage, step)); 290 cli_out("avs corevoltage set (in 0.1mV): %d with step %d\n", 291 voltage, (step) ? step : AVS_DEFAULT_CVOLT_INC_STEP_SIZE); 292 } 293 return CMD_OK; 294 } 295 if (parse_cmp("Margin", subcmd, 0)) { 296 soc_avs_debug_margin_t avs_debug_margin; 297 if ((ARG_CNT(a)) == 0) { 298 AVS_ERROR_RETURN( 299 soc_avs_debug_margin_get(unit, &avs_debug_margin)); 300 cli_out("avs custom margin: high=%d low=%d\n", 301 avs_debug_margin.vmargin_high, 302 avs_debug_margin.vmargin_low); 303 return CMD_OK; 304 } 305 306 parse_table_init(unit, &pt); 307 parse_table_add(&pt, "High", PQ_INT, 0, 308 &avs_debug_margin.vmargin_high, NULL); 309 parse_table_add(&pt, "Low", PQ_INT, 0, 310 &avs_debug_margin.vmargin_low, NULL); 311 312 if (parse_arg_eq(a, &pt) <= 0) { 313 cli_out("Error: invalid option %s\n", ARG_CUR(a)); 314 parse_arg_eq_done(&pt); 315 return CMD_USAGE; 316 } 317 parse_arg_eq_done(&pt); 318 319 AVS_ERROR_RETURN( 320 soc_avs_debug_margin_set(unit, &avs_debug_margin)); 321 return CMD_OK; 322 } 323 if (parse_cmp("Vpred", subcmd, 0)) { 324 uint32 v1, v2, vpred, vlow, vhigh; 325 char *cmd_arg; 326 if ((cmd_arg = ARG_GET(a)) == NULL){ 327 return CMD_USAGE; 328 } else { 329 v1 = parse_integer(cmd_arg); 330 } 331 if ((cmd_arg = ARG_GET(a)) == NULL){ 332 return CMD_USAGE; 333 } else { 334 v2 = parse_integer(cmd_arg); 335 } 336 AVS_ERROR_RETURN( 337 _soc_avs_predict_vpred(unit, -1, v1, v2, &vpred, &vlow, &vhigh)); 338 cli_out("avs predict(in 0.1mV): v1=%d v2=%d vpred=%d\n", 339 v1, v2, vpred); 340 return CMD_OK; 341 } 342 if (parse_cmp("Count", subcmd, 0)) { 343 int osc_type = -1; 344 if ((ARG_CNT(a)) == 0) { 345 AVS_ERROR_RETURN( 346 soc_avs_osc_count_dump(unit, SOC_AVS_ROSC_TYPE_ALL)); 347 return CMD_OK; 348 } 349 parse_table_init(unit, &pt); 350 parse_table_add(&pt, "Osc", PQ_MULTI | PQ_DFL, 0, &osc_type, 351 diag_parse_osc_type); 352 353 if (parse_arg_eq(a, &pt) <= 0) { 354 cli_out("Error: invalid option %s\n", ARG_CUR(a)); 355 parse_arg_eq_done(&pt); 356 return CMD_USAGE; 357 } 358 if (osc_type == -1) { 359 parse_arg_eq_done(&pt); 360 return CMD_USAGE; 361 } 362 parse_arg_eq_done(&pt); 363 364 AVS_ERROR_RETURN( 365 soc_avs_osc_count_dump(unit, osc_type)); 366 return CMD_OK; 367 } 368 if (parse_cmp("SHow", subcmd, 0)) { 369 AVS_ERROR_RETURN( 370 soc_avs_info_dump(unit)); 371 return CMD_OK; 372 } 373 if (parse_cmp("PVTmon", subcmd, 0)) { 374 int pvt_type = -1; 375 int32 temperature = 0; 376 uint32 voltage = 0; 377 if ((ARG_CNT(a)) == 0) { 378 AVS_ERROR_RETURN( 379 soc_avs_pvtmon_voltage_get(unit, &voltage)); 380 cli_out("avs pvtmon voltage get (in 0.1 mV): %d\n", voltage); 381 AVS_ERROR_RETURN( 382 soc_avs_temperature_get(unit, &temperature)); 383 cli_out("avs temperature get (in mC): %d\n", temperature); 384 return CMD_OK; 385 } 386 parse_table_init(unit, &pt); 387 parse_table_add(&pt, "Type", PQ_MULTI | PQ_DFL, 0, &pvt_type, 388 diag_parse_pvt_type); 389 if (parse_arg_eq(a, &pt) <= 0) { 390 cli_out("Error: invalid option %s\n", ARG_CUR(a)); 391 parse_arg_eq_done(&pt); 392 return CMD_USAGE; 393 } 394 if (pvt_type == -1) { 395 parse_arg_eq_done(&pt); 396 return CMD_USAGE; 397 } 398 parse_arg_eq_done(&pt); 399 if (pvt_type == 0) { 400 AVS_ERROR_RETURN( 401 soc_avs_pvtmon_voltage_get(unit, &voltage)); 402 cli_out("avs pvtmon voltage get (in 0.1 mV): %d\n", voltage); 403 return CMD_OK; 404 } 405 if (pvt_type == 1) { 406 AVS_ERROR_RETURN( 407 soc_avs_temperature_get(unit, &temperature)); 408 cli_out("avs temperature get (in mC): %d\n", temperature); 409 return CMD_OK; 410 } 411 return CMD_USAGE; 412 } 413 if (parse_cmp("RESetOSCillators", subcmd, 0)) { 414 AVS_ERROR_RETURN( 415 _soc_avs_initialize_oscs(unit)); 416 return CMD_OK; 417 } 418 if (sal_strcasecmp(subcmd, "openloop") == 0) { 419 AVS_ERROR_RETURN(soc_avs_openloop_main(unit)); 420 return CMD_OK; 421 } 422 if (sal_strcasecmp(subcmd, "vrm") == 0) { 423 soc_avs_vrm_profile_t vrm_profile; 424 char *mux_name = NULL, *dev_name = NULL; 425 int8 mux_value; 426 427 parse_table_init(unit, &pt); 428 parse_table_add(&pt, "mux", PQ_DFL|PQ_STRING, NULL, 429 &mux_name, NULL); 430 parse_table_add(&pt, "mux_value", PQ_INT8, 0, 431 &mux_value, NULL); 432 parse_table_add(&pt, "dev", PQ_DFL|PQ_STRING, NULL, 433 &dev_name, NULL); 434 if (parse_arg_eq(a, &pt) <= 0) { 435 cli_out("Error: invalid option %s\n", ARG_CUR(a)); 436 parse_arg_eq_done(&pt); 437 return CMD_USAGE; 438 } 439 440 sal_memset(&vrm_profile, 0, sizeof(soc_avs_vrm_profile_t)); 441 if (mux_name) { 442 sal_strncpy(vrm_profile.mux_name, mux_name, 443 sizeof(vrm_profile.mux_name) - 1); 444 } 445 if (dev_name) { 446 sal_strncpy(vrm_profile.vrm_name, dev_name, 447 sizeof(vrm_profile.vrm_name) - 1); 448 } 449 vrm_profile.mux_enable_value = (uint8)mux_value; 450 parse_arg_eq_done(&pt); 451 AVS_ERROR_RETURN(soc_avs_vrm_profile_add(unit, &vrm_profile)); 452 return CMD_OK; 453 } 454 return CMD_USAGE; 455 } 456 457 #else /* INCLUDE_AVS */ 458 459 int _diag_avs_c_not_empty; 460 461 #endif /* INCLUDE_AVS */