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

Commit 7e1ee633 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/clk: allow selection of different power state for ac vs battery



v2:
- s/init/fini/ typo, reported by Alex

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent d5d7a0fa
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -41,7 +41,10 @@ nouveau_control_mthd_pstate_info(struct nouveau_object *object, u32 mthd,

	if (clk) {
		args->count  = clk->state_nr;
		args->ustate = clk->ustate;
		if (clk->pwrsrc)
			args->ustate = clk->ustate_ac;
		else
			args->ustate = clk->ustate_dc;
		args->pstate = clk->pstate;
	} else {
		args->count  = 0;
@@ -123,7 +126,7 @@ nouveau_control_mthd_pstate_user(struct nouveau_object *object, u32 mthd,
	if (size < sizeof(*args) || !clk)
		return -EINVAL;

	return nouveau_clock_ustate(clk, args->state);
	return nouveau_clock_ustate(clk, args->state, clk->pwrsrc);
}

struct nouveau_oclass
+11 −6
Original line number Diff line number Diff line
@@ -75,8 +75,11 @@ struct nouveau_clock {
	wait_queue_head_t wait;
	atomic_t waiting;

	struct nouveau_eventh *pwrsrc_ntfy;
	int pwrsrc;
	int pstate; /* current */
	int ustate; /* user-requested (-1 disabled, -2 perfmon) */
	int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
	int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */
	int astate; /* perfmon adjustment (base) */
	int tstate; /* thermal adjustment (max-) */
	int dstate; /* display adjustment (min+) */
@@ -122,15 +125,17 @@ struct nouveau_clocks {
	struct nouveau_clock *clk = (p);                                       \
	_nouveau_clock_init(nv_object(clk));                                   \
})
#define nouveau_clock_fini(p,s)                                                \
	nouveau_subdev_fini(&(p)->base, (s))
#define nouveau_clock_fini(p,s) ({                                             \
	struct nouveau_clock *clk = (p);                                       \
	_nouveau_clock_fini(nv_object(clk), (s));                              \
})

int  nouveau_clock_create_(struct nouveau_object *, struct nouveau_object *,
			   struct nouveau_oclass *,
			   struct nouveau_clocks *, bool, int, void **);
void _nouveau_clock_dtor(struct nouveau_object *);
int  _nouveau_clock_init(struct nouveau_object *);
#define _nouveau_clock_fini _nouveau_subdev_fini
int  _nouveau_clock_fini(struct nouveau_object *, bool);

extern struct nouveau_oclass nv04_clock_oclass;
extern struct nouveau_oclass nv40_clock_oclass;
@@ -149,7 +154,7 @@ int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1,
int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,
			int clk, struct nouveau_pll_vals *);

int nouveau_clock_ustate(struct nouveau_clock *, int req);
int nouveau_clock_ustate(struct nouveau_clock *, int req, int pwr);
int nouveau_clock_astate(struct nouveau_clock *, int req, int rel);
int nouveau_clock_dstate(struct nouveau_clock *, int req, int rel);
int nouveau_clock_tstate(struct nouveau_clock *, int req, int rel);
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/log2.h>
#include <linux/pm_runtime.h>
#include <linux/power_supply.h>

#include <asm/unaligned.h>

+79 −22
Original line number Diff line number Diff line
@@ -202,12 +202,15 @@ nouveau_pstate_work(struct work_struct *work)

	if (!atomic_xchg(&clk->waiting, 0))
		return;
	clk->pwrsrc = power_supply_is_system_supplied();

	nv_trace(clk, "P %d U %d A %d T %d D %d\n", clk->pstate,
		 clk->ustate, clk->astate, clk->tstate, clk->dstate);
	nv_trace(clk, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n",
		 clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc,
		 clk->astate, clk->tstate, clk->dstate);

	if (clk->state_nr && clk->ustate != -1) {
		pstate = (clk->ustate < 0) ? clk->astate : clk->ustate;
	pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc;
	if (clk->state_nr && pstate != -1) {
		pstate = (pstate < 0) ? clk->astate : pstate;
		pstate = min(pstate, clk->state_nr - 1 - clk->tstate);
		pstate = max(pstate, clk->dstate);
	} else {
@@ -224,6 +227,7 @@ nouveau_pstate_work(struct work_struct *work)
	}

	wake_up_all(&clk->wait);
	nouveau_event_get(clk->pwrsrc_ntfy);
}

static int
@@ -381,18 +385,41 @@ nouveau_clock_ustate_update(struct nouveau_clock *clk, int req)
		req = i;
	}

	clk->ustate = req;
	return 0;
	return req + 2;
}

