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/perf.h>
0027 #include <subdev/pci.h>
0028
0029 u32
0030 nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr,
0031 u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
0032 {
0033 struct bit_entry bit_P;
0034 u32 perf = 0;
0035
0036 if (!bit_entry(bios, 'P', &bit_P)) {
0037 if (bit_P.version <= 2) {
0038 perf = nvbios_rd32(bios, bit_P.offset + 0);
0039 if (perf) {
0040 *ver = nvbios_rd08(bios, perf + 0);
0041 *hdr = nvbios_rd08(bios, perf + 1);
0042 if (*ver >= 0x40 && *ver < 0x41) {
0043 *cnt = nvbios_rd08(bios, perf + 5);
0044 *len = nvbios_rd08(bios, perf + 2);
0045 *snr = nvbios_rd08(bios, perf + 4);
0046 *ssz = nvbios_rd08(bios, perf + 3);
0047 return perf;
0048 } else
0049 if (*ver >= 0x20 && *ver < 0x40) {
0050 *cnt = nvbios_rd08(bios, perf + 2);
0051 *len = nvbios_rd08(bios, perf + 3);
0052 *snr = nvbios_rd08(bios, perf + 4);
0053 *ssz = nvbios_rd08(bios, perf + 5);
0054 return perf;
0055 }
0056 }
0057 }
0058 }
0059
0060 if (bios->bmp_offset) {
0061 if (nvbios_rd08(bios, bios->bmp_offset + 6) >= 0x25) {
0062 perf = nvbios_rd16(bios, bios->bmp_offset + 0x94);
0063 if (perf) {
0064 *hdr = nvbios_rd08(bios, perf + 0);
0065 *ver = nvbios_rd08(bios, perf + 1);
0066 *cnt = nvbios_rd08(bios, perf + 2);
0067 *len = nvbios_rd08(bios, perf + 3);
0068 *snr = 0;
0069 *ssz = 0;
0070 return perf;
0071 }
0072 }
0073 }
0074
0075 return 0;
0076 }
0077
0078 u32
0079 nvbios_perf_entry(struct nvkm_bios *bios, int idx,
0080 u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
0081 {
0082 u8 snr, ssz;
0083 u32 perf = nvbios_perf_table(bios, ver, hdr, cnt, len, &snr, &ssz);
0084 if (perf && idx < *cnt) {
0085 perf = perf + *hdr + (idx * (*len + (snr * ssz)));
0086 *hdr = *len;
0087 *cnt = snr;
0088 *len = ssz;
0089 return perf;
0090 }
0091 return 0;
0092 }
0093
0094 u32
0095 nvbios_perfEp(struct nvkm_bios *bios, int idx,
0096 u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *info)
0097 {
0098 u32 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len);
0099 memset(info, 0x00, sizeof(*info));
0100 info->pstate = nvbios_rd08(bios, perf + 0x00);
0101 switch (!!perf * *ver) {
0102 case 0x12:
0103 case 0x13:
0104 case 0x14:
0105 info->core = nvbios_rd32(bios, perf + 0x01) * 10;
0106 info->memory = nvbios_rd32(bios, perf + 0x05) * 20;
0107 info->fanspeed = nvbios_rd08(bios, perf + 0x37);
0108 if (*hdr > 0x38)
0109 info->voltage = nvbios_rd08(bios, perf + 0x38);
0110 break;
0111 case 0x21:
0112 case 0x23:
0113 case 0x24:
0114 info->fanspeed = nvbios_rd08(bios, perf + 0x04);
0115 info->voltage = nvbios_rd08(bios, perf + 0x05);
0116 info->shader = nvbios_rd16(bios, perf + 0x06) * 1000;
0117 info->core = info->shader + (signed char)
0118 nvbios_rd08(bios, perf + 0x08) * 1000;
0119 switch (bios->subdev.device->chipset) {
0120 case 0x49:
0121 case 0x4b:
0122 info->memory = nvbios_rd16(bios, perf + 0x0b) * 1000;
0123 break;
0124 default:
0125 info->memory = nvbios_rd16(bios, perf + 0x0b) * 2000;
0126 break;
0127 }
0128 break;
0129 case 0x25:
0130 info->fanspeed = nvbios_rd08(bios, perf + 0x04);
0131 info->voltage = nvbios_rd08(bios, perf + 0x05);
0132 info->core = nvbios_rd16(bios, perf + 0x06) * 1000;
0133 info->shader = nvbios_rd16(bios, perf + 0x0a) * 1000;
0134 info->memory = nvbios_rd16(bios, perf + 0x0c) * 1000;
0135 break;
0136 case 0x30:
0137 info->script = nvbios_rd16(bios, perf + 0x02);
0138 fallthrough;
0139 case 0x35:
0140 info->fanspeed = nvbios_rd08(bios, perf + 0x06);
0141 info->voltage = nvbios_rd08(bios, perf + 0x07);
0142 info->core = nvbios_rd16(bios, perf + 0x08) * 1000;
0143 info->shader = nvbios_rd16(bios, perf + 0x0a) * 1000;
0144 info->memory = nvbios_rd16(bios, perf + 0x0c) * 1000;
0145 info->vdec = nvbios_rd16(bios, perf + 0x10) * 1000;
0146 info->disp = nvbios_rd16(bios, perf + 0x14) * 1000;
0147 break;
0148 case 0x40:
0149 info->voltage = nvbios_rd08(bios, perf + 0x02);
0150 switch (nvbios_rd08(bios, perf + 0xb) & 0x3) {
0151 case 0:
0152 info->pcie_speed = NVKM_PCIE_SPEED_5_0;
0153 break;
0154 case 3:
0155 case 1:
0156 info->pcie_speed = NVKM_PCIE_SPEED_2_5;
0157 break;
0158 case 2:
0159 info->pcie_speed = NVKM_PCIE_SPEED_8_0;
0160 break;
0161 default:
0162 break;
0163 }
0164 info->pcie_width = 0xff;
0165 break;
0166 default:
0167 return 0;
0168 }
0169 return perf;
0170 }
0171
0172 u32
0173 nvbios_perfSe(struct nvkm_bios *bios, u32 perfE, int idx,
0174 u8 *ver, u8 *hdr, u8 cnt, u8 len)
0175 {
0176 u32 data = 0x00000000;
0177 if (idx < cnt) {
0178 data = perfE + *hdr + (idx * len);
0179 *hdr = len;
0180 }
0181 return data;
0182 }
0183
0184 u32
0185 nvbios_perfSp(struct nvkm_bios *bios, u32 perfE, int idx,
0186 u8 *ver, u8 *hdr, u8 cnt, u8 len,
0187 struct nvbios_perfS *info)
0188 {
0189 u32 data = nvbios_perfSe(bios, perfE, idx, ver, hdr, cnt, len);
0190 memset(info, 0x00, sizeof(*info));
0191 switch (!!data * *ver) {
0192 case 0x40:
0193 info->v40.freq = (nvbios_rd16(bios, data + 0x00) & 0x3fff) * 1000;
0194 break;
0195 default:
0196 break;
0197 }
0198 return data;
0199 }
0200
0201 int
0202 nvbios_perf_fan_parse(struct nvkm_bios *bios,
0203 struct nvbios_perf_fan *fan)
0204 {
0205 u8 ver, hdr, cnt, len, snr, ssz;
0206 u32 perf = nvbios_perf_table(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
0207 if (!perf)
0208 return -ENODEV;
0209
0210 if (ver >= 0x20 && ver < 0x40 && hdr > 6)
0211 fan->pwm_divisor = nvbios_rd16(bios, perf + 6);
0212 else
0213 fan->pwm_divisor = 0;
0214
0215 return 0;
0216 }