summaryrefslogtreecommitdiffstats
path: root/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c
blob: 5c1f442d6b13da39405ddc7c89ed84e2c4a90c26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c $              */
/*                                                                        */
/* IBM CONFIDENTIAL                                                       */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2013,2014              */
/*                                                                        */
/* p1                                                                     */
/*                                                                        */
/* Object Code Only (OCO) source materials                                */
/* Licensed Internal Code Source Materials                                */
/* IBM HostBoot Licensed Internal Code                                    */
/*                                                                        */
/* The source code for this program is not published or otherwise         */
/* divested of its trade secrets, irrespective of what has been           */
/* deposited with the U.S. Copyright Office.                              */
/*                                                                        */
/* Origin: 30                                                             */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
// $Id: lab_pstates.c,v 1.9 2014/02/21 03:02:20 jmcgill Exp $

/// \file lab_pstates.c
/// \brief Lab-only (as opposed to product-procedure) support for Pstates.
///
/// Lab-only Pstate support is separated from generic Pstate support to reduce
/// the size of OCC product firmware images.

#include "ssx.h"
// jwy #include "ppc32.h"
#include "lab_pstates.h"
// jwy #include "pmc_register_addresses.h"
// jwy #include "pmc_firmware_registers.h"
// jwy #include "pcbs_register_addresses.h"
// jwy #include "pcbs_firmware_registers.h"

/// Convert a voltage in microvolts to a VRM-11 VID code, rounding the implied
/// voltage as required.
///
/// \param v_uv Voltage in micro-volts
///
/// \param round \a round >= 0 indicate round voltage up, while \a round < 0
/// implies round voltage down
///
/// \param vrm11_vid A pointer to the location of the final VID code. This
/// location is updated even if the final VID code is invalid.
///
/// \bug Confirm if the 1.6125V offset is still valid for PgP

// Recall that VRM11 is inverted; rounding a VID code up rounds down the
// voltage. 

int
vuv2vrm11(uint32_t v_uv, int round, uint8_t *vrm11_vid)
{
    int32_t offset, vid;

    offset = VRM11_BASE_UV - v_uv;
    vid = offset / VRM11_STEP_UV;

    if (((offset % VRM11_STEP_UV) != 0) && (round < 0)) {
        vid++;
    }

    *vrm11_vid = vid;
    return vid11_validate(vid);
}


/// Convert a VRM-11 VID code to a voltage in microvolts

int
vrm112vuv(uint8_t vrm11_vid, uint32_t *v_uv)
{
    *v_uv= VRM11_BASE_UV - (vrm11_vid * VRM11_STEP_UV);
    return vid11_validate(vrm11_vid);
}


/// Convert a voltage in microvolts to an internal VID code, rounding the
/// implied voltage as required.
///
/// \param v_uv Voltage in micro-volts
///
/// \param round \a round >= 0 indicate round voltage up, while \a round < 0
/// implies round voltage down
///
/// \param ivid A pointer to the location of the final VID code.  This
/// location is updated even the event of errors.
///
/// \retval 0 Success
///
/// \retval -IVID_INVALID_VOLTAGE If \a v_uv can not be converted to a legal
/// IVID encoding. 

int
vuv2ivid(uint32_t v_uv, int round, uint8_t *ivid)
{
    int rc;
    int32_t offset, vid;

    offset = v_uv - IVID_BASE_UV;
    vid = offset / IVID_STEP_UV;

    if (((offset % IVID_STEP_UV) != 0) && (round >= 0)) {
	    vid++;
    }
    
    *ivid = vid;
    if ((vid < 0) || (vid > 0x7f)) {
        rc = -IVID_INVALID_VOLTAGE;
    } else {
        rc = 0;
    }
    return rc;
}
    
/// Convert an iVID code to a voltage in microvolts

int
ivid2vuv(uint8_t ivid, uint32_t *v_uv)
{
    if (ivid > 0x7f) {
    return -IVID_INVALID_VOLTAGE;
    } else {
    *v_uv= IVID_BASE_UV + (ivid * IVID_STEP_UV);
    return 0;
    }
}