static int
nouveau_clock_nstate(struct nouveau_clock *clk, const char *mode, int arglen)
{
	int ret = 1;

	if (strncasecmpz(mode, "disabled", arglen)) {
		char save = mode[arglen];
		long v;

		((char *)mode)[arglen] = '\0';
		if (!kstrtol(mode, 0, &v)) {
			ret = nouveau_clock_ustate_update(clk, v);
			if (ret < 0)
				ret = 1;
		}
		((char *)mode)[arglen] = save;
	}

	return ret - 2;
}

int
nouveau_clock_ustate(struct nouveau_clock *clk, int req)
nouveau_clock_ustate(struct nouveau_clock *clk, int req, int pwr)
{
	int ret = nouveau_clock_ustate_update(clk, req);
	if (ret)
		return ret;
	if (ret >= 0) {
		if (ret -= 2, pwr) clk->ustate_ac = ret;
		else		   clk->ustate_dc = ret;
		return nouveau_pstate_calc(clk, true);
	}
	return ret;
}

int
nouveau_clock_astate(struct nouveau_clock *clk, int req, int rel)
@@ -424,9 +451,26 @@ nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel)
	return nouveau_pstate_calc(clk, true);
}

static int
nouveau_clock_pwrsrc(void *data, u32 mask, int type)
{
	struct nouveau_clock *clk = data;
	nouveau_pstate_calc(clk, false);
	return NVKM_EVENT_DROP;
}

/******************************************************************************
 * subdev base class implementation
 *****************************************************************************/

int
_nouveau_clock_fini(struct nouveau_object *object, bool suspend)
{
	struct nouveau_clock *clk = (void *)object;
	nouveau_event_put(clk->pwrsrc_ntfy);
	return nouveau_subdev_fini(&clk->base, suspend);
}

int
_nouveau_clock_init(struct nouveau_object *object)
{
@@ -434,6 +478,10 @@ _nouveau_clock_init(struct nouveau_object *object)
	struct nouveau_clocks *clock = clk->domains;
	int ret;

	ret = nouveau_subdev_init(&clk->base);
	if (ret)
		return ret;

	memset(&clk->bstate, 0x00, sizeof(clk->bstate));
	INIT_LIST_HEAD(&clk->bstate.list);
	clk->bstate.pstate = 0xff;
@@ -464,6 +512,8 @@ _nouveau_clock_dtor(struct nouveau_object *object)
	struct nouveau_clock *clk = (void *)object;
	struct nouveau_pstate *pstate, *temp;

	nouveau_event_ref(NULL, &clk->pwrsrc_ntfy);

	list_for_each_entry_safe(pstate, temp, &clk->states, head) {
		nouveau_pstate_del(pstate);
	}
@@ -492,7 +542,8 @@ nouveau_clock_create_(struct nouveau_object *parent,

	INIT_LIST_HEAD(&clk->states);
	clk->domains = clocks;
	clk->ustate = -1;
	clk->ustate_ac = -1;
	clk->ustate_dc = -1;

	INIT_WORK(&clk->work, nouveau_pstate_work);
	init_waitqueue_head(&clk->wait);
@@ -505,20 +556,26 @@ nouveau_clock_create_(struct nouveau_object *parent,

	clk->allow_reclock = allow_reclock;

	ret = nouveau_event_new(device->ntfy, 1, NVKM_DEVICE_NTFY_POWER,
				nouveau_clock_pwrsrc, clk,
			       &clk->pwrsrc_ntfy);
	if (ret)
		return ret;

	mode = nouveau_stropt(device->cfgopt, "NvClkMode", &arglen);
	if (mode) {
		if (!strncasecmpz(mode, "disabled", arglen)) {
			clk->ustate = -1;
		} else {
			char save = mode[arglen];
			long v;

			((char *)mode)[arglen] = '\0';
			if (!kstrtol(mode, 0, &v))
				nouveau_clock_ustate_update(clk, v);
			((char *)mode)[arglen] = save;
		}
		clk->ustate_ac = nouveau_clock_nstate(clk, mode, arglen);
		clk->ustate_dc = nouveau_clock_nstate(clk, mode, arglen);
	}

	mode = nouveau_stropt(device->cfgopt, "NvClkModeAC", &arglen);
	if (mode)
		clk->ustate_ac = nouveau_clock_nstate(clk, mode, arglen);

	mode = nouveau_stropt(device->cfgopt, "NvClkModeDC", &arglen);
	if (mode)
		clk->ustate_dc = nouveau_clock_nstate(clk, mode, arglen);


	return 0;
}