1 /* 2 Copyright (c) 2002-2005, Thomas Kurschel 3 4 5 Part of Radeon accelerant 6 7 CRTC programming 8 */ 9 10 #include "radeon_accelerant.h" 11 #include "mmio.h" 12 #include "crtc_regs.h" 13 #include "GlobalData.h" 14 #include "set_mode.h" 15 #include "generic.h" 16 17 18 // hammer CRTC registers 19 void Radeon_ProgramCRTCRegisters( accelerator_info *ai, int crtc_idx, 20 crtc_regs *values ) 21 { 22 vuint8 *regs = ai->regs; 23 24 SHOW_FLOW0( 2, "" ); 25 26 if( crtc_idx == 0 ) { 27 OUTREGP( regs, RADEON_CRTC_GEN_CNTL, values->crtc_gen_cntl, 28 RADEON_CRTC_EXT_DISP_EN ); 29 30 OUTREG( regs, RADEON_CRTC_H_TOTAL_DISP, values->crtc_h_total_disp ); 31 OUTREG( regs, RADEON_CRTC_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid ); 32 OUTREG( regs, RADEON_CRTC_V_TOTAL_DISP, values->crtc_v_total_disp ); 33 OUTREG( regs, RADEON_CRTC_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid ); 34 OUTREG( regs, RADEON_CRTC_OFFSET_CNTL, values->crtc_offset_cntl ); 35 OUTREG( regs, RADEON_CRTC_PITCH, values->crtc_pitch ); 36 37 } else { 38 OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, values->crtc_gen_cntl, 39 RADEON_CRTC2_VSYNC_DIS | 40 RADEON_CRTC2_HSYNC_DIS | 41 RADEON_CRTC2_DISP_DIS | 42 RADEON_CRTC2_CRT2_ON ); 43 44 OUTREG( regs, RADEON_CRTC2_H_TOTAL_DISP, values->crtc_h_total_disp ); 45 OUTREG( regs, RADEON_CRTC2_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid ); 46 OUTREG( regs, RADEON_CRTC2_V_TOTAL_DISP, values->crtc_v_total_disp ); 47 OUTREG( regs, RADEON_CRTC2_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid ); 48 OUTREG( regs, RADEON_CRTC2_OFFSET_CNTL, values->crtc_offset_cntl ); 49 OUTREG( regs, RADEON_CRTC2_PITCH, values->crtc_pitch ); 50 } 51 } 52 53 54 // get required hsync delay depending on bit depth and output device 55 uint16 Radeon_GetHSyncFudge( crtc_info *crtc, int datatype ) 56 { 57 static int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; 58 static int hsync_fudge_fp[] = { 0x02, 0x02, 0x00, 0x00, 0x05, 0x05 }; 59 60 // there is an sync delay which depends on colour-depth and output device 61 if( (crtc->chosen_displays & (dd_dvi | dd_dvi_ext | dd_lvds )) != 0 ) 62 return hsync_fudge_fp[datatype - 1]; 63 else 64 return hsync_fudge_default[datatype - 1]; 65 } 66 67 68 // calculate CRTC register content 69 void Radeon_CalcCRTCRegisters( accelerator_info *ai, crtc_info *crtc, 70 display_mode *mode, crtc_regs *values ) 71 { 72 virtual_card *vc = ai->vc; 73 int hsync_start; 74 int hsync_wid; 75 int hsync_fudge; 76 int vsync_wid; 77 78 hsync_fudge = Radeon_GetHSyncFudge( crtc, vc->datatype ); 79 80 if( crtc->crtc_idx == 0 ) { 81 // here, we should set interlace/double scan mode 82 // but we don't support them (anyone missing them?) 83 values->crtc_gen_cntl = 84 RADEON_CRTC_EN 85 | (vc->datatype << 8); 86 87 } else { 88 values->crtc_gen_cntl = RADEON_CRTC2_EN 89 | (vc->datatype << 8) 90 | (0/*doublescan*/ ? RADEON_CRTC2_DBL_SCAN_EN : 0) 91 | ((mode->timing.flags & B_TIMING_INTERLACED) 92 ? RADEON_CRTC2_INTERLACE_EN : 0); 93 } 94 95 values->crtc_h_total_disp = 96 ((mode->timing.h_total / 8 - 1) & RADEON_CRTC_H_TOTAL) 97 | (((mode->timing.h_display / 8 - 1) << RADEON_CRTC_H_DISP_SHIFT) & RADEON_CRTC_H_DISP); 98 99 hsync_wid = (mode->timing.h_sync_end - mode->timing.h_sync_start) / 8; 100 101 hsync_start = mode->timing.h_sync_start - 8 + hsync_fudge; 102 103 values->crtc_h_sync_strt_wid = 104 (hsync_start & (RADEON_CRTC_H_SYNC_STRT_CHAR | RADEON_CRTC_H_SYNC_STRT_PIX)) 105 | (hsync_wid << RADEON_CRTC_H_SYNC_WID_SHIFT) 106 | ((mode->flags & B_POSITIVE_HSYNC) == 0 ? RADEON_CRTC_H_SYNC_POL : 0); 107 108 values->crtc_v_total_disp = 109 ((mode->timing.v_total - 1) & RADEON_CRTC_V_TOTAL) 110 | (((mode->timing.v_display - 1) << RADEON_CRTC_V_DISP_SHIFT) & RADEON_CRTC_V_DISP); 111 112 vsync_wid = mode->timing.v_sync_end - mode->timing.v_sync_start; 113 114 values->crtc_v_sync_strt_wid = 115 ((mode->timing.v_sync_start - 1) & RADEON_CRTC_V_SYNC_STRT) 116 | (vsync_wid << RADEON_CRTC_V_SYNC_WID_SHIFT) 117 | ((mode->flags & B_POSITIVE_VSYNC) == 0 118 ? RADEON_CRTC_V_SYNC_POL : 0); 119 120 values->crtc_offset_cntl = 0; 121 122 values->crtc_pitch = Radeon_RoundVWidth( mode->virtual_width, vc->bpp ) / 8; 123 124 SHOW_FLOW( 2, "crtc_pitch=%ld", values->crtc_pitch ); 125 126 values->crtc_pitch |= values->crtc_pitch << 16; 127 } 128 129 130 // update shown are of one port 131 static void moveOneDisplay( accelerator_info *ai, crtc_info *crtc ) 132 { 133 virtual_card *vc = ai->vc; 134 uint32 offset; 135 136 offset = (vc->mode.v_display_start + crtc->rel_y) * vc->pitch + 137 (vc->mode.h_display_start + crtc->rel_x) * vc->bpp + 138 vc->fb_offset; 139 140 SHOW_FLOW( 3, "Setting address %x on port %d", 141 offset, crtc->crtc_idx ); 142 143 OUTREG( ai->regs, crtc->crtc_idx == 0 ? RADEON_CRTC_OFFSET : RADEON_CRTC2_OFFSET, offset ); 144 } 145 146 // internal function: pan display 147 // engine lock should be hold 148 status_t Radeon_MoveDisplay( accelerator_info *ai, uint16 h_display_start, uint16 v_display_start ) 149 { 150 virtual_card *vc = ai->vc; 151 152 SHOW_FLOW( 4, "h_display_start=%ld, v_display_start=%ld", 153 h_display_start, v_display_start ); 154 155 if( h_display_start + vc->eff_width > vc->mode.virtual_width || 156 v_display_start + vc->eff_height > vc->mode.virtual_height ) 157 return B_ERROR; 158 159 // this is needed both for get_mode_info and for scrolling of virtual screens 160 vc->mode.h_display_start = h_display_start & ~7; 161 vc->mode.v_display_start = v_display_start; 162 163 // do it 164 if( vc->used_crtc[0] ) 165 moveOneDisplay( ai, &ai->si->crtc[0] ); 166 if( vc->used_crtc[1] ) 167 moveOneDisplay( ai, &ai->si->crtc[1] ); 168 169 // overlay position must be adjusted 170 Radeon_UpdateOverlay( ai ); 171 172 return B_OK; 173 } 174 175 // public function: pan display 176 status_t MOVE_DISPLAY( uint16 h_display_start, uint16 v_display_start ) 177 { 178 shared_info *si = ai->si; 179 status_t result; 180 181 ACQUIRE_BEN( si->engine.lock ); 182 183 // TBD: we should probably lock card first; in this case, we must 184 // split this function into locking and worker part, as this 185 // function is used internally as well 186 result = Radeon_MoveDisplay( ai, h_display_start, v_display_start ); 187 188 RELEASE_BEN( si->engine.lock ); 189 190 return result; 191 } 192