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