|
5 | 5 | /* */
|
6 | 6 | /* OpenPOWER HostBoot Project */
|
7 | 7 | /* */
|
8 |
| -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ |
| 8 | +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ |
9 | 9 | /* [+] International Business Machines Corp. */
|
10 | 10 | /* */
|
11 | 11 | /* */
|
@@ -138,8 +138,8 @@ fapi2::ReturnCode pfet_set_voff(
|
138 | 138 | /// @return delays in this register are in terms of PPM clock period
|
139 | 139 |
|
140 | 140 | uint8_t convert_delay_to_value (
|
141 |
| - const uint32_t i_delay, |
142 |
| - const uint32_t i_attr_proc_nest_frequency); |
| 141 | + const uint32_t i_delay_ns, |
| 142 | + const uint32_t i_proc_nest_frequency_MHz); |
143 | 143 |
|
144 | 144 | // ----------------------------------------------------------------------
|
145 | 145 | // Function definitions
|
@@ -222,7 +222,7 @@ fapi2::ReturnCode pfet_init(
|
222 | 222 | uint8_t l_pfet_powerup_delay_value = 0;
|
223 | 223 | uint8_t l_pfet_powerdown_delay_value = 0;
|
224 | 224 |
|
225 |
| - uint32_t l_proc_refclk_frequency; |
| 225 | + uint32_t l_proc_nest_frequency; |
226 | 226 | uint32_t l_pfet_powerup_delay_ns;
|
227 | 227 | uint32_t l_pfet_powerdown_delay_ns;
|
228 | 228 | uint8_t l_pfet_vdd_voff_sel;
|
@@ -255,11 +255,11 @@ fapi2::ReturnCode pfet_init(
|
255 | 255 | // ******************************************************************
|
256 | 256 | const fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> FAPI_SYSTEM;
|
257 | 257 | /// ----------------------------------------------------------
|
258 |
| - l_proc_refclk_frequency = 0; |
259 |
| - FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_FREQ_PROC_REFCLOCK_KHZ, |
| 258 | + l_proc_nest_frequency = 0; |
| 259 | + FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_FREQ_PB_MHZ, |
260 | 260 | FAPI_SYSTEM,
|
261 |
| - l_proc_refclk_frequency), |
262 |
| - "Error getting ATTR_FREQ_PROC_REFCLOCK"); |
| 261 | + l_proc_nest_frequency), |
| 262 | + "Error getting ATTR_FREQ_PB_MHZ"); |
263 | 263 |
|
264 | 264 |
|
265 | 265 | /// ----------------------------------------------------------
|
@@ -293,24 +293,24 @@ fapi2::ReturnCode pfet_init(
|
293 | 293 |
|
294 | 294 | l_pfet_powerup_delay_value =
|
295 | 295 | convert_delay_to_value( l_pfet_powerup_delay_ns,
|
296 |
| - l_proc_refclk_frequency); |
| 296 | + l_proc_nest_frequency); |
297 | 297 |
|
298 | 298 | l_pfet_powerdown_delay_value =
|
299 | 299 | convert_delay_to_value( l_pfet_powerdown_delay_ns,
|
300 |
| - l_proc_refclk_frequency); |
| 300 | + l_proc_nest_frequency); |
301 | 301 |
|
302 | 302 |
|
303 | 303 | FAPI_DBG("PFET Power Up Delay");
|
304 | 304 | FAPI_DBG(" ATTR_PM_PFET_POWERUP_DELAY_NS : %d (0x%X)",
|
305 |
| - l_pfet_powerup_delay_value, |
306 |
| - l_pfet_powerup_delay_value); |
307 |
| - FAPI_DBG(" pfet_powerup_delay_value : %X", l_pfet_powerup_delay_value); |
| 305 | + l_pfet_powerup_delay_ns, |
| 306 | + l_pfet_powerup_delay_ns); |
| 307 | + FAPI_DBG(" pfet_powerup_delay_value : %X", l_pfet_powerup_delay_value); |
308 | 308 |
|
309 | 309 | FAPI_DBG("PFET Power Down Delay");
|
310 | 310 | FAPI_DBG(" ATTR_PM_PFET_POWERDOWN_DELAY_NS : %d (0x%X)",
|
311 |
| - l_pfet_powerdown_delay_value, |
312 |
| - l_pfet_powerdown_delay_value); |
313 |
| - FAPI_DBG(" pfet_powerdown_delay_value : %X", l_pfet_powerdown_delay_value); |
| 311 | + l_pfet_powerdown_delay_ns, |
| 312 | + l_pfet_powerdown_delay_ns); |
| 313 | + FAPI_DBG(" pfet_powerdown_delay_value : %X", l_pfet_powerdown_delay_value); |
314 | 314 |
|
315 | 315 |
|
316 | 316 | // ******************************************************************
|
@@ -455,90 +455,91 @@ fapi_try_exit:
|
455 | 455 | //------------------------------------------------------------------------------
|
456 | 456 | // convert_delay_to_value
|
457 | 457 | // Helper function to convert time values (binary in ns)to hardware delays
|
| 458 | +// |
| 459 | +// The hardware uses a 1 in the power of 2 bit position of a 16 bit counter |
| 460 | +// to indicate a delay match. As the LSb of the counter will become a 1 every |
| 461 | +// other cycle, there is an inherent multiply by 2 built in. Thus, the smallest |
| 462 | +// delay possible is 2 x the counter frequency (eg for a 2GHz nest with PFET |
| 463 | +// controller logic running at /4 of that indicates a 2ns cycle time. With a |
| 464 | +// power of 2 of 0 (eg bit 15 of the counter) indicates a match on that LSb |
| 465 | +// every 4ns). |
458 | 466 | //------------------------------------------------------------------------------
|
459 | 467 | // @todo can this be done in a better way?
|
460 | 468 | uint8_t
|
461 |
| -convert_delay_to_value (uint32_t i_delay, |
462 |
| - uint32_t i_proc_nest_frequency) |
| 469 | +convert_delay_to_value (const uint32_t i_delay_ns, |
| 470 | + const uint32_t i_proc_nest_frequency_MHz) |
463 | 471 | {
|
464 |
| - uint8_t pfet_delay_value; |
| 472 | + uint8_t pfet_delay_value = 0xFF; // An illegal value |
465 | 473 | uint64_t dly;
|
466 |
| - // attr_proc_nest_frequency [MHz] |
467 |
| - // delay [ns] |
468 |
| - // pfet_delay_value = 15 - log2( i_delay * i_attr_proc_nest_frequency/1000); |
469 |
| - // since log2 function is not available, this is done manually |
| 474 | + |
| 475 | + // i_attr_proc_nest_frequency_MHz (Mcycles/s * M/M = cycles/us) |
| 476 | + |
| 477 | + // PPM cycle time (ns/cycle) = 1/PPM frequency_MHz [1/(cycles/us)] |
| 478 | + // = 1/PPM frequency_MHz [us/cycle] |
| 479 | + // = (1/PPM frequency_MHz)* 1000 ns/cycle |
| 480 | + // |
| 481 | + // PPM frequency_MHz (cycles/us) = i_attr_proc_nest_frequency_MHz / 4 (cycles/us) |
| 482 | + // |
| 483 | + // delay_ns = 2 * PPM cycle time (ns) * 2**(15-N) |
| 484 | + // where N (pfet_delay value) is the bit position of a 16 bit counter |
| 485 | + // that has the least significant bit toggling every other cycle. |
| 486 | + // The every other cycle is the reason for the 2 * cycle time. |
| 487 | + // |
| 488 | + // delay_ns / (2 * PPM cycle time (ns)) = 2**(15-N) |
| 489 | + // (delay_ns / 2) * PPM frequency (cycles/ns) = 2**(15-N) |
| 490 | + // (delay_ns / 2) * PPM frequency_MHz/1000 (cycles/us * us/1000ns -> cycles/ns) = 2**(15-N) |
| 491 | + // log2(delay_ns/2 * PPM Frequency_MHz/1000) = 15-N |
| 492 | + // N (pfet_delay_value) = 15 - log2(delay_ns/2 * PPM Frequency_MHz/1000); |
| 493 | + // N (pfet_delay_value) = 15 - log2(i_delay_ns/2 * (i_attr_proc_nest_frequency_MHz/4)/1000); |
| 494 | + // |
| 495 | + // dly = i_delay_ns/2 * (i_attr_proc_nest_frequency_MHz/4)/1000 |
470 | 496 | // pfet_delay_value = 15 - log2( dly );
|
471 |
| - dly = ( i_delay * i_proc_nest_frequency ); |
472 | 497 |
|
473 |
| - if ( dly <= 1400 ) |
474 |
| - { |
475 |
| - pfet_delay_value = 15 - 0 ; |
476 |
| - } |
477 |
| - else if (( 1400 < dly ) && ( dly <= 2800 ) ) |
478 |
| - { |
479 |
| - pfet_delay_value = 15 - 1 ; |
480 |
| - } |
481 |
| - else if (( 2800 < dly ) && ( dly <= 5600 ) ) |
482 |
| - { |
483 |
| - pfet_delay_value = 15 - 2 ; |
484 |
| - } |
485 |
| - else if (( 5600 < dly ) && ( dly <= 11500 ) ) |
486 |
| - { |
487 |
| - pfet_delay_value = 15 - 3 ; |
488 |
| - } |
489 |
| - else if (( 11500 < dly ) && ( dly <= 23000 ) ) |
490 |
| - { |
491 |
| - pfet_delay_value = 15 - 4 ; |
492 |
| - } |
493 |
| - else if (( 23000 < dly ) && ( dly <= 46000 ) ) |
494 |
| - { |
495 |
| - pfet_delay_value = 15 - 5 ; |
496 |
| - } |
497 |
| - else if (( 46000 < dly ) && ( dly <= 92000 ) ) |
498 |
| - { |
499 |
| - pfet_delay_value = 15 - 6 ; |
500 |
| - } |
501 |
| - else if (( 92000 < dly ) && ( dly <= 182000 ) ) |
502 |
| - { |
503 |
| - pfet_delay_value = 15 - 7 ; |
504 |
| - } |
505 |
| - else if (( 182000 < dly ) && ( dly <= 364000 ) ) |
506 |
| - { |
507 |
| - pfet_delay_value = 15 - 8 ; |
508 |
| - } |
509 |
| - else if (( 364000 < dly ) && ( dly <= 728000 ) ) |
510 |
| - { |
511 |
| - pfet_delay_value = 15 - 9 ; |
512 |
| - } |
513 |
| - else if (( 728000 < dly ) && ( dly <= 1456000 ) ) |
514 |
| - { |
515 |
| - pfet_delay_value = 15 - 10; |
516 |
| - } |
517 |
| - else if (( 1456000 < dly ) && ( dly <= 2912000 ) ) |
518 |
| - { |
519 |
| - pfet_delay_value = 15 - 11; |
520 |
| - } |
521 |
| - else if (( 2912000 < dly ) && ( dly <= 5824000 ) ) |
522 |
| - { |
523 |
| - pfet_delay_value = 15 - 12; |
524 |
| - } |
525 |
| - else if (( 5824000 < dly ) && ( dly <= 11648000 )) |
526 |
| - { |
527 |
| - pfet_delay_value = 15 - 13; |
528 |
| - } |
529 |
| - else if (( 11648000 < dly ) && ( dly <= 23296000 )) |
530 |
| - { |
531 |
| - pfet_delay_value = 15 - 14; |
532 |
| - } |
533 |
| - else if ( 23296000 < dly ) |
534 |
| - { |
535 |
| - pfet_delay_value = 15 - 15; |
536 |
| - } |
537 |
| - else |
| 498 | + dly = i_delay_ns / 2 * (i_proc_nest_frequency_MHz / 4 ) / 1000; |
| 499 | + FAPI_DBG("i_delay_ns = %d (0x%X), i_proc_nest_frequency_MHz = %d (0x%X), " |
| 500 | + "ppm_frequency_MHz = %d (0x%X), dly = %d (0x%08llX)", |
| 501 | + i_delay_ns, i_delay_ns, |
| 502 | + i_proc_nest_frequency_MHz, i_proc_nest_frequency_MHz, |
| 503 | + i_proc_nest_frequency_MHz / 4, i_proc_nest_frequency_MHz / 4, |
| 504 | + dly, dly ); |
| 505 | + |
| 506 | + uint16_t pow2bit_value = 0x8000; |
| 507 | + uint16_t value = (uint16_t)dly; |
| 508 | + |
| 509 | + // For log2, walk a 1 across the data to find the 2**i that is less than |
| 510 | + // or equal. |
| 511 | + for (uint32_t i = 0; i < 16; ++i) |
538 | 512 | {
|
539 |
| - pfet_delay_value = 15 - 15; |
| 513 | + if (pow2bit_value == value) // Matched exactly. We found the bit |
| 514 | + { |
| 515 | + FAPI_DBG("EQ i = %d pow2bit_value = 0x%04X, value = 0x%04X", i, pow2bit_value, value); |
| 516 | + pfet_delay_value = i; |
| 517 | + break; |
| 518 | + } |
| 519 | + else if (pow2bit_value < value) // Found bit that was less than |
| 520 | + { |
| 521 | + if (i == 0) |
| 522 | + { |
| 523 | + FAPI_DBG("LT but saturated: i = %d pow2bit_value = 0x%04X, value = 0x%04X", i, pow2bit_value, value); |
| 524 | + pfet_delay_value = i; |
| 525 | + } |
| 526 | + else |
| 527 | + { |
| 528 | + FAPI_DBG("LT but rounding up: i = %d pow2bit_value = 0x%04X, value = 0x%04X", i, pow2bit_value, value); |
| 529 | + pfet_delay_value = i - 1; // Power of 2 eg round up |
| 530 | + } |
| 531 | + |
| 532 | + break; |
| 533 | + } |
| 534 | + else // shift it right to check the next bit |
| 535 | + { |
| 536 | + pow2bit_value >>= 1; |
| 537 | + } |
540 | 538 | }
|
541 | 539 |
|
| 540 | + FAPI_DBG("pfet_delay_value = %d (0x%X))", |
| 541 | + pfet_delay_value, pfet_delay_value ); |
| 542 | + |
542 | 543 | return (pfet_delay_value);
|
543 | 544 | }
|
544 | 545 |
|
0 commit comments