| 1 | /* $NetBSD: nouveau_subdev_bios_pll.c,v 1.2 2015/02/25 17:29:43 riastradh Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright 2005-2006 Erik Waling |
| 5 | * Copyright 2006 Stephane Marchesin |
| 6 | * Copyright 2007-2009 Stuart Bennett |
| 7 | * |
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 9 | * copy of this software and associated documentation files (the "Software"), |
| 10 | * to deal in the Software without restriction, including without limitation |
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 12 | * and/or sell copies of the Software, and to permit persons to whom the |
| 13 | * Software is furnished to do so, subject to the following conditions: |
| 14 | * |
| 15 | * The above copyright notice and this permission notice shall be included in |
| 16 | * all copies or substantial portions of the Software. |
| 17 | * |
| 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 21 | * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 22 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF |
| 23 | * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 24 | * SOFTWARE. |
| 25 | */ |
| 26 | |
| 27 | #include <sys/cdefs.h> |
| 28 | __KERNEL_RCSID(0, "$NetBSD: nouveau_subdev_bios_pll.c,v 1.2 2015/02/25 17:29:43 riastradh Exp $" ); |
| 29 | |
| 30 | #include <subdev/vga.h> |
| 31 | #include <subdev/bios.h> |
| 32 | #include <subdev/bios/bit.h> |
| 33 | #include <subdev/bios/bmp.h> |
| 34 | #include <subdev/bios/pll.h> |
| 35 | |
| 36 | struct pll_mapping { |
| 37 | u8 type; |
| 38 | u32 reg; |
| 39 | }; |
| 40 | |
| 41 | static struct pll_mapping |
| 42 | nv04_pll_mapping[] = { |
| 43 | { PLL_CORE , 0x680500 }, |
| 44 | { PLL_MEMORY, 0x680504 }, |
| 45 | { PLL_VPLL0 , 0x680508 }, |
| 46 | { PLL_VPLL1 , 0x680520 }, |
| 47 | { } |
| 48 | }; |
| 49 | |
| 50 | static struct pll_mapping |
| 51 | nv40_pll_mapping[] = { |
| 52 | { PLL_CORE , 0x004000 }, |
| 53 | { PLL_MEMORY, 0x004020 }, |
| 54 | { PLL_VPLL0 , 0x680508 }, |
| 55 | { PLL_VPLL1 , 0x680520 }, |
| 56 | { } |
| 57 | }; |
| 58 | |
| 59 | static struct pll_mapping |
| 60 | nv50_pll_mapping[] = { |
| 61 | { PLL_CORE , 0x004028 }, |
| 62 | { PLL_SHADER, 0x004020 }, |
| 63 | { PLL_UNK03 , 0x004000 }, |
| 64 | { PLL_MEMORY, 0x004008 }, |
| 65 | { PLL_UNK40 , 0x00e810 }, |
| 66 | { PLL_UNK41 , 0x00e818 }, |
| 67 | { PLL_UNK42 , 0x00e824 }, |
| 68 | { PLL_VPLL0 , 0x614100 }, |
| 69 | { PLL_VPLL1 , 0x614900 }, |
| 70 | { } |
| 71 | }; |
| 72 | |
| 73 | static struct pll_mapping |
| 74 | nv84_pll_mapping[] = { |
| 75 | { PLL_CORE , 0x004028 }, |
| 76 | { PLL_SHADER, 0x004020 }, |
| 77 | { PLL_MEMORY, 0x004008 }, |
| 78 | { PLL_VDEC , 0x004030 }, |
| 79 | { PLL_UNK41 , 0x00e818 }, |
| 80 | { PLL_VPLL0 , 0x614100 }, |
| 81 | { PLL_VPLL1 , 0x614900 }, |
| 82 | { } |
| 83 | }; |
| 84 | |
| 85 | static u16 |
| 86 | pll_limits_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) |
| 87 | { |
| 88 | struct bit_entry bit_C; |
| 89 | |
| 90 | if (!bit_entry(bios, 'C', &bit_C) && bit_C.length >= 10) { |
| 91 | u16 data = nv_ro16(bios, bit_C.offset + 8); |
| 92 | if (data) { |
| 93 | *ver = nv_ro08(bios, data + 0); |
| 94 | *hdr = nv_ro08(bios, data + 1); |
| 95 | *len = nv_ro08(bios, data + 2); |
| 96 | *cnt = nv_ro08(bios, data + 3); |
| 97 | return data; |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | if (bmp_version(bios) >= 0x0524) { |
| 102 | u16 data = nv_ro16(bios, bios->bmp_offset + 142); |
| 103 | if (data) { |
| 104 | *ver = nv_ro08(bios, data + 0); |
| 105 | *hdr = 1; |
| 106 | *cnt = 1; |
| 107 | *len = 0x18; |
| 108 | return data; |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | *ver = 0x00; |
| 113 | return 0x0000; |
| 114 | } |
| 115 | |
| 116 | static struct pll_mapping * |
| 117 | pll_map(struct nouveau_bios *bios) |
| 118 | { |
| 119 | switch (nv_device(bios)->card_type) { |
| 120 | case NV_04: |
| 121 | case NV_10: |
| 122 | case NV_11: |
| 123 | case NV_20: |
| 124 | case NV_30: |
| 125 | return nv04_pll_mapping; |
| 126 | break; |
| 127 | case NV_40: |
| 128 | return nv40_pll_mapping; |
| 129 | case NV_50: |
| 130 | if (nv_device(bios)->chipset == 0x50) |
| 131 | return nv50_pll_mapping; |
| 132 | else |
| 133 | if (nv_device(bios)->chipset < 0xa3 || |
| 134 | nv_device(bios)->chipset == 0xaa || |
| 135 | nv_device(bios)->chipset == 0xac) |
| 136 | return nv84_pll_mapping; |
| 137 | default: |
| 138 | return NULL; |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | static u16 |
| 143 | pll_map_reg(struct nouveau_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) |
| 144 | { |
| 145 | struct pll_mapping *map; |
| 146 | u8 hdr, cnt; |
| 147 | u16 data; |
| 148 | |
| 149 | data = pll_limits_table(bios, ver, &hdr, &cnt, len); |
| 150 | if (data && *ver >= 0x30) { |
| 151 | data += hdr; |
| 152 | while (cnt--) { |
| 153 | if (nv_ro32(bios, data + 3) == reg) { |
| 154 | *type = nv_ro08(bios, data + 0); |
| 155 | return data; |
| 156 | } |
| 157 | data += *len; |
| 158 | } |
| 159 | return 0x0000; |
| 160 | } |
| 161 | |
| 162 | map = pll_map(bios); |
| 163 | while (map->reg) { |
| 164 | if (map->reg == reg && *ver >= 0x20) { |
| 165 | u16 addr = (data += hdr); |
| 166 | *type = map->type; |
| 167 | while (cnt--) { |
| 168 | if (nv_ro32(bios, data) == map->reg) |
| 169 | return data; |
| 170 | data += *len; |
| 171 | } |
| 172 | return addr; |
| 173 | } else |
| 174 | if (map->reg == reg) { |
| 175 | *type = map->type; |
| 176 | return data + 1; |
| 177 | } |
| 178 | map++; |
| 179 | } |
| 180 | |
| 181 | return 0x0000; |
| 182 | } |
| 183 | |
| 184 | static u16 |
| 185 | pll_map_type(struct nouveau_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) |
| 186 | { |
| 187 | struct pll_mapping *map; |
| 188 | u8 hdr, cnt; |
| 189 | u16 data; |
| 190 | |
| 191 | data = pll_limits_table(bios, ver, &hdr, &cnt, len); |
| 192 | if (data && *ver >= 0x30) { |
| 193 | data += hdr; |
| 194 | while (cnt--) { |
| 195 | if (nv_ro08(bios, data + 0) == type) { |
| 196 | *reg = nv_ro32(bios, data + 3); |
| 197 | return data; |
| 198 | } |
| 199 | data += *len; |
| 200 | } |
| 201 | return 0x0000; |
| 202 | } |
| 203 | |
| 204 | map = pll_map(bios); |
| 205 | while (map->reg) { |
| 206 | if (map->type == type && *ver >= 0x20) { |
| 207 | u16 addr = (data += hdr); |
| 208 | *reg = map->reg; |
| 209 | while (cnt--) { |
| 210 | if (nv_ro32(bios, data) == map->reg) |
| 211 | return data; |
| 212 | data += *len; |
| 213 | } |
| 214 | return addr; |
| 215 | } else |
| 216 | if (map->type == type) { |
| 217 | *reg = map->reg; |
| 218 | return data + 1; |
| 219 | } |
| 220 | map++; |
| 221 | } |
| 222 | |
| 223 | return 0x0000; |
| 224 | } |
| 225 | |
| 226 | int |
| 227 | nvbios_pll_parse(struct nouveau_bios *bios, u32 type, struct nvbios_pll *info) |
| 228 | { |
| 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: |
| 252 | info->vco1.min_freq = nv_ro32(bios, data + 0); |
| 253 | info->vco1.max_freq = nv_ro32(bios, data + 4); |
| 254 | info->vco2.min_freq = nv_ro32(bios, data + 8); |
| 255 | info->vco2.max_freq = nv_ro32(bios, data + 12); |
| 256 | info->vco1.min_inputfreq = nv_ro32(bios, data + 16); |
| 257 | info->vco2.min_inputfreq = nv_ro32(bios, data + 20); |
| 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: |
| 298 | info->vco1.min_freq = nv_ro16(bios, data + 4) * 1000; |
| 299 | info->vco1.max_freq = nv_ro16(bios, data + 6) * 1000; |
| 300 | info->vco2.min_freq = nv_ro16(bios, data + 8) * 1000; |
| 301 | info->vco2.max_freq = nv_ro16(bios, data + 10) * 1000; |
| 302 | info->vco1.min_inputfreq = nv_ro16(bios, data + 12) * 1000; |
| 303 | info->vco2.min_inputfreq = nv_ro16(bios, data + 14) * 1000; |
| 304 | info->vco1.max_inputfreq = nv_ro16(bios, data + 16) * 1000; |
| 305 | info->vco2.max_inputfreq = nv_ro16(bios, data + 18) * 1000; |
| 306 | info->vco1.min_n = nv_ro08(bios, data + 20); |
| 307 | info->vco1.max_n = nv_ro08(bios, data + 21); |
| 308 | info->vco1.min_m = nv_ro08(bios, data + 22); |
| 309 | info->vco1.max_m = nv_ro08(bios, data + 23); |
| 310 | info->vco2.min_n = nv_ro08(bios, data + 24); |
| 311 | info->vco2.max_n = nv_ro08(bios, data + 25); |
| 312 | info->vco2.min_m = nv_ro08(bios, data + 26); |
| 313 | info->vco2.max_m = nv_ro08(bios, data + 27); |
| 314 | |
| 315 | info->max_p = nv_ro08(bios, data + 29); |
| 316 | info->max_p_usable = info->max_p; |
| 317 | if (bios->version.chip < 0x60) |
| 318 | info->max_p_usable = 0x6; |
| 319 | info->bias_p = nv_ro08(bios, data + 30); |
| 320 | |
| 321 | if (len > 0x22) |
| 322 | info->refclk = nv_ro32(bios, data + 31); |
| 323 | break; |
| 324 | case 0x30: |
| 325 | data = nv_ro16(bios, data + 1); |
| 326 | |
| 327 | info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000; |
| 328 | info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000; |
| 329 | info->vco2.min_freq = nv_ro16(bios, data + 4) * 1000; |
| 330 | info->vco2.max_freq = nv_ro16(bios, data + 6) * 1000; |
| 331 | info->vco1.min_inputfreq = nv_ro16(bios, data + 8) * 1000; |
| 332 | info->vco2.min_inputfreq = nv_ro16(bios, data + 10) * 1000; |
| 333 | info->vco1.max_inputfreq = nv_ro16(bios, data + 12) * 1000; |
| 334 | info->vco2.max_inputfreq = nv_ro16(bios, data + 14) * 1000; |
| 335 | info->vco1.min_n = nv_ro08(bios, data + 16); |
| 336 | info->vco1.max_n = nv_ro08(bios, data + 17); |
| 337 | info->vco1.min_m = nv_ro08(bios, data + 18); |
| 338 | info->vco1.max_m = nv_ro08(bios, data + 19); |
| 339 | info->vco2.min_n = nv_ro08(bios, data + 20); |
| 340 | info->vco2.max_n = nv_ro08(bios, data + 21); |
| 341 | info->vco2.min_m = nv_ro08(bios, data + 22); |
| 342 | info->vco2.max_m = nv_ro08(bios, data + 23); |
| 343 | info->max_p_usable = info->max_p = nv_ro08(bios, data + 25); |
| 344 | info->bias_p = nv_ro08(bios, data + 27); |
| 345 | info->refclk = nv_ro32(bios, data + 28); |
| 346 | break; |
| 347 | case 0x40: |
| 348 | info->refclk = nv_ro16(bios, data + 9) * 1000; |
| 349 | data = nv_ro16(bios, data + 1); |
| 350 | |
| 351 | info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000; |
| 352 | info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000; |
| 353 | info->vco1.min_inputfreq = nv_ro16(bios, data + 4) * 1000; |
| 354 | info->vco1.max_inputfreq = nv_ro16(bios, data + 6) * 1000; |
| 355 | info->vco1.min_m = nv_ro08(bios, data + 8); |
| 356 | info->vco1.max_m = nv_ro08(bios, data + 9); |
| 357 | info->vco1.min_n = nv_ro08(bios, data + 10); |
| 358 | info->vco1.max_n = nv_ro08(bios, data + 11); |
| 359 | info->min_p = nv_ro08(bios, data + 12); |
| 360 | info->max_p = nv_ro08(bios, data + 13); |
| 361 | break; |
| 362 | default: |
| 363 | nv_error(bios, "unknown pll limits version 0x%02x\n" , ver); |
| 364 | return -EINVAL; |
| 365 | } |
| 366 | |
| 367 | if (!info->refclk) { |
| 368 | info->refclk = nv_device(bios)->crystal; |
| 369 | if (bios->version.chip == 0x51) { |
| 370 | u32 sel_clk = nv_rd32(bios, 0x680524); |
| 371 | if ((info->reg == 0x680508 && sel_clk & 0x20) || |
| 372 | (info->reg == 0x680520 && sel_clk & 0x80)) { |
| 373 | if (nv_rdvgac(bios, 0, 0x27) < 0xa3) |
| 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) { |
| 387 | info->vco1.max_freq = nv_ro32(bios, bios->bmp_offset + 67); |
| 388 | info->vco1.min_freq = nv_ro32(bios, bios->bmp_offset + 71); |
| 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 | |
| 400 | if (nv_device(bios)->crystal == 13500) { |
| 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 | } |
| 422 | |