vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / radeon / crtc.c
blob2718a55a255d5cec033b2d363b024fdf21a033d9
1 /*
2 Copyright (c) 2002-2005, Thomas Kurschel
5 Part of Radeon accelerant
7 CRTC programming
8 */
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"
18 // hammer CRTC registers
19 void Radeon_ProgramCRTCRegisters( accelerator_info *ai, int crtc_idx,
20 crtc_regs *values )
22 vuint8 *regs = ai->regs;
24 SHOW_FLOW0( 2, "" );
26 if( crtc_idx == 0 ) {
27 OUTREGP( regs, RADEON_CRTC_GEN_CNTL, values->crtc_gen_cntl,
28 RADEON_CRTC_EXT_DISP_EN );
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 );
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 );
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 );
54 // get required hsync delay depending on bit depth and output device
55 uint16 Radeon_GetHSyncFudge( crtc_info *crtc, int datatype )
57 static int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
58 static int hsync_fudge_fp[] = { 0x02, 0x02, 0x00, 0x00, 0x05, 0x05 };
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];
68 // calculate CRTC register content
69 void Radeon_CalcCRTCRegisters( accelerator_info *ai, crtc_info *crtc,
70 display_mode *mode, crtc_regs *values )
72 virtual_card *vc = ai->vc;
73 int hsync_start;
74 int hsync_wid;
75 int hsync_fudge;
76 int vsync_wid;
78 hsync_fudge = Radeon_GetHSyncFudge( crtc, vc->datatype );
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);
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);
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);
99 hsync_wid = (mode->timing.h_sync_end - mode->timing.h_sync_start) / 8;
101 hsync_start = mode->timing.h_sync_start - 8 + hsync_fudge;
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);
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);
112 vsync_wid = mode->timing.v_sync_end - mode->timing.v_sync_start;
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);
120 values->crtc_offset_cntl = 0;
122 values->crtc_pitch = Radeon_RoundVWidth( mode->virtual_width, vc->bpp ) / 8;
124 SHOW_FLOW( 2, "crtc_pitch=%ld", values->crtc_pitch );
126 values->crtc_pitch |= values->crtc_pitch << 16;
130 // update shown are of one port
131 static void moveOneDisplay( accelerator_info *ai, crtc_info *crtc )
133 virtual_card *vc = ai->vc;
134 uint32 offset;
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;
140 SHOW_FLOW( 3, "Setting address %x on port %d",
141 offset, crtc->crtc_idx );
143 OUTREG( ai->regs, crtc->crtc_idx == 0 ? RADEON_CRTC_OFFSET : RADEON_CRTC2_OFFSET, offset );
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 )
150 virtual_card *vc = ai->vc;
152 SHOW_FLOW( 4, "h_display_start=%ld, v_display_start=%ld",
153 h_display_start, v_display_start );
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;
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;
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] );
169 // overlay position must be adjusted
170 Radeon_UpdateOverlay( ai );
172 return B_OK;
175 // public function: pan display
176 status_t MOVE_DISPLAY( uint16 h_display_start, uint16 v_display_start )
178 shared_info *si = ai->si;
179 status_t result;
181 ACQUIRE_BEN( si->engine.lock );
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 );
188 RELEASE_BEN( si->engine.lock );
190 return result;