1 /* 2 Copyright (c) 2002-2004, Thomas Kurschel 3 4 5 Part of Radeon accelerant 6 7 Sets display modes, colour palette and handles DPMS 8 */ 9 10 11 #include "GlobalData.h" 12 #include "generic.h" 13 #include <sys/ioctl.h> 14 #include "radeon_regs.h" 15 #include "mmio.h" 16 #include "crtc_regs.h" 17 #include <GraphicsDefs.h> 18 19 #include "crtc_regs.h" 20 #include "overlay_regs.h" 21 #include "rbbm_regs.h" 22 #include "dac_regs.h" 23 24 #include "set_mode.h" 25 26 #include <string.h> 27 28 29 // round virtual width up to next valid size 30 uint32 Radeon_RoundVWidth( 31 int virtual_width, int bpp ) 32 { 33 // we have to make both the CRTC and the accelerator happy: 34 // - the CRTC wants virtual width in pixels to be a multiple of 8 35 // - the accelerator expects width in bytes to be a multiple of 64 36 37 // to put that together, width (in bytes) must be a multiple of the least 38 // common nominator of bytes-per-pixel*8 (CRTC) and 64 (accelerator); 39 40 // if bytes-per-pixel is a power of two and less than 8, the LCM is 64; 41 // almost all colour depth satisfy that apart from 24 bit; in this case, 42 // the LCM is 64*3=192 43 44 // after dividing by bytes-per-pixel we get pixels: in first case, 45 // width must be multiple of 64/bytes-per-pixel; in second case, 46 // width must be multiple of 64*3/3=64 47 48 if( bpp != 3 ) 49 return (virtual_width + 64/bpp - 1) & ~(64/bpp - 1); 50 else 51 return (virtual_width + 63) & ~63; 52 } 53 54 55 // list of registers that must be reset before display mode switch 56 // to avoid interferences 57 static struct { 58 uint16 reg; 59 uint32 val; 60 } common_regs[] = { 61 { RADEON_OVR_CLR, 0 }, 62 { RADEON_OVR_WID_LEFT_RIGHT, 0 }, 63 { RADEON_OVR_WID_TOP_BOTTOM, 0 }, 64 { RADEON_OV0_SCALE_CNTL, 0 }, // disable overlay 65 { RADEON_SUBPIC_CNTL, 0 }, 66 { RADEON_I2C_CNTL_1, 0 }, 67 }; 68 69 70 static void Radeon_InitCommonRegs( 71 accelerator_info *ai ) 72 { 73 vuint8 *regs = ai->regs; 74 uint i; 75 76 for( i = 0; i < sizeof( common_regs) / sizeof( common_regs[0] ); ++i ) 77 OUTREG( regs, common_regs[i].reg, common_regs[i].val ); 78 79 // enable extended display modes 80 OUTREGP( regs, RADEON_CRTC_GEN_CNTL, 81 RADEON_CRTC_EXT_DISP_EN, ~RADEON_CRTC_EXT_DISP_EN ); 82 83 // disable flat panel auto-centering 84 // (if we have a CRT on CRTC1, this must be disabled; 85 // if we have a flat panel on CRTC1, we setup CRTC manually, not 86 // using the auto-centre, automatic-sync-override magic) 87 OUTREG( regs, RADEON_CRTC_MORE_CNTL, 0 ); 88 } 89 90 91 // set display mode of one head; 92 // port restrictions, like fixed-sync TFTs connected to it, are taken care of 93 void Radeon_SetMode( 94 accelerator_info *ai, crtc_info *crtc, display_mode *mode, impactv_params *tv_params ) 95 { 96 virtual_card *vc = ai->vc; 97 shared_info *si = ai->si; 98 vuint8 *regs = ai->regs; 99 int format; 100 int bpp; 101 display_device_e disp_devices; 102 fp_info *fp_info; 103 104 crtc_regs crtc_values; 105 pll_regs pll_values; 106 fp_regs fp_values; 107 impactv_regs impactv_values; 108 uint32 surface_cntl; 109 110 bool internal_tv_encoder; 111 pll_dividers dividers; 112 113 crtc->mode = *mode; 114 115 // don't destroy passed values, use our copy instead 116 mode = &crtc->mode; 117 118 disp_devices = crtc->chosen_displays; 119 fp_info = &si->flatpanels[crtc->flatpanel_port]; 120 121 // if using an flat panel or LCD, maximum resolution 122 // is determined by the physical resolution; 123 // also, all timing is fixed 124 if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 ) { 125 if( mode->timing.h_display > fp_info->panel_xres ) 126 mode->timing.h_display = fp_info->panel_xres; 127 if( mode->timing.v_display > fp_info->panel_yres ) 128 mode->timing.v_display = fp_info->panel_yres; 129 130 mode->timing.h_total = mode->timing.h_display + fp_info->h_blank; 131 mode->timing.h_sync_start = mode->timing.h_display + fp_info->h_over_plus; 132 mode->timing.h_sync_end = mode->timing.h_sync_start + fp_info->h_sync_width; 133 mode->timing.v_total = mode->timing.v_display + fp_info->v_blank; 134 mode->timing.v_sync_start = mode->timing.v_display + fp_info->v_over_plus; 135 mode->timing.v_sync_end = mode->timing.v_sync_start + fp_info->v_sync_width; 136 137 mode->timing.pixel_clock = fp_info->dot_clock; 138 } 139 140 // TV-out supports at most 1024x768 141 if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) { 142 if( mode->timing.h_display > 1024 ) 143 mode->timing.h_display = 1024; 144 145 if( mode->timing.v_display > 768 ) 146 mode->timing.v_display = 768; 147 } 148 149 // if using TV-Out, the timing of the source signal must be tweaked to 150 // get proper timing 151 internal_tv_encoder = IS_INTERNAL_TV_OUT( si->tv_chip ); 152 153 // we need higher accuracy then Be thought of 154 mode->timing.pixel_clock *= 1000; 155 156 // TV stuff must be done first as it tweaks the display mode 157 if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) { 158 display_mode tweaked_mode; 159 160 Radeon_CalcImpacTVParams( 161 &si->pll, tv_params, vc->tv_standard, internal_tv_encoder, 162 mode, &tweaked_mode ); 163 164 *mode = tweaked_mode; 165 } 166 167 Radeon_GetFormat( mode->space, &format, &bpp ); 168 169 vc->bpp = bpp; 170 vc->datatype = format; 171 172 // time to read original register content 173 // lock hardware so noone bothers us 174 Radeon_WaitForIdle( ai, true ); 175 176 if( (disp_devices & (dd_dvi | dd_lvds | dd_dvi_ext)) != 0 ) { 177 if( crtc->crtc_idx == 0 ) 178 Radeon_ReadRMXRegisters( ai, &fp_values ); 179 180 Radeon_ReadFPRegisters( ai, &fp_values ); 181 } 182 183 if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) { 184 // some register's content isn't created from scratch but 185 // only modified, so we need the original content first 186 if( internal_tv_encoder ) 187 Radeon_InternalTVOutReadRegisters( ai, &impactv_values ); 188 else 189 Radeon_TheatreReadTVRegisters( ai, &impactv_values ); 190 } 191 192 193 // calculate all hardware register values 194 Radeon_CalcCRTCRegisters( ai, crtc, mode, &crtc_values ); 195 196 surface_cntl = RADEON_SURF_TRANSLATION_DIS; 197 198 if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) { 199 Radeon_CalcImpacTVRegisters( ai, mode, tv_params, &impactv_values, 200 crtc->crtc_idx, internal_tv_encoder, vc->tv_standard, disp_devices ); 201 } 202 203 if( (disp_devices & (dd_stv | dd_ctv)) == 0 ) 204 Radeon_CalcCRTPLLDividers( &si->pll, mode, ÷rs ); 205 else 206 dividers = tv_params->crt_dividers; 207 208 if( (disp_devices & dd_lvds) != 0 && si->flatpanels[0].fixed_dividers ) { 209 SHOW_FLOW0( 0, "Using fixed dividers for laptop panel" ); 210 dividers.feedback = si->flatpanels[0].feedback_div; 211 dividers.post_code = si->flatpanels[0].post_div; 212 dividers.ref = si->flatpanels[0].ref_div; 213 } 214 215 Radeon_CalcPLLRegisters( mode, ÷rs, &pll_values ); 216 217 // for first CRTC1, we need to setup RMX properly 218 if( crtc->crtc_idx == 0 ) 219 Radeon_CalcRMXRegisters( fp_info, mode, 220 (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0, 221 &fp_values ); 222 223 if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 ) 224 Radeon_CalcFPRegisters( ai, crtc, fp_info, &crtc_values, &fp_values ); 225 226 // we don't use pixel clock anymore, so it can be reset to Be's kHz 227 mode->timing.pixel_clock /= 1000; 228 229 // write values to registers 230 231 Radeon_InitCommonRegs( ai ); 232 233 Radeon_ProgramCRTCRegisters( ai, crtc->crtc_idx, &crtc_values ); 234 235 OUTREG( regs, RADEON_SURFACE_CNTL, surface_cntl ); 236 237 if( crtc->crtc_idx == 0 ) 238 Radeon_ProgramRMXRegisters( ai, &fp_values ); 239 240 if( (disp_devices & (dd_lvds | dd_dvi | dd_dvi_ext)) != 0 ) 241 Radeon_ProgramFPRegisters( ai, crtc, fp_info, &fp_values ); 242 243 //if( mode->timing.pixel_clock ) 244 Radeon_ProgramPLL( ai, crtc->crtc_idx, &pll_values ); 245 246 if( (disp_devices & (dd_ctv | dd_stv)) != 0 ) { 247 if( internal_tv_encoder ) 248 Radeon_InternalTVOutProgramRegisters( ai, &impactv_values ); 249 else 250 Radeon_TheatreProgramTVRegisters( ai, &impactv_values ); 251 } 252 253 crtc->active_displays = disp_devices; 254 255 // programming is over, so hardware can be used again 256 RELEASE_BEN( si->cp.lock ); 257 258 // overlay must be setup again after modeswitch (whoever was using it) 259 // TBD: this won't work if another virtual card was using it, 260 // but currently, virtual cards don't work anyway... 261 si->active_overlay.crtc_idx = -1; 262 } 263 264 265 // enable or disable VBlank interrupts 266 void Radeon_EnableIRQ( 267 accelerator_info *ai, bool enable ) 268 { 269 shared_info *si = ai->si; 270 uint32 int_cntl, int_mask; 271 272 int_cntl = INREG( ai->regs, RADEON_GEN_INT_CNTL ); 273 int_mask = 274 RADEON_CRTC_VBLANK_MASK 275 | (si->num_crtc > 1 ? RADEON_CRTC2_VBLANK_MASK : 0); 276 277 if( enable ) 278 int_cntl |= int_mask; 279 else 280 int_cntl &= ~int_mask; 281 282 OUTREG( ai->regs, RADEON_GEN_INT_CNTL, int_cntl ); 283 284 if( enable ) { 285 // on enable, we have to acknowledge all IRQs as the graphics card 286 // waits for that before it issues further IRQs 287 OUTREG( ai->regs, RADEON_GEN_INT_STATUS, int_cntl ); 288 } 289 290 si->enable_virtual_irq = enable; 291 } 292 293 294 // public function: set display mode 295 status_t SET_DISPLAY_MODE( 296 display_mode *mode_in ) 297 { 298 virtual_card *vc = ai->vc; 299 shared_info *si = ai->si; 300 display_mode bounds, mode; 301 302 mode = bounds = *mode_in; 303 304 ACQUIRE_BEN( si->engine.lock ); 305 306 SHOW_FLOW( 2, "width=%d, height=%d", mode.timing.h_display, mode.timing.v_display ); 307 308 // check mode and tweak parameters so we can program hardware 309 // without any further checks 310 if( PROPOSE_DISPLAY_MODE( &mode, &bounds, &bounds ) == B_ERROR ) { 311 SHOW_ERROR0( 2, "invalid mode" ); 312 313 RELEASE_BEN( si->engine.lock ); 314 return B_ERROR; 315 } 316 317 // already done by propose_display_mode, but it was undone on return; 318 // do this before equality check to recognize changes of multi-monitor mode 319 Radeon_DetectMultiMode( vc, &mode ); 320 321 // mode switches can take quite long and are visible, 322 // so avoid them if possible 323 if( memcmp( &mode, &vc->mode, sizeof( display_mode )) == 0 && 324 !vc->enforce_mode_change ) { 325 RELEASE_BEN( si->engine.lock ); 326 return B_OK; 327 } 328 329 // this flag was set when some internal parameter has changed that 330 // affects effective display mode 331 vc->enforce_mode_change = false; 332 333 // make sure, we don't get disturbed 334 //Radeon_Finish( ai ); 335 Radeon_EnableIRQ( ai, false ); 336 337 // free cursor and framebuffer memory 338 { 339 radeon_free_mem fm; 340 341 fm.magic = RADEON_PRIVATE_DATA_MAGIC; 342 fm.memory_type = mt_local; 343 fm.global = true; 344 345 if( vc->cursor.mem_handle ) { 346 fm.handle = vc->cursor.mem_handle; 347 ioctl( ai->fd, RADEON_FREE_MEM, &fm ); 348 } 349 350 if( vc->fb_mem_handle ) { 351 fm.handle = vc->fb_mem_handle; 352 ioctl( ai->fd, RADEON_FREE_MEM, &fm ); 353 } 354 } 355 356 memcpy( &vc->mode, &mode, sizeof( display_mode )); 357 358 // verify hardware restrictions *after* saving mode 359 // e.g. if you want a span mode but have one monitor disconnected, 360 // configuration shouldn't be touched, so you can continue working 361 // with two monitors later on just like nothing has happened 362 Radeon_VerifyMultiMode( vc, si, &mode ); 363 364 // set main flags 365 vc->independant_heads = vc->assigned_crtc[0] && si->crtc[0].chosen_displays != dd_none; 366 367 if( si->num_crtc > 1 ) 368 vc->independant_heads += vc->assigned_crtc[1] && si->crtc[1].chosen_displays != dd_none; 369 370 vc->different_heads = Radeon_DifferentPorts( &mode ); 371 SHOW_FLOW( 2, "independant heads: %d, different heads: %d", 372 vc->independant_heads, vc->different_heads ); 373 vc->scroll = mode.flags & B_SCROLL; 374 SHOW_FLOW( 2, "scrolling %s", vc->scroll ? "enabled" : "disabled" ); 375 376 // allocate frame buffer and cursor image memory 377 { 378 radeon_alloc_mem am; 379 int format, bpp; 380 381 // alloc cursor memory 382 am.magic = RADEON_PRIVATE_DATA_MAGIC; 383 am.size = 1024; 384 am.memory_type = mt_local; 385 am.global = true; 386 387 if( ioctl( ai->fd, RADEON_ALLOC_MEM, &am ) == B_OK ) { 388 vc->cursor.mem_handle = am.handle; 389 vc->cursor.fb_offset = am.offset; 390 } else { 391 // too bad that we are out of mem -> set reasonable values as 392 // it's too late to give up (ouch!) 393 SHOW_ERROR0( 2, "no memory for cursor image!" ); 394 vc->cursor.mem_handle = 0; 395 vc->cursor.fb_offset = 0; 396 } 397 398 vc->cursor.data = si->local_mem + vc->cursor.fb_offset; 399 400 // alloc frame buffer 401 Radeon_GetFormat( mode.space, &format, &bpp ); 402 vc->pitch = Radeon_RoundVWidth( mode.virtual_width, bpp ) * bpp; 403 am.size = vc->pitch * mode.virtual_height; 404 405 if( ioctl( ai->fd, RADEON_ALLOC_MEM, &am ) == B_OK ) { 406 vc->fb_mem_handle = am.handle; 407 vc->fb_offset = am.offset; 408 } else { 409 // ouch again - set reasonable values 410 SHOW_ERROR0( 2, "no memory for frame buffer!" ); 411 vc->fb_mem_handle = 0; 412 vc->fb_offset = 1024; 413 } 414 415 vc->fbc.frame_buffer = si->local_mem + vc->fb_offset; 416 vc->fbc.frame_buffer_dma = (void *)((uint8 *)si->framebuffer_pci + vc->fb_offset); 417 vc->fbc.bytes_per_row = vc->pitch; 418 419 SHOW_FLOW( 0, "frame buffer CPU-address=%x, phys-address=%x", 420 vc->fbc.frame_buffer, vc->fbc.frame_buffer_dma ); 421 } 422 423 // multi-screen stuff 424 Radeon_InitMultiModeVars( ai, &mode ); 425 426 // GO! 427 428 { 429 routing_regs routing_values; 430 impactv_params tv_params; 431 432 // we first switch off all output, so the monitor(s) won't get invalid signals 433 if( vc->assigned_crtc[0] ) { 434 // overwrite list of active displays to switch off displays 435 // someone else turned on 436 si->crtc[0].active_displays = vc->controlled_displays; 437 Radeon_SetDPMS( ai, 0, B_DPMS_SUSPEND ); 438 } 439 if( vc->assigned_crtc[1] ) { 440 si->crtc[1].active_displays = vc->controlled_displays; 441 Radeon_SetDPMS( ai, 1, B_DPMS_SUSPEND ); 442 } 443 444 // mark crtc that will be used from now on 445 vc->used_crtc[0] = vc->assigned_crtc[0] && si->crtc[0].chosen_displays != dd_none; 446 vc->used_crtc[1] = vc->assigned_crtc[1] && si->crtc[1].chosen_displays != dd_none; 447 448 // then change the mode 449 if( vc->used_crtc[0] ) 450 Radeon_SetMode( ai, &si->crtc[0], &mode, &tv_params ); 451 if( vc->used_crtc[1] ) 452 Radeon_SetMode( ai, &si->crtc[1], &mode, &tv_params ); 453 454 // setup signal routing 455 Radeon_ReadMonitorRoutingRegs( ai, &routing_values ); 456 Radeon_CalcMonitorRouting( ai, &tv_params, &routing_values ); 457 Radeon_ProgramMonitorRouting( ai, &routing_values ); 458 459 // finally, switch display(s) on 460 if( vc->used_crtc[0] ) 461 Radeon_SetDPMS( ai, 0, B_DPMS_ON ); 462 if( vc->used_crtc[1] ) 463 Radeon_SetDPMS( ai, 1, B_DPMS_ON ); 464 465 OUTREGP( ai->regs, RADEON_CRTC_EXT_CNTL, 0, ~RADEON_CRTC_DISPLAY_DIS ); 466 } 467 468 SHOW_FLOW( 3, "pitch=%ld", vc->pitch ); 469 470 // we'll modify bits of this reg, so save it for async access 471 si->dac_cntl2 = INREG( ai->regs, RADEON_DAC_CNTL2 ); 472 473 // setup 2D registers 474 Radeon_Init2D( ai ); 475 // setup position of framebuffer for 2D commands 476 Radeon_FillStateBuffer( ai, vc->datatype ); 477 478 // remember that 2D accelerator is not prepared for any virtual card 479 si->active_vc = -1; 480 481 // first move to well-defined position (to setup CRTC offset) 482 Radeon_MoveDisplay( ai, 0, 0 ); 483 // then to (probably faulty) user-defined pos 484 Radeon_MoveDisplay( ai, mode.h_display_start, mode.v_display_start ); 485 486 // set standard palette in direct-colour modes 487 if( vc->used_crtc[0] ) 488 Radeon_InitPalette( ai, 0 ); 489 if( vc->used_crtc[1] ) 490 Radeon_InitPalette( ai, 1 ); 491 492 // initialize cursor data 493 if( vc->used_crtc[0] ) 494 Radeon_SetCursorColors( ai, 0 ); 495 if( vc->used_crtc[1] ) 496 Radeon_SetCursorColors( ai, 1 ); 497 498 // sync should be settled now, so we can reenable IRQs 499 Radeon_EnableIRQ( ai, true ); 500 501 RELEASE_BEN( si->engine.lock ); 502 503 // !! all this must be done after lock has been 504 // released to avoid dead-lock !! 505 // TBD: any invalid intermediate states? 506 507 // move_cursor sets all cursor-related variables and registers 508 vc->cursor.is_visible = false; 509 MOVE_CURSOR( 0, 0 ); 510 511 return B_OK; 512 } 513