/// Format a voltage in microvolts as 10 microvolts into a user-supplied
/// string..  The string \a s must be able to store at least
/// FORMAT_10UV_STRLEN characters.

int
sprintf_10uv(char *s, uint32_t v_uv)
{
    return sprintf(s, "%d.%05d", v_uv / 1000000, (v_uv % 1000000) / 10);
}

#ifdef FAPIECMD

/// Format a voltage in microvolts as 10 microvolts to a stream.

int
fprintf_10uv(FILE *stream, uint32_t v_uv)
{
    int rc;
    char s[FORMAT_10UV_STRLEN];

    rc = sprintf_10uv(s, v_uv);
    if (rc > 0) {
    rc = fputs(s, stream);
    }
    return rc;
}


/// Format a VRM-11 VID code as 10 microvolts into a user-supplied string. The
/// string \a s must be able to store at least FORMAT_10UV_STRLEN characters.

int
sprintf_vrm11(char *s, uint8_t vrm11)
{
    int rc;
    uint32_t v_uv;

    if ((rc = vrm112vuv(vrm11, &v_uv)) != 0) {
        strcpy(s, FORMAT_10UV_ERROR);
    } else {
        rc = sprintf_10uv(s, v_uv);
    }
    return rc;
}


/// Format a VRM-11 VID code as 10 microvolts to a stream.

int
fprintf_vrm11(FILE *stream, uint8_t vrm11)
{
    int rc;
    char s[FORMAT_10UV_STRLEN];

    rc = sprintf_vrm11(s, vrm11);
    if (rc > 0) {
    rc = fputs(s, stream);
    }
    return rc;
}


/// Format an IVID code as 10 microvolts into a user-supplied string. The
/// string \a s must be able to store at least FORMAT_10UV_STRLEN characters.

int
sprintf_ivid(char *s, uint8_t ivid)
{
    int rc;
    uint32_t v_uv;

    if ((rc = ivid2vuv(ivid, &v_uv)) != 0) {
    return rc;
    }
    return sprintf_10uv(s, v_uv);
}


/// Format an iVID code as 10 microvolts to a stream.

int
fprintf_ivid(FILE *stream, uint8_t ivid)
{
    int rc;
    char s[FORMAT_10UV_STRLEN];

    rc = sprintf_ivid(s, ivid);
    if (rc > 0) {
    rc = fputs(s, stream);
    }
    return rc;
}


// NB: The gpst_print() routine only needs the revle* functions when compiled
// into little-endian Linux applications, which must provide their
// implementations. 

#ifdef _BIG_ENDIAN

#define revle16(x) x
#define revle32(x) x
#define revle64(x) x

#else

uint16_t revle16(uint16_t i_x);
uint32_t revle32(uint32_t i_x);
uint64_t revle64(uint64_t i_x);

#endif


/// Print a GlobalPstateTable structure on a given stream
///
/// \param stream The output stream
///
/// \param gpst The Global Pstate Table to print

