aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-06-12 23:23:42 -0400
committerBen Skeggs <bskeggs@redhat.com>2014-08-09 15:11:08 -0400
commit7e1ee6333c32a4b83aad430a4bcb8a7057f36194 (patch)
treee3f921e98245fe9f7c2582fdf8c2e21a795ba25f /drivers/gpu
parentd5d7a0fa742383406c84e5292d00eccdbf74d91a (diff)
drm/nouveau/clk: allow selection of different power state for ac vs battery
v2: - s/init/fini/ typo, reported by Alex Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/ctrl.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/clock.h17
-rw-r--r--drivers/gpu/drm/nouveau/core/os.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/base.c101
4 files changed, 96 insertions, 30 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c
index 4b69bf56ed01..754fc1da6a0b 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c
@@ -41,7 +41,10 @@ nouveau_control_mthd_pstate_info(struct nouveau_object *object, u32 mthd,
41 41
42 if (clk) { 42 if (clk) {
43 args->count = clk->state_nr; 43 args->count = clk->state_nr;
44 args->ustate = clk->ustate; 44 if (clk->pwrsrc)
45 args->ustate = clk->ustate_ac;
46 else
47 args->ustate = clk->ustate_dc;
45 args->pstate = clk->pstate; 48 args->pstate = clk->pstate;
46 } else { 49 } else {
47 args->count = 0; 50 args->count = 0;
@@ -123,7 +126,7 @@ nouveau_control_mthd_pstate_user(struct nouveau_object *object, u32 mthd,
123 if (size < sizeof(*args) || !clk) 126 if (size < sizeof(*args) || !clk)
124 return -EINVAL; 127 return -EINVAL;
125 128
126 return nouveau_clock_ustate(clk, args->state); 129 return nouveau_clock_ustate(clk, args->state, clk->pwrsrc);
127} 130}
128 131
129struct nouveau_oclass 132struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
index 3168e1a0578d..9f37c096c34d 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
@@ -75,8 +75,11 @@ struct nouveau_clock {
75 wait_queue_head_t wait; 75 wait_queue_head_t wait;
76 atomic_t waiting; 76 atomic_t waiting;
77 77
78 struct nouveau_eventh *pwrsrc_ntfy;
79 int pwrsrc;
78 int pstate; /* current */ 80 int pstate; /* current */
79 int ustate; /* user-requested (-1 disabled, -2 perfmon) */ 81 int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
82 int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */
80 int astate; /* perfmon adjustment (base) */ 83 int astate; /* perfmon adjustment (base) */
81 int tstate; /* thermal adjustment (max-) */ 84 int tstate; /* thermal adjustment (max-) */
82 int dstate; /* display adjustment (min+) */ 85 int dstate; /* display adjustment (min+) */
@@ -122,15 +125,17 @@ struct nouveau_clocks {
122 struct nouveau_clock *clk = (p); \ 125 struct nouveau_clock *clk = (p); \
123 _nouveau_clock_init(nv_object(clk)); \ 126 _nouveau_clock_init(nv_object(clk)); \
124}) 127})
125#define nouveau_clock_fini(p,s) \ 128#define nouveau_clock_fini(p,s) ({ \
126 nouveau_subdev_fini(&(p)->base, (s)) 129 struct nouveau_clock *clk = (p); \
130 _nouveau_clock_fini(nv_object(clk), (s)); \
131})
127 132
128int nouveau_clock_create_(struct nouveau_object *, struct nouveau_object *, 133int nouveau_clock_create_(struct nouveau_object *, struct nouveau_object *,
129 struct nouveau_oclass *, 134 struct nouveau_oclass *,
130 struct nouveau_clocks *, bool, int, void **); 135 struct nouveau_clocks *, bool, int, void **);
131void _nouveau_clock_dtor(struct nouveau_object *); 136void _nouveau_clock_dtor(struct nouveau_object *);
132int _nouveau_clock_init(struct nouveau_object *); 137int _nouveau_clock_init(struct nouveau_object *);
133#define _nouveau_clock_fini _nouveau_subdev_fini 138int _nouveau_clock_fini(struct nouveau_object *, bool);
134 139
135extern struct nouveau_oclass nv04_clock_oclass; 140extern struct nouveau_oclass nv04_clock_oclass;
136extern struct nouveau_oclass nv40_clock_oclass; 141extern struct nouveau_oclass nv40_clock_oclass;
@@ -149,7 +154,7 @@ int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1,
149int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, 154int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,
150 int clk, struct nouveau_pll_vals *); 155 int clk, struct nouveau_pll_vals *);
151 156
152int nouveau_clock_ustate(struct nouveau_clock *, int req); 157int nouveau_clock_ustate(struct nouveau_clock *, int req, int pwr);
153int nouveau_clock_astate(struct nouveau_clock *, int req, int rel); 158int nouveau_clock_astate(struct nouveau_clock *, int req, int rel);
154int nouveau_clock_dstate(struct nouveau_clock *, int req, int rel); 159int nouveau_clock_dstate(struct nouveau_clock *, int req, int rel);
155int nouveau_clock_tstate(struct nouveau_clock *, int req, int rel); 160int nouveau_clock_tstate(struct nouveau_clock *, int req, int rel);
diff --git a/drivers/gpu/drm/nouveau/core/os.h b/drivers/gpu/drm/nouveau/core/os.h
index d0ced94ca54c..e50decfebf30 100644
--- a/drivers/gpu/drm/nouveau/core/os.h
+++ b/drivers/gpu/drm/nouveau/core/os.h
@@ -21,6 +21,7 @@
21#include <linux/interrupt.h> 21#include <linux/interrupt.h>
22#include <linux/log2.h> 22#include <linux/log2.h>
23#include <linux/pm_runtime.h> 23#include <linux/pm_runtime.h>
24#include <linux/power_supply.h>
24 25
25#include <asm/unaligned.h> 26#include <asm/unaligned.h>
26 27
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/base.c b/drivers/gpu/drm/nouveau/core/subdev/clock/base.c
index 77966370e995..3ad848bbbbb0 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/base.c
@@ -202,12 +202,15 @@ nouveau_pstate_work(struct work_struct *work)
202 202
203 if (!atomic_xchg(&clk->waiting, 0)) 203 if (!atomic_xchg(&clk->waiting, 0))
204 return; 204 return;
205 clk->pwrsrc = power_supply_is_system_supplied();
205 206
206 nv_trace(clk, "P %d U %d A %d T %d D %d\n", clk->pstate, 207 nv_trace(clk, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n",
207 clk->ustate, clk->astate, clk->tstate, clk->dstate); 208 clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc,
209 clk->astate, clk->tstate, clk->dstate);
208 210
209 if (clk->state_nr && clk->ustate != -1) { 211 pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc;
210 pstate = (clk->ustate < 0) ? clk->astate : clk->ustate; 212 if (clk->state_nr && pstate != -1) {
213 pstate = (pstate < 0) ? clk->astate : pstate;
211 pstate = min(pstate, clk->state_nr - 1 - clk->tstate); 214 pstate = min(pstate, clk->state_nr - 1 - clk->tstate);
212 pstate = max(pstate, clk->dstate); 215 pstate = max(pstate, clk->dstate);
213 } else { 216 } else {
@@ -224,6 +227,7 @@ nouveau_pstate_work(struct work_struct *work)
224 } 227 }
225 228
226 wake_up_all(&clk->wait); 229 wake_up_all(&clk->wait);
230 nouveau_event_get(clk->pwrsrc_ntfy);
227} 231}
228 232
229static int 233static int
@@ -381,17 +385,40 @@ nouveau_clock_ustate_update(struct nouveau_clock *clk, int req)
381 req = i; 385 req = i;
382 } 386 }
383 387
384 clk->ustate = req; 388 return req + 2;
385 return 0; 389}
390
391static int
392nouveau_clock_nstate(struct nouveau_clock *clk, const char *mode, int arglen)
393{
394 int ret = 1;
395
396 if (strncasecmpz(mode, "disabled", arglen)) {
397 char save = mode[arglen];
398 long v;
399
400 ((char *)mode)[arglen] = '\0';
401 if (!kstrtol(mode, 0, &v)) {
402 ret = nouveau_clock_ustate_update(clk, v);
403 if (ret < 0)
404 ret = 1;
405 }
406 ((char *)mode)[arglen] = save;
407 }
408
409 return ret - 2;
386} 410}
387 411
388int 412int
389nouveau_clock_ustate(struct nouveau_clock *clk, int req) 413nouveau_clock_ustate(struct nouveau_clock *clk, int req, int pwr)
390{ 414{
391 int ret = nouveau_clock_ustate_update(clk, req); 415 int ret = nouveau_clock_ustate_update(clk, req);
392 if (ret) 416 if (ret >= 0) {
393 return ret; 417 if (ret -= 2, pwr) clk->ustate_ac = ret;
394 return nouveau_pstate_calc(clk, true); 418 else clk->ustate_dc = ret;
419 return nouveau_pstate_calc(clk, true);
420 }
421 return ret;
395} 422}
396 423
397int 424int
@@ -424,9 +451,26 @@ nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel)
424 return nouveau_pstate_calc(clk, true); 451 return nouveau_pstate_calc(clk, true);
425} 452}
426 453
454static int
455nouveau_clock_pwrsrc(void *data, u32 mask, int type)
456{
457 struct nouveau_clock *clk = data;
458 nouveau_pstate_calc(clk, false);
459 return NVKM_EVENT_DROP;
460}
461
427/****************************************************************************** 462/******************************************************************************
428 * subdev base class implementation 463 * subdev base class implementation
429 *****************************************************************************/ 464 *****************************************************************************/
465
466int
467_nouveau_clock_fini(struct nouveau_object *object, bool suspend)
468{
469 struct nouveau_clock *clk = (void *)object;
470 nouveau_event_put(clk->pwrsrc_ntfy);
471 return nouveau_subdev_fini(&clk->base, suspend);
472}
473
430int 474int
431_nouveau_clock_init(struct nouveau_object *object) 475_nouveau_clock_init(struct nouveau_object *object)
432{ 476{
@@ -434,6 +478,10 @@ _nouveau_clock_init(struct nouveau_object *object)
434 struct nouveau_clocks *clock = clk->domains; 478 struct nouveau_clocks *clock = clk->domains;
435 int ret; 479 int ret;
436 480
481 ret = nouveau_subdev_init(&clk->base);
482 if (ret)
483 return ret;
484
437 memset(&clk->bstate, 0x00, sizeof(clk->bstate)); 485 memset(&clk->bstate, 0x00, sizeof(clk->bstate));
438 INIT_LIST_HEAD(&clk->bstate.list); 486 INIT_LIST_HEAD(&clk->bstate.list);
439 clk->bstate.pstate = 0xff; 487 clk->bstate.pstate = 0xff;
@@ -464,6 +512,8 @@ _nouveau_clock_dtor(struct nouveau_object *object)
464 struct nouveau_clock *clk = (void *)object; 512 struct nouveau_clock *clk = (void *)object;
465 struct nouveau_pstate *pstate, *temp; 513 struct nouveau_pstate *pstate, *temp;
466 514
515 nouveau_event_ref(NULL, &clk->pwrsrc_ntfy);
516
467 list_for_each_entry_safe(pstate, temp, &clk->states, head) { 517 list_for_each_entry_safe(pstate, temp, &clk->states, head) {
468 nouveau_pstate_del(pstate); 518 nouveau_pstate_del(pstate);
469 } 519 }
@@ -492,7 +542,8 @@ nouveau_clock_create_(struct nouveau_object *parent,
492 542
493 INIT_LIST_HEAD(&clk->states); 543 INIT_LIST_HEAD(&clk->states);
494 clk->domains = clocks; 544 clk->domains = clocks;
495 clk->ustate = -1; 545 clk->ustate_ac = -1;
546 clk->ustate_dc = -1;
496 547
497 INIT_WORK(&clk->work, nouveau_pstate_work); 548 INIT_WORK(&clk->work, nouveau_pstate_work);
498 init_waitqueue_head(&clk->wait); 549 init_waitqueue_head(&clk->wait);
@@ -505,20 +556,26 @@ nouveau_clock_create_(struct nouveau_object *parent,
505 556
506 clk->allow_reclock = allow_reclock; 557 clk->allow_reclock = allow_reclock;
507 558
559 ret = nouveau_event_new(device->ntfy, 1, NVKM_DEVICE_NTFY_POWER,
560 nouveau_clock_pwrsrc, clk,
561 &clk->pwrsrc_ntfy);
562 if (ret)
563 return ret;
564
508 mode = nouveau_stropt(device->cfgopt, "NvClkMode", &arglen); 565 mode = nouveau_stropt(device->cfgopt, "NvClkMode", &arglen);
509 if (mode) { 566 if (mode) {
510 if (!strncasecmpz(mode, "disabled", arglen)) { 567 clk->ustate_ac = nouveau_clock_nstate(clk, mode, arglen);
511 clk->ustate = -1; 568 clk->ustate_dc = nouveau_clock_nstate(clk, mode, arglen);
512 } else {
513 char save = mode[arglen];
514 long v;
515
516 ((char *)mode)[arglen] = '\0';
517 if (!kstrtol(mode, 0, &v))
518 nouveau_clock_ustate_update(clk, v);
519 ((char *)mode)[arglen] = save;
520 }
521 } 569 }
522 570
571 mode = nouveau_stropt(device->cfgopt, "NvClkModeAC", &arglen);
572 if (mode)
573 clk->ustate_ac = nouveau_clock_nstate(clk, mode, arglen);
574
575 mode = nouveau_stropt(device->cfgopt, "NvClkModeDC", &arglen);
576 if (mode)
577 clk->ustate_dc = nouveau_clock_nstate(clk, mode, arglen);
578
579
523 return 0; 580 return 0;
524} 581}