/* CTRC functionality */ /* Author: Rudolf Cornelissen 4/2003-1/2006 */ #define MODULE_BIT 0x00040000 #include "nm_std.h" /* Adjust passed parameters to a valid mode line */ status_t nm_crtc_validate_timing( uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht, uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt ) { /* horizontal */ /* make all parameters multiples of 8 */ *hd_e &= 0xfff8; *hs_s &= 0xfff8; *hs_e &= 0xfff8; *ht &= 0xfff8; /* confine to required number of bits, taking logic into account */ if (*hd_e > ((0xff - 2) << 3)) *hd_e = ((0xff - 2) << 3); if (*hs_s > ((0xff - 1) << 3)) *hs_s = ((0xff - 1) << 3); if (*hs_e > ( 0xff << 3)) *hs_e = ( 0xff << 3); if (*ht > ((0xff + 5) << 3)) *ht = ((0xff + 5) << 3); /* NOTE: keep horizontal timing at multiples of 8! */ /* confine to a reasonable width */ if (*hd_e < 640) *hd_e = 640; if (*hd_e > si->ps.max_crtc_width) *hd_e = si->ps.max_crtc_width; /* if hor. total does not leave room for a sensible sync pulse,*/ /* increase it! */ if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80); /* if hor. total does not adhere to max. blanking pulse width,*/ /* decrease it! */ if (*ht > (*hd_e + 0x1f8)) *ht = (*hd_e + 0x1f8); /* make sure sync pulse is not during display */ if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8); if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8); /* correct sync pulse if it is too long: * there are only 5 bits available to save this in the card registers! */ if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8); /*vertical*/ /* confine to required number of bits, taking logic into account */ if (si->ps.card_type < NM2200) { if (*vd_e > (0x3ff - 2)) *vd_e = (0x3ff - 2); if (*vs_s > (0x3ff - 1)) *vs_s = (0x3ff - 1); if (*vs_e > 0x3ff ) *vs_e = 0x3ff ; if (*vt > (0x3ff + 2)) *vt = (0x3ff + 2); } else { if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2); if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1); if (*vs_e > 0x7ff ) *vs_e = 0x7ff ; if (*vt > (0x7ff + 2)) *vt = (0x7ff + 2); } /* confine to a reasonable height */ if (*vd_e < 480) *vd_e = 480; if (*vd_e > si->ps.max_crtc_height) *vd_e = si->ps.max_crtc_height; /*if vertical total does not leave room for a sync pulse, increase it!*/ if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3); /* if vert. total does not adhere to max. blanking pulse width,*/ /* decrease it! */ if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff); /* make sure sync pulse is not during display */ if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1); if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1); /* correct sync pulse if it is too long: * there are only 4 bits available to save this in the card registers! */ if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f); return B_OK; } /* set a mode line */ status_t nm_crtc_set_timing(display_mode target, bool crt_only) { uint8 temp; uint32 htotal; /*total horizontal total VCLKs*/ uint32 hdisp_e; /*end of horizontal display (begins at 0)*/ uint32 hsync_s; /*begin of horizontal sync pulse*/ uint32 hsync_e; /*end of horizontal sync pulse*/ uint32 hblnk_s; /*begin horizontal blanking*/ uint32 hblnk_e; /*end horizontal blanking*/ uint32 vtotal; /*total vertical total scanlines*/ uint32 vdisp_e; /*end of vertical display*/ uint32 vsync_s; /*begin of vertical sync pulse*/ uint32 vsync_e; /*end of vertical sync pulse*/ uint32 vblnk_s; /*begin vertical blanking*/ uint32 vblnk_e; /*end vertical blanking*/ uint32 linecomp; /*split screen and vdisp_e interrupt*/ LOG(4,("CRTC: setting timing\n")); /* modify visible sceensize if needed */ /* (note that MOVE_CURSOR checks for a panning/scrolling mode itself, * the display_mode as placed in si->dm may _not_ be modified!) */ if (!crt_only) { if (target.timing.h_display > si->ps.panel_width) { target.timing.h_display = si->ps.panel_width; LOG(4, ("CRTC: req. width > panel width: setting panning mode\n")); } if (target.timing.v_display > si->ps.panel_height) { target.timing.v_display = si->ps.panel_height; LOG(4, ("CRTC: req. height > panel height: setting scrolling " "mode\n")); } /* modify sync polarities * (needed to maintain correct panel centering): * both polarities must be negative (confirmed NM2160) */ target.timing.flags &= ~(B_POSITIVE_HSYNC | B_POSITIVE_VSYNC); } /* Modify parameters as required by standard VGA */ htotal = ((target.timing.h_total >> 3) - 5); hdisp_e = ((target.timing.h_display >> 3) - 1); hblnk_s = hdisp_e; hblnk_e = (htotal + 0); /* this register differs from standard VGA! */ /* (says + 4) */ hsync_s = (target.timing.h_sync_start >> 3); hsync_e = (target.timing.h_sync_end >> 3); vtotal = target.timing.v_total - 2; vdisp_e = target.timing.v_display - 1; vblnk_s = vdisp_e; vblnk_e = (vtotal + 1); vsync_s = target.timing.v_sync_start;//-1; vsync_e = target.timing.v_sync_end;//-1; /* prevent memory adress counter from being reset */ /* (linecomp may not occur) */ linecomp = target.timing.v_display; if (crt_only) { LOG(4,("CRTC: CRT only mode, setting full timing...\n")); /* log the mode that will be set */ 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)); 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)); /* actually program the card! */ /* unlock CRTC registers at index 0-7 */ temp = (ISACRTCR(VSYNCE) & 0x7f); /* we need to wait a bit or the card will mess-up it's */ /* register values.. */ snooze(10); ISACRTCW(VSYNCE, temp); /* horizontal standard VGA regs */ ISACRTCW(HTOTAL, (htotal & 0xff)); ISACRTCW(HDISPE, (hdisp_e & 0xff)); ISACRTCW(HBLANKS, (hblnk_s & 0xff)); /* also unlock vertical retrace registers in advance */ ISACRTCW(HBLANKE, ((hblnk_e & 0x1f) | 0x80)); ISACRTCW(HSYNCS, (hsync_s & 0xff)); ISACRTCW(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2))); /* vertical standard VGA regs */ ISACRTCW(VTOTAL, (vtotal & 0xff)); ISACRTCW(OVERFLOW, ( ((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) | ((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) | ((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) | ((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4)) )); ISACRTCW(PRROWSCN, 0x00); /* not used */ ISACRTCW(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6)))); ISACRTCW(VSYNCS, (vsync_s & 0xff)); temp = (ISACRTCR(VSYNCE) & 0xf0); /* we need to wait a bit or the card will mess-up it's */ /* register values.. */ snooze(10); ISACRTCW(VSYNCE, (temp | (vsync_e & 0x0f))); ISACRTCW(VDISPE, (vdisp_e & 0xff)); ISACRTCW(VBLANKS, (vblnk_s & 0xff)); ISACRTCW(VBLANKE, (vblnk_e & 0xff)); //linux: (BIOSmode) // regp->CRTC[23] = 0xC3; ISACRTCW(LINECOMP, (linecomp & 0xff)); /* horizontal - no extended regs available or needed on */ /* NeoMagic chips */ /* vertical - extended regs */ //fixme: checkout if b2 or 3 should be switched! (linux contains error here) //fixme: linecomp should also have an extra bit... testable by setting linecomp //to 100 for example and then try out writing an '1' to b2, b3(!) and the rest //for screenorig reset visible on upper half of the screen or not at all.. if (si->ps.card_type >= NM2200) ISACRTCW(VEXT, ( ((vtotal & 0x400) >> (10 - 0)) | ((vdisp_e & 0x400) >> (10 - 1)) | ((vblnk_s & 0x400) >> (10 - 2)) | ((vsync_s & 0x400) >> (10 - 3))/*| ((linecomp&0x400)>>3)*/ )); } else { LOG(4, ("CRTC: internal flatpanel active, setting display region only\n")); /* actually program the card! */ /* unlock CRTC registers at index 0-7 */ temp = (ISACRTCR(VSYNCE) & 0x7f); /* we need to wait a bit or the card will mess-up it's */ /* register values.. */ snooze(10); ISACRTCW(VSYNCE, temp); /* horizontal standard VGA regs */ ISACRTCW(HDISPE, (hdisp_e & 0xff)); /* vertical standard VGA regs */ temp = (ISACRTCR(OVERFLOW) & ~0x52); /* we need to wait a bit or the card will mess-up it's */ /* register values.. */ snooze(10); ISACRTCW(OVERFLOW, ( temp | ((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) | ((linecomp & 0x100) >> (8 - 4)) )); ISACRTCW(PRROWSCN, 0x00); /* not used */ temp = (ISACRTCR(MAXSCLIN) & ~0x40); /* we need to wait a bit or the card will mess-up it's */ /* register values.. */ snooze(10); ISACRTCW(MAXSCLIN, (temp | ((linecomp & 0x200) >> (9 - 6)))); ISACRTCW(VDISPE, (vdisp_e & 0xff)); //linux:(BIOSmode) // regp->CRTC[23] = 0xC3; ISACRTCW(LINECOMP, (linecomp & 0xff)); /* horizontal - no extended regs available or needed on */ /* NeoMagic chips */ /* vertical - extended regs */ //fixme: linecomp should have an extra bit... testable by setting linecomp //to 100 for example and then try out writing an '1' to b2, b3(!) and the rest //for screenorig reset visible on upper half of the screen or not at all.. if (si->ps.card_type >= NM2200) { temp = (ISACRTCR(VEXT) & ~0x02); /* we need to wait a bit or the card will mess-up it's */ /* register values.. */ snooze(10); ISACRTCW(VEXT, ( temp | ((vdisp_e & 0x400) >> (10 - 1))/*| ((linecomp&0x400)>>3)*/ )); } } /* setup HSYNC & VSYNC polarity */ LOG(2,("CRTC: sync polarity: ")); temp = ISARB(MISCR); if (target.timing.flags & B_POSITIVE_HSYNC) { LOG(2,("H:pos ")); temp &= ~0x40; } else { LOG(2,("H:neg ")); temp |= 0x40; } if (target.timing.flags & B_POSITIVE_VSYNC) { LOG(2,("V:pos ")); temp &= ~0x80; } else { LOG(2,("V:neg ")); temp |= 0x80; } /* we need to wait a bit or the card will mess-up it's register values.. */ snooze(10); ISAWB(MISCW, temp); LOG(2,(", MISC reg readback: $%02x\n", ISARB(MISCR))); /* program 'fixed' mode if needed */ if (si->ps.card_type != NM2070) { uint8 width; temp = ISAGRPHR(PANELCTRL1); /* we need to wait a bit or the card will mess-up it's register values.. */ snooze(10); switch (target.timing.h_display) { case 1280: width = (3 << 5); break; case 1024: width = (2 << 5); break; case 800: width = (1 << 5); break; case 640: default: //fixme: non-std modes should be in between above modes?!? width = (0 << 5); break; } switch (si->ps.card_type) { case NM2090: case NM2093: case NM2097: case NM2160: //fixme: checkout b6???? ISAGRPHW(PANELCTRL1, ((temp & ~0x20) | (width & 0x20))); break; default: /* NM2200 and later */ ISAGRPHW(PANELCTRL1, ((temp & ~0x60) | (width & 0x60))); break; } } return B_OK; } status_t nm_crtc_depth(int mode) { uint8 vid_delay = 0; LOG(4,("CRTC: setting colordepth to be displayed\n")); /* set VCLK scaling */ switch(mode) { case BPP8: vid_delay = 0x01; break; case BPP15: vid_delay = 0x02; break; case BPP16: vid_delay = 0x03; break; case BPP24: vid_delay = 0x04; break; default: LOG(4,("CRTC: colordepth not supported, aborting!\n")); return B_ERROR; break; } switch (si->ps.card_type) { case NM2070: vid_delay |= (ISAGRPHR(COLDEPTH) & 0xf0); break; default: vid_delay |= (ISAGRPHR(COLDEPTH) & 0x70); break; } /* we need to wait a bit or the card will mess-up it's */ /* register values.. (NM2160) */ snooze(10); ISAGRPHW(COLDEPTH, vid_delay); snooze(10); LOG(4,("CRTC: colordepth register readback $%02x\n", (ISAGRPHR(COLDEPTH)))); return B_OK; } status_t nm_crtc_dpms(bool display, bool h, bool v) { char msg[100]; const char* displayStatus; const char* horizontalSync; const char* verticalSync; uint8 temp, size_outputs; sprintf(msg, "CRTC: setting DPMS: "); /* start synchronous reset: required before turning screen off! */ ISASEQW(RESET, 0x01); /* turn screen off */ temp = ISASEQR(CLKMODE); /* we need to wait a bit or the card will mess-up it's */ /* register values.. (NM2160) */ snooze(10); if (display) { ISASEQW(CLKMODE, (temp & ~0x20)); /* end synchronous reset if display should be enabled */ ISASEQW(RESET, 0x03); displayStatus = "on"; } else { ISASEQW(CLKMODE, (temp | 0x20)); displayStatus = "off"; } temp = 0x00; if (h) { horizontalSync = "enabled"; } else { temp |= 0x10; horizontalSync = "disabled"; } if (v) { verticalSync = "enabled"; } else { temp |= 0x20; verticalSync = "disabled"; } snprintf(msg, sizeof(msg), "CRTC: setting DPMS: display %s, hsync %s, vsync %s\n", displayStatus, horizontalSync, verticalSync); LOG(4, (msg)); /* read panelsize and currently active outputs */ size_outputs = nm_general_output_read(); /* we need to wait a bit or the card will mess-up it's register */ /* values.. (NM2160) */ snooze(10); if (si->ps.card_type < NM2200) { /* no full DPMS support */ if (temp) { /* Turn panel plus backlight and external monitor's */ /* sync signals off */ ISAGRPHW(PANELCTRL1, (size_outputs & 0xfc)); } else { /* restore 'previous' output device(s) */ ISAGRPHW(PANELCTRL1, size_outputs); } } else { if (temp) { /* Turn panel plus backlight off */ ISAGRPHW(PANELCTRL1, (size_outputs & 0xfd)); } else { /* restore 'previous' panel situation */ ISAGRPHW(PANELCTRL1, size_outputs); } /* if external monitor is active, update it's DPMS state */ if (size_outputs & 0x01) { /* we have full DPMS support for external monitors */ //fixme: checkout if so... temp |= ((ISAGRPHR(ENSETRESET) & 0x0f) | 0x80); /* we need to wait a bit or the card will mess-up it's */ /* register values.. (NM2160) */ snooze(10); ISAGRPHW(ENSETRESET, temp); snooze(10); LOG(4,("CRTC: DPMS readback $%02x, programmed $%02x\n", ISAGRPHR(ENSETRESET), temp)); } } return B_OK; } status_t nm_crtc_set_display_pitch() { uint32 offset; LOG(4,("CRTC: setting card pitch (offset between lines)\n")); /* figure out offset value hardware needs: same for all Neomagic cards */ offset = si->fbc.bytes_per_row / 8; LOG(2,("CRTC: offset register set to: $%04x\n", offset)); /* program the card */ ISACRTCW(PITCHL, (offset & 0xff)); //fixme: test for max supported pitch if possible, //not all bits below will be implemented. //NM2160: confirmed b0 and b1 in register below to exist and work. if (si->ps.card_type != NM2070) ISAGRPHW(CRTC_PITCHE, ((offset & 0xff00) >> 8)); return B_OK; } status_t nm_crtc_set_display_start(uint32 startadd,uint8 bpp) { uint8 val; uint32 timeout = 0; LOG(2,("CRTC: relative startadd: $%06x\n",startadd)); LOG(2,("CRTC: frameRAM: $%08x\n",si->framebuffer)); LOG(2,("CRTC: framebuffer: $%08x\n",si->fbc.frame_buffer)); /* make sure we _just_ left retrace, because otherwise distortions */ /* might occur during our reprogramming (no double buffering) */ /* (verified on NM2160) */ /* we might have no retraces during setmode! So: * wait 25mS max. for retrace to occur (refresh > 40Hz) */ //fixme? move this function to the kernel driver... is much 'faster'. while ((!(ISARB(INSTAT1) & 0x08)) && (timeout < (25000/4))) { snooze(4); timeout++; } /* now wait until retrace ends (with timeout) */ timeout = 0; while ((ISARB(INSTAT1) & 0x08) && (timeout < (25000/4))) { snooze(4); timeout++; } /* set standard VGA registers */ /* (startadress in 32bit words (b2 - b17) */ ISACRTCW(FBSTADDH, ((startadd & 0x03fc00) >> 10)); ISACRTCW(FBSTADDL, ((startadd & 0x0003fc) >> 2)); /* set NM extended register */ //fixme: NM2380 _must_ have one more bit (has >4Mb RAM)!! //this is testable via virtualscreen in 640x480x8 mode... //(b4 is >256Kb adresswrap bit, so that's already occupied) val = ISAGRPHR(FBSTADDE); /* we need to wait a bit or the card will mess-up it's */ /* register values.. (NM2160) */ snooze(10); if (si->ps.card_type < NM2200) /* extended bits: (b18-20) */ ISAGRPHW(FBSTADDE,(((startadd >> 18) & 0x07) | (val & 0xf8))); else /* extended bits: (b18-21) */ ISAGRPHW(FBSTADDE,(((startadd >> 18) & 0x0f) | (val & 0xf0))); /* set byte adress: (b0 - 1): * Neomagic cards work with _pixel_ offset here. */ switch(bpp) { case 8: ISAATBW(HORPIXPAN, (startadd & 0x00000003)); break; case 15: case 16: ISAATBW(HORPIXPAN, ((startadd & 0x00000002) >> 1)); break; case 24: ISAATBW(HORPIXPAN, ((4 - (startadd & 0x00000003)) & 0x03)); break; } return B_OK; } /* setup centering mode for current internal or simultaneous */ /* flatpanel mode */ status_t nm_crtc_center(display_mode target, bool crt_only) { /* note: * NM2070 apparantly doesn't support horizontal */ /* centering this way... */ uint8 vcent1, vcent2, vcent3, vcent4, vcent5; uint8 hcent1, hcent2, hcent3, hcent4, hcent5; uint8 ctrl2, ctrl3; /* preset no centering */ uint16 hoffset = 0; uint16 voffset = 0; vcent1 = vcent2 = vcent3 = vcent4 = vcent5 = 0x00; hcent1 = hcent2 = hcent3 = hcent4 = hcent5 = 0x00; ctrl2 = ctrl3 = 0x00; /* calculate offsets for centering if prudent */ if (!crt_only) { if (target.timing.h_display < si->ps.panel_width) { hoffset = (si->ps.panel_width - target.timing.h_display); /* adjust for register contraints: * horizontal center granularity is 16 pixels */ hoffset = ((hoffset >> 4) - 1); /* turn on horizontal centering? */ ctrl3 = 0x10; } if (target.timing.v_display < si->ps.panel_height) { voffset = (si->ps.panel_height - target.timing.v_display); /* adjust for register contraints: * vertical center granularity is 2 pixels */ voffset = ((voffset >> 1) - 2); /* turn on vertical centering? */ ctrl2 = 0x01; } switch(target.timing.h_display) { case 640: hcent1 = hoffset; vcent3 = voffset; break; case 800: hcent2 = hoffset; switch(target.timing.v_display) { case 480: //Linux fixme: check this out... vcent3 = voffset; break; case 600: vcent4 = voffset; break; } break; case 1024: hcent5 = hoffset; vcent5 = voffset; break; case 1280: /* this mode equals the largest possible panel on the * * newest chip: so no centering needed here. */ break; default: //fixme?: block non-standard modes? for now: not centered. break; } } /* now program the card's registers */ ISAGRPHW(PANELVCENT1, vcent1); ISAGRPHW(PANELVCENT2, vcent2); ISAGRPHW(PANELVCENT3, vcent3); if (si->ps.card_type > NM2070) { ISAGRPHW(PANELVCENT4, vcent4); ISAGRPHW(PANELHCENT1, hcent1); ISAGRPHW(PANELHCENT2, hcent2); ISAGRPHW(PANELHCENT3, hcent3); } if (si->ps.card_type >= NM2160) { ISAGRPHW(PANELHCENT4, hcent4); } if (si->ps.card_type >= NM2200) { ISAGRPHW(PANELVCENT5, vcent5); ISAGRPHW(PANELHCENT5, hcent5); } /* program panel control register 2: don't touch bit 3-5 */ ctrl2 |= (ISAGRPHR(PANELCTRL2) & 0x38); /* we need to wait a bit or the card will mess-up it's register */ /* values.. (NM2160) */ snooze(10); ISAGRPHW(PANELCTRL2, ctrl2); if (si->ps.card_type > NM2070) { /* program panel control register 3: don't touch bit 7-5 */ /* and bit 3-0 */ ctrl3 |= (ISAGRPHR(PANELCTRL3) & 0xef); /* we need to wait a bit or the card will mess-up it's */ /* register values.. (NM2160) */ snooze(10); ISAGRPHW(PANELCTRL3, ctrl3); } return B_OK; } /* program panel modeline if needed */ status_t nm_crtc_prg_panel() { status_t stat = B_ERROR; /* only NM2070 requires this apparantly */ /* (because it's BIOS doesn't do it OK) */ if (si->ps.card_type > NM2070) return B_OK; switch(si->ps.panel_width) { case 640: /* 640x480 panels are only used on NM2070 */ ISACRTCW(PANEL_0x40, 0x5f); ISACRTCW(PANEL_0x41, 0x50); ISACRTCW(PANEL_0x42, 0x02); ISACRTCW(PANEL_0x43, 0x55); ISACRTCW(PANEL_0x44, 0x81); ISACRTCW(PANEL_0x45, 0x0b); ISACRTCW(PANEL_0x46, 0x2e); ISACRTCW(PANEL_0x47, 0xea); ISACRTCW(PANEL_0x48, 0x0c); ISACRTCW(PANEL_0x49, 0xe7); ISACRTCW(PANEL_0x4a, 0x04); ISACRTCW(PANEL_0x4b, 0x2d); ISACRTCW(PANEL_0x4c, 0x28); ISACRTCW(PANEL_0x4d, 0x90); ISACRTCW(PANEL_0x4e, 0x2b); ISACRTCW(PANEL_0x4f, 0xa0); stat = B_OK; break; case 800: switch(si->ps.panel_height) { case 600: /* 800x600 panels are used on all cards... */ ISACRTCW(PANEL_0x40, 0x7f); ISACRTCW(PANEL_0x41, 0x63); ISACRTCW(PANEL_0x42, 0x02); ISACRTCW(PANEL_0x43, 0x6c); ISACRTCW(PANEL_0x44, 0x1c); ISACRTCW(PANEL_0x45, 0x72); ISACRTCW(PANEL_0x46, 0xe0); ISACRTCW(PANEL_0x47, 0x58); ISACRTCW(PANEL_0x48, 0x0c); ISACRTCW(PANEL_0x49, 0x57); ISACRTCW(PANEL_0x4a, 0x73); ISACRTCW(PANEL_0x4b, 0x3d); ISACRTCW(PANEL_0x4c, 0x31); ISACRTCW(PANEL_0x4d, 0x01); ISACRTCW(PANEL_0x4e, 0x36); ISACRTCW(PANEL_0x4f, 0x1e); if (si->ps.card_type > NM2070) { ISACRTCW(PANEL_0x50, 0x6b); ISACRTCW(PANEL_0x51, 0x4f); ISACRTCW(PANEL_0x52, 0x0e); ISACRTCW(PANEL_0x53, 0x58); ISACRTCW(PANEL_0x54, 0x88); ISACRTCW(PANEL_0x55, 0x33); ISACRTCW(PANEL_0x56, 0x27); ISACRTCW(PANEL_0x57, 0x16); ISACRTCW(PANEL_0x58, 0x2c); ISACRTCW(PANEL_0x59, 0x94); } stat = B_OK; break; case 480: /* ...while 800x480 widescreen panels are not used on NM2070. */ ISACRTCW(PANEL_0x40, 0x7f); ISACRTCW(PANEL_0x41, 0x63); ISACRTCW(PANEL_0x42, 0x02); ISACRTCW(PANEL_0x43, 0x6b); ISACRTCW(PANEL_0x44, 0x1b); ISACRTCW(PANEL_0x45, 0x72); ISACRTCW(PANEL_0x46, 0xe0); ISACRTCW(PANEL_0x47, 0x1c); ISACRTCW(PANEL_0x48, 0x00); ISACRTCW(PANEL_0x49, 0x57); ISACRTCW(PANEL_0x4a, 0x73); ISACRTCW(PANEL_0x4b, 0x3e); ISACRTCW(PANEL_0x4c, 0x31); ISACRTCW(PANEL_0x4d, 0x01); ISACRTCW(PANEL_0x4e, 0x36); ISACRTCW(PANEL_0x4f, 0x1e); ISACRTCW(PANEL_0x50, 0x6b); ISACRTCW(PANEL_0x51, 0x4f); ISACRTCW(PANEL_0x52, 0x0e); ISACRTCW(PANEL_0x53, 0x57); ISACRTCW(PANEL_0x54, 0x87); ISACRTCW(PANEL_0x55, 0x33); ISACRTCW(PANEL_0x56, 0x27); ISACRTCW(PANEL_0x57, 0x16); ISACRTCW(PANEL_0x58, 0x2c); ISACRTCW(PANEL_0x59, 0x94); stat = B_OK; break; } break; case 1024: switch(si->ps.panel_height) { case 768: /* 1024x768 panels are only used on later cards * (NM2097 and later ?) */ ISACRTCW(PANEL_0x40, 0xa3); ISACRTCW(PANEL_0x41, 0x7f); ISACRTCW(PANEL_0x42, 0x06); ISACRTCW(PANEL_0x43, 0x85); ISACRTCW(PANEL_0x44, 0x96); ISACRTCW(PANEL_0x45, 0x24); ISACRTCW(PANEL_0x46, 0xe5); ISACRTCW(PANEL_0x47, 0x02); ISACRTCW(PANEL_0x48, 0x08); ISACRTCW(PANEL_0x49, 0xff); ISACRTCW(PANEL_0x4a, 0x25); ISACRTCW(PANEL_0x4b, 0x4f); ISACRTCW(PANEL_0x4c, 0x40); ISACRTCW(PANEL_0x4d, 0x00); ISACRTCW(PANEL_0x4e, 0x44); ISACRTCW(PANEL_0x4f, 0x0c); ISACRTCW(PANEL_0x50, 0x7a); ISACRTCW(PANEL_0x51, 0x56); ISACRTCW(PANEL_0x52, 0x00); ISACRTCW(PANEL_0x53, 0x5d); ISACRTCW(PANEL_0x54, 0x0e); ISACRTCW(PANEL_0x55, 0x3b); ISACRTCW(PANEL_0x56, 0x2b); ISACRTCW(PANEL_0x57, 0x00); ISACRTCW(PANEL_0x58, 0x2f); ISACRTCW(PANEL_0x59, 0x18); ISACRTCW(PANEL_0x60, 0x88); ISACRTCW(PANEL_0x61, 0x63); ISACRTCW(PANEL_0x62, 0x0b); ISACRTCW(PANEL_0x63, 0x69); ISACRTCW(PANEL_0x64, 0x1a); stat = B_OK; break; case 480: /* 1024x480 widescreen panels are only used on later cards * (NM2097 and later ?) */ ISACRTCW(PANEL_0x40, 0xa3); ISACRTCW(PANEL_0x41, 0x7f); ISACRTCW(PANEL_0x42, 0x1b); ISACRTCW(PANEL_0x43, 0x89); ISACRTCW(PANEL_0x44, 0x16); ISACRTCW(PANEL_0x45, 0x0b); ISACRTCW(PANEL_0x46, 0x2c); ISACRTCW(PANEL_0x47, 0xe8); ISACRTCW(PANEL_0x48, 0x0c); ISACRTCW(PANEL_0x49, 0xe7); ISACRTCW(PANEL_0x4a, 0x09); ISACRTCW(PANEL_0x4b, 0x4f); ISACRTCW(PANEL_0x4c, 0x40); ISACRTCW(PANEL_0x4d, 0x00); ISACRTCW(PANEL_0x4e, 0x44); ISACRTCW(PANEL_0x4f, 0x0c); ISACRTCW(PANEL_0x50, 0x7a); ISACRTCW(PANEL_0x51, 0x56); ISACRTCW(PANEL_0x52, 0x00); ISACRTCW(PANEL_0x53, 0x5d); ISACRTCW(PANEL_0x54, 0x0e); ISACRTCW(PANEL_0x55, 0x3b); ISACRTCW(PANEL_0x56, 0x2a); ISACRTCW(PANEL_0x57, 0x00); ISACRTCW(PANEL_0x58, 0x2f); ISACRTCW(PANEL_0x59, 0x18); ISACRTCW(PANEL_0x60, 0x88); ISACRTCW(PANEL_0x61, 0x63); ISACRTCW(PANEL_0x62, 0x0b); ISACRTCW(PANEL_0x63, 0x69); ISACRTCW(PANEL_0x64, 0x1a); stat = B_OK; break; } break; case 1280: /* no info available */ break; } if (stat != B_OK) LOG(2,("CRTC: unable to program panel: unknown modeline needed.\n")); return stat; } status_t nm_crtc_cursor_init() { int i; vuint32 * fb; uint32 curadd, curreg; /* the cursor is at the end of cardRAM */ curadd = ((si->ps.memory_size * 1024) - si->ps.curmem_size); /* set cursor bitmap adress on a 1kb boundary, and move the bits around * so they get placed at the correct registerbits */ curreg = (((curadd >> 10) & 0x000f) << 8); curreg |= (((curadd >> 10) & 0x0ff0) >> 4); /* NM2380 must have an extra bit for > 4Mb: assuming it to be on b12... */ curreg |= ((curadd >> 10) & 0x1000); if (si->ps.card_type < NM2200) CR1W(CURADDRESS, curreg); else CR1W(22CURADDRESS, curreg); /*set cursor colour*/ if (si->ps.card_type < NM2200) { /* background is black */ CR1W(CURBGCOLOR, 0x00000000); /* foreground is white */ CR1W(CURFGCOLOR, 0x00ffffff); } else { /* background is black */ CR1W(22CURBGCOLOR, 0x00000000); /* foreground is white */ CR1W(22CURFGCOLOR, 0x00ffffff); } /* we must set a valid colordepth to get full RAM access on Neomagic cards: * in old pre 8-bit color VGA modes some planemask is in effect apparantly, * allowing access only to every 7th and 8th RAM byte across the * entire RAM. */ nm_crtc_depth(BPP8); /* clear cursor: so we need full RAM access! */ fb = ((vuint32 *)(((uintptr_t)si->framebuffer) + curadd)); for (i = 0; i < (1024/4); i++) { fb[i] = 0; } /* activate hardware cursor */ nm_crtc_cursor_show(); return B_OK; } status_t nm_crtc_cursor_show() { if (si->ps.card_type < NM2200) { CR1W(CURCTRL, 0x00000001); } else { CR1W(22CURCTRL, 0x00000001); } return B_OK; } status_t nm_crtc_cursor_hide() { //linux fixme: using this kills PCI(?) access sometimes, //so use ISA access as below... /* if (si->ps.card_type < NM2200) { CR1W(CURCTRL, 0x00000000); } else { CR1W(22CURCTRL, 0x00000000); } */ /* disable cursor */ ISAGRPHW(CURCTRL,0x00); return B_OK; } /*set up cursor shape*/ status_t nm_crtc_cursor_define(uint8* andMask,uint8* xorMask) { uint8 y; vuint8 * cursor; /* get a pointer to the cursor: it's at the end of cardRAM */ cursor = (vuint8*) si->framebuffer; cursor += ((si->ps.memory_size * 1024) - si->ps.curmem_size); /*draw the cursor*/ for(y=0;y<16;y++) { cursor[y*16+8]=~*andMask++; cursor[y*16+0]=*xorMask++; cursor[y*16+9]=~*andMask++; cursor[y*16+1]=*xorMask++; } //test.. only valid for ps.f_ref * (n + 1)) / ((m + 1) * x)); LOG(2,("CRTC: Pixelclock is %fMHz\n", pclk)); nm_general_output_select(); } */ return B_OK; } /*position the cursor*/ status_t nm_crtc_cursor_position(uint16 x ,uint16 y) { //NM2160 is ok without this, still verify the rest..: /* make sure we are not in retrace, because the register(s) might get copied * during our reprogramming them (double buffering feature) */ /* fixme!? while (ACCR(STATUS) & 0x08) { snooze(4); } */ if (si->ps.card_type < NM2200) { CR1W(CURX, (uint32)x); CR1W(CURY, (uint32)y); } else { CR1W(22CURX, (uint32)x); CR1W(22CURY, (uint32)y); } return B_OK; }