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 #include "pll_regs.h" 17 #include "pll_access.h" 18 19 20 void Radeon_ReadRMXRegisters( 21 accelerator_info *ai, fp_regs *values ) 22 { 23 vuint8 *regs = ai->regs; 24 25 values->fp_horz_stretch = INREG( regs, RADEON_FP_HORZ_STRETCH ); 26 values->fp_vert_stretch = INREG( regs, RADEON_FP_VERT_STRETCH ); 27 } 28 29 void Radeon_CalcRMXRegisters( 30 fp_info *flatpanel, display_mode *mode, bool use_rmx, fp_regs *values ) 31 { 32 uint xres = mode->timing.h_display; 33 uint yres = mode->timing.v_display; 34 uint64 Hratio, Vratio; 35 36 if( !use_rmx ) { 37 // disable RMX unit if requested 38 values->fp_horz_stretch &= 39 ~(RADEON_HORZ_STRETCH_BLEND | 40 RADEON_HORZ_STRETCH_ENABLE); 41 42 values->fp_vert_stretch &= 43 ~(RADEON_VERT_STRETCH_ENABLE | 44 RADEON_VERT_STRETCH_BLEND); 45 46 return; 47 } 48 49 // RMX unit can only upscale, not downscale 50 if( xres > flatpanel->panel_xres ) 51 xres = flatpanel->panel_xres; 52 if( yres > flatpanel->panel_yres ) 53 yres = flatpanel->panel_yres; 54 55 Hratio = FIX_SCALE * (uint32)xres / flatpanel->panel_xres; 56 Vratio = FIX_SCALE * (uint32)yres / flatpanel->panel_yres; 57 58 // save it for overlay unit (overlays must be vertically scaled manually) 59 flatpanel->h_ratio = Hratio; 60 flatpanel->v_ratio = Vratio; 61 62 values->fp_horz_stretch = flatpanel->panel_xres << RADEON_HORZ_PANEL_SIZE_SHIFT; 63 64 if( Hratio == FIX_SCALE ) { 65 values->fp_horz_stretch &= 66 ~(RADEON_HORZ_STRETCH_BLEND | 67 RADEON_HORZ_STRETCH_ENABLE); 68 } else { 69 uint32 stretch; 70 71 stretch = (uint32)((Hratio * RADEON_HORZ_STRETCH_RATIO_MAX + 72 FIX_SCALE / 2) >> FIX_SHIFT) & RADEON_HORZ_STRETCH_RATIO_MASK; 73 74 values->fp_horz_stretch = stretch 75 | (values->fp_horz_stretch & (RADEON_HORZ_PANEL_SIZE | 76 RADEON_HORZ_FP_LOOP_STRETCH | 77 RADEON_HORZ_AUTO_RATIO_INC)); 78 values->fp_horz_stretch |= 79 RADEON_HORZ_STRETCH_BLEND | 80 RADEON_HORZ_STRETCH_ENABLE; 81 } 82 values->fp_horz_stretch &= ~RADEON_HORZ_AUTO_RATIO; 83 84 values->fp_vert_stretch = flatpanel->panel_yres << RADEON_VERT_PANEL_SIZE_SHIFT; 85 86 if( Vratio == FIX_SCALE ) { 87 values->fp_vert_stretch &= 88 ~(RADEON_VERT_STRETCH_ENABLE | 89 RADEON_VERT_STRETCH_BLEND); 90 } else { 91 uint32 stretch; 92 93 stretch = (uint32)((Vratio * RADEON_VERT_STRETCH_RATIO_MAX + 94 FIX_SCALE / 2) >> FIX_SHIFT) & RADEON_VERT_STRETCH_RATIO_MASK; 95 96 values->fp_vert_stretch = stretch 97 | (values->fp_vert_stretch & (RADEON_VERT_PANEL_SIZE | 98 RADEON_VERT_STRETCH_RESERVED)); 99 values->fp_vert_stretch |= 100 RADEON_VERT_STRETCH_ENABLE | 101 RADEON_VERT_STRETCH_BLEND; 102 } 103 values->fp_vert_stretch &= ~RADEON_VERT_AUTO_RATIO_EN; 104 } 105 106 // write RMX registers 107 void Radeon_ProgramRMXRegisters( 108 accelerator_info *ai, fp_regs *values ) 109 { 110 vuint8 *regs = ai->regs; 111 SHOW_FLOW0( 2, "" ); 112 OUTREG( regs, RADEON_FP_HORZ_STRETCH, values->fp_horz_stretch ); 113 OUTREG( regs, RADEON_FP_VERT_STRETCH, values->fp_vert_stretch ); 114 } 115 116 117 void Radeon_ReadFPRegisters( 118 accelerator_info *ai, fp_regs *values ) 119 { 120 vuint8 *regs = ai->regs; 121 122 values->fp_gen_cntl = INREG( regs, RADEON_FP_GEN_CNTL ); 123 values->fp2_gen_cntl = INREG( regs, RADEON_FP2_GEN_CNTL ); 124 values->lvds_gen_cntl = INREG( regs, RADEON_LVDS_GEN_CNTL ); 125 values->tmds_pll_cntl = INREG( regs, RADEON_TMDS_PLL_CNTL ); 126 values->tmds_trans_cntl = INREG( regs, RADEON_TMDS_TRANSMITTER_CNTL ); 127 values->fp_h_sync_strt_wid = INREG( regs, RADEON_FP_H_SYNC_STRT_WID ); 128 values->fp_v_sync_strt_wid = INREG( regs, RADEON_FP_V_SYNC_STRT_WID ); 129 values->fp2_h_sync_strt_wid = INREG( regs, RADEON_FP_H2_SYNC_STRT_WID ); 130 values->fp2_v_sync_strt_wid = INREG( regs, RADEON_FP_V2_SYNC_STRT_WID ); 131 values->bios_4_scratch = INREG( regs, RADEON_BIOS_4_SCRATCH ); 132 values->bios_5_scratch = INREG( regs, RADEON_BIOS_5_SCRATCH ); 133 values->bios_6_scratch = INREG( regs, RADEON_BIOS_6_SCRATCH ); 134 135 if (ai->si->asic == rt_rv280) { 136 // bit 22 of TMDS_PLL_CNTL is read-back inverted 137 values->tmds_pll_cntl ^= (1 << 22); 138 } 139 140 SHOW_FLOW( 2, "before: fp_gen_cntl=%08lx, horz=%08lx, vert=%08lx, lvds_gen_cntl=%08lx", 141 values->fp_gen_cntl, values->fp_horz_stretch, values->fp_vert_stretch, 142 values->lvds_gen_cntl ); 143 } 144 145 // calculcate flat panel crtc registers; 146 // must be called after normal CRTC registers are determined 147 void Radeon_CalcFPRegisters( 148 accelerator_info *ai, crtc_info *crtc, 149 fp_info *fp_port, crtc_regs *crtc_values, fp_regs *values ) 150 { 151 int i; 152 uint32 tmp = values->tmds_pll_cntl & 0xfffff; 153 154 // setup synchronization position 155 // (most values are ignored according to fp_gen_cntl, but at least polarity 156 // and pixel precise horizontal sync position are always used) 157 if( fp_port->is_fp2 ) { 158 SHOW_FLOW0( 2, "is_fp2" ); 159 values->fp2_h_sync_strt_wid = crtc_values->crtc_h_sync_strt_wid; 160 values->fp2_v_sync_strt_wid = crtc_values->crtc_v_sync_strt_wid; 161 } else { 162 SHOW_FLOW0( 2, "fp1" ); 163 values->fp_h_sync_strt_wid = crtc_values->crtc_h_sync_strt_wid; 164 values->fp_v_sync_strt_wid = crtc_values->crtc_v_sync_strt_wid; 165 } 166 167 if( fp_port->is_fp2 ) { 168 // should retain POST values (esp bit 28) 169 values->fp2_gen_cntl &= (0xFFFF0000); 170 171 } else { 172 // setup magic CRTC shadowing 173 values->fp_gen_cntl &= 174 ~(RADEON_FP_RMX_HVSYNC_CONTROL_EN | 175 RADEON_FP_DFP_SYNC_SEL | 176 RADEON_FP_CRT_SYNC_SEL | 177 RADEON_FP_CRTC_LOCK_8DOT | 178 RADEON_FP_USE_SHADOW_EN | 179 RADEON_FP_CRTC_USE_SHADOW_VEND | 180 RADEON_FP_CRT_SYNC_ALT); 181 values->fp_gen_cntl |= 182 RADEON_FP_CRTC_DONT_SHADOW_VPAR | 183 RADEON_FP_CRTC_DONT_SHADOW_HEND; 184 } 185 186 for (i = 0; i < 4; i++) { 187 if (ai->si->tmds_pll[i].freq == 0) 188 break; 189 if ((uint32)(fp_port->dot_clock) < ai->si->tmds_pll[i].freq) { 190 tmp = ai->si->tmds_pll[i].value ; 191 break; 192 } 193 } 194 195 if (IS_R300_VARIANT || (ai->si->asic == rt_rv280)) { 196 if (tmp & 0xfff00000) { 197 values->tmds_pll_cntl = tmp; 198 } else { 199 values->tmds_pll_cntl = ai->si->tmds_pll_cntl & 0xfff00000; 200 values->tmds_pll_cntl |= tmp; 201 } 202 } else { 203 values->tmds_pll_cntl = tmp; 204 } 205 206 values->tmds_trans_cntl = ai->si->tmds_transmitter_cntl 207 & ~(RADEON_TMDS_TRANSMITTER_PLLRST); 208 209 if (IS_R300_VARIANT || (ai->si->asic == rt_r200) || (ai->si->num_crtc == 1)) 210 values->tmds_trans_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN); 211 else // weird, RV chips got this bit reversed? 212 values->tmds_trans_cntl |= (RADEON_TMDS_TRANSMITTER_PLLEN); 213 214 215 // enable proper transmitter 216 if( (crtc->chosen_displays & dd_lvds) != 0 ) { 217 // using LVDS means there cannot be a DVI monitor 218 SHOW_FLOW0( 2, "lvds" ); 219 values->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON); 220 values->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); 221 222 } else if( !fp_port->is_fp2 ) { 223 // DVI on internal transmitter 224 SHOW_FLOW0( 2, "DVI INT" ); 225 values->fp_gen_cntl |= RADEON_FP_FPON | RADEON_FP_TMDS_EN; 226 // enabling 8 bit data may be dangerous; BIOS should have taken care of that 227 values->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; 228 229 } else { 230 // DVI on external transmitter 231 SHOW_FLOW0( 2, "DVI EXT" ); 232 values->fp2_gen_cntl |= RADEON_FP2_FPON | RADEON_FP_PANEL_FORMAT; 233 values->fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN; 234 235 //hack in missing bits test... 236 //values->fp2_gen_cntl |= (1 << 22) | (1 << 28); 237 238 if( ai->si->asic >= rt_r200 ) 239 values->fp2_gen_cntl |= RADEON_FP2_DV0_EN; 240 } 241 242 SHOW_FLOW( 2, "after: fp_gen_cntl=%08lx, fp2_gen_cntl=%08lx, horz=%08lx, vert=%08lx, lvds_gen_cntl=%08lx", 243 values->fp_gen_cntl, values->fp2_gen_cntl, values->fp_horz_stretch, values->fp_vert_stretch, 244 values->lvds_gen_cntl ); 245 } 246 247 248 // write flat panel registers 249 void Radeon_ProgramFPRegisters( 250 accelerator_info *ai, crtc_info *crtc, 251 fp_info *fp_port, fp_regs *values ) 252 { 253 shared_info *si = ai->si; 254 vuint8 *regs = ai->regs; 255 256 SHOW_FLOW0( 2, "" ); 257 258 OUTREGP( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl, RADEON_FP_SEL_CRTC2 ); 259 260 if( fp_port->is_fp2 ) { 261 SHOW_FLOW0( 2, "is_fp2" ); 262 OUTREGP( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl, 263 ~(RADEON_FP2_SOURCE_SEL_MASK | RADEON_FP2_SRC_SEL_MASK)); 264 OUTREGP( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl, 265 RADEON_FP2_SOURCE_SEL_CRTC2 | RADEON_FP2_SRC_SEL_CRTC2 ); 266 OUTREG( regs, RADEON_FP_H2_SYNC_STRT_WID, values->fp2_h_sync_strt_wid ); 267 OUTREG( regs, RADEON_FP_V2_SYNC_STRT_WID, values->fp2_v_sync_strt_wid ); 268 } else { 269 SHOW_FLOW0( 2, "is_fp1" ); 270 OUTREG( regs, RADEON_FP_H_SYNC_STRT_WID, values->fp_h_sync_strt_wid ); 271 OUTREG( regs, RADEON_FP_V_SYNC_STRT_WID, values->fp_v_sync_strt_wid ); 272 } 273 274 // workaround for old AIW Radeon having display buffer underflow 275 // in conjunction with DVI 276 if( si->asic == rt_r100 ) { 277 OUTREG( regs, RADEON_GRPH_BUFFER_CNTL, 278 INREG( regs, RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000); 279 } 280 281 if ( ai->si->is_mobility ) { 282 OUTREG( regs, RADEON_BIOS_4_SCRATCH, values->bios_4_scratch); 283 OUTREG( regs, RADEON_BIOS_5_SCRATCH, values->bios_5_scratch); 284 OUTREG( regs, RADEON_BIOS_6_SCRATCH, values->bios_6_scratch); 285 } 286 287 if( (crtc->chosen_displays & dd_lvds) != 0 ) { 288 289 //OUTREGP( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl, 290 // RADEON_LVDS_ON | RADEON_LVDS_BLON ); 291 292 uint32 old_pixclks_cntl; 293 uint32 tmp; 294 295 old_pixclks_cntl = Radeon_INPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL); 296 297 // ASIC bug: when LVDS_ON is reset, LVDS_ALWAYS_ON must be zero 298 if( ai->si->is_mobility || ai->si->is_igp ) 299 { 300 if (!(values->lvds_gen_cntl & RADEON_LVDS_ON)) { 301 Radeon_OUTPLLP( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb ); 302 } 303 } 304 305 // get current state of LCD 306 tmp = INREG( regs, RADEON_LVDS_GEN_CNTL); 307 308 // if LCD is on, and previous state was on, just write the state directly. 309 if (( tmp & ( RADEON_LVDS_ON | RADEON_LVDS_BLON )) == 310 ( values->lvds_gen_cntl & ( RADEON_LVDS_ON | RADEON_LVDS_BLON ))) { 311 OUTREG( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl ); 312 } else { 313 if ( values->lvds_gen_cntl & ( RADEON_LVDS_ON | RADEON_LVDS_BLON )) { 314 snooze( ai->si->panel_pwr_delay * 1000 ); 315 OUTREG( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl ); 316 } else { 317 318 //turn on backlight, wait for stable before turning on data ??? 319 OUTREG( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl | RADEON_LVDS_BLON ); 320 snooze( ai->si->panel_pwr_delay * 1000 ); 321 OUTREG( regs, RADEON_LVDS_GEN_CNTL, values->lvds_gen_cntl ); 322 } 323 } 324 325 if( ai->si->is_mobility || ai->si->is_igp ) { 326 if (!(values->lvds_gen_cntl & RADEON_LVDS_ON)) { 327 Radeon_OUTPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, old_pixclks_cntl ); 328 } 329 } 330 } 331 } 332