2 * Copyright 1993-2003 NVIDIA, Corporation
3 * Copyright 2007-2009 Stuart Bennett
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 #include <subdev/bios.h>
26 #include <subdev/bios/pll.h>
29 getMNP_single(struct nvkm_subdev
*subdev
, struct nvbios_pll
*info
, int clk
,
30 int *pN
, int *pM
, int *pP
)
32 /* Find M, N and P for a single stage PLL
34 * Note that some bioses (NV3x) have lookup tables of precomputed MNP
35 * values, but we're too lazy to use those atm
37 * "clk" parameter in kHz
38 * returns calculated clock
40 struct nvkm_bios
*bios
= subdev
->device
->bios
;
41 int minvco
= info
->vco1
.min_freq
, maxvco
= info
->vco1
.max_freq
;
42 int minM
= info
->vco1
.min_m
, maxM
= info
->vco1
.max_m
;
43 int minN
= info
->vco1
.min_n
, maxN
= info
->vco1
.max_n
;
44 int minU
= info
->vco1
.min_inputfreq
;
45 int maxU
= info
->vco1
.max_inputfreq
;
46 int minP
= info
->min_p
;
47 int maxP
= info
->max_p_usable
;
48 int crystal
= info
->refclk
;
51 int delta
, bestdelta
= INT_MAX
;
54 /* this division verified for nv20, nv18, nv28 (Haiku), and nv34 */
55 /* possibly correlated with introduction of 27MHz crystal */
56 if (bios
->version
.major
< 0x60) {
57 int cv
= bios
->version
.chip
;
58 if (cv
< 0x17 || cv
== 0x1a || cv
== 0x20) {
63 } else if (cv
< 0x40) {
74 if ((clk
* P
) < minvco
) {
79 if (clk
+ clk
/200 > maxvco
) /* +0.5% */
80 maxvco
= clk
+ clk
/200;
82 /* NV34 goes maxlog2P->0, NV20 goes 0->maxlog2P */
83 for (thisP
= minP
; thisP
<= maxP
; thisP
++) {
92 for (M
= minM
; M
<= maxM
; M
++) {
98 /* add crystal/2 to round better */
99 N
= (clkP
* M
+ crystal
/2) / crystal
;
106 /* more rounding additions */
107 calcclk
= ((N
* crystal
+ P
/2) / P
+ M
/2) / M
;
108 delta
= abs(calcclk
- clk
);
109 /* we do an exhaustive search rather than terminating
110 * on an optimality condition...
112 if (delta
< bestdelta
) {
118 if (delta
== 0) /* except this one */
128 getMNP_double(struct nvkm_subdev
*subdev
, struct nvbios_pll
*info
, int clk
,
129 int *pN1
, int *pM1
, int *pN2
, int *pM2
, int *pP
)
131 /* Find M, N and P for a two stage PLL
133 * Note that some bioses (NV30+) have lookup tables of precomputed MNP
134 * values, but we're too lazy to use those atm
136 * "clk" parameter in kHz
137 * returns calculated clock
139 int chip_version
= subdev
->device
->bios
->version
.chip
;
140 int minvco1
= info
->vco1
.min_freq
, maxvco1
= info
->vco1
.max_freq
;
141 int minvco2
= info
->vco2
.min_freq
, maxvco2
= info
->vco2
.max_freq
;
142 int minU1
= info
->vco1
.min_inputfreq
, minU2
= info
->vco2
.min_inputfreq
;
143 int maxU1
= info
->vco1
.max_inputfreq
, maxU2
= info
->vco2
.max_inputfreq
;
144 int minM1
= info
->vco1
.min_m
, maxM1
= info
->vco1
.max_m
;
145 int minN1
= info
->vco1
.min_n
, maxN1
= info
->vco1
.max_n
;
146 int minM2
= info
->vco2
.min_m
, maxM2
= info
->vco2
.max_m
;
147 int minN2
= info
->vco2
.min_n
, maxN2
= info
->vco2
.max_n
;
148 int maxlog2P
= info
->max_p_usable
;
149 int crystal
= info
->refclk
;
150 bool fixedgain2
= (minM2
== maxM2
&& minN2
== maxN2
);
151 int M1
, N1
, M2
, N2
, log2P
;
152 int clkP
, calcclk1
, calcclk2
, calcclkout
;
153 int delta
, bestdelta
= INT_MAX
;
156 int vco2
= (maxvco2
- maxvco2
/200) / 2;
157 for (log2P
= 0; clk
&& log2P
< maxlog2P
&& clk
<= (vco2
>> log2P
); log2P
++)
161 if (maxvco2
< clk
+ clk
/200) /* +0.5% */
162 maxvco2
= clk
+ clk
/200;
164 for (M1
= minM1
; M1
<= maxM1
; M1
++) {
165 if (crystal
/M1
< minU1
)
167 if (crystal
/M1
> maxU1
)
170 for (N1
= minN1
; N1
<= maxN1
; N1
++) {
171 calcclk1
= crystal
* N1
/ M1
;
172 if (calcclk1
< minvco1
)
174 if (calcclk1
> maxvco1
)
177 for (M2
= minM2
; M2
<= maxM2
; M2
++) {
178 if (calcclk1
/M2
< minU2
)
180 if (calcclk1
/M2
> maxU2
)
183 /* add calcclk1/2 to round better */
184 N2
= (clkP
* M2
+ calcclk1
/2) / calcclk1
;
191 if (chip_version
< 0x60)
192 if (N2
/M2
< 4 || N2
/M2
> 10)
195 calcclk2
= calcclk1
* N2
/ M2
;
196 if (calcclk2
< minvco2
)
198 if (calcclk2
> maxvco2
)
203 calcclkout
= calcclk2
>> log2P
;
204 delta
= abs(calcclkout
- clk
);
205 /* we do an exhaustive search rather than terminating
206 * on an optimality condition...
208 if (delta
< bestdelta
) {
210 bestclk
= calcclkout
;
216 if (delta
== 0) /* except this one */
227 nv04_pll_calc(struct nvkm_subdev
*subdev
, struct nvbios_pll
*info
, u32 freq
,
228 int *N1
, int *M1
, int *N2
, int *M2
, int *P
)
232 if (!info
->vco2
.max_freq
|| !N2
) {
233 ret
= getMNP_single(subdev
, info
, freq
, N1
, M1
, P
);
239 ret
= getMNP_double(subdev
, info
, freq
, N1
, M1
, N2
, M2
, P
);
243 nvkm_error(subdev
, "unable to compute acceptable pll values\n");