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-12/2015
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 %ukHz\n", target
.timing
.pixel_clock
));
45 LOG(1, ("SETMODE: requested virtual_width %u, virtual_height %u\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 /* disable TVout if supported */
66 if (si
->ps
.tvout
) BT_stop_tvout();
68 /* turn off screen(s) _after_ TVout is disabled (if applicable) */
69 head1_dpms(false, false, false, true);
70 if (si
->ps
.secondary_head
) head2_dpms(false, false, false, true);
71 if (si
->ps
.tvout
) BT_dpms(false);
73 /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
74 startadd
= (uint8
*)si
->fbc
.frame_buffer
- (uint8
*)si
->framebuffer
;
76 /* calculate and set new mode bytes_per_row */
77 nv_general_validate_pic_size (&target
, &si
->fbc
.bytes_per_row
, &si
->acc_mode
);
79 /*Perform the very long mode switch!*/
80 if (target
.flags
& DUALHEAD_BITS
) /*if some dualhead mode*/
82 uint8 colour_depth2
= colour_depth1
;
84 /* init display mode for secondary head */
85 display_mode target2
= target
;
87 LOG(1,("SETMODE: setting DUALHEAD mode\n"));
89 /* validate flags for secondary TVout */
90 //fixme: remove or block on autodetect fail. (is now shutoff)
91 if ((0) && (target2
.flags
& TV_BITS
))
93 target
.flags
&= ~TV_BITS
;//still needed for some routines...
94 target2
.flags
&= ~TV_BITS
;
95 LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
98 /* detect which connectors have a CRT connected */
99 //fixme: 'hot-plugging' for analog monitors removed: remove code as well;
100 //or make it work with digital panels connected as well.
101 // crt1 = nv_dac_crt_connected();
102 // crt2 = nv_dac2_crt_connected();
103 /* connect outputs 'straight-through' */
106 /* connector1 is used as primary output */
112 /* connector2 is used as primary output */
115 /* no CRT detected: assume connector1 is used as primary output */
118 /* set output connectors assignment if possible */
119 if ((target
.flags
& DUALHEAD_BITS
) == DUALHEAD_SWITCH
)
120 /* invert output assignment in switch mode */
121 nv_general_head_select(true);
123 nv_general_head_select(false);
125 /* set the pixel clock PLL(s) */
126 LOG(8,("SETMODE: target clock %dkHz\n",target
.timing
.pixel_clock
));
127 if (head1_set_pix_pll(target
) == B_ERROR
)
128 LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
130 LOG(8,("SETMODE: target2 clock %dkHz\n",target2
.timing
.pixel_clock
));
131 if (head2_set_pix_pll(target2
) == B_ERROR
)
132 LOG(8,("SETMODE: error setting pixel clock (DAC2)\n"));
134 /*set the colour depth for CRTC1 and the DAC */
139 head1_mode(BPP8
, 1.0);
144 head1_mode(BPP15
, 1.0);
149 head1_mode(BPP16
, 1.0);
154 head1_mode(BPP32
, 1.0);
158 /*set the colour depth for CRTC2 and DAC2 */
159 switch(target2
.space
)
163 head2_mode(BPP8
, 1.0);
168 head2_mode(BPP15
, 1.0);
173 head2_mode(BPP16
, 1.0);
178 head2_mode(BPP32
, 1.0);
183 /* check if we are doing interlaced TVout mode */
184 //fixme: we don't support interlaced mode?
185 si
->interlaced_tv_mode
= false;
187 /*set the display(s) pitches*/
188 head1_set_display_pitch ();
189 //fixme: seperate for real dualhead modes:
190 //we need a secondary si->fbc!
191 head2_set_display_pitch ();
193 /*work out where the "right" screen starts*/
194 startadd_right
= startadd
+ (target
.timing
.h_display
* (colour_depth1
>> 3));
196 /* Tell card what memory to display */
197 switch (target
.flags
& DUALHEAD_BITS
)
200 case DUALHEAD_SWITCH
:
201 head1_set_display_start(startadd
,colour_depth1
);
202 head2_set_display_start(startadd_right
,colour_depth2
);
205 head1_set_display_start(startadd
,colour_depth1
);
206 head2_set_display_start(startadd
,colour_depth2
);
211 head1_set_timing(target
);
212 head2_set_timing(target2
);
214 /* TVout support: program TVout encoder and modify CRTC timing */
215 if (si
->ps
.tvout
&& (target2
.flags
& TV_BITS
)) BT_setmode(target2
);
217 else /* single head mode */
219 int colour_mode
= BPP32
;
222 if (si
->ps
.secondary_head
)
224 /* detect which connectors have a CRT connected */
225 //fixme: 'hot-plugging' for analog monitors removed: remove code as well;
226 //or make it work with digital panels connected as well.
227 // crt1 = nv_dac_crt_connected();
228 // crt2 = nv_dac2_crt_connected();
229 /* connect outputs 'straight-through' */
232 /* connector1 is used as primary output */
238 /* connector2 is used as primary output */
241 /* no CRT detected: assume connector1 is used as primary output */
244 /* set output connectors assignment if possible */
245 nv_general_head_select(false);
250 case B_CMAP8
: colour_depth1
= 8; colour_mode
= BPP8
; break;
251 case B_RGB15_LITTLE
: colour_depth1
= 16; colour_mode
= BPP15
; break;
252 case B_RGB16_LITTLE
: colour_depth1
= 16; colour_mode
= BPP16
; break;
253 case B_RGB32_LITTLE
: colour_depth1
= 32; colour_mode
= BPP32
; break;
255 LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target
.space
));
259 /* set the pixel clock PLL */
260 if (head1_set_pix_pll(target
) == B_ERROR
)
261 LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
263 /* set the colour depth for CRTC1 and the DAC */
264 /* first set the colordepth */
265 head1_depth(colour_mode
);
266 /* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
267 head1_mode(colour_mode
,1.0);
269 /* set the display pitch */
270 head1_set_display_pitch();
272 /* tell the card what memory to display */
273 head1_set_display_start(startadd
,colour_depth1
);
276 head1_set_timing(target
);
278 /* TVout support: program TVout encoder and modify CRTC timing */
279 if (si
->ps
.tvout
&& (target
.flags
& TV_BITS
)) BT_setmode(target
);
281 //fixme: shut-off the videoPLL if it exists...
284 /* update driver's mode store */
287 /* update FIFO data fetching according to mode */
288 nv_crtc_update_fifo();
289 if (si
->ps
.secondary_head
) nv_crtc2_update_fifo();
291 /* set up acceleration for this mode */
293 * Maybe later we can forget about non-DMA mode (depends on 3D acceleration
295 if (!si
->settings
.block_acc
) {
296 if (!si
->settings
.dma_acc
)
302 /* set up overlay unit for this mode */
305 /* note freemem range */
306 /* first free adress follows hardcursor and workspace */
307 si
->engine
.threeD
.mem_low
= si
->fbc
.bytes_per_row
* si
->dm
.virtual_height
;
308 if (si
->settings
.hardcursor
) si
->engine
.threeD
.mem_low
+= 2048;
309 /* last free adress is end-of-ram minus max space needed for overlay bitmaps */
311 //if overlay buffers are allocated subtract buffersize from mem_high;
312 //only allocate overlay buffers if 3D is not in use. (block overlay during 3D)
313 si
->engine
.threeD
.mem_high
= si
->ps
.memory_size
- 1;
314 /* Keep some extra distance as a workaround for certain bugs (see
315 * DriverInterface.h for an explanation). */
316 if (si
->ps
.card_arch
< NV40A
)
317 si
->engine
.threeD
.mem_high
-= PRE_NV40_OFFSET
;
319 si
->engine
.threeD
.mem_high
-= NV40_PLUS_OFFSET
;
321 si
->engine
.threeD
.mem_high
-= (MAXBUFFERS
* 1024 * 1024 * 2); /* see overlay.c file */
323 /* restore screen(s) output state(s) */
324 SET_DPMS_MODE(si
->dpms_flags
);
326 /* enable interrupts using the kernel driver */
328 //add head2 once we use one driver instance 'per head' (instead of 'per card')
329 head1_interrupt_enable(true);
331 /* make sure a possible 3D add-on will re-initialize itself by signalling ready */
332 si
->engine
.threeD
.mode_changing
= false;
334 /* optimize memory-access if needed */
335 // head1_mem_priority(colour_depth1);
337 /* Tune RAM CAS-latency if needed. Must be done *here*! */
338 nv_set_cas_latency();
340 LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
346 Set which pixel of the virtual frame buffer will show up in the
347 top left corner of the display device. Used for page-flipping
348 games and virtual desktops.
350 status_t
MOVE_DISPLAY(uint16 h_display_start
, uint16 v_display_start
) {
352 uint32 startadd
,startadd_right
;
354 LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start
, v_display_start
));
356 /* nVidia cards support pixelprecise panning on both heads in all modes:
357 * No stepping granularity needed! */
359 /* determine bits used for the colordepth */
379 /* do not run past end of display */
380 switch (si
->dm
.flags
& DUALHEAD_BITS
)
383 case DUALHEAD_SWITCH
:
384 if (((si
->dm
.timing
.h_display
* 2) + h_display_start
) > si
->dm
.virtual_width
)
388 if ((si
->dm
.timing
.h_display
+ h_display_start
) > si
->dm
.virtual_width
)
392 if ((si
->dm
.timing
.v_display
+ v_display_start
) > si
->dm
.virtual_height
)
395 /* everybody remember where we parked... */
396 si
->dm
.h_display_start
= h_display_start
;
397 si
->dm
.v_display_start
= v_display_start
;
399 /* actually set the registers */
400 //fixme: seperate both heads: we need a secondary si->fbc!
401 startadd
= v_display_start
* si
->fbc
.bytes_per_row
;
402 startadd
+= h_display_start
* (colour_depth
>> 3);
403 startadd
+= (uint8
*)si
->fbc
.frame_buffer
- (uint8
*)si
->framebuffer
;
404 startadd_right
= startadd
+ si
->dm
.timing
.h_display
* (colour_depth
>> 3);
406 /* disable interrupts using the kernel driver */
407 head1_interrupt_enable(false);
408 if (si
->ps
.secondary_head
) head2_interrupt_enable(false);
410 switch (si
->dm
.flags
& DUALHEAD_BITS
)
413 case DUALHEAD_SWITCH
:
414 head1_set_display_start(startadd
,colour_depth
);
415 head2_set_display_start(startadd_right
,colour_depth
);
418 head1_set_display_start(startadd
,colour_depth
);
421 head1_set_display_start(startadd
,colour_depth
);
422 head2_set_display_start(startadd
,colour_depth
);
427 //add head2 once we use one driver instance 'per head' (instead of 'per card')
428 head1_interrupt_enable(true);
433 /* Set the indexed color palette */
434 void SET_INDEXED_COLORS(uint count
, uint8 first
, uint8
*color_data
, uint32 flags
) {
438 /* Protect gamma correction when not in CMAP8 */
439 if (si
->dm
.space
!= B_CMAP8
) return;
453 head1_palette(r
,g
,b
);
454 if (si
->dm
.flags
& DUALHEAD_BITS
) head2_palette(r
,g
,b
);
457 /* Put the display into one of the Display Power Management modes. */
458 status_t
SET_DPMS_MODE(uint32 dpms_flags
)
460 bool display
, h1h
, h1v
, h2h
, h2v
, do_p1
, do_p2
;
462 /* disable interrupts using the kernel driver */
463 head1_interrupt_enable(false);
464 if (si
->ps
.secondary_head
) head2_interrupt_enable(false);
466 LOG(4,("SET_DPMS_MODE: $%08x\n", dpms_flags
));
468 /* note current DPMS state for our reference */
469 si
->dpms_flags
= dpms_flags
;
471 /* preset: DPMS for panels should be executed */
472 do_p1
= do_p2
= true;
474 /* determine signals to send to head(s) */
475 display
= h1h
= h1v
= h2h
= h2v
= true;
478 case B_DPMS_ON
: /* H: on, V: on, display on */
480 case B_DPMS_STAND_BY
:
481 display
= h1h
= h2h
= false;
484 display
= h1v
= h2v
= false;
486 case B_DPMS_OFF
: /* H: off, V: off, display off */
487 display
= h1h
= h1v
= h2h
= h2v
= false;
490 LOG(8,("SET: Invalid DPMS settings $%08x\n", dpms_flags
));
492 //add head2 once we use one driver instance 'per head' (instead of 'per card')
493 head1_interrupt_enable(true);
498 /* CRTC used for TVout needs specific DPMS programming */
499 if (si
->dm
.flags
& TV_BITS
)
501 /* TV_PRIMARY tells us that the head to be used with TVout is the head that's
502 * actually assigned as being the primary head at powerup:
503 * so non dualhead-mode-dependant, and not 'fixed' CRTC1! */
504 if (si
->dm
.flags
& TV_PRIMARY
)
506 LOG(4,("SET_DPMS_MODE: tuning primary head DPMS settings for TVout compatibility\n"));
508 if ((si
->dm
.flags
& DUALHEAD_BITS
) != DUALHEAD_SWITCH
)
510 if (!(si
->settings
.vga_on_tv
))
512 /* block VGA output on head displaying on TV */
514 * this specific sync setting is required: Vsync is used to keep TVout
515 * synchronized to the CRTC 'vertically' (otherwise 'rolling' occurs).
516 * This leaves Hsync only for shutting off the VGA screen. */
519 /* block panel DPMS updates */
524 /* when concurrent VGA is used alongside TVout on a head, DPMS is safest
525 * applied this way: Vsync is needed for stopping TVout successfully when
526 * a (new) modeswitch occurs.
527 * (see routine BT_stop_tvout() in nv_brooktreetv.c) */
529 * applying 'normal' DPMS here and forcing Vsync on in the above mentioned
530 * routine seems to not always be enough: sometimes image generation will
531 * not resume in that case. */
538 if (!(si
->settings
.vga_on_tv
))
553 LOG(4,("SET_DPMS_MODE: tuning secondary head DPMS settings for TVout compatibility\n"));
555 if ((si
->dm
.flags
& DUALHEAD_BITS
) != DUALHEAD_SWITCH
)
557 if (!(si
->settings
.vga_on_tv
))
571 if (!(si
->settings
.vga_on_tv
))
586 /* issue actual DPMS commands as far as applicable */
587 head1_dpms(display
, h1h
, h1v
, do_p1
);
588 if ((si
->ps
.secondary_head
) && (si
->dm
.flags
& DUALHEAD_BITS
))
589 head2_dpms(display
, h2h
, h2v
, do_p2
);
590 if (si
->dm
.flags
& TV_BITS
)
594 //add head2 once we use one driver instance 'per head' (instead of 'per card')
595 head1_interrupt_enable(true);
600 /* Report device DPMS capabilities */
601 uint32
DPMS_CAPABILITIES(void)
603 return (B_DPMS_ON
| B_DPMS_STAND_BY
| B_DPMS_SUSPEND
| B_DPMS_OFF
);
606 /* Return the current DPMS mode */
607 uint32
DPMS_MODE(void)
609 return si
->dpms_flags
;