diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_display.c')
| -rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 419 |
1 files changed, 249 insertions, 170 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 580a5d10be9..f13ad0de9c8 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
| @@ -71,14 +71,13 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, | |||
| 71 | return ret; | 71 | return ret; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | dev_priv->engine.instmem.prepare_access(dev, true); | ||
| 75 | nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); | 74 | nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); |
| 76 | nv_wo32(dev, obj, 1, limit); | 75 | nv_wo32(dev, obj, 1, limit); |
| 77 | nv_wo32(dev, obj, 2, offset); | 76 | nv_wo32(dev, obj, 2, offset); |
| 78 | nv_wo32(dev, obj, 3, 0x00000000); | 77 | nv_wo32(dev, obj, 3, 0x00000000); |
| 79 | nv_wo32(dev, obj, 4, 0x00000000); | 78 | nv_wo32(dev, obj, 4, 0x00000000); |
| 80 | nv_wo32(dev, obj, 5, 0x00010000); | 79 | nv_wo32(dev, obj, 5, 0x00010000); |
| 81 | dev_priv->engine.instmem.finish_access(dev); | 80 | dev_priv->engine.instmem.flush(dev); |
| 82 | 81 | ||
| 83 | return 0; | 82 | return 0; |
| 84 | } | 83 | } |
| @@ -110,8 +109,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) | |||
| 110 | return ret; | 109 | return ret; |
| 111 | } | 110 | } |
| 112 | 111 | ||
| 113 | ret = nouveau_mem_init_heap(&chan->ramin_heap, chan->ramin->gpuobj-> | 112 | ret = drm_mm_init(&chan->ramin_heap, |
| 114 | im_pramin->start, 32768); | 113 | chan->ramin->gpuobj->im_pramin->start, 32768); |
| 115 | if (ret) { | 114 | if (ret) { |
| 116 | NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); | 115 | NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); |
| 117 | nv50_evo_channel_del(pchan); | 116 | nv50_evo_channel_del(pchan); |
| @@ -179,13 +178,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) | |||
| 179 | } | 178 | } |
| 180 | 179 | ||
| 181 | int | 180 | int |
| 181 | nv50_display_early_init(struct drm_device *dev) | ||
| 182 | { | ||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | void | ||
| 187 | nv50_display_late_takedown(struct drm_device *dev) | ||
| 188 | { | ||
| 189 | } | ||
| 190 | |||
| 191 | int | ||
| 182 | nv50_display_init(struct drm_device *dev) | 192 | nv50_display_init(struct drm_device *dev) |
| 183 | { | 193 | { |
| 184 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 194 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
| 185 | struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; | 195 | struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; |
| 196 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
| 186 | struct nouveau_channel *evo = dev_priv->evo; | 197 | struct nouveau_channel *evo = dev_priv->evo; |
| 187 | struct drm_connector *connector; | 198 | struct drm_connector *connector; |
| 188 | uint32_t val, ram_amount, hpd_en[2]; | 199 | uint32_t val, ram_amount; |
| 189 | uint64_t start; | 200 | uint64_t start; |
| 190 | int ret, i; | 201 | int ret, i; |
| 191 | 202 | ||
| @@ -366,26 +377,13 @@ nv50_display_init(struct drm_device *dev) | |||
| 366 | NV50_PDISPLAY_INTR_EN_CLK_UNK40)); | 377 | NV50_PDISPLAY_INTR_EN_CLK_UNK40)); |
| 367 | 378 | ||
| 368 | /* enable hotplug interrupts */ | 379 | /* enable hotplug interrupts */ |
| 369 | hpd_en[0] = hpd_en[1] = 0; | ||
| 370 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 380 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
| 371 | struct nouveau_connector *conn = nouveau_connector(connector); | 381 | struct nouveau_connector *conn = nouveau_connector(connector); |
| 372 | struct dcb_gpio_entry *gpio; | ||
| 373 | 382 | ||
| 374 | if (conn->dcb->gpio_tag == 0xff) | 383 | if (conn->dcb->gpio_tag == 0xff) |
| 375 | continue; | 384 | continue; |
| 376 | 385 | ||
| 377 | gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag); | 386 | pgpio->irq_enable(dev, conn->dcb->gpio_tag, true); |
| 378 | if (!gpio) | ||
| 379 | continue; | ||
| 380 | |||
| 381 | hpd_en[gpio->line >> 4] |= (0x00010001 << (gpio->line & 0xf)); | ||
| 382 | } | ||
| 383 | |||
| 384 | nv_wr32(dev, 0xe054, 0xffffffff); | ||
| 385 | nv_wr32(dev, 0xe050, hpd_en[0]); | ||
| 386 | if (dev_priv->chipset >= 0x90) { | ||
| 387 | nv_wr32(dev, 0xe074, 0xffffffff); | ||
| 388 | nv_wr32(dev, 0xe070, hpd_en[1]); | ||
| 389 | } | 387 | } |
| 390 | 388 | ||
| 391 | return 0; | 389 | return 0; |
| @@ -465,6 +463,7 @@ int nv50_display_create(struct drm_device *dev) | |||
| 465 | { | 463 | { |
| 466 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 464 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
| 467 | struct dcb_table *dcb = &dev_priv->vbios.dcb; | 465 | struct dcb_table *dcb = &dev_priv->vbios.dcb; |
| 466 | struct drm_connector *connector, *ct; | ||
| 468 | int ret, i; | 467 | int ret, i; |
| 469 | 468 | ||
| 470 | NV_DEBUG_KMS(dev, "\n"); | 469 | NV_DEBUG_KMS(dev, "\n"); |
| @@ -507,14 +506,18 @@ int nv50_display_create(struct drm_device *dev) | |||
| 507 | continue; | 506 | continue; |
| 508 | } | 507 | } |
| 509 | 508 | ||
| 509 | connector = nouveau_connector_create(dev, entry->connector); | ||
| 510 | if (IS_ERR(connector)) | ||
| 511 | continue; | ||
| 512 | |||
| 510 | switch (entry->type) { | 513 | switch (entry->type) { |
| 511 | case OUTPUT_TMDS: | 514 | case OUTPUT_TMDS: |
| 512 | case OUTPUT_LVDS: | 515 | case OUTPUT_LVDS: |
| 513 | case OUTPUT_DP: | 516 | case OUTPUT_DP: |
| 514 | nv50_sor_create(dev, entry); | 517 | nv50_sor_create(connector, entry); |
| 515 | break; | 518 | break; |
| 516 | case OUTPUT_ANALOG: | 519 | case OUTPUT_ANALOG: |
| 517 | nv50_dac_create(dev, entry); | 520 | nv50_dac_create(connector, entry); |
| 518 | break; | 521 | break; |
| 519 | default: | 522 | default: |
| 520 | NV_WARN(dev, "DCB encoder %d unknown\n", entry->type); | 523 | NV_WARN(dev, "DCB encoder %d unknown\n", entry->type); |
| @@ -522,11 +525,13 @@ int nv50_display_create(struct drm_device *dev) | |||
| 522 | } | 525 | } |
| 523 | } | 526 | } |
| 524 | 527 | ||
| 525 | for (i = 0 ; i < dcb->connector.entries; i++) { | 528 | list_for_each_entry_safe(connector, ct, |
| 526 | if (i != 0 && dcb->connector.entry[i].index2 == | 529 | &dev->mode_config.connector_list, head) { |
| 527 | dcb->connector.entry[i - 1].index2) | 530 | if (!connector->encoder_ids[0]) { |
| 528 | continue; | 531 | NV_WARN(dev, "%s has no encoders, removing\n", |
| 529 | nouveau_connector_create(dev, &dcb->connector.entry[i]); | 532 | drm_get_connector_name(connector)); |
| 533 | connector->funcs->destroy(connector); | ||
| 534 | } | ||
| 530 | } | 535 | } |
| 531 | 536 | ||
| 532 | ret = nv50_display_init(dev); | 537 | ret = nv50_display_init(dev); |
| @@ -538,7 +543,8 @@ int nv50_display_create(struct drm_device *dev) | |||
| 538 | return 0; | 543 | return 0; |
| 539 | } | 544 | } |
| 540 | 545 | ||
| 541 | int nv50_display_destroy(struct drm_device *dev) | 546 | void |
| 547 | nv50_display_destroy(struct drm_device *dev) | ||
| 542 | { | 548 | { |
| 543 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 549 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
| 544 | 550 | ||
| @@ -548,135 +554,30 @@ int nv50_display_destroy(struct drm_device *dev) | |||
| 548 | 554 | ||
| 549 | nv50_display_disable(dev); | 555 | nv50_display_disable(dev); |
| 550 | nv50_evo_channel_del(&dev_priv->evo); | 556 | nv50_evo_channel_del(&dev_priv->evo); |
| 551 | |||
| 552 | return 0; | ||
| 553 | } | ||
| 554 | |||
| 555 | static inline uint32_t | ||
| 556 | nv50_display_mode_ctrl(struct drm_device *dev, bool sor, int or) | ||
| 557 | { | ||
| 558 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
| 559 | uint32_t mc; | ||
| 560 | |||
| 561 | if (sor) { | ||
| 562 | if (dev_priv->chipset < 0x90 || | ||
| 563 | dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0) | ||
| 564 | mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(or)); | ||
| 565 | else | ||
| 566 | mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(or)); | ||
| 567 | } else { | ||
| 568 | mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(or)); | ||
| 569 | } | ||
| 570 | |||
| 571 | return mc; | ||
| 572 | } | ||
| 573 | |||
| 574 | static int | ||
| 575 | nv50_display_irq_head(struct drm_device *dev, int *phead, | ||
| 576 | struct dcb_entry **pdcbent) | ||
| 577 | { | ||
| 578 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
| 579 | uint32_t unk30 = nv_rd32(dev, NV50_PDISPLAY_UNK30_CTRL); | ||
| 580 | uint32_t dac = 0, sor = 0; | ||
| 581 | int head, i, or = 0, type = OUTPUT_ANY; | ||
| 582 | |||
| 583 | /* We're assuming that head 0 *or* head 1 will be active here, | ||
| 584 | * and not both. I'm not sure if the hw will even signal both | ||
| 585 | * ever, but it definitely shouldn't for us as we commit each | ||
| 586 | * CRTC separately, and submission will be blocked by the GPU | ||
| 587 | * until we handle each in turn. | ||
| 588 | */ | ||
| 589 | NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); | ||
| 590 | head = ffs((unk30 >> 9) & 3) - 1; | ||
| 591 | if (head < 0) | ||
| 592 | return -EINVAL; | ||
| 593 | |||
| 594 | /* This assumes CRTCs are never bound to multiple encoders, which | ||
| 595 | * should be the case. | ||
| 596 | */ | ||
| 597 | for (i = 0; i < 3 && type == OUTPUT_ANY; i++) { | ||
| 598 | uint32_t mc = nv50_display_mode_ctrl(dev, false, i); | ||
| 599 | if (!(mc & (1 << head))) | ||
| 600 | continue; | ||
| 601 | |||
| 602 | switch ((mc >> 8) & 0xf) { | ||
| 603 | case 0: type = OUTPUT_ANALOG; break; | ||
| 604 | case 1: type = OUTPUT_TV; break; | ||
| 605 | default: | ||
| 606 | NV_ERROR(dev, "unknown dac mode_ctrl: 0x%08x\n", dac); | ||
| 607 | return -1; | ||
| 608 | } | ||
| 609 | |||
| 610 | or = i; | ||
| 611 | } | ||
| 612 | |||
| 613 | for (i = 0; i < 4 && type == OUTPUT_ANY; i++) { | ||
| 614 | uint32_t mc = nv50_display_mode_ctrl(dev, true, i); | ||
| 615 | if (!(mc & (1 << head))) | ||
| 616 | continue; | ||
| 617 | |||
| 618 | switch ((mc >> 8) & 0xf) { | ||
| 619 | case 0: type = OUTPUT_LVDS; break; | ||
| 620 | case 1: type = OUTPUT_TMDS; break; | ||
| 621 | case 2: type = OUTPUT_TMDS; break; | ||
| 622 | case 5: type = OUTPUT_TMDS; break; | ||
| 623 | case 8: type = OUTPUT_DP; break; | ||
| 624 | case 9: type = OUTPUT_DP; break; | ||
| 625 | default: | ||
| 626 | NV_ERROR(dev, "unknown sor mode_ctrl: 0x%08x\n", sor); | ||
| 627 | return -1; | ||
| 628 | } | ||
| 629 | |||
| 630 | or = i; | ||
| 631 | } | ||
| 632 | |||
| 633 | NV_DEBUG_KMS(dev, "type %d, or %d\n", type, or); | ||
| 634 | if (type == OUTPUT_ANY) { | ||
| 635 | NV_ERROR(dev, "unknown encoder!!\n"); | ||
| 636 | return -1; | ||
| 637 | } | ||
| 638 | |||
| 639 | for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { | ||
| 640 | struct dcb_entry *dcbent = &dev_priv->vbios.dcb.entry[i]; | ||
| 641 | |||
| 642 | if (dcbent->type != type) | ||
| 643 | continue; | ||
| 644 | |||
| 645 | if (!(dcbent->or & (1 << or))) | ||
| 646 | continue; | ||
| 647 | |||
| 648 | *phead = head; | ||
| 649 | *pdcbent = dcbent; | ||
| 650 | return 0; | ||
| 651 | } | ||
| 652 | |||
| 653 | NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or); | ||
| 654 | return 0; | ||
| 655 | } | 557 | } |
| 656 | 558 | ||
| 657 | static uint32_t | 559 | static u16 |
| 658 | nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent, | 560 | nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb, |
| 659 | int pxclk) | 561 | u32 mc, int pxclk) |
| 660 | { | 562 | { |
| 661 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 563 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
| 662 | struct nouveau_connector *nv_connector = NULL; | 564 | struct nouveau_connector *nv_connector = NULL; |
| 663 | struct drm_encoder *encoder; | 565 | struct drm_encoder *encoder; |
| 664 | struct nvbios *bios = &dev_priv->vbios; | 566 | struct nvbios *bios = &dev_priv->vbios; |
| 665 | uint32_t mc, script = 0, or; | 567 | u32 script = 0, or; |
| 666 | 568 | ||
| 667 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | 569 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
| 668 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | 570 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
| 669 | 571 | ||
| 670 | if (nv_encoder->dcb != dcbent) | 572 | if (nv_encoder->dcb != dcb) |
| 671 | continue; | 573 | continue; |
| 672 | 574 | ||
| 673 | nv_connector = nouveau_encoder_connector_get(nv_encoder); | 575 | nv_connector = nouveau_encoder_connector_get(nv_encoder); |
| 674 | break; | 576 | break; |
| 675 | } | 577 | } |
| 676 | 578 | ||
| 677 | or = ffs(dcbent->or) - 1; | 579 | or = ffs(dcb->or) - 1; |
| 678 | mc = nv50_display_mode_ctrl(dev, dcbent->type != OUTPUT_ANALOG, or); | 580 | switch (dcb->type) { |
| 679 | switch (dcbent->type) { | ||
| 680 | case OUTPUT_LVDS: | 581 | case OUTPUT_LVDS: |
| 681 | script = (mc >> 8) & 0xf; | 582 | script = (mc >> 8) & 0xf; |
| 682 | if (bios->fp_no_ddc) { | 583 | if (bios->fp_no_ddc) { |
| @@ -767,17 +668,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) | |||
| 767 | static void | 668 | static void |
| 768 | nv50_display_unk10_handler(struct drm_device *dev) | 669 | nv50_display_unk10_handler(struct drm_device *dev) |
| 769 | { | 670 | { |
| 770 | struct dcb_entry *dcbent; | 671 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
| 771 | int head, ret; | 672 | u32 unk30 = nv_rd32(dev, 0x610030), mc; |
| 673 | int i, crtc, or, type = OUTPUT_ANY; | ||
| 772 | 674 | ||
| 773 | ret = nv50_display_irq_head(dev, &head, &dcbent); | 675 | NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); |
| 774 | if (ret) | 676 | dev_priv->evo_irq.dcb = NULL; |
| 775 | goto ack; | ||
| 776 | 677 | ||
| 777 | nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8); | 678 | nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8); |
| 778 | 679 | ||
| 779 | nouveau_bios_run_display_table(dev, dcbent, 0, -1); | 680 | /* Determine which CRTC we're dealing with, only 1 ever will be |
| 681 | * signalled at the same time with the current nouveau code. | ||
| 682 | */ | ||
| 683 | crtc = ffs((unk30 & 0x00000060) >> 5) - 1; | ||
| 684 | if (crtc < 0) | ||
| 685 | goto ack; | ||
| 686 | |||
| 687 | /* Nothing needs to be done for the encoder */ | ||
| 688 | crtc = ffs((unk30 & 0x00000180) >> 7) - 1; | ||
| 689 | if (crtc < 0) | ||
| 690 | goto ack; | ||
| 780 | 691 | ||
| 692 | /* Find which encoder was connected to the CRTC */ | ||
| 693 | for (i = 0; type == OUTPUT_ANY && i < 3; i++) { | ||
| 694 | mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i)); | ||
| 695 | NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc); | ||
| 696 | if (!(mc & (1 << crtc))) | ||
| 697 | continue; | ||
| 698 | |||
| 699 | switch ((mc & 0x00000f00) >> 8) { | ||
| 700 | case 0: type = OUTPUT_ANALOG; break; | ||
| 701 | case 1: type = OUTPUT_TV; break; | ||
| 702 | default: | ||
| 703 | NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc); | ||
| 704 | goto ack; | ||
| 705 | } | ||
| 706 | |||
| 707 | or = i; | ||
| 708 | } | ||
| 709 | |||
| 710 | for (i = 0; type == OUTPUT_ANY && i < 4; i++) { | ||
| 711 | if (dev_priv->chipset < 0x90 || | ||
| 712 | dev_priv->chipset == 0x92 || | ||
| 713 | dev_priv->chipset == 0xa0) | ||
| 714 | mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i)); | ||
| 715 | else | ||
| 716 | mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i)); | ||
| 717 | |||
| 718 | NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc); | ||
| 719 | if (!(mc & (1 << crtc))) | ||
| 720 | continue; | ||
| 721 | |||
| 722 | switch ((mc & 0x00000f00) >> 8) { | ||
| 723 | case 0: type = OUTPUT_LVDS; break; | ||
| 724 | case 1: type = OUTPUT_TMDS; break; | ||
| 725 | case 2: type = OUTPUT_TMDS; break; | ||
| 726 | case 5: type = OUTPUT_TMDS; break; | ||
| 727 | case 8: type = OUTPUT_DP; break; | ||
| 728 | case 9: type = OUTPUT_DP; break; | ||
| 729 | default: | ||
| 730 | NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc); | ||
| 731 | goto ack; | ||
| 732 | } | ||
| 733 | |||
| 734 | or = i; | ||
| 735 | } | ||
| 736 | |||
| 737 | /* There was no encoder to disable */ | ||
| 738 | if (type == OUTPUT_ANY) | ||
| 739 | goto ack; | ||
| 740 | |||
| 741 | /* Disable the encoder */ | ||
| 742 | for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { | ||
| 743 | struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; | ||
| 744 | |||
| 745 | if (dcb->type == type && (dcb->or & (1 << or))) { | ||
| 746 | nouveau_bios_run_display_table(dev, dcb, 0, -1); | ||
| 747 | dev_priv->evo_irq.dcb = dcb; | ||
| 748 | goto ack; | ||
| 749 | } | ||
| 750 | } | ||
| 751 | |||
| 752 | NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc); | ||
| 781 | ack: | 753 | ack: |
| 782 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10); | 754 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10); |
| 783 | nv_wr32(dev, 0x610030, 0x80000000); | 755 | nv_wr32(dev, 0x610030, 0x80000000); |
| @@ -817,33 +789,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) | |||
| 817 | static void | 789 | static void |
| 818 | nv50_display_unk20_handler(struct drm_device *dev) | 790 | nv50_display_unk20_handler(struct drm_device *dev) |
| 819 | { | 791 | { |
| 820 | struct dcb_entry *dcbent; | 792 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
| 821 | uint32_t tmp, pclk, script; | 793 | u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc; |
| 822 | int head, or, ret; | 794 | struct dcb_entry *dcb; |
| 795 | int i, crtc, or, type = OUTPUT_ANY; | ||
| 823 | 796 | ||
| 824 | ret = nv50_display_irq_head(dev, &head, &dcbent); | 797 | NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); |
| 825 | if (ret) | 798 | dcb = dev_priv->evo_irq.dcb; |
| 799 | if (dcb) { | ||
| 800 | nouveau_bios_run_display_table(dev, dcb, 0, -2); | ||
| 801 | dev_priv->evo_irq.dcb = NULL; | ||
| 802 | } | ||
| 803 | |||
| 804 | /* CRTC clock change requested? */ | ||
| 805 | crtc = ffs((unk30 & 0x00000600) >> 9) - 1; | ||
| 806 | if (crtc >= 0) { | ||
| 807 | pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)); | ||
| 808 | pclk &= 0x003fffff; | ||
| 809 | |||
| 810 | nv50_crtc_set_clock(dev, crtc, pclk); | ||
| 811 | |||
| 812 | tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc)); | ||
| 813 | tmp &= ~0x000000f; | ||
| 814 | nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp); | ||
| 815 | } | ||
| 816 | |||
| 817 | /* Nothing needs to be done for the encoder */ | ||
| 818 | crtc = ffs((unk30 & 0x00000180) >> 7) - 1; | ||
| 819 | if (crtc < 0) | ||
| 826 | goto ack; | 820 | goto ack; |
| 827 | or = ffs(dcbent->or) - 1; | 821 | pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff; |
| 828 | pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff; | ||
| 829 | script = nv50_display_script_select(dev, dcbent, pclk); | ||
| 830 | 822 | ||
| 831 | NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk); | 823 | /* Find which encoder is connected to the CRTC */ |
| 824 | for (i = 0; type == OUTPUT_ANY && i < 3; i++) { | ||
| 825 | mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i)); | ||
| 826 | NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc); | ||
| 827 | if (!(mc & (1 << crtc))) | ||
| 828 | continue; | ||
| 832 | 829 | ||
| 833 | if (dcbent->type != OUTPUT_DP) | 830 | switch ((mc & 0x00000f00) >> 8) { |
| 834 | nouveau_bios_run_display_table(dev, dcbent, 0, -2); | 831 | case 0: type = OUTPUT_ANALOG; break; |
| 832 | case 1: type = OUTPUT_TV; break; | ||
| 833 | default: | ||
| 834 | NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc); | ||
| 835 | goto ack; | ||
| 836 | } | ||
| 835 | 837 | ||
| 836 | nv50_crtc_set_clock(dev, head, pclk); | 838 | or = i; |
| 839 | } | ||
| 837 | 840 | ||
| 838 | nouveau_bios_run_display_table(dev, dcbent, script, pclk); | 841 | for (i = 0; type == OUTPUT_ANY && i < 4; i++) { |
| 842 | if (dev_priv->chipset < 0x90 || | ||
| 843 | dev_priv->chipset == 0x92 || | ||
| 844 | dev_priv->chipset == 0xa0) | ||
| 845 | mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i)); | ||
| 846 | else | ||
| 847 | mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i)); | ||
| 839 | 848 | ||
| 840 | nv50_display_unk20_dp_hack(dev, dcbent); | 849 | NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc); |
| 850 | if (!(mc & (1 << crtc))) | ||
| 851 | continue; | ||
| 852 | |||
| 853 | switch ((mc & 0x00000f00) >> 8) { | ||
| 854 | case 0: type = OUTPUT_LVDS; break; | ||
| 855 | case 1: type = OUTPUT_TMDS; break; | ||
| 856 | case 2: type = OUTPUT_TMDS; break; | ||
| 857 | case 5: type = OUTPUT_TMDS; break; | ||
| 858 | case 8: type = OUTPUT_DP; break; | ||
| 859 | case 9: type = OUTPUT_DP; break; | ||
| 860 | default: | ||
| 861 | NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc); | ||
| 862 | goto ack; | ||
| 863 | } | ||
| 864 | |||
| 865 | or = i; | ||
| 866 | } | ||
| 867 | |||
| 868 | if (type == OUTPUT_ANY) | ||
| 869 | goto ack; | ||
| 870 | |||
| 871 | /* Enable the encoder */ | ||
| 872 | for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { | ||
| 873 | dcb = &dev_priv->vbios.dcb.entry[i]; | ||
| 874 | if (dcb->type == type && (dcb->or & (1 << or))) | ||
| 875 | break; | ||
| 876 | } | ||
| 877 | |||
| 878 | if (i == dev_priv->vbios.dcb.entries) { | ||
| 879 | NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc); | ||
| 880 | goto ack; | ||
| 881 | } | ||
| 841 | 882 | ||
| 842 | tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head)); | 883 | script = nv50_display_script_select(dev, dcb, mc, pclk); |
| 843 | tmp &= ~0x000000f; | 884 | nouveau_bios_run_display_table(dev, dcb, script, pclk); |
| 844 | nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp); | ||
| 845 | 885 | ||
| 846 | if (dcbent->type != OUTPUT_ANALOG) { | 886 | nv50_display_unk20_dp_hack(dev, dcb); |
| 887 | |||
| 888 | if (dcb->type != OUTPUT_ANALOG) { | ||
| 847 | tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); | 889 | tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); |
| 848 | tmp &= ~0x00000f0f; | 890 | tmp &= ~0x00000f0f; |
| 849 | if (script & 0x0100) | 891 | if (script & 0x0100) |
| @@ -853,24 +895,61 @@ nv50_display_unk20_handler(struct drm_device *dev) | |||
| 853 | nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0); | 895 | nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0); |
| 854 | } | 896 | } |
| 855 | 897 | ||
| 898 | dev_priv->evo_irq.dcb = dcb; | ||
| 899 | dev_priv->evo_irq.pclk = pclk; | ||
| 900 | dev_priv->evo_irq.script = script; | ||
| 901 | |||
| 856 | ack: | 902 | ack: |
| 857 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20); | 903 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20); |
| 858 | nv_wr32(dev, 0x610030, 0x80000000); | 904 | nv_wr32(dev, 0x610030, 0x80000000); |
| 859 | } | 905 | } |
| 860 | 906 | ||
| 907 | /* If programming a TMDS output on a SOR that can also be configured for | ||
| 908 | * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off. | ||
| 909 | * | ||
| 910 | * It looks like the VBIOS TMDS scripts make an attempt at this, however, | ||
| 911 | * the VBIOS scripts on at least one board I have only switch it off on | ||
| 912 | * link 0, causing a blank display if the output has previously been | ||
| 913 | * programmed for DisplayPort. | ||
| 914 | */ | ||
| 915 | static void | ||
| 916 | nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb) | ||
| 917 | { | ||
| 918 | int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1); | ||
| 919 | struct drm_encoder *encoder; | ||
| 920 | u32 tmp; | ||
| 921 | |||
| 922 | if (dcb->type != OUTPUT_TMDS) | ||
| 923 | return; | ||
| 924 | |||
| 925 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
| 926 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
| 927 | |||
| 928 | if (nv_encoder->dcb->type == OUTPUT_DP && | ||
| 929 | nv_encoder->dcb->or & (1 << or)) { | ||
| 930 | tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); | ||
| 931 | tmp &= ~NV50_SOR_DP_CTRL_ENABLED; | ||
| 932 | nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp); | ||
| 933 | break; | ||
| 934 | } | ||
| 935 | } | ||
| 936 | } | ||
| 937 | |||
| 861 | static void | 938 | static void |
| 862 | nv50_display_unk40_handler(struct drm_device *dev) | 939 | nv50_display_unk40_handler(struct drm_device *dev) |
| 863 | { | 940 | { |
| 864 | struct dcb_entry *dcbent; | 941 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
| 865 | int head, pclk, script, ret; | 942 | struct dcb_entry *dcb = dev_priv->evo_irq.dcb; |
| 943 | u16 script = dev_priv->evo_irq.script; | ||
| 944 | u32 unk30 = nv_rd32(dev, 0x610030), pclk = dev_priv->evo_irq.pclk; | ||
| 866 | 945 | ||
| 867 | ret = nv50_display_irq_head(dev, &head, &dcbent); | 946 | NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); |
| 868 | if (ret) | 947 | dev_priv->evo_irq.dcb = NULL; |
| 948 | if (!dcb) | ||
| 869 | goto ack; | 949 | goto ack; |
| 870 | pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff; | ||
| 871 | script = nv50_display_script_select(dev, dcbent, pclk); | ||
| 872 | 950 | ||
| 873 | nouveau_bios_run_display_table(dev, dcbent, script, -pclk); | 951 | nouveau_bios_run_display_table(dev, dcb, script, -pclk); |
| 952 | nv50_display_unk40_dp_set_tmds(dev, dcb); | ||
| 874 | 953 | ||
| 875 | ack: | 954 | ack: |
| 876 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40); | 955 | nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40); |
