avs.c (132579B)
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: 9 * Requires: 10 */ 11 #include <shared/bsl.h> 12 13 #ifdef INCLUDE_AVS 14 #include <soc/avs.h> 15 #include <soc/i2c.h> 16 17 #define AVS_LEGACY_THRESHOLD (0) /* Adopt the original threshold algorithm*/ 18 19 static soc_avs_control_t *soc_avs_ctrl[SOC_MAX_NUM_DEVICES]; 20 static soc_avs_functions_t *soc_avs_functions[SOC_MAX_NUM_DEVICES] = {NULL}; 21 static soc_avs_vrm_access_t *soc_vrm_access_functions[SOC_MAX_NUM_DEVICES] = {NULL}; 22 static uint32 _soc_last_set_voltage[SOC_MAX_NUM_DEVICES]; 23 24 25 static int _cent_freq_thr[] = { 26 27368.00, /* CENT_FREQ_THRESHOLD_0 */ 27 23800.00, /* CENT_FREQ_THRESHOLD_1 */ 28 19704.00, /* CENT_FREQ_THRESHOLD_2 */ 29 11384.50, /* CENT_FREQ_THRESHOLD_3 */ 30 37474.00, /* CENT_FREQ_THRESHOLD_4 */ 31 32060.50, /* CENT_FREQ_THRESHOLD_5 */ 32 26603.00, /* CENT_FREQ_THRESHOLD_6 */ 33 15597.00, /* CENT_FREQ_THRESHOLD_7 */ 34 105960.00, /* CENT_FREQ_THRESHOLD_8 */ 35 89260.00, /* CENT_FREQ_THRESHOLD_9 */ 36 75010.00, /* CENT_FREQ_THRESHOLD_10*/ 37 42939.00, /* CENT_FREQ_THRESHOLD_11*/ 38 77610.00, /* CENT_FREQ_THRESHOLD_12*/ 39 63710.00, /* CENT_FREQ_THRESHOLD_13*/ 40 52685.00, /* CENT_FREQ_THRESHOLD_14*/ 41 29877.50, /* CENT_FREQ_THRESHOLD_15*/ 42 73335.00, /* CENT_FREQ_THRESHOLD_16*/ 43 58880.00, /* CENT_FREQ_THRESHOLD_17*/ 44 50385.00, /* CENT_FREQ_THRESHOLD_18*/ 45 29011.50, /* CENT_FREQ_THRESHOLD_19*/ 46 43638.00, /* CENT_FREQ_THRESHOLD_20*/ 47 35133.50, /* CENT_FREQ_THRESHOLD_21*/ 48 30099.00, /* CENT_FREQ_THRESHOLD_22*/ 49 17083.00, /* CENT_FREQ_THRESHOLD_23*/ 50 08787.00, /* CENT_FREQ_THRESHOLD_24*/ 51 07574.50, /* CENT_FREQ_THRESHOLD_25*/ 52 06485.00, /* CENT_FREQ_THRESHOLD_26*/ 53 05713.50, /* CENT_FREQ_THRESHOLD_27*/ 54 05986.00, /* CENT_FREQ_THRESHOLD_28*/ 55 07330.50, /* CENT_FREQ_THRESHOLD_29*/ 56 03933.15, /* CENT_FREQ_THRESHOLD_30*/ 57 04304.60, /* CENT_FREQ_THRESHOLD_31*/ 58 01610.80, /* CENT_FREQ_THRESHOLD_32*/ 59 01273.10, /* CENT_FREQ_THRESHOLD_33*/ 60 01610.80, /* CENT_FREQ_THRESHOLD_34*/ 61 01273.10, /* CENT_FREQ_THRESHOLD_35*/ 62 }; 63 64 static int _rmt_freq_thr[] = { 65 23800.00, /* RMT_FREQ_THRESHOLD_GS */ 66 11384.50, /* RMT_FREQ_THRESHOLD_GH */ 67 }; 68 69 70 static int _cent_fth_slope[] = { 71 72120, /* CENT_FREQ_THRESHOLD_SLOPE_0 */ 72 82720, /* CENT_FREQ_THRESHOLD_SLOPE_1 */ 73 71370, /* CENT_FREQ_THRESHOLD_SLOPE_2 */ 74 66720, /* CENT_FREQ_THRESHOLD_SLOPE_3 */ 75 97800, /* CENT_FREQ_THRESHOLD_SLOPE_4 */ 76 109680, /* CENT_FREQ_THRESHOLD_SLOPE_5 */ 77 94700, /* CENT_FREQ_THRESHOLD_SLOPE_6 */ 78 89820, /* CENT_FREQ_THRESHOLD_SLOPE_7 */ 79 277250, /* CENT_FREQ_THRESHOLD_SLOPE_8 */ 80 301000, /* CENT_FREQ_THRESHOLD_SLOPE_9 */ 81 269500, /* CENT_FREQ_THRESHOLD_SLOPE_10*/ 82 245600, /* CENT_FREQ_THRESHOLD_SLOPE_11*/ 83 214250, /* CENT_FREQ_THRESHOLD_SLOPE_12*/ 84 231250, /* CENT_FREQ_THRESHOLD_SLOPE_13*/ 85 201250, /* CENT_FREQ_THRESHOLD_SLOPE_14*/ 86 180750, /* CENT_FREQ_THRESHOLD_SLOPE_15*/ 87 205000, /* CENT_FREQ_THRESHOLD_SLOPE_16*/ 88 216000, /* CENT_FREQ_THRESHOLD_SLOPE_17*/ 89 189500, /* CENT_FREQ_THRESHOLD_SLOPE_18*/ 90 172500, /* CENT_FREQ_THRESHOLD_SLOPE_19*/ 91 122980, /* CENT_FREQ_THRESHOLD_SLOPE_20*/ 92 128750, /* CENT_FREQ_THRESHOLD_SLOPE_21*/ 93 114080, /* CENT_FREQ_THRESHOLD_SLOPE_22*/ 94 101950, /* CENT_FREQ_THRESHOLD_SLOPE_23*/ 95 28500, /* CENT_FREQ_THRESHOLD_SLOPE_24*/ 96 29300, /* CENT_FREQ_THRESHOLD_SLOPE_25*/ 97 34480, /* CENT_FREQ_THRESHOLD_SLOPE_26*/ 98 32700, /* CENT_FREQ_THRESHOLD_SLOPE_27*/ 99 33080, /* CENT_FREQ_THRESHOLD_SLOPE_28*/ 100 33650, /* CENT_FREQ_THRESHOLD_SLOPE_29*/ 101 32190, /* CENT_FREQ_THRESHOLD_SLOPE_30*/ 102 35620, /* CENT_FREQ_THRESHOLD_SLOPE_31*/ 103 7660, /* CENT_FREQ_THRESHOLD_SLOPE_32*/ 104 5490, /* CENT_FREQ_THRESHOLD_SLOPE_33*/ 105 8670, /* CENT_FREQ_THRESHOLD_SLOPE_34*/ 106 7290, /* CENT_FREQ_THRESHOLD_SLOPE_35*/ 107 }; 108 109 int 110 soc_avs_inited(int unit) 111 { 112 if (!SOC_UNIT_VALID(unit)) { 113 return(0); 114 } 115 if (SOC_AVS_CONTROL(unit) == NULL) { 116 return (0); 117 } 118 return ((SOC_AVS_CONTROL(unit)->flags & SOC_AVS_F_INITED) != 0); 119 } 120 121 int 122 soc_avs_track_inited(int unit) 123 { 124 if (!SOC_UNIT_VALID(unit)) { 125 return(0); 126 } 127 if (SOC_AVS_CONTROL(unit) == NULL) { 128 return (0); 129 } 130 return ((SOC_AVS_CONTROL(unit)->flags & SOC_AVS_F_TRACK_INITED) != 0); 131 } 132 #ifdef BCM_SBUSDMA_SUPPORT 133 STATIC sbusdma_desc_handle_t 134 _soc_avs_rosc_handles[SOC_MAX_NUM_DEVICES][SOC_AVS_ROSC_TYPE_ALL]; 135 136 void 137 _soc_sbusdma_avs_cb(int unit, int status, sbusdma_desc_handle_t handle, 138 void *data) 139 { 140 soc_avs_control_t *avs; 141 int i; 142 143 avs = SOC_AVS_CONTROL(unit); 144 145 if (status == SOC_E_NONE) { 146 if(PTR_TO_INT(data) == SOC_AVS_ROSC_TYPE_REMOTE){ 147 avs->rmt_rosc_count_sync = 1; 148 } 149 if(PTR_TO_INT(data) == SOC_AVS_ROSC_TYPE_CENTRAL){ 150 avs->cent_rosc_count_sync= 1; 151 } 152 } else { 153 LOG_ERROR(BSL_LS_SOC_AVS, 154 (BSL_META_U(unit, 155 "avs ROSC count SBUSDMA failed: type %d\n"), 156 PTR_TO_INT(data))); 157 if (status == SOC_E_TIMEOUT) { 158 (void)soc_sbusdma_desc_delete(unit, handle); 159 for (i = 0; i < SOC_AVS_ROSC_TYPE_ALL; i++) { 160 if (_soc_avs_rosc_handles[unit][i] == handle) { 161 _soc_avs_rosc_handles[unit][i] = 0; 162 break; 163 } 164 } 165 } 166 } 167 } 168 169 int 170 _soc_avs_sbusdma_run(int unit, int type) 171 { 172 int ret=SOC_E_NONE; 173 sal_usecs_t dma_timeout = 1000000; 174 int timer_started = 0; 175 soc_timeout_t to; 176 177 do{ 178 ret = soc_sbusdma_desc_run(unit, _soc_avs_rosc_handles[unit][type]); 179 if ((ret == SOC_E_BUSY) || (ret == SOC_E_INIT)) { 180 if (ret == SOC_E_INIT) { 181 break; 182 } 183 /* timeout if sbus dma has been busy for too long. */ 184 if (!timer_started) { 185 soc_timeout_init(&to, 2 * dma_timeout, 0); 186 timer_started = 1; 187 } 188 if (soc_timeout_check(&to)) { 189 LOG_WARN(BSL_LS_SOC_AVS, 190 (BSL_META_U(unit, 191 "sbusdma desc run operation timeout\n"))); 192 break; 193 } 194 sal_usleep(10); 195 } 196 } while ((ret == SOC_E_BUSY) || (ret == SOC_E_INIT)); 197 198 return ret; 199 } 200 201 int 202 soc_avs_sbusdma_desc_setup(int unit) 203 { 204 soc_sbusdma_desc_ctrl_t ctrl; 205 soc_sbusdma_desc_cfg_t cfg; 206 uint32 *buff; 207 int alloc_size; 208 uint8 cent_acc_type, rmt_acc_type; 209 int cent_blkoff, rmt_blkoff; 210 soc_reg_t cent_reg, rmt_reg; 211 uint32 cent_addr, rmt_addr; 212 soc_avs_control_t *avs; 213 soc_avs_info_t *avs_info; 214 215 avs = SOC_AVS_CONTROL(unit); 216 avs_info = SOC_AVS_INFO(unit); 217 218 /* allocate memory */ 219 alloc_size = (avs_info->num_centrals + avs_info->num_remotes) * 220 sizeof(uint32); 221 if ((buff = (uint32 *)soc_cm_salloc(unit, alloc_size, 222 "Storage for _soc_avs_osc_count dma")) 223 == NULL) { 224 return (SOC_E_MEMORY); 225 } 226 sal_memset(buff, 0, alloc_size); 227 avs->cent_desc_buff = buff; 228 avs->rmt_desc_buff = &buff[avs_info->num_centrals]; 229 230 cent_reg = avs_info->cen_osc_reg; 231 rmt_reg = avs_info->rmt_osc_reg; 232 233 if (!SOC_REG_IS_VALID(unit, cent_reg) || 234 !SOC_REG_IS_VALID(unit, rmt_reg)) { 235 return (SOC_E_INTERNAL); 236 } 237 238 cent_addr = soc_reg_addr_get(unit, cent_reg, REG_PORT_ANY, 0, 239 SOC_REG_ADDR_OPTION_NONE, 240 ¢_blkoff, ¢_acc_type); 241 242 rmt_addr = soc_reg_addr_get(unit, rmt_reg, REG_PORT_ANY, 0, 243 SOC_REG_ADDR_OPTION_NONE, 244 &rmt_blkoff, &rmt_acc_type); 245 246 /* central */ 247 sal_memset(&ctrl, 0, sizeof(soc_sbusdma_desc_ctrl_t)); 248 sal_memset(&cfg, 0, sizeof(soc_sbusdma_desc_cfg_t)); 249 ctrl.flags = 0; 250 ctrl.cfg_count = 1; 251 ctrl.buff = avs->cent_desc_buff; 252 ctrl.cb = _soc_sbusdma_avs_cb; 253 ctrl.data = INT_TO_PTR(SOC_AVS_ROSC_TYPE_CENTRAL); 254 sal_strncpy(ctrl.name, "CROSC COUNTERS", sizeof(ctrl.name)-1); 255 cfg.acc_type = cent_acc_type; 256 cfg.blk = cent_blkoff; 257 cfg.addr = cent_addr; 258 cfg.width = SOC_REG_IS_64(unit, cent_reg) ? 2 : 1; 259 cfg.count = avs_info->num_centrals; 260 cfg.addr_shift = 10; 261 SOC_AVS_FREE_IF_ERROR_RETURN 262 (soc_sbusdma_desc_create(unit, &ctrl, &cfg, 263 &_soc_avs_rosc_handles[unit][SOC_AVS_ROSC_TYPE_CENTRAL]), 264 buff); 265 266 /* remote */ 267 sal_memset(&ctrl, 0, sizeof(soc_sbusdma_desc_ctrl_t)); 268 sal_memset(&cfg, 0, sizeof(soc_sbusdma_desc_cfg_t)); 269 ctrl.flags = 0; 270 ctrl.cfg_count = 1; 271 ctrl.buff = avs->rmt_desc_buff; 272 ctrl.cb = _soc_sbusdma_avs_cb; 273 ctrl.data = INT_TO_PTR(SOC_AVS_ROSC_TYPE_REMOTE); 274 sal_strncpy(ctrl.name, "RROSC COUNTERS", sizeof(ctrl.name)-1); 275 cfg.acc_type = rmt_acc_type; 276 cfg.blk = rmt_blkoff; 277 cfg.addr = rmt_addr; 278 cfg.width = SOC_REG_IS_64(unit, rmt_reg) ? 2 : 1; 279 cfg.count = avs_info->num_remotes; 280 cfg.addr_shift = 8; 281 SOC_AVS_FREE_IF_ERROR_RETURN 282 (soc_sbusdma_desc_create(unit, &ctrl, &cfg, 283 &_soc_avs_rosc_handles[unit][SOC_AVS_ROSC_TYPE_REMOTE]), 284 buff); 285 286 avs->rmt_rosc_count_sync = 0; 287 avs->cent_rosc_count_sync = 0; 288 289 return SOC_E_NONE; 290 } 291 int 292 soc_avs_sbusdma_desc_free(int unit) 293 { 294 uint8 i, state = 0; 295 int ret, err = 0; 296 soc_avs_control_t *avs; 297 298 avs = SOC_AVS_CONTROL(unit); 299 300 if (avs->cent_desc_buff != NULL) { 301 soc_cm_sfree(unit, avs->cent_desc_buff); 302 avs->cent_desc_buff = NULL; 303 avs->rmt_desc_buff = NULL; 304 } 305 avs->cent_rosc_count_sync = 0; 306 avs->rmt_rosc_count_sync = 0; 307 308 for (i = 0; i < SOC_AVS_ROSC_TYPE_ALL; i++) { 309 if (_soc_avs_rosc_handles[unit][i]) { 310 do { 311 (void)soc_sbusdma_desc_get_state(unit, 312 _soc_avs_rosc_handles[unit][i], 313 &state); 314 if (state) { 315 sal_usleep(10); 316 } 317 } while (state); 318 ret = soc_sbusdma_desc_delete(unit, 319 _soc_avs_rosc_handles[unit][i]); 320 if (ret) { 321 err++; 322 } 323 _soc_avs_rosc_handles[unit][i] = 0; 324 } 325 } 326 return err; 327 } 328 #endif 329 330 /* 331 * Function: 332 * _soc_avs_xbmp_check 333 * Purpose: 334 * Check if the index of the ROSC in exclude bitmap or not 335 * Parameters: 336 * type - (IN)SOC_AVS_ROSC_TYPE_REMOTE or SOC_AVS_ROSC_TYPE_CENTRAL 337 * index - (IN) index of ROSC 338 * Returns: 339 * SOC_AVS_BOOL_TRUE :the index should be exclude in the process 340 * SOC_AVS_BOOL_FALSE :the index should be used in the process 341 */ 342 STATIC int 343 _soc_avs_xbmp_check(int unit, int type, int index) 344 { 345 if (type == SOC_AVS_ROSC_TYPE_REMOTE) { 346 return SOC_AVS_OSC_EXCLUDED(index, 347 SOC_AVS_XBMP(unit)->rmt_xbmp[index/NUM_BITS_PER_XBMP] | 348 SOC_AVS_INFO(unit)->rmt_xbmp[index/NUM_BITS_PER_XBMP]); 349 } 350 if (type == SOC_AVS_ROSC_TYPE_CENTRAL) { 351 return SOC_AVS_OSC_EXCLUDED(index, 352 SOC_AVS_XBMP(unit)->cent_xbmp[index/NUM_BITS_PER_XBMP] | 353 SOC_AVS_INFO(unit)->cent_xbmp[index/NUM_BITS_PER_XBMP]); 354 } 355 return SOC_AVS_BOOL_TRUE; 356 357 } 358 359 int 360 soc_avs_ioctl(int unit, soc_avs_ioctl_t opcode, void* data, int len) 361 { 362 363 if (!soc_avs_inited(unit)) { 364 return SOC_E_INIT; 365 } 366 367 if ((SOC_AVS_FUNCTIONS(unit) != NULL) && 368 (SOC_AVS_FUNCTIONS(unit)->ioctl != NULL)) { 369 return SOC_AVS_FUNCTIONS(unit)->ioctl(unit, opcode, data, len); 370 } 371 return (SOC_E_UNAVAIL); 372 373 } 374 375 /* 376 * Function: 377 * _soc_avs_pvt_value_read 378 * Purpose: 379 * Read the 10b data value for specified PVT_MON. 380 * Parameters: 381 * pvtmon - (IN) specifies one of PVT_TEMPERATURE, PVT_1V_0, PVT_1V_1, etc 382 * data - (OUT) 10b pvtmon.data 383 * Returns: 384 * data - (OUT) 10b pvtmon.data 385 */ 386 #define _SOC_AVS_PVTMON_MAX_REREADS 10 387 STATIC int 388 _soc_avs_pvt_value_read(int unit, soc_avs_pvt_t pvtmon, uint32 *data) 389 { 390 int j; 391 uint32 regval; 392 uint32 valid_data = 0; 393 uint32 done = 0; 394 395 if (data == NULL) { 396 return (SOC_E_PARAM); 397 } 398 *data = 0; 399 regval = 0; 400 for (j = 0; j < _SOC_AVS_PVTMON_MAX_REREADS; j++) { 401 switch (pvtmon) { 402 case SOC_AVS_PVT_TEMPERATURE: 403 SOC_IF_ERROR_RETURN( 404 READ_AVS_REG_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUSr(unit, 405 ®val)); 406 break; 407 case SOC_AVS_PVT_1V_0: 408 SOC_IF_ERROR_RETURN( 409 READ_AVS_REG_RO_REGISTERS_0_PVT_1V_0_MNTR_STATUSr(unit, 410 ®val)); 411 break; 412 default: 413 *data = 0; 414 return (SOC_E_PARAM); 415 } 416 /* all PVT monitor measurement status register have the same field format */ 417 valid_data = soc_reg_field_get(unit, 418 AVS_REG_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUSr, 419 regval, VALID_DATAf); 420 done = soc_reg_field_get(unit, 421 AVS_REG_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUSr, 422 regval, DONEf); 423 424 /* Wait for valid to be set */ 425 if (valid_data && done) { 426 break; 427 } 428 } 429 *data = soc_reg_field_get(unit, 430 AVS_REG_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUSr, 431 regval, DATAf); 432 if (!valid_data) { 433 return (SOC_E_FAIL); 434 } else { 435 return (SOC_E_NONE); 436 } 437 } 438 439 /* This just assumes that the PVTMON sequencer did the measurement. */ 440 /* Get the value from PVTMON for the specified value */ 441 STATIC int 442 _soc_avs_pvtmon_get(int unit, soc_avs_pvt_t pvtmon, uint32 *data) 443 { 444 int i; 445 uint32 code, count, sum; 446 447 /* Disable all but the particular measurement we're interested in */ 448 count = ~(1 << pvtmon) & 0x7F; 449 SOC_IF_ERROR_RETURN( 450 WRITE_AVS_REG_HW_MNTR_SEQUENCER_MASK_PVT_MNTRr(unit, count)); 451 SOC_IF_ERROR_RETURN( 452 WRITE_AVS_REG_HW_MNTR_SEQUENCER_MASK_CEN_ROSC_0r(unit, SOC_AVS_ALL_ONES)); 453 SOC_IF_ERROR_RETURN( 454 WRITE_AVS_REG_HW_MNTR_SEQUENCER_MASK_CEN_ROSC_1r(unit, SOC_AVS_ALL_ONES)); 455 sal_usleep(SOC_AVS_PVT_DISABLE_DELAY); 456 457 sum = 0; 458 for (i = 0; i < _SOC_AVS_PVTMON_MAX_REREADS; i ++) { 459 SOC_IF_ERROR_RETURN( 460 _soc_avs_pvt_value_read(unit, pvtmon, &code)); 461 sum += code; 462 sal_usleep(SOC_AVS_PVT_DISABLE_DELAY); 463 } 464 code = sum / _SOC_AVS_PVTMON_MAX_REREADS; 465 *data = code; 466 /* Re-enable all of the other measurements */ 467 SOC_IF_ERROR_RETURN( 468 WRITE_AVS_REG_HW_MNTR_SEQUENCER_MASK_PVT_MNTRr(unit, 0)); 469 SOC_IF_ERROR_RETURN( 470 WRITE_AVS_REG_HW_MNTR_SEQUENCER_MASK_CEN_ROSC_0r(unit, 0)); 471 SOC_IF_ERROR_RETURN( 472 WRITE_AVS_REG_HW_MNTR_SEQUENCER_MASK_CEN_ROSC_1r(unit, 0)); 473 474 return SOC_E_NONE; 475 } 476 STATIC int 477 _soc_avs_reset_measurement(int unit, soc_avs_pvt_t pvtmon) 478 { 479 uint32 regval; 480 uint32 m_init_pvt_mntr; 481 482 /* set */ 483 SOC_IF_ERROR_RETURN( 484 READ_AVS_REG_HW_MNTR_MEASUREMENTS_INIT_PVT_MNTRr(unit, ®val)); 485 486 m_init_pvt_mntr = (soc_reg_field_get(unit, 487 AVS_REG_HW_MNTR_MEASUREMENTS_INIT_PVT_MNTRr, 488 regval, M_INIT_PVT_MNTRf)); 489 m_init_pvt_mntr |= (0x1 << pvtmon); 490 491 soc_reg_field_set(unit, AVS_REG_HW_MNTR_MEASUREMENTS_INIT_PVT_MNTRr, 492 ®val, M_INIT_PVT_MNTRf, m_init_pvt_mntr); 493 494 SOC_IF_ERROR_RETURN( 495 WRITE_AVS_REG_HW_MNTR_MEASUREMENTS_INIT_PVT_MNTRr(unit, regval)); 496 497 /* clr */ 498 SOC_IF_ERROR_RETURN( 499 READ_AVS_REG_HW_MNTR_MEASUREMENTS_INIT_PVT_MNTRr(unit, ®val)); 500 501 m_init_pvt_mntr = (soc_reg_field_get(unit, 502 AVS_REG_HW_MNTR_MEASUREMENTS_INIT_PVT_MNTRr, 503 regval, M_INIT_PVT_MNTRf)); 504 m_init_pvt_mntr &= ~(0x1 << pvtmon); 505 506 soc_reg_field_set(unit, AVS_REG_HW_MNTR_MEASUREMENTS_INIT_PVT_MNTRr, 507 ®val, M_INIT_PVT_MNTRf, m_init_pvt_mntr); 508 509 SOC_IF_ERROR_RETURN( 510 WRITE_AVS_REG_HW_MNTR_MEASUREMENTS_INIT_PVT_MNTRr(unit, regval)); 511 512 return (SOC_E_NONE); 513 } 514 515 /* Use Software Override to do measurements */ 516 /* This just reads the requested register with debounce */ 517 STATIC int 518 _soc_avs_sw_takeover_measure(int unit, soc_avs_pvt_t pvtmon, uint32 *code) 519 { 520 #define _SOC_AVS_RETRY_LOOPS 5 521 /* found that we sometimes don't get valid data even after the 26 tries */ 522 #define _SOC_AVS_AVERAGE_LOOPS 26 523 /* the more loops the longer the process, but better the average */ 524 #define _SOC_AVS_HW_MNTR_SW_CONTROLS_RESET_VALUE 0 525 #define _SOC_AVS_MAX_ITERATIONS 100 526 /* don't let any loops run forever */ 527 528 int i, j, k; 529 uint32 regval, busy = 1, count = 0, sum; 530 531 if (code == NULL) { 532 return (SOC_E_PARAM); 533 } 534 *code = 0; 535 536 for (k = 0; k < _SOC_AVS_RETRY_LOOPS; k++) { 537 *code = sum = count = 0; 538 539 for (i = 0; i < _SOC_AVS_AVERAGE_LOOPS; i++) { 540 541 /* These steps need to be done one-at-a-time */ 542 regval = 0; 543 soc_reg_field_set(unit, AVS_REG_HW_MNTR_SW_CONTROLSr, ®val, 544 SW_TAKEOVERf, 1); 545 SOC_IF_ERROR_RETURN( 546 WRITE_AVS_REG_HW_MNTR_SW_CONTROLSr(unit, regval)); 547 548 soc_reg_field_set(unit, AVS_REG_HW_MNTR_SW_CONTROLSr, ®val, 549 SW_SENSOR_IDXf, pvtmon); 550 /* sensors in 'PVT Monitor' group */ 551 SOC_IF_ERROR_RETURN( 552 WRITE_AVS_REG_HW_MNTR_SW_CONTROLSr(unit, regval)); 553 554 soc_reg_field_set(unit, AVS_REG_HW_MNTR_SW_CONTROLSr, ®val, 555 SW_DO_MEASUREf, 1); 556 SOC_IF_ERROR_RETURN( 557 WRITE_AVS_REG_HW_MNTR_SW_CONTROLSr(unit, regval)); 558 559 /* _soc_avs_msec_sleep(500); 560 * delay a bit before checking busy status */ 561 sal_usleep(1000); 562 /* delay a bit before checking busy status */ 563 564 /* The busy comes on during processing and goes off when done */ 565 for (j = 0; j < _SOC_AVS_MAX_ITERATIONS; j++) { 566 SOC_IF_ERROR_RETURN( 567 READ_AVS_REG_HW_MNTR_SW_MEASUREMENT_UNIT_BUSYr(unit, 568 ®val)); 569 busy = soc_reg_field_get(unit, 570 AVS_REG_HW_MNTR_SW_MEASUREMENT_UNIT_BUSYr, 571 regval, BUSYf); 572 if (busy == 0) break; /* from j for loop */ 573 /* _soc_avs_msec_sleep(1); delay a bit before checking again! */ 574 } 575 576 /* We sometimes see the busy stuck on for some reason 577 * (if its still on, dismiss this data) */ 578 if (busy == 1) { 579 SOC_IF_ERROR_RETURN( 580 WRITE_AVS_REG_HW_MNTR_SW_CONTROLSr(unit, 581 _SOC_AVS_HW_MNTR_SW_CONTROLS_RESET_VALUE)); 582 continue; /* with next averaging loop */ 583 } 584 585 if (i < 10) { 586 continue; /* skip the first couple of results */ 587 } 588 589 SOC_IF_ERROR_RETURN(_soc_avs_pvt_value_read(unit, pvtmon, code)); 590 if (*code == 0) { 591 continue; 592 } 593 /* ignore results from this loop and continue with 594 * next averaging loop */ 595 596 sum += *code; 597 count++; 598 599 /* 600 * LOG_VERBOSE(BSL_LS_SOC_AVS, 601 * (BSL_META_U(unit, 602 * "i = %3d, code = %0d, sum = %0d, count = %0d" 603 * "\n"), 604 * i, *code, sum, count)); 605 */ 606 607 SOC_IF_ERROR_RETURN( 608 READ_AVS_REG_HW_MNTR_SW_CONTROLSr(unit, ®val)); 609 soc_reg_field_set(unit, AVS_REG_HW_MNTR_SW_CONTROLSr, ®val, 610 SW_DO_MEASUREf, 0); 611 SOC_IF_ERROR_RETURN( 612 WRITE_AVS_REG_HW_MNTR_SW_CONTROLSr(unit, regval)); 613 614 /* enable this to just read it once 615 * break; 616 */ 617 618 } /* _SOC_AVS_AVERAGE_LOOPS */ 619 620 /* Use an average value to dismiss the variance in the reads (this is 621 * called debouncing */ 622 if (count != 0) { 623 *code = sum/count; 624 break; /* from _SOC_AVS_RETRY_LOOPS */ 625 } 626 627 /* If we failed to get valid from this pass, reset for next pass */ 628 SOC_IF_ERROR_RETURN(_soc_avs_reset_measurement(unit, pvtmon)); 629 } /* _SOC_AVS_RETRY_LOOPS */ 630 631 632 SOC_IF_ERROR_RETURN( 633 READ_AVS_REG_HW_MNTR_SW_CONTROLSr(unit, ®val)); 634 soc_reg_field_set(unit, AVS_REG_HW_MNTR_SW_CONTROLSr, ®val, 635 SW_TAKEOVERf, 0); 636 SOC_IF_ERROR_RETURN( 637 WRITE_AVS_REG_HW_MNTR_SW_CONTROLSr(unit, regval)); 638 639 return (count == 0? SOC_E_FAIL : SOC_E_NONE); 640 } 641 642 int 643 soc_avs_temperature_get(int unit, int *temperature) 644 { 645 uint32 value; 646 soc_avs_info_t *avs_info; 647 648 if (!soc_avs_inited(unit)) { 649 return SOC_E_INIT; 650 } 651 if (temperature == NULL) { 652 return (SOC_E_PARAM); 653 } 654 avs_info = SOC_AVS_INFO(unit); 655 *temperature = 0; 656 if (avs_info->avs_flags & SOC_AVS_INFO_F_USE_SOFTWARE_TAKEOVER) { 657 /* use software override to do measurements */ 658 SOC_IF_ERROR_RETURN( 659 _soc_avs_sw_takeover_measure(unit, SOC_AVS_PVT_TEMPERATURE, &value)); 660 } else { 661 /* PVTMON sequencer did the measurement. */ 662 SOC_IF_ERROR_RETURN( 663 _soc_avs_pvtmon_get(unit, SOC_AVS_PVT_TEMPERATURE, &value)); 664 } 665 SOC_IF_ERROR_RETURN( 666 soc_avs_ioctl(unit, SOC_AVS_CTRL_PVTMON_TEMP_GET, &value, 0)); 667 *temperature = value; 668 return SOC_E_NONE; 669 } 670 671 int 672 soc_avs_pvtmon_voltage_get(int unit, uint32 *voltage) 673 { 674 uint32 value; 675 soc_avs_info_t *avs_info; 676 677 if (!soc_avs_inited(unit)) { 678 return SOC_E_INIT; 679 } 680 if (voltage == NULL) { 681 return (SOC_E_PARAM); 682 } 683 avs_info = SOC_AVS_INFO(unit); 684 *voltage = 0; 685 if (avs_info->avs_flags & SOC_AVS_INFO_F_USE_SOFTWARE_TAKEOVER) { 686 /* use software override to do measurements */ 687 SOC_IF_ERROR_RETURN( 688 _soc_avs_sw_takeover_measure(unit, SOC_AVS_PVT_1V_0, &value)); 689 } else { 690 /* PVTMON sequencer did the measurement. */ 691 SOC_IF_ERROR_RETURN( 692 _soc_avs_pvtmon_get(unit, SOC_AVS_PVT_1V_0, &value)); 693 } 694 SOC_IF_ERROR_RETURN( 695 soc_avs_ioctl(unit, SOC_AVS_CTRL_PVTMON_VOLTAGE_GET, &value, 0)); 696 *voltage = value; 697 698 LOG_VERBOSE(BSL_LS_SOC_AVS, 699 (BSL_META_U(unit, 700 "==== unit = %d, pvt get voltage = %0d (0.1 mV)\n"), 701 unit, *voltage)); 702 return SOC_E_NONE; 703 } 704 705 STATIC int 706 _soc_avs_pvt_value_write(int unit, soc_avs_pvt_t pvtmon, uint32 data) 707 { 708 int rval; 709 710 switch (pvtmon) { 711 case SOC_AVS_PVT_1V_0: 712 rval = 1; 713 SOC_IF_ERROR_RETURN(WRITE_AVS_REG_PVT_MNTR_CONFIG_PVT_MNTR_CTRLr(unit, rval)); 714 SOC_IF_ERROR_RETURN( 715 WRITE_AVS_REG_PVT_MNTR_CONFIG_DAC_CODE_PROGRAMMING_ENABLEr(unit, rval)); 716 717 SOC_IF_ERROR_RETURN(WRITE_AVS_REG_PVT_MNTR_CONFIG_DAC_CODEr(unit, data)); 718 SOC_IF_ERROR_RETURN(WRITE_AVS_REG_PVT_MNTR_CONFIG_MIN_DAC_CODEr(unit, data)); 719 SOC_IF_ERROR_RETURN(WRITE_AVS_REG_PVT_MNTR_CONFIG_MAX_DAC_CODEr(unit, data)); 720 721 rval = 0x1180; 722 /* PVTMON control bits : RMON_sel = 0x6; Mode = 0x4 */ 723 SOC_IF_ERROR_RETURN(WRITE_AVS_REG_PVT_MNTR_CONFIG_PVT_MNTR_CTRLr(unit, rval)); 724 break; 725 726 default: 727 return SOC_E_PARAM; 728 729 } 730 731 return SOC_E_NONE; 732 } 733 734 int 735 soc_avs_pvtmon_voltage_set(int unit, uint32 voltage) 736 { 737 uint32 value; 738 739 if (!soc_avs_inited(unit)) { 740 return SOC_E_INIT; 741 } 742 743 value = voltage; 744 SOC_IF_ERROR_RETURN( 745 soc_avs_ioctl(unit, SOC_AVS_CTRL_PVTMON_VOLTAGE_SET, &value, 0)); 746 747 SOC_IF_ERROR_RETURN( 748 _soc_avs_pvt_value_write(unit, SOC_AVS_PVT_1V_0, value)); 749 750 /* Delay for the voltage to get reflected. */ 751 sal_msleep(SOC_AVS_DAC_DELAY); 752 753 return SOC_E_NONE; 754 } 755 756 #define AVS_V_TO_UV_SCALE (1000000) 757 #define AVS_SCALING_FACTOR (100) 758 /* voltage :(OUT) voltage value (0.1mV granularity)*/ 759 int 760 soc_avs_voltage_get(int unit, uint32 *voltage) 761 { 762 if (voltage == NULL) { 763 return SOC_E_PARAM; 764 } 765 766 if ((SOC_AVS_CONTROL(unit)->flags & SOC_AVS_F_VRM_INITED) == 0) { 767 return SOC_E_UNAVAIL; 768 } 769 770 if (SOC_AVS_VRM_ACCESS(unit)) { 771 if (SOC_AVS_VRM_ACCESS(unit)->voltage_get){ 772 return SOC_AVS_VRM_ACCESS(unit)->voltage_get(unit, 773 voltage); 774 } 775 } 776 if (SOC_AVS_VRM_INFO(unit)) { 777 #ifdef COMPILER_HAS_DOUBLE 778 double volts; 779 #else 780 int volts; 781 #endif 782 int rv, fd; 783 784 if ((SOC_AVS_VRM_INFO(unit)->mux_id != -1) && 785 SOC_AVS_VRM_INFO(unit)->profile.mux_enable_value) { 786 fd = SOC_AVS_VRM_INFO(unit)->mux_id; 787 rv = soc_i2c_device(unit, fd)->driver->write(unit, fd, 0, 788 &SOC_AVS_VRM_INFO(unit)->profile.mux_enable_value, 1); 789 if (SOC_FAILURE(rv)) { 790 return rv; 791 } 792 } 793 794 fd = SOC_AVS_VRM_INFO(unit)->vrm_id; 795 *voltage = 0; 796 rv = soc_i2c_device(unit, fd)->driver->ioctl(unit, fd, 797 PMBUS_IOC_READ_VOUT, 798 &volts, 0); 799 if (SOC_FAILURE(rv)) { 800 return rv; 801 } 802 803 #ifdef COMPILER_HAS_DOUBLE 804 /* V -> 0.1mV */ 805 *voltage = (uint32)((volts * AVS_V_TO_UV_SCALE) / AVS_SCALING_FACTOR); 806 #else 807 /* uV -> 0.1mV */ 808 *voltage = volts / AVS_SCALING_FACTOR; 809 #endif 810 if (*voltage == 0) { 811 /* Some i2c device report non-error on un-supported type */ 812 return SOC_E_UNAVAIL; 813 } 814 } 815 return SOC_E_UNAVAIL; 816 } 817 818 /* 819 * Function: 820 * soc_avs_voltage_set 821 * Purpose: 822 * Set the voltage to external voltage supplier 823 * Parameters 824 * voltage - (IN) voltage corresponding to desired voltage (0.1mV granularity) 825 * Returns: 826 * SOC_E_xxx 827 */ 828 int 829 soc_avs_voltage_set(int unit, uint32 voltage) 830 { 831 int rv = SOC_E_UNAVAIL; 832 833 if ((SOC_AVS_CONTROL(unit)->flags & SOC_AVS_F_VRM_INITED) == 0) { 834 return SOC_E_UNAVAIL; 835 } 836 LOG_VERBOSE(BSL_LS_SOC_AVS, 837 (BSL_META_U(unit, 838 "==== unit = %d, request to " 839 "set voltage = %0d (0.1 mV)\n"), 840 unit, voltage)); 841 842 if (voltage > SOC_AVS_MAX_VOLTAGE) { 843 LOG_WARN(BSL_LS_SOC_AVS, 844 (BSL_META_U(unit, 845 "Fail to set voltage %d " 846 "(> SOC_AVS_MAX_VOLTAGE) try %d \n"), 847 voltage, SOC_AVS_MAX_VOLTAGE)); 848 voltage = SOC_AVS_MAX_VOLTAGE; 849 } else if(voltage < SOC_AVS_MIN_VOLTAGE){ 850 LOG_WARN(BSL_LS_SOC_AVS, 851 (BSL_META_U(unit, 852 "Fail to set voltage %d " 853 "(< SOC_AVS_MIN_VOLTAGE) try %d \n"), 854 voltage, SOC_AVS_MIN_VOLTAGE)); 855 voltage = SOC_AVS_MIN_VOLTAGE; 856 } 857 if (SOC_AVS_VRM_ACCESS(unit)) { 858 if (SOC_AVS_VRM_ACCESS(unit)->voltage_get){ 859 rv = SOC_AVS_VRM_ACCESS(unit)->voltage_set(unit, 860 voltage); 861 } 862 } else if (SOC_AVS_VRM_INFO(unit)) { 863 #ifdef COMPILER_HAS_DOUBLE 864 double volts; 865 #else 866 int volts; 867 #endif 868 int fd; 869 870 if ((SOC_AVS_VRM_INFO(unit)->mux_id != -1) && 871 SOC_AVS_VRM_INFO(unit)->profile.mux_enable_value) { 872 fd = SOC_AVS_VRM_INFO(unit)->mux_id; 873 rv = soc_i2c_device(unit, fd)->driver->write(unit, fd, 0, 874 &SOC_AVS_VRM_INFO(unit)->profile.mux_enable_value, 1); 875 if (SOC_FAILURE(rv)) { 876 return rv; 877 } 878 } 879 880 #ifdef COMPILER_HAS_DOUBLE 881 /* 0.1mV -> V */ 882 volts = (double)voltage * AVS_SCALING_FACTOR / AVS_V_TO_UV_SCALE; 883 #else 884 /* 0.1mV -> uV */ 885 volts = voltage * AVS_SCALING_FACTOR; 886 #endif 887 fd = SOC_AVS_VRM_INFO(unit)->vrm_id; 888 rv = soc_i2c_device(unit, fd)->driver->ioctl(unit, fd, 889 PMBUS_IOC_SET_VOUT, 890 &volts, 0); 891 } else { 892 rv = SOC_E_UNAVAIL; 893 } 894 895 if (SOC_FAILURE(rv)) { 896 LOG_WARN(BSL_LS_SOC_AVS, 897 (BSL_META_U(unit, 898 "Fail to set voltage %d\n"), 899 voltage)); 900 return (rv); 901 } else { 902 /* remember last_set_voltage for avs_track voltage adjusment*/ 903 _soc_last_set_voltage[unit] = voltage; 904 return (SOC_E_NONE); 905 } 906 } 907 908 /* 909 * Function: 910 * _soc_avs_calc_v3_for_ref_f3 911 * Purpose: 912 * Computes voltage v3 corresponding to ref_freq f3. 913 * Parameters: 914 * f2 - (IN)Frequency at low voltage 915 * v2 - (IN)Low voltage 916 * m - (IN)Slope 917 * f3 - (IN)Frequency at high voltage 918 * Returns: 919 * Voltage v3 (units of 0.1mV) 920 */ 921 STATIC uint32 922 _soc_avs_calc_v3_for_ref_f3(uint32 f2, uint32 v2, uint32 m, uint32 f3) 923 { 924 uint32 v3; 925 uint32 vdelta; 926 927 /* find v3 corresponding to f3 */ 928 if (f2 >= f3) { 929 vdelta = ((f2 - f3) * SOC_AVS_S2)/m; 930 SOC_AVS_ASSERT(v2 > vdelta); 931 v3 = v2 - vdelta; 932 } else { 933 vdelta = ((f3 - f2) * SOC_AVS_S2)/m; 934 v3 = v2 + vdelta; 935 } 936 937 return (v3); 938 } 939 940 /* We need the frequency units to be in 10K but multiplying by 10K will cause 941 * the numerator to overflow in frequency calculation. 942 * So use 1K before division and multiply by 10 after. 943 */ 944 #define SOC_AVS_FREQ_DIVIDER 1000U 945 #define SOC_AVS_FREQ_DIVIDER_ADJUSTMENT 10U 946 STATIC uint32 947 _soc_avs_reg_to_freq(int unit, uint32 rosc_count) 948 { 949 uint32 freq; 950 int rosc_count_mode; 951 int ref_clk_freq; /* in MHz*/ 952 int max_ref_clk_counter; 953 soc_avs_info_t *avs_info; 954 955 avs_info = SOC_AVS_INFO(unit); 956 rosc_count_mode = avs_info->rosc_count_mode; 957 ref_clk_freq = avs_info->ref_clk_freq; 958 max_ref_clk_counter = (avs_info->measurement_time_control * 256U) 959 + 255U; 960 freq = ( ((ref_clk_freq * rosc_count) * SOC_AVS_FREQ_DIVIDER) / 961 (max_ref_clk_counter * rosc_count_mode) 962 ) * SOC_AVS_FREQ_DIVIDER_ADJUSTMENT; 963 964 return (freq); 965 } 966 967 STATIC uint32 968 _soc_avs_freq_to_reg(int unit, uint32 freq) 969 { 970 uint32 reg; 971 int rosc_count_mode; 972 int ref_clk_freq; /* in MHz*/ 973 int max_ref_clk_counter; 974 soc_avs_info_t *avs_info; 975 976 avs_info = SOC_AVS_INFO(unit); 977 rosc_count_mode = avs_info->rosc_count_mode; 978 ref_clk_freq = avs_info->ref_clk_freq; 979 max_ref_clk_counter = (avs_info->measurement_time_control * 256U) 980 + 255U; 981 reg = ((freq / ref_clk_freq) * (max_ref_clk_counter * rosc_count_mode)) / 982 (SOC_AVS_FREQ_DIVIDER * SOC_AVS_FREQ_DIVIDER_ADJUSTMENT); 983 return reg; 984 } 985 986 987 /* 988 * Function: 989 * _soc_avs_get_cent_osc_ref_freq 990 * Purpose: 991 * Get certain central ROSC's reference_frequency value 992 * Parameters: 993 * osc_num - (IN)specifies one of the central_osc 994 * ref_freq - (OUT)reference_frequency_threshold 995 * Returns: 996 * SOC_E_xxx 997 */ 998 STATIC int 999 _soc_avs_get_cent_osc_ref_freq(int unit, int osc_num, uint32 *ref_freq) 1000 { 1001 if (!soc_avs_inited(unit)) { 1002 return SOC_E_INIT; 1003 } 1004 1005 if (ref_freq == NULL){ 1006 return (SOC_E_PARAM); 1007 } 1008 if (osc_num > SOC_AVS_INFO(unit)->num_centrals) { 1009 return (SOC_E_PARAM); 1010 } 1011 *ref_freq = 0; /* default: consider it un-implemented osc */ 1012 *ref_freq = (SOC_AVS_CONTROL(unit)->cen_freq_thr[osc_num]); 1013 return SOC_E_NONE; 1014 } 1015 1016 /* 1017 * Function: 1018 * _soc_avs_get_rmt_osc_ref_freq 1019 * Purpose: 1020 * Get certain Remote ROSC's HVT and SVT reference_frequency value 1021 * Parameters: 1022 * osc_num - (IN)specifies one of the central_osc 1023 * ref_freq_h - (OUT)HVT reference_frequency_threshold 1024 * ref_freq_s - (OUT)SVT reference_frequency_threshold 1025 * Returns: 1026 * SOC_E_xxx 1027 */ 1028 STATIC int 1029 _soc_avs_get_rmt_osc_ref_freq(int unit, int osc_num, uint32 1030 *ref_freq_h, uint32 *ref_freq_s) 1031 { 1032 if ((ref_freq_h == NULL) || (ref_freq_s == NULL)) { 1033 return (SOC_E_PARAM); 1034 } 1035 *ref_freq_h = 0; 1036 *ref_freq_s = 0; 1037 *ref_freq_h = (SOC_AVS_CONTROL(unit)->rmt_freq_thr[1]); 1038 *ref_freq_s = (SOC_AVS_CONTROL(unit)->rmt_freq_thr[0]); 1039 return SOC_E_NONE; 1040 } 1041 1042 /* 1043 * There is a divide_by_2 for cent_rosc_counter in NTSW chips. 1044 * so real_count_value = 2*value_that_we_read 1045 */ 1046 #define SOC_AVS_CENT_OSC_COUNT_MULTIPLIER 2 1047 1048 /* 1049 * Function: 1050 * _soc_avs_cent_osc_count_get 1051 * Purpose: 1052 * Get specified central ROSC count 1053 * Parameters: 1054 * start_osc - (IN)specifies first central_osc 1055 * num_osc - (IN)specifies number of central_osc 1056 * ref_freq_s - (OUT)specifies array to return oscillator counts 1057 * Returns: 1058 * SOC_E_xxx 1059 */ 1060 1061 STATIC uint32 1062 _soc_avs_cent_osc_count_get(int unit, int start_osc, int num_osc, uint32 *count) 1063 { 1064 int i, failed = 0, n; 1065 soc_avs_info_t *avs_info; 1066 #ifdef BCM_SBUSDMA_SUPPORT 1067 soc_avs_control_t *avs; 1068 int use_dma = 0; 1069 soc_timeout_t to; 1070 sal_usecs_t dma_timeout = 1000000; 1071 #endif 1072 1073 if (!soc_avs_inited(unit)) { 1074 return SOC_E_INIT; 1075 } 1076 1077 avs_info = SOC_AVS_INFO(unit); 1078 if (count == NULL) { 1079 return (SOC_E_PARAM); 1080 } 1081 sal_memset(count, 0, num_osc*(sizeof(*count))); 1082 1083 #ifdef BCM_SBUSDMA_SUPPORT 1084 if (soc_feature(unit, soc_feature_sbusdma) && 1085 (avs_info->avs_flags & SOC_AVS_INFO_F_RSOC_COUNT_DMA)){ 1086 avs = SOC_AVS_CONTROL(unit); 1087 use_dma = 1; 1088 (void)_soc_avs_sbusdma_run(unit, SOC_AVS_ROSC_TYPE_CENTRAL); 1089 1090 soc_timeout_init(&to, 2 * dma_timeout, 0); 1091 for(;;) { 1092 if(avs->cent_rosc_count_sync){ 1093 avs->cent_rosc_count_sync = 0; 1094 break; 1095 } 1096 if (soc_timeout_check(&to)) { 1097 use_dma = 0; 1098 LOG_WARN(BSL_LS_SOC_AVS, 1099 (BSL_META_U(unit, 1100 "cent rosc count read operation " 1101 "timeout\n"))); 1102 break; 1103 } 1104 } 1105 } 1106 if (use_dma) { 1107 sal_memcpy(count, &SOC_AVS_CONTROL(unit)->cent_desc_buff[start_osc], 1108 num_osc * sizeof(uint32)); 1109 1110 }else 1111 #endif 1112 { 1113 /* read osc_counts */ 1114 for (i = start_osc; i < start_osc + num_osc; i++) { 1115 n = i - start_osc; 1116 if (avs_info->avs_flags & 1117 SOC_AVS_INFO_F_DO_NOT_ACCESS_XOSC) { 1118 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_CENTRAL, i)){ 1119 count[n] = 0; 1120 continue; 1121 } 1122 } 1123 SOC_IF_ERROR_RETURN( 1124 READ_AVS_REG_RO_REGISTERS_0_CEN_ROSC_STATUSr( 1125 unit, i, &count[n])); 1126 } 1127 } 1128 /* process the counts */ 1129 for (i = start_osc; i < start_osc + num_osc; i++) { 1130 n = i - start_osc; 1131 if (avs_info->avs_flags & SOC_AVS_INFO_F_DO_NOT_ACCESS_XOSC) { 1132 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_CENTRAL, i)){ 1133 count[n] = 0; 1134 continue; 1135 } 1136 } 1137 if (soc_reg_field_get(unit, AVS_REG_RO_REGISTERS_0_CEN_ROSC_STATUSr, 1138 count[n], VALIDf) == 0) { 1139 failed = 1; 1140 LOG_WARN(BSL_LS_SOC_AVS, 1141 (BSL_META_U(unit, 1142 "Fail to get cent osc[%d] %x\n"), 1143 i, count[i])); 1144 } 1145 count[n] = SOC_AVS_CENT_OSC_COUNT_MULTIPLIER * 1146 soc_reg_field_get(unit, AVS_REG_RO_REGISTERS_0_CEN_ROSC_STATUSr, 1147 count[n], DATAf); 1148 } 1149 if (failed == 1) { 1150 return (SOC_E_FAIL); 1151 } else { 1152 return (SOC_E_NONE); 1153 } 1154 } 1155 /* 1156 * Function: 1157 * _soc_avs_rmt_osc_count_get 1158 * Purpose: 1159 * Get specified remote ROSC COUNT_S, COUNT_H 1160 * Parameters: 1161 * start_osc - (IN)specifies first central_osc 1162 * num_osc - (IN)specifies number of central_osc 1163 * count_h - (OUT)specifies array to return COUNT_H values 1164 * count_s - (OUT)specifies array to return COUNT_S values 1165 * Returns: 1166 * SOC_E_xxx 1167 */ 1168 1169 STATIC int 1170 _soc_avs_rmt_osc_count_get(int unit, int start_osc, int num_osc, 1171 uint32 *count_h, uint32 *count_s) 1172 { 1173 int i, n; 1174 soc_avs_info_t *avs_info; 1175 #ifdef BCM_SBUSDMA_SUPPORT 1176 soc_avs_control_t *avs; 1177 int use_dma = 0; 1178 soc_timeout_t to; 1179 sal_usecs_t dma_timeout = 1000000; 1180 #endif 1181 1182 if (!soc_avs_inited(unit)) { 1183 return SOC_E_INIT; 1184 } 1185 1186 avs_info = SOC_AVS_INFO(unit); 1187 if ((count_h == NULL) || (count_s == NULL)) { 1188 return (SOC_E_PARAM); 1189 } 1190 sal_memset(count_h, 0, num_osc*(sizeof(*count_h))); 1191 sal_memset(count_s, 0, num_osc*(sizeof(*count_s))); 1192 1193 #ifdef BCM_SBUSDMA_SUPPORT 1194 if (soc_feature(unit, soc_feature_sbusdma) && 1195 (avs_info->avs_flags & SOC_AVS_INFO_F_RSOC_COUNT_DMA)){ 1196 avs = SOC_AVS_CONTROL(unit); 1197 use_dma = 1; 1198 (void)_soc_avs_sbusdma_run(unit, SOC_AVS_ROSC_TYPE_REMOTE); 1199 1200 soc_timeout_init(&to, 2 * dma_timeout, 0); 1201 for(;;) { 1202 if (avs->rmt_rosc_count_sync){ 1203 avs->rmt_rosc_count_sync = 0; 1204 break; 1205 } 1206 if (soc_timeout_check(&to)) { 1207 use_dma = 0; 1208 LOG_WARN(BSL_LS_SOC_AVS, 1209 (BSL_META_U(unit, 1210 "rmt rosc count read operation " 1211 "timeout\n"))); 1212 break; 1213 } 1214 } 1215 } 1216 if (use_dma) { 1217 sal_memcpy(count_s, &SOC_AVS_CONTROL(unit)->rmt_desc_buff[start_osc], 1218 num_osc * sizeof(uint32)); 1219 }else 1220 #endif 1221 { 1222 /* read count registers */ 1223 for (i = start_osc; i < start_osc + num_osc; i++) { 1224 n = i - start_osc; 1225 if (avs_info->avs_flags & 1226 SOC_AVS_INFO_F_DO_NOT_ACCESS_XOSC) { 1227 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_REMOTE, i)){ 1228 count_h[n] = 0; 1229 count_s[n] = 0; 1230 continue; 1231 } 1232 } 1233 /* use (count_s + i) to hold regval */ 1234 SOC_IF_ERROR_RETURN( 1235 READ_AVS_REG_PMB_SLAVE_AVS_ROSC_COUNTr(unit, i, &count_s[n])); 1236 sal_msleep(SOC_AVS_REMOTE_DELAY); 1237 } 1238 } 1239 /* extract fields from regval */ 1240 for (i = start_osc; i < start_osc + num_osc; i++) { 1241 n = i - start_osc; 1242 if (avs_info->avs_flags & SOC_AVS_INFO_F_DO_NOT_ACCESS_XOSC) { 1243 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_REMOTE, i)){ 1244 count_h[n] = 0; 1245 count_s[n] = 0; 1246 continue; 1247 } 1248 } 1249 count_h[n] = soc_reg_field_get(unit, AVS_REG_PMB_SLAVE_AVS_ROSC_COUNTr, 1250 count_s[n], COUNT_Hf); 1251 count_s[n] = soc_reg_field_get(unit, AVS_REG_PMB_SLAVE_AVS_ROSC_COUNTr, 1252 count_s[n], COUNT_Sf); 1253 } 1254 1255 return (SOC_E_NONE); 1256 1257 } 1258 1259 int 1260 soc_avs_osc_count_dump(int unit, int type) 1261 { 1262 int i, alloc_size; 1263 uint32 *alloc_ptr = NULL, 1264 *pcount_cent_osc = NULL, 1265 *pcount_rmt_osc_h = NULL, 1266 *pcount_rmt_osc_s = NULL; 1267 soc_avs_info_t *avs_info; 1268 1269 if (!soc_avs_inited(unit)) { 1270 return SOC_E_INIT; 1271 } 1272 avs_info = SOC_AVS_INFO(unit); 1273 1274 /* allocate memory */ 1275 alloc_size = 3 * SOC_AVS_MAX(avs_info->num_centrals, avs_info->num_remotes) 1276 *sizeof(uint32); 1277 if ((alloc_ptr = (uint32 *)sal_alloc(alloc_size, 1278 "Storage for _soc_avs_osc_count_dump")) == NULL) { 1279 return (SOC_E_MEMORY); 1280 } 1281 1282 pcount_cent_osc = alloc_ptr; 1283 pcount_rmt_osc_h = pcount_cent_osc + 1284 avs_info->num_centrals; 1285 pcount_rmt_osc_s = pcount_rmt_osc_h + 1286 avs_info->num_remotes; 1287 1288 sal_memset(alloc_ptr, 0, alloc_size); 1289 1290 /* read all cent,rmt osc counts */ 1291 if ((type == SOC_AVS_ROSC_TYPE_CENTRAL) || (type == SOC_AVS_ROSC_TYPE_ALL)) { 1292 SOC_AVS_FREE_IF_ERROR_RETURN( 1293 _soc_avs_cent_osc_count_get(unit, avs_info->first_cent, 1294 avs_info->num_centrals, 1295 pcount_cent_osc), alloc_ptr); 1296 } 1297 if ((type == SOC_AVS_ROSC_TYPE_REMOTE) || (type == SOC_AVS_ROSC_TYPE_ALL)) { 1298 SOC_AVS_FREE_IF_ERROR_RETURN( 1299 _soc_avs_rmt_osc_count_get(unit, avs_info->first_rmt, 1300 avs_info->num_remotes, 1301 pcount_rmt_osc_h, pcount_rmt_osc_s), 1302 alloc_ptr); 1303 } 1304 1305 if ((type == SOC_AVS_ROSC_TYPE_CENTRAL) || (type == SOC_AVS_ROSC_TYPE_ALL)) { 1306 LOG_CLI((BSL_META_U(unit, " index, cent_osc_count\n"))); 1307 for (i = avs_info->first_cent; i < avs_info->num_centrals; i++) { 1308 LOG_CLI((BSL_META_U(unit, "%d, %05d \n"), i, pcount_cent_osc[i])); 1309 } 1310 } 1311 1312 if ((type == SOC_AVS_ROSC_TYPE_REMOTE) || (type == SOC_AVS_ROSC_TYPE_ALL)) { 1313 LOG_CLI((BSL_META_U(unit, 1314 " index, count_rmt_osc_h, count_rmt_osc_s\n"))); 1315 for (i = avs_info->first_rmt; i < avs_info->num_remotes; i++) { 1316 LOG_CLI((BSL_META_U(unit, 1317 "%d, %05d, %5d \n"), 1318 i, pcount_rmt_osc_h[i],pcount_rmt_osc_s[i])); 1319 } 1320 } 1321 sal_free(alloc_ptr); 1322 return SOC_E_NONE; 1323 } 1324 1325 /* 1326 * Function: 1327 * _soc_avs_reg_field_all_ones 1328 * Purpose: 1329 * Get the all ones value of spefic register's field 1330 * Parameters: 1331 * soc_reg_t - (IN)specifies register 1332 * soc_field_t - (IN)specifies field 1333 * Returns: 1334 * return the all ones field value 1335 */ 1336 uint32 1337 _soc_avs_reg_field_all_ones(int unit, soc_reg_t reg, soc_field_t field) 1338 { 1339 soc_field_info_t *finfop; 1340 uint32 mask; 1341 1342 if (!SOC_REG_IS_VALID(unit, reg)) { 1343 #if !defined(SOC_NO_NAMES) 1344 LOG_CLI((BSL_META_U(unit, 1345 "reg %s is invalid\n"), soc_reg_name[reg])); 1346 #endif 1347 assert(SOC_REG_IS_VALID(unit, reg)); 1348 } 1349 SOC_FIND_FIELD(field, 1350 SOC_REG_INFO(unit, reg).fields, 1351 SOC_REG_INFO(unit, reg).nFields, 1352 finfop); 1353 if (finfop->len < 32) { 1354 mask = (1 << finfop->len) - 1; 1355 } else { 1356 mask = -1; 1357 } 1358 return mask; 1359 } 1360 1361 1362 #define SOC_AVS_ROSC_CONTROL_INIT_VALUE 0x7FFF50CF 1363 1364 /* 1365 * Function: 1366 * _soc_avs_initialize_oscs 1367 * Purpose: 1368 * Initialiaze central, remote osc 1369 * Parameters: 1370 * unit - (IN)specifies unit 1371 * Returns: 1372 * SOC_E_xxx 1373 */ 1374 int 1375 _soc_avs_initialize_oscs(int unit) 1376 { 1377 soc_avs_info_t *avs_info; 1378 uint32 regval, fieldval; 1379 soc_avs_reg_info_t *osc_cen_init_list,*osc_cen_thr_en_list; 1380 int i; 1381 soc_reg_t reg; 1382 soc_field_t field; 1383 1384 if (!soc_avs_inited(unit)) { 1385 return SOC_E_INIT; 1386 } 1387 avs_info = SOC_AVS_INFO(unit); 1388 /* AVS_MEASUREMENT_TIME_CONTROLr.LIMITf = AVS_MEASUREMENT_TIME_CONTROL*/ 1389 regval = 0; 1390 soc_reg_field_set(unit, AVS_REG_HW_MNTR_ROSC_MEASUREMENT_TIME_CONTROLr, 1391 ®val, LIMITf, avs_info->measurement_time_control); 1392 SOC_IF_ERROR_RETURN( 1393 WRITE_AVS_REG_HW_MNTR_ROSC_MEASUREMENT_TIME_CONTROLr(unit, 1394 regval)); 1395 1396 /* AVS_REG_HW_MNTR_ROSC_COUNTING_MODEr.MODEf = avs_info->rosc_count_mode*/ 1397 regval = 0; 1398 soc_reg_field_set(unit, AVS_REG_HW_MNTR_ROSC_COUNTING_MODEr, ®val, 1399 MODEf, avs_info->rosc_count_mode); 1400 SOC_IF_ERROR_RETURN( 1401 WRITE_AVS_REG_HW_MNTR_ROSC_COUNTING_MODEr(unit, regval)); 1402 1403 SOC_AVS_IF_ERROR_NOT_UNAVAIL_RETURN( 1404 soc_avs_ioctl(unit, SOC_AVS_CTRL_OSC_INIT, NULL, 0)); 1405 1406 if (avs_info->osc_cen_init_info) { 1407 /* always enable all oscillators at start-up */ 1408 osc_cen_init_list = avs_info->osc_cen_init_info; 1409 for (i = 0; osc_cen_init_list[i].reg_name != -1 ; i++) { 1410 reg = osc_cen_init_list[i].reg_name; 1411 field = osc_cen_init_list[i].reg_field; 1412 /* always enable all oscillators at start-up */ 1413 regval = 0; 1414 fieldval = _soc_avs_reg_field_all_ones(unit, reg, field); 1415 soc_reg_field_set(unit, reg, 1416 ®val, field, fieldval); 1417 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, 1418 reg, REG_PORT_ANY, 0, regval)); 1419 /* different form BCG, we don't clear this after enable */ 1420 } 1421 } 1422 1423 SOC_AVS_IF_ERROR_NOT_UNAVAIL_RETURN( 1424 soc_avs_ioctl(unit, SOC_AVS_CTRL_OSC_THRESHOLD, NULL, 0)); 1425 1426 if (avs_info->osc_cen_thr_en_info) { 1427 osc_cen_thr_en_list = avs_info->osc_cen_thr_en_info; 1428 /* Set up the Threshold enables */ 1429 for (i = 0; osc_cen_thr_en_list[i].reg_name != -1 ; i++) { 1430 reg = osc_cen_thr_en_list[i].reg_name; 1431 field = osc_cen_thr_en_list[i].reg_field; 1432 regval = 0; 1433 if (avs_info->avs_flags & SOC_AVS_INFO_F_USE_SOFTWARE_TAKEOVER) { 1434 /* If using software takeover then DISABLE all the 1435 threshold enables */ 1436 fieldval = 0; 1437 } else { 1438 /* If NOT using software takeover then ENABLE all the 1439 threshold enables */ 1440 fieldval = _soc_avs_reg_field_all_ones(unit, reg, field); 1441 } 1442 soc_reg_field_set(unit, reg, 1443 ®val, field, fieldval); 1444 SOC_IF_ERROR_RETURN( 1445 soc_reg32_set(unit, reg, REG_PORT_ANY, 0, regval)); 1446 } 1447 } 1448 1449 /* Remote oscillators are on PMB bus on newer parts */ 1450 regval = SOC_AVS_ROSC_CONTROL_INIT_VALUE; 1451 for (i = 0; i < avs_info->num_remotes; i++) { 1452 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_REMOTE, i)){ 1453 continue; 1454 } 1455 SOC_IF_ERROR_RETURN( 1456 WRITE_AVS_REG_PMB_SLAVE_AVS_ROSC_CONTROLr(unit, i, regval)); 1457 1458 sal_msleep(SOC_AVS_REMOTE_DELAY); 1459 } 1460 1461 return (SOC_E_NONE); 1462 } 1463 /* to determine v1s, v2s - local_fit */ 1464 #define SOC_AVS_VHIGH SOC_AVS_UINT(10200) 1465 #define SOC_AVS_V1_DIFF SOC_AVS_UINT(200) /* 20 mV*/ 1466 #define SOC_AVS_V1_MINUS_V2 SOC_AVS_UINT(300) /* 30 mV */ 1467 /* lowest slow-slow part voltage */ 1468 #define SOC_AVS_VLOW_SS SOC_AVS_INT(9400) 1469 #define SOC_AVS_V2S_INC_FOR_2ND_PASS SOC_AVS_UINT(280); /* 28mV */ 1470 #define SOC_AVS_VLOW_DIFF SOC_AVS_INT(600) /* 60 mV */ 1471 1472 #define SOC_AVS_VHI_VLO_MIN_DIFF SOC_AVS_UINT(100) /* 10 mV */ 1473 1474 /* 1475 * Function: 1476 * _soc_avs_predict_vpred 1477 * Purpose: 1478 * Applies (v1, v2), records (f1, f2), 1479 * computes v3 for pre-defined ref f3, returns vpred = max(v3). 1480 * Parameters: 1481 * dac_code_low - (IN)dac_code correspoding to v1 1482 * dac_code_high - (IN)dac_code correspoding to v2 1483 * vpred - (OUT)The converged voltage 1484 * Returns: 1485 * SOC_E_xxx 1486 */ 1487 int 1488 _soc_avs_predict_vpred(int unit, int pass, uint32 dac_code_low, uint32 1489 dac_code_high, uint32 *vpred, uint32 *vlow, uint32 *vhigh) 1490 { 1491 soc_avs_control_t *avs; 1492 soc_avs_info_t *avs_info; 1493 int32 v3_max_cent_osc, v3_max_rmt_osc; 1494 int i, alloc_size; 1495 uint32 *alloc_ptr = NULL, 1496 *pcount_cent_osc_at_vhigh = NULL, *pcount_cent_osc_at_vlow = NULL, 1497 *pcount_rmt_osc_at_vhigh_h = NULL, *pcount_rmt_osc_at_vlow_h = NULL, 1498 *pcount_rmt_osc_at_vhigh_s = NULL, *pcount_rmt_osc_at_vlow_s = NULL; 1499 1500 if (!soc_avs_inited(unit)) { 1501 return SOC_E_INIT; 1502 } 1503 if (vpred == NULL){ 1504 return SOC_E_PARAM; 1505 } 1506 SOC_AVS_ASSERT(dac_code_high > dac_code_low); 1507 avs = SOC_AVS_CONTROL(unit); 1508 avs_info = SOC_AVS_INFO(unit); 1509 /* Return Vpred value 0 in case of errors */ 1510 *vpred = 0; 1511 1512 /* allocate memory */ 1513 alloc_size = (2 * avs_info->num_centrals + 4 * avs_info->num_remotes) * 1514 sizeof(uint32); 1515 if ((alloc_ptr = (uint32 *)sal_alloc(alloc_size, 1516 "Storage for _soc_avs_predict_vpred")) == NULL) { 1517 return (SOC_E_MEMORY); 1518 } 1519 pcount_cent_osc_at_vhigh = alloc_ptr; 1520 pcount_cent_osc_at_vlow = pcount_cent_osc_at_vhigh + 1521 avs_info->num_centrals; 1522 pcount_rmt_osc_at_vhigh_h = pcount_cent_osc_at_vlow + 1523 avs_info->num_centrals; 1524 pcount_rmt_osc_at_vlow_h = pcount_rmt_osc_at_vhigh_h + 1525 avs_info->num_remotes; 1526 pcount_rmt_osc_at_vhigh_s = pcount_rmt_osc_at_vlow_h + 1527 avs_info->num_remotes; 1528 pcount_rmt_osc_at_vlow_s = pcount_rmt_osc_at_vhigh_s + 1529 avs_info->num_remotes; 1530 sal_memset(alloc_ptr, 0, alloc_size); 1531 1532 if ((pass == 0) || (pass == -1)){ 1533 /* Apply first voltage (high DAC is higher voltage) */ 1534 SOC_AVS_FREE_IF_ERROR_RETURN( 1535 soc_avs_voltage_set(unit, dac_code_high), alloc_ptr); 1536 SOC_AVS_FREE_IF_ERROR_RETURN( 1537 soc_avs_voltage_get(unit, vhigh),alloc_ptr); 1538 avs->v1r_cache = *vhigh; 1539 1540 /* read all cent,rmt osc counts (at vhigh) */ 1541 SOC_AVS_FREE_IF_ERROR_RETURN( 1542 _soc_avs_cent_osc_count_get(unit,avs_info->first_cent, 1543 avs_info->num_centrals, 1544 pcount_cent_osc_at_vhigh), alloc_ptr); 1545 SOC_AVS_FREE_IF_ERROR_RETURN( 1546 _soc_avs_rmt_osc_count_get(unit, avs_info->first_rmt, 1547 avs_info->num_remotes, 1548 pcount_rmt_osc_at_vhigh_h, 1549 pcount_rmt_osc_at_vhigh_s), alloc_ptr); 1550 if (pass == 0) { 1551 /* save the v1s values to cache */ 1552 sal_memcpy(avs->cent_v1s_osc_cache, pcount_cent_osc_at_vhigh, 1553 avs_info->num_centrals * sizeof(uint32)); 1554 sal_memcpy(avs->rmt_v1s_h_osc_cache, pcount_rmt_osc_at_vhigh_h, 1555 avs_info->num_remotes * sizeof(uint32)); 1556 sal_memcpy(avs->rmt_v1s_s_osc_cache, pcount_rmt_osc_at_vhigh_s, 1557 avs_info->num_remotes * sizeof(uint32)); 1558 } 1559 } else { 1560 /* restore the v1s value from cache */ 1561 sal_memcpy(pcount_cent_osc_at_vhigh, avs->cent_v1s_osc_cache, 1562 avs_info->num_centrals * sizeof(uint32)); 1563 sal_memcpy(pcount_rmt_osc_at_vhigh_h, avs->rmt_v1s_h_osc_cache, 1564 avs_info->num_remotes * sizeof(uint32)); 1565 sal_memcpy(pcount_rmt_osc_at_vhigh_s, avs->rmt_v1s_s_osc_cache, 1566 avs_info->num_remotes * sizeof(uint32)); 1567 *vhigh = avs->v1r_cache; 1568 } 1569 /* Switch to the 2nd voltage and record the oscillator values 1570 * (low DAC is lower voltage) */ 1571 SOC_AVS_FREE_IF_ERROR_RETURN( 1572 soc_avs_voltage_set(unit, dac_code_low),alloc_ptr); 1573 SOC_AVS_FREE_IF_ERROR_RETURN( 1574 soc_avs_voltage_get(unit, vlow),alloc_ptr); 1575 1576 /* average read-write delta */ 1577 avs_info->rw_delta = (((int)dac_code_high - (int)*vhigh) + 1578 ((int)dac_code_low - (int)*vlow)) 1579 / 2; 1580 1581 if (soc_property_get(unit,"use_rw_delta", 0) == 0){ 1582 avs_info->rw_delta = 0; 1583 } 1584 LOG_VERBOSE(BSL_LS_SOC_AVS, 1585 (BSL_META_U(unit, 1586 "dac_code_high %d dac_code_low %d " 1587 "vhigh %d vlow %d rw_delta %d\n"), 1588 dac_code_high, dac_code_low, *vhigh, *vlow, 1589 avs_info->rw_delta)); 1590 /* Verify that AVS hardware is enabled on this board!. 1591 * If the difference in the two voltages is < 10mV then we don't do 1592 * AVS on this part!. */ 1593 SOC_AVS_ASSERT(*vhigh > *vlow); 1594 if ((*vhigh - *vlow) < SOC_AVS_VHI_VLO_MIN_DIFF) { 1595 LOG_INFO(BSL_LS_SOC_AVS, 1596 (BSL_META_U(unit, 1597 "Voltage diff was < " 1598 "%0d mV -- stopping AVS processing!\n"), 1599 SOC_AVS_VHI_VLO_MIN_DIFF/10)); 1600 sal_free(alloc_ptr); 1601 return (SOC_E_DISABLED); 1602 } 1603 1604 /* read all cent, rmt osc counts (at vlow) */ 1605 SOC_AVS_FREE_IF_ERROR_RETURN( 1606 _soc_avs_cent_osc_count_get(unit, avs_info->first_cent, 1607 avs_info->num_centrals, 1608 pcount_cent_osc_at_vlow), alloc_ptr); 1609 SOC_AVS_FREE_IF_ERROR_RETURN( 1610 _soc_avs_rmt_osc_count_get(unit, avs_info->first_rmt, 1611 avs_info->num_remotes, 1612 pcount_rmt_osc_at_vlow_h, 1613 pcount_rmt_osc_at_vlow_s), alloc_ptr); 1614 1615 /* we want largest predicted voltage across all the usable oscillators */ 1616 v3_max_cent_osc = 0; 1617 LOG_VERBOSE(BSL_LS_SOC_AVS, 1618 (BSL_META_U(unit, 1619 "cent_osc, v1, r_count1, f1, v2, r_count2," 1620 " f2, f3, v3, exclude, h/s\n"))); 1621 for (i = avs_info->first_cent; i < avs_info->num_centrals; i++) { 1622 uint32 freq_at_vhigh, freq_at_vlow; 1623 uint32 f3; 1624 uint32 slope; 1625 uint32 v3; 1626 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_CENTRAL, i)){ 1627 LOG_VERBOSE(BSL_LS_SOC_AVS, 1628 (BSL_META_U(unit, 1629 "%d, %d, %d, -, %d, %d, -, -, -, 1, -\n"), 1630 i, *vhigh, pcount_cent_osc_at_vhigh[i], 1631 *vlow, pcount_cent_osc_at_vlow[i])); 1632 continue; 1633 } 1634 if ((pcount_cent_osc_at_vhigh[i] == 0) || 1635 (pcount_cent_osc_at_vlow[i] == 0)) { 1636 LOG_VERBOSE(BSL_LS_SOC_AVS, 1637 (BSL_META_U(unit, 1638 "%d, %d, %d, -, " 1639 "%d, %d, -, -, -, 0, -\n"), 1640 i, *vhigh, pcount_cent_osc_at_vhigh[i], 1641 *vlow, pcount_cent_osc_at_vlow[i])); 1642 continue; 1643 } 1644 1645 freq_at_vhigh = _soc_avs_reg_to_freq(unit, 1646 pcount_cent_osc_at_vhigh[i]); 1647 freq_at_vlow = _soc_avs_reg_to_freq(unit, 1648 pcount_cent_osc_at_vlow[i]); 1649 1650 SOC_AVS_ASSERT(freq_at_vhigh > freq_at_vlow); 1651 1652 /* m = (f1-f2)/(v1-v2) 1653 * Scaling factor is added to improve accuracy. 1654 * Must remember slope is now in 10,000th */ 1655 slope = (freq_at_vhigh - freq_at_vlow)*SOC_AVS_S2 / (*vhigh - *vlow); 1656 1657 /* read pre-defined freq_threshold (f3) */ 1658 SOC_AVS_FREE_IF_ERROR_RETURN( 1659 _soc_avs_get_cent_osc_ref_freq(unit, i, &f3), alloc_ptr); 1660 1661 /* find v3 corresponding to f3 */ 1662 v3 = _soc_avs_calc_v3_for_ref_f3(freq_at_vlow, *vlow, slope, f3); 1663 1664 avs->saved_voltage[i] = v3; 1665 LOG_VERBOSE(BSL_LS_SOC_AVS, 1666 (BSL_META_U(unit, 1667 "%d, %d, %d, %d, %d, %d, %d, %d, %d, 0, -\n"), 1668 i, *vhigh, pcount_cent_osc_at_vhigh[i], freq_at_vhigh, 1669 *vlow, pcount_cent_osc_at_vlow[i], freq_at_vlow, f3, v3)); 1670 /* max */ 1671 v3_max_cent_osc = SOC_AVS_MAX(v3, v3_max_cent_osc); 1672 } /* for all cent_osc */ 1673 LOG_VERBOSE(BSL_LS_SOC_AVS, 1674 (BSL_META_U(unit, 1675 "Max voltage across " 1676 "Central oscillators = %0d\n"), 1677 v3_max_cent_osc)); 1678 1679 v3_max_rmt_osc = 0; 1680 LOG_VERBOSE(BSL_LS_SOC_AVS, 1681 (BSL_META_U(unit, 1682 "rmt_osc, v1, r_count1, f1, v2, r_count2," 1683 " f2, f3, v3, exclude, h/s\n"))); 1684 for (i = avs_info->first_rmt; i < avs_info->num_remotes; i++) { 1685 uint32 freq_at_vhigh_s, freq_at_vhigh_h; 1686 uint32 freq_at_vlow_s, freq_at_vlow_h; 1687 uint32 f3_s, f3_h; 1688 uint32 slope; 1689 uint32 v3_s, v3_h; 1690 1691 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_REMOTE, i)){ 1692 LOG_VERBOSE(BSL_LS_SOC_AVS, 1693 (BSL_META_U(unit, 1694 "%d, %d, %d, -, %d, %d, -, -, -, 1, h\n"), 1695 i, *vhigh, pcount_rmt_osc_at_vhigh_h[i], 1696 *vlow, pcount_rmt_osc_at_vlow_h[i])); 1697 LOG_VERBOSE(BSL_LS_SOC_AVS, 1698 (BSL_META_U(unit, 1699 "%d, %d, %d, -, %d, %d, -, -, -, 1, s\n"), 1700 i, *vhigh, pcount_rmt_osc_at_vhigh_s[i], 1701 *vlow, pcount_rmt_osc_at_vlow_s[i])); 1702 continue; 1703 } 1704 1705 freq_at_vhigh_h = _soc_avs_reg_to_freq(unit, 1706 pcount_rmt_osc_at_vhigh_h[i]); 1707 freq_at_vhigh_s = _soc_avs_reg_to_freq(unit, 1708 pcount_rmt_osc_at_vhigh_s[i]); 1709 1710 freq_at_vlow_h = _soc_avs_reg_to_freq(unit, 1711 pcount_rmt_osc_at_vlow_h[i]); 1712 freq_at_vlow_s = _soc_avs_reg_to_freq(unit, 1713 pcount_rmt_osc_at_vlow_s[i]); 1714 1715 SOC_AVS_FREE_IF_ERROR_RETURN( 1716 _soc_avs_get_rmt_osc_ref_freq(unit, i, &f3_h, &f3_s), alloc_ptr); 1717 1718 SOC_AVS_ASSERT(freq_at_vhigh_h > freq_at_vlow_h); 1719 slope = (freq_at_vhigh_h - freq_at_vlow_h)*SOC_AVS_S2 / (*vhigh - *vlow); 1720 v3_h = _soc_avs_calc_v3_for_ref_f3(freq_at_vlow_h, *vlow, slope, f3_h); 1721 1722 SOC_AVS_ASSERT(freq_at_vhigh_s > freq_at_vlow_s); 1723 slope = (freq_at_vhigh_s - freq_at_vlow_s)*SOC_AVS_S2 / (*vhigh - *vlow); 1724 v3_s = _soc_avs_calc_v3_for_ref_f3(freq_at_vlow_s, *vlow, slope, f3_s); 1725 1726 1727 LOG_VERBOSE(BSL_LS_SOC_AVS, 1728 (BSL_META_U(unit, 1729 "%d, %d, %d, %d, %d, %d, %d, %d, %d, 0, h\n"), 1730 i, *vhigh, pcount_rmt_osc_at_vhigh_h[i], freq_at_vhigh_h, 1731 *vlow, pcount_rmt_osc_at_vlow_h[i],freq_at_vlow_h, f3_h, 1732 v3_h)); 1733 1734 LOG_VERBOSE(BSL_LS_SOC_AVS, 1735 (BSL_META_U(unit, 1736 "%d, %d, %d, %d, %d, %d, %d, %d, %d, 0, s\n"), 1737 i, *vhigh, pcount_rmt_osc_at_vhigh_s[i], freq_at_vhigh_s, 1738 *vlow, pcount_rmt_osc_at_vlow_s[i],freq_at_vlow_s, f3_s, 1739 v3_s)); 1740 1741 v3_max_rmt_osc = SOC_AVS_MAX(v3_h, v3_max_rmt_osc); 1742 v3_max_rmt_osc = SOC_AVS_MAX(v3_s, v3_max_rmt_osc); 1743 } 1744 LOG_VERBOSE(BSL_LS_SOC_AVS, 1745 (BSL_META_U(unit, 1746 "Max voltage across " 1747 "Remote oscillators = %0d\n"), 1748 v3_max_rmt_osc)); 1749 /* Final Vpred */ 1750 *vpred = SOC_AVS_MAX(v3_max_cent_osc, v3_max_rmt_osc); 1751 1752 sal_free(alloc_ptr); 1753 1754 LOG_INFO(BSL_LS_SOC_AVS, 1755 (BSL_META_U(unit, 1756 "v1s=%0d, v2s=%0d, " 1757 "v1r=%0d, v2r=%0d, vpred=%0d\n"), 1758 dac_code_high, dac_code_low, *vhigh, *vlow, *vpred)); 1759 1760 return (SOC_E_NONE); 1761 } 1762 #define DAC_CALIBRATION 1763 /* 1764 * Function: 1765 * _soc_avs_find_final_voltage 1766 * Purpose: 1767 * Runs avs_predict_vpred, adds margins, sets voltage to computed Vavs 1768 * Parameters: 1769 * vpred - (OUT)Output from _soc_avs_predict_vpred 1770 * vavs_sv - (OUT)Output vpred plus margins 1771 * Returns: 1772 * SOC_E_xxx 1773 */ 1774 STATIC int 1775 _soc_avs_find_final_voltage(int unit, uint32 *vpred, uint32 *vavs_sv) 1776 { 1777 soc_avs_control_t *avs; 1778 soc_avs_info_t *avs_info; 1779 int32 new_vmin_avs; 1780 uint32 ccv; 1781 int32 v2s, v1s; 1782 int pass; 1783 int32 vsum, vavs; 1784 int32 slope_avs, intercept_avs, vmargin; 1785 int32 vmargin_high, vmargin_low; 1786 int32 vlow, vhigh; 1787 #ifdef DAC_CALIBRATION 1788 int32 slope_dac; 1789 int32 avs_dac_code; 1790 #endif 1791 1792 avs = SOC_AVS_CONTROL(unit); 1793 avs_info = SOC_AVS_INFO(unit); 1794 1795 new_vmin_avs = avs_info->vmin_avs; 1796 1797 SOC_AVS_LOCK(avs); 1798 if (SOC_AVS_MARGIN(unit)->vmargin_high){ 1799 vmargin_high = SOC_AVS_MARGIN(unit)->vmargin_high; 1800 } else { 1801 vmargin_high = avs_info->vmargin_high; 1802 } 1803 if (SOC_AVS_MARGIN(unit)->vmargin_low){ 1804 vmargin_low = SOC_AVS_MARGIN(unit)->vmargin_low; 1805 } else { 1806 vmargin_low = avs_info->vmargin_low; 1807 } 1808 slope_avs = ((vmargin_high - vmargin_low)*SOC_AVS_S2) / 1809 ((avs_info->vmax_avs - avs_info->vmin_avs) + 1810 (vmargin_low - vmargin_high)); 1811 avs->slope_margin = slope_avs; 1812 1813 intercept_avs = vmargin_low - 1814 ((slope_avs * (avs_info->vmin_avs - vmargin_low)) / 1815 SOC_AVS_S2); 1816 avs->intercept_margin = intercept_avs; 1817 1818 SOC_AVS_UNLOCK(avs); 1819 /* Read cur_core_voltage (will depend on OTP) */ 1820 SOC_IF_ERROR_RETURN(soc_avs_voltage_get(unit, &ccv)); 1821 1822 /* Determine v1s, v2s (voltage points for local fit) */ 1823 v1s = ccv + SOC_AVS_V1_DIFF; 1824 v2s = v1s - SOC_AVS_V1_MINUS_V2; 1825 1826 LOG_INFO(BSL_LS_SOC_AVS, 1827 (BSL_META_U(unit, 1828 "ccv=%0d, " 1829 "v1s=%0d, v2s=%0d\n"), 1830 ccv, v1s, v2s)); 1831 1832 /* First pass uses rough values (local fit) and the second uses 1833 * the more refined (wider range) values (global fit) */ 1834 for (pass = 0; pass < 2; pass++) { 1835 SOC_IF_ERROR_RETURN(_soc_avs_predict_vpred(unit, pass, v2s, 1836 v1s, vpred, (uint32 *)&vlow, (uint32 *)&vhigh)); 1837 if (*vpred == 0) return 0; 1838 1839 vmargin = (slope_avs * (int32)(*vpred))/SOC_AVS_S2 + intercept_avs; 1840 1841 vsum = (int32)(*vpred) + vmargin; 1842 /* Make sure this is NEVER outside the allowable voltage min/max 1843 * values */ 1844 if (vsum < new_vmin_avs) { 1845 vavs = new_vmin_avs; 1846 } else if (vsum > avs_info->vmax_avs) { 1847 vavs = avs_info->vmax_avs; 1848 } else { 1849 vavs = vsum; 1850 } 1851 LOG_INFO(BSL_LS_SOC_AVS, 1852 (BSL_META_U(unit, 1853 "pass=%0d, " 1854 "vpred=%0d, vavs=%0d, vmargin %0d\n"), 1855 pass, *vpred, vavs, vmargin)); 1856 #ifdef DAC_CALIBRATION 1857 slope_dac = ((v1s - v2s) * SOC_AVS_S2) / (vhigh - vlow); 1858 avs_dac_code = ((slope_dac * vavs) - (slope_dac * vlow))/SOC_AVS_S2 + v2s; 1859 1860 if (vavs < SOC_AVS_VLOW_SS) { 1861 v2s = avs_dac_code + SOC_AVS_V2S_INC_FOR_2ND_PASS; 1862 } 1863 LOG_VERBOSE(BSL_LS_SOC_AVS, 1864 (BSL_META_U(unit, "avs_dac_code calibration " 1865 "slope_dac %d vavs %d avs_dac_code %d " 1866 "v2s %d \n"), 1867 slope_dac, vavs, avs_dac_code, v2s)); 1868 #else 1869 /* On next pass, adjust low value (v2s) to get more precise calculation 1870 * on second pass */ 1871 /* This turns the process from a local fit to a global fit process */ 1872 /* For some chip boot from 0.9V, in below case, no need to do 2nd pass. 1873 orig: if(vavs > 0.94) exit; 1874 change to: voltage diff if(v2s-vavs) < 0.06 exit; */ 1875 if ((v2s - vavs) > SOC_AVS_VLOW_DIFF) { 1876 SOC_AVS_ASSERT(vavs > 0); 1877 v2s = (uint32)vavs + SOC_AVS_V2S_INC_FOR_2ND_PASS; 1878 SOC_AVS_ASSERT(v1s > v2s); 1879 } else { 1880 /* no need to do 2nd pass - because v1s, v2s remain same as 1881 1st pass */ 1882 break; 1883 } 1884 #endif 1885 } 1886 1887 SOC_AVS_ASSERT(vavs > 0); 1888 LOG_INFO(BSL_LS_SOC_AVS, 1889 (BSL_META_U(unit, 1890 "set avs_dac_code %d (vavs %d)\n"), 1891 avs_dac_code, vavs)); 1892 SOC_IF_ERROR_RETURN(soc_avs_voltage_set(unit, (uint32)avs_dac_code)); 1893 if (avs_info->avs_flags & SOC_AVS_INFO_F_USE_LVM_FLAG){ 1894 /* check LVM */ 1895 SOC_AVS_IF_ERROR_NOT_UNAVAIL_RETURN( 1896 soc_avs_ioctl(unit, SOC_AVS_CTRL_LVM_MODE, NULL, 0)); 1897 } 1898 1899 *vavs_sv = (uint32)*vpred; 1900 SOC_IF_ERROR_RETURN(soc_avs_voltage_get(unit, (uint32 *)&vlow)); 1901 LOG_INFO(BSL_LS_SOC_AVS, 1902 (BSL_META_U(unit, "Find Voltage %d\n"), vlow)); 1903 return SOC_E_NONE; 1904 } 1905 1906 /* 1907 * Function: 1908 * _soc_avs_rmt_osc_thr_get 1909 * Purpose: 1910 * Get hi, lo h, s thresholds for specified range of 1911 * remote_oscillators. 1912 * Parameters: 1913 * start_osc - (IN)specifies first remote_osc 1914 * num_osc - (IN)specifies number of remote_osc 1915 * lo_thr_h - (OUT)low threshold_h 1916 * hi_thr_h - (OUT)high threshold_h 1917 * lo_thr_s - (OUT)low threshold_s 1918 * hi_thr_s - (OUT)high threshold_s 1919 * Returns: 1920 * SOC_E_xxx 1921 */ 1922 STATIC int 1923 _soc_avs_rmt_osc_thr_get(int unit, int start_osc, int num_osc, 1924 uint32 *lo_thr_h, uint32 *hi_thr_h, uint32 *lo_thr_s, uint32 *hi_thr_s) 1925 { 1926 int i, cached = 0, n; 1927 soc_avs_control_t *avs; 1928 soc_avs_info_t *avs_info; 1929 1930 avs = SOC_AVS_CONTROL(unit); 1931 avs_info = SOC_AVS_INFO(unit); 1932 1933 if ((lo_thr_h == NULL) || (hi_thr_h == NULL) || (lo_thr_s == NULL) || 1934 (hi_thr_s == NULL)) { 1935 return (SOC_E_PARAM); 1936 } 1937 sal_memset(lo_thr_h, 0, num_osc*(sizeof(*lo_thr_h))); 1938 sal_memset(hi_thr_h, 0, num_osc*(sizeof(*hi_thr_h))); 1939 sal_memset(lo_thr_s, 0, num_osc*(sizeof(*lo_thr_s))); 1940 sal_memset(hi_thr_s, 0, num_osc*(sizeof(*hi_thr_s))); 1941 1942 if (avs_info->avs_flags & 1943 SOC_AVS_INFO_F_RSOC_THRESHOLD_CACHE) { 1944 if ((avs->rmt_h_thr_cache == NULL) || 1945 (avs->rmt_s_thr_cache == NULL)) { 1946 cached = 0; 1947 } else { 1948 cached = 1; 1949 } 1950 } 1951 1952 if (cached) { 1953 sal_memcpy(lo_thr_h, &avs->rmt_h_thr_cache[start_osc], 1954 num_osc * sizeof(uint32)); 1955 sal_memcpy(lo_thr_s, &avs->rmt_s_thr_cache[start_osc], 1956 num_osc * sizeof(uint32)); 1957 } else { 1958 /* read thr_h, thr_s registers */ 1959 for (i = start_osc; i < start_osc + num_osc; i++) { 1960 n = i - start_osc; 1961 if (SOC_AVS_INFO(unit)->avs_flags & 1962 SOC_AVS_INFO_F_DO_NOT_ACCESS_XOSC) { 1963 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_REMOTE, i)){ 1964 continue; 1965 } 1966 } 1967 SOC_IF_ERROR_RETURN( 1968 READ_AVS_REG_PMB_SLAVE_AVS_ROSC_H_THRESHOLDr(unit, i, 1969 &lo_thr_h[n])); 1970 sal_msleep(SOC_AVS_REMOTE_DELAY); 1971 1972 SOC_IF_ERROR_RETURN( 1973 READ_AVS_REG_PMB_SLAVE_AVS_ROSC_S_THRESHOLDr(unit, i, 1974 &lo_thr_s[n])); 1975 sal_msleep(SOC_AVS_REMOTE_DELAY); 1976 } 1977 } 1978 /* extract hi,lo_thr_h from registers */ 1979 for (i = start_osc; i < start_osc + num_osc; i++) { 1980 n = i - start_osc; 1981 if (SOC_AVS_INFO(unit)->avs_flags & 1982 SOC_AVS_INFO_F_DO_NOT_ACCESS_XOSC) { 1983 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_REMOTE, i)){ 1984 hi_thr_h[n] = 0; 1985 lo_thr_h[n] = 0; 1986 hi_thr_s[n] = 0; 1987 lo_thr_s[n] = 0; 1988 continue; 1989 } 1990 } 1991 1992 hi_thr_h[n] = soc_reg_field_get(unit, 1993 AVS_REG_PMB_SLAVE_AVS_ROSC_H_THRESHOLDr, lo_thr_h[n], 1994 THRESH_HIf); 1995 lo_thr_h[n] = soc_reg_field_get(unit, 1996 AVS_REG_PMB_SLAVE_AVS_ROSC_H_THRESHOLDr, lo_thr_h[n], 1997 THRESH_LOf); 1998 hi_thr_s[n] = soc_reg_field_get(unit, 1999 AVS_REG_PMB_SLAVE_AVS_ROSC_S_THRESHOLDr, lo_thr_s[n], 2000 THRESH_HIf); 2001 lo_thr_s[n] = soc_reg_field_get(unit, 2002 AVS_REG_PMB_SLAVE_AVS_ROSC_S_THRESHOLDr, lo_thr_s[n], 2003 THRESH_LOf); 2004 } 2005 return SOC_E_NONE; 2006 } 2007 2008 /* 2009 * Function: 2010 * _soc_avs_cent_osc_thr_get 2011 * Purpose: 2012 * Get hi, lo counter thresholds for specified range of central 2013 * oscillators 2014 * Parameters: 2015 * start_osc - (IN)specifies first remote_osc 2016 * num_osc - (IN)specifies number of remote_osc 2017 * lo_thr - (OUT)low threshold 2018 * hi_thr - (OUT)high threshold 2019 * Returns: 2020 * SOC_E_xxx 2021 */ 2022 STATIC int 2023 _soc_avs_cent_osc_thr_get(int unit, int start_osc, int num_osc, 2024 uint32 *lo_thr, uint32 *hi_thr) 2025 { 2026 int i, cached = 0, n = 0; 2027 soc_avs_control_t *avs; 2028 soc_avs_info_t *avs_info; 2029 2030 avs = SOC_AVS_CONTROL(unit); 2031 avs_info = SOC_AVS_INFO(unit); 2032 2033 if ((lo_thr == NULL) || (hi_thr == NULL)) { 2034 return (SOC_E_PARAM); 2035 } 2036 sal_memset(lo_thr, 0, num_osc*(sizeof(*lo_thr))); 2037 sal_memset(hi_thr, 0, num_osc*(sizeof(*hi_thr))); 2038 2039 if (avs_info->avs_flags & 2040 SOC_AVS_INFO_F_RSOC_THRESHOLD_CACHE) { 2041 if ((avs->cent_lo_thr_cache == NULL) || 2042 (avs->cent_hi_thr_cache == NULL)) { 2043 cached = 0; 2044 } else { 2045 cached = 1; 2046 } 2047 } 2048 if (cached) { 2049 sal_memcpy(lo_thr, &avs->cent_lo_thr_cache[start_osc], 2050 num_osc * sizeof(uint32)); 2051 sal_memcpy(hi_thr, &avs->cent_hi_thr_cache[start_osc], 2052 num_osc * sizeof(uint32)); 2053 } else { 2054 /* read lo_thr, hi_thr reg */ 2055 for (i = start_osc; i < start_osc + num_osc; i++) { 2056 n = i - start_osc; 2057 if (avs_info->avs_flags & 2058 SOC_AVS_INFO_F_DO_NOT_ACCESS_XOSC) { 2059 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_CENTRAL, i)){ 2060 continue; 2061 } 2062 } 2063 SOC_IF_ERROR_RETURN( 2064 READ_AVS_REG_ROSC_THRESHOLD_1_THRESHOLD1_CEN_ROSCr( 2065 unit, i, &lo_thr[n])); 2066 2067 SOC_IF_ERROR_RETURN( 2068 READ_AVS_REG_ROSC_THRESHOLD_2_THRESHOLD2_CEN_ROSCr( 2069 unit, i, &hi_thr[n])); 2070 } 2071 } 2072 /* Extract threshold field from registers */ 2073 for (i = start_osc; i < start_osc + num_osc; i++) { 2074 n = i - start_osc; 2075 if (avs_info->avs_flags & 2076 SOC_AVS_INFO_F_DO_NOT_ACCESS_XOSC) { 2077 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_CENTRAL, i)){ 2078 lo_thr[n] = 0; 2079 hi_thr[n] = 0; 2080 continue; 2081 } 2082 } 2083 lo_thr[n] = soc_reg_field_get(unit, 2084 AVS_REG_ROSC_THRESHOLD_1_THRESHOLD1_CEN_ROSCr, lo_thr[n], 2085 THRESHOLDf); 2086 hi_thr[n] = soc_reg_field_get(unit, 2087 AVS_REG_ROSC_THRESHOLD_2_THRESHOLD2_CEN_ROSCr, hi_thr[n], 2088 THRESHOLDf); 2089 } 2090 return SOC_E_NONE; 2091 } 2092 2093 #define _W_OP_HI 1 2094 #define _W_OP_LO 2 2095 #define _W_OP_ALL 3 2096 /* 2097 * Function: 2098 * _soc_avs_rmt_osc_thr_set 2099 * Purpose: 2100 * Fill hi/lo s_, h_ thresholds into specified range of remote osc. 2101 * SAME value is copied into all registers. 2102 * Parameters: 2103 * start_osc - (IN)specifies first remote_osc 2104 * num_osc - (IN)specifies number of remote_osc 2105 * write_op - (IN)specifies write fields of the register 2106 * regval_h - (IN)value to be programmed in ROSC_H_THRESHOLD register 2107 * regval_s - (IN)value to be programmed in ROSC_S_THRESHOLD register 2108 * Returns: 2109 * SOC_E_xxx 2110 */ 2111 2112 STATIC int 2113 _soc_avs_rmt_osc_thr_set(int unit, int start_osc, int num_osc, 2114 int write_op, 2115 uint32 regval_h, uint32 regval_s) 2116 { 2117 int i, cached = 0; 2118 soc_avs_control_t *avs; 2119 soc_avs_info_t *avs_info; 2120 uint32 thr_h, thr_s; 2121 2122 avs = SOC_AVS_CONTROL(unit); 2123 avs_info = SOC_AVS_INFO(unit); 2124 2125 if (avs_info->avs_flags & 2126 SOC_AVS_INFO_F_RSOC_THRESHOLD_CACHE) { 2127 if ((avs->rmt_h_thr_cache == NULL) || 2128 (avs->rmt_s_thr_cache == NULL)) { 2129 cached = 0; 2130 } else { 2131 cached = 1; 2132 } 2133 } 2134 /* write (same) regval_h, regval_s to all registers */ 2135 for (i = start_osc; i < start_osc + num_osc; i++) { 2136 if (SOC_AVS_INFO(unit)->avs_flags & 2137 SOC_AVS_INFO_F_DO_NOT_ACCESS_XOSC) { 2138 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_REMOTE, i)){ 2139 continue; 2140 } 2141 } 2142 SOC_IF_ERROR_RETURN( 2143 READ_AVS_REG_PMB_SLAVE_AVS_ROSC_H_THRESHOLDr(unit, i, 2144 &thr_h)); 2145 sal_msleep(SOC_AVS_REMOTE_DELAY); 2146 2147 SOC_IF_ERROR_RETURN( 2148 READ_AVS_REG_PMB_SLAVE_AVS_ROSC_S_THRESHOLDr(unit, i, 2149 &thr_s)); 2150 sal_msleep(SOC_AVS_REMOTE_DELAY); 2151 2152 if (write_op == _W_OP_HI) { 2153 soc_reg_field_set(unit, AVS_REG_PMB_SLAVE_AVS_ROSC_H_THRESHOLDr, 2154 &thr_h, THRESH_HIf, regval_h); 2155 soc_reg_field_set(unit, AVS_REG_PMB_SLAVE_AVS_ROSC_S_THRESHOLDr, 2156 &thr_s, THRESH_HIf, regval_s); 2157 } else if (write_op == _W_OP_LO) { 2158 soc_reg_field_set(unit, AVS_REG_PMB_SLAVE_AVS_ROSC_H_THRESHOLDr, 2159 &thr_h, THRESH_LOf, regval_h); 2160 soc_reg_field_set(unit, AVS_REG_PMB_SLAVE_AVS_ROSC_S_THRESHOLDr, 2161 &thr_s, THRESH_LOf, regval_s); 2162 } else { 2163 thr_h = regval_h; 2164 thr_s = regval_s; 2165 } 2166 SOC_IF_ERROR_RETURN( 2167 WRITE_AVS_REG_PMB_SLAVE_AVS_ROSC_H_THRESHOLDr(unit, i, thr_h)); 2168 sal_msleep(SOC_AVS_REMOTE_DELAY); 2169 SOC_IF_ERROR_RETURN( 2170 WRITE_AVS_REG_PMB_SLAVE_AVS_ROSC_S_THRESHOLDr(unit, i, thr_s)); 2171 sal_msleep(SOC_AVS_REMOTE_DELAY); 2172 if (cached) { 2173 avs->rmt_h_thr_cache[i] = thr_h; 2174 avs->rmt_s_thr_cache[i] = thr_s; 2175 } 2176 } 2177 return SOC_E_NONE; 2178 } 2179 2180 /* 2181 * Function: 2182 * _soc_avs_cent_osc_thr_set 2183 * Purpose: 2184 * Program hi/lo threshold for specified range of central osc. 2185 * Unique values can be specified for each osc. 2186 * Parameters: 2187 * start_osc - (IN)specifies first remote_osc 2188 * num_osc - (IN)specifies number of remote_osc 2189 * sel_hi_thr - (IN)when true means program hi_threshold 2190 * regval - (IN)array of values to be written into threshold registers 2191 * Returns: 2192 * SOC_E_xxx 2193 */ 2194 STATIC int 2195 _soc_avs_cent_osc_thr_set(int unit, int start_osc, int num_osc, 2196 soc_avs_bool_t sel_hi_thr, const uint32 *regval) 2197 { 2198 int i, cached = 0, n; 2199 soc_avs_control_t *avs; 2200 soc_avs_info_t *avs_info; 2201 2202 avs = SOC_AVS_CONTROL(unit); 2203 avs_info = SOC_AVS_INFO(unit); 2204 2205 if (regval == NULL) { 2206 return (SOC_E_PARAM); 2207 } 2208 if (avs_info->avs_flags & 2209 SOC_AVS_INFO_F_RSOC_THRESHOLD_CACHE) { 2210 if ((avs->cent_lo_thr_cache == NULL) || 2211 (avs->cent_hi_thr_cache == NULL)) { 2212 cached = 0; 2213 } else { 2214 cached = 1; 2215 } 2216 } 2217 2218 for (i = start_osc; i < start_osc + num_osc; i++) { 2219 n = i - start_osc; 2220 if (avs_info->avs_flags & 2221 SOC_AVS_INFO_F_DO_NOT_ACCESS_XOSC) { 2222 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_CENTRAL, i)){ 2223 continue; 2224 } 2225 } 2226 if (sel_hi_thr == SOC_AVS_BOOL_TRUE) { 2227 SOC_IF_ERROR_RETURN( 2228 WRITE_AVS_REG_ROSC_THRESHOLD_2_THRESHOLD2_CEN_ROSCr(unit, i, 2229 regval[n])); 2230 if (cached) { 2231 avs->cent_hi_thr_cache[i] = regval[n]; 2232 } 2233 } else { 2234 SOC_IF_ERROR_RETURN( 2235 WRITE_AVS_REG_ROSC_THRESHOLD_1_THRESHOLD1_CEN_ROSCr(unit, i, 2236 regval[n])); 2237 if (cached) { 2238 avs->cent_lo_thr_cache[i] = regval[n]; 2239 } 2240 } 2241 } 2242 return SOC_E_NONE; 2243 } 2244 2245 #if AVS_LEGACY_THRESHOLD 2246 /* 2247 * Function: 2248 * _soc_avs_find_new_thr 2249 * Purpose: 2250 * Reads osc_counts, determines lowest_osc_count and programs osc_thresholds. 2251 * Is a helper function for _soc_avs_set_new_thr. 2252 * Parameters: 2253 * sel_hi_thr - (IN)1 => hi_thr, 0 => lo_thr 2254 * write_rmt_osc_thr - (IN)1 => write rmt_osc_thr 2255 * alloc_ptr - (OUT)points to area in mem to store osc_counts temporarily 2256 * rmt_osc_regval_h - (OUT)rmt_osc_regval_h 2257 * rmt_osc_regval_s - (OUT)rmt_osc_regval_s 2258 * Returns: 2259 * SOC_E_xxx 2260 */ 2261 STATIC int 2262 _soc_avs_find_new_thr(int unit, soc_avs_bool_t sel_hi_thr, 2263 int write_rmt_osc_thr, uint32 *alloc_ptr, 2264 uint32 *rmt_osc_regval_h, uint32 *rmt_osc_regval_s) 2265 { 2266 soc_avs_info_t *avs_info; 2267 uint32 *rmt_osc_count_s = NULL, *rmt_osc_count_h = NULL, 2268 *cent_osc_count = NULL, *cent_osc_thr = NULL; 2269 uint32 lowest_count_s = SOC_AVS_ALL_ONES; 2270 uint32 lowest_count_h = SOC_AVS_ALL_ONES; 2271 int i; 2272 2273 avs_info = SOC_AVS_INFO(unit); 2274 2275 if ((alloc_ptr == NULL) || (rmt_osc_regval_h == NULL) || 2276 (rmt_osc_regval_s == NULL)) { 2277 return (SOC_E_PARAM); 2278 } 2279 2280 /* Read osc_count for remote oscillators and find lowest */ 2281 rmt_osc_count_s = alloc_ptr; 2282 rmt_osc_count_h = rmt_osc_count_s + avs_info->num_remotes; 2283 SOC_AVS_FREE_IF_ERROR_RETURN( 2284 _soc_avs_rmt_osc_count_get(unit, 2285 avs_info->first_rmt, avs_info->num_remotes, 2286 rmt_osc_count_h, rmt_osc_count_s), 2287 alloc_ptr); 2288 for (i = avs_info->first_rmt; i < avs_info->num_remotes; i++) { 2289 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_REMOTE, i)){ 2290 continue; 2291 } 2292 if (rmt_osc_count_s[i] != 0) { 2293 lowest_count_s = SOC_AVS_MIN(lowest_count_s, rmt_osc_count_s[i]); 2294 } 2295 if (rmt_osc_count_h[i] != 0) { 2296 lowest_count_h = SOC_AVS_MIN(lowest_count_h, rmt_osc_count_h[i]); 2297 } 2298 } 2299 /* Read osc_count for central oscillators and find lowest */ 2300 cent_osc_count = alloc_ptr; 2301 SOC_IF_ERROR_RETURN( 2302 _soc_avs_cent_osc_count_get(unit, 2303 avs_info->first_cent, 2304 avs_info->num_centrals, cent_osc_count)); 2305 for (i = 0; i < avs_info->num_centrals; i++) { 2306 /* In 28nm , only oscillators 1&3 are SVT and HVT types */ 2307 /* So we can include only them in finding lowest oscillator count */ 2308 if (i != 1 && i != 3) { 2309 continue; /*skip others*/ 2310 } 2311 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_CENTRAL, i)){ 2312 continue; 2313 } 2314 if (cent_osc_count[i] == 0) { 2315 continue; 2316 } 2317 if (i == 1) { 2318 lowest_count_s = SOC_AVS_MIN(lowest_count_s, cent_osc_count[i]); 2319 } 2320 if (i == 3) { 2321 lowest_count_h = SOC_AVS_MIN(lowest_count_h, cent_osc_count[i]); 2322 } 2323 } 2324 /* update thresholds for rmt_osc */ 2325 if (sel_hi_thr == SOC_AVS_BOOL_TRUE) { 2326 soc_reg_field_set(unit, AVS_REG_PMB_SLAVE_AVS_ROSC_H_THRESHOLDr, 2327 rmt_osc_regval_h, THRESH_HIf, lowest_count_h); 2328 soc_reg_field_set(unit, AVS_REG_PMB_SLAVE_AVS_ROSC_S_THRESHOLDr, 2329 rmt_osc_regval_s, THRESH_HIf, lowest_count_s); 2330 } else { 2331 soc_reg_field_set(unit, AVS_REG_PMB_SLAVE_AVS_ROSC_H_THRESHOLDr, 2332 rmt_osc_regval_h, THRESH_LOf, lowest_count_h); 2333 soc_reg_field_set(unit, AVS_REG_PMB_SLAVE_AVS_ROSC_S_THRESHOLDr, 2334 rmt_osc_regval_s, THRESH_LOf, lowest_count_s); 2335 } 2336 2337 cent_osc_thr = cent_osc_count; 2338 for (i = avs_info->first_cent; i < avs_info->num_centrals; i++) { 2339 /* Central #1 is SVT and #3 is HVT */ 2340 if (i == 1) { 2341 cent_osc_thr[i] = lowest_count_s; 2342 } else if (i == 3) { 2343 cent_osc_thr[i] = lowest_count_h; 2344 } else { 2345 cent_osc_thr[i] = cent_osc_count[i]; 2346 } 2347 if (sel_hi_thr == SOC_AVS_BOOL_TRUE) { 2348 soc_reg_field_set(unit, 2349 AVS_REG_ROSC_THRESHOLD_2_THRESHOLD2_CEN_ROSCr, 2350 cent_osc_count + i, THRESHOLDf, cent_osc_thr[i]); 2351 } else { 2352 soc_reg_field_set(unit, 2353 AVS_REG_ROSC_THRESHOLD_1_THRESHOLD1_CEN_ROSCr, 2354 cent_osc_count + i, THRESHOLDf, cent_osc_thr[i]); 2355 } 2356 } 2357 /* write thresholds for cent_osc */ 2358 SOC_IF_ERROR_RETURN( 2359 _soc_avs_cent_osc_thr_set(unit, avs_info->first_cent, 2360 avs_info->num_centrals, sel_hi_thr, 2361 cent_osc_count)); 2362 2363 /* write thresholds for rmt_osc */ 2364 if (write_rmt_osc_thr) { 2365 SOC_IF_ERROR_RETURN( 2366 _soc_avs_rmt_osc_thr_set(unit, 2367 avs_info->first_rmt, avs_info->num_remotes, 2368 _W_OP_ALL, 2369 *rmt_osc_regval_h, *rmt_osc_regval_s)); 2370 } 2371 2372 return SOC_E_NONE; 2373 } 2374 #endif /* AVS_LEGACY_THRESHOLD */ 2375 2376 #define SOC_AVS_VINC_FOR_SET_NEW_THR_STEP (16) 2377 2378 STATIC int 2379 _soc_avs_set_new_thresholds(int unit) 2380 { 2381 soc_avs_control_t *avs; 2382 soc_avs_info_t *avs_info; 2383 int32 vmarginl, vmarginh, slope_margin, intercept_margin; 2384 uint32 reg, freq; 2385 uint32 lower1, upper1, lower3, upper3; 2386 int i; 2387 2388 avs = SOC_AVS_CONTROL(unit); 2389 avs_info = SOC_AVS_INFO(unit); 2390 slope_margin = avs->slope_margin; 2391 intercept_margin = avs->intercept_margin; 2392 LOG_VERBOSE(BSL_LS_SOC_AVS, 2393 (BSL_META_U(unit, 2394 "slope_margin %d intercept margin %d\n"), 2395 slope_margin, intercept_margin)); 2396 LOG_VERBOSE(BSL_LS_SOC_AVS, 2397 (BSL_META_U(unit, 2398 "i, saved_voltage, vmarginl, vmarginh," 2399 " cen_freq_thr, freq_l, reg_l, freq_h, reg_h "))); 2400 2401 for (i = avs_info->first_cent; i < avs_info->num_centrals; i++) { 2402 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_CENTRAL, i)){ 2403 continue; 2404 } 2405 vmarginl = (slope_margin * avs->saved_voltage[i]) / SOC_AVS_S2 + 2406 intercept_margin; 2407 /* high is 10mV higher than low */ 2408 vmarginh = vmarginl + avs->new_thr_inc; 2409 2410 LOG_VERBOSE(BSL_LS_SOC_AVS, 2411 (BSL_META_U(unit, "%d, %d, %d, %d, %d "), 2412 i, avs->saved_voltage[i], vmarginl, vmarginh, 2413 avs->cen_freq_thr[i])); 2414 2415 freq = avs->cen_freq_thr[i] + 2416 (avs->cen_fth_slope[i] * vmarginl) / SOC_AVS_S2; 2417 reg = _soc_avs_freq_to_reg(unit, freq); 2418 SOC_IF_ERROR_RETURN( 2419 _soc_avs_cent_osc_thr_set(unit, i, 1, SOC_AVS_BOOL_FALSE, ®)); 2420 2421 LOG_VERBOSE(BSL_LS_SOC_AVS, 2422 (BSL_META_U(unit, "%d, %d, "), freq, reg)); 2423 2424 freq = avs->cen_freq_thr[i] + 2425 (avs->cen_fth_slope[i] * vmarginh) / SOC_AVS_S2; 2426 reg = _soc_avs_freq_to_reg(unit, freq); 2427 SOC_IF_ERROR_RETURN( 2428 _soc_avs_cent_osc_thr_set(unit, i, 1, SOC_AVS_BOOL_TRUE, ®)); 2429 2430 LOG_VERBOSE(BSL_LS_SOC_AVS, 2431 (BSL_META_U(unit, "%d, %d \n"), freq, reg)); 2432 } 2433 2434 /* All the remotes are same types as centrals 1 & 3 */ 2435 SOC_IF_ERROR_RETURN( 2436 _soc_avs_cent_osc_thr_get(unit, 1, 1, &lower1, &upper1)); 2437 SOC_IF_ERROR_RETURN( 2438 _soc_avs_cent_osc_thr_get(unit, 3, 1, &lower3, &upper3)); 2439 2440 LOG_VERBOSE(BSL_LS_SOC_AVS, 2441 (BSL_META_U(unit, "lower1 %d upper1 %d lower3 %d upper3 %d\n"), 2442 lower1, upper1, lower3, upper3)); 2443 2444 for (i = avs_info->first_rmt; i < avs_info->num_remotes; i++) { 2445 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_REMOTE, i)){ 2446 continue; 2447 } 2448 SOC_IF_ERROR_RETURN( 2449 _soc_avs_rmt_osc_thr_set(unit, i, 1, _W_OP_LO, lower3, lower1)); 2450 SOC_IF_ERROR_RETURN( 2451 _soc_avs_rmt_osc_thr_set(unit, i, 1, _W_OP_HI, upper3, upper1)); 2452 } 2453 avs->flags |= SOC_AVS_F_THRESHOLD_SET; 2454 return SOC_E_NONE; 2455 } 2456 2457 #if AVS_LEGACY_THRESHOLD 2458 /* 2459 * Function: 2460 * _soc_avs_set_new_thr 2461 * Purpose: 2462 * Finds lowest_count for cur_dac_code and sets lo_thr for all osc to 2463 * this value. Changes voltage to cur_dac_code+OFFSET, finds new lowest_count 2464 * and sets hi_thr for all osc to this value. 2465 * Parameters: 2466 * vavs_sv - (IN)Voltage at which lo_thr is determined. 2467 * Returns: 2468 * SOC_E_xxx 2469 */ 2470 STATIC int 2471 _soc_avs_set_new_thr(int unit, uint32 vavs_sv) 2472 { 2473 uint32 current_voltage; /* current_dac; */ 2474 uint32 read_voltage; 2475 soc_avs_bool_t sel_hi_thr, write_rmt_osc_thr; 2476 uint32 rmt_osc_regval_h, rmt_osc_regval_s; 2477 int alloc_size; 2478 uint32 *alloc_ptr = NULL; 2479 soc_avs_info_t *avs_info = SOC_AVS_INFO(unit); 2480 soc_avs_control_t *avs = SOC_AVS_CONTROL(unit); 2481 2482 if ((SOC_AVS_INFO(unit)->avs_flags & SOC_AVS_INFO_F_SET_THRESHOLDS) == 0) { 2483 return (SOC_E_NONE); 2484 } 2485 2486 /* allocate memory */ 2487 alloc_size = 2 * SOC_AVS_MAX(avs_info->num_centrals, avs_info->num_remotes) * 2488 sizeof(uint32); 2489 if ((alloc_ptr = (uint32 *)sal_alloc(alloc_size, 2490 "Storage for _soc_avs_set_new_thr")) == NULL) { 2491 return (SOC_E_MEMORY); 2492 } 2493 /* Set the lo_thr with the smallest count found at current (low) voltage */ 2494 /* Find_and_write lo_thr for cent, find_only lo_thr for rmt */ 2495 rmt_osc_regval_h = 0, rmt_osc_regval_s = 0; 2496 2497 /* get threshold low based on vavs + rw_delta */ 2498 current_voltage = vavs_sv + avs_info->rw_delta; 2499 SOC_IF_ERROR_RETURN(soc_avs_voltage_set(unit, (uint32)current_voltage)); 2500 2501 if (LOG_CHECK(BSL_LS_SOC_AVS|BSL_VERBOSE)) { 2502 SOC_AVS_FREE_IF_ERROR_RETURN( 2503 soc_avs_voltage_get(unit, &read_voltage), alloc_ptr); 2504 } 2505 2506 SOC_AVS_FREE_IF_ERROR_RETURN( 2507 _soc_avs_find_new_thr(unit, sel_hi_thr = SOC_AVS_BOOL_FALSE, 2508 write_rmt_osc_thr = FALSE, alloc_ptr, 2509 &rmt_osc_regval_h, &rmt_osc_regval_s), 2510 alloc_ptr); 2511 2512 /* Now, raise the DAC (raise the voltage) to figure out the hi_thr value */ 2513 /* get threshold high based on vavs + rw_delta + new_thr_inc */ 2514 current_voltage += avs->new_thr_inc; 2515 2516 LOG_INFO(BSL_LS_SOC_AVS, 2517 (BSL_META_U(unit, 2518 "set voltage %d to set hi threshold\n"), 2519 current_voltage)); 2520 2521 SOC_AVS_FREE_IF_ERROR_RETURN( 2522 soc_avs_voltage_set(unit, current_voltage), alloc_ptr); 2523 if (LOG_CHECK(BSL_LS_SOC_AVS|BSL_VERBOSE)) { 2524 SOC_AVS_FREE_IF_ERROR_RETURN( 2525 soc_avs_voltage_get(unit, &read_voltage), alloc_ptr); 2526 } 2527 /* Set the hi_thr with the smallest count found at higher voltage */ 2528 /* Find_and_write hi_thr for cent, 2529 * find hi_thr for rmt, write hi_lo_thr for rmt */ 2530 SOC_AVS_FREE_IF_ERROR_RETURN( 2531 _soc_avs_find_new_thr(unit, sel_hi_thr = SOC_AVS_BOOL_TRUE, 2532 write_rmt_osc_thr = TRUE, alloc_ptr, 2533 &rmt_osc_regval_h, &rmt_osc_regval_s), 2534 alloc_ptr); 2535 2536 sal_free(alloc_ptr); 2537 2538 avs->flags |= SOC_AVS_F_THRESHOLD_SET; 2539 return (SOC_E_NONE); 2540 } 2541 #endif 2542 2543 /* 2544 * Function: 2545 * _soc_avs_start_main 2546 * Purpose: 2547 * Runs initialize_oscs, find_final_voltage, set_new_thr. 2548 * Parameters: 2549 * 2550 * Returns: 2551 * SOC_E_xxx 2552 */ 2553 STATIC int 2554 _soc_avs_start_main(int unit) 2555 { 2556 uint32 vpred = 0, vavs_sv = 0; 2557 2558 SOC_IF_ERROR_RETURN(_soc_avs_initialize_oscs(unit)); 2559 2560 SOC_IF_ERROR_RETURN(_soc_avs_find_final_voltage(unit, &vpred, &vavs_sv)); 2561 if (vpred == 0) { 2562 LOG_WARN(BSL_LS_SOC_AVS, 2563 (BSL_META_U(unit, "get the vpred=0\n"))); 2564 return (SOC_E_DISABLED); 2565 } 2566 2567 #if AVS_LEGACY_THRESHOLD 2568 SOC_IF_ERROR_RETURN(_soc_avs_set_new_thr(unit, vavs_sv)); 2569 #endif 2570 SOC_IF_ERROR_RETURN(_soc_avs_set_new_thresholds(unit)); 2571 2572 return (SOC_E_NONE); 2573 } 2574 2575 2576 /* This is the main entry point for AVS processing */ 2577 /* This is one-time routine that must be called during init.*/ 2578 int 2579 soc_avs_start(int unit) 2580 { 2581 if (!soc_avs_inited(unit)) { 2582 return SOC_E_INIT; 2583 } 2584 SOC_IF_ERROR_RETURN(_soc_avs_start_main(unit)); 2585 return (SOC_E_NONE); 2586 } 2587 2588 /* System VRM access function registeration */ 2589 int 2590 soc_avs_vrm_access_func_register(int unit, soc_avs_vrm_access_t *vrm_access) 2591 { 2592 soc_avs_control_t *avs; 2593 2594 soc_vrm_access_functions[unit] = vrm_access; 2595 if (SOC_AVS_CONTROL(unit) != NULL) { 2596 avs = SOC_AVS_CONTROL(unit); 2597 avs->vrm_access = vrm_access; 2598 } 2599 return SOC_E_NONE; 2600 } 2601 2602 /* 2603 * Default vrm info when vrm access functions are not specified. 2604 * The default vrm should be pmbus compatiable device which driver is 2605 * implemented in soc i2c device descriptor scheme. 2606 */ 2607 static int 2608 soc_avs_vrm_info_init(int unit, soc_avs_vrm_info_t *vrm_info) 2609 { 2610 int dev_id = 0; 2611 int fd, rv; 2612 i2c_driver_t *i2c_drv; 2613 2614 if (vrm_info == NULL) { 2615 return SOC_E_PARAM; 2616 } 2617 2618 if (!(vrm_info->profile.vrm_name)) { 2619 return SOC_E_PARAM; 2620 } 2621 vrm_info->mux_id = -1; 2622 vrm_info->vrm_id = -1; 2623 2624 /* Access the device to check if it exists or not. */ 2625 if (vrm_info->profile.mux_name[0] != '\0') { 2626 dev_id = soc_i2c_devopen(unit, vrm_info->profile.mux_name, 0, 0); 2627 if (dev_id < 0) { 2628 LOG_ERROR(BSL_LS_SOC_AVS, 2629 (BSL_META_U(unit, "Fail to open mux in VRM profile.\n"))); 2630 return SOC_E_FAIL; 2631 } 2632 vrm_info->mux_id = dev_id; 2633 } 2634 /* Enable mux when both mux device and its enable vlaue are specified */ 2635 if ((vrm_info->mux_id != -1) && (vrm_info->profile.mux_enable_value)) { 2636 fd = vrm_info->mux_id; 2637 i2c_drv = soc_i2c_device(unit, fd)->driver; 2638 rv = i2c_drv->write(unit, vrm_info->mux_id, 0, 2639 &vrm_info->profile.mux_enable_value, 1); 2640 if (SOC_FAILURE(rv)) { 2641 LOG_ERROR(BSL_LS_SOC_AVS, 2642 (BSL_META_U(unit, 2643 "Fail to enable mux in VRM profile.\n"))); 2644 return rv; 2645 } 2646 } 2647 2648 if (vrm_info->profile.vrm_name[0] != '\0') { 2649 dev_id = soc_i2c_devopen(unit, vrm_info->profile.vrm_name, 0, 0); 2650 if (dev_id < 0) { 2651 LOG_ERROR(BSL_LS_SOC_AVS, 2652 (BSL_META_U(unit, "Fail to open vrm in VRM profile.\n"))); 2653 return SOC_E_FAIL; 2654 } 2655 vrm_info->vrm_id = dev_id; 2656 } 2657 2658 return SOC_E_NONE; 2659 } 2660 2661 /* Specify the vrm as the default vrm */ 2662 int 2663 soc_avs_vrm_profile_add(int unit, soc_avs_vrm_profile_t *vrm_profile) 2664 { 2665 soc_avs_vrm_info_t *vrm_info; 2666 2667 if (SOC_AVS_CONTROL(unit) == NULL) { 2668 return SOC_E_INIT; 2669 } 2670 /* Only allow one vrm profile, new one will replace the old one */ 2671 if (SOC_AVS_VRM_INFO(unit) == NULL) { 2672 vrm_info = sal_alloc(sizeof(soc_avs_vrm_info_t), "avs vrm"); 2673 if (vrm_info == NULL) { 2674 return SOC_E_MEMORY; 2675 } 2676 SOC_AVS_VRM_INFO(unit) = vrm_info; 2677 } else { 2678 LOG_WARN(BSL_LS_SOC_AVS, 2679 (BSL_META_U(unit, "VRM profile has been replaced \n"))); 2680 } 2681 2682 sal_memcpy(&SOC_AVS_VRM_INFO(unit)->profile, vrm_profile, 2683 sizeof(soc_avs_vrm_profile_t)); 2684 2685 return SOC_E_NONE; 2686 } 2687 2688 /* 2689 * VRM initialization function 2690 * If default vrm is not available or compatable with i2c pmbus driver, 2691 * user has to register its vrm access functions. 2692 */ 2693 int 2694 soc_avs_vrm_init(int unit) 2695 { 2696 /* Check the custom registered access function */ 2697 if (SOC_AVS_VRM_ACCESS(unit) != NULL) { 2698 if (SOC_AVS_VRM_ACCESS(unit)->vrm_init != NULL) { 2699 return SOC_AVS_VRM_ACCESS(unit)->vrm_init(unit); 2700 } 2701 } 2702 /* Try to use the pmbus vrm */ 2703 if (SOC_AVS_VRM_INFO(unit) != NULL) { 2704 return soc_avs_vrm_info_init(unit, SOC_AVS_VRM_INFO(unit)); 2705 } 2706 return SOC_E_UNAVAIL; 2707 } 2708 2709 int 2710 soc_avs_vrm_deinit(int unit) 2711 { 2712 int rv; 2713 2714 /* Check the custom registered access function */ 2715 if (SOC_AVS_VRM_ACCESS(unit) != NULL) { 2716 if (SOC_AVS_VRM_ACCESS(unit)->vrm_deinit != NULL) { 2717 rv = SOC_AVS_VRM_ACCESS(unit)->vrm_deinit(unit); 2718 if (SOC_FAILURE(rv)) { 2719 return rv; 2720 } 2721 } 2722 } 2723 /* Try to use the pmbus vrm */ 2724 if (SOC_AVS_VRM_INFO(unit) != NULL) { 2725 sal_free(SOC_AVS_VRM_INFO(unit)); 2726 SOC_AVS_VRM_INFO(unit) = NULL; 2727 } 2728 return SOC_E_NONE; 2729 } 2730 2731 /* Get the device openloop target voltage */ 2732 int 2733 soc_avs_openloop_voltage_get(int unit, uint32 *voltage) 2734 { 2735 if ((SOC_AVS_FUNCTIONS(unit) != NULL) && 2736 (SOC_AVS_FUNCTIONS(unit)->openloop_voltage_get != NULL)) { 2737 return SOC_AVS_FUNCTIONS(unit)->openloop_voltage_get(unit, voltage); 2738 } 2739 return SOC_E_UNAVAIL; 2740 } 2741 2742 int 2743 soc_avs_openloop_main(int unit) 2744 { 2745 int rv; 2746 uint32 voltage; 2747 2748 if (SOC_AVS_CONTROL(unit) == NULL) { 2749 return SOC_E_UNAVAIL; 2750 } 2751 if ((SOC_AVS_CONTROL(unit)->flags & SOC_AVS_F_VRM_INITED) == 0) { 2752 rv = soc_avs_vrm_init(unit); 2753 if (SOC_FAILURE(rv)) { 2754 LOG_ERROR(BSL_LS_SOC_AVS, 2755 (BSL_META_U(unit, "Fail to init VRM !\n"))); 2756 return rv; 2757 } 2758 SOC_AVS_CONTROL(unit)->flags |= SOC_AVS_F_VRM_INITED; 2759 } 2760 rv = soc_avs_openloop_voltage_get(unit, &voltage); 2761 if (SOC_FAILURE(rv)) { 2762 return rv; 2763 } 2764 rv = soc_avs_voltage_set(unit, voltage); 2765 if (SOC_FAILURE(rv)) { 2766 return rv; 2767 } 2768 /* need to sleep a while to stabelize the voltage */ 2769 sal_usleep(SOC_AVS_OPENLOOP_DELAY); 2770 return SOC_E_NONE; 2771 } 2772 2773 /* 2774 * Function: 2775 * soc_avs_function_register 2776 * Purpose: 2777 * avs_functions register function 2778 * Parameters: 2779 * 2780 * Returns: 2781 * SOC_E_xxx 2782 */ 2783 int 2784 soc_avs_function_register(int unit, soc_avs_functions_t *avs_functions) 2785 { 2786 soc_avs_functions[unit] = avs_functions; 2787 2788 /* Overwrite existed avs functions */ 2789 if (SOC_AVS_CONTROL(unit) != NULL) { 2790 SOC_AVS_CONTROL(unit)->avs_functions = soc_avs_functions[unit]; 2791 } 2792 return SOC_E_NONE; 2793 } 2794 2795 int 2796 soc_avs_unregister(int unit) 2797 { 2798 soc_avs_functions[unit] = NULL; 2799 return SOC_E_NONE; 2800 } 2801 2802 /* 2803 * Function: 2804 * soc_avs_init 2805 * Purpose: 2806 * software data structures allocation and initialization for avs module. 2807 * Parameters: 2808 * 2809 * Returns: 2810 * SOC_E_xxx 2811 */ 2812 int 2813 soc_avs_init(int unit) 2814 { 2815 soc_avs_control_t *avs; 2816 soc_avs_info_t *avs_info; 2817 int rv, i, track_step_size, new_thr_inc; 2818 int vmin_avs; 2819 int alloc_size; 2820 2821 if (!soc_feature(unit, soc_feature_avs) && 2822 !soc_feature(unit, soc_feature_avs_openloop)) { 2823 return SOC_E_UNAVAIL; 2824 } 2825 2826 if (SOC_AVS_CONTROL(unit) == NULL) { 2827 SOC_AVS_CONTROL(unit) = 2828 sal_alloc(sizeof(soc_avs_control_t), "avs_control"); 2829 if (SOC_AVS_CONTROL(unit) == NULL) { 2830 return SOC_E_MEMORY; 2831 } 2832 sal_memset(SOC_AVS_CONTROL(unit), 0, sizeof(soc_avs_control_t)); 2833 } 2834 2835 avs = SOC_AVS_CONTROL(unit); 2836 2837 avs->avs_functions = soc_avs_functions[unit]; 2838 avs->vrm_access = soc_vrm_access_functions[unit]; 2839 if (soc_feature(unit, soc_feature_avs_openloop)) { 2840 return SOC_E_NONE; 2841 } 2842 2843 /* avs_debug_xbmp, avs_debug_margin */ 2844 avs->avs_debug_xbmp = sal_alloc(sizeof(soc_avs_debug_xbmp_t), "avs_debug_xbmp"); 2845 if (avs->avs_debug_xbmp == NULL) { 2846 sal_free(avs); 2847 return SOC_E_MEMORY; 2848 } 2849 sal_memset(avs->avs_debug_xbmp, 0, sizeof(soc_avs_debug_xbmp_t)); 2850 2851 avs->avs_debug_margin = 2852 sal_alloc(sizeof(soc_avs_debug_margin_t), "avs_debug_margin"); 2853 if (avs->avs_debug_margin == NULL) { 2854 sal_free(avs->avs_debug_xbmp); 2855 sal_free(avs); 2856 return SOC_E_MEMORY; 2857 } 2858 sal_memset(avs->avs_debug_margin, 0, sizeof(soc_avs_debug_margin_t)); 2859 2860 2861 /* cen_freq_thr, rmt_freq_thr, cen_fth_slope */ 2862 avs->cen_freq_thr = _cent_freq_thr; 2863 avs->rmt_freq_thr = _rmt_freq_thr; 2864 avs->cen_fth_slope = _cent_fth_slope; 2865 2866 avs->avs_info = sal_alloc(sizeof(soc_avs_info_t), "avs_info"); 2867 if (avs->avs_info == NULL) { 2868 sal_free(avs->avs_debug_margin); 2869 sal_free(avs->avs_debug_xbmp); 2870 sal_free(avs); 2871 return SOC_E_MEMORY; 2872 } 2873 sal_memset(avs->avs_info, 0, sizeof(soc_avs_info_t)); 2874 2875 avs_info = avs->avs_info; 2876 /* general avs_info initialization */ 2877 /* default - disabled */ 2878 avs_info->num_centrals = 0; 2879 avs_info->first_cent = 0; 2880 for (i = 0; i < SOC_AVS_NUM_CENT_XBMP; i++) { 2881 avs_info->cent_xbmp[i] = 0xFFFFFFFF; 2882 } 2883 avs_info->num_remotes = 0; 2884 avs_info->first_rmt = 0; 2885 for (i = 0; i < SOC_AVS_NUM_RMT_XBMP; i++) { 2886 avs_info->rmt_xbmp[i] = 0xFFFFFFFF; 2887 } 2888 avs_info->vmin_avs = SOC_AVS_INT(SOC_AVS_DEFAULT_VMIN_AVS); 2889 avs_info->vmax_avs = SOC_AVS_INT(SOC_AVS_DEFAULT_VMAX_AVS); 2890 avs_info->vmargin_low = SOC_AVS_INT(SOC_AVS_DEFAULT_VMARGIN_LOW); 2891 avs_info->vmargin_high = SOC_AVS_INT(SOC_AVS_DEFAULT_VMARGIN_HIGH); 2892 #ifdef BCM_SBUSDMA_SUPPORT 2893 avs_info->cen_osc_reg = INVALIDr; 2894 avs_info->rmt_osc_reg = INVALIDr; 2895 #endif 2896 if (SOC_AVS_FUNCTIONS(unit)->info_init == NULL) { 2897 LOG_ERROR(BSL_LS_SOC_AVS, 2898 (BSL_META_U(unit, "no init functions registerd\n"))); 2899 sal_free(avs_info); 2900 sal_free(avs->avs_debug_xbmp); 2901 sal_free(avs); 2902 return SOC_E_INTERNAL; 2903 } 2904 /* chip specific avs_info initialization */ 2905 rv = (SOC_AVS_FUNCTIONS(unit)->info_init)(unit, avs_info); 2906 if (SOC_FAILURE(rv)) { 2907 sal_free(avs->avs_debug_margin); 2908 sal_free(avs->avs_debug_xbmp); 2909 sal_free(avs_info); 2910 sal_free(avs); 2911 return rv; 2912 } 2913 /* avs_info checker */ 2914 if ((avs_info->num_centrals == 0) || 2915 (avs_info->num_centrals > 128) || 2916 (avs_info->num_remotes == 0) || 2917 (avs_info->num_remotes > 256)) { 2918 sal_free(avs->avs_debug_margin); 2919 sal_free(avs->avs_debug_xbmp); 2920 sal_free(avs_info); 2921 sal_free(avs); 2922 return (SOC_E_PARAM); 2923 } 2924 /* overwrite the avs info from config */ 2925 vmin_avs = soc_property_get(unit, "avs_vmin", avs_info->vmin_avs); 2926 avs_info->vmin_avs = vmin_avs; 2927 2928 /* Create multex */ 2929 if ((avs->avsMutex = sal_mutex_create("AVS CONTROL")) == NULL) { 2930 sal_free(avs->avs_debug_margin); 2931 sal_free(avs->avs_debug_xbmp); 2932 sal_free(avs_info); 2933 sal_free(avs); 2934 return (SOC_E_INTERNAL); 2935 } 2936 /* init avs track thread */ 2937 avs->avs_track_pid = SAL_THREAD_ERROR; 2938 avs->avs_track_interval = 0; 2939 2940 #ifdef BCM_SBUSDMA_SUPPORT 2941 if (soc_feature(unit, soc_feature_sbusdma)) { 2942 rv = soc_avs_sbusdma_desc_setup(unit); 2943 if (rv) { 2944 (void)soc_avs_sbusdma_desc_free(unit); 2945 avs_info->avs_flags &= ~SOC_AVS_INFO_F_RSOC_COUNT_DMA; 2946 } 2947 } 2948 #endif 2949 alloc_size = avs_info->num_centrals * sizeof(uint32); 2950 avs->cent_v1s_osc_cache = sal_alloc(alloc_size, "cent v1s ROSC cache"); 2951 if (avs->cent_v1s_osc_cache == NULL) { 2952 sal_free(avs->avs_debug_margin); 2953 sal_free(avs->avs_debug_xbmp); 2954 sal_free(avs_info); 2955 sal_free(avs); 2956 return SOC_E_MEMORY; 2957 } 2958 sal_memset(avs->cent_v1s_osc_cache, 0, alloc_size); 2959 alloc_size = avs_info->num_remotes * sizeof(uint32); 2960 avs->rmt_v1s_h_osc_cache = sal_alloc(alloc_size, "remote v1s h ROSC cache"); 2961 if (avs->rmt_v1s_h_osc_cache == NULL) { 2962 sal_free(avs->cent_v1s_osc_cache); 2963 sal_free(avs->avs_debug_margin); 2964 sal_free(avs->avs_debug_xbmp); 2965 sal_free(avs_info); 2966 sal_free(avs); 2967 return SOC_E_MEMORY; 2968 } 2969 sal_memset(avs->rmt_v1s_h_osc_cache, 0, alloc_size); 2970 avs->rmt_v1s_s_osc_cache = sal_alloc(alloc_size, "remote v1s s ROSC cache"); 2971 if (avs->rmt_v1s_s_osc_cache == NULL) { 2972 sal_free(avs->cent_v1s_osc_cache); 2973 sal_free(avs->rmt_v1s_h_osc_cache); 2974 sal_free(avs->avs_debug_margin); 2975 sal_free(avs->avs_debug_xbmp); 2976 sal_free(avs_info); 2977 sal_free(avs); 2978 return SOC_E_MEMORY; 2979 } 2980 sal_memset(avs->rmt_v1s_s_osc_cache, 0, alloc_size); 2981 2982 if (avs_info->avs_flags & SOC_AVS_INFO_F_RSOC_THRESHOLD_CACHE) { 2983 alloc_size = avs_info->num_centrals * sizeof(uint32); 2984 avs->cent_lo_thr_cache = sal_alloc(alloc_size, "cent ROSC lo thr cache"); 2985 if (avs->cent_lo_thr_cache == NULL) { 2986 sal_free(avs->cent_v1s_osc_cache); 2987 sal_free(avs->rmt_v1s_h_osc_cache); 2988 sal_free(avs->rmt_v1s_s_osc_cache); 2989 sal_free(avs->avs_debug_margin); 2990 sal_free(avs->avs_debug_xbmp); 2991 sal_free(avs_info); 2992 sal_free(avs); 2993 return SOC_E_MEMORY; 2994 } 2995 avs->cent_hi_thr_cache = sal_alloc(alloc_size, "cent ROSC hi thr cache"); 2996 if (avs->cent_hi_thr_cache == NULL) { 2997 sal_free(avs->cent_v1s_osc_cache); 2998 sal_free(avs->rmt_v1s_h_osc_cache); 2999 sal_free(avs->rmt_v1s_s_osc_cache); 3000 sal_free(avs->cent_lo_thr_cache); 3001 sal_free(avs->avs_debug_margin); 3002 sal_free(avs->avs_debug_xbmp); 3003 sal_free(avs_info); 3004 sal_free(avs); 3005 return SOC_E_MEMORY; 3006 } 3007 3008 sal_memset(avs->cent_lo_thr_cache, 0, alloc_size); 3009 sal_memset(avs->cent_hi_thr_cache, 0, alloc_size); 3010 3011 alloc_size = avs_info->num_remotes * sizeof(uint32); 3012 avs->rmt_h_thr_cache = sal_alloc(alloc_size, "rmt ROSC h thr cache"); 3013 if (avs->rmt_h_thr_cache == NULL) { 3014 sal_free(avs->cent_v1s_osc_cache); 3015 sal_free(avs->rmt_v1s_h_osc_cache); 3016 sal_free(avs->rmt_v1s_s_osc_cache); 3017 sal_free(avs->cent_hi_thr_cache); 3018 sal_free(avs->cent_lo_thr_cache); 3019 sal_free(avs->avs_debug_margin); 3020 sal_free(avs->avs_debug_xbmp); 3021 sal_free(avs_info); 3022 sal_free(avs); 3023 return SOC_E_MEMORY; 3024 } 3025 avs->rmt_s_thr_cache = sal_alloc(alloc_size, "rmt ROSC s thr cache"); 3026 if (avs->rmt_s_thr_cache == NULL) { 3027 sal_free(avs->cent_v1s_osc_cache); 3028 sal_free(avs->rmt_v1s_h_osc_cache); 3029 sal_free(avs->rmt_v1s_s_osc_cache); 3030 sal_free(avs->rmt_h_thr_cache); 3031 sal_free(avs->cent_hi_thr_cache); 3032 sal_free(avs->cent_lo_thr_cache); 3033 sal_free(avs->avs_debug_margin); 3034 sal_free(avs->avs_debug_xbmp); 3035 sal_free(avs_info); 3036 sal_free(avs); 3037 return SOC_E_MEMORY; 3038 } 3039 sal_memset(avs->rmt_h_thr_cache, 0, alloc_size); 3040 sal_memset(avs->rmt_s_thr_cache, 0, alloc_size); 3041 } 3042 3043 /* allocate saved_voltage */ 3044 alloc_size = avs_info->num_centrals * sizeof(uint32); 3045 avs->saved_voltage = sal_alloc(alloc_size, "cent ROSC saved voltage"); 3046 if (avs->saved_voltage == NULL) { 3047 sal_free(avs->cent_v1s_osc_cache); 3048 sal_free(avs->rmt_v1s_h_osc_cache); 3049 sal_free(avs->rmt_v1s_s_osc_cache); 3050 sal_free(avs->rmt_s_thr_cache); 3051 sal_free(avs->rmt_h_thr_cache); 3052 sal_free(avs->cent_hi_thr_cache); 3053 sal_free(avs->cent_lo_thr_cache); 3054 sal_free(avs->avs_debug_margin); 3055 sal_free(avs->avs_debug_xbmp); 3056 sal_free(avs_info); 3057 sal_free(avs); 3058 return SOC_E_MEMORY; 3059 } 3060 sal_memset(avs->saved_voltage, 0, alloc_size); 3061 3062 avs->flags |= SOC_AVS_F_INITED; 3063 3064 /* track_inc_unit */ 3065 rv = soc_avs_ioctl(unit, SOC_AVS_CTRL_QUERY_TRACK_STEP_SIZE, &track_step_size, 1); 3066 3067 if (SOC_FAILURE(rv)) { 3068 /* default 3 mV*/ 3069 avs->track_step_size = 30; 3070 } else { 3071 avs->track_step_size = track_step_size; 3072 } 3073 /* overwrite the avs from config */ 3074 avs->track_step_size = soc_property_get(unit, "avs_track_step", avs->track_step_size); 3075 3076 /* new_thr_inc_unit */ 3077 rv = soc_avs_ioctl(unit, SOC_AVS_CTRL_QUERY_NEW_THR_INC, &new_thr_inc, 1); 3078 3079 if (SOC_FAILURE(rv)) { 3080 /* default 10 mV */ 3081 avs->new_thr_inc = 100; 3082 } else { 3083 avs->new_thr_inc = new_thr_inc; 3084 } 3085 /* overwrite the avs info from config */ 3086 avs->new_thr_inc = soc_property_get(unit, "avs_thr_inc", avs->new_thr_inc); 3087 3088 return SOC_E_NONE; 3089 } 3090 3091 /* 3092 * Function: 3093 * soc_avs_deinit 3094 * Purpose: 3095 * software data structures, resource de-initialization for avs module. 3096 * Parameters: 3097 * 3098 * Returns: 3099 * SOC_E_xxx 3100 */ 3101 int 3102 soc_avs_deinit(int unit) 3103 { 3104 soc_avs_control_t *avs; 3105 3106 avs = SOC_AVS_CONTROL(unit); 3107 if (avs) { 3108 if (SOC_AVS_FUNCTIONS(unit)->info_deinit) { 3109 SOC_AVS_FUNCTIONS(unit)->info_deinit(unit); 3110 } 3111 SOC_AVS_FUNCTIONS(unit) = NULL; 3112 (void)soc_avs_vrm_deinit(unit); 3113 if (avs->avsMutex) { 3114 sal_mutex_destroy(avs->avsMutex); 3115 avs->avsMutex = NULL; 3116 } 3117 if (avs->avs_debug_margin) { 3118 sal_free(avs->avs_debug_margin); 3119 } 3120 if (avs->avs_debug_xbmp) { 3121 sal_free(avs->avs_debug_xbmp); 3122 } 3123 if (avs->avs_info) { 3124 sal_free(avs->avs_info); 3125 } 3126 #ifdef BCM_SBUSDMA_SUPPORT 3127 if (soc_feature(unit, soc_feature_sbusdma)) { 3128 (void)soc_avs_sbusdma_desc_free(unit); 3129 } 3130 #endif 3131 if(avs->rmt_s_thr_cache) { 3132 sal_free(avs->rmt_s_thr_cache); 3133 } 3134 if(avs->rmt_h_thr_cache) { 3135 sal_free(avs->rmt_h_thr_cache); 3136 } 3137 if(avs->cent_hi_thr_cache) { 3138 sal_free(avs->cent_hi_thr_cache); 3139 } 3140 if(avs->cent_lo_thr_cache) { 3141 sal_free(avs->cent_lo_thr_cache); 3142 } 3143 if(avs->cent_v1s_osc_cache) { 3144 sal_free(avs->cent_v1s_osc_cache); 3145 } 3146 if(avs->rmt_v1s_h_osc_cache) { 3147 sal_free(avs->rmt_v1s_h_osc_cache); 3148 } 3149 if(avs->rmt_v1s_s_osc_cache) { 3150 sal_free(avs->rmt_v1s_s_osc_cache); 3151 } 3152 if(avs->saved_voltage) { 3153 sal_free(avs->saved_voltage); 3154 } 3155 sal_free(avs); 3156 } 3157 SOC_AVS_CONTROL(unit) = NULL; 3158 3159 return 0; 3160 } 3161 3162 /* 3163 * Function: 3164 * soc_avs_debug_margin_set 3165 * Purpose: 3166 * Mainly for CLI cmd usage to change the margin during the verification 3167 * If the custom margin value is set, algorithm will take this value instead 3168 * of chip initialized margin value. 3169 * Parameters: 3170 * 3171 * Returns: 3172 * SOC_E_xxx 3173 */ 3174 int 3175 soc_avs_debug_margin_set(int unit, soc_avs_debug_margin_t *avs_debug_margin) 3176 { 3177 soc_avs_control_t *avs; 3178 3179 if (!soc_avs_inited(unit)) { 3180 return SOC_E_INIT; 3181 } 3182 avs = SOC_AVS_CONTROL(unit); 3183 3184 SOC_AVS_LOCK(avs); 3185 SOC_AVS_MARGIN(unit)->vmargin_low = avs_debug_margin->vmargin_low; 3186 SOC_AVS_MARGIN(unit)->vmargin_high = avs_debug_margin->vmargin_high; 3187 SOC_AVS_UNLOCK(avs); 3188 return SOC_E_NONE; 3189 } 3190 3191 /* 3192 * Function: 3193 * soc_avs_debug_margin_get 3194 * Purpose: 3195 * Mainly for CLI cmd usage to get the customed margin during the verification 3196 * Parameters: 3197 * 3198 * Returns: 3199 * SOC_E_xxx 3200 */ 3201 int 3202 soc_avs_debug_margin_get(int unit, soc_avs_debug_margin_t *avs_debug_margin) 3203 { 3204 soc_avs_control_t *avs; 3205 3206 if (!soc_avs_inited(unit)) { 3207 return SOC_E_INIT; 3208 } 3209 avs = SOC_AVS_CONTROL(unit); 3210 3211 SOC_AVS_LOCK(avs); 3212 avs_debug_margin->vmargin_low = SOC_AVS_MARGIN(unit)->vmargin_low; 3213 avs_debug_margin->vmargin_high = SOC_AVS_MARGIN(unit)->vmargin_high; 3214 SOC_AVS_UNLOCK(avs); 3215 return SOC_E_NONE; 3216 } 3217 3218 /* 3219 * Function: 3220 * soc_avs_xbmp_set 3221 * Purpose: 3222 * Mainly for CLI cmd usage to config the osc exclusive bitmap 3223 * Parameters: 3224 * 3225 * Returns: 3226 * SOC_E_xxx 3227 */ 3228 int 3229 soc_avs_xbmp_set(int unit, int type, int start_osc, int num_osc, int value) 3230 { 3231 soc_avs_control_t *avs; 3232 int i; 3233 if (!soc_avs_inited(unit)) { 3234 return SOC_E_INIT; 3235 } 3236 avs = SOC_AVS_CONTROL(unit); 3237 3238 SOC_AVS_LOCK(avs); 3239 if (type == SOC_AVS_ROSC_TYPE_CENTRAL) { 3240 for (i = start_osc; i < start_osc + num_osc; i++) { 3241 if ((i >= 0) && (i / NUM_BITS_PER_XBMP < SOC_AVS_NUM_CENT_XBMP)) { 3242 if (value == 0) { 3243 SOC_AVS_XBMP(unit)->cent_xbmp[i / NUM_BITS_PER_XBMP] &= ~(0x1 << 3244 (i % NUM_BITS_PER_XBMP)); 3245 } else { 3246 SOC_AVS_XBMP(unit)->cent_xbmp[i / NUM_BITS_PER_XBMP] |= 0x1 << 3247 (i % NUM_BITS_PER_XBMP); 3248 } 3249 } else { 3250 SOC_AVS_UNLOCK(avs); 3251 return (SOC_E_FAIL); 3252 } 3253 } 3254 } 3255 if (type == SOC_AVS_ROSC_TYPE_REMOTE) { 3256 for (i = start_osc; i < start_osc + num_osc; i++) { 3257 if ((i >= 0) && (i / NUM_BITS_PER_XBMP < SOC_AVS_NUM_RMT_XBMP)) { 3258 if (value == 0) { 3259 SOC_AVS_XBMP(unit)->rmt_xbmp[i / NUM_BITS_PER_XBMP] &= ~(0x1 << 3260 (i % NUM_BITS_PER_XBMP)); 3261 } else { 3262 SOC_AVS_XBMP(unit)->rmt_xbmp[i / NUM_BITS_PER_XBMP] |= 3263 0x1 << (i % NUM_BITS_PER_XBMP); 3264 } 3265 } else { 3266 SOC_AVS_UNLOCK(avs); 3267 return (SOC_E_FAIL); 3268 } 3269 } 3270 } 3271 SOC_AVS_UNLOCK(avs); 3272 return SOC_E_NONE; 3273 } 3274 /* 3275 * Function: 3276 * soc_avs_xbmp_get 3277 * Purpose: 3278 * Mainly for CLI cmd usage to get the currently osc exclusive bitmap 3279 * which is the "OR" result of the customized value and chip initialized value 3280 * Parameters: 3281 * 3282 * Returns: 3283 * SOC_E_xxx 3284 */ 3285 int 3286 soc_avs_xbmp_dump(int unit, int type) 3287 { 3288 int i; 3289 if (!soc_avs_inited(unit)) { 3290 return SOC_E_INIT; 3291 } 3292 if (type == SOC_AVS_ROSC_TYPE_REMOTE) { 3293 for (i = 0; i < SOC_AVS_NUM_RMT_XBMP; i++) { 3294 LOG_CLI((BSL_META_U(unit, 3295 "soc_avs_xbmp_dump: rmt_xbmp[%d] = 0x%08x\n"), 3296 i, (SOC_AVS_XBMP(unit)->rmt_xbmp[i] | 3297 SOC_AVS_INFO(unit)->rmt_xbmp[i]))); 3298 } 3299 } 3300 if (type == SOC_AVS_ROSC_TYPE_CENTRAL) { 3301 for (i = 0; i < SOC_AVS_NUM_CENT_XBMP; i++) { 3302 LOG_CLI((BSL_META_U(unit, 3303 "soc_avs_xbmp_dump: cent_xbmp[%d] = 0x%08x\n"), 3304 i, (SOC_AVS_XBMP(unit)->cent_xbmp[i] | 3305 SOC_AVS_INFO(unit)->cent_xbmp[i]))); 3306 } 3307 } 3308 return (SOC_E_NONE); 3309 } 3310 3311 /* 3312 * Function: 3313 * _soc_avs_reset_sequencer 3314 * Purpose: 3315 * Reset the sequencer and all of its calculations. 3316 * Parameters: 3317 * 3318 * Returns: 3319 * SOC_E_xxx 3320 */ 3321 STATIC int 3322 _soc_avs_reset_sequencer(int unit) 3323 { 3324 uint32 regval, fieldval; 3325 soc_reg_t reg; 3326 soc_field_t field; 3327 int i; 3328 soc_avs_reg_info_t *osc_seq_reset_list; 3329 soc_avs_info_t *avs_info; 3330 3331 if(soc_avs_track_inited(unit)) { 3332 return SOC_E_NONE; 3333 } 3334 avs_info = SOC_AVS_INFO(unit); 3335 3336 SOC_AVS_IF_ERROR_NOT_UNAVAIL_RETURN( 3337 soc_avs_ioctl(unit, SOC_AVS_CTRL_SEQUENCER_INIT, NULL, 0)); 3338 3339 3340 /* AVS_REG_HW_MNTR_SEQUENCER_INITr.SEQUENCER_INITf */ 3341 regval = 0; 3342 reg = AVS_REG_HW_MNTR_SEQUENCER_INITr; 3343 field = SEQUENCER_INITf; 3344 soc_reg_field_set(unit, reg, ®val, field, 1); 3345 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, regval)); 3346 regval = 0; 3347 soc_reg_field_set(unit, reg, ®val, field, 0); 3348 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, regval)); 3349 3350 SOC_AVS_IF_ERROR_NOT_UNAVAIL_RETURN( 3351 soc_avs_ioctl(unit, SOC_AVS_CTRL_PVTMON_INIT, NULL, 0)); 3352 3353 /* AVS_REG_HW_MNTR_MEASUREMENTS_INIT_PVT_MNTRr.M_INIT_PVT_MNTRf */ 3354 reg = AVS_REG_HW_MNTR_MEASUREMENTS_INIT_PVT_MNTRr; 3355 field = M_INIT_PVT_MNTRf; 3356 fieldval = _soc_avs_reg_field_all_ones(unit, reg, field); 3357 regval = 0; 3358 soc_reg_field_set(unit, reg, ®val, field, fieldval); 3359 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, regval)); 3360 3361 SOC_AVS_IF_ERROR_NOT_UNAVAIL_RETURN( 3362 soc_avs_ioctl(unit, SOC_AVS_CTRL_OSC_MNTR_INIT, NULL, 0)); 3363 3364 /* reset cent and rmt OSCs measurement */ 3365 if (avs_info->osc_seq_reset_info) { 3366 uint32 delay; 3367 int rosc_count_mode; 3368 int ref_clk_freq; /* in MHz*/ 3369 uint32 max_ref_clk_counter; 3370 3371 osc_seq_reset_list = avs_info->osc_seq_reset_info; 3372 for (i = 0; osc_seq_reset_list[i].reg_name != -1 ; i++) { 3373 reg = osc_seq_reset_list[i].reg_name; 3374 field = osc_seq_reset_list[i].reg_field; 3375 regval = 0; 3376 fieldval = _soc_avs_reg_field_all_ones(unit, reg, field); 3377 soc_reg_field_set(unit, reg, ®val, field, fieldval); 3378 SOC_IF_ERROR_RETURN( 3379 soc_reg32_set(unit, reg, REG_PORT_ANY, 0, regval)); 3380 regval = 0; 3381 fieldval = 0; 3382 soc_reg_field_set(unit, reg, ®val, field, fieldval); 3383 SOC_IF_ERROR_RETURN( 3384 soc_reg32_set(unit, reg, REG_PORT_ANY, 0, regval)); 3385 } 3386 3387 /* add delay to let all cent ROSC counts be valid*/ 3388 rosc_count_mode = avs_info->rosc_count_mode; 3389 ref_clk_freq = avs_info->ref_clk_freq; 3390 max_ref_clk_counter = (avs_info->measurement_time_control * 256U) 3391 + 255U; 3392 /* delay in us */ 3393 delay = (max_ref_clk_counter * rosc_count_mode * avs_info->num_centrals) 3394 / ref_clk_freq; 3395 /* delay in ms */ 3396 delay /= 1000; 3397 /* delay with safe margin */ 3398 delay = delay * 2; 3399 sal_msleep(delay); 3400 } 3401 3402 SOC_AVS_IF_ERROR_NOT_UNAVAIL_RETURN( 3403 soc_avs_ioctl(unit, SOC_AVS_CTRL_HW_MNTR_SW_CONTROL, NULL, 0)); 3404 3405 /* Make sure we're not in take-over mode so sequencer will begin its 3406 * measurements */ 3407 regval = 0; 3408 reg = AVS_REG_HW_MNTR_SW_CONTROLSr; 3409 soc_reg_field_set(unit, reg, ®val, SW_TAKEOVERf, 0); 3410 soc_reg_field_set(unit, reg, ®val, SW_DO_MEASUREf, 0); 3411 soc_reg_field_set(unit, reg, ®val, SW_SENSOR_IDXf, 0); 3412 SOC_IF_ERROR_RETURN(soc_reg32_set(unit, reg, REG_PORT_ANY, 0, regval)); 3413 3414 sal_msleep(SOC_AVS_SEQUENCER_DELAY); 3415 3416 SOC_AVS_CONTROL(unit)->flags |= SOC_AVS_F_TRACK_INITED; 3417 return (SOC_E_NONE); 3418 } 3419 3420 3421 /* 3422 * Function: 3423 * _soc_avs_adjust_voltage 3424 * Purpose: 3425 * If current voltage is within [Vmin_avs,Vmax_avs], last_set_voltage is 3426 * adjusted with adj_step. If current voltage is outside the range, 3427 * last_set_voltage is adjusted by adj_step in direction to bring back voltage 3428 * within the range (by ignoring sign of adj_step). 3429 * Parameters: 3430 * adjustment_step - (IN)Positive, negative value to be added to 3431 * last_set_voltage. 3432 * voltage_change_aborted - (OUT)TRUE if we could change voltage as requested. 3433 * Returns: 3434 * SOC_E_xxx 3435 */ 3436 STATIC int 3437 _soc_avs_adjust_voltage(int unit, int adjustment_step, soc_avs_bool_t 3438 *voltage_change_aborted) 3439 { 3440 uint32 last_set_voltage, new_set_voltage; 3441 uint32 read_voltage; 3442 int32 new_vmin_avs; 3443 soc_avs_info_t *avs_info = SOC_AVS_INFO(unit); 3444 3445 if (voltage_change_aborted == NULL) { 3446 return (SOC_E_PARAM); 3447 } 3448 *voltage_change_aborted = SOC_AVS_BOOL_FALSE; 3449 new_vmin_avs = avs_info->vmin_avs; 3450 3451 last_set_voltage = _soc_last_set_voltage[unit]; 3452 SOC_AVS_ASSERT(last_set_voltage > 0); 3453 3454 SOC_IF_ERROR_RETURN(soc_avs_voltage_get(unit, &read_voltage)); 3455 3456 /* Make sure we never violate the voltage max and min values */ 3457 /* Note that the adjustment step can be negative to adjust the other way */ 3458 if ((new_vmin_avs <= (int32)read_voltage) && 3459 ((int32)read_voltage <= avs_info->vmax_avs)) { 3460 *voltage_change_aborted = SOC_AVS_BOOL_FALSE; 3461 if (adjustment_step < 0) { 3462 SOC_AVS_ASSERT(last_set_voltage > SOC_AVS_ABS(adjustment_step)); 3463 } 3464 new_set_voltage = last_set_voltage + (uint32)adjustment_step; 3465 3466 LOG_INFO(BSL_LS_SOC_AVS, 3467 (BSL_META_U(unit, 3468 "adjust step %d to voltage %d\n"), 3469 adjustment_step, new_set_voltage)); 3470 3471 SOC_IF_ERROR_RETURN(soc_avs_voltage_set(unit, new_set_voltage)); 3472 3473 } else { 3474 *voltage_change_aborted = SOC_AVS_BOOL_TRUE; 3475 3476 /* new algorithm says we shouldn't ALLOW the voltage to exceed its 3477 * limits. 3478 * So we know we're outside the safe voltage range -- bring it back */ 3479 3480 if ((int32)read_voltage > new_vmin_avs) { 3481 SOC_AVS_ASSERT(last_set_voltage > SOC_AVS_ABS(adjustment_step)); 3482 new_set_voltage = last_set_voltage - SOC_AVS_ABS(adjustment_step); 3483 LOG_WARN(BSL_LS_SOC_AVS, 3484 (BSL_META_U(unit, 3485 "WARNING, read_voltage = %0d, is out of" 3486 " limits, voltage will be decreased\n"), 3487 read_voltage)); 3488 3489 } else { 3490 new_set_voltage = last_set_voltage + SOC_AVS_ABS(adjustment_step); 3491 LOG_WARN(BSL_LS_SOC_AVS, 3492 (BSL_META_U(unit, 3493 "WARNING, read_voltage = %0d, is out of" 3494 " limits, voltage will be increased\n"), 3495 read_voltage)); 3496 } 3497 SOC_IF_ERROR_RETURN(soc_avs_voltage_set(unit, new_set_voltage)); 3498 } 3499 return (SOC_E_NONE); 3500 } 3501 #define SOC_AVS_TRACK_VINC_STEP (2) 3502 /* 2 step * 3 mV per step */ 3503 #define SOC_AVS_TRACK_VDEC_STEP (-1) 3504 /* -1 step * 3 mV per step */ 3505 3506 /* 3507 * Function: 3508 * _soc_avs_converge_process 3509 * Purpose: 3510 * If any osc_count < lo_thr then increase the voltage. 3511 * Else if all osc_count are > hi_thr, then decrease the voltage. 3512 * Parameters: 3513 * voltage_change_requested - (OUT)0,+1,-1 to indicated no change, inc, dec 3514 * voltage_change_aborted - (OUT)TRUE if we could change voltage as requested. 3515 * Returns: 3516 * SOC_E_xxx 3517 */ 3518 STATIC int 3519 _soc_avs_converge_process(int unit, int *voltage_change_requested, 3520 soc_avs_bool_t *voltage_change_aborted) 3521 { 3522 int i, alloc_size; 3523 uint32 *posc_count = NULL, *posc_lo_thr = NULL, *posc_hi_thr = NULL; 3524 uint32 *posc_count_h = NULL, *posc_count_s = NULL, *posc_lo_thr_h = NULL, 3525 *posc_hi_thr_h = NULL, *posc_lo_thr_s = NULL, *posc_hi_thr_s = NULL; 3526 soc_avs_bool_t inc_voltage = SOC_AVS_BOOL_FALSE, 3527 found_one_osc_below_hi_thr = SOC_AVS_BOOL_FALSE; 3528 uint32 *alloc_ptr = NULL; 3529 int inc_val, dec_val; 3530 char *s = NULL, *s1 = NULL; 3531 3532 soc_avs_info_t *avs_info = SOC_AVS_INFO(unit); 3533 soc_avs_control_t *avs = SOC_AVS_CONTROL(unit); 3534 3535 if ((avs->flags & SOC_AVS_F_THRESHOLD_SET) == 0) { 3536 LOG_WARN(BSL_LS_SOC_AVS, 3537 (BSL_META_U(unit, 3538 "Threshold values are not set. " 3539 "Stop the _soc_avs_converge_process.\n"))); 3540 return (SOC_E_INTERNAL); 3541 } 3542 3543 if ((voltage_change_requested == NULL) || 3544 (voltage_change_aborted == NULL)) { 3545 return (SOC_E_PARAM); 3546 } 3547 /* init outputs */ 3548 *voltage_change_aborted = SOC_AVS_BOOL_FALSE; 3549 *voltage_change_requested = 0; /* no change */ 3550 3551 /* allocate memory */ 3552 alloc_size = 6 * SOC_AVS_MAX(avs_info->num_centrals, avs_info->num_remotes) 3553 * sizeof(uint32); 3554 if ((alloc_ptr = (uint32 *)sal_alloc(alloc_size, 3555 "Storage for _soc_avs_converge_process")) == NULL) { 3556 return (SOC_E_MEMORY); 3557 } 3558 3559 /* read all cent_osc counts, thresholds */ 3560 sal_memset(alloc_ptr, 0, alloc_size); 3561 posc_count = alloc_ptr; 3562 posc_hi_thr = posc_count + avs_info->num_centrals; 3563 posc_lo_thr = posc_hi_thr + avs_info->num_centrals; 3564 3565 SOC_AVS_FREE_IF_ERROR_RETURN( 3566 _soc_avs_cent_osc_count_get(unit, avs_info->first_cent, 3567 avs_info->num_centrals, posc_count), 3568 alloc_ptr); 3569 3570 SOC_AVS_FREE_IF_ERROR_RETURN( 3571 _soc_avs_cent_osc_thr_get(unit, avs_info->first_cent, 3572 avs_info->num_centrals, posc_lo_thr, 3573 posc_hi_thr), alloc_ptr); 3574 LOG_VERBOSE(BSL_LS_SOC_AVS, 3575 (BSL_META_U(unit, 3576 "index, osc_count, [lo_thr, hi_thr], +/-/ \n"))); 3577 3578 /* Process cent_osc counts, thresholds */ 3579 for (i = avs_info->first_cent; i < avs_info->num_centrals; i++) { 3580 /* skip the items we are excluding */ 3581 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_CENTRAL, i)){ 3582 continue; 3583 } 3584 if (posc_count[i] == 0) { 3585 continue; 3586 } 3587 /* this should have already been handled by exclude list, but ... */ 3588 if (LOG_CHECK(BSL_LS_SOC_AVS|BSL_VERBOSE)) { 3589 if (posc_count[i] < posc_lo_thr[i]) { 3590 s = "-"; 3591 } else if (posc_count[i] > posc_hi_thr[i]) { 3592 s = "+"; 3593 } else { 3594 s = " "; 3595 } 3596 } 3597 LOG_VERBOSE(BSL_LS_SOC_AVS, 3598 (BSL_META_U(unit, "%d, %d, [%d, %d], %s\n"), 3599 i, posc_count[i], posc_lo_thr[i], posc_hi_thr[i], s)); 3600 3601 if ((posc_lo_thr[i] != 0) && 3602 (posc_count[i] < posc_lo_thr[i])) { 3603 inc_voltage = SOC_AVS_BOOL_TRUE; 3604 } else if ((posc_hi_thr[i] != 0) && 3605 (posc_count[i] <= posc_hi_thr[i])) { 3606 found_one_osc_below_hi_thr = SOC_AVS_BOOL_TRUE; 3607 } 3608 } 3609 3610 /* read all rmt_osc counts, thresholds */ 3611 sal_memset(alloc_ptr, 0, alloc_size); 3612 posc_count_h = alloc_ptr; 3613 posc_count_s = posc_count_h + avs_info->num_remotes; 3614 posc_hi_thr_h = posc_count_s + avs_info->num_remotes; 3615 posc_lo_thr_h = posc_hi_thr_h + avs_info->num_remotes; 3616 posc_hi_thr_s = posc_lo_thr_h + avs_info->num_remotes; 3617 posc_lo_thr_s = posc_hi_thr_s + avs_info->num_remotes; 3618 3619 SOC_AVS_FREE_IF_ERROR_RETURN( 3620 _soc_avs_rmt_osc_count_get(unit, avs_info->first_rmt, 3621 avs_info->num_remotes, 3622 posc_count_h, posc_count_s), alloc_ptr); 3623 3624 SOC_AVS_FREE_IF_ERROR_RETURN( 3625 _soc_avs_rmt_osc_thr_get(unit, avs_info->first_rmt, 3626 avs_info->num_remotes, posc_lo_thr_h, 3627 posc_hi_thr_h, posc_lo_thr_s, posc_hi_thr_s), 3628 alloc_ptr); 3629 LOG_VERBOSE(BSL_LS_SOC_AVS, 3630 (BSL_META_U(unit, 3631 "index, osc_count_h , [lo_thr_h, hi_thr_h], " 3632 "osc_count_s, [lo_thr_s, hi_thr_s], +/-/ ,+/-/ \n"))); 3633 3634 /* Process remote_osc counts, thresholds */ 3635 for (i = avs_info->first_rmt; i < avs_info->num_remotes; i++) { 3636 /* skip the items we are excluding */ 3637 if (_soc_avs_xbmp_check(unit, SOC_AVS_ROSC_TYPE_REMOTE, i)){ 3638 continue; 3639 } 3640 3641 /*if we didn't get a value then this is an unimplemented oscillator*/ 3642 /* this should have already been handled by exclude list */ 3643 if ((posc_count_h[i] == 0) || (posc_count_s[i] == 0)) { 3644 continue; 3645 } 3646 if (LOG_CHECK(BSL_LS_SOC_AVS|BSL_VERBOSE)) { 3647 if (posc_count_h[i] < posc_lo_thr_h[i]) { 3648 s = "-"; 3649 } else if (posc_count_h[i] > posc_hi_thr_h[i]) { 3650 s = "+"; 3651 } else { 3652 s = " "; 3653 } 3654 if (posc_count_s[i] < posc_lo_thr_s[i]) { 3655 s1 = "-"; 3656 } else if (posc_count_s[i] > posc_hi_thr_s[i]) { 3657 s1 = "+"; 3658 } else { 3659 s1 = " "; 3660 } 3661 } 3662 LOG_VERBOSE(BSL_LS_SOC_AVS, 3663 (BSL_META_U(unit, "%d, %d, [%d, %d], %d, [%d, %d], %s, %s\n"), 3664 i, posc_count_h[i], posc_lo_thr_h[i], posc_hi_thr_h[i], 3665 posc_count_s[i], posc_lo_thr_s[i], posc_hi_thr_s[i], 3666 s, s1)); 3667 3668 if (((posc_lo_thr_s[i] != 0) && 3669 (posc_count_s[i] < posc_lo_thr_s[i])) || 3670 ((posc_lo_thr_h[i] != 0) && 3671 (posc_count_h[i] < posc_lo_thr_h[i]))) { 3672 inc_voltage = SOC_AVS_BOOL_TRUE; 3673 3674 } else if (((posc_hi_thr_s[i] != 0) && 3675 (posc_count_s[i] <= posc_hi_thr_s[i])) || 3676 ((posc_hi_thr_h[i] != 0) && 3677 (posc_count_h[i] <= posc_hi_thr_h[i]))) { 3678 found_one_osc_below_hi_thr = SOC_AVS_BOOL_TRUE; 3679 } 3680 } 3681 if (inc_voltage == SOC_AVS_BOOL_TRUE) { 3682 /* we raise the voltage by raising the DAC */ 3683 *voltage_change_requested = +1; /* inc */ 3684 inc_val = SOC_AVS_TRACK_VINC_STEP * avs->track_step_size; 3685 SOC_AVS_FREE_IF_ERROR_RETURN( 3686 _soc_avs_adjust_voltage(unit, inc_val, voltage_change_aborted), 3687 alloc_ptr); 3688 } else if (found_one_osc_below_hi_thr == SOC_AVS_BOOL_FALSE) { 3689 /* we lower the voltage by lowering the DAC */ 3690 *voltage_change_requested = -1; /* dec */ 3691 dec_val = SOC_AVS_TRACK_VDEC_STEP * avs->track_step_size; 3692 SOC_AVS_FREE_IF_ERROR_RETURN( 3693 _soc_avs_adjust_voltage(unit, dec_val, voltage_change_aborted), 3694 alloc_ptr); 3695 } 3696 3697 sal_free(alloc_ptr); 3698 return (SOC_E_NONE); 3699 } 3700 /* 3701 * Function: 3702 * soc_avs_track 3703 * Purpose: 3704 * Reset sequencer and invoke _soc_avs_converge_process function. 3705 * This function will be called periodically when system is running. 3706 */ 3707 int 3708 soc_avs_track(int unit) 3709 { 3710 int voltage_change_requested; 3711 soc_avs_bool_t voltage_change_aborted; 3712 3713 if (!soc_avs_inited(unit)) { 3714 return SOC_E_INIT; 3715 } 3716 3717 SOC_IF_ERROR_RETURN(_soc_avs_reset_sequencer(unit)); 3718 3719 SOC_IF_ERROR_RETURN( 3720 _soc_avs_converge_process(unit, 3721 &voltage_change_requested, 3722 &voltage_change_aborted)); 3723 3724 LOG_INFO(BSL_LS_SOC_AVS, 3725 (BSL_META_U(unit, 3726 "voltage_change_requested=%0d, " 3727 "voltage_change_aborted=%0d, last_set_voltage=%0d\n"), 3728 voltage_change_requested, voltage_change_aborted, 3729 _soc_last_set_voltage[unit])); 3730 3731 return SOC_E_NONE; 3732 } 3733 void soc_avs_thread(void *unit_vp) 3734 { 3735 int unit = PTR_TO_INT(unit_vp); 3736 soc_avs_control_t *avs = SOC_AVS_CONTROL(unit); 3737 int rv = SOC_E_NONE; 3738 int interval; 3739 3740 while ((interval = avs->avs_track_interval) != 0) { 3741 #ifdef SOC_AVS_DEBUG 3742 sal_usecs_t start_time; 3743 #endif 3744 LOG_VERBOSE(BSL_LS_SOC_AVS, 3745 (BSL_META_U(unit, "sleep %d\n"), interval)); 3746 3747 (void)sal_sem_take(avs->avs_track_notify, interval); 3748 3749 if (avs->avs_track_interval == 0) { /* Exit signaled */ 3750 break; 3751 } 3752 #ifdef SOC_AVS_DEBUG 3753 start_time = sal_time_usecs(); 3754 #endif 3755 rv = soc_avs_track(unit); 3756 #ifdef SOC_AVS_DEBUG 3757 LOG_VERBOSE(BSL_LS_SOC_AVS, 3758 (BSL_META_U(unit, 3759 "Time taken for avs track: %d usec\n"), 3760 SAL_USECS_SUB(sal_time_usecs(), start_time))); 3761 #endif 3762 if (SOC_FAILURE(rv)) { 3763 LOG_INFO(BSL_LS_SOC_AVS, 3764 (BSL_META_U(unit, "Fail to do avs_track\n"))); 3765 } 3766 3767 if (!(avs->avs_track_interval)) { 3768 break; 3769 } 3770 } 3771 LOG_INFO(BSL_LS_SOC_AVS, 3772 (BSL_META_U(unit, 3773 "exiting thread\n"))); 3774 3775 avs->avs_track_pid = SAL_THREAD_ERROR; 3776 avs->avs_track_interval = 0; 3777 sal_thread_exit(0); 3778 } 3779 3780 int 3781 soc_avs_track_stop(int unit) 3782 { 3783 soc_avs_control_t *avs = SOC_AVS_CONTROL(unit); 3784 soc_timeout_t to; 3785 sal_usecs_t timeout; 3786 int rv = SOC_E_NONE; 3787 3788 if (!soc_avs_inited(unit)) { 3789 return SOC_E_INIT; 3790 } 3791 LOG_INFO(BSL_LS_SOC_AVS, 3792 (BSL_META_U(unit, "stop avs track"))); 3793 timeout = (1 * SECOND_USEC); 3794 /* Stop thread if present */ 3795 if (avs->avs_track_interval != 0) { 3796 avs->avs_track_interval = 0; 3797 sal_sem_give(avs->avs_track_notify); 3798 soc_timeout_init(&to, timeout, 0); 3799 while ((avs->avs_track_pid) != SAL_THREAD_ERROR) { 3800 if (soc_timeout_check(&to)) { 3801 LOG_ERROR(BSL_LS_SOC_AVS, 3802 (BSL_META_U(unit, "thread did not exit\n"))); 3803 avs->avs_track_pid = SAL_THREAD_ERROR; 3804 rv = SOC_E_TIMEOUT; 3805 break; 3806 } 3807 3808 sal_usleep(10000); 3809 } 3810 } 3811 if (NULL != avs->avs_track_notify) { 3812 sal_sem_destroy(avs->avs_track_notify); 3813 avs->avs_track_notify = NULL; 3814 } 3815 LOG_INFO(BSL_LS_SOC_AVS, 3816 (BSL_META_U(unit, "thread stopped\n"))); 3817 3818 return (rv); 3819 } 3820 int 3821 soc_avs_track_start(int unit, int interval) 3822 { 3823 soc_avs_control_t *avs = SOC_AVS_CONTROL(unit); 3824 sal_sem_t sem; 3825 3826 if (!soc_avs_inited(unit)) { 3827 return SOC_E_INIT; 3828 } 3829 LOG_INFO(BSL_LS_SOC_AVS, 3830 (BSL_META_U(unit, 3831 "avs_track start with interval=%d\n"), interval)); 3832 3833 /* Stop if already running */ 3834 if (avs->avs_track_interval != 0) { 3835 SOC_IF_ERROR_RETURN(soc_avs_track_stop(unit)); 3836 } 3837 3838 if (interval == 0) { 3839 return SOC_E_NONE; 3840 } 3841 if ((sem = avs->avs_track_notify) != NULL) { 3842 avs->avs_track_notify = NULL; /* Stop others from waking sem */ 3843 sal_sem_destroy(sem); /* Then destroy it */ 3844 } 3845 3846 avs->avs_track_notify = sal_sem_create("avs track notify", 3847 sal_sem_BINARY, 0); 3848 3849 sal_snprintf(avs->avs_track_name, 3850 sizeof(avs->avs_track_name), 3851 "bcmAVS.%d", unit); 3852 /* Start the thread */ 3853 if (interval != 0) { 3854 avs->avs_track_interval = interval; 3855 3856 avs->avs_track_pid = 3857 sal_thread_create(avs->avs_track_name, 3858 SAL_THREAD_STKSZ, 3859 50, 3860 soc_avs_thread, INT_TO_PTR(unit)); 3861 3862 if (avs->avs_track_pid == SAL_THREAD_ERROR) { 3863 avs->avs_track_interval = 0; 3864 LOG_ERROR(BSL_LS_SOC_AVS, 3865 (BSL_META_U(unit, "thread create failed\n"))); 3866 return (SOC_E_INTERNAL); 3867 } 3868 3869 LOG_INFO(BSL_LS_SOC_AVS, 3870 (BSL_META_U(unit, "Created AVS thread\n"))); 3871 } 3872 return SOC_E_NONE; 3873 } 3874 3875 int 3876 soc_avs_info_dump(int unit) 3877 { 3878 soc_avs_control_t *avs = SOC_AVS_CONTROL(unit); 3879 soc_avs_info_t *avs_info; 3880 int i, xbmp_index; 3881 3882 if (!soc_avs_inited(unit)) { 3883 return SOC_E_INIT; 3884 } 3885 avs_info = SOC_AVS_INFO(unit); 3886 LOG_CLI((BSL_META_U(unit, 3887 "Unit %d AVS Info Structure:\n"), unit)); 3888 LOG_CLI((BSL_META_U(unit, 3889 "\tnum_centrals = %d num_remotes = %d\n"), 3890 avs_info->num_centrals, avs_info->num_remotes)); 3891 xbmp_index = (avs_info->num_centrals + NUM_BITS_PER_XBMP - 1) 3892 / NUM_BITS_PER_XBMP; 3893 for (i = 0; i < xbmp_index; i++) { 3894 LOG_CLI((BSL_META_U(unit, 3895 "\tcent_xbmp[%d] = 0x%08x\n"), 3896 i, avs_info->cent_xbmp[i])); 3897 } 3898 xbmp_index = (avs_info->num_remotes + NUM_BITS_PER_XBMP - 1) 3899 / NUM_BITS_PER_XBMP; 3900 for (i = 0; i < xbmp_index; i++) { 3901 LOG_CLI((BSL_META_U(unit, 3902 "\trmt_xbmp[%d] = 0x%08x\n"), 3903 i, avs_info->rmt_xbmp[i])); 3904 } 3905 LOG_CLI((BSL_META_U(unit, 3906 "\tvmin_avs = %d vmax_avs = %d (in 0.1mV)\n" 3907 "\tvmargin_low = %d vmargin_high = %d (in 0.1mV)\n" 3908 "\tavs_flags = 0x%x \n"), 3909 avs_info->vmin_avs, avs_info->vmax_avs, 3910 avs_info->vmargin_low, avs_info->vmargin_high, 3911 avs_info->avs_flags)); 3912 LOG_CLI((BSL_META_U(unit, 3913 "\tdebug_margin_low = %d debug_margin_high = %d (in 0.1mV)\n" 3914 "\tavs_thr_inc = %d avs_track_step = %d (in 0.1mV)\n"), 3915 avs->avs_debug_margin->vmargin_low, avs->avs_debug_margin->vmargin_high, 3916 avs->new_thr_inc, avs->track_step_size)); 3917 return SOC_E_NONE; 3918 } 3919 3920 #else /* INCLUDE_AVS */ 3921 3922 int _common_avs_c_not_empty; 3923 3924 #endif /* INCLUDE_AVS */