1 /* 2 Copyright (c) 2002, 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 "overlay_regs.h" 20 #include "capture_regs.h" 21 #include "rbbm_regs.h" 22 #include "dac_regs.h" 23 24 #include <string.h> 25 26 void Radeon_SetMode( accelerator_info *ai, virtual_port *port, display_mode *mode ); 27 void Radeon_EnableIRQ( accelerator_info *ai, bool enable ); 28 29 30 // Radeon's DACs share same public registers, this function 31 // selects the DAC you'll talk to 32 static void selectDAC( accelerator_info *ai, virtual_port *port ) 33 { 34 Radeon_WriteRegCP( ai, RADEON_DAC_CNTL2, 35 (port->is_crtc2 ? RADEON_DAC2_PALETTE_ACC_CTL : 0) | 36 (ai->si->dac_cntl2 & ~RADEON_DAC2_PALETTE_ACC_CTL) ); 37 } 38 39 40 // set standard colour palette (needed for non-palette modes) 41 static void initDAC( accelerator_info *ai, virtual_port *port ) 42 { 43 int i; 44 45 selectDAC( ai, port ); 46 47 Radeon_WriteRegCP( ai, RADEON_PALETTE_INDEX, 0 ); 48 49 for( i = 0; i < 256; ++i ) 50 Radeon_WriteRegCP( ai, RADEON_PALETTE_DATA, (i << 16) | (i << 8) | i ); 51 } 52 53 54 55 // round virtual width up to next valid size 56 uint32 Radeon_RoundVWidth( int virtual_width, int bpp ) 57 { 58 // we have to make both the CRTC and the accelerator happy: 59 // - the CRTC wants virtual width in pixels to be a multiple of 8 60 // - the accelerator expects width in bytes to be a multiple of 64 61 62 // to put that together, width (in bytes) must be a multiple of the least 63 // common nominator of bytes-per-pixel*8 (CRTC) and 64 (accelerator); 64 65 // if bytes-per-pixel is a power of two and less than 8, the LCM is 64; 66 // almost all colour depth satisfy that apart from 24 bit; in this case, 67 // the LCM is 64*3=192 68 69 // after dividing by bytes-per-pixel we get pixels: in first case, 70 // width must be multiple of 64/bytes-per-pixel; in second case, 71 // width must be multiple of 64*3/3=64 72 73 if( bpp != 3 ) 74 return (virtual_width + 64/bpp - 1) & ~(64/bpp - 1); 75 else 76 return (virtual_width + 63) & ~63; 77 } 78 79 80 // list of registers that must be reset before display mode switch 81 // to avoid interferences 82 static struct { 83 uint16 reg; 84 uint32 val; 85 } common_regs[] = { 86 { RADEON_OVR_CLR, 0 }, 87 { RADEON_OVR_WID_LEFT_RIGHT, 0 }, 88 { RADEON_OVR_WID_TOP_BOTTOM, 0 }, 89 { RADEON_OV0_SCALE_CNTL, 0 }, 90 { RADEON_SUBPIC_CNTL, 0 }, 91 { RADEON_VIPH_CONTROL, 0 }, 92 { RADEON_I2C_CNTL_1, 0 }, 93 { RADEON_GEN_INT_CNTL, 0 }, 94 { RADEON_CAP0_TRIG_CNTL, 0 }, 95 }; 96 97 static void Radeon_InitCommonRegs( accelerator_info *ai ) 98 { 99 vuint8 *regs = ai->regs; 100 uint i; 101 102 for( i = 0; i < sizeof( common_regs) / sizeof( common_regs[0] ); ++i ) 103 OUTREG( regs, common_regs[i].reg, common_regs[i].val ); 104 } 105 106 // set display mode of one port; 107 // port restrictions, like fixed-sync TFTs connected to it, are taken care of 108 void Radeon_SetMode( accelerator_info *ai, virtual_port *port, display_mode *mode ) 109 { 110 virtual_card *vc = ai->vc; 111 shared_info *si = ai->si; 112 vuint8 *regs = ai->regs; 113 int format; 114 int bpp; 115 display_type_e disp_type; 116 port_regs values; 117 118 port->mode = *mode; 119 120 // don't destroy passed values, use our copy instead 121 mode = &port->mode; 122 123 disp_type = si->ports[port->physical_port].disp_type; 124 125 // if using an flat panel or LCD, maximum resolution 126 // is determined by the physical resolution; 127 // also, all timing is fixed 128 if( disp_type == dt_dvi_1 || disp_type == dt_lvds ) { 129 fp_info *fp_info = &si->fp_port; 130 131 if( mode->timing.h_display > fp_info->panel_xres ) 132 mode->timing.h_display = fp_info->panel_xres; 133 if( mode->timing.v_display > fp_info->panel_yres ) 134 mode->timing.v_display = fp_info->panel_yres; 135 136 mode->timing.h_total = mode->timing.h_display + fp_info->h_blank; 137 mode->timing.h_sync_start = mode->timing.h_display + fp_info->h_over_plus; 138 mode->timing.h_sync_end = mode->timing.h_sync_start + fp_info->h_sync_width; 139 mode->timing.v_total = mode->timing.v_display + fp_info->v_blank; 140 mode->timing.v_sync_start = mode->timing.v_display + fp_info->v_over_plus; 141 mode->timing.v_sync_end = mode->timing.v_sync_start + fp_info->v_sync_width; 142 143 mode->timing.pixel_clock = fp_info->dot_clock; 144 } 145 146 Radeon_GetFormat( mode->space, &format, &bpp ); 147 148 vc->bpp = bpp; 149 vc->datatype = format; 150 151 // calculate all hardware register values 152 Radeon_CalcCRTCRegisters( ai, port, mode, &values ); 153 154 values.surface_cntl = RADEON_SURF_TRANSLATION_DIS; 155 156 // for flat panels, we may not have pixel clock if DDC data is missing; 157 // as we don't change effective resolution we can leave it as set by BIOS 158 if( mode->timing.pixel_clock ) 159 Radeon_CalcPLLDividers( &si->pll, mode->timing.pixel_clock / 10, &values ); 160 161 if( disp_type == dt_dvi_1 || disp_type == dt_lvds ) 162 Radeon_CalcFPRegisters( ai, port, &si->fp_port, mode, &values ); 163 164 165 // write values to registers 166 Radeon_SetDPMS( ai, port, B_DPMS_SUSPEND ); 167 168 Radeon_InitCommonRegs( ai ); 169 170 Radeon_ProgramCRTCRegisters( ai, port, &values ); 171 172 OUTREG( regs, RADEON_SURFACE_CNTL, values.surface_cntl ); 173 174 if( disp_type == dt_dvi_1 || disp_type == dt_lvds ) 175 Radeon_ProgramFPRegisters( ai, &si->fp_port, &values ); 176 177 178 if( mode->timing.pixel_clock ) 179 Radeon_ProgramPLL( ai, port, &values ); 180 181 Radeon_SetDPMS( ai, port, B_DPMS_ON ); 182 183 // overlay must be setup again after modeswitch (whoever was using it) 184 // TBD: this won't work if another virtual card was using it, 185 // but currently, virtual cards don't work anyway... 186 si->active_overlay.port = -1; 187 } 188 189 190 // enable or disable VBlank interrupts 191 void Radeon_EnableIRQ( accelerator_info *ai, bool enable ) 192 { 193 shared_info *si = ai->si; 194 uint32 int_cntl, int_mask; 195 196 int_cntl = INREG( ai->regs, RADEON_GEN_INT_CNTL ); 197 int_mask = 198 RADEON_CRTC_VBLANK_MASK 199 | (si->has_crtc2 ? RADEON_CRTC2_VBLANK_MASK : 0); 200 201 if( enable ) 202 int_cntl |= int_mask; 203 else 204 int_cntl &= ~int_mask; 205 206 OUTREG( ai->regs, RADEON_GEN_INT_CNTL, int_cntl ); 207 208 if( enable ) { 209 // on enable, we have to acknowledge all IRQs as the graphics card 210 // waits for that before it issues further IRQs 211 OUTREG( ai->regs, RADEON_GEN_INT_STATUS, int_cntl ); 212 } 213 214 si->enable_virtual_irq = enable; 215 } 216 217 218 // public function: set display mode 219 status_t SET_DISPLAY_MODE( display_mode *mode_in ) 220 { 221 virtual_card *vc = ai->vc; 222 shared_info *si = ai->si; 223 display_mode bounds, mode; 224 225 mode = bounds = *mode_in; 226 227 ACQUIRE_BEN( si->engine.lock ); 228 229 SHOW_FLOW( 2, "width=%d, height=%d", mode.timing.h_display, mode.timing.v_display ); 230 231 // check mode and tweak parameters so we can program hardware 232 // without any further checks 233 if( PROPOSE_DISPLAY_MODE( &mode, &bounds, &bounds ) == B_ERROR ) { 234 SHOW_ERROR0( 2, "invalid mode" ); 235 236 RELEASE_BEN( si->engine.lock ); 237 return B_ERROR; 238 } 239 240 // already done by propose_display_mode, but it was undone on return; 241 // do this before equality check to recognize changed to multi-monitor mode 242 Radeon_DetectMultiMode( vc, &mode ); 243 244 // mode switches can take quite long and are visible, 245 // so avoid them if possible 246 if( memcmp( &mode, &vc->mode, sizeof( display_mode )) == 0 ) { 247 RELEASE_BEN( si->engine.lock ); 248 return B_OK; 249 } 250 251 // make sure, we don't get disturbed 252 Radeon_Finish( ai ); 253 Radeon_EnableIRQ( ai, false ); 254 255 // free cursor and framebuffer memory 256 { 257 radeon_free_local_mem fm; 258 259 fm.magic = RADEON_PRIVATE_DATA_MAGIC; 260 261 if( vc->cursor.mem_handle ) { 262 fm.handle = vc->cursor.mem_handle; 263 ioctl( ai->fd, RADEON_FREE_LOCAL_MEM, &fm ); 264 } 265 266 if( vc->fb_mem_handle ) { 267 fm.handle = vc->fb_mem_handle; 268 ioctl( ai->fd, RADEON_FREE_LOCAL_MEM, &fm ); 269 } 270 } 271 272 memcpy( &vc->mode, &mode, sizeof( display_mode )); 273 274 // verify hardware restrictions *after* saving mode 275 // e.g. if you want a span mode but have one monitor disconnected, 276 // configuration shouldn't be touched, so you can continue working 277 // with two monitors later on just like nothing has happened 278 Radeon_VerifyMultiMode( vc, si, &mode ); 279 280 // set main flags 281 vc->independant_ports = Radeon_NeedsSecondPort( &mode ) ? 2 : 1; 282 vc->different_ports = Radeon_DifferentPorts( &mode ); 283 SHOW_FLOW( 2, "independant ports: %d", vc->independant_ports ); 284 vc->scroll = mode.flags & B_SCROLL; 285 SHOW_FLOW( 2, "scrolling %s", vc->scroll ? "enabled" : "disabled" ); 286 287 // allocate frame buffer and cursor image memory 288 { 289 radeon_alloc_local_mem am; 290 int format, bpp; 291 292 // alloc cursor memory 293 am.magic = RADEON_PRIVATE_DATA_MAGIC; 294 am.size = 1024; 295 296 if( ioctl( ai->fd, RADEON_ALLOC_LOCAL_MEM, &am ) == B_OK ) { 297 vc->cursor.mem_handle = am.handle; 298 vc->cursor.fb_offset = am.fb_offset; 299 } else { 300 // too bad that we are out of mem -> set reasonable values as 301 // it's too late to give up (ouch!) 302 SHOW_ERROR0( 2, "no memory for cursor image!" ); 303 vc->cursor.mem_handle = 0; 304 vc->cursor.fb_offset = 0; 305 } 306 307 vc->cursor.data = si->framebuffer + vc->cursor.fb_offset; 308 309 // alloc frame buffer 310 Radeon_GetFormat( mode.space, &format, &bpp ); 311 vc->pitch = Radeon_RoundVWidth( mode.virtual_width, bpp ) * bpp; 312 am.size = vc->pitch * mode.virtual_height; 313 314 if( ioctl( ai->fd, RADEON_ALLOC_LOCAL_MEM, &am ) == B_OK ) { 315 vc->fb_mem_handle = am.handle; 316 vc->fb_offset = am.fb_offset; 317 } else { 318 // ouch again - set reasonable values 319 SHOW_ERROR0( 2, "no memory for frame buffer!" ); 320 vc->fb_mem_handle = 0; 321 vc->fb_offset = 1024; 322 } 323 324 vc->fbc.frame_buffer = si->framebuffer + vc->fb_offset; 325 vc->fbc.frame_buffer_dma = (void *)((uint8 *)si->framebuffer_pci + vc->fb_offset); 326 vc->fbc.bytes_per_row = vc->pitch; 327 } 328 329 // multi-screen stuff 330 Radeon_InitMultiModeVars( vc, &mode ); 331 332 // GO! 333 Radeon_SetMode( ai, &vc->ports[0], &mode ); 334 335 if( vc->independant_ports > 1 ) 336 Radeon_SetMode( ai, &vc->ports[1], &mode ); 337 338 SHOW_FLOW( 3, "pitch=%ld", vc->pitch ); 339 340 // we'll modify bits of this reg, so save it for async access 341 si->dac_cntl2 = INREG( ai->regs, RADEON_DAC_CNTL2 ); 342 343 // init accelerator 344 Radeon_Init2D( ai, vc->datatype ); 345 346 // remember that 2D accelerator is not prepared for any virtual card 347 si->active_vc = -1; 348 349 Radeon_ActivateVirtualCard( ai ); 350 351 // first move to well-defined position (to setup CRTC offset) 352 Radeon_MoveDisplay( ai, 0, 0 ); 353 // then to (probably faulty) user-defined pos 354 Radeon_MoveDisplay( ai, mode.h_display_start, mode.v_display_start ); 355 356 // set standard palette in direct-colour modes 357 initDAC( ai, &vc->ports[0] ); 358 if( vc->independant_ports > 1 ) 359 initDAC( ai, &vc->ports[1] ); 360 361 // initialize cursor data 362 Radeon_SetCursorColors( ai, &vc->ports[0] ); 363 if( vc->independant_ports > 1 ) 364 Radeon_SetCursorColors( ai, &vc->ports[1] ); 365 366 // sync should be settled now, so we can reenable IRQs 367 // TBD: IRQ handling doesn't work correctly and doesn't make sense with two 368 // displays connected, so let's leave them disabled for now 369 //Radeon_EnableIRQ( ai, true ); 370 371 RELEASE_BEN( si->engine.lock ); 372 373 // !! all this must be done after lock has been 374 // released to avoid dead-lock !! 375 // TBD: any invalid intermediate states? 376 377 // move_cursor sets all cursor-related variables and registers 378 vc->cursor.is_visible = false; 379 MOVE_CURSOR( 0, 0 ); 380 381 return B_OK; 382 } 383 384 // update shown are of one port 385 static void moveOneDisplay( accelerator_info *ai, virtual_port *port ) 386 { 387 virtual_card *vc = ai->vc; 388 uint32 offset; 389 390 offset = (vc->mode.v_display_start + port->rel_y) * vc->pitch + 391 (vc->mode.h_display_start + port->rel_x) * vc->bpp + 392 vc->fb_offset; 393 394 SHOW_FLOW( 3, "Setting address %x on port %d", 395 offset, port->is_crtc2 ); 396 397 Radeon_WaitForFifo( ai, 1 ); 398 399 OUTREG( ai->regs, port->is_crtc2 ? RADEON_CRTC2_OFFSET : RADEON_CRTC_OFFSET, offset ); 400 /* Radeon_WriteRegCP( ai, port->is_crtc2 ? RADEON_CRTC2_OFFSET : RADEON_CRTC_OFFSET, 401 offset );*/ 402 } 403 404 status_t Radeon_MoveDisplay( accelerator_info *ai, uint16 h_display_start, uint16 v_display_start ) 405 { 406 virtual_card *vc = ai->vc; 407 408 SHOW_FLOW( 4, "h_display_start=%ld, v_display_start=%ld", 409 h_display_start, v_display_start ); 410 411 if( h_display_start + vc->eff_width > vc->mode.virtual_width || 412 v_display_start + vc->eff_height > vc->mode.virtual_height ) 413 return B_ERROR; 414 415 // this is needed both for get_mode_info and for scrolling of virtual screens 416 vc->mode.h_display_start = h_display_start & ~7; 417 vc->mode.v_display_start = v_display_start; 418 419 // do it 420 moveOneDisplay( ai, &vc->ports[0] ); 421 422 if( vc->independant_ports > 1 ) 423 moveOneDisplay( ai, &vc->ports[1] ); 424 425 // overlay position must be adjusted 426 Radeon_UpdateOverlay( ai ); 427 428 return B_OK; 429 } 430 431 // public function: pan display 432 status_t MOVE_DISPLAY( uint16 h_display_start, uint16 v_display_start ) 433 { 434 shared_info *si = ai->si; 435 status_t result; 436 437 ACQUIRE_BEN( si->engine.lock ); 438 439 // TBD: we should probably lock card first; in this case, we must 440 // split this function into locking and worker part, as this 441 // function is used internally as well 442 result = Radeon_MoveDisplay( ai, h_display_start, v_display_start ); 443 444 RELEASE_BEN( si->engine.lock ); 445 446 return result; 447 } 448 449 static void setPalette( accelerator_info *ai, virtual_port *port, 450 uint count, uint8 first, uint8 *color_data ); 451 452 // public function: set colour palette 453 void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) 454 { 455 virtual_card *vc = ai->vc; 456 shared_info *si = ai->si; 457 // uint i; 458 459 SHOW_FLOW( 3, "first=%d, count=%d", first, flags ); 460 461 if( vc->mode.space != B_CMAP8 ) { 462 SHOW_ERROR0( 2, "Tried to set palette in non-palette mode" ); 463 return; 464 } 465 466 // we need to lock card, though this isn't done in sample driver 467 ACQUIRE_BEN( si->engine.lock ); 468 469 setPalette( ai, &vc->ports[0], count, first, color_data ); 470 471 if( vc->independant_ports > 1 ) 472 setPalette( ai, &vc->ports[1], count, first, color_data ); 473 474 RELEASE_BEN( si->engine.lock ); 475 } 476 477 478 // set palette of one DAC 479 static void setPalette( accelerator_info *ai, virtual_port *port, 480 uint count, uint8 first, uint8 *color_data ) 481 { 482 uint i; 483 484 selectDAC( ai, port ); 485 486 Radeon_WriteRegCP( ai, RADEON_PALETTE_INDEX, first ); 487 488 for( i = 0; i < count; ++i, color_data += 3 ) 489 Radeon_WriteRegCP( ai, RADEON_PALETTE_DATA, 490 ((uint32)color_data[0] << 16) | 491 ((uint32)color_data[1] << 8) | 492 color_data[2] ); 493 } 494