.. | .. |
---|
24 | 24 | #include "core.h" |
---|
25 | 25 | #include "curs.h" |
---|
26 | 26 | #include "ovly.h" |
---|
| 27 | +#include "crc.h" |
---|
27 | 28 | |
---|
28 | 29 | #include <nvif/class.h> |
---|
| 30 | +#include <nvif/event.h> |
---|
| 31 | +#include <nvif/cl0046.h> |
---|
29 | 32 | |
---|
30 | 33 | #include <drm/drm_atomic_helper.h> |
---|
31 | 34 | #include <drm/drm_crtc_helper.h> |
---|
| 35 | +#include <drm/drm_vblank.h> |
---|
32 | 36 | #include "nouveau_connector.h" |
---|
| 37 | + |
---|
33 | 38 | void |
---|
34 | 39 | nv50_head_flush_clr(struct nv50_head *head, |
---|
35 | 40 | struct nv50_head_atom *asyh, bool flush) |
---|
.. | .. |
---|
37 | 42 | union nv50_head_atom_mask clr = { |
---|
38 | 43 | .mask = asyh->clr.mask & ~(flush ? 0 : asyh->set.mask), |
---|
39 | 44 | }; |
---|
| 45 | + if (clr.crc) nv50_crc_atomic_clr(head); |
---|
40 | 46 | if (clr.olut) head->func->olut_clr(head); |
---|
41 | 47 | if (clr.core) head->func->core_clr(head); |
---|
42 | 48 | if (clr.curs) head->func->curs_clr(head); |
---|
| 49 | +} |
---|
| 50 | + |
---|
| 51 | +void |
---|
| 52 | +nv50_head_flush_set_wndw(struct nv50_head *head, struct nv50_head_atom *asyh) |
---|
| 53 | +{ |
---|
| 54 | + if (asyh->set.curs ) head->func->curs_set(head, asyh); |
---|
| 55 | + if (asyh->set.olut ) { |
---|
| 56 | + asyh->olut.offset = nv50_lut_load(&head->olut, |
---|
| 57 | + asyh->olut.buffer, |
---|
| 58 | + asyh->state.gamma_lut, |
---|
| 59 | + asyh->olut.load); |
---|
| 60 | + head->func->olut_set(head, asyh); |
---|
| 61 | + } |
---|
43 | 62 | } |
---|
44 | 63 | |
---|
45 | 64 | void |
---|
.. | .. |
---|
48 | 67 | if (asyh->set.view ) head->func->view (head, asyh); |
---|
49 | 68 | if (asyh->set.mode ) head->func->mode (head, asyh); |
---|
50 | 69 | if (asyh->set.core ) head->func->core_set(head, asyh); |
---|
51 | | - if (asyh->set.olut ) { |
---|
52 | | - asyh->olut.offset = nv50_lut_load(&head->olut, |
---|
53 | | - asyh->olut.mode <= 1, |
---|
54 | | - asyh->olut.buffer, |
---|
55 | | - asyh->state.gamma_lut); |
---|
56 | | - head->func->olut_set(head, asyh); |
---|
57 | | - } |
---|
58 | | - if (asyh->set.curs ) head->func->curs_set(head, asyh); |
---|
59 | 70 | if (asyh->set.base ) head->func->base (head, asyh); |
---|
60 | 71 | if (asyh->set.ovly ) head->func->ovly (head, asyh); |
---|
61 | 72 | if (asyh->set.dither ) head->func->dither (head, asyh); |
---|
62 | 73 | if (asyh->set.procamp) head->func->procamp (head, asyh); |
---|
| 74 | + if (asyh->set.crc ) nv50_crc_atomic_set (head, asyh); |
---|
63 | 75 | if (asyh->set.or ) head->func->or (head, asyh); |
---|
64 | 76 | } |
---|
65 | 77 | |
---|
.. | .. |
---|
81 | 93 | struct nv50_head_atom *asyh, |
---|
82 | 94 | struct nouveau_conn_atom *asyc) |
---|
83 | 95 | { |
---|
84 | | - struct drm_connector *connector = asyc->state.connector; |
---|
85 | 96 | u32 mode = 0x00; |
---|
86 | 97 | |
---|
87 | | - if (asyc->dither.mode == DITHERING_MODE_AUTO) { |
---|
88 | | - if (asyh->base.depth > connector->display_info.bpc * 3) |
---|
89 | | - mode = DITHERING_MODE_DYNAMIC2X2; |
---|
90 | | - } else { |
---|
91 | | - mode = asyc->dither.mode; |
---|
| 98 | + if (asyc->dither.mode) { |
---|
| 99 | + if (asyc->dither.mode == DITHERING_MODE_AUTO) { |
---|
| 100 | + if (asyh->base.depth > asyh->or.bpc * 3) |
---|
| 101 | + mode = DITHERING_MODE_DYNAMIC2X2; |
---|
| 102 | + } else { |
---|
| 103 | + mode = asyc->dither.mode; |
---|
| 104 | + } |
---|
| 105 | + |
---|
| 106 | + if (asyc->dither.depth == DITHERING_DEPTH_AUTO) { |
---|
| 107 | + if (asyh->or.bpc >= 8) |
---|
| 108 | + mode |= DITHERING_DEPTH_8BPC; |
---|
| 109 | + } else { |
---|
| 110 | + mode |= asyc->dither.depth; |
---|
| 111 | + } |
---|
92 | 112 | } |
---|
93 | 113 | |
---|
94 | | - if (asyc->dither.depth == DITHERING_DEPTH_AUTO) { |
---|
95 | | - if (connector->display_info.bpc >= 8) |
---|
96 | | - mode |= DITHERING_DEPTH_8BPC; |
---|
97 | | - } else { |
---|
98 | | - mode |= asyc->dither.depth; |
---|
99 | | - } |
---|
100 | | - |
---|
101 | | - asyh->dither.enable = mode; |
---|
102 | | - asyh->dither.bits = mode >> 1; |
---|
103 | | - asyh->dither.mode = mode >> 3; |
---|
| 114 | + asyh->dither.enable = NVVAL_GET(mode, NV507D, HEAD_SET_DITHER_CONTROL, ENABLE); |
---|
| 115 | + asyh->dither.bits = NVVAL_GET(mode, NV507D, HEAD_SET_DITHER_CONTROL, BITS); |
---|
| 116 | + asyh->dither.mode = NVVAL_GET(mode, NV507D, HEAD_SET_DITHER_CONTROL, MODE); |
---|
104 | 117 | asyh->set.dither = true; |
---|
105 | 118 | } |
---|
106 | 119 | |
---|
.. | .. |
---|
214 | 227 | { |
---|
215 | 228 | struct nv50_disp *disp = nv50_disp(head->base.base.dev); |
---|
216 | 229 | struct drm_property_blob *olut = asyh->state.gamma_lut; |
---|
| 230 | + int size; |
---|
217 | 231 | |
---|
218 | 232 | /* Determine whether core output LUT should be enabled. */ |
---|
219 | 233 | if (olut) { |
---|
.. | .. |
---|
231 | 245 | } |
---|
232 | 246 | |
---|
233 | 247 | if (!olut) { |
---|
234 | | - asyh->olut.handle = 0; |
---|
235 | | - return 0; |
---|
| 248 | + if (!head->func->olut_identity) { |
---|
| 249 | + asyh->olut.handle = 0; |
---|
| 250 | + return 0; |
---|
| 251 | + } |
---|
| 252 | + size = 0; |
---|
| 253 | + } else { |
---|
| 254 | + size = drm_color_lut_size(olut); |
---|
236 | 255 | } |
---|
237 | 256 | |
---|
| 257 | + if (!head->func->olut(head, asyh, size)) { |
---|
| 258 | + DRM_DEBUG_KMS("Invalid olut\n"); |
---|
| 259 | + return -EINVAL; |
---|
| 260 | + } |
---|
238 | 261 | asyh->olut.handle = disp->core->chan.vram.handle; |
---|
239 | 262 | asyh->olut.buffer = !asyh->olut.buffer; |
---|
240 | | - head->func->olut(head, asyh); |
---|
| 263 | + |
---|
241 | 264 | return 0; |
---|
242 | 265 | } |
---|
243 | 266 | |
---|
.. | .. |
---|
301 | 324 | struct nouveau_conn_atom *asyc = NULL; |
---|
302 | 325 | struct drm_connector_state *conns; |
---|
303 | 326 | struct drm_connector *conn; |
---|
304 | | - int i; |
---|
| 327 | + int i, ret; |
---|
305 | 328 | |
---|
306 | 329 | NV_ATOMIC(drm, "%s atomic_check %d\n", crtc->name, asyh->state.active); |
---|
307 | 330 | if (asyh->state.active) { |
---|
.. | .. |
---|
396 | 419 | asyh->set.curs = asyh->curs.visible; |
---|
397 | 420 | } |
---|
398 | 421 | |
---|
| 422 | + ret = nv50_crc_atomic_check_head(head, asyh, armh); |
---|
| 423 | + if (ret) |
---|
| 424 | + return ret; |
---|
| 425 | + |
---|
399 | 426 | if (asyh->clr.mask || asyh->set.mask) |
---|
400 | 427 | nv50_atom(asyh->state.state)->lock_core = true; |
---|
401 | 428 | return 0; |
---|
.. | .. |
---|
404 | 431 | static const struct drm_crtc_helper_funcs |
---|
405 | 432 | nv50_head_help = { |
---|
406 | 433 | .atomic_check = nv50_head_atomic_check, |
---|
| 434 | + .get_scanout_position = nouveau_display_scanoutpos, |
---|
407 | 435 | }; |
---|
408 | 436 | |
---|
409 | 437 | static void |
---|
.. | .. |
---|
433 | 461 | asyh->ovly = armh->ovly; |
---|
434 | 462 | asyh->dither = armh->dither; |
---|
435 | 463 | asyh->procamp = armh->procamp; |
---|
| 464 | + asyh->crc = armh->crc; |
---|
| 465 | + asyh->or = armh->or; |
---|
| 466 | + asyh->dp = armh->dp; |
---|
436 | 467 | asyh->clr.mask = 0; |
---|
437 | 468 | asyh->set.mask = 0; |
---|
438 | 469 | return &asyh->state; |
---|
439 | | -} |
---|
440 | | - |
---|
441 | | -static void |
---|
442 | | -__drm_atomic_helper_crtc_reset(struct drm_crtc *crtc, |
---|
443 | | - struct drm_crtc_state *state) |
---|
444 | | -{ |
---|
445 | | - if (crtc->state) |
---|
446 | | - crtc->funcs->atomic_destroy_state(crtc, crtc->state); |
---|
447 | | - crtc->state = state; |
---|
448 | | - crtc->state->crtc = crtc; |
---|
449 | 470 | } |
---|
450 | 471 | |
---|
451 | 472 | static void |
---|
.. | .. |
---|
456 | 477 | if (WARN_ON(!(asyh = kzalloc(sizeof(*asyh), GFP_KERNEL)))) |
---|
457 | 478 | return; |
---|
458 | 479 | |
---|
| 480 | + if (crtc->state) |
---|
| 481 | + nv50_head_atomic_destroy_state(crtc, crtc->state); |
---|
| 482 | + |
---|
459 | 483 | __drm_atomic_helper_crtc_reset(crtc, &asyh->state); |
---|
| 484 | +} |
---|
| 485 | + |
---|
| 486 | +static int |
---|
| 487 | +nv50_head_late_register(struct drm_crtc *crtc) |
---|
| 488 | +{ |
---|
| 489 | + return nv50_head_crc_late_register(nv50_head(crtc)); |
---|
460 | 490 | } |
---|
461 | 491 | |
---|
462 | 492 | static void |
---|
463 | 493 | nv50_head_destroy(struct drm_crtc *crtc) |
---|
464 | 494 | { |
---|
465 | 495 | struct nv50_head *head = nv50_head(crtc); |
---|
| 496 | + |
---|
| 497 | + nvif_notify_dtor(&head->base.vblank); |
---|
466 | 498 | nv50_lut_fini(&head->olut); |
---|
467 | 499 | drm_crtc_cleanup(crtc); |
---|
468 | 500 | kfree(head); |
---|
.. | .. |
---|
477 | 509 | .page_flip = drm_atomic_helper_page_flip, |
---|
478 | 510 | .atomic_duplicate_state = nv50_head_atomic_duplicate_state, |
---|
479 | 511 | .atomic_destroy_state = nv50_head_atomic_destroy_state, |
---|
| 512 | + .enable_vblank = nouveau_display_vblank_enable, |
---|
| 513 | + .disable_vblank = nouveau_display_vblank_disable, |
---|
| 514 | + .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, |
---|
| 515 | + .late_register = nv50_head_late_register, |
---|
480 | 516 | }; |
---|
481 | 517 | |
---|
482 | | -int |
---|
| 518 | +static const struct drm_crtc_funcs |
---|
| 519 | +nvd9_head_func = { |
---|
| 520 | + .reset = nv50_head_reset, |
---|
| 521 | + .gamma_set = drm_atomic_helper_legacy_gamma_set, |
---|
| 522 | + .destroy = nv50_head_destroy, |
---|
| 523 | + .set_config = drm_atomic_helper_set_config, |
---|
| 524 | + .page_flip = drm_atomic_helper_page_flip, |
---|
| 525 | + .atomic_duplicate_state = nv50_head_atomic_duplicate_state, |
---|
| 526 | + .atomic_destroy_state = nv50_head_atomic_destroy_state, |
---|
| 527 | + .enable_vblank = nouveau_display_vblank_enable, |
---|
| 528 | + .disable_vblank = nouveau_display_vblank_disable, |
---|
| 529 | + .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, |
---|
| 530 | + .verify_crc_source = nv50_crc_verify_source, |
---|
| 531 | + .get_crc_sources = nv50_crc_get_sources, |
---|
| 532 | + .set_crc_source = nv50_crc_set_source, |
---|
| 533 | + .late_register = nv50_head_late_register, |
---|
| 534 | +}; |
---|
| 535 | + |
---|
| 536 | +static int nv50_head_vblank_handler(struct nvif_notify *notify) |
---|
| 537 | +{ |
---|
| 538 | + struct nouveau_crtc *nv_crtc = |
---|
| 539 | + container_of(notify, struct nouveau_crtc, vblank); |
---|
| 540 | + |
---|
| 541 | + if (drm_crtc_handle_vblank(&nv_crtc->base)) |
---|
| 542 | + nv50_crc_handle_vblank(nv50_head(&nv_crtc->base)); |
---|
| 543 | + |
---|
| 544 | + return NVIF_NOTIFY_KEEP; |
---|
| 545 | +} |
---|
| 546 | + |
---|
| 547 | +struct nv50_head * |
---|
483 | 548 | nv50_head_create(struct drm_device *dev, int index) |
---|
484 | 549 | { |
---|
485 | 550 | struct nouveau_drm *drm = nouveau_drm(dev); |
---|
486 | 551 | struct nv50_disp *disp = nv50_disp(dev); |
---|
487 | 552 | struct nv50_head *head; |
---|
488 | | - struct nv50_wndw *curs, *wndw; |
---|
| 553 | + struct nv50_wndw *base, *ovly, *curs; |
---|
| 554 | + struct nouveau_crtc *nv_crtc; |
---|
489 | 555 | struct drm_crtc *crtc; |
---|
| 556 | + const struct drm_crtc_funcs *funcs; |
---|
490 | 557 | int ret; |
---|
491 | 558 | |
---|
492 | 559 | head = kzalloc(sizeof(*head), GFP_KERNEL); |
---|
493 | 560 | if (!head) |
---|
494 | | - return -ENOMEM; |
---|
| 561 | + return ERR_PTR(-ENOMEM); |
---|
495 | 562 | |
---|
496 | 563 | head->func = disp->core->func->head; |
---|
497 | 564 | head->base.index = index; |
---|
498 | 565 | |
---|
| 566 | + if (disp->disp->object.oclass < GF110_DISP) |
---|
| 567 | + funcs = &nv50_head_func; |
---|
| 568 | + else |
---|
| 569 | + funcs = &nvd9_head_func; |
---|
| 570 | + |
---|
499 | 571 | if (disp->disp->object.oclass < GV100_DISP) { |
---|
500 | | - ret = nv50_ovly_new(drm, head->base.index, &wndw); |
---|
501 | | - ret = nv50_base_new(drm, head->base.index, &wndw); |
---|
| 572 | + ret = nv50_base_new(drm, head->base.index, &base); |
---|
| 573 | + ret = nv50_ovly_new(drm, head->base.index, &ovly); |
---|
502 | 574 | } else { |
---|
503 | | - ret = nv50_wndw_new(drm, DRM_PLANE_TYPE_OVERLAY, |
---|
504 | | - head->base.index * 2 + 1, &wndw); |
---|
505 | 575 | ret = nv50_wndw_new(drm, DRM_PLANE_TYPE_PRIMARY, |
---|
506 | | - head->base.index * 2 + 0, &wndw); |
---|
| 576 | + head->base.index * 2 + 0, &base); |
---|
| 577 | + ret = nv50_wndw_new(drm, DRM_PLANE_TYPE_OVERLAY, |
---|
| 578 | + head->base.index * 2 + 1, &ovly); |
---|
507 | 579 | } |
---|
508 | 580 | if (ret == 0) |
---|
509 | 581 | ret = nv50_curs_new(drm, head->base.index, &curs); |
---|
510 | 582 | if (ret) { |
---|
511 | 583 | kfree(head); |
---|
512 | | - return ret; |
---|
| 584 | + return ERR_PTR(ret); |
---|
513 | 585 | } |
---|
514 | 586 | |
---|
515 | | - crtc = &head->base.base; |
---|
516 | | - drm_crtc_init_with_planes(dev, crtc, &wndw->plane, &curs->plane, |
---|
517 | | - &nv50_head_func, "head-%d", head->base.index); |
---|
| 587 | + nv_crtc = &head->base; |
---|
| 588 | + crtc = &nv_crtc->base; |
---|
| 589 | + drm_crtc_init_with_planes(dev, crtc, &base->plane, &curs->plane, |
---|
| 590 | + funcs, "head-%d", head->base.index); |
---|
518 | 591 | drm_crtc_helper_add(crtc, &nv50_head_help); |
---|
| 592 | + /* Keep the legacy gamma size at 256 to avoid compatibility issues */ |
---|
519 | 593 | drm_mode_crtc_set_gamma_size(crtc, 256); |
---|
| 594 | + drm_crtc_enable_color_mgmt(crtc, base->func->ilut_size, |
---|
| 595 | + disp->disp->object.oclass >= GF110_DISP, |
---|
| 596 | + head->func->olut_size); |
---|
520 | 597 | |
---|
521 | 598 | if (head->func->olut_set) { |
---|
522 | 599 | ret = nv50_lut_init(disp, &drm->client.mmu, &head->olut); |
---|
523 | | - if (ret) |
---|
524 | | - goto out; |
---|
| 600 | + if (ret) { |
---|
| 601 | + nv50_head_destroy(crtc); |
---|
| 602 | + return ERR_PTR(ret); |
---|
| 603 | + } |
---|
525 | 604 | } |
---|
526 | 605 | |
---|
527 | | -out: |
---|
| 606 | + ret = nvif_notify_ctor(&disp->disp->object, "kmsVbl", nv50_head_vblank_handler, |
---|
| 607 | + false, NV04_DISP_NTFY_VBLANK, |
---|
| 608 | + &(struct nvif_notify_head_req_v0) { |
---|
| 609 | + .head = nv_crtc->index, |
---|
| 610 | + }, |
---|
| 611 | + sizeof(struct nvif_notify_head_req_v0), |
---|
| 612 | + sizeof(struct nvif_notify_head_rep_v0), |
---|
| 613 | + &nv_crtc->vblank); |
---|
528 | 614 | if (ret) |
---|
529 | | - nv50_head_destroy(crtc); |
---|
530 | | - return ret; |
---|
| 615 | + return ERR_PTR(ret); |
---|
| 616 | + |
---|
| 617 | + return head; |
---|
531 | 618 | } |
---|