]>
git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blob - drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
2 * Copyright 2013 Red Hat Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
24 #include <subdev/clk.h>
25 #include <subdev/bios.h>
26 #include <subdev/bios/boost.h>
27 #include <subdev/bios/cstep.h>
28 #include <subdev/bios/perf.h>
29 #include <subdev/fb.h>
30 #include <subdev/therm.h>
31 #include <subdev/volt.h>
33 #include <core/option.h>
35 /******************************************************************************
37 *****************************************************************************/
39 nvkm_clk_adjust(struct nvkm_clk
*clk
, bool adjust
,
40 u8 pstate
, u8 domain
, u32 input
)
42 struct nvkm_bios
*bios
= clk
->subdev
.device
->bios
;
43 struct nvbios_boostE boostE
;
44 u8 ver
, hdr
, cnt
, len
;
47 data
= nvbios_boostEm(bios
, pstate
, &ver
, &hdr
, &cnt
, &len
, &boostE
);
49 struct nvbios_boostS boostS
;
50 u8 idx
= 0, sver
, shdr
;
53 input
= max(boostE
.min
, input
);
54 input
= min(boostE
.max
, input
);
58 subd
= nvbios_boostSp(bios
, idx
++, data
, &sver
, &shdr
,
60 if (subd
&& boostS
.domain
== domain
) {
62 input
= input
* boostS
.percent
/ 100;
63 input
= max(boostS
.min
, input
);
64 input
= min(boostS
.max
, input
);
73 /******************************************************************************
75 *****************************************************************************/
77 nvkm_cstate_prog(struct nvkm_clk
*clk
, struct nvkm_pstate
*pstate
, int cstatei
)
79 struct nvkm_subdev
*subdev
= &clk
->subdev
;
80 struct nvkm_device
*device
= subdev
->device
;
81 struct nvkm_therm
*therm
= device
->therm
;
82 struct nvkm_volt
*volt
= device
->volt
;
83 struct nvkm_cstate
*cstate
;
86 if (!list_empty(&pstate
->list
)) {
87 cstate
= list_entry(pstate
->list
.prev
, typeof(*cstate
), head
);
89 cstate
= &pstate
->base
;
93 ret
= nvkm_therm_cstate(therm
, pstate
->fanspeed
, +1);
94 if (ret
&& ret
!= -ENODEV
) {
95 nvkm_error(subdev
, "failed to raise fan speed: %d\n", ret
);
101 ret
= volt
->set_id(volt
, cstate
->voltage
, +1);
102 if (ret
&& ret
!= -ENODEV
) {
103 nvkm_error(subdev
, "failed to raise voltage: %d\n", ret
);
108 ret
= clk
->calc(clk
, cstate
);
110 ret
= clk
->prog(clk
);
115 ret
= volt
->set_id(volt
, cstate
->voltage
, -1);
116 if (ret
&& ret
!= -ENODEV
)
117 nvkm_error(subdev
, "failed to lower voltage: %d\n", ret
);
121 ret
= nvkm_therm_cstate(therm
, pstate
->fanspeed
, -1);
122 if (ret
&& ret
!= -ENODEV
)
123 nvkm_error(subdev
, "failed to lower fan speed: %d\n", ret
);
130 nvkm_cstate_del(struct nvkm_cstate
*cstate
)
132 list_del(&cstate
->head
);
137 nvkm_cstate_new(struct nvkm_clk
*clk
, int idx
, struct nvkm_pstate
*pstate
)
139 struct nvkm_bios
*bios
= clk
->subdev
.device
->bios
;
140 struct nvkm_domain
*domain
= clk
->domains
;
141 struct nvkm_cstate
*cstate
= NULL
;
142 struct nvbios_cstepX cstepX
;
146 data
= nvbios_cstepXp(bios
, idx
, &ver
, &hdr
, &cstepX
);
150 cstate
= kzalloc(sizeof(*cstate
), GFP_KERNEL
);
154 *cstate
= pstate
->base
;
155 cstate
->voltage
= cstepX
.voltage
;
157 while (domain
&& domain
->name
!= nv_clk_src_max
) {
158 if (domain
->flags
& NVKM_CLK_DOM_FLAG_CORE
) {
159 u32 freq
= nvkm_clk_adjust(clk
, true, pstate
->pstate
,
160 domain
->bios
, cstepX
.freq
);
161 cstate
->domain
[domain
->name
] = freq
;
166 list_add(&cstate
->head
, &pstate
->list
);
170 /******************************************************************************
172 *****************************************************************************/
174 nvkm_pstate_prog(struct nvkm_clk
*clk
, int pstatei
)
176 struct nvkm_subdev
*subdev
= &clk
->subdev
;
177 struct nvkm_ram
*ram
= subdev
->device
->fb
->ram
;
178 struct nvkm_pstate
*pstate
;
181 list_for_each_entry(pstate
, &clk
->states
, head
) {
182 if (idx
++ == pstatei
)
186 nvkm_debug(subdev
, "setting performance state %d\n", pstatei
);
187 clk
->pstate
= pstatei
;
189 if (ram
&& ram
->func
->calc
) {
190 int khz
= pstate
->base
.domain
[nv_clk_src_mem
];
192 ret
= ram
->func
->calc(ram
, khz
);
194 ret
= ram
->func
->prog(ram
);
196 ram
->func
->tidy(ram
);
199 return nvkm_cstate_prog(clk
, pstate
, 0);
203 nvkm_pstate_work(struct work_struct
*work
)
205 struct nvkm_clk
*clk
= container_of(work
, typeof(*clk
), work
);
206 struct nvkm_subdev
*subdev
= &clk
->subdev
;
209 if (!atomic_xchg(&clk
->waiting
, 0))
211 clk
->pwrsrc
= power_supply_is_system_supplied();
213 nvkm_trace(subdev
, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n",
214 clk
->pstate
, clk
->pwrsrc
, clk
->ustate_ac
, clk
->ustate_dc
,
215 clk
->astate
, clk
->tstate
, clk
->dstate
);
217 pstate
= clk
->pwrsrc
? clk
->ustate_ac
: clk
->ustate_dc
;
218 if (clk
->state_nr
&& pstate
!= -1) {
219 pstate
= (pstate
< 0) ? clk
->astate
: pstate
;
220 pstate
= min(pstate
, clk
->state_nr
- 1 + clk
->tstate
);
221 pstate
= max(pstate
, clk
->dstate
);
223 pstate
= clk
->pstate
= -1;
226 nvkm_trace(subdev
, "-> %d\n", pstate
);
227 if (pstate
!= clk
->pstate
) {
228 int ret
= nvkm_pstate_prog(clk
, pstate
);
230 nvkm_error(subdev
, "error setting pstate %d: %d\n",
235 wake_up_all(&clk
->wait
);
236 nvkm_notify_get(&clk
->pwrsrc_ntfy
);
240 nvkm_pstate_calc(struct nvkm_clk
*clk
, bool wait
)
242 atomic_set(&clk
->waiting
, 1);
243 schedule_work(&clk
->work
);
245 wait_event(clk
->wait
, !atomic_read(&clk
->waiting
));
250 nvkm_pstate_info(struct nvkm_clk
*clk
, struct nvkm_pstate
*pstate
)
252 struct nvkm_domain
*clock
= clk
->domains
- 1;
253 struct nvkm_cstate
*cstate
;
254 struct nvkm_subdev
*subdev
= &clk
->subdev
;
255 char info
[3][32] = { "", "", "" };
259 if (pstate
->pstate
!= 0xff)
260 snprintf(name
, sizeof(name
), "%02x", pstate
->pstate
);
262 while ((++clock
)->name
!= nv_clk_src_max
) {
263 u32 lo
= pstate
->base
.domain
[clock
->name
];
268 nvkm_debug(subdev
, "%02x: %10d KHz\n", clock
->name
, lo
);
269 list_for_each_entry(cstate
, &pstate
->list
, head
) {
270 u32 freq
= cstate
->domain
[clock
->name
];
273 nvkm_debug(subdev
, "%10d KHz\n", freq
);
276 if (clock
->mname
&& ++i
< ARRAY_SIZE(info
)) {
280 snprintf(info
[i
], sizeof(info
[i
]), "%s %d MHz",
283 snprintf(info
[i
], sizeof(info
[i
]),
284 "%s %d-%d MHz", clock
->mname
, lo
, hi
);
289 nvkm_debug(subdev
, "%s: %s %s %s\n", name
, info
[0], info
[1], info
[2]);
293 nvkm_pstate_del(struct nvkm_pstate
*pstate
)
295 struct nvkm_cstate
*cstate
, *temp
;
297 list_for_each_entry_safe(cstate
, temp
, &pstate
->list
, head
) {
298 nvkm_cstate_del(cstate
);
301 list_del(&pstate
->head
);
306 nvkm_pstate_new(struct nvkm_clk
*clk
, int idx
)
308 struct nvkm_bios
*bios
= clk
->subdev
.device
->bios
;
309 struct nvkm_domain
*domain
= clk
->domains
- 1;
310 struct nvkm_pstate
*pstate
;
311 struct nvkm_cstate
*cstate
;
312 struct nvbios_cstepE cstepE
;
313 struct nvbios_perfE perfE
;
314 u8 ver
, hdr
, cnt
, len
;
317 data
= nvbios_perfEp(bios
, idx
, &ver
, &hdr
, &cnt
, &len
, &perfE
);
320 if (perfE
.pstate
== 0xff)
323 pstate
= kzalloc(sizeof(*pstate
), GFP_KERNEL
);
324 cstate
= &pstate
->base
;
328 INIT_LIST_HEAD(&pstate
->list
);
330 pstate
->pstate
= perfE
.pstate
;
331 pstate
->fanspeed
= perfE
.fanspeed
;
332 cstate
->voltage
= perfE
.voltage
;
333 cstate
->domain
[nv_clk_src_core
] = perfE
.core
;
334 cstate
->domain
[nv_clk_src_shader
] = perfE
.shader
;
335 cstate
->domain
[nv_clk_src_mem
] = perfE
.memory
;
336 cstate
->domain
[nv_clk_src_vdec
] = perfE
.vdec
;
337 cstate
->domain
[nv_clk_src_dom6
] = perfE
.disp
;
339 while (ver
>= 0x40 && (++domain
)->name
!= nv_clk_src_max
) {
340 struct nvbios_perfS perfS
;
341 u8 sver
= ver
, shdr
= hdr
;
342 u32 perfSe
= nvbios_perfSp(bios
, data
, domain
->bios
,
343 &sver
, &shdr
, cnt
, len
, &perfS
);
344 if (perfSe
== 0 || sver
!= 0x40)
347 if (domain
->flags
& NVKM_CLK_DOM_FLAG_CORE
) {
348 perfS
.v40
.freq
= nvkm_clk_adjust(clk
, false,
354 cstate
->domain
[domain
->name
] = perfS
.v40
.freq
;
357 data
= nvbios_cstepEm(bios
, pstate
->pstate
, &ver
, &hdr
, &cstepE
);
359 int idx
= cstepE
.index
;
361 nvkm_cstate_new(clk
, idx
, pstate
);
365 nvkm_pstate_info(clk
, pstate
);
366 list_add_tail(&pstate
->head
, &clk
->states
);
371 /******************************************************************************
372 * Adjustment triggers
373 *****************************************************************************/
375 nvkm_clk_ustate_update(struct nvkm_clk
*clk
, int req
)
377 struct nvkm_pstate
*pstate
;
380 if (!clk
->allow_reclock
)
383 if (req
!= -1 && req
!= -2) {
384 list_for_each_entry(pstate
, &clk
->states
, head
) {
385 if (pstate
->pstate
== req
)
390 if (pstate
->pstate
!= req
)
399 nvkm_clk_nstate(struct nvkm_clk
*clk
, const char *mode
, int arglen
)
403 if (clk
->allow_reclock
&& !strncasecmpz(mode
, "auto", arglen
))
406 if (strncasecmpz(mode
, "disabled", arglen
)) {
407 char save
= mode
[arglen
];
410 ((char *)mode
)[arglen
] = '\0';
411 if (!kstrtol(mode
, 0, &v
)) {
412 ret
= nvkm_clk_ustate_update(clk
, v
);
416 ((char *)mode
)[arglen
] = save
;
423 nvkm_clk_ustate(struct nvkm_clk
*clk
, int req
, int pwr
)
425 int ret
= nvkm_clk_ustate_update(clk
, req
);
427 if (ret
-= 2, pwr
) clk
->ustate_ac
= ret
;
428 else clk
->ustate_dc
= ret
;
429 return nvkm_pstate_calc(clk
, true);
435 nvkm_clk_astate(struct nvkm_clk
*clk
, int req
, int rel
, bool wait
)
437 if (!rel
) clk
->astate
= req
;
438 if ( rel
) clk
->astate
+= rel
;
439 clk
->astate
= min(clk
->astate
, clk
->state_nr
- 1);
440 clk
->astate
= max(clk
->astate
, 0);
441 return nvkm_pstate_calc(clk
, wait
);
445 nvkm_clk_tstate(struct nvkm_clk
*clk
, int req
, int rel
)
447 if (!rel
) clk
->tstate
= req
;
448 if ( rel
) clk
->tstate
+= rel
;
449 clk
->tstate
= min(clk
->tstate
, 0);
450 clk
->tstate
= max(clk
->tstate
, -(clk
->state_nr
- 1));
451 return nvkm_pstate_calc(clk
, true);
455 nvkm_clk_dstate(struct nvkm_clk
*clk
, int req
, int rel
)
457 if (!rel
) clk
->dstate
= req
;
458 if ( rel
) clk
->dstate
+= rel
;
459 clk
->dstate
= min(clk
->dstate
, clk
->state_nr
- 1);
460 clk
->dstate
= max(clk
->dstate
, 0);
461 return nvkm_pstate_calc(clk
, true);
465 nvkm_clk_pwrsrc(struct nvkm_notify
*notify
)
467 struct nvkm_clk
*clk
=
468 container_of(notify
, typeof(*clk
), pwrsrc_ntfy
);
469 nvkm_pstate_calc(clk
, false);
470 return NVKM_NOTIFY_DROP
;
473 /******************************************************************************
474 * subdev base class implementation
475 *****************************************************************************/
478 _nvkm_clk_fini(struct nvkm_object
*object
, bool suspend
)
480 struct nvkm_clk
*clk
= (void *)object
;
481 nvkm_notify_put(&clk
->pwrsrc_ntfy
);
482 return nvkm_subdev_fini_old(&clk
->subdev
, suspend
);
486 _nvkm_clk_init(struct nvkm_object
*object
)
488 struct nvkm_clk
*clk
= (void *)object
;
489 struct nvkm_subdev
*subdev
= &clk
->subdev
;
490 struct nvkm_domain
*clock
= clk
->domains
;
493 ret
= nvkm_subdev_init_old(&clk
->subdev
);
497 memset(&clk
->bstate
, 0x00, sizeof(clk
->bstate
));
498 INIT_LIST_HEAD(&clk
->bstate
.list
);
499 clk
->bstate
.pstate
= 0xff;
501 while (clock
->name
!= nv_clk_src_max
) {
502 ret
= clk
->read(clk
, clock
->name
);
504 nvkm_error(subdev
, "%02x freq unknown\n", clock
->name
);
507 clk
->bstate
.base
.domain
[clock
->name
] = ret
;
511 nvkm_pstate_info(clk
, &clk
->bstate
);
513 clk
->astate
= clk
->state_nr
- 1;
517 nvkm_pstate_calc(clk
, true);
522 _nvkm_clk_dtor(struct nvkm_object
*object
)
524 struct nvkm_clk
*clk
= (void *)object
;
525 struct nvkm_pstate
*pstate
, *temp
;
527 nvkm_notify_fini(&clk
->pwrsrc_ntfy
);
529 list_for_each_entry_safe(pstate
, temp
, &clk
->states
, head
) {
530 nvkm_pstate_del(pstate
);
533 nvkm_subdev_destroy(&clk
->subdev
);
537 nvkm_clk_create_(struct nvkm_object
*parent
, struct nvkm_object
*engine
,
538 struct nvkm_oclass
*oclass
, struct nvkm_domain
*clocks
,
539 struct nvkm_pstate
*pstates
, int nb_pstates
,
540 bool allow_reclock
, int length
, void **object
)
542 struct nvkm_device
*device
= nv_device(parent
);
543 struct nvkm_clk
*clk
;
544 int ret
, idx
, arglen
;
547 ret
= nvkm_subdev_create_(parent
, engine
, oclass
, 0, "CLK",
548 "clock", length
, object
);
553 INIT_LIST_HEAD(&clk
->states
);
554 clk
->domains
= clocks
;
558 INIT_WORK(&clk
->work
, nvkm_pstate_work
);
559 init_waitqueue_head(&clk
->wait
);
560 atomic_set(&clk
->waiting
, 0);
562 /* If no pstates are provided, try and fetch them from the BIOS */
566 ret
= nvkm_pstate_new(clk
, idx
++);
569 for (idx
= 0; idx
< nb_pstates
; idx
++)
570 list_add_tail(&pstates
[idx
].head
, &clk
->states
);
571 clk
->state_nr
= nb_pstates
;
574 clk
->allow_reclock
= allow_reclock
;
576 ret
= nvkm_notify_init(NULL
, &device
->event
, nvkm_clk_pwrsrc
, true,
577 NULL
, 0, 0, &clk
->pwrsrc_ntfy
);
581 mode
= nvkm_stropt(device
->cfgopt
, "NvClkMode", &arglen
);
583 clk
->ustate_ac
= nvkm_clk_nstate(clk
, mode
, arglen
);
584 clk
->ustate_dc
= nvkm_clk_nstate(clk
, mode
, arglen
);
587 mode
= nvkm_stropt(device
->cfgopt
, "NvClkModeAC", &arglen
);
589 clk
->ustate_ac
= nvkm_clk_nstate(clk
, mode
, arglen
);
591 mode
= nvkm_stropt(device
->cfgopt
, "NvClkModeDC", &arglen
);
593 clk
->ustate_dc
= nvkm_clk_nstate(clk
, mode
, arglen
);