Purpose
This document describes the Virtual P-state (vP-state) Table in the NVIDIA VBIOS.
The Virtual P-state (vP-state) Table maps discreet points on the Voltage/Frequency curve to vP-states. These vP-states are typically used as caps (limits).
Note
|
This specification only provides the details about vP-state entry which is required to fetch base clock. |
Virtual P-state Table
The Virtual P-state Table starts with a header, followed immediately by an array of entries.
It consist of following sections:
-
Header – The version number, header size, size of each vP-state entry, number of vP-state entries, etc.
-
Entry – One for each vP-state. It consist of associated P-state.
-
Domain frequencies – Sub-table in vP-state entry table consisting of limits for domain frequencies.
The vP-state table is a part of BIOS information table’s (BIT) Performance table entry (ID = ‘P’ i.e. 0x50 and version = 2) and its location is extracted by reading 32 bit dword from an offset 0x38 from the performance table (refer to sample code).
Virtual P-state Table Version
This document describes vP-state table version 1.0 which is supported only on GPU families GF11X through GM20X (i.e. NVC0 through NV110 families as per nouveau’s code names).
Note
|
Table version and structure will change in Pascal and later GPUs. |
Virtual P-state Table Header Structure
Name | Bit width | Meaning and (Values) |
---|---|---|
Version |
8 |
Virtual P-state Table Version (0x10) |
Header Size |
8 |
Size of Virtual P-state Table Header in bytes (20) |
Base Entry Size |
8 |
Size of Virtual P-state Table Entry in bytes, not including the domain frequencies (5) |
Domain Freq Size |
8 |
Size of each Virtual P-state Domain Frequency Entry in bytes (2) |
Domain Freq Count |
8 |
Number of Virtual P-state Domain Frequencies allocated |
Entry Count |
8 |
Number of Virtual P-state Table Entries |
Reserved |
88 |
|
Index of Rated TDP vP-state (Base Clock) |
8 |
Fastest thermally sustainable vP-state for the TDP app on worst case silicon, worst case conditions (also known as base clock) |
Reserved |
40 |
Virtual P-state Table Entry Structure
Name | Bit width | Values and Meaning |
---|---|---|
P-state |
8 |
P-state associated with this vP-state. A value of 0xff indicates SKIP ENTRY. |
Reserved |
32 |
Virtual P-state Domain Frequency Entry Structure
This is a sub-table in Virtual P-state Table Entry. Domain frequency entries are indexed as per clock domain enumeration.
Name | Bit width | Values and Meaning |
---|---|---|
Domain Frequency |
16 |
Domain frequency associated with this vP-state in MHz. A value of 0 indicates that vP-states do not specify a limit for this domain. |
It is safe to assume that there will always be one domain frequency entry per vP-state table entry. Non-zero value of this entry belongs to GPC clock domain.
Sample code
Sample code to read base clock from vP-state table.
Note
|
this code is based on nouveau driver which is capable of reading various entries from BIT. |
1: void read_vpstate_table(struct nvkm_bios *bios) 2: { 3: struct bit_entry bit_P; 4: u16 vpstate_tbl = 0x0000, offset, domain_clk; 5: u8 ver, i, hdr_size, base_entry_size, domain_freq_size, domain_freq_count, base_clk_idx; 6: 7: if (!bit_entry(bios, 'P', &bit_P)) { 8: if (bit_P.version == 2) 9: vpstate_tbl = nvbios_rd16(bios, bit_P.offset + 0x38); 10: else 11: return; 12: 13: if (vpstate_tbl) { 14: ver = nvbios_rd08(bios, vpstate_tbl + 0); 15: printk("vP-state entry version = 0x%x\n", ver); 16: switch (ver) { 17: case 0x10: 18: printk("vP-state header size = %d\n", 19: hdr_size = nvbios_rd08(bios, vpstate_tbl + 1)); 20: printk("base entry size = %d\n", 21: base_entry_size = nvbios_rd08(bios, vpstate_tbl + 2)); 22: printk("domain freq entry size = %d\n", 23: domain_freq_size = nvbios_rd08(bios, vpstate_tbl + 3)); 24: printk("domain freq entries count = %d\n", 25: domain_freq_count = nvbios_rd08(bios, vpstate_tbl + 4)); 26: 27: 28: base_clk_idx = nvbios_rd08(bios, vpstate_tbl + 17); 29: printk("base clk index = %d\n", base_clk_idx); 30: 31: 32: offset = vpstate + hdr_size + 33: ((base_entry_size + (domain_freq_size * domain_freq_count)) * base_clk); 34: printk("offset = %d\n", offset); 35: 36: 37: printk("p-state for base clk = %d", 38: nvbios_rd08(bios, offset + 0)); 39: 40: for (i = 0; i < domain_freq_count; i++) { 41: domain_clk = nvbios_rd16(bios, offset + base_entry_size + 42: (i * domain_freq_size)); 43: printk("domain clock index = %d, domain clock limit value = %d MHz\n", 44: i, domain_clk); 45: } 46: 47: return; 48: default: 49: return; 50: } 51: } 52: } 53: 54: return; 55: }