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