0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #include "pll.h"
0024
0025 #include <subdev/bios.h>
0026 #include <subdev/bios/pll.h>
0027
0028 static int
0029 getMNP_single(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk,
0030 int *pN, int *pM, int *pP)
0031 {
0032
0033
0034
0035
0036
0037
0038
0039
0040 struct nvkm_bios *bios = subdev->device->bios;
0041 int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq;
0042 int minM = info->vco1.min_m, maxM = info->vco1.max_m;
0043 int minN = info->vco1.min_n, maxN = info->vco1.max_n;
0044 int minU = info->vco1.min_inputfreq;
0045 int maxU = info->vco1.max_inputfreq;
0046 int minP = info->min_p;
0047 int maxP = info->max_p_usable;
0048 int crystal = info->refclk;
0049 int M, N, thisP, P;
0050 int clkP, calcclk;
0051 int delta, bestdelta = INT_MAX;
0052 int bestclk = 0;
0053
0054
0055
0056 if (bios->version.major < 0x60) {
0057 int cv = bios->version.chip;
0058 if (cv < 0x17 || cv == 0x1a || cv == 0x20) {
0059 if (clk > 250000)
0060 maxM = 6;
0061 if (clk > 340000)
0062 maxM = 2;
0063 } else if (cv < 0x40) {
0064 if (clk > 150000)
0065 maxM = 6;
0066 if (clk > 200000)
0067 maxM = 4;
0068 if (clk > 340000)
0069 maxM = 2;
0070 }
0071 }
0072
0073 P = 1 << maxP;
0074 if ((clk * P) < minvco) {
0075 minvco = clk * maxP;
0076 maxvco = minvco * 2;
0077 }
0078
0079 if (clk + clk/200 > maxvco)
0080 maxvco = clk + clk/200;
0081
0082
0083 for (thisP = minP; thisP <= maxP; thisP++) {
0084 P = 1 << thisP;
0085 clkP = clk * P;
0086
0087 if (clkP < minvco)
0088 continue;
0089 if (clkP > maxvco)
0090 return bestclk;
0091
0092 for (M = minM; M <= maxM; M++) {
0093 if (crystal/M < minU)
0094 return bestclk;
0095 if (crystal/M > maxU)
0096 continue;
0097
0098
0099 N = (clkP * M + crystal/2) / crystal;
0100
0101 if (N < minN)
0102 continue;
0103 if (N > maxN)
0104 break;
0105
0106
0107 calcclk = ((N * crystal + P/2) / P + M/2) / M;
0108 delta = abs(calcclk - clk);
0109
0110
0111
0112 if (delta < bestdelta) {
0113 bestdelta = delta;
0114 bestclk = calcclk;
0115 *pN = N;
0116 *pM = M;
0117 *pP = thisP;
0118 if (delta == 0)
0119 return bestclk;
0120 }
0121 }
0122 }
0123
0124 return bestclk;
0125 }
0126
0127 static int
0128 getMNP_double(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk,
0129 int *pN1, int *pM1, int *pN2, int *pM2, int *pP)
0130 {
0131
0132
0133
0134
0135
0136
0137
0138
0139 int chip_version = subdev->device->bios->version.chip;
0140 int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq;
0141 int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq;
0142 int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq;
0143 int maxU1 = info->vco1.max_inputfreq, maxU2 = info->vco2.max_inputfreq;
0144 int minM1 = info->vco1.min_m, maxM1 = info->vco1.max_m;
0145 int minN1 = info->vco1.min_n, maxN1 = info->vco1.max_n;
0146 int minM2 = info->vco2.min_m, maxM2 = info->vco2.max_m;
0147 int minN2 = info->vco2.min_n, maxN2 = info->vco2.max_n;
0148 int maxlog2P = info->max_p_usable;
0149 int crystal = info->refclk;
0150 bool fixedgain2 = (minM2 == maxM2 && minN2 == maxN2);
0151 int M1, N1, M2, N2, log2P;
0152 int clkP, calcclk1, calcclk2, calcclkout;
0153 int delta, bestdelta = INT_MAX;
0154 int bestclk = 0;
0155
0156 int vco2 = (maxvco2 - maxvco2/200) / 2;
0157 for (log2P = 0; clk && log2P < maxlog2P && clk <= (vco2 >> log2P); log2P++)
0158 ;
0159 clkP = clk << log2P;
0160
0161 if (maxvco2 < clk + clk/200)
0162 maxvco2 = clk + clk/200;
0163
0164 for (M1 = minM1; M1 <= maxM1; M1++) {
0165 if (crystal/M1 < minU1)
0166 return bestclk;
0167 if (crystal/M1 > maxU1)
0168 continue;
0169
0170 for (N1 = minN1; N1 <= maxN1; N1++) {
0171 calcclk1 = crystal * N1 / M1;
0172 if (calcclk1 < minvco1)
0173 continue;
0174 if (calcclk1 > maxvco1)
0175 break;
0176
0177 for (M2 = minM2; M2 <= maxM2; M2++) {
0178 if (calcclk1/M2 < minU2)
0179 break;
0180 if (calcclk1/M2 > maxU2)
0181 continue;
0182
0183
0184 N2 = (clkP * M2 + calcclk1/2) / calcclk1;
0185 if (N2 < minN2)
0186 continue;
0187 if (N2 > maxN2)
0188 break;
0189
0190 if (!fixedgain2) {
0191 if (chip_version < 0x60)
0192 if (N2/M2 < 4 || N2/M2 > 10)
0193 continue;
0194
0195 calcclk2 = calcclk1 * N2 / M2;
0196 if (calcclk2 < minvco2)
0197 break;
0198 if (calcclk2 > maxvco2)
0199 continue;
0200 } else
0201 calcclk2 = calcclk1;
0202
0203 calcclkout = calcclk2 >> log2P;
0204 delta = abs(calcclkout - clk);
0205
0206
0207
0208 if (delta < bestdelta) {
0209 bestdelta = delta;
0210 bestclk = calcclkout;
0211 *pN1 = N1;
0212 *pM1 = M1;
0213 *pN2 = N2;
0214 *pM2 = M2;
0215 *pP = log2P;
0216 if (delta == 0)
0217 return bestclk;
0218 }
0219 }
0220 }
0221 }
0222
0223 return bestclk;
0224 }
0225
0226 int
0227 nv04_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info, u32 freq,
0228 int *N1, int *M1, int *N2, int *M2, int *P)
0229 {
0230 int ret;
0231
0232 if (!info->vco2.max_freq || !N2) {
0233 ret = getMNP_single(subdev, info, freq, N1, M1, P);
0234 if (N2) {
0235 *N2 = 1;
0236 *M2 = 1;
0237 }
0238 } else {
0239 ret = getMNP_double(subdev, info, freq, N1, M1, N2, M2, P);
0240 }
0241
0242 if (!ret)
0243 nvkm_error(subdev, "unable to compute acceptable pll values\n");
0244 return ret;
0245 }