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/therm.h>
0027
0028 static u32
0029 therm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
0030 {
0031 struct bit_entry bit_P;
0032 u32 therm = 0;
0033
0034 if (!bit_entry(bios, 'P', &bit_P)) {
0035 if (bit_P.version == 1)
0036 therm = nvbios_rd32(bios, bit_P.offset + 12);
0037 else if (bit_P.version == 2)
0038 therm = nvbios_rd32(bios, bit_P.offset + 16);
0039 else
0040 nvkm_error(&bios->subdev,
0041 "unknown offset for thermal in BIT P %d\n",
0042 bit_P.version);
0043 }
0044
0045
0046 if (!therm)
0047 return 0;
0048
0049 *ver = nvbios_rd08(bios, therm + 0);
0050 *hdr = nvbios_rd08(bios, therm + 1);
0051 *len = nvbios_rd08(bios, therm + 2);
0052 *cnt = nvbios_rd08(bios, therm + 3);
0053 return therm + nvbios_rd08(bios, therm + 1);
0054 }
0055
0056 static u32
0057 nvbios_therm_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
0058 {
0059 u8 hdr, cnt;
0060 u32 therm = therm_table(bios, ver, &hdr, len, &cnt);
0061 if (therm && idx < cnt)
0062 return therm + idx * *len;
0063 return 0;
0064 }
0065
0066 int
0067 nvbios_therm_sensor_parse(struct nvkm_bios *bios,
0068 enum nvbios_therm_domain domain,
0069 struct nvbios_therm_sensor *sensor)
0070 {
0071 s8 thrs_section, sensor_section, offset;
0072 u8 ver, len, i;
0073 u32 entry;
0074
0075
0076 if (domain != NVBIOS_THERM_DOMAIN_CORE)
0077 return -EINVAL;
0078
0079
0080 thrs_section = 0;
0081 sensor_section = -1;
0082 i = 0;
0083 while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
0084 s16 value = nvbios_rd16(bios, entry + 1);
0085
0086 switch (nvbios_rd08(bios, entry + 0)) {
0087 case 0x0:
0088 thrs_section = value;
0089 if (value > 0)
0090 return 0;
0091 break;
0092 case 0x01:
0093 sensor_section++;
0094 if (sensor_section == 0) {
0095 offset = ((s8) nvbios_rd08(bios, entry + 2)) / 2;
0096 sensor->offset_constant = offset;
0097 }
0098 break;
0099
0100 case 0x04:
0101 if (thrs_section == 0) {
0102 sensor->thrs_critical.temp = (value & 0xff0) >> 4;
0103 sensor->thrs_critical.hysteresis = value & 0xf;
0104 }
0105 break;
0106
0107 case 0x07:
0108 if (thrs_section == 0) {
0109 sensor->thrs_down_clock.temp = (value & 0xff0) >> 4;
0110 sensor->thrs_down_clock.hysteresis = value & 0xf;
0111 }
0112 break;
0113
0114 case 0x08:
0115 if (thrs_section == 0) {
0116 sensor->thrs_fan_boost.temp = (value & 0xff0) >> 4;
0117 sensor->thrs_fan_boost.hysteresis = value & 0xf;
0118 }
0119 break;
0120
0121 case 0x10:
0122 if (sensor_section == 0)
0123 sensor->offset_num = value;
0124 break;
0125
0126 case 0x11:
0127 if (sensor_section == 0)
0128 sensor->offset_den = value;
0129 break;
0130
0131 case 0x12:
0132 if (sensor_section == 0)
0133 sensor->slope_mult = value;
0134 break;
0135
0136 case 0x13:
0137 if (sensor_section == 0)
0138 sensor->slope_div = value;
0139 break;
0140 case 0x32:
0141 if (thrs_section == 0) {
0142 sensor->thrs_shutdown.temp = (value & 0xff0) >> 4;
0143 sensor->thrs_shutdown.hysteresis = value & 0xf;
0144 }
0145 break;
0146 }
0147 }
0148
0149 return 0;
0150 }
0151
0152 int
0153 nvbios_therm_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan)
0154 {
0155 struct nvbios_therm_trip_point *cur_trip = NULL;
0156 u8 ver, len, i;
0157 u32 entry;
0158
0159 uint8_t duty_lut[] = { 0, 0, 25, 0, 40, 0, 50, 0,
0160 75, 0, 85, 0, 100, 0, 100, 0 };
0161
0162 i = 0;
0163 fan->nr_fan_trip = 0;
0164 fan->fan_mode = NVBIOS_THERM_FAN_OTHER;
0165 while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
0166 s16 value = nvbios_rd16(bios, entry + 1);
0167
0168 switch (nvbios_rd08(bios, entry + 0)) {
0169 case 0x22:
0170 fan->min_duty = value & 0xff;
0171 fan->max_duty = (value & 0xff00) >> 8;
0172 break;
0173 case 0x24:
0174 fan->nr_fan_trip++;
0175 if (fan->fan_mode > NVBIOS_THERM_FAN_TRIP)
0176 fan->fan_mode = NVBIOS_THERM_FAN_TRIP;
0177 cur_trip = &fan->trip[fan->nr_fan_trip - 1];
0178 cur_trip->hysteresis = value & 0xf;
0179 cur_trip->temp = (value & 0xff0) >> 4;
0180 cur_trip->fan_duty = duty_lut[(value & 0xf000) >> 12];
0181 break;
0182 case 0x25:
0183 cur_trip = &fan->trip[fan->nr_fan_trip - 1];
0184 cur_trip->fan_duty = value;
0185 break;
0186 case 0x26:
0187 if (!fan->pwm_freq)
0188 fan->pwm_freq = value;
0189 break;
0190 case 0x3b:
0191 fan->bump_period = value;
0192 break;
0193 case 0x3c:
0194 fan->slow_down_period = value;
0195 break;
0196 case 0x46:
0197 if (fan->fan_mode > NVBIOS_THERM_FAN_LINEAR)
0198 fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
0199 fan->linear_min_temp = nvbios_rd08(bios, entry + 1);
0200 fan->linear_max_temp = nvbios_rd08(bios, entry + 2);
0201 break;
0202 }
0203 }
0204
0205
0206 if (bios->subdev.device->card_type >= NV_C0 &&
0207 fan->fan_mode == NVBIOS_THERM_FAN_OTHER) {
0208 fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
0209 }
0210
0211 return 0;
0212 }