3 Copyright 1999, Be Incorporated. All Rights Reserved.
4 This file may be used under the terms of the Be Sample Code License.
9 Rudolf Cornelissen 11/2002-6/2008
12 #define MODULE_BIT 0x00200000
16 /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
17 status_t
SET_DISPLAY_MODE(display_mode
*mode_to_set
)
20 * It's impossible to deviate whatever small amount in a display_mode if the lower
21 * and upper limits are the same!
23 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
24 * returns B_BAD_VALUE!
25 * Which means PROPOSEMODE should not return that on anything except on
27 * display_mode.virtual_width;
28 * display_mode.virtual_height;
29 * display_mode.timing.h_display;
30 * display_mode.timing.v_display;
32 * We don't use bounds here by making sure bounds and target are the same struct!
33 * (See the call to PROPOSE_DISPLAY_MODE below) */
34 display_mode
/*bounds,*/ target
;
36 uint8 colour_depth1
= 32;
37 uint32 startadd
,startadd_right
;
38 // bool crt1, crt2, cross;
40 /* Adjust mode to valid one and fail if invalid */
41 target
/*= bounds*/ = *mode_to_set
;
42 /* show the mode bits */
43 LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target
.flags
));
44 LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target
.timing
.pixel_clock
));
45 LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
46 target
.virtual_width
, target
.virtual_height
));
48 /* See BOUNDS WARNING above... */
49 if (PROPOSE_DISPLAY_MODE(&target
, &target
, &target
) == B_ERROR
) return B_ERROR
;
51 /* make sure a possible 3D add-on will block rendering and re-initialize itself.
52 * note: update in _this_ order only */
53 /* SET_DISPLAY_MODE will reset this flag when it's done. */
54 si
->engine
.threeD
.mode_changing
= true;
55 /* every 3D add-on will reset this bit-flag when it's done. */
56 si
->engine
.threeD
.newmode
= 0xffffffff;
57 /* every 3D clone needs to reclaim a slot.
58 * note: this also cleans up reserved channels for killed 3D clones.. */
59 si
->engine
.threeD
.clones
= 0x00000000;
61 /* disable interrupts using the kernel driver */
62 // head1_interrupt_enable(false);
63 // if (si->ps.secondary_head) head2_interrupt_enable(false);
65 /* turn off screen(s) */
66 // head1_dpms(false, false, false, true);
67 // if (si->ps.secondary_head) head2_dpms(false, false, false, true);
69 /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
70 startadd
= (uint8
*)si
->fbc
.frame_buffer
- (uint8
*)si
->framebuffer
;
72 /* calculate and set new mode bytes_per_row */
73 nv_general_validate_pic_size (&target
, &si
->fbc
.bytes_per_row
, &si
->acc_mode
);
75 /*Perform the very long mode switch!*/
76 if (target
.flags
& DUALHEAD_BITS
) /*if some dualhead mode*/
78 uint8 colour_depth2
= colour_depth1
;
80 /* init display mode for secondary head */
81 display_mode target2
= target
;
83 LOG(1,("SETMODE: setting DUALHEAD mode\n"));
85 /* detect which connectors have a CRT connected */
86 //fixme: 'hot-plugging' for analog monitors removed: remove code as well;
87 //or make it work with digital panels connected as well.
88 // crt1 = nv_dac_crt_connected();
89 // crt2 = nv_dac2_crt_connected();
90 /* connect outputs 'straight-through' */
93 /* connector1 is used as primary output */
99 /* connector2 is used as primary output */
102 /* no CRT detected: assume connector1 is used as primary output */
105 /* set output connectors assignment if possible */
106 // if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH)
107 /* invert output assignment in switch mode */
108 // nv_general_head_select(true);
110 // nv_general_head_select(false);
112 /* set the pixel clock PLL(s) */
113 LOG(8,("SETMODE: target clock %dkHz\n",target
.timing
.pixel_clock
));
114 // if (head1_set_pix_pll(target) == B_ERROR)
115 // LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
117 LOG(8,("SETMODE: target2 clock %dkHz\n",target2
.timing
.pixel_clock
));
118 // if (head2_set_pix_pll(target2) == B_ERROR)
119 // LOG(8,("SETMODE: error setting pixel clock (DAC2)\n"));
121 /*set the colour depth for CRTC1 and the DAC */
126 // head1_mode(BPP8, 1.0);
127 // head1_depth(BPP8);
131 // head1_mode(BPP15, 1.0);
132 // head1_depth(BPP15);
136 // head1_mode(BPP16, 1.0);
137 // head1_depth(BPP16);
141 // head1_mode(BPP32, 1.0);
142 // head1_depth(BPP32);
145 /*set the colour depth for CRTC2 and DAC2 */
146 switch(target2
.space
)
150 // head2_mode(BPP8, 1.0);
151 // head2_depth(BPP8);
155 // head2_mode(BPP15, 1.0);
156 // head2_depth(BPP15);
160 // head2_mode(BPP16, 1.0);
161 // head2_depth(BPP16);
165 // head2_mode(BPP32, 1.0);
166 // head2_depth(BPP32);
170 /*set the display(s) pitches*/
171 // head1_set_display_pitch ();
172 //fixme: seperate for real dualhead modes:
173 //we need a secondary si->fbc!
174 // head2_set_display_pitch ();
176 /*work out where the "right" screen starts*/
177 startadd_right
= startadd
+ (target
.timing
.h_display
* (colour_depth1
>> 3));
179 /* Tell card what memory to display */
180 switch (target
.flags
& DUALHEAD_BITS
)
183 case DUALHEAD_SWITCH
:
184 // head1_set_display_start(startadd,colour_depth1);
185 // head2_set_display_start(startadd_right,colour_depth2);
188 // head1_set_display_start(startadd,colour_depth1);
189 // head2_set_display_start(startadd,colour_depth2);
194 // head1_set_timing(target);
195 // head2_set_timing(target2);
197 else /* single head mode */
199 int colour_mode
= BPP32
;
202 if (si
->ps
.secondary_head
)
204 /* detect which connectors have a CRT connected */
205 //fixme: 'hot-plugging' for analog monitors removed: remove code as well;
206 //or make it work with digital panels connected as well.
207 // crt1 = nv_dac_crt_connected();
208 // crt2 = nv_dac2_crt_connected();
209 /* connect outputs 'straight-through' */
212 /* connector1 is used as primary output */
218 /* connector2 is used as primary output */
221 /* no CRT detected: assume connector1 is used as primary output */
224 /* set output connectors assignment if possible */
225 nv_general_head_select(false);
230 case B_CMAP8
: colour_depth1
= 8; colour_mode
= BPP8
; break;
231 case B_RGB15_LITTLE
: colour_depth1
= 16; colour_mode
= BPP15
; break;
232 case B_RGB16_LITTLE
: colour_depth1
= 16; colour_mode
= BPP16
; break;
233 case B_RGB32_LITTLE
: colour_depth1
= 32; colour_mode
= BPP32
; break;
235 LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target
.space
));
239 /* set the pixel clock PLL */
240 // if (head1_set_pix_pll(target) == B_ERROR)
241 // LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
243 /* set the colour depth for CRTC1 and the DAC */
244 /* first set the colordepth */
245 // head1_depth(colour_mode);
246 /* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
247 // head1_mode(colour_mode,1.0);
249 /* set the display pitch */
250 // head1_set_display_pitch();
252 /* tell the card what memory to display */
253 // head1_set_display_start(startadd,colour_depth1);
256 // head1_set_timing(target);
258 //fixme: shut-off the videoPLL if it exists...
261 /* update driver's mode store */
264 /* update FIFO data fetching according to mode */
265 // nv_crtc_update_fifo();
266 // if (si->ps.secondary_head) nv_crtc2_update_fifo();
268 /* set up acceleration for this mode */
270 * Maybe later we can forget about non-DMA mode (depends on 3D acceleration
272 //no acc support for G8x yet!
273 if (si
->ps
.card_arch
< NV50A
)
277 /* set up overlay unit for this mode */
280 /* note freemem range */
281 /* first free adress follows hardcursor and workspace */
282 si
->engine
.threeD
.mem_low
= si
->fbc
.bytes_per_row
* si
->dm
.virtual_height
;
283 if (si
->settings
.hardcursor
) si
->engine
.threeD
.mem_low
+= 2048;
284 /* last free adress is end-of-ram minus max space needed for overlay bitmaps */
286 //if overlay buffers are allocated subtract buffersize from mem_high;
287 //only allocate overlay buffers if 3D is not in use. (block overlay during 3D)
288 si
->engine
.threeD
.mem_high
= si
->ps
.memory_size
- 1;
289 /* Keep some extra distance as a workaround for certain bugs (see
290 * DriverInterface.h for an explanation). */
291 si
->engine
.threeD
.mem_high
-= NV40_PLUS_OFFSET
;
293 /* restore screen(s) output state(s) */
294 // SET_DPMS_MODE(si->dpms_flags);
296 /* enable interrupts using the kernel driver */
298 //add head2 once we use one driver instance 'per head' (instead of 'per card')
299 // head1_interrupt_enable(true);
301 /* make sure a possible 3D add-on will re-initialize itself by signalling ready */
302 si
->engine
.threeD
.mode_changing
= false;
304 /* optimize memory-access if needed */
305 // head1_mem_priority(colour_depth1);
307 /* Tune RAM CAS-latency if needed. Must be done *here*! */
308 // nv_set_cas_latency();
310 LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
316 Set which pixel of the virtual frame buffer will show up in the
317 top left corner of the display device. Used for page-flipping
318 games and virtual desktops.
320 status_t
MOVE_DISPLAY(uint16 h_display_start
, uint16 v_display_start
) {
322 uint32 startadd
,startadd_right
;
324 LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start
, v_display_start
));
326 /* nVidia cards support pixelprecise panning on both heads in all modes:
327 * No stepping granularity needed! */
329 /* determine bits used for the colordepth */
349 /* do not run past end of display */
350 switch (si
->dm
.flags
& DUALHEAD_BITS
)
353 case DUALHEAD_SWITCH
:
354 if (((si
->dm
.timing
.h_display
* 2) + h_display_start
) > si
->dm
.virtual_width
)
358 if ((si
->dm
.timing
.h_display
+ h_display_start
) > si
->dm
.virtual_width
)
362 if ((si
->dm
.timing
.v_display
+ v_display_start
) > si
->dm
.virtual_height
)
365 /* everybody remember where we parked... */
366 si
->dm
.h_display_start
= h_display_start
;
367 si
->dm
.v_display_start
= v_display_start
;
369 /* actually set the registers */
370 //fixme: seperate both heads: we need a secondary si->fbc!
371 startadd
= v_display_start
* si
->fbc
.bytes_per_row
;
372 startadd
+= h_display_start
* (colour_depth
>> 3);
373 startadd
+= (uint8
*)si
->fbc
.frame_buffer
- (uint8
*)si
->framebuffer
;
374 startadd_right
= startadd
+ si
->dm
.timing
.h_display
* (colour_depth
>> 3);
376 /* disable interrupts using the kernel driver */
377 head1_interrupt_enable(false);
378 if (si
->ps
.secondary_head
) head2_interrupt_enable(false);
380 switch (si
->dm
.flags
& DUALHEAD_BITS
)
383 case DUALHEAD_SWITCH
:
384 head1_set_display_start(startadd
,colour_depth
);
385 head2_set_display_start(startadd_right
,colour_depth
);
388 head1_set_display_start(startadd
,colour_depth
);
391 head1_set_display_start(startadd
,colour_depth
);
392 head2_set_display_start(startadd
,colour_depth
);
397 //add head2 once we use one driver instance 'per head' (instead of 'per card')
398 head1_interrupt_enable(true);
403 /* Set the indexed color palette */
404 void SET_INDEXED_COLORS(uint count
, uint8 first
, uint8
*color_data
, uint32 flags
) {
408 /* Protect gamma correction when not in CMAP8 */
409 if (si
->dm
.space
!= B_CMAP8
) return;
423 head1_palette(r
,g
,b
);
424 if (si
->dm
.flags
& DUALHEAD_BITS
) head2_palette(r
,g
,b
);
427 /* Put the display into one of the Display Power Management modes. */
428 status_t
SET_DPMS_MODE(uint32 dpms_flags
)
430 bool display
, h1h
, h1v
, h2h
, h2v
, do_p1
, do_p2
;
432 /* disable interrupts using the kernel driver */
433 head1_interrupt_enable(false);
434 if (si
->ps
.secondary_head
) head2_interrupt_enable(false);
436 LOG(4,("SET_DPMS_MODE: $%08x\n", dpms_flags
));
438 /* note current DPMS state for our reference */
439 si
->dpms_flags
= dpms_flags
;
441 /* preset: DPMS for panels should be executed */
442 do_p1
= do_p2
= true;
444 /* determine signals to send to head(s) */
445 display
= h1h
= h1v
= h2h
= h2v
= true;
448 case B_DPMS_ON
: /* H: on, V: on, display on */
450 case B_DPMS_STAND_BY
:
451 display
= h1h
= h2h
= false;
454 display
= h1v
= h2v
= false;
456 case B_DPMS_OFF
: /* H: off, V: off, display off */
457 display
= h1h
= h1v
= h2h
= h2v
= false;
460 LOG(8,("SET: Invalid DPMS settings $%08x\n", dpms_flags
));
462 //add head2 once we use one driver instance 'per head' (instead of 'per card')
463 head1_interrupt_enable(true);
468 /* issue actual DPMS commands as far as applicable */
469 head1_dpms(display
, h1h
, h1v
, do_p1
);
470 if ((si
->ps
.secondary_head
) && (si
->dm
.flags
& DUALHEAD_BITS
))
471 head2_dpms(display
, h2h
, h2v
, do_p2
);
474 //add head2 once we use one driver instance 'per head' (instead of 'per card')
475 head1_interrupt_enable(true);
480 /* Report device DPMS capabilities */
481 uint32
DPMS_CAPABILITIES(void)
483 return (B_DPMS_ON
| B_DPMS_STAND_BY
| B_DPMS_SUSPEND
| B_DPMS_OFF
);
486 /* Return the current DPMS mode */
487 uint32
DPMS_MODE(void)
489 return si
->dpms_flags
;