1 /* 2 Copyright 1999, Be Incorporated. All Rights Reserved. 3 This file may be used under the terms of the Be Sample Code License. 4 5 Other authors: 6 Rudolf Cornelissen 4/2003-1/2006 7 */ 8 9 #define MODULE_BIT 0x00200000 10 11 #include "acc_std.h" 12 13 /* 14 Enable/Disable interrupts. Just a wrapper around the 15 ioctl() to the kernel driver. 16 */ 17 static void interrupt_enable(bool flag) 18 { 19 status_t result; 20 nm_set_bool_state sbs; 21 22 if (si->ps.int_assigned) 23 { 24 /* set the magic number so the driver knows we're for real */ 25 sbs.magic = NM_PRIVATE_DATA_MAGIC; 26 sbs.do_it = flag; 27 /* contact driver and get a pointer to the registers and shared data */ 28 result = ioctl(fd, NM_RUN_INTERRUPTS, &sbs, sizeof(sbs)); 29 } 30 } 31 32 /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */ 33 status_t SET_DISPLAY_MODE(display_mode *mode_to_set) 34 { 35 /* BOUNDS WARNING: 36 * It's impossible to deviate whatever small amount in a display_mode if the lower 37 * and upper limits are the same! 38 * Besides: 39 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE 40 * returns B_BAD_VALUE! 41 * Which means PROPOSEMODE should not return that on anything except on 42 * deviations for: 43 * display_mode.virtual_width; 44 * display_mode.virtual_height; 45 * display_mode.timing.h_display; 46 * display_mode.timing.v_display; 47 * So: 48 * We don't use bounds here by making sure bounds and target are the same struct! 49 * (See the call to PROPOSE_DISPLAY_MODE below) */ 50 display_mode /*bounds,*/ target; 51 52 uint8 colour_depth = 24; 53 uint32 startadd; 54 55 /* if internal panel is active we don't touch the CRTC timing and the pixelPLL */ 56 bool crt_only = true; 57 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)); 65 66 /* See BOUNDS WARNING above... */ 67 if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR; 68 69 /* disable interrupts using the kernel driver */ 70 interrupt_enable(false); 71 72 /* make sure the card's registers are unlocked (KB output select may lock!) */ 73 nm_unlock(); 74 75 /* if we have the flatpanel turned on modify visible part of mode if nessesary */ 76 if (nm_general_output_read() & 0x02) 77 { 78 LOG(4,("SETMODE: internal flatpanel enabled, skipping CRTC/pixelPLL setup\n")); 79 crt_only = false; 80 } 81 82 /* turn off screen(s) */ 83 nm_crtc_dpms(false, false, false); 84 85 /* where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?) */ 86 startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; 87 88 /* Perform the mode switch */ 89 { 90 status_t status = B_OK; 91 int colour_mode = BPP24; 92 93 switch(target.space) 94 { 95 case B_CMAP8: colour_depth = 8; colour_mode = BPP8; break; 96 case B_RGB15_LITTLE: colour_depth = 16; colour_mode = BPP15; break; 97 case B_RGB16_LITTLE: colour_depth = 16; colour_mode = BPP16; break; 98 case B_RGB24_LITTLE: colour_depth = 24; colour_mode = BPP24; break; 99 default: 100 LOG(8,("SETMODE: Invalid colorspace $%08x\n", target.space)); 101 return B_ERROR; 102 } 103 104 /* calculate and set new mode bytes_per_row */ 105 nm_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode); 106 107 /* set the pixelclock PLL */ 108 if (crt_only) 109 { 110 status = nm_dac_set_pix_pll(target); 111 if (status == B_ERROR) 112 LOG(8,("CRTC: error setting pixelclock\n")); 113 } 114 115 /* set the colour depth for CRTC1 and the DAC */ 116 nm_dac_mode(colour_mode, 1.0); 117 nm_crtc_depth(colour_mode); 118 119 /* set the display pitch */ 120 nm_crtc_set_display_pitch(); 121 122 /* tell the card what memory to display */ 123 nm_crtc_set_display_start(startadd,colour_depth); 124 125 /* enable primary analog output */ 126 //fixme: choose output connector(s) 127 128 /* set the timing */ 129 nm_crtc_set_timing(target, crt_only); 130 131 /* always setup centering so a KB BIOS switch to flatpanel will go OK... */ 132 nm_crtc_center(target, crt_only); 133 /* program panel modeline if needed */ 134 if (!crt_only) nm_crtc_prg_panel(); 135 } 136 137 /* update driver's mode store */ 138 si->dm = target; 139 140 /* set up acceleration for this mode */ 141 nm_acc_init(); 142 143 /* restore screen(s) output state(s) */ 144 SET_DPMS_MODE(si->dpms_flags); 145 146 /* log currently selected output */ 147 nm_general_output_select(); 148 149 LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0)); 150 151 /* enable interrupts using the kernel driver */ 152 interrupt_enable(true); 153 154 /* Tune RAM CAS-latency if needed. Must be done *here*! */ 155 nm_set_cas_latency(); 156 157 return B_OK; 158 } 159 160 /* 161 Set which pixel of the virtual frame buffer will show up in the 162 top left corner of the display device. Used for page-flipping 163 games and virtual desktops. 164 */ 165 status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) 166 { 167 uint8 colour_depth; 168 uint32 startadd; 169 170 uint16 h_display = si->dm.timing.h_display; /* local copy needed for flatpanel */ 171 uint16 v_display = si->dm.timing.v_display; /* local copy needed for flatpanel */ 172 173 LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start)); 174 175 /* Neomagic cards support pixelprecise panning in all modes: 176 * No stepping granularity needed! */ 177 178 /* determine bits used for the colordepth */ 179 switch(si->dm.space) 180 { 181 case B_CMAP8: 182 colour_depth=8; 183 break; 184 case B_RGB15_LITTLE: 185 case B_RGB16_LITTLE: 186 colour_depth=16; 187 break; 188 case B_RGB24_LITTLE: 189 colour_depth=24; 190 break; 191 default: 192 return B_ERROR; 193 } 194 195 /* if internal panel is active correct visible screensize! */ 196 if (nm_general_output_read() & 0x02) 197 { 198 if (h_display > si->ps.panel_width) h_display = si->ps.panel_width; 199 if (v_display > si->ps.panel_height) v_display = si->ps.panel_height; 200 } 201 202 /* do not run past end of display */ 203 if ((h_display + h_display_start) > si->dm.virtual_width) 204 return B_ERROR; 205 if ((v_display + v_display_start) > si->dm.virtual_height) 206 return B_ERROR; 207 208 /* everybody remember where we parked... */ 209 si->dm.h_display_start = h_display_start; 210 si->dm.v_display_start = v_display_start; 211 212 /* actually set the registers */ 213 startadd = v_display_start * si->fbc.bytes_per_row; 214 startadd += h_display_start * (colour_depth >> 3); 215 startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; 216 217 interrupt_enable(false); 218 219 nm_crtc_set_display_start(startadd,colour_depth); 220 221 interrupt_enable(true); 222 return B_OK; 223 } 224 225 /* Set the indexed color palette. */ 226 void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) { 227 int i; 228 uint8 *r,*g,*b; 229 230 /* Protect gamma correction when not in CMAP8 */ 231 if (si->dm.space != B_CMAP8) return; 232 233 r = si->color_data; 234 g = r + 256; 235 b = g + 256; 236 237 i = first; 238 while (count--) 239 { 240 r[i] = *color_data++; 241 g[i] = *color_data++; 242 b[i] = *color_data++; 243 i++; 244 } 245 nm_dac_palette(r,g,b, 256); 246 } 247 248 /* Put the display into one of the Display Power Management modes. */ 249 status_t SET_DPMS_MODE(uint32 dpms_flags) 250 { 251 interrupt_enable(false); 252 253 LOG(4,("SET_DPMS_MODE: $%08x\n", dpms_flags)); 254 255 /* note current DPMS state for our reference */ 256 si->dpms_flags = dpms_flags; 257 258 switch(dpms_flags) 259 { 260 case B_DPMS_ON: /* H: on, V: on */ 261 nm_crtc_dpms(true, true , true); 262 break; 263 case B_DPMS_STAND_BY: 264 nm_crtc_dpms(false, false, true); 265 break; 266 case B_DPMS_SUSPEND: 267 nm_crtc_dpms(false, true, false); 268 break; 269 case B_DPMS_OFF: /* H: off, V: off, display off */ 270 nm_crtc_dpms(false, false, false); 271 break; 272 default: 273 LOG(8,("SET_DPMS_MODE: Invalid DPMS settings) $%08x\n", dpms_flags)); 274 interrupt_enable(true); 275 return B_ERROR; 276 } 277 interrupt_enable(true); 278 return B_OK; 279 } 280 281 /* Report device DPMS capabilities. */ 282 uint32 DPMS_CAPABILITIES(void) 283 { 284 if (si->ps.card_type < NM2200) 285 /* MagicGraph cards don't have full DPMS support */ 286 return B_DPMS_ON | B_DPMS_OFF; 287 else 288 /* MagicMedia cards do have full DPMS support for external monitors */ 289 //fixme: checkout if this is true... 290 return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; 291 } 292 293 /* Return the current DPMS mode. */ 294 uint32 DPMS_MODE(void) 295 { 296 return si->dpms_flags; 297 } 298