]>
Commit | Line | Data |
---|---|---|
70790f4f BS |
1 | /* |
2 | * Copyright 2005-2006 Erik Waling | |
3 | * Copyright 2006 Stephane Marchesin | |
4 | * Copyright 2007-2009 Stuart Bennett | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining a | |
7 | * copy of this software and associated documentation files (the "Software"), | |
8 | * to deal in the Software without restriction, including without limitation | |
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
10 | * and/or sell copies of the Software, and to permit persons to whom the | |
11 | * Software is furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in | |
14 | * all copies or substantial portions of the Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
20 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | |
21 | * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
22 | * SOFTWARE. | |
23 | */ | |
70790f4f BS |
24 | #include <subdev/bios.h> |
25 | #include <subdev/bios/bit.h> | |
26 | #include <subdev/bios/bmp.h> | |
27 | #include <subdev/bios/pll.h> | |
d390b480 BS |
28 | #include <subdev/vga.h> |
29 | ||
70790f4f BS |
30 | |
31 | struct pll_mapping { | |
32 | u8 type; | |
33 | u32 reg; | |
34 | }; | |
35 | ||
36 | static struct pll_mapping | |
37 | nv04_pll_mapping[] = { | |
38 | { PLL_CORE , 0x680500 }, | |
39 | { PLL_MEMORY, 0x680504 }, | |
40 | { PLL_VPLL0 , 0x680508 }, | |
41 | { PLL_VPLL1 , 0x680520 }, | |
42 | {} | |
43 | }; | |
44 | ||
45 | static struct pll_mapping | |
46 | nv40_pll_mapping[] = { | |
47 | { PLL_CORE , 0x004000 }, | |
48 | { PLL_MEMORY, 0x004020 }, | |
49 | { PLL_VPLL0 , 0x680508 }, | |
50 | { PLL_VPLL1 , 0x680520 }, | |
51 | {} | |
52 | }; | |
53 | ||
54 | static struct pll_mapping | |
55 | nv50_pll_mapping[] = { | |
56 | { PLL_CORE , 0x004028 }, | |
57 | { PLL_SHADER, 0x004020 }, | |
58 | { PLL_UNK03 , 0x004000 }, | |
59 | { PLL_MEMORY, 0x004008 }, | |
60 | { PLL_UNK40 , 0x00e810 }, | |
61 | { PLL_UNK41 , 0x00e818 }, | |
62 | { PLL_UNK42 , 0x00e824 }, | |
63 | { PLL_VPLL0 , 0x614100 }, | |
64 | { PLL_VPLL1 , 0x614900 }, | |
65 | {} | |
66 | }; | |
67 | ||
68 | static struct pll_mapping | |
d390b480 | 69 | g84_pll_mapping[] = { |
70790f4f BS |
70 | { PLL_CORE , 0x004028 }, |
71 | { PLL_SHADER, 0x004020 }, | |
72 | { PLL_MEMORY, 0x004008 }, | |
73 | { PLL_VDEC , 0x004030 }, | |
74 | { PLL_UNK41 , 0x00e818 }, | |
75 | { PLL_VPLL0 , 0x614100 }, | |
76 | { PLL_VPLL1 , 0x614900 }, | |
77 | {} | |
78 | }; | |
79 | ||
80 | static u16 | |
d390b480 | 81 | pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) |
70790f4f BS |
82 | { |
83 | struct bit_entry bit_C; | |
4d3df19a | 84 | u16 data = 0x0000; |
70790f4f | 85 | |
4d3df19a BS |
86 | if (!bit_entry(bios, 'C', &bit_C)) { |
87 | if (bit_C.version == 1 && bit_C.length >= 10) | |
88 | data = nvbios_rd16(bios, bit_C.offset + 8); | |
70790f4f | 89 | if (data) { |
7f5f518f BS |
90 | *ver = nvbios_rd08(bios, data + 0); |
91 | *hdr = nvbios_rd08(bios, data + 1); | |
92 | *len = nvbios_rd08(bios, data + 2); | |
93 | *cnt = nvbios_rd08(bios, data + 3); | |
70790f4f BS |
94 | return data; |
95 | } | |
96 | } | |
97 | ||
98 | if (bmp_version(bios) >= 0x0524) { | |
4d3df19a | 99 | data = nvbios_rd16(bios, bios->bmp_offset + 142); |
70790f4f | 100 | if (data) { |
7f5f518f | 101 | *ver = nvbios_rd08(bios, data + 0); |
70790f4f BS |
102 | *hdr = 1; |
103 | *cnt = 1; | |
104 | *len = 0x18; | |
105 | return data; | |
106 | } | |
107 | } | |
108 | ||
109 | *ver = 0x00; | |
4d3df19a | 110 | return data; |
70790f4f BS |
111 | } |
112 | ||
113 | static struct pll_mapping * | |
d390b480 | 114 | pll_map(struct nvkm_bios *bios) |
70790f4f | 115 | { |
46484438 BS |
116 | struct nvkm_device *device = bios->subdev.device; |
117 | switch (device->card_type) { | |
70790f4f BS |
118 | case NV_04: |
119 | case NV_10: | |
4a0ff754 | 120 | case NV_11: |
70790f4f BS |
121 | case NV_20: |
122 | case NV_30: | |
123 | return nv04_pll_mapping; | |
124 | break; | |
125 | case NV_40: | |
126 | return nv40_pll_mapping; | |
127 | case NV_50: | |
46484438 | 128 | if (device->chipset == 0x50) |
70790f4f BS |
129 | return nv50_pll_mapping; |
130 | else | |
46484438 BS |
131 | if (device->chipset < 0xa3 || |
132 | device->chipset == 0xaa || | |
133 | device->chipset == 0xac) | |
d390b480 | 134 | return g84_pll_mapping; |
70790f4f BS |
135 | default: |
136 | return NULL; | |
137 | } | |
138 | } | |
139 | ||
140 | static u16 | |
d390b480 | 141 | pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) |
70790f4f BS |
142 | { |
143 | struct pll_mapping *map; | |
144 | u8 hdr, cnt; | |
145 | u16 data; | |
146 | ||
147 | data = pll_limits_table(bios, ver, &hdr, &cnt, len); | |
148 | if (data && *ver >= 0x30) { | |
149 | data += hdr; | |
150 | while (cnt--) { | |
7f5f518f BS |
151 | if (nvbios_rd32(bios, data + 3) == reg) { |
152 | *type = nvbios_rd08(bios, data + 0); | |
70790f4f BS |
153 | return data; |
154 | } | |
155 | data += *len; | |
156 | } | |
157 | return 0x0000; | |
158 | } | |
159 | ||
160 | map = pll_map(bios); | |
2781c928 | 161 | while (map && map->reg) { |
70790f4f BS |
162 | if (map->reg == reg && *ver >= 0x20) { |
163 | u16 addr = (data += hdr); | |
5e5a195e | 164 | *type = map->type; |
70790f4f | 165 | while (cnt--) { |
7f5f518f | 166 | if (nvbios_rd32(bios, data) == map->reg) |
70790f4f | 167 | return data; |
70790f4f BS |
168 | data += *len; |
169 | } | |
170 | return addr; | |
171 | } else | |
172 | if (map->reg == reg) { | |
173 | *type = map->type; | |
174 | return data + 1; | |
175 | } | |
176 | map++; | |
177 | } | |
178 | ||
179 | return 0x0000; | |
180 | } | |
181 | ||
182 | static u16 | |
d390b480 | 183 | pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) |
70790f4f BS |
184 | { |
185 | struct pll_mapping *map; | |
186 | u8 hdr, cnt; | |
187 | u16 data; | |
188 | ||
189 | data = pll_limits_table(bios, ver, &hdr, &cnt, len); | |
190 | if (data && *ver >= 0x30) { | |
191 | data += hdr; | |
192 | while (cnt--) { | |
7f5f518f BS |
193 | if (nvbios_rd08(bios, data + 0) == type) { |
194 | *reg = nvbios_rd32(bios, data + 3); | |
70790f4f BS |
195 | return data; |
196 | } | |
197 | data += *len; | |
198 | } | |
199 | return 0x0000; | |
200 | } | |
201 | ||
202 | map = pll_map(bios); | |
2781c928 | 203 | while (map && map->reg) { |
70790f4f BS |
204 | if (map->type == type && *ver >= 0x20) { |
205 | u16 addr = (data += hdr); | |
5e5a195e | 206 | *reg = map->reg; |
70790f4f | 207 | while (cnt--) { |
7f5f518f | 208 | if (nvbios_rd32(bios, data) == map->reg) |
70790f4f | 209 | return data; |
70790f4f BS |
210 | data += *len; |
211 | } | |
212 | return addr; | |
213 | } else | |
214 | if (map->type == type) { | |
215 | *reg = map->reg; | |
216 | return data + 1; | |
217 | } | |
218 | map++; | |
219 | } | |
220 | ||
221 | return 0x0000; | |
222 | } | |
223 | ||
224 | int | |
d390b480 | 225 | nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) |
70790f4f | 226 | { |
60b29d20 BS |
227 | struct nvkm_subdev *subdev = &bios->subdev; |
228 | struct nvkm_device *device = subdev->device; | |
70790f4f BS |
229 | u8 ver, len; |
230 | u32 reg = type; | |
231 | u16 data; | |
232 | ||
233 | if (type > PLL_MAX) { | |
234 | reg = type; | |
235 | data = pll_map_reg(bios, reg, &type, &ver, &len); | |
236 | } else { | |
237 | data = pll_map_type(bios, type, ®, &ver, &len); | |
238 | } | |
239 | ||
240 | if (ver && !data) | |
241 | return -ENOENT; | |
242 | ||
243 | memset(info, 0, sizeof(*info)); | |
244 | info->type = type; | |
245 | info->reg = reg; | |
246 | ||
247 | switch (ver) { | |
248 | case 0x00: | |
249 | break; | |
250 | case 0x10: | |
251 | case 0x11: | |
7f5f518f BS |
252 | info->vco1.min_freq = nvbios_rd32(bios, data + 0); |
253 | info->vco1.max_freq = nvbios_rd32(bios, data + 4); | |
254 | info->vco2.min_freq = nvbios_rd32(bios, data + 8); | |
255 | info->vco2.max_freq = nvbios_rd32(bios, data + 12); | |
256 | info->vco1.min_inputfreq = nvbios_rd32(bios, data + 16); | |
257 | info->vco2.min_inputfreq = nvbios_rd32(bios, data + 20); | |
70790f4f BS |
258 | info->vco1.max_inputfreq = INT_MAX; |
259 | info->vco2.max_inputfreq = INT_MAX; | |
260 | ||
261 | info->max_p = 0x7; | |
262 | info->max_p_usable = 0x6; | |
263 | ||
264 | /* these values taken from nv30/31/36 */ | |
265 | switch (bios->version.chip) { | |
266 | case 0x36: | |
267 | info->vco1.min_n = 0x5; | |
268 | break; | |
269 | default: | |
270 | info->vco1.min_n = 0x1; | |
271 | break; | |
272 | } | |
273 | info->vco1.max_n = 0xff; | |
274 | info->vco1.min_m = 0x1; | |
275 | info->vco1.max_m = 0xd; | |
276 | ||
277 | /* | |
278 | * On nv30, 31, 36 (i.e. all cards with two stage PLLs with this | |
279 | * table version (apart from nv35)), N2 is compared to | |
280 | * maxN2 (0x46) and 10 * maxM2 (0x4), so set maxN2 to 0x28 and | |
281 | * save a comparison | |
282 | */ | |
283 | info->vco2.min_n = 0x4; | |
284 | switch (bios->version.chip) { | |
285 | case 0x30: | |
286 | case 0x35: | |
287 | info->vco2.max_n = 0x1f; | |
288 | break; | |
289 | default: | |
290 | info->vco2.max_n = 0x28; | |
291 | break; | |
292 | } | |
293 | info->vco2.min_m = 0x1; | |
294 | info->vco2.max_m = 0x4; | |
295 | break; | |
296 | case 0x20: | |
297 | case 0x21: | |
7f5f518f BS |
298 | info->vco1.min_freq = nvbios_rd16(bios, data + 4) * 1000; |
299 | info->vco1.max_freq = nvbios_rd16(bios, data + 6) * 1000; | |
300 | info->vco2.min_freq = nvbios_rd16(bios, data + 8) * 1000; | |
301 | info->vco2.max_freq = nvbios_rd16(bios, data + 10) * 1000; | |
302 | info->vco1.min_inputfreq = nvbios_rd16(bios, data + 12) * 1000; | |
303 | info->vco2.min_inputfreq = nvbios_rd16(bios, data + 14) * 1000; | |
304 | info->vco1.max_inputfreq = nvbios_rd16(bios, data + 16) * 1000; | |
305 | info->vco2.max_inputfreq = nvbios_rd16(bios, data + 18) * 1000; | |
306 | info->vco1.min_n = nvbios_rd08(bios, data + 20); | |
307 | info->vco1.max_n = nvbios_rd08(bios, data + 21); | |
308 | info->vco1.min_m = nvbios_rd08(bios, data + 22); | |
309 | info->vco1.max_m = nvbios_rd08(bios, data + 23); | |
310 | info->vco2.min_n = nvbios_rd08(bios, data + 24); | |
311 | info->vco2.max_n = nvbios_rd08(bios, data + 25); | |
312 | info->vco2.min_m = nvbios_rd08(bios, data + 26); | |
313 | info->vco2.max_m = nvbios_rd08(bios, data + 27); | |
314 | ||
315 | info->max_p = nvbios_rd08(bios, data + 29); | |
70790f4f BS |
316 | info->max_p_usable = info->max_p; |
317 | if (bios->version.chip < 0x60) | |
318 | info->max_p_usable = 0x6; | |
7f5f518f | 319 | info->bias_p = nvbios_rd08(bios, data + 30); |
70790f4f BS |
320 | |
321 | if (len > 0x22) | |
7f5f518f | 322 | info->refclk = nvbios_rd32(bios, data + 31); |
70790f4f BS |
323 | break; |
324 | case 0x30: | |
7f5f518f BS |
325 | data = nvbios_rd16(bios, data + 1); |
326 | ||
327 | info->vco1.min_freq = nvbios_rd16(bios, data + 0) * 1000; | |
328 | info->vco1.max_freq = nvbios_rd16(bios, data + 2) * 1000; | |
329 | info->vco2.min_freq = nvbios_rd16(bios, data + 4) * 1000; | |
330 | info->vco2.max_freq = nvbios_rd16(bios, data + 6) * 1000; | |
331 | info->vco1.min_inputfreq = nvbios_rd16(bios, data + 8) * 1000; | |
332 | info->vco2.min_inputfreq = nvbios_rd16(bios, data + 10) * 1000; | |
333 | info->vco1.max_inputfreq = nvbios_rd16(bios, data + 12) * 1000; | |
334 | info->vco2.max_inputfreq = nvbios_rd16(bios, data + 14) * 1000; | |
335 | info->vco1.min_n = nvbios_rd08(bios, data + 16); | |
336 | info->vco1.max_n = nvbios_rd08(bios, data + 17); | |
337 | info->vco1.min_m = nvbios_rd08(bios, data + 18); | |
338 | info->vco1.max_m = nvbios_rd08(bios, data + 19); | |
339 | info->vco2.min_n = nvbios_rd08(bios, data + 20); | |
340 | info->vco2.max_n = nvbios_rd08(bios, data + 21); | |
341 | info->vco2.min_m = nvbios_rd08(bios, data + 22); | |
342 | info->vco2.max_m = nvbios_rd08(bios, data + 23); | |
343 | info->max_p_usable = info->max_p = nvbios_rd08(bios, data + 25); | |
344 | info->bias_p = nvbios_rd08(bios, data + 27); | |
345 | info->refclk = nvbios_rd32(bios, data + 28); | |
70790f4f BS |
346 | break; |
347 | case 0x40: | |
7f5f518f BS |
348 | info->refclk = nvbios_rd16(bios, data + 9) * 1000; |
349 | data = nvbios_rd16(bios, data + 1); | |
350 | ||
351 | info->vco1.min_freq = nvbios_rd16(bios, data + 0) * 1000; | |
352 | info->vco1.max_freq = nvbios_rd16(bios, data + 2) * 1000; | |
353 | info->vco1.min_inputfreq = nvbios_rd16(bios, data + 4) * 1000; | |
354 | info->vco1.max_inputfreq = nvbios_rd16(bios, data + 6) * 1000; | |
355 | info->vco1.min_m = nvbios_rd08(bios, data + 8); | |
356 | info->vco1.max_m = nvbios_rd08(bios, data + 9); | |
357 | info->vco1.min_n = nvbios_rd08(bios, data + 10); | |
358 | info->vco1.max_n = nvbios_rd08(bios, data + 11); | |
359 | info->min_p = nvbios_rd08(bios, data + 12); | |
360 | info->max_p = nvbios_rd08(bios, data + 13); | |
70790f4f BS |
361 | break; |
362 | default: | |
60b29d20 | 363 | nvkm_error(subdev, "unknown pll limits version 0x%02x\n", ver); |
70790f4f BS |
364 | return -EINVAL; |
365 | } | |
366 | ||
367 | if (!info->refclk) { | |
d8f266a3 | 368 | info->refclk = device->crystal; |
70790f4f | 369 | if (bios->version.chip == 0x51) { |
d8f266a3 | 370 | u32 sel_clk = nvkm_rd32(device, 0x680524); |
70790f4f BS |
371 | if ((info->reg == 0x680508 && sel_clk & 0x20) || |
372 | (info->reg == 0x680520 && sel_clk & 0x80)) { | |
a8dae9fe | 373 | if (nvkm_rdvgac(device, 0, 0x27) < 0xa3) |
70790f4f BS |
374 | info->refclk = 200000; |
375 | else | |
376 | info->refclk = 25000; | |
377 | } | |
378 | } | |
379 | } | |
380 | ||
381 | /* | |
382 | * By now any valid limit table ought to have set a max frequency for | |
383 | * vco1, so if it's zero it's either a pre limit table bios, or one | |
384 | * with an empty limit table (seen on nv18) | |
385 | */ | |
386 | if (!info->vco1.max_freq) { | |
7f5f518f BS |
387 | info->vco1.max_freq = nvbios_rd32(bios, bios->bmp_offset + 67); |
388 | info->vco1.min_freq = nvbios_rd32(bios, bios->bmp_offset + 71); | |
70790f4f BS |
389 | if (bmp_version(bios) < 0x0506) { |
390 | info->vco1.max_freq = 256000; | |
391 | info->vco1.min_freq = 128000; | |
392 | } | |
393 | ||
394 | info->vco1.min_inputfreq = 0; | |
395 | info->vco1.max_inputfreq = INT_MAX; | |
396 | info->vco1.min_n = 0x1; | |
397 | info->vco1.max_n = 0xff; | |
398 | info->vco1.min_m = 0x1; | |
399 | ||
d8f266a3 | 400 | if (device->crystal == 13500) { |
70790f4f BS |
401 | /* nv05 does this, nv11 doesn't, nv10 unknown */ |
402 | if (bios->version.chip < 0x11) | |
403 | info->vco1.min_m = 0x7; | |
404 | info->vco1.max_m = 0xd; | |
405 | } else { | |
406 | if (bios->version.chip < 0x11) | |
407 | info->vco1.min_m = 0x8; | |
408 | info->vco1.max_m = 0xe; | |
409 | } | |
410 | ||
411 | if (bios->version.chip < 0x17 || | |
412 | bios->version.chip == 0x1a || | |
413 | bios->version.chip == 0x20) | |
414 | info->max_p = 4; | |
415 | else | |
416 | info->max_p = 5; | |
417 | info->max_p_usable = info->max_p; | |
418 | } | |
419 | ||
420 | return 0; | |
421 | } |