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.
25 #include <subdev/clock.h>
26 #include <subdev/timer.h>
27 #include <subdev/bios.h>
28 #include <subdev/bios/pll.h>
32 struct nve0_clock_info
{
41 struct nve0_clock_priv
{
42 struct nouveau_clock base
;
43 struct nve0_clock_info eng
[16];
46 static u32
read_div(struct nve0_clock_priv
*, int, u32
, u32
);
47 static u32
read_pll(struct nve0_clock_priv
*, u32
);
50 read_vco(struct nve0_clock_priv
*priv
, u32 dsrc
)
52 u32 ssrc
= nv_rd32(priv
, dsrc
);
53 if (!(ssrc
& 0x00000100))
54 return read_pll(priv
, 0x00e800);
55 return read_pll(priv
, 0x00e820);
59 read_pll(struct nve0_clock_priv
*priv
, u32 pll
)
61 u32 ctrl
= nv_rd32(priv
, pll
+ 0x00);
62 u32 coef
= nv_rd32(priv
, pll
+ 0x04);
63 u32 P
= (coef
& 0x003f0000) >> 16;
64 u32 N
= (coef
& 0x0000ff00) >> 8;
65 u32 M
= (coef
& 0x000000ff) >> 0;
69 if (!(ctrl
& 0x00000001))
75 sclk
= nv_device(priv
)->crystal
;
79 sclk
= read_pll(priv
, 0x132020);
80 P
= (coef
& 0x10000000) ? 2 : 1;
83 sclk
= read_div(priv
, 0, 0x137320, 0x137330);
84 fN
= nv_rd32(priv
, pll
+ 0x10) >> 16;
90 sclk
= read_div(priv
, (pll
& 0xff) / 0x20, 0x137120, 0x137140);
99 sclk
= (sclk
* N
) + (((u16
)(fN
+ 4096) * sclk
) >> 13);
100 return sclk
/ (M
* P
);
104 read_div(struct nve0_clock_priv
*priv
, int doff
, u32 dsrc
, u32 dctl
)
106 u32 ssrc
= nv_rd32(priv
, dsrc
+ (doff
* 4));
107 u32 sctl
= nv_rd32(priv
, dctl
+ (doff
* 4));
109 switch (ssrc
& 0x00000003) {
111 if ((ssrc
& 0x00030000) != 0x00030000)
112 return nv_device(priv
)->crystal
;
117 if (sctl
& 0x80000000) {
118 u32 sclk
= read_vco(priv
, dsrc
+ (doff
* 4));
119 u32 sdiv
= (sctl
& 0x0000003f) + 2;
120 return (sclk
* 2) / sdiv
;
123 return read_vco(priv
, dsrc
+ (doff
* 4));
130 read_mem(struct nve0_clock_priv
*priv
)
132 switch (nv_rd32(priv
, 0x1373f4) & 0x0000000f) {
133 case 1: return read_pll(priv
, 0x132020);
134 case 2: return read_pll(priv
, 0x132000);
141 read_clk(struct nve0_clock_priv
*priv
, int clk
)
143 u32 sctl
= nv_rd32(priv
, 0x137250 + (clk
* 4));
147 u32 ssel
= nv_rd32(priv
, 0x137100);
148 if (ssel
& (1 << clk
)) {
149 sclk
= read_pll(priv
, 0x137000 + (clk
* 0x20));
152 sclk
= read_div(priv
, clk
, 0x137160, 0x1371d0);
156 u32 ssrc
= nv_rd32(priv
, 0x137160 + (clk
* 0x04));
157 if ((ssrc
& 0x00000003) == 0x00000003) {
158 sclk
= read_div(priv
, clk
, 0x137160, 0x1371d0);
159 if (ssrc
& 0x00000100) {
160 if (ssrc
& 0x40000000)
161 sclk
= read_pll(priv
, 0x1370e0);
167 sclk
= read_div(priv
, clk
, 0x137160, 0x1371d0);
172 if (sctl
& 0x80000000) {
174 sdiv
= ((sctl
& 0x00003f00) >> 8) + 2;
176 sdiv
= ((sctl
& 0x0000003f) >> 0) + 2;
177 return (sclk
* 2) / sdiv
;
184 nve0_clock_read(struct nouveau_clock
*clk
, enum nv_clk_src src
)
186 struct nouveau_device
*device
= nv_device(clk
);
187 struct nve0_clock_priv
*priv
= (void *)clk
;
190 case nv_clk_src_crystal
:
191 return device
->crystal
;
192 case nv_clk_src_href
:
195 return read_mem(priv
);
197 return read_clk(priv
, 0x00);
199 return read_clk(priv
, 0x01);
200 case nv_clk_src_hubk07
:
201 return read_clk(priv
, 0x02);
202 case nv_clk_src_hubk06
:
203 return read_clk(priv
, 0x07);
204 case nv_clk_src_hubk01
:
205 return read_clk(priv
, 0x08);
206 case nv_clk_src_daemon
:
207 return read_clk(priv
, 0x0c);
208 case nv_clk_src_vdec
:
209 return read_clk(priv
, 0x0e);
211 nv_error(clk
, "invalid clock source %d\n", src
);
217 calc_div(struct nve0_clock_priv
*priv
, int clk
, u32 ref
, u32 freq
, u32
*ddiv
)
219 u32 div
= min((ref
* 2) / freq
, (u32
)65);
224 return (ref
* 2) / div
;
228 calc_src(struct nve0_clock_priv
*priv
, int clk
, u32 freq
, u32
*dsrc
, u32
*ddiv
)
232 /* use one of the fixed frequencies if possible */
249 /* otherwise, calculate the closest divider */
250 sclk
= read_vco(priv
, 0x137160 + (clk
* 4));
252 sclk
= calc_div(priv
, clk
, sclk
, freq
, ddiv
);
257 calc_pll(struct nve0_clock_priv
*priv
, int clk
, u32 freq
, u32
*coef
)
259 struct nouveau_bios
*bios
= nouveau_bios(priv
);
260 struct nvbios_pll limits
;
263 ret
= nvbios_pll_parse(bios
, 0x137000 + (clk
* 0x20), &limits
);
267 limits
.refclk
= read_div(priv
, clk
, 0x137120, 0x137140);
271 ret
= nva3_pll_calc(nv_subdev(priv
), &limits
, freq
, &N
, NULL
, &M
, &P
);
275 *coef
= (P
<< 16) | (N
<< 8) | M
;
280 calc_clk(struct nve0_clock_priv
*priv
,
281 struct nouveau_cstate
*cstate
, int clk
, int dom
)
283 struct nve0_clock_info
*info
= &priv
->eng
[clk
];
284 u32 freq
= cstate
->domain
[dom
];
285 u32 src0
, div0
, div1D
, div1P
= 0;
288 /* invalid clock domain */
292 /* first possible path, using only dividers */
293 clk0
= calc_src(priv
, clk
, freq
, &src0
, &div0
);
294 clk0
= calc_div(priv
, clk
, clk0
, freq
, &div1D
);
296 /* see if we can get any closer using PLLs */
297 if (clk0
!= freq
&& (0x0000ff87 & (1 << clk
))) {
299 clk1
= calc_pll(priv
, clk
, freq
, &info
->coef
);
301 clk1
= cstate
->domain
[nv_clk_src_hubk06
];
302 clk1
= calc_div(priv
, clk
, clk1
, freq
, &div1P
);
305 /* select the method which gets closest to target freq */
306 if (abs((int)freq
- clk0
) <= abs((int)freq
- clk1
)) {
309 info
->ddiv
|= 0x80000000;
313 info
->mdiv
|= 0x80000000;
320 info
->mdiv
|= 0x80000000;
321 info
->mdiv
|= div1P
<< 8;
323 info
->ssel
= (1 << clk
);
324 info
->dsrc
= 0x40000100;
332 nve0_clock_calc(struct nouveau_clock
*clk
, struct nouveau_cstate
*cstate
)
334 struct nve0_clock_priv
*priv
= (void *)clk
;
337 if ((ret
= calc_clk(priv
, cstate
, 0x00, nv_clk_src_gpc
)) ||
338 (ret
= calc_clk(priv
, cstate
, 0x01, nv_clk_src_rop
)) ||
339 (ret
= calc_clk(priv
, cstate
, 0x02, nv_clk_src_hubk07
)) ||
340 (ret
= calc_clk(priv
, cstate
, 0x07, nv_clk_src_hubk06
)) ||
341 (ret
= calc_clk(priv
, cstate
, 0x08, nv_clk_src_hubk01
)) ||
342 (ret
= calc_clk(priv
, cstate
, 0x0c, nv_clk_src_daemon
)) ||
343 (ret
= calc_clk(priv
, cstate
, 0x0e, nv_clk_src_vdec
)))
350 nve0_clock_prog_0(struct nve0_clock_priv
*priv
, int clk
)
352 struct nve0_clock_info
*info
= &priv
->eng
[clk
];
354 nv_mask(priv
, 0x1371d0 + (clk
* 0x04), 0x8000003f, info
->ddiv
);
355 nv_wr32(priv
, 0x137160 + (clk
* 0x04), info
->dsrc
);
360 nve0_clock_prog_1_0(struct nve0_clock_priv
*priv
, int clk
)
362 nv_mask(priv
, 0x137100, (1 << clk
), 0x00000000);
363 nv_wait(priv
, 0x137100, (1 << clk
), 0x00000000);
367 nve0_clock_prog_1_1(struct nve0_clock_priv
*priv
, int clk
)
369 nv_mask(priv
, 0x137160 + (clk
* 0x04), 0x00000100, 0x00000000);
373 nve0_clock_prog_2(struct nve0_clock_priv
*priv
, int clk
)
375 struct nve0_clock_info
*info
= &priv
->eng
[clk
];
376 const u32 addr
= 0x137000 + (clk
* 0x20);
377 nv_mask(priv
, addr
+ 0x00, 0x00000004, 0x00000000);
378 nv_mask(priv
, addr
+ 0x00, 0x00000001, 0x00000000);
380 nv_wr32(priv
, addr
+ 0x04, info
->coef
);
381 nv_mask(priv
, addr
+ 0x00, 0x00000001, 0x00000001);
382 nv_wait(priv
, addr
+ 0x00, 0x00020000, 0x00020000);
383 nv_mask(priv
, addr
+ 0x00, 0x00020004, 0x00000004);
388 nve0_clock_prog_3(struct nve0_clock_priv
*priv
, int clk
)
390 struct nve0_clock_info
*info
= &priv
->eng
[clk
];
392 nv_mask(priv
, 0x137250 + (clk
* 0x04), 0x00003f00, info
->mdiv
);
394 nv_mask(priv
, 0x137250 + (clk
* 0x04), 0x0000003f, info
->mdiv
);
398 nve0_clock_prog_4_0(struct nve0_clock_priv
*priv
, int clk
)
400 struct nve0_clock_info
*info
= &priv
->eng
[clk
];
402 nv_mask(priv
, 0x137100, (1 << clk
), info
->ssel
);
403 nv_wait(priv
, 0x137100, (1 << clk
), info
->ssel
);
408 nve0_clock_prog_4_1(struct nve0_clock_priv
*priv
, int clk
)
410 struct nve0_clock_info
*info
= &priv
->eng
[clk
];
412 nv_mask(priv
, 0x137160 + (clk
* 0x04), 0x40000000, 0x40000000);
413 nv_mask(priv
, 0x137160 + (clk
* 0x04), 0x00000100, 0x00000100);
418 nve0_clock_prog(struct nouveau_clock
*clk
)
420 struct nve0_clock_priv
*priv
= (void *)clk
;
423 void (*exec
)(struct nve0_clock_priv
*, int);
425 { 0x007f, nve0_clock_prog_0
}, /* div programming */
426 { 0x007f, nve0_clock_prog_1_0
}, /* select div mode */
427 { 0xff80, nve0_clock_prog_1_1
},
428 { 0x00ff, nve0_clock_prog_2
}, /* (maybe) program pll */
429 { 0xff80, nve0_clock_prog_3
}, /* final divider */
430 { 0x007f, nve0_clock_prog_4_0
}, /* (maybe) select pll mode */
431 { 0xff80, nve0_clock_prog_4_1
},
435 for (i
= 0; i
< ARRAY_SIZE(stage
); i
++) {
436 for (j
= 0; j
< ARRAY_SIZE(priv
->eng
); j
++) {
437 if (!(stage
[i
].mask
& (1 << j
)))
439 if (!priv
->eng
[j
].freq
)
441 stage
[i
].exec(priv
, j
);
449 nve0_clock_tidy(struct nouveau_clock
*clk
)
451 struct nve0_clock_priv
*priv
= (void *)clk
;
452 memset(priv
->eng
, 0x00, sizeof(priv
->eng
));
455 static struct nouveau_clocks
457 { nv_clk_src_crystal
, 0xff },
458 { nv_clk_src_href
, 0xff },
459 { nv_clk_src_gpc
, 0x00, NVKM_CLK_DOM_FLAG_CORE
, "core", 2000 },
460 { nv_clk_src_hubk07
, 0x01, NVKM_CLK_DOM_FLAG_CORE
},
461 { nv_clk_src_rop
, 0x02, NVKM_CLK_DOM_FLAG_CORE
},
462 { nv_clk_src_mem
, 0x03, 0, "memory", 500 },
463 { nv_clk_src_hubk06
, 0x04, NVKM_CLK_DOM_FLAG_CORE
},
464 { nv_clk_src_hubk01
, 0x05 },
465 { nv_clk_src_vdec
, 0x06 },
466 { nv_clk_src_daemon
, 0x07 },
471 nve0_clock_ctor(struct nouveau_object
*parent
, struct nouveau_object
*engine
,
472 struct nouveau_oclass
*oclass
, void *data
, u32 size
,
473 struct nouveau_object
**pobject
)
475 struct nve0_clock_priv
*priv
;
478 ret
= nouveau_clock_create(parent
, engine
, oclass
, nve0_domain
, NULL
, 0,
480 *pobject
= nv_object(priv
);
484 priv
->base
.read
= nve0_clock_read
;
485 priv
->base
.calc
= nve0_clock_calc
;
486 priv
->base
.prog
= nve0_clock_prog
;
487 priv
->base
.tidy
= nve0_clock_tidy
;
491 struct nouveau_oclass
492 nve0_clock_oclass
= {
493 .handle
= NV_SUBDEV(CLOCK
, 0xe0),
494 .ofuncs
= &(struct nouveau_ofuncs
) {
495 .ctor
= nve0_clock_ctor
,
496 .dtor
= _nouveau_clock_dtor
,
497 .init
= _nouveau_clock_init
,
498 .fini
= _nouveau_clock_fini
,
This page took 0.095279 seconds and 5 git commands to generate.