0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include "priv.h"
0026
0027 static int
0028 pwm_info(struct nvkm_therm *therm, int *line, int *ctrl, int *indx)
0029 {
0030 struct nvkm_subdev *subdev = &therm->subdev;
0031
0032 if (*line == 0x04) {
0033 *ctrl = 0x00e100;
0034 *line = 4;
0035 *indx = 0;
0036 } else
0037 if (*line == 0x09) {
0038 *ctrl = 0x00e100;
0039 *line = 9;
0040 *indx = 1;
0041 } else
0042 if (*line == 0x10) {
0043 *ctrl = 0x00e28c;
0044 *line = 0;
0045 *indx = 0;
0046 } else {
0047 nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", *line);
0048 return -ENODEV;
0049 }
0050
0051 return 0;
0052 }
0053
0054 int
0055 nv50_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
0056 {
0057 struct nvkm_device *device = therm->subdev.device;
0058 u32 data = enable ? 0x00000001 : 0x00000000;
0059 int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
0060 if (ret == 0)
0061 nvkm_mask(device, ctrl, 0x00010001 << line, data << line);
0062 return ret;
0063 }
0064
0065 int
0066 nv50_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
0067 {
0068 struct nvkm_device *device = therm->subdev.device;
0069 int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
0070 if (ret)
0071 return ret;
0072
0073 if (nvkm_rd32(device, ctrl) & (1 << line)) {
0074 *divs = nvkm_rd32(device, 0x00e114 + (id * 8));
0075 *duty = nvkm_rd32(device, 0x00e118 + (id * 8));
0076 return 0;
0077 }
0078
0079 return -EINVAL;
0080 }
0081
0082 int
0083 nv50_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
0084 {
0085 struct nvkm_device *device = therm->subdev.device;
0086 int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
0087 if (ret)
0088 return ret;
0089
0090 nvkm_wr32(device, 0x00e114 + (id * 8), divs);
0091 nvkm_wr32(device, 0x00e118 + (id * 8), duty | 0x80000000);
0092 return 0;
0093 }
0094
0095 int
0096 nv50_fan_pwm_clock(struct nvkm_therm *therm, int line)
0097 {
0098 struct nvkm_device *device = therm->subdev.device;
0099 int pwm_clock;
0100
0101
0102 if (device->chipset > 0x50 && device->chipset < 0x94) {
0103 u8 pwm_div = nvkm_rd32(device, 0x410c);
0104 if (nvkm_rd32(device, 0xc040) & 0x800000) {
0105
0106
0107 pwm_clock = (100000000 >> pwm_div) * 10 / 24;
0108 } else {
0109
0110 pwm_clock = (device->crystal * 1000) >> pwm_div;
0111 pwm_clock /= 20;
0112 }
0113 } else {
0114 pwm_clock = (device->crystal * 1000) / 20;
0115 }
0116
0117 return pwm_clock;
0118 }
0119
0120 static void
0121 nv50_sensor_setup(struct nvkm_therm *therm)
0122 {
0123 struct nvkm_device *device = therm->subdev.device;
0124 nvkm_mask(device, 0x20010, 0x40000000, 0x0);
0125 mdelay(20);
0126 }
0127
0128 static int
0129 nv50_temp_get(struct nvkm_therm *therm)
0130 {
0131 struct nvkm_device *device = therm->subdev.device;
0132 struct nvbios_therm_sensor *sensor = &therm->bios_sensor;
0133 int core_temp;
0134
0135 core_temp = nvkm_rd32(device, 0x20014) & 0x3fff;
0136
0137
0138 if (!sensor->slope_div || !sensor->slope_mult ||
0139 !sensor->offset_num || !sensor->offset_den)
0140 return -ENODEV;
0141
0142 core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
0143 core_temp = core_temp + sensor->offset_num / sensor->offset_den;
0144 core_temp = core_temp + sensor->offset_constant - 8;
0145
0146
0147 if (core_temp < 0)
0148 core_temp = 0;
0149
0150 return core_temp;
0151 }
0152
0153 static void
0154 nv50_therm_init(struct nvkm_therm *therm)
0155 {
0156 nv50_sensor_setup(therm);
0157 }
0158
0159 static const struct nvkm_therm_func
0160 nv50_therm = {
0161 .init = nv50_therm_init,
0162 .intr = nv40_therm_intr,
0163 .pwm_ctrl = nv50_fan_pwm_ctrl,
0164 .pwm_get = nv50_fan_pwm_get,
0165 .pwm_set = nv50_fan_pwm_set,
0166 .pwm_clock = nv50_fan_pwm_clock,
0167 .temp_get = nv50_temp_get,
0168 .program_alarms = nvkm_therm_program_alarms_polling,
0169 };
0170
0171 int
0172 nv50_therm_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
0173 struct nvkm_therm **ptherm)
0174 {
0175 return nvkm_therm_new_(&nv50_therm, device, type, inst, ptherm);
0176 }