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