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_vctl.c (15527B)


      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_ext_vcore_ctl.c
      8  */
      9 
     10 #include <shared/bsl.h>
     11 
     12 #ifdef INCLUDE_AVS
     13 
     14 #define _SOC_AVS_TH_VOLTAGE_CALIBRATE_USE_I2C
     15 
     16 #define _SOC_AVS_TH_VOLTAGE_GET_USE_I2C
     17 /* #define _SOC_AVS_TH_VOLTAGE_GET_USE_PVTMON */
     18 
     19 #define _SOC_AVS_TH_VOLTAGE_SET_USE_I2C
     20 /* #define _SOC_AVS_TH_VOLTAGE_SET_USE_PVTMON - not yet implemented */
     21 
     22 #include <soc/avs.h>
     23 
     24 #if defined(_SOC_AVS_TH_VOLTAGE_CALIBRATE_USE_I2C) || defined(_SOC_AVS_TH_VOLTAGE_GET_USE_I2C) || defined(_SOC_AVS_TH_VOLTAGE_SET_USE_I2C)
     25 #include <soc/i2c.h>
     26 #endif
     27 
     28 
     29 
     30 /*---------------------------------------------------------------------------*/
     31 #if defined(_SOC_AVS_TH_VOLTAGE_CALIBRATE_USE_I2C) || defined(_SOC_AVS_TH_VOLTAGE_GET_USE_I2C) || defined(_SOC_AVS_TH_VOLTAGE_SET_USE_I2C)
     32 typedef
     33 struct th_avs_vconfig_params{
     34     uint8 mux;
     35     char *adc;
     36     int  chan;
     37     char *dac;
     38 } th_avs_vparams_t;
     39 
     40 STATIC char *_soc_th_avs_board_vctl_sel;
     41 
     42 #define MUX_0 0
     43 #define MUX_2 2
     44 th_avs_vparams_t
     45 th_adp4000_vs_config = {1 << MUX_0, I2C_ADC_0, I2C_ADC_CH0, "pwctrl2"};
     46 
     47 th_avs_vparams_t
     48 th_ltc388x_vs_config = {1 << MUX_2, I2C_LTC3882_55, I2C_BOTH_CH, I2C_LTC3882_55};
     49 #endif
     50 
     51 #if defined(_SOC_AVS_TH_VOLTAGE_CALIBRATE_USE_I2C) || defined(_SOC_AVS_TH_VOLTAGE_SET_USE_I2C)
     52 static dac_calibrate_t
     53 th_adp4000_dac_params = {0,"Core",-1,1,0,0,ADP4000_MIN_DACVAL,ADP4000_MAX_DACVAL-0x3,ADP4000_MID_DACVAL,1};
     54 static dac_calibrate_t
     55 th_ltc388x_dac_params = {0,"Core",-1,1,0,0,LTC388x_1_5V_DACVAL,LTC388x_0_6V_DACVAL,LTC388x_1V_DACVAL,1};
     56 #endif
     57 
     58 #if defined(_SOC_AVS_TH_VOLTAGE_CALIBRATE_USE_I2C)
     59 STATIC soc_error_t
     60 _soc_th_i2c_adp4000_voltage_calibrate(int unit)
     61 {
     62     int adc, dac, rv, mux;
     63     i2c_adc_t  adc_data;
     64 #ifdef COMPILER_HAS_DOUBLE
     65     double volts;
     66 #else
     67     int volts;
     68 #endif
     69 
     70     /* Going to set a voltage (need DAC), and the DAC is MUXed */
     71     /* Open MUX (lpt0) device */
     72     if ((mux = soc_i2c_devopen(unit, I2C_MUX_3, 0, 0)) < 0) {
     73         LOG_ERROR(BSL_LS_SOC_AVS,
     74             (BSL_META_U(unit,
     75                         "Could not open %s for mux selection:%s\n"),
     76                         I2C_MUX_3, soc_errmsg(mux)));
     77         return SOC_E_FAIL;
     78     }
     79 
     80     /* Set mux value so we can see the device when we try to open it */
     81     if((rv = soc_i2c_device(unit, mux)->driver->
     82                 write(unit, mux, 0, &th_adp4000_vs_config.mux, 1)) < 0) {
     83         LOG_ERROR(BSL_LS_SOC_AVS,
     84             (BSL_META_U(unit,
     85                         "Error: write of lpt byte failed:%s\n"),
     86                         soc_errmsg(rv)));
     87         return SOC_E_FAIL;
     88     }
     89 
     90     /* Open ADC device */
     91     if((adc = soc_i2c_devopen(unit, th_adp4000_vs_config.adc, 0, 0)) < 0) {
     92         LOG_ERROR(BSL_LS_SOC_AVS,
     93             (BSL_META_U(unit,
     94                         "Could not open %s:%s\n"),
     95                         th_adp4000_vs_config.adc, soc_errmsg(adc)));
     96         return SOC_E_FAIL;
     97     }
     98 
     99     /* Open the correct DAC */
    100     if ( (dac = soc_i2c_devopen(unit, th_adp4000_vs_config.dac, 0, 0)) < 0) {
    101         LOG_ERROR(BSL_LS_SOC_AVS,
    102             (BSL_META_U(unit,
    103                         "Could not open %s:%s\n"),
    104                         th_adp4000_vs_config.dac, soc_errmsg(dac)));
    105         return SOC_E_FAIL;
    106     }
    107 
    108     /* Set DAC calibration table */
    109     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    110                 I2C_DAC_IOC_SET_CALTAB, (void*)&th_adp4000_dac_params, 0) < 0)) {
    111         LOG_ERROR(BSL_LS_SOC_AVS,
    112             (BSL_META_U(unit,
    113                         "Error: failed to set DAC calibration table.\n")));
    114         return SOC_E_FAIL;
    115     }
    116 
    117     /* Set the DAC to the (digital) value which generates the minimum analog
    118        voltage at the ADC. */
    119     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    120                 I2C_DAC_IOC_SETDAC_MIN, &volts, 0) < 0)) {
    121         LOG_ERROR(BSL_LS_SOC_AVS,
    122             (BSL_META_U(unit,
    123                         "Error: failed to set min DAC Vout.\n")));
    124         return SOC_E_FAIL;
    125     }
    126 
    127     /* Read the resultant (minimum) voltage at the ADC. */
    128     if((rv = soc_i2c_device(unit, adc)->driver->ioctl(unit, adc,
    129                 I2C_ADC_QUERY_CHANNEL,&adc_data, th_adp4000_vs_config.chan)) < 0) {
    130         LOG_ERROR(BSL_LS_SOC_AVS,
    131             (BSL_META_U(unit,
    132                         "Error: failed to read A/D min voltage.\n")));
    133         return SOC_E_FAIL;
    134     }
    135 
    136     volts = adc_data.val;
    137 
    138     /* Update DAC calibration table with this minimum voltage. */
    139     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    140                 I2C_DAC_IOC_CALIBRATE_MIN, &volts, 0) < 0)) {
    141         LOG_ERROR(BSL_LS_SOC_AVS,
    142             (BSL_META_U(unit,
    143                         "Error: failed to update min DAC Vout.\n")));
    144         return SOC_E_FAIL;
    145     }
    146 
    147     /* Set the DAC to the (digital) value which generates the maximum analog
    148        voltage at the ADC. */
    149     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    150                 I2C_DAC_IOC_SETDAC_MAX, &volts, 0) < 0)) {
    151         LOG_ERROR(BSL_LS_SOC_AVS,
    152             (BSL_META_U(unit,
    153                         "Error: failed to set max DAC Vout.\n")));
    154         return SOC_E_FAIL;
    155     }
    156 
    157     /* Read the resultant (maximum) voltage at the ADC. */
    158     if((rv = soc_i2c_device(unit, adc)->driver->ioctl(unit, adc,
    159                 I2C_ADC_QUERY_CHANNEL, &adc_data, th_adp4000_vs_config.chan)) < 0) {
    160         LOG_ERROR(BSL_LS_SOC_AVS,
    161             (BSL_META_U(unit,
    162                         "Error: failed to read A/D max voltage.\n")));
    163         return SOC_E_FAIL;
    164     }
    165 
    166     volts = adc_data.val;
    167 
    168     /* Update DAC calibration table with this maximum voltage. */
    169     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    170                 I2C_DAC_IOC_CALIBRATE_MAX, &volts, 0) < 0)) {
    171         LOG_ERROR(BSL_LS_SOC_AVS,
    172             (BSL_META_U(unit,
    173                         "Error: failed to update max DAC Vout.\n")));
    174         return SOC_E_FAIL;
    175     }
    176 
    177     /* Very important, set the DAC back to nominal */
    178     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    179                 I2C_DAC_IOC_SETDAC_MID, &volts, 0) < 0)) {
    180         LOG_ERROR(BSL_LS_SOC_AVS,
    181             (BSL_META_U(unit,
    182                         "Error: resetting of DAC to nominal value failed:%s\n"),
    183                         soc_errmsg(rv)));
    184         return SOC_E_FAIL;
    185     }
    186 
    187     /* update the calibration table with the analog voltage step per DAC
    188        digital step. */
    189     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    190                 I2C_DAC_IOC_CALIBRATE_STEP, &volts, 0) < 0)) {
    191         LOG_ERROR(BSL_LS_SOC_AVS,
    192             (BSL_META_U(unit,
    193                         "Error: failed to calibrate DAC.\n")));
    194         return SOC_E_FAIL;
    195     }
    196 
    197     return SOC_E_NONE;
    198 }
    199 #endif /* _SOC_AVS_TH_VOLTAGE_CALIBRATE_USE_I2C */
    200 
    201 #if defined(_SOC_AVS_TH_VOLTAGE_GET_USE_I2C)
    202 STATIC soc_error_t
    203 _soc_th_i2c_adp4000_voltage_get(int unit, uint32 *val)
    204 {
    205     int adc, rv;
    206     i2c_adc_t  adc_data;
    207 
    208     /* Open I2C device */
    209     if((adc = soc_i2c_devopen(unit, th_adp4000_vs_config.adc, 0, 0)) < 0) {
    210         LOG_ERROR(BSL_LS_SOC_AVS,
    211             (BSL_META_U(unit,
    212                         "Could not open %s:%s\n"),
    213                         th_adp4000_vs_config.adc, soc_errmsg(adc)));
    214         return SOC_E_FAIL;
    215     }
    216 
    217     /* Read the voltage */
    218     if ((adc < 0) || (adc >= soc_i2c_device_count(unit))) {
    219         return SOC_E_PARAM;
    220     }
    221 
    222     if (soc_i2c_device(unit, adc)->driver == NULL) {
    223         return SOC_E_PARAM;
    224     }
    225 
    226     if((rv = soc_i2c_device(unit, adc)->driver->ioctl(unit, adc,
    227                 I2C_ADC_QUERY_CHANNEL,&adc_data, th_adp4000_vs_config.chan)) < 0) {
    228         LOG_ERROR(BSL_LS_SOC_AVS,
    229             (BSL_META_U(unit,
    230                         "Error: failed to read A/D voltage.\n")));
    231         return SOC_E_FAIL;
    232     }
    233 
    234 #ifdef COMPILER_HAS_DOUBLE
    235     *val = (adc_data.val * 10000);
    236 #else
    237     *val = adc_data.val;
    238 #endif
    239     return SOC_E_NONE;
    240 }
    241 
    242 STATIC soc_error_t
    243 _soc_th_i2c_ltc388x_voltage_get(int unit, uint32 *val)
    244 {
    245     int adc, rv;
    246 #ifdef COMPILER_HAS_DOUBLE
    247     double value=0;
    248 #else
    249     int value=0;
    250 #endif
    251 
    252     /* Open I2C device */
    253     if((adc = soc_i2c_devopen(unit, th_ltc388x_vs_config.adc, 0, 0)) < 0) {
    254         LOG_ERROR(BSL_LS_SOC_AVS,
    255             (BSL_META_U(unit,
    256                         "Could not open %s:%s\n"),
    257                         th_ltc388x_vs_config.adc, soc_errmsg(adc)));
    258         return SOC_E_FAIL;
    259     }
    260 
    261     /* Read the voltage */
    262     if((rv = soc_i2c_device(unit, adc)->driver->ioctl(unit, adc,
    263                 I2C_LTC_IOC_READ_VOUT,&value, th_ltc388x_vs_config.chan)) < 0) {
    264         LOG_ERROR(BSL_LS_SOC_AVS,
    265             (BSL_META_U(unit,
    266                         "Error: failed to read VDD_Core's LTC device.\n")));
    267         return SOC_E_FAIL;
    268     }
    269 
    270 #ifdef COMPILER_HAS_DOUBLE
    271     *val = (value * 10000);
    272 #else
    273     *val = value;
    274 #endif
    275     return SOC_E_NONE;
    276 }
    277 
    278 #endif /*_SOC_AVS_TH_VOLTAGE_GET_USE_I2C */
    279 
    280 #if defined(_SOC_AVS_TH_VOLTAGE_SET_USE_I2C)
    281 STATIC soc_error_t
    282 _soc_th_i2c_adp4000_voltage_set(int unit, uint32 val)
    283 {
    284     int rv, dac, mux;
    285 #ifdef COMPILER_HAS_DOUBLE
    286     double value = (double) val;
    287     value = value/10000;
    288 #else
    289     int value;
    290     /* value = _shr_atof_exp10(val, 2); */
    291     value = val * 100; /* RHS is in 0.1mV units, we want LHS in uV */
    292 #endif
    293 
    294     /* Going to set a voltage (need DAC), and the DAC is MUXed */
    295     /* Open MUX (lpt0) device */
    296     if ((mux = soc_i2c_devopen(unit, I2C_MUX_3, 0, 0)) < 0) {
    297         LOG_ERROR(BSL_LS_SOC_AVS,
    298             (BSL_META_U(unit,
    299                         "Could not open %s for mux selection:%s\n"),
    300                         I2C_MUX_3, soc_errmsg(mux)));
    301         return SOC_E_FAIL;
    302     }
    303 
    304     /* Set mux value so we can see the device when we try to open it */
    305     if((rv = soc_i2c_device(unit, mux)->driver->
    306                 write(unit, mux, 0, &th_adp4000_vs_config.mux, 1)) < 0) {
    307         LOG_ERROR(BSL_LS_SOC_AVS,
    308             (BSL_META_U(unit,
    309                         "Error: write of lpt byte failed:%s\n"),
    310                         soc_errmsg(rv)));
    311         return SOC_E_FAIL;
    312     }
    313 
    314     /* Open the correct DAC */
    315     if ( (dac = soc_i2c_devopen(unit, th_adp4000_vs_config.dac, 0, 0)) < 0) {
    316         LOG_ERROR(BSL_LS_SOC_AVS,
    317             (BSL_META_U(unit,
    318                         "Could not open %s:%s\n"),
    319                         th_adp4000_vs_config.dac, soc_errmsg(dac)));
    320         return SOC_E_FAIL;
    321     }
    322 
    323     /* Set DAC calibration table */
    324     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    325                 I2C_DAC_IOC_SET_CALTAB, (void*)&th_adp4000_dac_params, 0) < 0)) {
    326         LOG_ERROR(BSL_LS_SOC_AVS,
    327             (BSL_META_U(unit,
    328                         "Error: failed to set DAC calibration table.\n")));
    329         return SOC_E_FAIL;
    330     }
    331 
    332     /* Finally, set the actual voltage ... */
    333     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    334                 I2C_DAC_IOC_SET_VOUT, &value, 0) < 0)) {
    335         LOG_ERROR(BSL_LS_SOC_AVS,
    336             (BSL_META_U(unit,
    337                         "Error: failed to set DAC VDD_Core %d\n"), val));
    338         return SOC_E_FAIL;
    339     }
    340 
    341     return SOC_E_NONE;
    342 }
    343 
    344 STATIC soc_error_t
    345 _soc_th_i2c_ltc388x_voltage_set(int unit, uint32 val)
    346 {
    347     int rv, dac, mux, offset = 7;
    348 #ifdef COMPILER_HAS_DOUBLE
    349     double value = (double) val;
    350     value = value/10000;
    351 #else
    352     int value;
    353     /* value = _shr_atof_exp10(val, 2); */
    354     value = val * 100; /* RHS is in 0.1mV units, we want LHS in uV */
    355 #endif
    356 
    357     /* Going to set a voltage (need DAC), and the DAC is MUXed */
    358     /* Open MUX (lpt0) device */
    359     if ((mux = soc_i2c_devopen(unit, I2C_MUX_70, 0, 0)) < 0) {
    360         LOG_ERROR(BSL_LS_SOC_AVS,
    361             (BSL_META_U(unit,
    362                         "Could not open %s for mux selection:%s\n"),
    363                         I2C_MUX_3, soc_errmsg(mux)));
    364         return SOC_E_FAIL;
    365     }
    366 
    367     /* Set mux value so we can see the device when we try to open it */
    368     if((rv = soc_i2c_device(unit, mux)->driver->
    369                 write(unit, mux, 0, &th_ltc388x_vs_config.mux, 1)) < 0) {
    370         LOG_ERROR(BSL_LS_SOC_AVS,
    371             (BSL_META_U(unit,
    372                         "Error: write of lpt byte failed:%s\n"),
    373                         soc_errmsg(rv)));
    374         return SOC_E_FAIL;
    375     }
    376 
    377     /* Open the correct DAC */
    378     if ( (dac = soc_i2c_devopen(unit, th_ltc388x_vs_config.dac, 0, 0)) < 0) {
    379         LOG_ERROR(BSL_LS_SOC_AVS,
    380             (BSL_META_U(unit,
    381                         "Could not open %s:%s\n"),
    382                         th_adp4000_vs_config.dac, soc_errmsg(dac)));
    383         return SOC_E_FAIL;
    384     }
    385 
    386     /* Set DAC calibration table */
    387     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    388                 I2C_DAC_IOC_SET_CALTAB, (void*)&th_ltc388x_dac_params, 0) < 0)) {
    389         LOG_ERROR(BSL_LS_SOC_AVS,
    390             (BSL_META_U(unit,
    391                         "Error: failed to set DAC calibration table.\n")));
    392         return SOC_E_FAIL;
    393     }
    394 
    395     /* Set LTC sense resistor */
    396     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    397                 I2C_LTC_IOC_SET_CONFIG, &offset, 0) < 0)) {
    398         LOG_ERROR(BSL_LS_SOC_AVS,
    399             (BSL_META_U(unit,
    400                     "Error: failed to configure max and min of device .\n")));
    401     }
    402 
    403     /* Finally, set the actual voltage ... */
    404     if ((rv = soc_i2c_device(unit, dac)->driver->ioctl(unit, dac,
    405                 I2C_LTC_IOC_SET_VOUT, &value, 0) < 0)) {
    406         LOG_ERROR(BSL_LS_SOC_AVS,
    407             (BSL_META_U(unit,
    408                     "Error: failed to set VDD_Core's LTC device %d\n"), val));
    409         return SOC_E_FAIL;
    410     }
    411 
    412     return SOC_E_NONE;
    413 }
    414 #endif /*_SOC_AVS_TH_VOLTAGE_SET_USE_I2C */
    415 
    416 
    417 /*---------------------------------------------------------------------------*/
    418 soc_error_t
    419 soc_th_avs_vcore_init(int unit)
    420 {
    421 #if defined(_SOC_AVS_TH_VOLTAGE_CALIBRATE_USE_I2C)
    422     _soc_th_avs_board_vctl_sel = soc_property_get_str(unit,
    423                                                       "th_avs_board_vctl_sel");
    424     if (_soc_th_avs_board_vctl_sel != NULL) {
    425         if ((sal_strcmp(_soc_th_avs_board_vctl_sel, "ADP4000") == 0)) {
    426             return _soc_th_i2c_adp4000_voltage_calibrate(unit);
    427         }
    428     }
    429 #endif
    430 
    431    return SOC_E_NONE;
    432 }
    433 
    434 soc_error_t
    435 soc_th_avs_vcore_deinit(int unit)
    436 {
    437    return SOC_E_NONE;
    438 }
    439 
    440 soc_error_t
    441 soc_th_avs_vcore_get(int unit, uint32 *voltage)
    442 {
    443 #if defined(_SOC_AVS_TH_VOLTAGE_GET_USE_I2C)
    444     if (_soc_th_avs_board_vctl_sel != NULL) {
    445         if ((sal_strcmp(_soc_th_avs_board_vctl_sel, "ADP4000") == 0)) {
    446             return _soc_th_i2c_adp4000_voltage_get(unit, voltage);
    447         } else if ((sal_strcmp(_soc_th_avs_board_vctl_sel, "LTC388X") == 0)) {
    448             return _soc_th_i2c_ltc388x_voltage_get(unit, voltage);
    449         }
    450     }
    451 #endif
    452 
    453 #if defined(_SOC_AVS_TH_VOLTAGE_GET_USE_PVTMON)
    454    return soc_avs_pvtmon_voltage_get(unit, voltage);
    455 #endif
    456 
    457    return SOC_E_UNAVAIL;
    458 }
    459 
    460 soc_error_t
    461 soc_th_avs_vcore_set(int unit, uint32 voltage)
    462 {
    463 #if defined(_SOC_AVS_TH_VOLTAGE_SET_USE_I2C)
    464     if (_soc_th_avs_board_vctl_sel != NULL) {
    465         if ((sal_strcmp(_soc_th_avs_board_vctl_sel, "ADP4000") == 0)) {
    466             return _soc_th_i2c_adp4000_voltage_set(unit, voltage);
    467         } else if ((sal_strcmp(_soc_th_avs_board_vctl_sel, "LTC388X") == 0)) {
    468             return _soc_th_i2c_ltc388x_voltage_set(unit, voltage);
    469         }
    470     }
    471 #endif
    472 
    473    return SOC_E_UNAVAIL;
    474 }
    475 
    476 #endif /* INCLUDE_AVS */