0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <subdev/bios.h>
0025 #include <subdev/bios/bit.h>
0026 #include <subdev/bios/vpstate.h>
0027
0028 static u32
0029 nvbios_vpstate_offset(struct nvkm_bios *b)
0030 {
0031 struct bit_entry bit_P;
0032
0033 if (!bit_entry(b, 'P', &bit_P)) {
0034 if (bit_P.version == 2 && bit_P.length >= 0x3c)
0035 return nvbios_rd32(b, bit_P.offset + 0x38);
0036 }
0037
0038 return 0x0000;
0039 }
0040
0041 int
0042 nvbios_vpstate_parse(struct nvkm_bios *b, struct nvbios_vpstate_header *h)
0043 {
0044 if (!h)
0045 return -EINVAL;
0046
0047 h->offset = nvbios_vpstate_offset(b);
0048 if (!h->offset)
0049 return -ENODEV;
0050
0051 h->version = nvbios_rd08(b, h->offset);
0052 switch (h->version) {
0053 case 0x10:
0054 h->hlen = nvbios_rd08(b, h->offset + 0x1);
0055 h->elen = nvbios_rd08(b, h->offset + 0x2);
0056 h->slen = nvbios_rd08(b, h->offset + 0x3);
0057 h->scount = nvbios_rd08(b, h->offset + 0x4);
0058 h->ecount = nvbios_rd08(b, h->offset + 0x5);
0059
0060 h->base_id = nvbios_rd08(b, h->offset + 0x0f);
0061 if (h->hlen > 0x10)
0062 h->boost_id = nvbios_rd08(b, h->offset + 0x10);
0063 else
0064 h->boost_id = 0xff;
0065 if (h->hlen > 0x11)
0066 h->tdp_id = nvbios_rd08(b, h->offset + 0x11);
0067 else
0068 h->tdp_id = 0xff;
0069 return 0;
0070 default:
0071 return -EINVAL;
0072 }
0073 }
0074
0075 int
0076 nvbios_vpstate_entry(struct nvkm_bios *b, struct nvbios_vpstate_header *h,
0077 u8 idx, struct nvbios_vpstate_entry *e)
0078 {
0079 u32 offset;
0080
0081 if (!e || !h || idx > h->ecount)
0082 return -EINVAL;
0083
0084 offset = h->offset + h->hlen + idx * (h->elen + (h->slen * h->scount));
0085 e->pstate = nvbios_rd08(b, offset);
0086 e->clock_mhz = nvbios_rd16(b, offset + 0x5);
0087 return 0;
0088 }