openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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