void
gpst_print(FILE *stream, GlobalPstateTable *gpst)
{
    // Endian-corrected scalar Pstate fields

    uint32_t options;
    uint32_t pstate0_frequency_khz, frequency_step_khz;
    uint8_t entries, pstate_stepsize, vrm_stepdelay_range, vrm_stepdelay_value;
    Pstate pmin, pvsafe, psafe;

    // Endian-corrected vector Pstate fields

    gpst_entry_t entry;

    // Other local variables

    int i;
    uint8_t evid_vdd, evid_vcs, evid_vdd_eff, evid_vcs_eff,
    maxreg_vdd, maxreg_vcs;
    int8_t pstate;
    char evid_vdd_str[FORMAT_10UV_STRLEN];
    char evid_vcs_str[FORMAT_10UV_STRLEN];
    char evid_vdd_eff_str[FORMAT_10UV_STRLEN];
    char evid_vcs_eff_str[FORMAT_10UV_STRLEN];
    char maxreg_vdd_str[FORMAT_10UV_STRLEN];
    char maxreg_vcs_str[FORMAT_10UV_STRLEN];

    // Get endian-corrected scalars

    options = revle32(gpst->options.options);
    pstate0_frequency_khz = revle32(gpst->pstate0_frequency_khz);
    frequency_step_khz = revle32(gpst->frequency_step_khz);
    entries = gpst->entries;
    pstate_stepsize = gpst->pstate_stepsize;
    vrm_stepdelay_range = gpst->vrm_stepdelay_range;
    vrm_stepdelay_value = gpst->vrm_stepdelay_value;
    pmin = gpst->pmin;
    pvsafe = gpst->pvsafe;
    psafe = gpst->psafe;


    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    
    fprintf(stream, "Global Pstate Table @ %p\n", gpst);
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    
    fprintf(stream, "%d Entries from %+d to %+d\n",
        entries, gpst_pmin(gpst), gpst_pmax(gpst));
    fprintf(stream, "Frequency Step = %u KHz\n", frequency_step_khz);
    fprintf(stream, "Pstate 0 Frequency = %u KHz\n", pstate0_frequency_khz);
    fprintf(stream, "Pstate 0 Frequency Code (per core) :");
    for (i = 0; i < PGP_NCORES; i++) {
        if ((i != 0) && ((i % 4) == 0)) {
            fprintf(stream, "\n                                    ");
        }
        fprintf(stream, " 0x%03x", revle16(gpst->pstate0_frequency_code[i]));
    }
    fprintf(stream, "\n");
    fprintf(stream, "DPLL Fmax Bias (per core)          :");
    for (i = 0; i < PGP_NCORES; i++) {
        fprintf(stream, " %d", gpst->dpll_fmax_bias[i]);
    }
    fprintf(stream, "\n");
    fprintf(stream, "Pstate Step Size %u, VRM Range %u, VRM Delay %u\n",
            pstate_stepsize, vrm_stepdelay_range, vrm_stepdelay_value);
    fprintf(stream, "Pvsafe %d, Psafe %d\n", pvsafe, psafe);
    
    if (options == 0) {
        fprintf(stream, "No Options\n");
    } else {
        fprintf(stream, "Options 0x%08x:\n", options);
        if (options & PSTATE_NO_COPY_GPST) {
            fprintf(stream, "    PSTATE_NO_COPY_GPST\n");
        }
        if (options & PSTATE_NO_INSTALL_GPST) {
            fprintf(stream, "    PSTATE_NO_INSTALL_GPST\n");
        }
        if (options & PSTATE_NO_INSTALL_LPSA) {
            fprintf(stream, "    PSTATE_NO_INSTALL_LPSA\n");
        }
        if (options & PSTATE_NO_INSTALL_RESCLK) {
            fprintf(stream, "    PSTATE_NO_INSTALL_RESCLK\n");
        }
        if (options & PSTATE_FORCE_INITIAL_PMIN) {
            fprintf(stream, "    PSTATE_FORCE_INITIAL_PMIN\n");
        }
    }
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    
    fprintf(stream, 
        "  I Pstate F(MHz) evid_vdd(V)  evid_vcs(V) evid_vdd_eff(V) evid_vcs_eff(V) maxreg_vdd(V)  maxreg_vcs(V)\n"
        "---------------------------------------------------------------------------------------------------------\n");

    for (i = gpst->entries - 1; i >= 0; i--) {

        entry.value = revle64(gpst->pstate[i].value);
    
    evid_vdd = entry.fields.evid_vdd;
    sprintf_vrm11(evid_vdd_str, evid_vdd);

    evid_vcs = entry.fields.evid_vcs;
    sprintf_vrm11(evid_vcs_str, evid_vcs);

    evid_vdd_eff = entry.fields.evid_vdd_eff;
    sprintf_ivid(evid_vdd_eff_str, evid_vdd_eff);

    evid_vcs_eff = entry.fields.evid_vcs_eff;
    sprintf_ivid(evid_vcs_eff_str, evid_vcs_eff);

    maxreg_vdd = entry.fields.maxreg_vdd;
    sprintf_ivid(maxreg_vdd_str, maxreg_vdd);

    maxreg_vcs = entry.fields.maxreg_vcs;
    sprintf_ivid(maxreg_vcs_str, maxreg_vcs);

    pstate = gpst_pmin(gpst) + i;

    fprintf(stream, 
        "%3d %+4d    "
        "%4d  "
        "0x%02x %s  "
        "0x%02x %s  "
        "0x%02x %s    "
        "0x%02x %s   "
        "0x%02x %s   "
        "0x%02x %s\n",
        i, pstate,
        (pstate0_frequency_khz + (frequency_step_khz * pstate)) / 1000,
        evid_vdd, evid_vdd_str,
        evid_vcs, evid_vcs_str,
        evid_vdd_eff, evid_vdd_eff_str,
        evid_vcs_eff, evid_vcs_eff_str,
        maxreg_vdd, maxreg_vdd_str,
        maxreg_vcs, maxreg_vcs_str);
    }
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    
}


