1409f1731Sshadow303 /* 2*e02e12deSAxel Dörfler Copyright (c) 2002-2005, Thomas Kurschel 3409f1731Sshadow303 4409f1731Sshadow303 5409f1731Sshadow303 Part of Radeon accelerant 6409f1731Sshadow303 7409f1731Sshadow303 CRTC programming 8409f1731Sshadow303 */ 9409f1731Sshadow303 10409f1731Sshadow303 #include "radeon_accelerant.h" 11409f1731Sshadow303 #include "mmio.h" 12409f1731Sshadow303 #include "crtc_regs.h" 132a37e4c1Sshadow303 #include "GlobalData.h" 14*e02e12deSAxel Dörfler #include "set_mode.h" 152a37e4c1Sshadow303 16409f1731Sshadow303 17409f1731Sshadow303 // hammer CRTC registers 18*e02e12deSAxel Dörfler void Radeon_ProgramCRTCRegisters( accelerator_info *ai, int crtc_idx, 19*e02e12deSAxel Dörfler crtc_regs *values ) 20409f1731Sshadow303 { 21409f1731Sshadow303 vuint8 *regs = ai->regs; 22409f1731Sshadow303 23409f1731Sshadow303 SHOW_FLOW0( 2, "" ); 24409f1731Sshadow303 25*e02e12deSAxel Dörfler if( crtc_idx == 0 ) { 26*e02e12deSAxel Dörfler OUTREGP( regs, RADEON_CRTC_GEN_CNTL, values->crtc_gen_cntl, 27*e02e12deSAxel Dörfler RADEON_CRTC_EXT_DISP_EN ); 28409f1731Sshadow303 29409f1731Sshadow303 OUTREG( regs, RADEON_CRTC_H_TOTAL_DISP, values->crtc_h_total_disp ); 30409f1731Sshadow303 OUTREG( regs, RADEON_CRTC_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid ); 31409f1731Sshadow303 OUTREG( regs, RADEON_CRTC_V_TOTAL_DISP, values->crtc_v_total_disp ); 32409f1731Sshadow303 OUTREG( regs, RADEON_CRTC_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid ); 33409f1731Sshadow303 OUTREG( regs, RADEON_CRTC_OFFSET_CNTL, values->crtc_offset_cntl ); 34409f1731Sshadow303 OUTREG( regs, RADEON_CRTC_PITCH, values->crtc_pitch ); 35*e02e12deSAxel Dörfler 36*e02e12deSAxel Dörfler } else { 37*e02e12deSAxel Dörfler OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, values->crtc_gen_cntl, 38*e02e12deSAxel Dörfler RADEON_CRTC2_VSYNC_DIS | 39*e02e12deSAxel Dörfler RADEON_CRTC2_HSYNC_DIS | 40*e02e12deSAxel Dörfler RADEON_CRTC2_DISP_DIS | 41*e02e12deSAxel Dörfler RADEON_CRTC2_CRT2_ON ); 42*e02e12deSAxel Dörfler 43*e02e12deSAxel Dörfler OUTREG( regs, RADEON_CRTC2_H_TOTAL_DISP, values->crtc_h_total_disp ); 44*e02e12deSAxel Dörfler OUTREG( regs, RADEON_CRTC2_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid ); 45*e02e12deSAxel Dörfler OUTREG( regs, RADEON_CRTC2_V_TOTAL_DISP, values->crtc_v_total_disp ); 46*e02e12deSAxel Dörfler OUTREG( regs, RADEON_CRTC2_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid ); 47*e02e12deSAxel Dörfler OUTREG( regs, RADEON_CRTC2_OFFSET_CNTL, values->crtc_offset_cntl ); 48*e02e12deSAxel Dörfler OUTREG( regs, RADEON_CRTC2_PITCH, values->crtc_pitch ); 49409f1731Sshadow303 } 50409f1731Sshadow303 } 51409f1731Sshadow303 52409f1731Sshadow303 53409f1731Sshadow303 // get required hsync delay depending on bit depth and output device 54*e02e12deSAxel Dörfler uint16 Radeon_GetHSyncFudge( crtc_info *crtc, int datatype ) 55409f1731Sshadow303 { 56409f1731Sshadow303 static int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; 57409f1731Sshadow303 static int hsync_fudge_fp[] = { 0x02, 0x02, 0x00, 0x00, 0x05, 0x05 }; 58409f1731Sshadow303 59409f1731Sshadow303 // there is an sync delay which depends on colour-depth and output device 60*e02e12deSAxel Dörfler if( (crtc->chosen_displays & (dd_dvi | dd_dvi_ext | dd_lvds )) != 0 ) 61409f1731Sshadow303 return hsync_fudge_fp[datatype - 1]; 62409f1731Sshadow303 else 63409f1731Sshadow303 return hsync_fudge_default[datatype - 1]; 64409f1731Sshadow303 } 65409f1731Sshadow303 66409f1731Sshadow303 67409f1731Sshadow303 // calculate CRTC register content 68*e02e12deSAxel Dörfler void Radeon_CalcCRTCRegisters( accelerator_info *ai, crtc_info *crtc, 69*e02e12deSAxel Dörfler display_mode *mode, crtc_regs *values ) 70409f1731Sshadow303 { 71409f1731Sshadow303 virtual_card *vc = ai->vc; 72409f1731Sshadow303 int hsync_start; 73409f1731Sshadow303 int hsync_wid; 74409f1731Sshadow303 int hsync_fudge; 75409f1731Sshadow303 int vsync_wid; 76409f1731Sshadow303 77*e02e12deSAxel Dörfler hsync_fudge = Radeon_GetHSyncFudge( crtc, vc->datatype ); 78409f1731Sshadow303 79*e02e12deSAxel Dörfler if( crtc->crtc_idx == 0 ) { 80*e02e12deSAxel Dörfler // here, we should set interlace/double scan mode 81*e02e12deSAxel Dörfler // but we don't support them (anyone missing them?) 82*e02e12deSAxel Dörfler values->crtc_gen_cntl = 83*e02e12deSAxel Dörfler RADEON_CRTC_EN 84*e02e12deSAxel Dörfler | (vc->datatype << 8); 85*e02e12deSAxel Dörfler 86*e02e12deSAxel Dörfler } else { 87*e02e12deSAxel Dörfler values->crtc_gen_cntl = RADEON_CRTC2_EN 88409f1731Sshadow303 | (vc->datatype << 8) 89409f1731Sshadow303 | (0/*doublescan*/ ? RADEON_CRTC2_DBL_SCAN_EN : 0) 90409f1731Sshadow303 | ((mode->timing.flags & B_TIMING_INTERLACED) 91*e02e12deSAxel Dörfler ? RADEON_CRTC2_INTERLACE_EN : 0); 92409f1731Sshadow303 } 93409f1731Sshadow303 94409f1731Sshadow303 values->crtc_h_total_disp = 95409f1731Sshadow303 ((mode->timing.h_total / 8 - 1) & RADEON_CRTC_H_TOTAL) 96409f1731Sshadow303 | (((mode->timing.h_display / 8 - 1) << RADEON_CRTC_H_DISP_SHIFT) & RADEON_CRTC_H_DISP); 97409f1731Sshadow303 98409f1731Sshadow303 hsync_wid = (mode->timing.h_sync_end - mode->timing.h_sync_start) / 8; 99409f1731Sshadow303 100409f1731Sshadow303 hsync_start = mode->timing.h_sync_start - 8 + hsync_fudge; 101409f1731Sshadow303 102409f1731Sshadow303 values->crtc_h_sync_strt_wid = 103409f1731Sshadow303 (hsync_start & (RADEON_CRTC_H_SYNC_STRT_CHAR | RADEON_CRTC_H_SYNC_STRT_PIX)) 104409f1731Sshadow303 | (hsync_wid << RADEON_CRTC_H_SYNC_WID_SHIFT) 105409f1731Sshadow303 | ((mode->flags & B_POSITIVE_HSYNC) == 0 ? RADEON_CRTC_H_SYNC_POL : 0); 106409f1731Sshadow303 107409f1731Sshadow303 values->crtc_v_total_disp = 108409f1731Sshadow303 ((mode->timing.v_total - 1) & RADEON_CRTC_V_TOTAL) 109409f1731Sshadow303 | (((mode->timing.v_display - 1) << RADEON_CRTC_V_DISP_SHIFT) & RADEON_CRTC_V_DISP); 110409f1731Sshadow303 111409f1731Sshadow303 vsync_wid = mode->timing.v_sync_end - mode->timing.v_sync_start; 112409f1731Sshadow303 113409f1731Sshadow303 values->crtc_v_sync_strt_wid = 114409f1731Sshadow303 ((mode->timing.v_sync_start - 1) & RADEON_CRTC_V_SYNC_STRT) 115409f1731Sshadow303 | (vsync_wid << RADEON_CRTC_V_SYNC_WID_SHIFT) 116409f1731Sshadow303 | ((mode->flags & B_POSITIVE_VSYNC) == 0 117409f1731Sshadow303 ? RADEON_CRTC_V_SYNC_POL : 0); 118409f1731Sshadow303 119409f1731Sshadow303 values->crtc_offset_cntl = 0; 120409f1731Sshadow303 121409f1731Sshadow303 values->crtc_pitch = Radeon_RoundVWidth( mode->virtual_width, vc->bpp ) / 8; 122409f1731Sshadow303 123409f1731Sshadow303 SHOW_FLOW( 2, "crtc_pitch=%ld", values->crtc_pitch ); 124409f1731Sshadow303 125409f1731Sshadow303 values->crtc_pitch |= values->crtc_pitch << 16; 126409f1731Sshadow303 } 1272a37e4c1Sshadow303 1282a37e4c1Sshadow303 1292a37e4c1Sshadow303 // update shown are of one port 130*e02e12deSAxel Dörfler static void moveOneDisplay( accelerator_info *ai, crtc_info *crtc ) 1312a37e4c1Sshadow303 { 1322a37e4c1Sshadow303 virtual_card *vc = ai->vc; 1332a37e4c1Sshadow303 uint32 offset; 1342a37e4c1Sshadow303 135*e02e12deSAxel Dörfler offset = (vc->mode.v_display_start + crtc->rel_y) * vc->pitch + 136*e02e12deSAxel Dörfler (vc->mode.h_display_start + crtc->rel_x) * vc->bpp + 1372a37e4c1Sshadow303 vc->fb_offset; 1382a37e4c1Sshadow303 1392a37e4c1Sshadow303 SHOW_FLOW( 3, "Setting address %x on port %d", 140*e02e12deSAxel Dörfler offset, crtc->crtc_idx ); 1412a37e4c1Sshadow303 142*e02e12deSAxel Dörfler OUTREG( ai->regs, crtc->crtc_idx == 0 ? RADEON_CRTC_OFFSET : RADEON_CRTC2_OFFSET, offset ); 1432a37e4c1Sshadow303 } 1442a37e4c1Sshadow303 1452a37e4c1Sshadow303 // internal function: pan display 1462a37e4c1Sshadow303 // engine lock should be hold 1472a37e4c1Sshadow303 status_t Radeon_MoveDisplay( accelerator_info *ai, uint16 h_display_start, uint16 v_display_start ) 1482a37e4c1Sshadow303 { 1492a37e4c1Sshadow303 virtual_card *vc = ai->vc; 1502a37e4c1Sshadow303 1512a37e4c1Sshadow303 SHOW_FLOW( 4, "h_display_start=%ld, v_display_start=%ld", 1522a37e4c1Sshadow303 h_display_start, v_display_start ); 1532a37e4c1Sshadow303 1542a37e4c1Sshadow303 if( h_display_start + vc->eff_width > vc->mode.virtual_width || 1552a37e4c1Sshadow303 v_display_start + vc->eff_height > vc->mode.virtual_height ) 1562a37e4c1Sshadow303 return B_ERROR; 1572a37e4c1Sshadow303 1582a37e4c1Sshadow303 // this is needed both for get_mode_info and for scrolling of virtual screens 1592a37e4c1Sshadow303 vc->mode.h_display_start = h_display_start & ~7; 1602a37e4c1Sshadow303 vc->mode.v_display_start = v_display_start; 1612a37e4c1Sshadow303 1622a37e4c1Sshadow303 // do it 163*e02e12deSAxel Dörfler if( vc->used_crtc[0] ) 164*e02e12deSAxel Dörfler moveOneDisplay( ai, &ai->si->crtc[0] ); 165*e02e12deSAxel Dörfler if( vc->used_crtc[1] ) 166*e02e12deSAxel Dörfler moveOneDisplay( ai, &ai->si->crtc[1] ); 1672a37e4c1Sshadow303 1682a37e4c1Sshadow303 // overlay position must be adjusted 1692a37e4c1Sshadow303 Radeon_UpdateOverlay( ai ); 1702a37e4c1Sshadow303 1712a37e4c1Sshadow303 return B_OK; 1722a37e4c1Sshadow303 } 1732a37e4c1Sshadow303 1742a37e4c1Sshadow303 // public function: pan display 1752a37e4c1Sshadow303 status_t MOVE_DISPLAY( uint16 h_display_start, uint16 v_display_start ) 1762a37e4c1Sshadow303 { 1772a37e4c1Sshadow303 shared_info *si = ai->si; 1782a37e4c1Sshadow303 status_t result; 1792a37e4c1Sshadow303 1802a37e4c1Sshadow303 ACQUIRE_BEN( si->engine.lock ); 1812a37e4c1Sshadow303 1822a37e4c1Sshadow303 // TBD: we should probably lock card first; in this case, we must 1832a37e4c1Sshadow303 // split this function into locking and worker part, as this 1842a37e4c1Sshadow303 // function is used internally as well 1852a37e4c1Sshadow303 result = Radeon_MoveDisplay( ai, h_display_start, v_display_start ); 1862a37e4c1Sshadow303 1872a37e4c1Sshadow303 RELEASE_BEN( si->engine.lock ); 1882a37e4c1Sshadow303 1892a37e4c1Sshadow303 return result; 1902a37e4c1Sshadow303 } 191