1*68353368SRudolf Cornelissen /* CTRC functionality */ 2*68353368SRudolf Cornelissen /* Author: 3*68353368SRudolf Cornelissen Rudolf Cornelissen 11/2002-9/2004 4*68353368SRudolf Cornelissen */ 5*68353368SRudolf Cornelissen 6*68353368SRudolf Cornelissen #define MODULE_BIT 0x00040000 7*68353368SRudolf Cornelissen 8*68353368SRudolf Cornelissen #include "nv_std.h" 9*68353368SRudolf Cornelissen 10*68353368SRudolf Cornelissen /*Adjust passed parameters to a valid mode line*/ 11*68353368SRudolf Cornelissen status_t nv_crtc_validate_timing( 12*68353368SRudolf Cornelissen uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht, 13*68353368SRudolf Cornelissen uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt 14*68353368SRudolf Cornelissen ) 15*68353368SRudolf Cornelissen { 16*68353368SRudolf Cornelissen /* horizontal */ 17*68353368SRudolf Cornelissen /* make all parameters multiples of 8 */ 18*68353368SRudolf Cornelissen *hd_e &= 0xfff8; 19*68353368SRudolf Cornelissen *hs_s &= 0xfff8; 20*68353368SRudolf Cornelissen *hs_e &= 0xfff8; 21*68353368SRudolf Cornelissen *ht &= 0xfff8; 22*68353368SRudolf Cornelissen 23*68353368SRudolf Cornelissen /* confine to required number of bits, taking logic into account */ 24*68353368SRudolf Cornelissen if (*hd_e > ((0x01ff - 2) << 3)) *hd_e = ((0x01ff - 2) << 3); 25*68353368SRudolf Cornelissen if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3); 26*68353368SRudolf Cornelissen if (*hs_e > ( 0x01ff << 3)) *hs_e = ( 0x01ff << 3); 27*68353368SRudolf Cornelissen if (*ht > ((0x01ff + 5) << 3)) *ht = ((0x01ff + 5) << 3); 28*68353368SRudolf Cornelissen 29*68353368SRudolf Cornelissen /* NOTE: keep horizontal timing at multiples of 8! */ 30*68353368SRudolf Cornelissen /* confine to a reasonable width */ 31*68353368SRudolf Cornelissen if (*hd_e < 640) *hd_e = 640; 32*68353368SRudolf Cornelissen if (si->ps.card_type > NV04) 33*68353368SRudolf Cornelissen { 34*68353368SRudolf Cornelissen if (*hd_e > 2048) *hd_e = 2048; 35*68353368SRudolf Cornelissen } 36*68353368SRudolf Cornelissen else 37*68353368SRudolf Cornelissen { 38*68353368SRudolf Cornelissen if (*hd_e > 1920) *hd_e = 1920; 39*68353368SRudolf Cornelissen } 40*68353368SRudolf Cornelissen 41*68353368SRudolf Cornelissen /* if hor. total does not leave room for a sensible sync pulse, increase it! */ 42*68353368SRudolf Cornelissen if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80); 43*68353368SRudolf Cornelissen 44*68353368SRudolf Cornelissen /* if hor. total does not adhere to max. blanking pulse width, decrease it! */ 45*68353368SRudolf Cornelissen if (*ht > (*hd_e + 0x3f8)) *ht = (*hd_e + 0x3f8); 46*68353368SRudolf Cornelissen 47*68353368SRudolf Cornelissen /* make sure sync pulse is not during display */ 48*68353368SRudolf Cornelissen if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8); 49*68353368SRudolf Cornelissen if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8); 50*68353368SRudolf Cornelissen 51*68353368SRudolf Cornelissen /* correct sync pulse if it is too long: 52*68353368SRudolf Cornelissen * there are only 5 bits available to save this in the card registers! */ 53*68353368SRudolf Cornelissen if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8); 54*68353368SRudolf Cornelissen 55*68353368SRudolf Cornelissen /*vertical*/ 56*68353368SRudolf Cornelissen /* confine to required number of bits, taking logic into account */ 57*68353368SRudolf Cornelissen //fixme if needed: on GeForce cards there are 12 instead of 11 bits... 58*68353368SRudolf Cornelissen if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2); 59*68353368SRudolf Cornelissen if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1); 60*68353368SRudolf Cornelissen if (*vs_e > 0x7ff ) *vs_e = 0x7ff ; 61*68353368SRudolf Cornelissen if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2); 62*68353368SRudolf Cornelissen 63*68353368SRudolf Cornelissen /* confine to a reasonable height */ 64*68353368SRudolf Cornelissen if (*vd_e < 480) *vd_e = 480; 65*68353368SRudolf Cornelissen if (si->ps.card_type > NV04) 66*68353368SRudolf Cornelissen { 67*68353368SRudolf Cornelissen if (*vd_e > 1536) *vd_e = 1536; 68*68353368SRudolf Cornelissen } 69*68353368SRudolf Cornelissen else 70*68353368SRudolf Cornelissen { 71*68353368SRudolf Cornelissen if (*vd_e > 1440) *vd_e = 1440; 72*68353368SRudolf Cornelissen } 73*68353368SRudolf Cornelissen 74*68353368SRudolf Cornelissen /*if vertical total does not leave room for a sync pulse, increase it!*/ 75*68353368SRudolf Cornelissen if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3); 76*68353368SRudolf Cornelissen 77*68353368SRudolf Cornelissen /* if vert. total does not adhere to max. blanking pulse width, decrease it! */ 78*68353368SRudolf Cornelissen if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff); 79*68353368SRudolf Cornelissen 80*68353368SRudolf Cornelissen /* make sure sync pulse is not during display */ 81*68353368SRudolf Cornelissen if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1); 82*68353368SRudolf Cornelissen if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1); 83*68353368SRudolf Cornelissen 84*68353368SRudolf Cornelissen /* correct sync pulse if it is too long: 85*68353368SRudolf Cornelissen * there are only 4 bits available to save this in the card registers! */ 86*68353368SRudolf Cornelissen if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f); 87*68353368SRudolf Cornelissen 88*68353368SRudolf Cornelissen return B_OK; 89*68353368SRudolf Cornelissen } 90*68353368SRudolf Cornelissen 91*68353368SRudolf Cornelissen /*set a mode line - inputs are in pixels*/ 92*68353368SRudolf Cornelissen status_t nv_crtc_set_timing(display_mode target) 93*68353368SRudolf Cornelissen { 94*68353368SRudolf Cornelissen uint8 temp; 95*68353368SRudolf Cornelissen 96*68353368SRudolf Cornelissen uint32 htotal; /*total horizontal total VCLKs*/ 97*68353368SRudolf Cornelissen uint32 hdisp_e; /*end of horizontal display (begins at 0)*/ 98*68353368SRudolf Cornelissen uint32 hsync_s; /*begin of horizontal sync pulse*/ 99*68353368SRudolf Cornelissen uint32 hsync_e; /*end of horizontal sync pulse*/ 100*68353368SRudolf Cornelissen uint32 hblnk_s; /*begin horizontal blanking*/ 101*68353368SRudolf Cornelissen uint32 hblnk_e; /*end horizontal blanking*/ 102*68353368SRudolf Cornelissen 103*68353368SRudolf Cornelissen uint32 vtotal; /*total vertical total scanlines*/ 104*68353368SRudolf Cornelissen uint32 vdisp_e; /*end of vertical display*/ 105*68353368SRudolf Cornelissen uint32 vsync_s; /*begin of vertical sync pulse*/ 106*68353368SRudolf Cornelissen uint32 vsync_e; /*end of vertical sync pulse*/ 107*68353368SRudolf Cornelissen uint32 vblnk_s; /*begin vertical blanking*/ 108*68353368SRudolf Cornelissen uint32 vblnk_e; /*end vertical blanking*/ 109*68353368SRudolf Cornelissen 110*68353368SRudolf Cornelissen uint32 linecomp; /*split screen and vdisp_e interrupt*/ 111*68353368SRudolf Cornelissen 112*68353368SRudolf Cornelissen LOG(4,("CRTC: setting timing\n")); 113*68353368SRudolf Cornelissen 114*68353368SRudolf Cornelissen /* setup tuned internal modeline for flatpanel if connected and active */ 115*68353368SRudolf Cornelissen /* notes: 116*68353368SRudolf Cornelissen * - the CRTC modeline must end earlier than the panel modeline to keep correct 117*68353368SRudolf Cornelissen * sync going; 118*68353368SRudolf Cornelissen * - if the CRTC modeline ends too soon, pixelnoise will occur in 8 (or so) pixel 119*68353368SRudolf Cornelissen * wide horizontal stripes. This can be observed earliest on fullscreen overlay, 120*68353368SRudolf Cornelissen * and if it gets worse, also normal desktop output will suffer. The stripes 121*68353368SRudolf Cornelissen * are mainly visible at the left of the screen, over the entire screen height. */ 122*68353368SRudolf Cornelissen if (si->ps.tmds1_active) 123*68353368SRudolf Cornelissen { 124*68353368SRudolf Cornelissen LOG(2,("CRTC: DFP active: tuning modeline\n")); 125*68353368SRudolf Cornelissen 126*68353368SRudolf Cornelissen /* horizontal timing */ 127*68353368SRudolf Cornelissen target.timing.h_sync_start = 128*68353368SRudolf Cornelissen ((uint16)((si->ps.p1_timing.h_sync_start / ((float)si->ps.p1_timing.h_display)) * 129*68353368SRudolf Cornelissen target.timing.h_display)) & 0xfff8; 130*68353368SRudolf Cornelissen 131*68353368SRudolf Cornelissen target.timing.h_sync_end = 132*68353368SRudolf Cornelissen ((uint16)((si->ps.p1_timing.h_sync_end / ((float)si->ps.p1_timing.h_display)) * 133*68353368SRudolf Cornelissen target.timing.h_display)) & 0xfff8; 134*68353368SRudolf Cornelissen 135*68353368SRudolf Cornelissen target.timing.h_total = 136*68353368SRudolf Cornelissen (((uint16)((si->ps.p1_timing.h_total / ((float)si->ps.p1_timing.h_display)) * 137*68353368SRudolf Cornelissen target.timing.h_display)) & 0xfff8) - 8; 138*68353368SRudolf Cornelissen 139*68353368SRudolf Cornelissen /* in native mode the CRTC needs some extra time to keep synced correctly; 140*68353368SRudolf Cornelissen * OTOH the overlay unit distorts if we reserve too much time! */ 141*68353368SRudolf Cornelissen if (target.timing.h_display == si->ps.p1_timing.h_display) 142*68353368SRudolf Cornelissen { 143*68353368SRudolf Cornelissen /* NV11 timing has different constraints than later cards */ 144*68353368SRudolf Cornelissen if (si->ps.card_type == NV11) 145*68353368SRudolf Cornelissen target.timing.h_total -= 56; 146*68353368SRudolf Cornelissen else 147*68353368SRudolf Cornelissen /* confirmed NV34 with 1680x1050 panel */ 148*68353368SRudolf Cornelissen target.timing.h_total -= 32; 149*68353368SRudolf Cornelissen } 150*68353368SRudolf Cornelissen 151*68353368SRudolf Cornelissen if (target.timing.h_sync_start == target.timing.h_display) 152*68353368SRudolf Cornelissen target.timing.h_sync_start += 8; 153*68353368SRudolf Cornelissen if (target.timing.h_sync_end == target.timing.h_total) 154*68353368SRudolf Cornelissen target.timing.h_sync_end -= 8; 155*68353368SRudolf Cornelissen 156*68353368SRudolf Cornelissen /* vertical timing */ 157*68353368SRudolf Cornelissen target.timing.v_sync_start = 158*68353368SRudolf Cornelissen ((uint16)((si->ps.p1_timing.v_sync_start / ((float)si->ps.p1_timing.v_display)) * 159*68353368SRudolf Cornelissen target.timing.v_display)); 160*68353368SRudolf Cornelissen 161*68353368SRudolf Cornelissen target.timing.v_sync_end = 162*68353368SRudolf Cornelissen ((uint16)((si->ps.p1_timing.v_sync_end / ((float)si->ps.p1_timing.v_display)) * 163*68353368SRudolf Cornelissen target.timing.v_display)); 164*68353368SRudolf Cornelissen 165*68353368SRudolf Cornelissen target.timing.v_total = 166*68353368SRudolf Cornelissen ((uint16)((si->ps.p1_timing.v_total / ((float)si->ps.p1_timing.v_display)) * 167*68353368SRudolf Cornelissen target.timing.v_display)) - 1; 168*68353368SRudolf Cornelissen 169*68353368SRudolf Cornelissen if (target.timing.v_sync_start == target.timing.v_display) 170*68353368SRudolf Cornelissen target.timing.v_sync_start += 1; 171*68353368SRudolf Cornelissen if (target.timing.v_sync_end == target.timing.v_total) 172*68353368SRudolf Cornelissen target.timing.v_sync_end -= 1; 173*68353368SRudolf Cornelissen 174*68353368SRudolf Cornelissen /* disable GPU scaling testmode so automatic scaling will be done */ 175*68353368SRudolf Cornelissen DACW(FP_DEBUG1, 0); 176*68353368SRudolf Cornelissen } 177*68353368SRudolf Cornelissen 178*68353368SRudolf Cornelissen /* Modify parameters as required by standard VGA */ 179*68353368SRudolf Cornelissen htotal = ((target.timing.h_total >> 3) - 5); 180*68353368SRudolf Cornelissen hdisp_e = ((target.timing.h_display >> 3) - 1); 181*68353368SRudolf Cornelissen hblnk_s = hdisp_e; 182*68353368SRudolf Cornelissen hblnk_e = (htotal + 4);//0; 183*68353368SRudolf Cornelissen hsync_s = (target.timing.h_sync_start >> 3); 184*68353368SRudolf Cornelissen hsync_e = (target.timing.h_sync_end >> 3); 185*68353368SRudolf Cornelissen 186*68353368SRudolf Cornelissen vtotal = target.timing.v_total - 2; 187*68353368SRudolf Cornelissen vdisp_e = target.timing.v_display - 1; 188*68353368SRudolf Cornelissen vblnk_s = vdisp_e; 189*68353368SRudolf Cornelissen vblnk_e = (vtotal + 1); 190*68353368SRudolf Cornelissen vsync_s = target.timing.v_sync_start;//-1; 191*68353368SRudolf Cornelissen vsync_e = target.timing.v_sync_end;//-1; 192*68353368SRudolf Cornelissen 193*68353368SRudolf Cornelissen /* prevent memory adress counter from being reset (linecomp may not occur) */ 194*68353368SRudolf Cornelissen linecomp = target.timing.v_display; 195*68353368SRudolf Cornelissen 196*68353368SRudolf Cornelissen /* enable access to primary head */ 197*68353368SRudolf Cornelissen set_crtc_owner(0); 198*68353368SRudolf Cornelissen 199*68353368SRudolf Cornelissen /* Note for laptop and DVI flatpanels: 200*68353368SRudolf Cornelissen * CRTC timing has a seperate set of registers from flatpanel timing. 201*68353368SRudolf Cornelissen * The flatpanel timing registers have scaling registers that are used to match 202*68353368SRudolf Cornelissen * these two modelines. */ 203*68353368SRudolf Cornelissen { 204*68353368SRudolf Cornelissen LOG(4,("CRTC: Setting full timing...\n")); 205*68353368SRudolf Cornelissen 206*68353368SRudolf Cornelissen /* log the mode that will be set */ 207*68353368SRudolf Cornelissen LOG(2,("CRTC:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e)); 208*68353368SRudolf Cornelissen LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e)); 209*68353368SRudolf Cornelissen 210*68353368SRudolf Cornelissen /* actually program the card! */ 211*68353368SRudolf Cornelissen /* unlock CRTC registers at index 0-7 */ 212*68353368SRudolf Cornelissen CRTCW(VSYNCE, (CRTCR(VSYNCE) & 0x7f)); 213*68353368SRudolf Cornelissen /* horizontal standard VGA regs */ 214*68353368SRudolf Cornelissen CRTCW(HTOTAL, (htotal & 0xff)); 215*68353368SRudolf Cornelissen CRTCW(HDISPE, (hdisp_e & 0xff)); 216*68353368SRudolf Cornelissen CRTCW(HBLANKS, (hblnk_s & 0xff)); 217*68353368SRudolf Cornelissen /* also unlock vertical retrace registers in advance */ 218*68353368SRudolf Cornelissen CRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80)); 219*68353368SRudolf Cornelissen CRTCW(HSYNCS, (hsync_s & 0xff)); 220*68353368SRudolf Cornelissen CRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2))); 221*68353368SRudolf Cornelissen 222*68353368SRudolf Cornelissen /* vertical standard VGA regs */ 223*68353368SRudolf Cornelissen CRTCW(VTOTAL, (vtotal & 0xff)); 224*68353368SRudolf Cornelissen CRTCW(OVERFLOW, 225*68353368SRudolf Cornelissen ( 226*68353368SRudolf Cornelissen ((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) | 227*68353368SRudolf Cornelissen ((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) | 228*68353368SRudolf Cornelissen ((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) | 229*68353368SRudolf Cornelissen ((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4)) 230*68353368SRudolf Cornelissen )); 231*68353368SRudolf Cornelissen CRTCW(PRROWSCN, 0x00); /* not used */ 232*68353368SRudolf Cornelissen CRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6)))); 233*68353368SRudolf Cornelissen CRTCW(VSYNCS, (vsync_s & 0xff)); 234*68353368SRudolf Cornelissen CRTCW(VSYNCE, ((CRTCR(VSYNCE) & 0xf0) | (vsync_e & 0x0f))); 235*68353368SRudolf Cornelissen CRTCW(VDISPE, (vdisp_e & 0xff)); 236*68353368SRudolf Cornelissen CRTCW(VBLANKS, (vblnk_s & 0xff)); 237*68353368SRudolf Cornelissen CRTCW(VBLANKE, (vblnk_e & 0xff)); 238*68353368SRudolf Cornelissen CRTCW(LINECOMP, (linecomp & 0xff)); 239*68353368SRudolf Cornelissen 240*68353368SRudolf Cornelissen /* horizontal extended regs */ 241*68353368SRudolf Cornelissen //fixme: we reset bit4. is this correct?? 242*68353368SRudolf Cornelissen CRTCW(HEB, (CRTCR(HEB) & 0xe0) | 243*68353368SRudolf Cornelissen ( 244*68353368SRudolf Cornelissen ((htotal & 0x100) >> (8 - 0)) | 245*68353368SRudolf Cornelissen ((hdisp_e & 0x100) >> (8 - 1)) | 246*68353368SRudolf Cornelissen ((hblnk_s & 0x100) >> (8 - 2)) | 247*68353368SRudolf Cornelissen ((hsync_s & 0x100) >> (8 - 3)) 248*68353368SRudolf Cornelissen )); 249*68353368SRudolf Cornelissen 250*68353368SRudolf Cornelissen /* (mostly) vertical extended regs */ 251*68353368SRudolf Cornelissen CRTCW(LSR, 252*68353368SRudolf Cornelissen ( 253*68353368SRudolf Cornelissen ((vtotal & 0x400) >> (10 - 0)) | 254*68353368SRudolf Cornelissen ((vdisp_e & 0x400) >> (10 - 1)) | 255*68353368SRudolf Cornelissen ((vsync_s & 0x400) >> (10 - 2)) | 256*68353368SRudolf Cornelissen ((vblnk_s & 0x400) >> (10 - 3)) | 257*68353368SRudolf Cornelissen ((hblnk_e & 0x040) >> (6 - 4)) 258*68353368SRudolf Cornelissen //fixme: we still miss one linecomp bit!?! is this it?? 259*68353368SRudolf Cornelissen //| ((linecomp & 0x400) >> 3) 260*68353368SRudolf Cornelissen )); 261*68353368SRudolf Cornelissen 262*68353368SRudolf Cornelissen /* more vertical extended regs (on GeForce cards only) */ 263*68353368SRudolf Cornelissen if (si->ps.card_arch >= NV10A) 264*68353368SRudolf Cornelissen { 265*68353368SRudolf Cornelissen CRTCW(EXTRA, 266*68353368SRudolf Cornelissen ( 267*68353368SRudolf Cornelissen ((vtotal & 0x800) >> (11 - 0)) | 268*68353368SRudolf Cornelissen ((vdisp_e & 0x800) >> (11 - 2)) | 269*68353368SRudolf Cornelissen ((vsync_s & 0x800) >> (11 - 4)) | 270*68353368SRudolf Cornelissen ((vblnk_s & 0x800) >> (11 - 6)) 271*68353368SRudolf Cornelissen //fixme: do we miss another linecomp bit!?! 272*68353368SRudolf Cornelissen )); 273*68353368SRudolf Cornelissen } 274*68353368SRudolf Cornelissen 275*68353368SRudolf Cornelissen /* setup 'large screen' mode */ 276*68353368SRudolf Cornelissen if (target.timing.h_display >= 1280) 277*68353368SRudolf Cornelissen CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xfb)); 278*68353368SRudolf Cornelissen else 279*68353368SRudolf Cornelissen CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x04)); 280*68353368SRudolf Cornelissen 281*68353368SRudolf Cornelissen /* setup HSYNC & VSYNC polarity */ 282*68353368SRudolf Cornelissen LOG(2,("CRTC: sync polarity: ")); 283*68353368SRudolf Cornelissen temp = NV_REG8(NV8_MISCR); 284*68353368SRudolf Cornelissen if (target.timing.flags & B_POSITIVE_HSYNC) 285*68353368SRudolf Cornelissen { 286*68353368SRudolf Cornelissen LOG(2,("H:pos ")); 287*68353368SRudolf Cornelissen temp &= ~0x40; 288*68353368SRudolf Cornelissen } 289*68353368SRudolf Cornelissen else 290*68353368SRudolf Cornelissen { 291*68353368SRudolf Cornelissen LOG(2,("H:neg ")); 292*68353368SRudolf Cornelissen temp |= 0x40; 293*68353368SRudolf Cornelissen } 294*68353368SRudolf Cornelissen if (target.timing.flags & B_POSITIVE_VSYNC) 295*68353368SRudolf Cornelissen { 296*68353368SRudolf Cornelissen LOG(2,("V:pos ")); 297*68353368SRudolf Cornelissen temp &= ~0x80; 298*68353368SRudolf Cornelissen } 299*68353368SRudolf Cornelissen else 300*68353368SRudolf Cornelissen { 301*68353368SRudolf Cornelissen LOG(2,("V:neg ")); 302*68353368SRudolf Cornelissen temp |= 0x80; 303*68353368SRudolf Cornelissen } 304*68353368SRudolf Cornelissen NV_REG8(NV8_MISCW) = temp; 305*68353368SRudolf Cornelissen 306*68353368SRudolf Cornelissen LOG(2,(", MISC reg readback: $%02x\n", NV_REG8(NV8_MISCR))); 307*68353368SRudolf Cornelissen } 308*68353368SRudolf Cornelissen 309*68353368SRudolf Cornelissen /* always disable interlaced operation */ 310*68353368SRudolf Cornelissen /* (interlace is supported on upto and including NV10, NV15, and NV30 and up) */ 311*68353368SRudolf Cornelissen CRTCW(INTERLACE, 0xff); 312*68353368SRudolf Cornelissen 313*68353368SRudolf Cornelissen /* disable CRTC slaved mode unless a panel is in use */ 314*68353368SRudolf Cornelissen // fixme: this kills TVout when it was in use... 315*68353368SRudolf Cornelissen if (!si->ps.tmds1_active) CRTCW(PIXEL, (CRTCR(PIXEL) & 0x7f)); 316*68353368SRudolf Cornelissen 317*68353368SRudolf Cornelissen /* setup flatpanel if connected and active */ 318*68353368SRudolf Cornelissen if (si->ps.tmds1_active) 319*68353368SRudolf Cornelissen { 320*68353368SRudolf Cornelissen uint32 iscale_x, iscale_y; 321*68353368SRudolf Cornelissen 322*68353368SRudolf Cornelissen /* calculate inverse scaling factors used by hardware in 20.12 format */ 323*68353368SRudolf Cornelissen iscale_x = (((1 << 12) * target.timing.h_display) / si->ps.p1_timing.h_display); 324*68353368SRudolf Cornelissen iscale_y = (((1 << 12) * target.timing.v_display) / si->ps.p1_timing.v_display); 325*68353368SRudolf Cornelissen 326*68353368SRudolf Cornelissen /* unblock flatpanel timing programming (or something like that..) */ 327*68353368SRudolf Cornelissen CRTCW(FP_HTIMING, 0); 328*68353368SRudolf Cornelissen CRTCW(FP_VTIMING, 0); 329*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_HTIMING reg readback: $%02x\n", CRTCR(FP_HTIMING))); 330*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_VTIMING reg readback: $%02x\n", CRTCR(FP_VTIMING))); 331*68353368SRudolf Cornelissen 332*68353368SRudolf Cornelissen /* enable full width visibility on flatpanel */ 333*68353368SRudolf Cornelissen DACW(FP_HVALID_S, 0); 334*68353368SRudolf Cornelissen DACW(FP_HVALID_E, (si->ps.p1_timing.h_display - 1)); 335*68353368SRudolf Cornelissen /* enable full height visibility on flatpanel */ 336*68353368SRudolf Cornelissen DACW(FP_VVALID_S, 0); 337*68353368SRudolf Cornelissen DACW(FP_VVALID_E, (si->ps.p1_timing.v_display - 1)); 338*68353368SRudolf Cornelissen 339*68353368SRudolf Cornelissen /* nVidia cards support upscaling except on ??? */ 340*68353368SRudolf Cornelissen /* NV11 cards can upscale after all! */ 341*68353368SRudolf Cornelissen if (0)//si->ps.card_type == NV11) 342*68353368SRudolf Cornelissen { 343*68353368SRudolf Cornelissen /* disable last fetched line limiting */ 344*68353368SRudolf Cornelissen DACW(FP_DEBUG2, 0x00000000); 345*68353368SRudolf Cornelissen /* inform panel to scale if needed */ 346*68353368SRudolf Cornelissen if ((iscale_x != (1 << 12)) || (iscale_y != (1 << 12))) 347*68353368SRudolf Cornelissen { 348*68353368SRudolf Cornelissen LOG(2,("CRTC: DFP needs to do scaling\n")); 349*68353368SRudolf Cornelissen DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) | 0x00000100)); 350*68353368SRudolf Cornelissen } 351*68353368SRudolf Cornelissen else 352*68353368SRudolf Cornelissen { 353*68353368SRudolf Cornelissen LOG(2,("CRTC: no scaling for DFP needed\n")); 354*68353368SRudolf Cornelissen DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) & 0xfffffeff)); 355*68353368SRudolf Cornelissen } 356*68353368SRudolf Cornelissen } 357*68353368SRudolf Cornelissen else 358*68353368SRudolf Cornelissen { 359*68353368SRudolf Cornelissen float dm_aspect; 360*68353368SRudolf Cornelissen 361*68353368SRudolf Cornelissen LOG(2,("CRTC: GPU scales for DFP if needed\n")); 362*68353368SRudolf Cornelissen 363*68353368SRudolf Cornelissen /* calculate display mode aspect */ 364*68353368SRudolf Cornelissen dm_aspect = (target.timing.h_display / ((float)target.timing.v_display)); 365*68353368SRudolf Cornelissen 366*68353368SRudolf Cornelissen /* limit last fetched line if vertical scaling is done */ 367*68353368SRudolf Cornelissen if (iscale_y != (1 << 12)) 368*68353368SRudolf Cornelissen DACW(FP_DEBUG2, ((1 << 28) | ((target.timing.v_display - 1) << 16))); 369*68353368SRudolf Cornelissen else 370*68353368SRudolf Cornelissen DACW(FP_DEBUG2, 0x00000000); 371*68353368SRudolf Cornelissen 372*68353368SRudolf Cornelissen /* inform panel not to scale */ 373*68353368SRudolf Cornelissen DACW(FP_TG_CTRL, (DACR(FP_TG_CTRL) & 0xfffffeff)); 374*68353368SRudolf Cornelissen 375*68353368SRudolf Cornelissen /* GPU scaling is automatically setup by hardware, so only modify this 376*68353368SRudolf Cornelissen * scalingfactor for non 4:3 (1.33) aspect panels; 377*68353368SRudolf Cornelissen * let's consider 1280x1024 1:33 aspect (it's 1.25 aspect actually!) */ 378*68353368SRudolf Cornelissen 379*68353368SRudolf Cornelissen /* correct for widescreen panels relative to mode... 380*68353368SRudolf Cornelissen * (so if panel is more widescreen than mode being set) */ 381*68353368SRudolf Cornelissen /* BTW: known widescreen panels: 382*68353368SRudolf Cornelissen * 1280 x 800 (1.60), 383*68353368SRudolf Cornelissen * 1440 x 900 (1.60), 384*68353368SRudolf Cornelissen * 1680 x 1050 (1.60), 385*68353368SRudolf Cornelissen * 1920 x 1200 (1.60). */ 386*68353368SRudolf Cornelissen /* known 4:3 aspect non-standard resolution panels: 387*68353368SRudolf Cornelissen * 1400 x 1050 (1.33). */ 388*68353368SRudolf Cornelissen /* NOTE: 389*68353368SRudolf Cornelissen * allow 0.10 difference so 1280x1024 panels will be used fullscreen! */ 390*68353368SRudolf Cornelissen if ((iscale_x != (1 << 12)) && (si->ps.panel1_aspect > (dm_aspect + 0.10))) 391*68353368SRudolf Cornelissen { 392*68353368SRudolf Cornelissen uint16 diff; 393*68353368SRudolf Cornelissen 394*68353368SRudolf Cornelissen LOG(2,("CRTC: (relative) widescreen panel: tuning horizontal scaling\n")); 395*68353368SRudolf Cornelissen 396*68353368SRudolf Cornelissen /* X-scaling should be the same as Y-scaling */ 397*68353368SRudolf Cornelissen iscale_x = iscale_y; 398*68353368SRudolf Cornelissen /* enable testmode (b12) and program modified X-scaling factor */ 399*68353368SRudolf Cornelissen DACW(FP_DEBUG1, (((iscale_x >> 1) & 0x00000fff) | (1 << 12))); 400*68353368SRudolf Cornelissen /* center/cut-off left and right side of screen */ 401*68353368SRudolf Cornelissen diff = ((si->ps.p1_timing.h_display - 402*68353368SRudolf Cornelissen (target.timing.h_display * ((1 << 12) / ((float)iscale_x)))) 403*68353368SRudolf Cornelissen / 2); 404*68353368SRudolf Cornelissen DACW(FP_HVALID_S, diff); 405*68353368SRudolf Cornelissen DACW(FP_HVALID_E, ((si->ps.p1_timing.h_display - diff) - 1)); 406*68353368SRudolf Cornelissen } 407*68353368SRudolf Cornelissen /* correct for portrait panels... */ 408*68353368SRudolf Cornelissen /* NOTE: 409*68353368SRudolf Cornelissen * allow 0.10 difference so 1280x1024 panels will be used fullscreen! */ 410*68353368SRudolf Cornelissen if ((iscale_y != (1 << 12)) && (si->ps.panel1_aspect < (dm_aspect - 0.10))) 411*68353368SRudolf Cornelissen { 412*68353368SRudolf Cornelissen LOG(2,("CRTC: (relative) portrait panel: should tune vertical scaling\n")); 413*68353368SRudolf Cornelissen /* fixme: implement if this kind of portrait panels exist on nVidia... */ 414*68353368SRudolf Cornelissen } 415*68353368SRudolf Cornelissen } 416*68353368SRudolf Cornelissen 417*68353368SRudolf Cornelissen /* do some logging.. */ 418*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_HVALID_S reg readback: $%08x\n", DACR(FP_HVALID_S))); 419*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_HVALID_E reg readback: $%08x\n", DACR(FP_HVALID_E))); 420*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_VVALID_S reg readback: $%08x\n", DACR(FP_VVALID_S))); 421*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_VVALID_E reg readback: $%08x\n", DACR(FP_VVALID_E))); 422*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_DEBUG0 reg readback: $%08x\n", DACR(FP_DEBUG0))); 423*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_DEBUG1 reg readback: $%08x\n", DACR(FP_DEBUG1))); 424*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_DEBUG2 reg readback: $%08x\n", DACR(FP_DEBUG2))); 425*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_DEBUG3 reg readback: $%08x\n", DACR(FP_DEBUG3))); 426*68353368SRudolf Cornelissen LOG(2,("CRTC: FP_TG_CTRL reg readback: $%08x\n", DACR(FP_TG_CTRL))); 427*68353368SRudolf Cornelissen } 428*68353368SRudolf Cornelissen 429*68353368SRudolf Cornelissen return B_OK; 430*68353368SRudolf Cornelissen } 431*68353368SRudolf Cornelissen 432*68353368SRudolf Cornelissen status_t nv_crtc_depth(int mode) 433*68353368SRudolf Cornelissen { 434*68353368SRudolf Cornelissen uint8 viddelay = 0; 435*68353368SRudolf Cornelissen uint32 genctrl = 0; 436*68353368SRudolf Cornelissen 437*68353368SRudolf Cornelissen /* set VCLK scaling */ 438*68353368SRudolf Cornelissen switch(mode) 439*68353368SRudolf Cornelissen { 440*68353368SRudolf Cornelissen case BPP8: 441*68353368SRudolf Cornelissen viddelay = 0x01; 442*68353368SRudolf Cornelissen /* genctrl b4 & b5 reset: 'direct mode' */ 443*68353368SRudolf Cornelissen genctrl = 0x00101100; 444*68353368SRudolf Cornelissen break; 445*68353368SRudolf Cornelissen case BPP15: 446*68353368SRudolf Cornelissen viddelay = 0x02; 447*68353368SRudolf Cornelissen /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ 448*68353368SRudolf Cornelissen genctrl = 0x00100130; 449*68353368SRudolf Cornelissen break; 450*68353368SRudolf Cornelissen case BPP16: 451*68353368SRudolf Cornelissen viddelay = 0x02; 452*68353368SRudolf Cornelissen /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ 453*68353368SRudolf Cornelissen genctrl = 0x00101130; 454*68353368SRudolf Cornelissen break; 455*68353368SRudolf Cornelissen case BPP24: 456*68353368SRudolf Cornelissen viddelay = 0x03; 457*68353368SRudolf Cornelissen /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ 458*68353368SRudolf Cornelissen genctrl = 0x00100130; 459*68353368SRudolf Cornelissen break; 460*68353368SRudolf Cornelissen case BPP32: 461*68353368SRudolf Cornelissen viddelay = 0x03; 462*68353368SRudolf Cornelissen /* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */ 463*68353368SRudolf Cornelissen genctrl = 0x00101130; 464*68353368SRudolf Cornelissen break; 465*68353368SRudolf Cornelissen } 466*68353368SRudolf Cornelissen /* enable access to primary head */ 467*68353368SRudolf Cornelissen set_crtc_owner(0); 468*68353368SRudolf Cornelissen 469*68353368SRudolf Cornelissen CRTCW(PIXEL, ((CRTCR(PIXEL) & 0xfc) | viddelay)); 470*68353368SRudolf Cornelissen DACW(GENCTRL, genctrl); 471*68353368SRudolf Cornelissen 472*68353368SRudolf Cornelissen return B_OK; 473*68353368SRudolf Cornelissen } 474*68353368SRudolf Cornelissen 475*68353368SRudolf Cornelissen status_t nv_crtc_dpms(bool display, bool h, bool v) 476*68353368SRudolf Cornelissen { 477*68353368SRudolf Cornelissen uint8 temp; 478*68353368SRudolf Cornelissen 479*68353368SRudolf Cornelissen LOG(4,("CRTC: setting DPMS: ")); 480*68353368SRudolf Cornelissen 481*68353368SRudolf Cornelissen /* enable access to primary head */ 482*68353368SRudolf Cornelissen set_crtc_owner(0); 483*68353368SRudolf Cornelissen 484*68353368SRudolf Cornelissen /* start synchronous reset: required before turning screen off! */ 485*68353368SRudolf Cornelissen SEQW(RESET, 0x01); 486*68353368SRudolf Cornelissen 487*68353368SRudolf Cornelissen /* turn screen off */ 488*68353368SRudolf Cornelissen temp = SEQR(CLKMODE); 489*68353368SRudolf Cornelissen if (display) 490*68353368SRudolf Cornelissen { 491*68353368SRudolf Cornelissen SEQW(CLKMODE, (temp & ~0x20)); 492*68353368SRudolf Cornelissen 493*68353368SRudolf Cornelissen /* end synchronous reset if display should be enabled */ 494*68353368SRudolf Cornelissen SEQW(RESET, 0x03); 495*68353368SRudolf Cornelissen 496*68353368SRudolf Cornelissen //'safe mode' test! feedback needed with this 'setting'! 497*68353368SRudolf Cornelissen if (0)//si->ps.tmds1_active) 498*68353368SRudolf Cornelissen { 499*68353368SRudolf Cornelissen /* powerup both LVDS (laptop panellink) and TMDS (DVI panellink) 500*68353368SRudolf Cornelissen * internal transmitters... */ 501*68353368SRudolf Cornelissen /* note: 502*68353368SRudolf Cornelissen * the powerbits in this register are hardwired to the DVI connectors, 503*68353368SRudolf Cornelissen * instead of to the DACs! (confirmed NV34) */ 504*68353368SRudolf Cornelissen //fixme... 505*68353368SRudolf Cornelissen DACW(FP_DEBUG0, (DACR(FP_DEBUG0) & 0xcfffffff)); 506*68353368SRudolf Cornelissen /* ... and powerup external TMDS transmitter if it exists */ 507*68353368SRudolf Cornelissen /* (confirmed OK on NV28 and NV34) */ 508*68353368SRudolf Cornelissen CRTCW(0x59, (CRTCR(0x59) | 0x01)); 509*68353368SRudolf Cornelissen } 510*68353368SRudolf Cornelissen 511*68353368SRudolf Cornelissen LOG(4,("display on, ")); 512*68353368SRudolf Cornelissen } 513*68353368SRudolf Cornelissen else 514*68353368SRudolf Cornelissen { 515*68353368SRudolf Cornelissen SEQW(CLKMODE, (temp | 0x20)); 516*68353368SRudolf Cornelissen 517*68353368SRudolf Cornelissen //'safe mode' test! feedback needed with this 'setting'! 518*68353368SRudolf Cornelissen if (0)//si->ps.tmds1_active) 519*68353368SRudolf Cornelissen { 520*68353368SRudolf Cornelissen /* powerdown both LVDS (laptop panellink) and TMDS (DVI panellink) 521*68353368SRudolf Cornelissen * internal transmitters... */ 522*68353368SRudolf Cornelissen /* note: 523*68353368SRudolf Cornelissen * the powerbits in this register are hardwired to the DVI connectors, 524*68353368SRudolf Cornelissen * instead of to the DACs! (confirmed NV34) */ 525*68353368SRudolf Cornelissen //fixme... 526*68353368SRudolf Cornelissen DACW(FP_DEBUG0, (DACR(FP_DEBUG0) | 0x30000000)); 527*68353368SRudolf Cornelissen /* ... and powerdown external TMDS transmitter if it exists */ 528*68353368SRudolf Cornelissen /* (confirmed OK on NV28 and NV34) */ 529*68353368SRudolf Cornelissen CRTCW(0x59, (CRTCR(0x59) & 0xfe)); 530*68353368SRudolf Cornelissen } 531*68353368SRudolf Cornelissen 532*68353368SRudolf Cornelissen LOG(4,("display off, ")); 533*68353368SRudolf Cornelissen } 534*68353368SRudolf Cornelissen 535*68353368SRudolf Cornelissen if (h) 536*68353368SRudolf Cornelissen { 537*68353368SRudolf Cornelissen CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0x7f)); 538*68353368SRudolf Cornelissen LOG(4,("hsync enabled, ")); 539*68353368SRudolf Cornelissen } 540*68353368SRudolf Cornelissen else 541*68353368SRudolf Cornelissen { 542*68353368SRudolf Cornelissen CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x80)); 543*68353368SRudolf Cornelissen LOG(4,("hsync disabled, ")); 544*68353368SRudolf Cornelissen } 545*68353368SRudolf Cornelissen if (v) 546*68353368SRudolf Cornelissen { 547*68353368SRudolf Cornelissen CRTCW(REPAINT1, (CRTCR(REPAINT1) & 0xbf)); 548*68353368SRudolf Cornelissen LOG(4,("vsync enabled\n")); 549*68353368SRudolf Cornelissen } 550*68353368SRudolf Cornelissen else 551*68353368SRudolf Cornelissen { 552*68353368SRudolf Cornelissen CRTCW(REPAINT1, (CRTCR(REPAINT1) | 0x40)); 553*68353368SRudolf Cornelissen LOG(4,("vsync disabled\n")); 554*68353368SRudolf Cornelissen } 555*68353368SRudolf Cornelissen 556*68353368SRudolf Cornelissen return B_OK; 557*68353368SRudolf Cornelissen } 558*68353368SRudolf Cornelissen 559*68353368SRudolf Cornelissen status_t nv_crtc_dpms_fetch(bool *display, bool *h, bool *v) 560*68353368SRudolf Cornelissen { 561*68353368SRudolf Cornelissen /* enable access to primary head */ 562*68353368SRudolf Cornelissen set_crtc_owner(0); 563*68353368SRudolf Cornelissen 564*68353368SRudolf Cornelissen *display = !(SEQR(CLKMODE) & 0x20); 565*68353368SRudolf Cornelissen *h = !(CRTCR(REPAINT1) & 0x80); 566*68353368SRudolf Cornelissen *v = !(CRTCR(REPAINT1) & 0x40); 567*68353368SRudolf Cornelissen 568*68353368SRudolf Cornelissen LOG(4,("CTRC: fetched DPMS state: ")); 569*68353368SRudolf Cornelissen if (*display) LOG(4,("display on, ")); 570*68353368SRudolf Cornelissen else LOG(4,("display off, ")); 571*68353368SRudolf Cornelissen if (*h) LOG(4,("hsync enabled, ")); 572*68353368SRudolf Cornelissen else LOG(4,("hsync disabled, ")); 573*68353368SRudolf Cornelissen if (*v) LOG(4,("vsync enabled\n")); 574*68353368SRudolf Cornelissen else LOG(4,("vsync disabled\n")); 575*68353368SRudolf Cornelissen 576*68353368SRudolf Cornelissen return B_OK; 577*68353368SRudolf Cornelissen } 578*68353368SRudolf Cornelissen 579*68353368SRudolf Cornelissen status_t nv_crtc_set_display_pitch() 580*68353368SRudolf Cornelissen { 581*68353368SRudolf Cornelissen uint32 offset; 582*68353368SRudolf Cornelissen 583*68353368SRudolf Cornelissen LOG(4,("CRTC: setting card pitch (offset between lines)\n")); 584*68353368SRudolf Cornelissen 585*68353368SRudolf Cornelissen /* figure out offset value hardware needs */ 586*68353368SRudolf Cornelissen offset = si->fbc.bytes_per_row / 8; 587*68353368SRudolf Cornelissen 588*68353368SRudolf Cornelissen LOG(2,("CRTC: offset register set to: $%04x\n", offset)); 589*68353368SRudolf Cornelissen 590*68353368SRudolf Cornelissen /* enable access to primary head */ 591*68353368SRudolf Cornelissen set_crtc_owner(0); 592*68353368SRudolf Cornelissen 593*68353368SRudolf Cornelissen /* program the card */ 594*68353368SRudolf Cornelissen CRTCW(PITCHL, (offset & 0x00ff)); 595*68353368SRudolf Cornelissen CRTCW(REPAINT0, ((CRTCR(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3))); 596*68353368SRudolf Cornelissen 597*68353368SRudolf Cornelissen return B_OK; 598*68353368SRudolf Cornelissen } 599*68353368SRudolf Cornelissen 600*68353368SRudolf Cornelissen status_t nv_crtc_set_display_start(uint32 startadd,uint8 bpp) 601*68353368SRudolf Cornelissen { 602*68353368SRudolf Cornelissen uint8 temp; 603*68353368SRudolf Cornelissen uint32 timeout = 0; 604*68353368SRudolf Cornelissen 605*68353368SRudolf Cornelissen LOG(4,("CRTC: setting card RAM to be displayed bpp %d\n", bpp)); 606*68353368SRudolf Cornelissen 607*68353368SRudolf Cornelissen LOG(2,("CRTC: startadd: $%08x\n", startadd)); 608*68353368SRudolf Cornelissen LOG(2,("CRTC: frameRAM: $%08x\n", si->framebuffer)); 609*68353368SRudolf Cornelissen LOG(2,("CRTC: framebuffer: $%08x\n", si->fbc.frame_buffer)); 610*68353368SRudolf Cornelissen 611*68353368SRudolf Cornelissen /* we might have no retraces during setmode! */ 612*68353368SRudolf Cornelissen /* wait 25mS max. for retrace to occur (refresh > 40Hz) */ 613*68353368SRudolf Cornelissen while (((NV_REG32(NV32_RASTER) & 0x000007ff) < si->dm.timing.v_display) && 614*68353368SRudolf Cornelissen (timeout < (25000/10))) 615*68353368SRudolf Cornelissen { 616*68353368SRudolf Cornelissen /* don't snooze much longer or retrace might get missed! */ 617*68353368SRudolf Cornelissen snooze(10); 618*68353368SRudolf Cornelissen timeout++; 619*68353368SRudolf Cornelissen } 620*68353368SRudolf Cornelissen 621*68353368SRudolf Cornelissen /* enable access to primary head */ 622*68353368SRudolf Cornelissen set_crtc_owner(0); 623*68353368SRudolf Cornelissen 624*68353368SRudolf Cornelissen if (si->ps.card_arch == NV04A) 625*68353368SRudolf Cornelissen { 626*68353368SRudolf Cornelissen /* upto 32Mb RAM adressing: must be used this way on pre-NV10! */ 627*68353368SRudolf Cornelissen 628*68353368SRudolf Cornelissen /* set standard registers */ 629*68353368SRudolf Cornelissen /* (NVidia: startadress in 32bit words (b2 - b17) */ 630*68353368SRudolf Cornelissen CRTCW(FBSTADDL, ((startadd & 0x000003fc) >> 2)); 631*68353368SRudolf Cornelissen CRTCW(FBSTADDH, ((startadd & 0x0003fc00) >> 10)); 632*68353368SRudolf Cornelissen 633*68353368SRudolf Cornelissen /* set extended registers */ 634*68353368SRudolf Cornelissen /* NV4 extended bits: (b18-22) */ 635*68353368SRudolf Cornelissen temp = (CRTCR(REPAINT0) & 0xe0); 636*68353368SRudolf Cornelissen CRTCW(REPAINT0, (temp | ((startadd & 0x007c0000) >> 18))); 637*68353368SRudolf Cornelissen /* NV4 extended bits: (b23-24) */ 638*68353368SRudolf Cornelissen temp = (CRTCR(HEB) & 0x9f); 639*68353368SRudolf Cornelissen CRTCW(HEB, (temp | ((startadd & 0x01800000) >> 18))); 640*68353368SRudolf Cornelissen } 641*68353368SRudolf Cornelissen else 642*68353368SRudolf Cornelissen { 643*68353368SRudolf Cornelissen /* upto 4Gb RAM adressing: must be used on NV10 and later! */ 644*68353368SRudolf Cornelissen /* NOTE: 645*68353368SRudolf Cornelissen * While this register also exists on pre-NV10 cards, it will 646*68353368SRudolf Cornelissen * wrap-around at 16Mb boundaries!! */ 647*68353368SRudolf Cornelissen 648*68353368SRudolf Cornelissen /* 30bit adress in 32bit words */ 649*68353368SRudolf Cornelissen NV_REG32(NV32_NV10FBSTADD32) = (startadd & 0xfffffffc); 650*68353368SRudolf Cornelissen } 651*68353368SRudolf Cornelissen 652*68353368SRudolf Cornelissen /* set NV4/NV10 byte adress: (b0 - 1) */ 653*68353368SRudolf Cornelissen ATBW(HORPIXPAN, ((startadd & 0x00000003) << 1)); 654*68353368SRudolf Cornelissen 655*68353368SRudolf Cornelissen return B_OK; 656*68353368SRudolf Cornelissen } 657*68353368SRudolf Cornelissen 658*68353368SRudolf Cornelissen status_t nv_crtc_cursor_init() 659*68353368SRudolf Cornelissen { 660*68353368SRudolf Cornelissen int i; 661*68353368SRudolf Cornelissen uint32 * fb; 662*68353368SRudolf Cornelissen /* cursor bitmap will be stored at the start of the framebuffer */ 663*68353368SRudolf Cornelissen const uint32 curadd = 0; 664*68353368SRudolf Cornelissen 665*68353368SRudolf Cornelissen /* enable access to primary head */ 666*68353368SRudolf Cornelissen set_crtc_owner(0); 667*68353368SRudolf Cornelissen 668*68353368SRudolf Cornelissen /* set cursor bitmap adress ... */ 669*68353368SRudolf Cornelissen if ((si->ps.card_arch == NV04A) || (si->ps.laptop)) 670*68353368SRudolf Cornelissen { 671*68353368SRudolf Cornelissen /* must be used this way on pre-NV10 and on all 'Go' cards! */ 672*68353368SRudolf Cornelissen 673*68353368SRudolf Cornelissen /* cursorbitmap must start on 2Kbyte boundary: */ 674*68353368SRudolf Cornelissen /* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */ 675*68353368SRudolf Cornelissen CRTCW(CURCTL0, ((curadd & 0x0001f800) >> 9)); 676*68353368SRudolf Cornelissen /* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */ 677*68353368SRudolf Cornelissen CRTCW(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80)); 678*68353368SRudolf Cornelissen /* set adress bit24-31 */ 679*68353368SRudolf Cornelissen CRTCW(CURCTL2, ((curadd & 0xff000000) >> 24)); 680*68353368SRudolf Cornelissen } 681*68353368SRudolf Cornelissen else 682*68353368SRudolf Cornelissen { 683*68353368SRudolf Cornelissen /* upto 4Gb RAM adressing: 684*68353368SRudolf Cornelissen * can be used on NV10 and later (except for 'Go' cards)! */ 685*68353368SRudolf Cornelissen /* NOTE: 686*68353368SRudolf Cornelissen * This register does not exist on pre-NV10 and 'Go' cards. */ 687*68353368SRudolf Cornelissen 688*68353368SRudolf Cornelissen /* cursorbitmap must still start on 2Kbyte boundary: */ 689*68353368SRudolf Cornelissen NV_REG32(NV32_NV10CURADD32) = (curadd & 0xfffff800); 690*68353368SRudolf Cornelissen } 691*68353368SRudolf Cornelissen 692*68353368SRudolf Cornelissen /* set cursor colour: not needed because of direct nature of cursor bitmap. */ 693*68353368SRudolf Cornelissen 694*68353368SRudolf Cornelissen /*clear cursor*/ 695*68353368SRudolf Cornelissen fb = (uint32 *) si->framebuffer + curadd; 696*68353368SRudolf Cornelissen for (i=0;i<(2048/4);i++) 697*68353368SRudolf Cornelissen { 698*68353368SRudolf Cornelissen fb[i]=0; 699*68353368SRudolf Cornelissen } 700*68353368SRudolf Cornelissen 701*68353368SRudolf Cornelissen /* select 32x32 pixel, 16bit color cursorbitmap, no doublescan */ 702*68353368SRudolf Cornelissen NV_REG32(NV32_CURCONF) = 0x02000100; 703*68353368SRudolf Cornelissen 704*68353368SRudolf Cornelissen /* activate hardware cursor */ 705*68353368SRudolf Cornelissen nv_crtc_cursor_show(); 706*68353368SRudolf Cornelissen 707*68353368SRudolf Cornelissen return B_OK; 708*68353368SRudolf Cornelissen } 709*68353368SRudolf Cornelissen 710*68353368SRudolf Cornelissen status_t nv_crtc_cursor_show() 711*68353368SRudolf Cornelissen { 712*68353368SRudolf Cornelissen LOG(4,("CRTC: enabling cursor\n")); 713*68353368SRudolf Cornelissen 714*68353368SRudolf Cornelissen /* enable access to CRTC1 on dualhead cards */ 715*68353368SRudolf Cornelissen set_crtc_owner(0); 716*68353368SRudolf Cornelissen 717*68353368SRudolf Cornelissen /* b0 = 1 enables cursor */ 718*68353368SRudolf Cornelissen CRTCW(CURCTL0, (CRTCR(CURCTL0) | 0x01)); 719*68353368SRudolf Cornelissen 720*68353368SRudolf Cornelissen return B_OK; 721*68353368SRudolf Cornelissen } 722*68353368SRudolf Cornelissen 723*68353368SRudolf Cornelissen status_t nv_crtc_cursor_hide() 724*68353368SRudolf Cornelissen { 725*68353368SRudolf Cornelissen LOG(4,("CRTC: disabling cursor\n")); 726*68353368SRudolf Cornelissen 727*68353368SRudolf Cornelissen /* enable access to primary head */ 728*68353368SRudolf Cornelissen set_crtc_owner(0); 729*68353368SRudolf Cornelissen 730*68353368SRudolf Cornelissen /* b0 = 0 disables cursor */ 731*68353368SRudolf Cornelissen CRTCW(CURCTL0, (CRTCR(CURCTL0) & 0xfe)); 732*68353368SRudolf Cornelissen 733*68353368SRudolf Cornelissen return B_OK; 734*68353368SRudolf Cornelissen } 735*68353368SRudolf Cornelissen 736*68353368SRudolf Cornelissen /*set up cursor shape*/ 737*68353368SRudolf Cornelissen status_t nv_crtc_cursor_define(uint8* andMask,uint8* xorMask) 738*68353368SRudolf Cornelissen { 739*68353368SRudolf Cornelissen int x, y; 740*68353368SRudolf Cornelissen uint8 b; 741*68353368SRudolf Cornelissen uint16 *cursor; 742*68353368SRudolf Cornelissen uint16 pixel; 743*68353368SRudolf Cornelissen 744*68353368SRudolf Cornelissen /* get a pointer to the cursor */ 745*68353368SRudolf Cornelissen cursor = (uint16*) si->framebuffer; 746*68353368SRudolf Cornelissen 747*68353368SRudolf Cornelissen /* draw the cursor */ 748*68353368SRudolf Cornelissen /* (Nvidia cards have a RGB15 direct color cursor bitmap, bit #16 is transparancy) */ 749*68353368SRudolf Cornelissen for (y = 0; y < 16; y++) 750*68353368SRudolf Cornelissen { 751*68353368SRudolf Cornelissen b = 0x80; 752*68353368SRudolf Cornelissen for (x = 0; x < 8; x++) 753*68353368SRudolf Cornelissen { 754*68353368SRudolf Cornelissen /* preset transparant */ 755*68353368SRudolf Cornelissen pixel = 0x0000; 756*68353368SRudolf Cornelissen /* set white if requested */ 757*68353368SRudolf Cornelissen if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff; 758*68353368SRudolf Cornelissen /* set black if requested */ 759*68353368SRudolf Cornelissen if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000; 760*68353368SRudolf Cornelissen /* set invert if requested */ 761*68353368SRudolf Cornelissen if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff; 762*68353368SRudolf Cornelissen /* place the pixel in the bitmap */ 763*68353368SRudolf Cornelissen cursor[x + (y * 32)] = pixel; 764*68353368SRudolf Cornelissen b >>= 1; 765*68353368SRudolf Cornelissen } 766*68353368SRudolf Cornelissen xorMask++; 767*68353368SRudolf Cornelissen andMask++; 768*68353368SRudolf Cornelissen b = 0x80; 769*68353368SRudolf Cornelissen for (; x < 16; x++) 770*68353368SRudolf Cornelissen { 771*68353368SRudolf Cornelissen /* preset transparant */ 772*68353368SRudolf Cornelissen pixel = 0x0000; 773*68353368SRudolf Cornelissen /* set white if requested */ 774*68353368SRudolf Cornelissen if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff; 775*68353368SRudolf Cornelissen /* set black if requested */ 776*68353368SRudolf Cornelissen if ((!(*andMask & b)) && (*xorMask & b)) pixel = 0x8000; 777*68353368SRudolf Cornelissen /* set invert if requested */ 778*68353368SRudolf Cornelissen if ( (*andMask & b) && (*xorMask & b)) pixel = 0x7fff; 779*68353368SRudolf Cornelissen /* place the pixel in the bitmap */ 780*68353368SRudolf Cornelissen cursor[x + (y * 32)] = pixel; 781*68353368SRudolf Cornelissen b >>= 1; 782*68353368SRudolf Cornelissen } 783*68353368SRudolf Cornelissen xorMask++; 784*68353368SRudolf Cornelissen andMask++; 785*68353368SRudolf Cornelissen } 786*68353368SRudolf Cornelissen 787*68353368SRudolf Cornelissen return B_OK; 788*68353368SRudolf Cornelissen } 789*68353368SRudolf Cornelissen 790*68353368SRudolf Cornelissen /* position the cursor */ 791*68353368SRudolf Cornelissen status_t nv_crtc_cursor_position(uint16 x, uint16 y) 792*68353368SRudolf Cornelissen { 793*68353368SRudolf Cornelissen uint16 yhigh; 794*68353368SRudolf Cornelissen 795*68353368SRudolf Cornelissen /* make sure we are beyond the first line of the cursorbitmap being drawn during 796*68353368SRudolf Cornelissen * updating the position to prevent distortions: no double buffering feature */ 797*68353368SRudolf Cornelissen /* Note: 798*68353368SRudolf Cornelissen * we need to return as quick as possible or some apps will exhibit lagging.. */ 799*68353368SRudolf Cornelissen 800*68353368SRudolf Cornelissen /* read the old cursor Y position */ 801*68353368SRudolf Cornelissen yhigh = ((DACR(CURPOS) & 0x0fff0000) >> 16); 802*68353368SRudolf Cornelissen /* make sure we will wait until we are below both the old and new Y position: 803*68353368SRudolf Cornelissen * visible cursorbitmap drawing needs to be done at least... */ 804*68353368SRudolf Cornelissen if (y > yhigh) yhigh = y; 805*68353368SRudolf Cornelissen 806*68353368SRudolf Cornelissen if (yhigh < (si->dm.timing.v_display - 16)) 807*68353368SRudolf Cornelissen { 808*68353368SRudolf Cornelissen /* we have vertical lines below old and new cursorposition to spare. So we 809*68353368SRudolf Cornelissen * update the cursor postion 'mid-screen', but below that area. */ 810*68353368SRudolf Cornelissen while (((uint16)(NV_REG32(NV32_RASTER) & 0x000007ff)) < (yhigh + 16)) 811*68353368SRudolf Cornelissen { 812*68353368SRudolf Cornelissen snooze(10); 813*68353368SRudolf Cornelissen } 814*68353368SRudolf Cornelissen } 815*68353368SRudolf Cornelissen else 816*68353368SRudolf Cornelissen { 817*68353368SRudolf Cornelissen /* no room to spare, just wait for retrace (is relatively slow) */ 818*68353368SRudolf Cornelissen while ((NV_REG32(NV32_RASTER) & 0x000007ff) < si->dm.timing.v_display) 819*68353368SRudolf Cornelissen { 820*68353368SRudolf Cornelissen /* don't snooze much longer or retrace might get missed! */ 821*68353368SRudolf Cornelissen snooze(10); 822*68353368SRudolf Cornelissen } 823*68353368SRudolf Cornelissen } 824*68353368SRudolf Cornelissen 825*68353368SRudolf Cornelissen /* update cursorposition */ 826*68353368SRudolf Cornelissen DACW(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16))); 827*68353368SRudolf Cornelissen 828*68353368SRudolf Cornelissen return B_OK; 829*68353368SRudolf Cornelissen } 830