1 /* 2 * Copyright 2012 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 */ 24 #include "nv50.h" 25 #include "rootnv50.h" 26 27 #include <core/client.h> 28 #include <core/enum.h> 29 #include <core/gpuobj.h> 30 #include <subdev/bios.h> 31 #include <subdev/bios/disp.h> 32 #include <subdev/bios/init.h> 33 #include <subdev/bios/pll.h> 34 #include <subdev/devinit.h> 35 36 static void 37 nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head) 38 { 39 struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); 40 struct nvkm_device *device = disp->engine.subdev.device; 41 nvkm_mask(device, 0x61002c, (4 << head), 0); 42 } 43 44 static void 45 nv50_disp_vblank_init(struct nvkm_event *event, int type, int head) 46 { 47 struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); 48 struct nvkm_device *device = disp->engine.subdev.device; 49 nvkm_mask(device, 0x61002c, (4 << head), (4 << head)); 50 } 51 52 const struct nvkm_event_func 53 nv50_disp_vblank_func = { 54 .ctor = nvkm_disp_vblank_ctor, 55 .init = nv50_disp_vblank_init, 56 .fini = nv50_disp_vblank_fini, 57 }; 58 59 static const struct nvkm_enum 60 nv50_disp_intr_error_type[] = { 61 { 3, "ILLEGAL_MTHD" }, 62 { 4, "INVALID_VALUE" }, 63 { 5, "INVALID_STATE" }, 64 { 7, "INVALID_HANDLE" }, 65 {} 66 }; 67 68 static const struct nvkm_enum 69 nv50_disp_intr_error_code[] = { 70 { 0x00, "" }, 71 {} 72 }; 73 74 static void 75 nv50_disp_intr_error(struct nv50_disp *disp, int chid) 76 { 77 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 78 struct nvkm_device *device = subdev->device; 79 u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08)); 80 u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08)); 81 u32 code = (addr & 0x00ff0000) >> 16; 82 u32 type = (addr & 0x00007000) >> 12; 83 u32 mthd = (addr & 0x00000ffc); 84 const struct nvkm_enum *ec, *et; 85 86 et = nvkm_enum_find(nv50_disp_intr_error_type, type); 87 ec = nvkm_enum_find(nv50_disp_intr_error_code, code); 88 89 nvkm_error(subdev, 90 "ERROR %d [%s] %02x [%s] chid %d mthd %04x data %08x\n", 91 type, et ? et->name : "", code, ec ? ec->name : "", 92 chid, mthd, data); 93 94 if (chid < ARRAY_SIZE(disp->chan)) { 95 switch (mthd) { 96 case 0x0080: 97 nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR); 98 break; 99 default: 100 break; 101 } 102 } 103 104 nvkm_wr32(device, 0x610020, 0x00010000 << chid); 105 nvkm_wr32(device, 0x610080 + (chid * 0x08), 0x90000000); 106 } 107 108 static struct nvkm_output * 109 exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, 110 u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, 111 struct nvbios_outp *info) 112 { 113 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 114 struct nvkm_bios *bios = subdev->device->bios; 115 struct nvkm_output *outp; 116 u16 mask, type; 117 118 if (or < 4) { 119 type = DCB_OUTPUT_ANALOG; 120 mask = 0; 121 } else 122 if (or < 8) { 123 switch (ctrl & 0x00000f00) { 124 case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; 125 case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; 126 case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break; 127 case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break; 128 case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; 129 case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; 130 default: 131 nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); 132 return NULL; 133 } 134 or -= 4; 135 } else { 136 or = or - 8; 137 type = 0x0010; 138 mask = 0; 139 switch (ctrl & 0x00000f00) { 140 case 0x00000000: type |= disp->pior.type[or]; break; 141 default: 142 nvkm_error(subdev, "unknown PIOR mc %08x\n", ctrl); 143 return NULL; 144 } 145 } 146 147 mask = 0x00c0 & (mask << 6); 148 mask |= 0x0001 << or; 149 mask |= 0x0100 << head; 150 151 list_for_each_entry(outp, &disp->base.outp, head) { 152 if ((outp->info.hasht & 0xff) == type && 153 (outp->info.hashm & mask) == mask) { 154 *data = nvbios_outp_match(bios, outp->info.hasht, 155 outp->info.hashm, 156 ver, hdr, cnt, len, info); 157 if (!*data) 158 return NULL; 159 return outp; 160 } 161 } 162 163 return NULL; 164 } 165 166 static struct nvkm_output * 167 exec_script(struct nv50_disp *disp, int head, int id) 168 { 169 struct nvkm_device *device = disp->base.engine.subdev.device; 170 struct nvkm_bios *bios = device->bios; 171 struct nvkm_output *outp; 172 struct nvbios_outp info; 173 u8 ver, hdr, cnt, len; 174 u32 data, ctrl = 0; 175 u32 reg; 176 int i; 177 178 /* DAC */ 179 for (i = 0; !(ctrl & (1 << head)) && i < disp->dac.nr; i++) 180 ctrl = nvkm_rd32(device, 0x610b5c + (i * 8)); 181 182 /* SOR */ 183 if (!(ctrl & (1 << head))) { 184 if (nv_device(disp)->chipset < 0x90 || 185 nv_device(disp)->chipset == 0x92 || 186 nv_device(disp)->chipset == 0xa0) { 187 reg = 0x610b74; 188 } else { 189 reg = 0x610798; 190 } 191 for (i = 0; !(ctrl & (1 << head)) && i < disp->sor.nr; i++) 192 ctrl = nvkm_rd32(device, reg + (i * 8)); 193 i += 4; 194 } 195 196 /* PIOR */ 197 if (!(ctrl & (1 << head))) { 198 for (i = 0; !(ctrl & (1 << head)) && i < disp->pior.nr; i++) 199 ctrl = nvkm_rd32(device, 0x610b84 + (i * 8)); 200 i += 8; 201 } 202 203 if (!(ctrl & (1 << head))) 204 return NULL; 205 i--; 206 207 outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info); 208 if (outp) { 209 struct nvbios_init init = { 210 .subdev = nv_subdev(disp), 211 .bios = bios, 212 .offset = info.script[id], 213 .outp = &outp->info, 214 .crtc = head, 215 .execute = 1, 216 }; 217 218 nvbios_exec(&init); 219 } 220 221 return outp; 222 } 223 224 static struct nvkm_output * 225 exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) 226 { 227 struct nvkm_device *device = disp->base.engine.subdev.device; 228 struct nvkm_bios *bios = device->bios; 229 struct nvkm_output *outp; 230 struct nvbios_outp info1; 231 struct nvbios_ocfg info2; 232 u8 ver, hdr, cnt, len; 233 u32 data, ctrl = 0; 234 u32 reg; 235 int i; 236 237 /* DAC */ 238 for (i = 0; !(ctrl & (1 << head)) && i < disp->dac.nr; i++) 239 ctrl = nvkm_rd32(device, 0x610b58 + (i * 8)); 240 241 /* SOR */ 242 if (!(ctrl & (1 << head))) { 243 if (nv_device(disp)->chipset < 0x90 || 244 nv_device(disp)->chipset == 0x92 || 245 nv_device(disp)->chipset == 0xa0) { 246 reg = 0x610b70; 247 } else { 248 reg = 0x610794; 249 } 250 for (i = 0; !(ctrl & (1 << head)) && i < disp->sor.nr; i++) 251 ctrl = nvkm_rd32(device, reg + (i * 8)); 252 i += 4; 253 } 254 255 /* PIOR */ 256 if (!(ctrl & (1 << head))) { 257 for (i = 0; !(ctrl & (1 << head)) && i < disp->pior.nr; i++) 258 ctrl = nvkm_rd32(device, 0x610b80 + (i * 8)); 259 i += 8; 260 } 261 262 if (!(ctrl & (1 << head))) 263 return NULL; 264 i--; 265 266 outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); 267 if (!outp) 268 return NULL; 269 270 if (outp->info.location == 0) { 271 switch (outp->info.type) { 272 case DCB_OUTPUT_TMDS: 273 *conf = (ctrl & 0x00000f00) >> 8; 274 if (pclk >= 165000) 275 *conf |= 0x0100; 276 break; 277 case DCB_OUTPUT_LVDS: 278 *conf = disp->sor.lvdsconf; 279 break; 280 case DCB_OUTPUT_DP: 281 *conf = (ctrl & 0x00000f00) >> 8; 282 break; 283 case DCB_OUTPUT_ANALOG: 284 default: 285 *conf = 0x00ff; 286 break; 287 } 288 } else { 289 *conf = (ctrl & 0x00000f00) >> 8; 290 pclk = pclk / 2; 291 } 292 293 data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); 294 if (data && id < 0xff) { 295 data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); 296 if (data) { 297 struct nvbios_init init = { 298 .subdev = nv_subdev(disp), 299 .bios = bios, 300 .offset = data, 301 .outp = &outp->info, 302 .crtc = head, 303 .execute = 1, 304 }; 305 306 nvbios_exec(&init); 307 } 308 } 309 310 return outp; 311 } 312 313 static void 314 nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head) 315 { 316 exec_script(disp, head, 1); 317 } 318 319 static void 320 nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) 321 { 322 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 323 struct nvkm_output *outp = exec_script(disp, head, 2); 324 325 /* the binary driver does this outside of the supervisor handling 326 * (after the third supervisor from a detach). we (currently?) 327 * allow both detach/attach to happen in the same set of 328 * supervisor interrupts, so it would make sense to execute this 329 * (full power down?) script after all the detach phases of the 330 * supervisor handling. like with training if needed from the 331 * second supervisor, nvidia doesn't do this, so who knows if it's 332 * entirely safe, but it does appear to work.. 333 * 334 * without this script being run, on some configurations i've 335 * seen, switching from DP to TMDS on a DP connector may result 336 * in a blank screen (SOR_PWR off/on can restore it) 337 */ 338 if (outp && outp->info.type == DCB_OUTPUT_DP) { 339 struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); 340 struct nvbios_init init = { 341 .subdev = subdev, 342 .bios = subdev->device->bios, 343 .outp = &outp->info, 344 .crtc = head, 345 .offset = outpdp->info.script[4], 346 .execute = 1, 347 }; 348 349 nvbios_exec(&init); 350 atomic_set(&outpdp->lt.done, 0); 351 } 352 } 353 354 static void 355 nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) 356 { 357 struct nvkm_device *device = disp->base.engine.subdev.device; 358 struct nvkm_devinit *devinit = device->devinit; 359 u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; 360 if (pclk) 361 nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); 362 } 363 364 static void 365 nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, 366 struct dcb_output *outp, u32 pclk) 367 { 368 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 369 struct nvkm_device *device = subdev->device; 370 const int link = !(outp->sorconf.link & 1); 371 const int or = ffs(outp->or) - 1; 372 const u32 soff = ( or * 0x800); 373 const u32 loff = (link * 0x080) + soff; 374 const u32 ctrl = nvkm_rd32(device, 0x610794 + (or * 8)); 375 const u32 symbol = 100000; 376 const s32 vactive = nvkm_rd32(device, 0x610af8 + (head * 0x540)) & 0xffff; 377 const s32 vblanke = nvkm_rd32(device, 0x610ae8 + (head * 0x540)) & 0xffff; 378 const s32 vblanks = nvkm_rd32(device, 0x610af0 + (head * 0x540)) & 0xffff; 379 u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff); 380 u32 clksor = nvkm_rd32(device, 0x614300 + soff); 381 int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; 382 int TU, VTUi, VTUf, VTUa; 383 u64 link_data_rate, link_ratio, unk; 384 u32 best_diff = 64 * symbol; 385 u32 link_nr, link_bw, bits; 386 u64 value; 387 388 link_bw = (clksor & 0x000c0000) ? 270000 : 162000; 389 link_nr = hweight32(dpctrl & 0x000f0000); 390 391 /* symbols/hblank - algorithm taken from comments in tegra driver */ 392 value = vblanke + vactive - vblanks - 7; 393 value = value * link_bw; 394 do_div(value, pclk); 395 value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); 396 nvkm_mask(device, 0x61c1e8 + soff, 0x0000ffff, value); 397 398 /* symbols/vblank - algorithm taken from comments in tegra driver */ 399 value = vblanks - vblanke - 25; 400 value = value * link_bw; 401 do_div(value, pclk); 402 value = value - ((36 / link_nr) + 3) - 1; 403 nvkm_mask(device, 0x61c1ec + soff, 0x00ffffff, value); 404 405 /* watermark / activesym */ 406 if ((ctrl & 0xf0000) == 0x60000) bits = 30; 407 else if ((ctrl & 0xf0000) == 0x50000) bits = 24; 408 else bits = 18; 409 410 link_data_rate = (pclk * bits / 8) / link_nr; 411 412 /* calculate ratio of packed data rate to link symbol rate */ 413 link_ratio = link_data_rate * symbol; 414 do_div(link_ratio, link_bw); 415 416 for (TU = 64; TU >= 32; TU--) { 417 /* calculate average number of valid symbols in each TU */ 418 u32 tu_valid = link_ratio * TU; 419 u32 calc, diff; 420 421 /* find a hw representation for the fraction.. */ 422 VTUi = tu_valid / symbol; 423 calc = VTUi * symbol; 424 diff = tu_valid - calc; 425 if (diff) { 426 if (diff >= (symbol / 2)) { 427 VTUf = symbol / (symbol - diff); 428 if (symbol - (VTUf * diff)) 429 VTUf++; 430 431 if (VTUf <= 15) { 432 VTUa = 1; 433 calc += symbol - (symbol / VTUf); 434 } else { 435 VTUa = 0; 436 VTUf = 1; 437 calc += symbol; 438 } 439 } else { 440 VTUa = 0; 441 VTUf = min((int)(symbol / diff), 15); 442 calc += symbol / VTUf; 443 } 444 445 diff = calc - tu_valid; 446 } else { 447 /* no remainder, but the hw doesn't like the fractional 448 * part to be zero. decrement the integer part and 449 * have the fraction add a whole symbol back 450 */ 451 VTUa = 0; 452 VTUf = 1; 453 VTUi--; 454 } 455 456 if (diff < best_diff) { 457 best_diff = diff; 458 bestTU = TU; 459 bestVTUa = VTUa; 460 bestVTUf = VTUf; 461 bestVTUi = VTUi; 462 if (diff == 0) 463 break; 464 } 465 } 466 467 if (!bestTU) { 468 nvkm_error(subdev, "unable to find suitable dp config\n"); 469 return; 470 } 471 472 /* XXX close to vbios numbers, but not right */ 473 unk = (symbol - link_ratio) * bestTU; 474 unk *= link_ratio; 475 do_div(unk, symbol); 476 do_div(unk, symbol); 477 unk += 6; 478 479 nvkm_mask(device, 0x61c10c + loff, 0x000001fc, bestTU << 2); 480 nvkm_mask(device, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 | 481 bestVTUf << 16 | 482 bestVTUi << 8 | unk); 483 } 484 485 static void 486 nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) 487 { 488 struct nvkm_device *device = disp->base.engine.subdev.device; 489 struct nvkm_output *outp; 490 u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; 491 u32 hval, hreg = 0x614200 + (head * 0x800); 492 u32 oval, oreg; 493 u32 mask, conf; 494 495 outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); 496 if (!outp) 497 return; 498 499 /* we allow both encoder attach and detach operations to occur 500 * within a single supervisor (ie. modeset) sequence. the 501 * encoder detach scripts quite often switch off power to the 502 * lanes, which requires the link to be re-trained. 503 * 504 * this is not generally an issue as the sink "must" (heh) 505 * signal an irq when it's lost sync so the driver can 506 * re-train. 507 * 508 * however, on some boards, if one does not configure at least 509 * the gpu side of the link *before* attaching, then various 510 * things can go horribly wrong (PDISP disappearing from mmio, 511 * third supervisor never happens, etc). 512 * 513 * the solution is simply to retrain here, if necessary. last 514 * i checked, the binary driver userspace does not appear to 515 * trigger this situation (it forces an UPDATE between steps). 516 */ 517 if (outp->info.type == DCB_OUTPUT_DP) { 518 u32 soff = (ffs(outp->info.or) - 1) * 0x08; 519 u32 ctrl, datarate; 520 521 if (outp->info.location == 0) { 522 ctrl = nvkm_rd32(device, 0x610794 + soff); 523 soff = 1; 524 } else { 525 ctrl = nvkm_rd32(device, 0x610b80 + soff); 526 soff = 2; 527 } 528 529 switch ((ctrl & 0x000f0000) >> 16) { 530 case 6: datarate = pclk * 30; break; 531 case 5: datarate = pclk * 24; break; 532 case 2: 533 default: 534 datarate = pclk * 18; 535 break; 536 } 537 538 if (nvkm_output_dp_train(outp, datarate / soff, true)) 539 OUTP_ERR(outp, "link not trained before attach"); 540 } 541 542 exec_clkcmp(disp, head, 0, pclk, &conf); 543 544 if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) { 545 oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800; 546 oval = 0x00000000; 547 hval = 0x00000000; 548 mask = 0xffffffff; 549 } else 550 if (!outp->info.location) { 551 if (outp->info.type == DCB_OUTPUT_DP) 552 nv50_disp_intr_unk20_2_dp(disp, head, &outp->info, pclk); 553 oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800; 554 oval = (conf & 0x0100) ? 0x00000101 : 0x00000000; 555 hval = 0x00000000; 556 mask = 0x00000707; 557 } else { 558 oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800; 559 oval = 0x00000001; 560 hval = 0x00000001; 561 mask = 0x00000707; 562 } 563 564 nvkm_mask(device, hreg, 0x0000000f, hval); 565 nvkm_mask(device, oreg, mask, oval); 566 } 567 568 /* If programming a TMDS output on a SOR that can also be configured for 569 * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off. 570 * 571 * It looks like the VBIOS TMDS scripts make an attempt at this, however, 572 * the VBIOS scripts on at least one board I have only switch it off on 573 * link 0, causing a blank display if the output has previously been 574 * programmed for DisplayPort. 575 */ 576 static void 577 nv50_disp_intr_unk40_0_tmds(struct nv50_disp *disp, 578 struct dcb_output *outp) 579 { 580 struct nvkm_device *device = disp->base.engine.subdev.device; 581 struct nvkm_bios *bios = device->bios; 582 const int link = !(outp->sorconf.link & 1); 583 const int or = ffs(outp->or) - 1; 584 const u32 loff = (or * 0x800) + (link * 0x80); 585 const u16 mask = (outp->sorconf.link << 6) | outp->or; 586 struct dcb_output match; 587 u8 ver, hdr; 588 589 if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) 590 nvkm_mask(device, 0x61c10c + loff, 0x00000001, 0x00000000); 591 } 592 593 static void 594 nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) 595 { 596 struct nvkm_device *device = disp->base.engine.subdev.device; 597 struct nvkm_output *outp; 598 u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; 599 u32 conf; 600 601 outp = exec_clkcmp(disp, head, 1, pclk, &conf); 602 if (!outp) 603 return; 604 605 if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS) 606 nv50_disp_intr_unk40_0_tmds(disp, &outp->info); 607 } 608 609 void 610 nv50_disp_intr_supervisor(struct work_struct *work) 611 { 612 struct nv50_disp *disp = 613 container_of(work, struct nv50_disp, supervisor); 614 struct nvkm_subdev *subdev = &disp->base.engine.subdev; 615 struct nvkm_device *device = subdev->device; 616 u32 super = nvkm_rd32(device, 0x610030); 617 int head; 618 619 nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super); 620 621 if (disp->super & 0x00000010) { 622 nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); 623 for (head = 0; head < disp->head.nr; head++) { 624 if (!(super & (0x00000020 << head))) 625 continue; 626 if (!(super & (0x00000080 << head))) 627 continue; 628 nv50_disp_intr_unk10_0(disp, head); 629 } 630 } else 631 if (disp->super & 0x00000020) { 632 for (head = 0; head < disp->head.nr; head++) { 633 if (!(super & (0x00000080 << head))) 634 continue; 635 nv50_disp_intr_unk20_0(disp, head); 636 } 637 for (head = 0; head < disp->head.nr; head++) { 638 if (!(super & (0x00000200 << head))) 639 continue; 640 nv50_disp_intr_unk20_1(disp, head); 641 } 642 for (head = 0; head < disp->head.nr; head++) { 643 if (!(super & (0x00000080 << head))) 644 continue; 645 nv50_disp_intr_unk20_2(disp, head); 646 } 647 } else 648 if (disp->super & 0x00000040) { 649 for (head = 0; head < disp->head.nr; head++) { 650 if (!(super & (0x00000080 << head))) 651 continue; 652 nv50_disp_intr_unk40_0(disp, head); 653 } 654 } 655 656 nvkm_wr32(device, 0x610030, 0x80000000); 657 } 658 659 void 660 nv50_disp_intr(struct nvkm_subdev *subdev) 661 { 662 struct nv50_disp *disp = (void *)subdev; 663 struct nvkm_device *device = disp->base.engine.subdev.device; 664 u32 intr0 = nvkm_rd32(device, 0x610020); 665 u32 intr1 = nvkm_rd32(device, 0x610024); 666 667 while (intr0 & 0x001f0000) { 668 u32 chid = __ffs(intr0 & 0x001f0000) - 16; 669 nv50_disp_intr_error(disp, chid); 670 intr0 &= ~(0x00010000 << chid); 671 } 672 673 while (intr0 & 0x0000001f) { 674 u32 chid = __ffs(intr0 & 0x0000001f); 675 nv50_disp_chan_uevent_send(disp, chid); 676 intr0 &= ~(0x00000001 << chid); 677 } 678 679 if (intr1 & 0x00000004) { 680 nvkm_disp_vblank(&disp->base, 0); 681 nvkm_wr32(device, 0x610024, 0x00000004); 682 } 683 684 if (intr1 & 0x00000008) { 685 nvkm_disp_vblank(&disp->base, 1); 686 nvkm_wr32(device, 0x610024, 0x00000008); 687 } 688 689 if (intr1 & 0x00000070) { 690 disp->super = (intr1 & 0x00000070); 691 schedule_work(&disp->supervisor); 692 nvkm_wr32(device, 0x610024, disp->super); 693 } 694 } 695 696 static const struct nvkm_disp_func 697 nv50_disp = { 698 .root = &nv50_disp_root_oclass, 699 }; 700 701 static int 702 nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, 703 struct nvkm_oclass *oclass, void *data, u32 size, 704 struct nvkm_object **pobject) 705 { 706 struct nv50_disp *disp; 707 int ret; 708 709 ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", 710 "display", &disp); 711 *pobject = nv_object(disp); 712 if (ret) 713 return ret; 714 715 disp->base.func = &nv50_disp; 716 717 ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); 718 if (ret) 719 return ret; 720 721 nv_subdev(disp)->intr = nv50_disp_intr; 722 INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); 723 disp->head.nr = 2; 724 disp->dac.nr = 3; 725 disp->sor.nr = 2; 726 disp->pior.nr = 3; 727 disp->dac.power = nv50_dac_power; 728 disp->dac.sense = nv50_dac_sense; 729 disp->sor.power = nv50_sor_power; 730 disp->pior.power = nv50_pior_power; 731 return 0; 732 } 733 734 struct nvkm_oclass * 735 nv50_disp_oclass = &(struct nv50_disp_impl) { 736 .base.base.handle = NV_ENGINE(DISP, 0x50), 737 .base.base.ofuncs = &(struct nvkm_ofuncs) { 738 .ctor = nv50_disp_ctor, 739 .dtor = _nvkm_disp_dtor, 740 .init = _nvkm_disp_init, 741 .fini = _nvkm_disp_fini, 742 }, 743 .base.outp.internal.crt = nv50_dac_output_new, 744 .base.outp.internal.tmds = nv50_sor_output_new, 745 .base.outp.internal.lvds = nv50_sor_output_new, 746 .base.outp.external.tmds = nv50_pior_output_new, 747 .base.outp.external.dp = nv50_pior_dp_new, 748 .base.vblank = &nv50_disp_vblank_func, 749 .head.scanoutpos = nv50_disp_root_scanoutpos, 750 }.base.base; 751