Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c9191aa authored by Martin Peres's avatar Martin Peres Committed by Ben Skeggs
Browse files

drm/nvd7/therm: handle another kind of PWM fans



This should fix fan management on many nvd7+ chipsets.

Signed-off-by: default avatarMartin Peres <martin.peres@labri.fr>
Tested-by: default avatarTimothée Ravier <tim@siosm.fr>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 61679fe1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ struct nouveau_therm {
	int (*pwm_ctrl)(struct nouveau_therm *, int line, bool);
	int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *);
	int (*pwm_set)(struct nouveau_therm *, int line, u32, u32);
	int (*pwm_clock)(struct nouveau_therm *);
	int (*pwm_clock)(struct nouveau_therm *, int line);

	int (*fan_get)(struct nouveau_therm *);
	int (*fan_set)(struct nouveau_therm *, int);
+2 −1
Original line number Diff line number Diff line
@@ -242,7 +242,8 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm)
	/* attempt to locate a drivable fan, and determine control method */
	ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func);
	if (ret == 0) {
		if (func.log[0] & DCB_GPIO_LOG_DIR_IN) {
		/* FIXME: is this really the place to perform such checks ? */
		if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) {
			nv_debug(therm, "GPIO_FAN is in input mode\n");
			ret = -EINVAL;
		} else {
+1 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ nouveau_fanpwm_set(struct nouveau_therm *therm, int percent)
	if (priv->base.bios.pwm_freq) {
		divs = 1;
		if (therm->pwm_clock)
			divs = therm->pwm_clock(therm);
			divs = therm->pwm_clock(therm, priv->func.line);
		divs /= priv->base.bios.pwm_freq;
	}

+1 −1
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
}

int
nv50_fan_pwm_clock(struct nouveau_therm *therm)
nv50_fan_pwm_clock(struct nouveau_therm *therm, int line)
{
	int chipset = nv_device(therm)->chipset;
	int crystal = nv_device(therm)->crystal;
+29 −11
Original line number Diff line number Diff line
@@ -32,10 +32,12 @@ static int
pwm_info(struct nouveau_therm *therm, int line)
{
	u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04));

	switch (gpio & 0x000000c0) {
	case 0x00000000: /* normal mode, possibly pwm forced off by us */
	case 0x00000040: /* nvio special */
		switch (gpio & 0x0000001f) {
		case 0x00: return 2;
		case 0x19: return 1;
		case 0x1c: return 0;
		default:
@@ -56,8 +58,9 @@ nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
	int indx = pwm_info(therm, line);
	if (indx < 0)
		return indx;

	else if (indx < 2)
		nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data);
	/* nothing to do for indx == 2, it seems hardwired to PTHERM */
	return 0;
}

@@ -67,12 +70,17 @@ nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
	int indx = pwm_info(therm, line);
	if (indx < 0)
		return indx;

	else if (indx < 2) {
		if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) {
			*divs = nv_rd32(therm, 0x00e114 + (indx * 8));
			*duty = nv_rd32(therm, 0x00e118 + (indx * 8));
			return 0;
		}
	} else if (indx == 2) {
		*divs = nv_rd32(therm, 0x0200d8) & 0x1fff;
		*duty = nv_rd32(therm, 0x0200dc) & 0x1fff;
		return 0;
	}

	return -EINVAL;
}
@@ -83,16 +91,26 @@ nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
	int indx = pwm_info(therm, line);
	if (indx < 0)
		return indx;

	else if (indx < 2) {
		nv_wr32(therm, 0x00e114 + (indx * 8), divs);
		nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000);
	} else if (indx == 2) {
		nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */
		nv_wr32(therm, 0x0200dc, duty | 0x40000000);
	}
	return 0;
}

static int
nvd0_fan_pwm_clock(struct nouveau_therm *therm)
nvd0_fan_pwm_clock(struct nouveau_therm *therm, int line)
{
	int indx = pwm_info(therm, line);
	if (indx < 0)
		return 0;
	else if (indx < 2)
		return (nv_device(therm)->crystal * 1000) / 20;
	else
		return nv_device(therm)->crystal * 1000 / 10;
}

static int
Loading