/// Print a LocalPstateArray structure on a given stream
///
/// \param stream The output stream
///
/// \param lpsa The Local Pstate Array to print
///
/// \todo Replace the hex dump with a decoded Local Pstate Table + ivrm table

void
lpsa_print(FILE* stream, LocalPstateArray* lpsa)
{
    int i;
    uint8_t entries;
    uint8_t entries_div4;
    char ivid_vdd_str[FORMAT_10UV_STRLEN];
    char ivid_vcs_str[FORMAT_10UV_STRLEN]; 
    uint8_t ivid_vdd, ivid_vcs;
    lpst_entry_t   lpst_entry;
    vdsvin_entry_t vdsvin_entry;

    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    
    fprintf(stream, "Local Pstate Array @ %p\n", lpsa);
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    
    fprintf(stream, "%d Entries from %+d to %+d\n",
        lpsa->entries, lpst_pmin(lpsa), lpst_pmax(lpsa));
    fprintf(stream, "Step Delay Rising %u, Step Delay Falling %u\n",
            lpsa->stepdelay_rising,
            lpsa->stepdelay_lowering);
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------------------\n");    
    fprintf(stream, 
        " I  ivid_vdd(V)   ivid_vcs(V)   Core vdd  Core vcs  ECO vdd   ECO vcs   ps1 inc  ps2 inc  ps3 inc  inc step  dec step\n"
        "                                pwrratio  pwrratio  pwrratio  pwrratio                                               \n"
        "---------------------------------------------------------------------------------------------------------------------\n");
        
    entries      = lpsa->entries;
    entries_div4 = entries/4;    
    
    if ( entries % 4 != 0)
       entries_div4++;
        
    for (i = entries_div4-1  ; i >= 0; i--) {    
      lpst_entry.value = revle64(lpsa->pstate[i].value);
    
      ivid_vdd = lpst_entry.fields.ivid_vdd;
      sprintf_ivid(ivid_vdd_str, ivid_vdd);

      ivid_vcs = lpst_entry.fields.ivid_vcs;
      sprintf_ivid(ivid_vcs_str, ivid_vcs);

      fprintf(stream,
           "%2u  "
           "0x%02x %s  "
           "0x%02x %s  "
           "%-9u %-9u %-9u %-9u "
           "%-8u %-8u %-8u "
           "%-9u %-9u \n",
           i,
           ivid_vdd, ivid_vdd_str,
           ivid_vcs, ivid_vcs_str,
           (uint8_t)lpst_entry.fields.vdd_core_pwrratio,
           (uint8_t)lpst_entry.fields.vcs_core_pwrratio,
           (uint8_t)lpst_entry.fields.vdd_eco_pwrratio,
           (uint8_t)lpst_entry.fields.vcs_eco_pwrratio,
           (uint8_t)lpst_entry.fields.ps1_vid_incr,
           (uint8_t)lpst_entry.fields.ps2_vid_incr,
           (uint8_t)lpst_entry.fields.ps3_vid_incr,
           (uint8_t)lpst_entry.fields.inc_step,
           (uint8_t)lpst_entry.fields.dec_step);
    }

    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------------------\n\n");   

   fprintf(stream, 
        "--------------------------------\n");
   fprintf(stream,            
        "VDS\n");    
    fprintf(stream, 
        " I    beg_offset  end_offset    \n"
        "--------------------------------\n");     

    for (i = 15  ; i >= 0; i--) {    
      vdsvin_entry.value = revle64(lpsa->vdsvin[i].value);
    
      fprintf(stream,
           "%2u    "
           "%-10u  "
           "%-10u   \n",
           i,
           (uint8_t)vdsvin_entry.fields.ivid0,
           (uint8_t)vdsvin_entry.fields.ivid1);
    }

    fprintf(stream, 
        "--------------------------------\n\n");   
        

   fprintf(stream, 
        "-----------------------------------------------------\n");
   fprintf(stream,        
        "VIN\n");    
    fprintf(stream, 
        " I    ptef0 pfet1 pfet2 pfet3 pfet4 pfet5 pfet6 pfet7\n"
        "-----------------------------------------------------\n");     

    for (i = 63  ; i >= 0; i--) {    
      vdsvin_entry.value = revle64(lpsa->vdsvin[i].value);

      fprintf(stream,
           "%2u    "
           "%-5u %-5u %-5u %-5u %-5u %-5u %-5u %-5u\n",
           i,
           (uint8_t)vdsvin_entry.fields.pfet0, 
           (uint8_t)vdsvin_entry.fields.pfet1, 
           (uint8_t)vdsvin_entry.fields.pfet2, 
           (uint8_t)vdsvin_entry.fields.pfet3, 
           (uint8_t)vdsvin_entry.fields.pfet4, 
           (uint8_t)vdsvin_entry.fields.pfet5, 
           (uint8_t)vdsvin_entry.fields.pfet6, 
           (uint8_t)vdsvin_entry.fields.pfet7);           
    }  
    
    fprintf(stream, 
        "-----------------------------------------------------\n\n");   
}    

