2 Copyright 1999, Be Incorporated. All Rights Reserved.
3 This file may be used under the terms of the Be Sample Code License.
8 Rudolf Cornelissen 11/2002-5/2006
11 #define MODULE_BIT 0x00200000
16 Enable/Disable interrupts. Just a wrapper around the
17 ioctl() to the kernel driver.
19 static void interrupt_enable(bool flag
)
22 gx00_set_bool_state sbs
;
24 if (si
->ps
.int_assigned
)
26 /* set the magic number so the driver knows we're for real */
27 sbs
.magic
= GX00_PRIVATE_DATA_MAGIC
;
29 /* contact driver and get a pointer to the registers and shared data */
30 result
= ioctl(fd
, GX00_RUN_INTERRUPTS
, &sbs
, sizeof(sbs
));
34 /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
35 status_t
SET_DISPLAY_MODE(display_mode
*mode_to_set
)
38 * It's impossible to deviate whatever small amount in a display_mode if the lower
39 * and upper limits are the same!
41 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
42 * returns B_BAD_VALUE!
43 * Which means PROPOSEMODE should not return that on anything except on
45 * display_mode.virtual_width;
46 * display_mode.virtual_height;
47 * display_mode.timing.h_display;
48 * display_mode.timing.v_display;
50 * We don't use bounds here by making sure bounds and target are the same struct!
51 * (See the call to PROPOSE_DISPLAY_MODE below) */
52 display_mode
/*bounds,*/ target
;
54 uint8 colour_depth1
= 32;
56 uint32 startadd
,startadd_right
;
58 /* Adjust mode to valid one and fail if invalid */
59 target
/*= bounds*/ = *mode_to_set
;
60 /* show the mode bits */
61 LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target
.flags
));
62 LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target
.timing
.pixel_clock
));
63 LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
64 target
.virtual_width
, target
.virtual_height
));
66 /* See BOUNDS WARNING above... */
67 if (PROPOSE_DISPLAY_MODE(&target
, &target
, &target
) == B_ERROR
) return B_ERROR
;
69 /* overlay engine, cursor and MOVE_DISPLAY need to know the status even when
70 * in singlehead mode */
71 si
->switched_crtcs
= false;
73 /* disable interrupts using the kernel driver */
74 interrupt_enable(false);
76 /* then turn off screen(s) */
77 gx00_crtc_dpms(false, false, false);
78 if (si
->ps
.secondary_head
)
80 g400_crtc2_dpms(false, false, false);
84 /* on singlehead cards with TVout program the MAVEN as well */
85 if (si
->ps
.tvout
) gx00_maven_dpms(false, false, false);
88 /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
89 startadd
= (uint8
*)si
->fbc
.frame_buffer
- (uint8
*)si
->framebuffer
;
91 /* calculate and set new mode bytes_per_row */
92 gx00_general_validate_pic_size (&target
, &si
->fbc
.bytes_per_row
, &si
->acc_mode
);
94 /*Perform the very long mode switch!*/
95 if (target
.flags
& DUALHEAD_BITS
) /*if some dualhead mode*/
97 uint8 colour_depth2
= colour_depth1
;
99 /* init display mode for secondary head */
100 display_mode target2
= target
;
102 LOG(1,("SETMODE: setting DUALHEAD mode\n"));
104 /* set the pixel clock PLL(s) */
105 LOG(8,("SETMODE: target clock %dkHz\n",target
.timing
.pixel_clock
));
106 if (gx00_dac_set_pix_pll(target
) == B_ERROR
)
107 LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
109 /* we do not need to set the pixelclock here for a head that's in TVout mode */
110 if (!(target2
.flags
& TV_BITS
))
112 LOG(8,("SETMODE: target2 clock %dkHz\n",target2
.timing
.pixel_clock
));
113 if (gx00_maven_set_vid_pll(target2
) == B_ERROR
)
114 LOG(8,("SETMODE: error setting pixel clock (MAVEN)\n"));
117 /*set the colour depth for CRTC1 and the DAC */
122 gx00_dac_mode(BPP16
, 1.0);
123 gx00_crtc_depth(BPP16
);
127 gx00_dac_mode(BPP32
, 1.0);
128 gx00_crtc_depth(BPP32
);
131 /*set the colour depth for CRTC2 and the MAVEN */
132 switch(target2
.space
)
136 gx00_maven_mode(BPP16
, 1.0);
137 g400_crtc2_depth(BPP16
);
141 gx00_maven_mode(BPP32DIR
, 1.0);
142 g400_crtc2_depth(BPP32DIR
);
146 /* check if we are doing interlaced TVout mode */
147 si
->interlaced_tv_mode
= false;
148 if ((target2
.flags
& TV_BITS
) && (si
->ps
.card_type
>= G450
))
149 si
->interlaced_tv_mode
= true;
151 /*set the display(s) pitches*/
152 gx00_crtc_set_display_pitch ();
153 //fixme: seperate for real dualhead modes:
154 //we need a secondary si->fbc!
155 g400_crtc2_set_display_pitch ();
157 /*work out where the "right" screen starts*/
158 startadd_right
=startadd
+(target
.timing
.h_display
* (colour_depth1
>> 3));
160 /* calculate needed MAVEN-CRTC delay: formula valid for straight-through CRTC's */
162 if (colour_depth2
== 16) si
->crtc_delay
+= 0;
164 /* set the outputs */
165 switch (si
->ps
.card_type
)
169 /* setup vertical timing adjust for crtc connected to the MAVEN:
170 * assuming connected straight through. */
171 /* (extra "blanking" line for MAVEN hardware design fault) */
172 target2
.timing
.v_display
++;
174 switch (target
.flags
& DUALHEAD_BITS
)
178 gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN
);
179 si
->switched_crtcs
= false;
181 case DUALHEAD_SWITCH
:
182 if (i2c_sec_tv_adapter() == B_OK
)
184 /* Don't switch CRTC's because MAVEN YUV is impossible then,
185 * and primary head output will be limited to 135Mhz pixelclock. */
186 LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
187 gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN
);
188 si
->switched_crtcs
= true;
192 /* This limits the pixelclocks on both heads to 135Mhz,
193 * but you can use overlay on the other output now. */
194 LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
195 gx00_general_dac_select(DS_CRTC1MAVEN_CRTC2DAC
);
196 si
->switched_crtcs
= false;
197 /* re-calculate MAVEN-CRTC delay: formula valid for crossed CRTC's */
199 if (colour_depth1
== 16) si
->crtc_delay
+= 4;
200 /* re-setup vertical timing adjust for crtc connected to the MAVEN:
201 * cross connected. */
202 /* (extra "blanking" line for MAVEN hardware design fault) */
203 target
.timing
.v_display
++;
204 target2
.timing
.v_display
--;
211 if (!si
->ps
.primary_dvi
)
212 /* output connector use is always 'straight-through' */
213 //fixme: re-evaluate when DVI is setup...
215 switch (target
.flags
& DUALHEAD_BITS
)
219 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2
);
220 si
->switched_crtcs
= false;
222 case DUALHEAD_SWITCH
:
223 if (i2c_sec_tv_adapter() == B_OK
)
225 /* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
226 * and primary head output will be limited to 235Mhz pixelclock. */
227 LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
228 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2
);
229 si
->switched_crtcs
= true;
233 /* This limits the pixelclocks on both heads to 235Mhz,
234 * but you can use overlay on the other output now. */
235 LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
236 gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1
);
237 si
->switched_crtcs
= false;
243 /* output connector use is cross-linked if no TV cable connected! */
244 //fixme: re-evaluate when DVI is setup...
246 switch (target
.flags
& DUALHEAD_BITS
)
250 if (i2c_sec_tv_adapter() == B_OK
)
252 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2
);
253 si
->switched_crtcs
= false;
257 /* This limits the pixelclocks on both heads to 235Mhz,
258 * but you can use overlay on the other output now. */
259 gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1
);
260 si
->switched_crtcs
= false;
263 case DUALHEAD_SWITCH
:
264 if (i2c_sec_tv_adapter() == B_OK
)
266 /* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
267 * and primary head output will be limited to 235Mhz pixelclock. */
268 LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
269 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2
);
270 si
->switched_crtcs
= true;
274 LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
275 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2
);
276 si
->switched_crtcs
= false;
286 if (si
->switched_crtcs
)
288 uint32 temp
= startadd
;
289 startadd
= startadd_right
;
290 startadd_right
= temp
;
293 /*Tell card what memory to display*/
294 switch (target
.flags
& DUALHEAD_BITS
)
297 case DUALHEAD_SWITCH
:
298 gx00_crtc_set_display_start(startadd
,colour_depth1
);
299 g400_crtc2_set_display_start(startadd_right
,colour_depth2
);
302 gx00_crtc_set_display_start(startadd
,colour_depth1
);
303 g400_crtc2_set_display_start(startadd
,colour_depth2
);
308 gx00_crtc_set_timing(target
);
309 /* we do not need to setup CRTC2 here for a head that's in TVout mode */
310 if (!(target2
.flags
& TV_BITS
)) result
= g400_crtc2_set_timing(target2
);
312 /* TVout support: setup CRTC2 and it's pixelclock */
313 if (si
->ps
.tvout
&& (target2
.flags
& TV_BITS
)) maventv_init(target2
);
315 else /* single head mode */
318 int colour_mode
= BPP32
;
339 LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target
.space
));
343 /* set the pixel clock PLL */
344 if (si
->ps
.card_type
>= G100
)
345 //fixme: how about when TVout is enabled???
346 status
= gx00_dac_set_pix_pll(target
);
349 status
= mil2_dac_set_pix_pll((target
.timing
.pixel_clock
)/1000.0, colour_depth1
);
352 LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
354 /* set the colour depth for CRTC1 and the DAC */
355 gx00_dac_mode(colour_mode
,1.0);
356 gx00_crtc_depth(colour_mode
);
358 /* if we do TVout mode, its non-interlaced (as we are on <= G400MAX for sure) */
359 si
->interlaced_tv_mode
= false;
361 /* set the display pitch */
362 gx00_crtc_set_display_pitch();
364 /* tell the card what memory to display */
365 gx00_crtc_set_display_start(startadd
,colour_depth1
);
367 /* enable primary analog output */
368 switch (si
->ps
.card_type
)
374 if (!si
->ps
.secondary_head
&& si
->ps
.tvout
&& (target
.flags
& TV_BITS
))
375 gx00_general_dac_select(DS_CRTC1MAVEN
);
377 gx00_general_dac_select(DS_CRTC1DAC
);
381 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2
);
382 gx50_general_output_select();
389 if (!si
->ps
.secondary_head
&& si
->ps
.tvout
&& (target
.flags
& TV_BITS
))
391 /* calculate MAVEN-CRTC delay: only used during TVout */
393 if (colour_depth1
== 16) si
->crtc_delay
+= 4;
394 /* setup CRTC1 and it's pixelclock for TVout */
395 maventv_init(target
);
399 gx00_maven_shutoff();
400 gx00_crtc_set_timing(target
);
404 /* update driver's mode store */
407 /* set up acceleration for this mode */
410 /* restore screen(s) output state(s) */
411 SET_DPMS_MODE(si
->dpms_flags
);
413 /* clear line at bottom of screen if dualhead mode:
414 * MAVEN hardware design fault 'fix'.
416 * Not applicable for singlehead cards with a MAVEN, since it's only used
417 * for TVout there. */
418 if ((target
.flags
& DUALHEAD_BITS
) && (si
->ps
.card_type
<= G400MAX
))
419 gx00_maven_clrline();
421 LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
423 /* enable interrupts using the kernel driver */
424 interrupt_enable(true);
426 /* optimize memory-access if needed */
427 gx00_crtc_mem_priority(colour_depth1
);
429 /* Tune RAM CAS-latency if needed. Must be done *here*! */
430 mga_set_cas_latency();
436 Set which pixel of the virtual frame buffer will show up in the
437 top left corner of the display device. Used for page-flipping
438 games and virtual desktops.
440 status_t
MOVE_DISPLAY(uint16 h_display_start
, uint16 v_display_start
) {
442 uint32 startadd
,startadd_right
;
444 LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start
, v_display_start
));
446 /* G400 CRTC1 handles multiples of 8 for 8bit, 4 for 16bit, 2 for 32 bit
447 G400 CRTC2 handles multiples of 32 for 16-bit and 16 for 32-bit - must stoop to this in dualhead
450 /* reset lower bits, don't return an error! */
451 if (si
->dm
.flags
& DUALHEAD_BITS
)
457 h_display_start
&= ~0x1f;
461 h_display_start
&= ~0x0f;
464 LOG(8,("SET:Invalid DH colour depth 0x%08x, should never happen\n", si
->dm
.space
));
474 h_display_start
&= ~0x07;
476 case B_RGB15_LITTLE
: case B_RGB16_LITTLE
:
478 h_display_start
&= ~0x03;
482 h_display_start
&= ~0x01;
489 /* do not run past end of display */
490 switch (si
->dm
.flags
& DUALHEAD_BITS
)
493 case DUALHEAD_SWITCH
:
494 if (((si
->dm
.timing
.h_display
* 2) + h_display_start
) > si
->dm
.virtual_width
)
498 if ((si
->dm
.timing
.h_display
+ h_display_start
) > si
->dm
.virtual_width
)
502 if ((si
->dm
.timing
.v_display
+ v_display_start
) > si
->dm
.virtual_height
)
505 /* everybody remember where we parked... */
506 si
->dm
.h_display_start
= h_display_start
;
507 si
->dm
.v_display_start
= v_display_start
;
509 /* actually set the registers */
510 //fixme: seperate both heads: we need a secondary si->fbc!
511 startadd
= v_display_start
* si
->fbc
.bytes_per_row
;
512 startadd
+= h_display_start
* (colour_depth
>> 3);
513 startadd
+= (uint8
*)si
->fbc
.frame_buffer
- (uint8
*)si
->framebuffer
;
514 startadd_right
= startadd
+ si
->dm
.timing
.h_display
* (colour_depth
>> 3);
516 /* account for switched CRTC's */
517 if (si
->switched_crtcs
)
519 uint32 temp
= startadd
;
520 startadd
= startadd_right
;
521 startadd_right
= temp
;
524 interrupt_enable(false);
526 switch (si
->dm
.flags
&DUALHEAD_BITS
)
529 case DUALHEAD_SWITCH
:
530 gx00_crtc_set_display_start(startadd
,colour_depth
);
531 g400_crtc2_set_display_start(startadd_right
,colour_depth
);
534 gx00_crtc_set_display_start(startadd
,colour_depth
);
537 gx00_crtc_set_display_start(startadd
,colour_depth
);
538 g400_crtc2_set_display_start(startadd
,colour_depth
);
542 interrupt_enable(true);
547 Set the indexed color palette.
549 void SET_INDEXED_COLORS(uint count
, uint8 first
, uint8
*color_data
, uint32 flags
) {
553 /* Protect gamma correction when not in CMAP8 */
554 if (si
->dm
.space
!= B_CMAP8
) return;
568 gx00_dac_palette(r
,g
,b
);
571 /* Put the display into one of the Display Power Management modes. */
572 status_t
SET_DPMS_MODE(uint32 dpms_flags
)
574 interrupt_enable(false);
576 LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags
));
578 /* note current DPMS state for our reference */
579 si
->dpms_flags
= dpms_flags
;
581 if (si
->dm
.flags
& DUALHEAD_BITS
) /* dualhead */
585 case B_DPMS_ON
: /* H: on, V: on */
586 gx00_crtc_dpms(true, true, true);
587 if (si
->ps
.secondary_head
) g400_crtc2_dpms(true, true, true);
589 case B_DPMS_STAND_BY
:
590 if (si
->settings
.greensync
)
592 /* blank screen, but keep sync running */
593 gx00_crtc_dpms(false, true, true);
597 gx00_crtc_dpms(false, false, true);
599 if (si
->ps
.secondary_head
)
601 if ((si
->dm
.flags
& TV_BITS
) && (si
->ps
.card_type
> G400MAX
))
603 /* keep display enabled in TVout modes for G450 and G550! */
604 g400_crtc2_dpms(true, false, true);
608 g400_crtc2_dpms(false, false, true);
613 if (si
->settings
.greensync
)
615 /* blank screen, but keep sync running */
616 gx00_crtc_dpms(false, true, true);
620 gx00_crtc_dpms(false, true, false);
622 if (si
->ps
.secondary_head
)
624 if ((si
->dm
.flags
& TV_BITS
) && (si
->ps
.card_type
> G400MAX
))
626 /* keep display enabled in TVout modes for G450 and G550! */
627 g400_crtc2_dpms(true, true, false);
631 g400_crtc2_dpms(false, true, false);
635 case B_DPMS_OFF
: /* H: off, V: off, display off */
636 if (si
->settings
.greensync
)
638 /* blank screen, but keep sync running */
639 gx00_crtc_dpms(false, true, true);
643 gx00_crtc_dpms(false, false, false);
645 if (si
->ps
.secondary_head
)
647 if ((si
->dm
.flags
& TV_BITS
) && (si
->ps
.card_type
> G400MAX
))
649 /* keep display enabled in TVout modes for G450 and G550! */
650 g400_crtc2_dpms(true, false, false);
654 g400_crtc2_dpms(false, false, false);
659 LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags
));
660 interrupt_enable(true);
664 else /* singlehead */
668 case B_DPMS_ON
: /* H: on, V: on */
669 gx00_crtc_dpms(true, true, true);
670 /* on singlehead cards with TVout program the MAVEN as well */
671 if (si
->dm
.flags
& TV_BITS
) gx00_maven_dpms(true, true, true);
673 case B_DPMS_STAND_BY
:
674 if (si
->settings
.greensync
)
676 /* blank screen, but keep sync running */
677 gx00_crtc_dpms(false, true, true);
681 gx00_crtc_dpms(false, false, true);
683 /* on singlehead cards with TVout program the MAVEN as well */
684 if (si
->dm
.flags
& TV_BITS
) gx00_maven_dpms(false, false, true);
687 if (si
->settings
.greensync
)
689 /* blank screen, but keep sync running */
690 gx00_crtc_dpms(false, true, true);
694 gx00_crtc_dpms(false, true, false);
696 /* on singlehead cards with TVout program the MAVEN as well */
697 if (si
->dm
.flags
& TV_BITS
) gx00_maven_dpms(false, true, false);
699 case B_DPMS_OFF
: /* H: off, V: off, display off */
700 if (si
->settings
.greensync
)
702 /* blank screen, but keep sync running */
703 gx00_crtc_dpms(false, true, true);
707 gx00_crtc_dpms(false, false, false);
709 /* on singlehead cards with TVout program the MAVEN as well */
710 if (si
->dm
.flags
& TV_BITS
) gx00_maven_dpms(false, false, false);
713 LOG(8,("SET: Invalid DPMS settings (SH) 0x%08x\n", dpms_flags
));
714 interrupt_enable(true);
718 interrupt_enable(true);
722 /* Report device DPMS capabilities. */
723 uint32
DPMS_CAPABILITIES(void)
725 if (si
->settings
.greensync
)
726 /* we can blank the screen on CRTC1, G400 CRTC2 does not support intermediate
728 //fixme: G450/G550 support full DPMS on CRTC2...
729 return B_DPMS_ON
| B_DPMS_OFF
;
731 /* normally CRTC1 supports full DPMS (and on G450/G550 CRTC2 also).. */
732 return B_DPMS_ON
| B_DPMS_STAND_BY
| B_DPMS_SUSPEND
| B_DPMS_OFF
;
735 /* Return the current DPMS mode. */
736 uint32
DPMS_MODE(void)
738 return si
->dpms_flags
;