1 /* second CTRC functionality 2 3 Authors: 4 Mark Watson 6/2000, 5 Rudolf Cornelissen 12/2002 - 11/2005 6 */ 7 8 #define MODULE_BIT 0x00020000 9 10 #include "mga_std.h" 11 12 /*set a mode line - inputs are in pixels/scanlines*/ 13 status_t g400_crtc2_set_timing(display_mode target) 14 { 15 uint32 temp; 16 17 LOG(4,("CRTC2: setting timing\n")); 18 19 if ((!(target.flags & TV_BITS)) || (si->ps.card_type <= G400MAX)) 20 { 21 /* G450/G550 monitor mode, and all modes on older cards */ 22 23 /* check horizontal timing parameters are to nearest 8 pixels */ 24 if ((target.timing.h_display & 0x07) | (target.timing.h_sync_start & 0x07) | 25 (target.timing.h_sync_end & 0x07) | (target.timing.h_total & 0x07)) 26 { 27 LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n")); 28 return B_ERROR; 29 } 30 31 /* make sure NTSC clock killer circuitry is disabled */ 32 CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010)); 33 34 /* make sure CRTC2 is set to progressive scan for monitor mode */ 35 CR2W(CTL, (CR2R(CTL) & ~0x02001000)); 36 37 /* program the second CRTC */ 38 CR2W(HPARAM, ((((target.timing.h_display - 8) & 0x0fff) << 16) | 39 ((target.timing.h_total - 8) & 0x0fff))); 40 CR2W(HSYNC, ((((target.timing.h_sync_end - 8) & 0x0fff) << 16) | 41 ((target.timing.h_sync_start - 8) & 0x0fff))); 42 CR2W(VPARAM, ((((target.timing.v_display - 1) & 0x0fff) << 16) | 43 ((target.timing.v_total - 1) & 0x0fff))); 44 CR2W(VSYNC, ((((target.timing.v_sync_end - 1) & 0x0fff) << 16) | 45 ((target.timing.v_sync_start - 1) & 0x0fff))); 46 //Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!) 47 //CR2W(PRELOAD, (((target.timing.v_sync_start & 0x0fff) << 16) | 48 // (target.timing.h_sync_start & 0x0fff))); 49 CR2W(PRELOAD, ((((target.timing.v_sync_start - 1) & 0x0fff) << 16) | 50 ((target.timing.h_sync_start - 8) & 0x0fff))); 51 52 temp = (0xfff << 16); 53 if (!(target.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8); 54 if (!(target.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9); 55 CR2W(MISC, temp); 56 57 /* On <= G400MAX dualhead cards we need to send a copy to the MAVEN; 58 * unless TVout is active */ 59 if ((si->ps.secondary_head) && (!(target.flags & TV_BITS))) 60 gx00_maven_set_timing(target); 61 } 62 else 63 { 64 /* G450/G550 TVout mode */ 65 display_mode tv_mode = target; 66 uint8 frame; 67 unsigned int vcount, prev_vcount; 68 69 LOG(4,("CRTC2: setting up G450/G550 TVout mode\n")); 70 71 /* check horizontal timing parameters are to nearest 8 pixels */ 72 if ((tv_mode.timing.h_display & 0x07) | (tv_mode.timing.h_sync_start & 0x07) | 73 (tv_mode.timing.h_sync_end & 0x07)) 74 { 75 LOG(8,("CRTC2: Horizontal timings are not multiples of 8 pixels\n")); 76 return B_ERROR; 77 } 78 79 /* disable NTSC clock killer circuitry */ 80 CR2W(DATACTL, (CR2R(DATACTL) & ~0x00000010)); 81 82 if (tv_mode.timing.h_total & 0x07) 83 { 84 /* we rely on this for both PAL and NTSC modes if h_total is 'illegal' */ 85 LOG(4,("CRTC2: enabling clock killer circuitry\n")); 86 CR2W(DATACTL, (CR2R(DATACTL) | 0x00000010)); 87 } 88 89 /* make sure h_total is valid for TVout mode */ 90 tv_mode.timing.h_total &= ~0x07; 91 92 /* modify tv_mode for interlaced use */ 93 tv_mode.timing.v_display >>= 1; 94 tv_mode.timing.v_sync_start >>= 1; 95 tv_mode.timing.v_sync_end >>= 1; 96 tv_mode.timing.v_total >>= 1; 97 98 /*program the second CRTC*/ 99 CR2W(HPARAM, ((((tv_mode.timing.h_display - 8) & 0x0fff) << 16) | 100 ((tv_mode.timing.h_total - 8) & 0x0fff))); 101 CR2W(HSYNC, ((((tv_mode.timing.h_sync_end - 8) & 0x0fff) << 16) | 102 ((tv_mode.timing.h_sync_start - 8) & 0x0fff))); 103 CR2W(VPARAM, ((((tv_mode.timing.v_display - 1) & 0x0fff) << 16) | 104 ((tv_mode.timing.v_total - 1) & 0x0fff))); 105 CR2W(VSYNC, ((((tv_mode.timing.v_sync_end - 1) & 0x0fff) << 16) | 106 ((tv_mode.timing.v_sync_start - 1) & 0x0fff))); 107 //Mark: (wrong AFAIK, warning: SETMODE MAVEN-CRTC delay is now tuned to new setup!!) 108 //CR2W(PRELOAD, (((tv_mode.timing.v_sync_start & 0x0fff) << 16) | 109 // (tv_mode.timing.h_sync_start & 0x0fff))); 110 CR2W(PRELOAD, ((((tv_mode.timing.v_sync_start - 1) & 0x0fff) << 16) | 111 ((tv_mode.timing.h_sync_start - 8) & 0x0fff))); 112 113 /* set CRTC2 to interlaced mode: 114 * First enable progressive scan mode while making sure 115 * CRTC2 is setup for TVout mode use... */ 116 CR2W(CTL, ((CR2R(CTL) & ~0x02000000) | 0x00001000)); 117 /* now synchronize to the start of a frame... */ 118 prev_vcount = 0; 119 for (frame = 0; frame < 2; frame++) 120 { 121 for (;;) 122 { 123 vcount = (CR2R(VCOUNT) & 0x00000fff); 124 if (vcount >= prev_vcount) 125 prev_vcount = vcount; 126 else 127 break; 128 } 129 } 130 /* and start interlaced mode now! */ 131 CR2W(CTL, (CR2R(CTL) | 0x02000000)); 132 133 temp = (0xfff << 16); 134 if (!(tv_mode.timing.flags & B_POSITIVE_HSYNC)) temp |= (0x01 << 8); 135 if (!(tv_mode.timing.flags & B_POSITIVE_VSYNC)) temp |= (0x01 << 9); 136 CR2W(MISC, temp); 137 } 138 139 return B_OK; 140 } 141 142 status_t g400_crtc2_depth(int mode) 143 { 144 /* validate bit depth and set mode */ 145 /* also clears TVout mode (b12) */ 146 switch(mode) 147 { 148 case BPP16:case BPP32DIR: 149 CR2W(CTL,(CR2R(CTL)&0xFF10077F)|(mode<<21)); 150 break; 151 case BPP8:case BPP15:case BPP24:case BPP32:default: 152 LOG(8,("CRTC2:Invalid bit depth\n")); 153 return B_ERROR; 154 break; 155 } 156 157 return B_OK; 158 } 159 160 status_t g400_crtc2_dpms(bool display, bool h, bool v) 161 { 162 char msg[100]; 163 164 sprintf(msg, "CRTC2: setting DPMS: "); 165 166 if (si->ps.card_type <= G400MAX) 167 { 168 if (display && h && v) 169 { 170 /* enable CRTC2 and don't touch the rest */ 171 CR2W(CTL, ((CR2R(CTL) & 0xFFF0177E) | 0x01)); 172 sprintf(msg, "%sdisplay on, hsync enabled, vsync enabled\n", msg); 173 } 174 else 175 { 176 /* disable CRTC2 and don't touch the rest */ 177 CR2W(CTL, (CR2R(CTL) & 0xFFF0177E)); 178 sprintf(msg, "%sdisplay off, hsync disabled, vsync disabled\n", msg); 179 } 180 181 LOG(4, (msg)); 182 183 /* On <= G400MAX dualhead cards we always need to send a 'copy' to the MAVEN */ 184 if (si->ps.secondary_head) gx00_maven_dpms(display, h, v); 185 } 186 else /* G450/G550 */ 187 { 188 /* set HD15 and DVI-A sync pol. to be fixed 'straight through' from the CRTCs, 189 * and preset enabled sync signals on both connectors. 190 * (polarities and primary DPMS are done via other registers.) */ 191 uint8 temp = 0x00; 192 193 if (display) 194 { 195 /* enable CRTC2 and don't touch the rest */ 196 CR2W(CTL, ((CR2R(CTL) & 0xFFF0177E) | 0x01)); 197 sprintf(msg, "%sdisplay on, ", msg); 198 } 199 else 200 { 201 /* disable CRTC2 and don't touch the rest */ 202 CR2W(CTL, (CR2R(CTL) & 0xFFF0177E)); 203 sprintf(msg, "%sdisplay off, ", msg); 204 } 205 206 if (si->crossed_conns) 207 { 208 if (h) 209 { 210 /* enable DVI-A hsync */ 211 temp &= ~0x01; 212 sprintf(msg, "%shsync enabled, ", msg); 213 } 214 else 215 { 216 /* disable DVI-A hsync */ 217 temp |= 0x01; 218 sprintf(msg, "%shsync disabled, ", msg); 219 } 220 if (v) 221 { 222 /* enable DVI-A vsync */ 223 temp &= ~0x02; 224 sprintf(msg, "%svsync enabled\n", msg); 225 } 226 else 227 { 228 /* disable DVI-A vsync */ 229 temp |= 0x02; 230 sprintf(msg, "%svsync disabled\n", msg); 231 } 232 } 233 else 234 { 235 if (h) 236 { 237 /* enable HD15 hsync */ 238 temp &= ~0x10; 239 sprintf(msg, "%shsync enabled, ", msg); 240 } 241 else 242 { 243 /* disable HD15 hsync */ 244 temp |= 0x10; 245 sprintf(msg, "%shsync disabled, ", msg); 246 } 247 if (v) 248 { 249 /* enable HD15 vsync */ 250 temp &= ~0x20; 251 sprintf(msg, "%svsync enabled\n", msg); 252 } 253 else 254 { 255 /* disable HD15 vsync */ 256 temp |= 0x20; 257 sprintf(msg, "%svsync disabled\n", msg); 258 } 259 } 260 261 LOG(4, (msg)); 262 263 /* program new syncs */ 264 DXIW(SYNCCTRL, temp); 265 } 266 267 return B_OK; 268 } 269 270 status_t g400_crtc2_set_display_pitch() 271 { 272 uint32 offset; 273 274 LOG(4,("CRTC2: setting card pitch (offset between lines)\n")); 275 276 /* figure out offset value hardware needs */ 277 offset = si->fbc.bytes_per_row; 278 if (si->interlaced_tv_mode) 279 { 280 LOG(4,("CRTC2: setting interlaced mode\n")); 281 /* double the CRTC2 linelength so fields are displayed instead of frames */ 282 offset *= 2; 283 } 284 else 285 LOG(4,("CRTC2: setting progressive scan mode\n")); 286 287 LOG(2,("CRTC2: offset set to %d bytes\n", offset)); 288 289 /* program the head */ 290 CR2W(OFFSET,offset); 291 return B_OK; 292 } 293 294 status_t g400_crtc2_set_display_start(uint32 startadd,uint8 bpp) 295 { 296 LOG(4,("CRTC2: setting card RAM to be displayed for %d bits per pixel\n", bpp)); 297 298 LOG(2,("CRTC2: startadd: $%x\n",startadd)); 299 LOG(2,("CRTC2: frameRAM: $%x\n",si->framebuffer)); 300 LOG(2,("CRTC2: framebuffer: $%x\n",si->fbc.frame_buffer)); 301 302 if (si->interlaced_tv_mode) 303 { 304 LOG(4,("CRTC2: setting up fields for interlaced mode\n")); 305 /* program the head for interlaced use */ 306 //fixme: seperate both heads: we need a secondary si->fbc! 307 /* setup field 0 startadress in buffer to read picture's odd lines */ 308 CR2W(STARTADD0, (startadd + si->fbc.bytes_per_row)); 309 /* setup field 1 startadress in buffer to read picture's even lines */ 310 CR2W(STARTADD1, startadd); 311 } 312 else 313 { 314 LOG(4,("CRTC2: setting up frames for progressive scan mode\n")); 315 /* program the head for non-interlaced use */ 316 CR2W(STARTADD0, startadd); 317 } 318 319 return B_OK; 320 } 321