/// Print CPM Pstate Range structure on a given stream
///
/// \param stream   The output stream
///
/// \param cpmrange The CPM Pstate Range structure to print

void
cpmrange_print(FILE* stream, CpmPstateModeRanges* cpmrange)
{
    int i;
    
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    
    fprintf(stream, "CPM Pstate Range @ %p\n",  cpmrange);
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    

    fprintf(stream, "Valid Number of CPM Pstate Ranges : %u\n", 
            cpmrange->validRanges);
            
    for (i = 0; i < 8; i++) {        
      fprintf(stream, "  CPM Range %d Pstate : %d\n", 
              i, cpmrange->inflectionPoint[i]);
    }
    
    fprintf(stream, "  CPM Pmax : %d\n", 
            cpmrange->pMax);    
    
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    
}

/// Print a Resonant Clocking Setup structure on a given stream
///
/// \param stream The output stream
///
/// \param resclk The ResonantClockingSetup to print

void
resclk_print(FILE* stream, ResonantClockingSetup* resclk)
{
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    
    fprintf(stream, "Resonant Clocking Setup @ %p\n", resclk);
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    

    fprintf(stream, "Full Clock Sector Buffer Pstate      : %d\n", 
            resclk->full_csb_ps);
    fprintf(stream, "Low Frequency Resonant Lower Pstate  : %d\n", 
            resclk->res_low_lower_ps);
    fprintf(stream, "Low Frequency Resonant Upper Pstate  : %d\n", 
            resclk->res_low_upper_ps);
    fprintf(stream, "High Frequency Resonant Lower Pstate : %d\n", 
            resclk->res_high_lower_ps);
    fprintf(stream, "High Frequency Resonant Upper Pstate : %d\n", 
            resclk->res_high_upper_ps);
    
    fprintf(stream, 
        "---------------------------------------------------------------------------------------------------------\n");    
}    


/// Print a PstateSuperStructure on a given stream
///
/// \param stream The output stream
///
/// \param pss The PstateSuperStructure to print

void
pss_print(FILE* stream, PstateSuperStructure* pss)
{
    fprintf(stream, 
        "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");    
    fprintf(stream, "PstateSuperStructure @ %p\n", pss);
    fprintf(stream, 
        "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");    
    
    gpst_print(stream, &(pss->gpst));
    lpsa_print(stream, &(pss->lpsa));
    resclk_print(stream, &(pss->resclk));

    fprintf(stream, 
        "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");    
}

    
#endif // FAPIECMD    
OpenPOWER on IntegriCloud