1 /* 2 Copyright (c) 2002-2004, Thomas Kurschel 3 4 5 Part of Radeon accelerant 6 7 Flat panel support 8 */ 9 10 #include "radeon_accelerant.h" 11 #include "mmio.h" 12 #include "fp_regs.h" 13 #include "memcntrl_regs.h" 14 #include "utils.h" 15 #include "set_mode.h" 16 17 18 void Radeon_ReadRMXRegisters( 19 accelerator_info *ai, fp_regs *values ) 20 { 21 vuint8 *regs = ai->regs; 22 23 values->fp_horz_stretch = INREG( regs, RADEON_FP_HORZ_STRETCH ); 24 values->fp_vert_stretch = INREG( regs, RADEON_FP_VERT_STRETCH ); 25 } 26 27 void Radeon_CalcRMXRegisters( 28 fp_info *flatpanel, display_mode *mode, bool use_rmx, fp_regs *values ) 29 { 30 uint xres = mode->timing.h_display; 31 uint yres = mode->timing.v_display; 32 uint64 Hratio, Vratio; 33 34 if( !use_rmx ) { 35 // disable RMX unit if requested 36 values->fp_horz_stretch &= 37 ~(RADEON_HORZ_STRETCH_BLEND | 38 RADEON_HORZ_STRETCH_ENABLE); 39 40 values->fp_vert_stretch &= 41 ~(RADEON_VERT_STRETCH_ENABLE | 42 RADEON_VERT_STRETCH_BLEND); 43 44 return; 45 } 46 47 // RMX unit can only upscale, not downscale 48 if( xres > flatpanel->panel_xres ) 49 xres = flatpanel->panel_xres; 50 if( yres > flatpanel->panel_yres ) 51 yres = flatpanel->panel_yres; 52 53 Hratio = FIX_SCALE * (uint32)xres / flatpanel->panel_xres; 54 Vratio = FIX_SCALE * (uint32)yres / flatpanel->panel_yres; 55 56 // save it for overlay unit (overlays must be vertically scaled manually) 57 flatpanel->h_ratio = Hratio; 58 flatpanel->v_ratio = Vratio; 59 60 values->fp_horz_stretch = flatpanel->panel_xres << RADEON_HORZ_PANEL_SIZE_SHIFT; 61 62 if( Hratio == FIX_SCALE ) { 63 values->fp_horz_stretch &= 64 ~(RADEON_HORZ_STRETCH_BLEND | 65 RADEON_HORZ_STRETCH_ENABLE); 66 } else { 67 uint32 stretch; 68 69 stretch = (uint32)((Hratio * RADEON_HORZ_STRETCH_RATIO_MAX + 70 FIX_SCALE / 2) >> FIX_SHIFT) & RADEON_HORZ_STRETCH_RATIO_MASK; 71 72 values->fp_horz_stretch = stretch 73 | (values->fp_horz_stretch & (RADEON_HORZ_PANEL_SIZE | 74 RADEON_HORZ_FP_LOOP_STRETCH | 75 RADEON_HORZ_AUTO_RATIO_INC)); 76 values->fp_horz_stretch |= 77 RADEON_HORZ_STRETCH_BLEND | 78 RADEON_HORZ_STRETCH_ENABLE; 79 } 80 values->fp_horz_stretch &= ~RADEON_HORZ_AUTO_RATIO; 81 82 values->fp_vert_stretch = flatpanel->panel_yres << RADEON_VERT_PANEL_SIZE_SHIFT; 83 84 if( Vratio == FIX_SCALE ) { 85 values->fp_vert_stretch &= 86 ~(RADEON_VERT_STRETCH_ENABLE | 87 RADEON_VERT_STRETCH_BLEND); 88 } else { 89 uint32 stretch; 90 91 stretch = (uint32)((Vratio * RADEON_VERT_STRETCH_RATIO_MAX + 92 FIX_SCALE / 2) >> FIX_SHIFT) & RADEON_VERT_STRETCH_RATIO_MASK; 93 94 values->fp_vert_stretch = stretch 95 | (values->fp_vert_stretch & (RADEON_VERT_PANEL_SIZE | 96 RADEON_VERT_STRETCH_RESERVED)); 97 values->fp_vert_stretch |= 98 RADEON_VERT_STRETCH_ENABLE | 99 RADEON_VERT_STRETCH_BLEND; 100 } 101 values->fp_vert_stretch &= ~RADEON_VERT_AUTO_RATIO_EN; 102 } 103 104 // write RMX registers 105 void Radeon_ProgramRMXRegisters( 106 accelerator_info *ai, fp_regs *values ) 107 { 108 vuint8 *regs = ai->regs; 109 110 OUTREG( regs, RADEON_FP_HORZ_STRETCH, values->fp_horz_stretch ); 111 OUTREG( regs, RADEON_FP_VERT_STRETCH, values->fp_vert_stretch ); 112 } 113 114 115 void Radeon_ReadFPRegisters( 116 accelerator_info *ai, fp_regs *values ) 117 { 118 vuint8 *regs = ai->regs; 119 120 values->fp_gen_cntl = INREG( regs, RADEON_FP_GEN_CNTL ); 121 values->fp2_gen_cntl = INREG( regs, RADEON_FP2_GEN_CNTL ); 122 values->lvds_gen_cntl = INREG( regs, RADEON_LVDS_GEN_CNTL ); 123 values->fp_h_sync_strt_wid = INREG( regs, RADEON_FP_H_SYNC_STRT_WID ); 124 values->fp_v_sync_strt_wid = INREG( regs, RADEON_FP_V_SYNC_STRT_WID ); 125 values->fp2_h_sync_strt_wid = INREG( regs, RADEON_FP_H2_SYNC_STRT_WID ); 126 values->fp2_v_sync_strt_wid = INREG( regs, RADEON_FP_V2_SYNC_STRT_WID ); 127 128 SHOW_FLOW( 2, "before: fp_gen_cntl=%lx, horz=%lx, vert=%lx, lvds_gen_cntl=%lx", 129 values->fp_gen_cntl, values->fp_horz_stretch, values->fp_vert_stretch, 130 values->lvds_gen_cntl ); 131 } 132 133 // calculcate flat panel crtc registers; 134 // must be called after normal CRTC registers are determined 135 void Radeon_CalcFPRegisters( 136 accelerator_info *ai, crtc_info *crtc, 137 fp_info *fp_port, crtc_regs *crtc_values, fp_regs *values ) 138 { 139 // setup synchronization position 140 // (most values are ignored according to fp_gen_cntl, but at least polarity 141 // and pixel precise horizontal sync position are always used) 142 if( fp_port->is_fp2 ) { 143 values->fp2_h_sync_strt_wid = crtc_values->crtc_h_sync_strt_wid; 144 values->fp2_v_sync_strt_wid = crtc_values->crtc_v_sync_strt_wid; 145 } else { 146 values->fp_h_sync_strt_wid = crtc_values->crtc_h_sync_strt_wid; 147 values->fp_v_sync_strt_wid = crtc_values->crtc_v_sync_strt_wid; 148 } 149 150 if( fp_port->is_fp2 ) 151 values->fp2_gen_cntl = 0; 152 else { 153 // setup magic CRTC shadowing 154 values->fp_gen_cntl &= 155 ~(RADEON_FP_RMX_HVSYNC_CONTROL_EN | 156 RADEON_FP_DFP_SYNC_SEL | 157 RADEON_FP_CRT_SYNC_SEL | 158 RADEON_FP_CRTC_LOCK_8DOT | 159 RADEON_FP_USE_SHADOW_EN | 160 RADEON_FP_CRTC_USE_SHADOW_VEND | 161 RADEON_FP_CRT_SYNC_ALT); 162 values->fp_gen_cntl |= 163 RADEON_FP_CRTC_DONT_SHADOW_VPAR | 164 RADEON_FP_CRTC_DONT_SHADOW_HEND; 165 } 166 167 // enable proper transmitter 168 if( (crtc->chosen_displays & dd_lvds) != 0 ) { 169 // using LVDS means there cannot be a DVI monitor 170 values->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON); 171 values->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); 172 173 } else if( !fp_port->is_fp2 ) { 174 // DVI on internal transmitter 175 values->fp_gen_cntl |= RADEON_FP_FPON | RADEON_FP_TMDS_EN; 176 // enabling 8 bit data may be dangerous; BIOS should have taken care of that 177 values->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; 178 179 } else { 180 // DVI on external transmitter 181 values->fp2_gen_cntl |= RADEON_FP2_FPON | RADEON_FP_PANEL_FORMAT; 182 values->fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN; 183 184 if( ai->si->asic >= rt_r200 ) 185 values->fp2_gen_cntl |= RADEON_FP2_DV0_EN; 186 } 187 188 SHOW_FLOW( 2, "after: fp_gen_cntl=%lx, horz=%lx, vert=%lx, lvds_gen_cntl=%lx", 189 values->fp_gen_cntl, values->fp_horz_stretch, values->fp_vert_stretch, 190 values->lvds_gen_cntl ); 191 } 192 193 194 // write flat panel registers 195 void Radeon_ProgramFPRegisters( 196 accelerator_info *ai, crtc_info *crtc, 197 fp_info *fp_port, fp_regs *values ) 198 { 199 shared_info *si = ai->si; 200 vuint8 *regs = ai->regs; 201 202 SHOW_FLOW0( 2, "" ); 203 204 OUTREGP( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl, RADEON_FP_SEL_CRTC2 ); 205 206 if( fp_port->is_fp2 ) { 207 OUTREGP( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl, 208 RADEON_FP2_SOURCE_SEL_CRTC2 | RADEON_FP2_SRC_SEL_CRTC2 ); 209 OUTREG( regs, RADEON_FP_H2_SYNC_STRT_WID, values->fp2_h_sync_strt_wid ); 210 OUTREG( regs, RADEON_FP_V2_SYNC_STRT_WID, values->fp2_v_sync_strt_wid ); 211 } else { 212 OUTREG( regs, RADEON_FP_H_SYNC_STRT_WID, values->fp_h_sync_strt_wid ); 213 OUTREG( regs, RADEON_FP_V_SYNC_STRT_WID, values->fp_v_sync_strt_wid ); 214 } 215 216 // workaround for old AIW Radeon having display buffer underflow 217 // in conjunction with DVI 218 if( si->asic == rt_r100 ) { 219 OUTREG( regs, RADEON_GRPH_BUFFER_CNTL, 220 INREG( regs, RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000); 221 } 222 223 if( (crtc->chosen_displays & dd_lvds) != 0 ) { 224 OUTREGP( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl, 225 RADEON_LVDS_ON | RADEON_LVDS_BLON ); 226 } 227 } 228