1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "drmP.h"
26#include "nouveau_drv.h"
27#include "nouveau_hw.h"
28
29int
30nv50_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
31 int *N1, int *M1, int *N2, int *M2, int *P)
32{
33 struct nouveau_pll_vals pll_vals;
34 int ret;
35
36 ret = nouveau_calc_pll_mnp(dev, pll, clk, &pll_vals);
37 if (ret <= 0)
38 return ret;
39
40 *N1 = pll_vals.N1;
41 *M1 = pll_vals.M1;
42 *N2 = pll_vals.N2;
43 *M2 = pll_vals.M2;
44 *P = pll_vals.log2P;
45 return ret;
46}
47
48int
49nva3_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
50 int *pN, int *pfN, int *pM, int *P)
51{
52 u32 best_err = ~0, err;
53 int M, lM, hM, N, fN;
54
55 *P = pll->vco1.maxfreq / clk;
56 if (*P > pll->max_p)
57 *P = pll->max_p;
58 if (*P < pll->min_p)
59 *P = pll->min_p;
60
61 lM = (pll->refclk + pll->vco1.max_inputfreq) / pll->vco1.max_inputfreq;
62 lM = max(lM, (int)pll->vco1.min_m);
63 hM = (pll->refclk + pll->vco1.min_inputfreq) / pll->vco1.min_inputfreq;
64 hM = min(hM, (int)pll->vco1.max_m);
65
66 for (M = lM; M <= hM; M++) {
67 u32 tmp = clk * *P * M;
68 N = tmp / pll->refclk;
69 fN = tmp % pll->refclk;
70 if (!pfN && fN >= pll->refclk / 2)
71 N++;
72
73 if (N < pll->vco1.min_n)
74 continue;
75 if (N > pll->vco1.max_n)
76 break;
77
78 err = abs(clk - (pll->refclk * N / M / *P));
79 if (err < best_err) {
80 best_err = err;
81 *pN = N;
82 *pM = M;
83 }
84
85 if (pfN) {
86 *pfN = (((fN << 13) / pll->refclk) - 4096) & 0xffff;
87 return clk;
88 }
89 }
90
91 if (unlikely(best_err == ~0)) {
92 NV_ERROR(dev, "unable to find matching pll values\n");
93 return -EINVAL;
94 }
95
96 return pll->refclk * *pN / *pM / *P;
97}
98