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

Commit cb9fa626 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nv50/pm: add support for pwm fan control



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 8f27c543
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -167,8 +167,11 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
		}
	}

	if (pm->fanspeed_get)
		perflvl->fanspeed = pm->fanspeed_get(dev);
	if (pm->fanspeed_get) {
		ret = pm->fanspeed_get(dev);
		if (ret > 0)
			perflvl->fanspeed = ret;
	}

	return 0;
}
+2 −0
Original line number Diff line number Diff line
@@ -66,6 +66,8 @@ int nv50_pm_clock_get(struct drm_device *, u32 id);
void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *,
			u32 id, int khz);
void nv50_pm_clock_set(struct drm_device *, void *);
int nv50_pm_fanspeed_get(struct drm_device *);
int nv50_pm_fanspeed_set(struct drm_device *, int percent);

/* nva3_pm.c */
int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
+4 −0
Original line number Diff line number Diff line
@@ -386,6 +386,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
			engine->pm.temp_get	= nv84_temp_get;
		else
			engine->pm.temp_get	= nv40_temp_get;
		engine->pm.fanspeed_get		= nv50_pm_fanspeed_get;
		engine->pm.fanspeed_set		= nv50_pm_fanspeed_set;
		engine->vram.init		= nv50_vram_init;
		engine->vram.takedown		= nv50_vram_fini;
		engine->vram.get		= nv50_vram_new;
@@ -441,6 +443,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
		engine->pm.clocks_get		= nvc0_pm_clocks_get;
		engine->pm.voltage_get		= nouveau_voltage_gpio_get;
		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
		engine->pm.fanspeed_get		= nv50_pm_fanspeed_get;
		engine->pm.fanspeed_set		= nv50_pm_fanspeed_set;
		break;
	case 0xd0:
		engine->instmem.init		= nvc0_instmem_init;
+74 −0
Original line number Diff line number Diff line
@@ -144,3 +144,77 @@ nv50_pm_clock_set(struct drm_device *dev, void *pre_state)
	kfree(state);
}

struct pwm_info {
	int id;
	int invert;
	u8  tag;
	u32 ctrl;
	int line;
};

static int
nv50_pm_fanspeed_pwm(struct drm_device *dev, struct pwm_info *pwm)
{
	struct dcb_gpio_entry *gpio;

	gpio = nouveau_bios_gpio_entry(dev, 0x09);
	if (gpio) {
		pwm->tag = gpio->tag;
		pwm->id = (gpio->line == 9) ? 1 : 0;
		pwm->invert = gpio->state[0] & 1;
		pwm->ctrl = (gpio->line < 16) ? 0xe100 : 0xe28c;
		pwm->line = (gpio->line & 0xf);
		return 0;
	}

	return -ENOENT;
}

int
nv50_pm_fanspeed_get(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
	struct pwm_info pwm;
	int ret;

	ret = nv50_pm_fanspeed_pwm(dev, &pwm);
	if (ret)
		return ret;

	if (nv_rd32(dev, pwm.ctrl) & (0x00000001 << pwm.line)) {
		u32 divs = nv_rd32(dev, 0x00e114 + (pwm.id * 8));
		u32 duty = nv_rd32(dev, 0x00e118 + (pwm.id * 8));
		if (divs) {
			divs = max(divs, duty);
			if (pwm.invert)
				duty = divs - duty;
			return (duty * 100) / divs;
		}

		return 0;
	}

	return pgpio->get(dev, pwm.tag) * 100;
}

int
nv50_pm_fanspeed_set(struct drm_device *dev, int percent)
{
	struct pwm_info pwm;
	u32 divs, duty;
	int ret;

	ret = nv50_pm_fanspeed_pwm(dev, &pwm);
	if (ret)
		return ret;

	divs = nv_rd32(dev, 0x00e114 + (pwm.id * 8));
	duty = ((divs * percent) + 99) / 100;
	if (pwm.invert)
		duty = divs - duty;

	nv_mask(dev, pwm.ctrl, 0x00010001 << pwm.line, 0x00000001 << pwm.line);
	nv_wr32(dev, 0x00e118 + (pwm.id * 8), 0x80000000 | duty);
	return 0;
}