diff options
author | Jerome Glisse <jglisse@redhat.com> | 2009-07-13 15:04:08 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-07-29 01:45:09 -0400 |
commit | c93bb85b5cba3e3a06f2cad8e9bc5c23d3d10aac (patch) | |
tree | 3168bee69e08dcb1f0f509b03ea1693a688d34ef /drivers/gpu/drm/radeon/atombios_crtc.c | |
parent | e024e11070a0a0dc7163ce1ec2da354a638bdbed (diff) |
drm/radeon/kms: fix bandwidth computation on avivo hardware
Fix bandwidth computation and crtc priority in memory controller
so that crtc memory request are fullfill in time to avoid display
artifact.
Signed-off-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/atombios_crtc.c')
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_crtc.c | 276 |
1 files changed, 131 insertions, 145 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index eac26cdb5dae..74d034f77c6b 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
@@ -31,6 +31,132 @@ | |||
31 | #include "atom.h" | 31 | #include "atom.h" |
32 | #include "atom-bits.h" | 32 | #include "atom-bits.h" |
33 | 33 | ||
34 | static void atombios_overscan_setup(struct drm_crtc *crtc, | ||
35 | struct drm_display_mode *mode, | ||
36 | struct drm_display_mode *adjusted_mode) | ||
37 | { | ||
38 | struct drm_device *dev = crtc->dev; | ||
39 | struct radeon_device *rdev = dev->dev_private; | ||
40 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
41 | SET_CRTC_OVERSCAN_PS_ALLOCATION args; | ||
42 | int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); | ||
43 | int a1, a2; | ||
44 | |||
45 | memset(&args, 0, sizeof(args)); | ||
46 | |||
47 | args.usOverscanRight = 0; | ||
48 | args.usOverscanLeft = 0; | ||
49 | args.usOverscanBottom = 0; | ||
50 | args.usOverscanTop = 0; | ||
51 | args.ucCRTC = radeon_crtc->crtc_id; | ||
52 | |||
53 | switch (radeon_crtc->rmx_type) { | ||
54 | case RMX_CENTER: | ||
55 | args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; | ||
56 | args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; | ||
57 | args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; | ||
58 | args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; | ||
59 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | ||
60 | break; | ||
61 | case RMX_ASPECT: | ||
62 | a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; | ||
63 | a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; | ||
64 | |||
65 | if (a1 > a2) { | ||
66 | args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; | ||
67 | args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; | ||
68 | } else if (a2 > a1) { | ||
69 | args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; | ||
70 | args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; | ||
71 | } | ||
72 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | ||
73 | break; | ||
74 | case RMX_FULL: | ||
75 | default: | ||
76 | args.usOverscanRight = 0; | ||
77 | args.usOverscanLeft = 0; | ||
78 | args.usOverscanBottom = 0; | ||
79 | args.usOverscanTop = 0; | ||
80 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | ||
81 | break; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | static void atombios_scaler_setup(struct drm_crtc *crtc) | ||
86 | { | ||
87 | struct drm_device *dev = crtc->dev; | ||
88 | struct radeon_device *rdev = dev->dev_private; | ||
89 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
90 | ENABLE_SCALER_PS_ALLOCATION args; | ||
91 | int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); | ||
92 | /* fixme - fill in enc_priv for atom dac */ | ||
93 | enum radeon_tv_std tv_std = TV_STD_NTSC; | ||
94 | |||
95 | if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) | ||
96 | return; | ||
97 | |||
98 | memset(&args, 0, sizeof(args)); | ||
99 | |||
100 | args.ucScaler = radeon_crtc->crtc_id; | ||
101 | |||
102 | if (radeon_crtc->devices & (ATOM_DEVICE_TV_SUPPORT)) { | ||
103 | switch (tv_std) { | ||
104 | case TV_STD_NTSC: | ||
105 | default: | ||
106 | args.ucTVStandard = ATOM_TV_NTSC; | ||
107 | break; | ||
108 | case TV_STD_PAL: | ||
109 | args.ucTVStandard = ATOM_TV_PAL; | ||
110 | break; | ||
111 | case TV_STD_PAL_M: | ||
112 | args.ucTVStandard = ATOM_TV_PALM; | ||
113 | break; | ||
114 | case TV_STD_PAL_60: | ||
115 | args.ucTVStandard = ATOM_TV_PAL60; | ||
116 | break; | ||
117 | case TV_STD_NTSC_J: | ||
118 | args.ucTVStandard = ATOM_TV_NTSCJ; | ||
119 | break; | ||
120 | case TV_STD_SCART_PAL: | ||
121 | args.ucTVStandard = ATOM_TV_PAL; /* ??? */ | ||
122 | break; | ||
123 | case TV_STD_SECAM: | ||
124 | args.ucTVStandard = ATOM_TV_SECAM; | ||
125 | break; | ||
126 | case TV_STD_PAL_CN: | ||
127 | args.ucTVStandard = ATOM_TV_PALCN; | ||
128 | break; | ||
129 | } | ||
130 | args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; | ||
131 | } else if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT)) { | ||
132 | args.ucTVStandard = ATOM_TV_CV; | ||
133 | args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; | ||
134 | } else { | ||
135 | switch (radeon_crtc->rmx_type) { | ||
136 | case RMX_FULL: | ||
137 | args.ucEnable = ATOM_SCALER_EXPANSION; | ||
138 | break; | ||
139 | case RMX_CENTER: | ||
140 | args.ucEnable = ATOM_SCALER_CENTER; | ||
141 | break; | ||
142 | case RMX_ASPECT: | ||
143 | args.ucEnable = ATOM_SCALER_EXPANSION; | ||
144 | break; | ||
145 | default: | ||
146 | if (ASIC_IS_AVIVO(rdev)) | ||
147 | args.ucEnable = ATOM_SCALER_DISABLE; | ||
148 | else | ||
149 | args.ucEnable = ATOM_SCALER_CENTER; | ||
150 | break; | ||
151 | } | ||
152 | } | ||
153 | atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); | ||
154 | if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT) | ||
155 | && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_RV570) { | ||
156 | atom_rv515_force_tv_scaler(rdev); | ||
157 | } | ||
158 | } | ||
159 | |||
34 | static void atombios_lock_crtc(struct drm_crtc *crtc, int lock) | 160 | static void atombios_lock_crtc(struct drm_crtc *crtc, int lock) |
35 | { | 161 | { |
36 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | 162 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
@@ -522,6 +648,9 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, | |||
522 | radeon_crtc_set_base(crtc, x, y, old_fb); | 648 | radeon_crtc_set_base(crtc, x, y, old_fb); |
523 | radeon_legacy_atom_set_surface(crtc); | 649 | radeon_legacy_atom_set_surface(crtc); |
524 | } | 650 | } |
651 | atombios_overscan_setup(crtc, mode, adjusted_mode); | ||
652 | atombios_scaler_setup(crtc); | ||
653 | radeon_bandwidth_update(rdev); | ||
525 | return 0; | 654 | return 0; |
526 | } | 655 | } |
527 | 656 | ||
@@ -529,6 +658,8 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, | |||
529 | struct drm_display_mode *mode, | 658 | struct drm_display_mode *mode, |
530 | struct drm_display_mode *adjusted_mode) | 659 | struct drm_display_mode *adjusted_mode) |
531 | { | 660 | { |
661 | if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) | ||
662 | return false; | ||
532 | return true; | 663 | return true; |
533 | } | 664 | } |
534 | 665 | ||
@@ -561,148 +692,3 @@ void radeon_atombios_init_crtc(struct drm_device *dev, | |||
561 | AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; | 692 | AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; |
562 | drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); | 693 | drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); |
563 | } | 694 | } |
564 | |||
565 | void radeon_init_disp_bw_avivo(struct drm_device *dev, | ||
566 | struct drm_display_mode *mode1, | ||
567 | uint32_t pixel_bytes1, | ||
568 | struct drm_display_mode *mode2, | ||
569 | uint32_t pixel_bytes2) | ||
570 | { | ||
571 | struct radeon_device *rdev = dev->dev_private; | ||
572 | fixed20_12 min_mem_eff; | ||
573 | fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff; | ||
574 | fixed20_12 sclk_ff, mclk_ff; | ||
575 | uint32_t dc_lb_memory_split, temp; | ||
576 | |||
577 | min_mem_eff.full = rfixed_const_8(0); | ||
578 | if (rdev->disp_priority == 2) { | ||
579 | uint32_t mc_init_misc_lat_timer = 0; | ||
580 | if (rdev->family == CHIP_RV515) | ||
581 | mc_init_misc_lat_timer = | ||
582 | RREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER); | ||
583 | else if (rdev->family == CHIP_RS690) | ||
584 | mc_init_misc_lat_timer = | ||
585 | RREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER); | ||
586 | |||
587 | mc_init_misc_lat_timer &= | ||
588 | ~(R300_MC_DISP1R_INIT_LAT_MASK << | ||
589 | R300_MC_DISP1R_INIT_LAT_SHIFT); | ||
590 | mc_init_misc_lat_timer &= | ||
591 | ~(R300_MC_DISP0R_INIT_LAT_MASK << | ||
592 | R300_MC_DISP0R_INIT_LAT_SHIFT); | ||
593 | |||
594 | if (mode2) | ||
595 | mc_init_misc_lat_timer |= | ||
596 | (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); | ||
597 | if (mode1) | ||
598 | mc_init_misc_lat_timer |= | ||
599 | (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); | ||
600 | |||
601 | if (rdev->family == CHIP_RV515) | ||
602 | WREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER, | ||
603 | mc_init_misc_lat_timer); | ||
604 | else if (rdev->family == CHIP_RS690) | ||
605 | WREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER, | ||
606 | mc_init_misc_lat_timer); | ||
607 | } | ||
608 | |||
609 | /* | ||
610 | * determine is there is enough bw for current mode | ||
611 | */ | ||
612 | temp_ff.full = rfixed_const(100); | ||
613 | mclk_ff.full = rfixed_const(rdev->clock.default_mclk); | ||
614 | mclk_ff.full = rfixed_div(mclk_ff, temp_ff); | ||
615 | sclk_ff.full = rfixed_const(rdev->clock.default_sclk); | ||
616 | sclk_ff.full = rfixed_div(sclk_ff, temp_ff); | ||
617 | |||
618 | temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1); | ||
619 | temp_ff.full = rfixed_const(temp); | ||
620 | mem_bw.full = rfixed_mul(mclk_ff, temp_ff); | ||
621 | mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); | ||
622 | |||
623 | pix_clk.full = 0; | ||
624 | pix_clk2.full = 0; | ||
625 | peak_disp_bw.full = 0; | ||
626 | if (mode1) { | ||
627 | temp_ff.full = rfixed_const(1000); | ||
628 | pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */ | ||
629 | pix_clk.full = rfixed_div(pix_clk, temp_ff); | ||
630 | temp_ff.full = rfixed_const(pixel_bytes1); | ||
631 | peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); | ||
632 | } | ||
633 | if (mode2) { | ||
634 | temp_ff.full = rfixed_const(1000); | ||
635 | pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */ | ||
636 | pix_clk2.full = rfixed_div(pix_clk2, temp_ff); | ||
637 | temp_ff.full = rfixed_const(pixel_bytes2); | ||
638 | peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); | ||
639 | } | ||
640 | |||
641 | if (peak_disp_bw.full >= mem_bw.full) { | ||
642 | DRM_ERROR | ||
643 | ("You may not have enough display bandwidth for current mode\n" | ||
644 | "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); | ||
645 | printk("peak disp bw %d, mem_bw %d\n", | ||
646 | rfixed_trunc(peak_disp_bw), rfixed_trunc(mem_bw)); | ||
647 | } | ||
648 | |||
649 | /* | ||
650 | * Line Buffer Setup | ||
651 | * There is a single line buffer shared by both display controllers. | ||
652 | * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between the display | ||
653 | * controllers. The paritioning can either be done manually or via one of four | ||
654 | * preset allocations specified in bits 1:0: | ||
655 | * 0 - line buffer is divided in half and shared between each display controller | ||
656 | * 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4 | ||
657 | * 2 - D1 gets the whole buffer | ||
658 | * 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4 | ||
659 | * Setting bit 2 of DC_LB_MEMORY_SPLIT controls switches to manual allocation mode. | ||
660 | * In manual allocation mode, D1 always starts at 0, D1 end/2 is specified in bits | ||
661 | * 14:4; D2 allocation follows D1. | ||
662 | */ | ||
663 | |||
664 | /* is auto or manual better ? */ | ||
665 | dc_lb_memory_split = | ||
666 | RREG32(AVIVO_DC_LB_MEMORY_SPLIT) & ~AVIVO_DC_LB_MEMORY_SPLIT_MASK; | ||
667 | dc_lb_memory_split &= ~AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE; | ||
668 | #if 1 | ||
669 | /* auto */ | ||
670 | if (mode1 && mode2) { | ||
671 | if (mode1->hdisplay > mode2->hdisplay) { | ||
672 | if (mode1->hdisplay > 2560) | ||
673 | dc_lb_memory_split |= | ||
674 | AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q; | ||
675 | else | ||
676 | dc_lb_memory_split |= | ||
677 | AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; | ||
678 | } else if (mode2->hdisplay > mode1->hdisplay) { | ||
679 | if (mode2->hdisplay > 2560) | ||
680 | dc_lb_memory_split |= | ||
681 | AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; | ||
682 | else | ||
683 | dc_lb_memory_split |= | ||
684 | AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; | ||
685 | } else | ||
686 | dc_lb_memory_split |= | ||
687 | AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; | ||
688 | } else if (mode1) { | ||
689 | dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY; | ||
690 | } else if (mode2) { | ||
691 | dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; | ||
692 | } | ||
693 | #else | ||
694 | /* manual */ | ||
695 | dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE; | ||
696 | dc_lb_memory_split &= | ||
697 | ~(AVIVO_DC_LB_DISP1_END_ADR_MASK << | ||
698 | AVIVO_DC_LB_DISP1_END_ADR_SHIFT); | ||
699 | if (mode1) { | ||
700 | dc_lb_memory_split |= | ||
701 | ((((mode1->hdisplay / 2) + 64) & AVIVO_DC_LB_DISP1_END_ADR_MASK) | ||
702 | << AVIVO_DC_LB_DISP1_END_ADR_SHIFT); | ||
703 | } else if (mode2) { | ||
704 | dc_lb_memory_split |= (0 << AVIVO_DC_LB_DISP1_END_ADR_SHIFT); | ||
705 | } | ||
706 | #endif | ||
707 | WREG32(AVIVO_DC_LB_MEMORY_SPLIT, dc_lb_memory_split); | ||
708 | } | ||