#define MODULE_BIT 0x00040000
#include "mga_std.h"
status_t gx00_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
)
{
*hd_e &= 0x0ff8;
*hs_s &= 0x0ff8;
*hs_e &= 0x0ff8;
*ht &= 0x0ff8;
if (*hd_e > ((0x00ff + 1) << 3)) *hd_e = ((0x00ff + 1) << 3);
if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3);
if (*hs_e > ( 0x01ff << 3)) *hs_e = ( 0x01ff << 3);
if (*ht > ((0x01ff + 5) << 3)) *ht = ((0x01ff + 5) << 3);
if (*hd_e < 640) *hd_e = 640;
switch (si->ps.card_type)
{
case MIL1:
case MYST:
if (*hd_e > 1600) *hd_e = 1600;
break;
case MIL2:
case G100:
case G200:
if (*hd_e > 1920) *hd_e = 1920;
break;
default:
if (*hd_e > 2048) *hd_e = 2048;
break;
}
if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80);
if (*ht > (*hd_e + 0x3f8)) *ht = (*hd_e + 0x3f8);
if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8);
if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8);
if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8);
if (*vd_e > 0x7ff ) *vd_e = 0x7ff ;
if (*vs_s > (0xfff - 1)) *vs_s = (0xfff - 1);
if (*vs_e > 0xfff ) *vs_e = 0xfff ;
if (*vt > (0xfff + 2)) *vt = (0xfff + 2);
if (*vd_e < 480) *vd_e = 480;
switch (si->ps.card_type)
{
case MIL1:
case MYST:
if (*vd_e > 1200) *vd_e = 1200;
break;
case MIL2:
case G100:
case G200:
if (*vd_e > 1440) *vd_e = 1440;
break;
default:
if (*vd_e > 1536) *vd_e = 1536;
break;
}
if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3);
if (*vt > (*vd_e + 0xff)) *vt = (*vd_e + 0xff);
if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1);
if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1);
if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f);
return B_OK;
}
status_t gx00_crtc_set_timing(display_mode target)
{
uint8 temp;
uint32 htotal;
uint32 hdisp_e;
uint32 hsync_s;
uint32 hsync_e;
uint32 hblnk_s;
uint32 hblnk_e;
uint32 vtotal;
uint32 vdisp_e;
uint32 vsync_s;
uint32 vsync_e;
uint32 vblnk_s;
uint32 vblnk_e;
uint32 linecomp;
LOG(4,("CRTC: setting timing\n"));
htotal = ((target.timing.h_total >> 3) - 5);
hdisp_e = ((target.timing.h_display >> 3) - 1);
hblnk_s = hdisp_e;
hblnk_e = (htotal + 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;
linecomp = target.timing.v_display;
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));
VGAW_I(CRTC, 0x00, (htotal & 0x0ff));
VGAW_I(CRTC, 0x01, (hdisp_e & 0x0ff));
VGAW_I(CRTC, 0x02, (hblnk_s & 0x0ff));
VGAW_I(CRTC, 0x03, ((hblnk_e & 0x01f) | 0x80));
VGAW_I(CRTC, 0x04, (hsync_s & 0x0ff));
VGAW_I(CRTC, 0x05, (hsync_e & 0x01f) | ((hblnk_e & 0x020) << 2));
VGAW_I(CRTC, 0x06, (vtotal & 0x0ff));
VGAW_I(CRTC, 0x07,
(
((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))
));
VGAW_I(CRTC, 0x08, 0x00);
VGAW_I(CRTC, 0x09, ((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6)));
VGAW_I(CRTC, 0x10, (vsync_s & 0x0ff));
VGAW_I(CRTC, 0x11, (((VGAR_I(CRTC, 0x11)) & 0xf0) | (vsync_e & 0x00f)));
VGAW_I(CRTC, 0x12, (vdisp_e & 0x0ff));
VGAW_I(CRTC, 0x15, (vblnk_s & 0x0ff));
VGAW_I(CRTC, 0x16, (vblnk_e & 0x0ff));
VGAW_I(CRTC, 0x18, (linecomp & 0x0ff));
VGAW_I(CRTCEXT, 1,
(
((htotal & 0x100) >> (8 - 0)) |
((hblnk_s & 0x100) >> (8 - 1)) |
((hsync_s & 0x100) >> (8 - 2)) |
((hblnk_e & 0x040) >> (6 - 6)) |
(VGAR_I(CRTCEXT, 1) & 0xb8)
));
VGAW_I(CRTCEXT, 2,
(
((vtotal & 0xc00) >> (10 - 0)) |
((vdisp_e & 0x400) >> (10 - 2)) |
((vblnk_s & 0xc00) >> (10 - 3)) |
((vsync_s & 0xc00) >> (10 - 5)) |
((linecomp & 0x400) >> (10 - 7))
));
LOG(2,("CRTC: sync polarity: "));
temp = VGAR(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;
}
VGAW(MISCW, temp);
LOG(2,(", MISC reg readback: $%02x\n", VGAR(MISCR)));
return B_OK;
}
status_t gx00_crtc_depth(int mode)
{
uint8 viddelay = 0;
if (si->ps.card_type < G100) do {
if (si->ps.memory_size <= 2) { viddelay = 1<<3; break;}
if (si->ps.memory_size <= 4) { viddelay = 0<<3; break;}
viddelay = 2<<3;
} while (0);
if (si->settings.greensync)
{
if (si->ps.card_type <= MIL2)
DXIW(GENCTRL, (DXIR(GENCTRL) | 0x20));
else
DXIW(GENCTRL, (DXIR(GENCTRL) & ~0x20));
viddelay |= 0x40;
LOG(4,("CRTC: sync_on_green enabled\n"));
}
else
{
if (si->ps.card_type <= MIL2)
DXIW(GENCTRL, (DXIR(GENCTRL) & ~0x20));
else
DXIW(GENCTRL, (DXIR(GENCTRL) | 0x20));
LOG(4,("CRTC: sync_on_green disabled\n"));
}
switch(mode)
{
case BPP8:
VGAW_I(CRTCEXT,3,viddelay|0x80);
break;
case BPP15:case BPP16:
VGAW_I(CRTCEXT,3,viddelay|0x81);
break;
case BPP24:
VGAW_I(CRTCEXT,3,viddelay|0x82);
break;
case BPP32:case BPP32DIR:
VGAW_I(CRTCEXT,3,viddelay|0x83);
break;
}
return B_OK;
}
status_t gx00_crtc_dpms(bool display, bool h, bool v)
{
char msg[100];
strlcpy(msg, "CRTC: setting DPMS: ", sizeof(msg));
if (display)
{
VGAW_I(SEQ,1, 0x00);
strlcat(msg, "display on, ", sizeof(msg));
}
else
{
VGAW_I(SEQ,1, 0x20);
strlcat(msg, "display off, ", sizeof(msg));
}
if (h)
{
VGAW_I(CRTCEXT, 1, (VGAR_I(CRTCEXT, 1) & 0xef));
strlcat(msg, "hsync enabled, ", sizeof(msg));
}
else
{
VGAW_I(CRTCEXT, 1, (VGAR_I(CRTCEXT, 1) | 0x10));
strlcat(msg, "hsync disabled, ", sizeof(msg));
}
if (v)
{
VGAW_I(CRTCEXT, 1, (VGAR_I(CRTCEXT, 1) & 0xdf));
strlcat(msg, "vsync enabled\n", sizeof(msg));
}
else
{
VGAW_I(CRTCEXT, 1, (VGAR_I(CRTCEXT, 1) | 0x20));
strlcat(msg, "vsync disabled\n", sizeof(msg));
}
LOG(4, (msg));
VGAW_I(CRTC,0x17,0xC3);
VGAW_I(CRTC,0x14,0x00);
if (si->ps.card_type >= G450)
{
if (si->crossed_conns)
{
DXIW(SYNCCTRL, (DXIR(SYNCCTRL) & 0x0f));
}
else
{
DXIW(SYNCCTRL, (DXIR(SYNCCTRL) & 0xf0));
}
}
return B_OK;
}
status_t gx00_crtc_set_display_pitch()
{
uint32 offset;
LOG(4,("CRTC: setting card pitch (offset between lines)\n"));
offset = si->fbc.bytes_per_row / 16;
LOG(2,("CRTC: offset register: 0x%04x\n",offset));
VGAW_I(CRTC,0x13,(offset&0xFF));
VGAW_I(CRTCEXT,0,(VGAR_I(CRTCEXT,0)&0xCF)|((offset&0x300)>>4));
return B_OK;
}
status_t gx00_crtc_set_display_start(uint32 startadd,uint8 bpp)
{
uint32 ext0;
LOG(4,("CRTC: setting card RAM to be displayed bpp %d\n", bpp));
startadd >>= 3;
LOG(2,("CRTC: startadd: %x\n",startadd));
LOG(2,("CRTC: frameRAM: %x\n",si->framebuffer));
LOG(2,("CRTC: framebuffer: %x\n",si->fbc.frame_buffer));
if (si->ps.card_type < G100)
{
uint32 timeout = 0;
while ((!(ACCR(STATUS) & 0x08)) && (timeout < (25000/4)))
{
snooze(4);
timeout++;
}
}
VGAW_I(CRTC,0xD,startadd&0xFF);
VGAW_I(CRTC,0xC,(startadd&0xFF00)>>8);
ext0 = VGAR_I(CRTCEXT,0)&0xB0;
ext0|= (startadd&0xF0000)>>16;
if (si->ps.card_type>=G200)
ext0|=(startadd&0x100000)>>14;
if (si->ps.card_type>=G400)
VGAW_I(CRTCEXT,8,((startadd&0x200000)>>21));
VGAW_I(CRTCEXT,0,ext0);
return B_OK;
}
status_t gx00_crtc_mem_priority(uint8 colordepth)
{
float tpixclk, tmclk, refresh, temp;
uint8 mp, vc, hiprilvl, maxhipri, prioctl;
if (si->settings.usebios || (si->ps.pins_status != B_OK))
{
LOG(4,("CRTC: Card not coldstarted, skipping memory priority level setup\n"));
return B_OK;
}
if (si->ps.card_type != G200)
{
LOG(4,("CRTC: Memory priority level setup not needed, skipping\n"));
return B_OK;
}
LOG(4,("CRTC: Setting G200 memory priority level\n"));
switch ((si->ps.memrdbk_reg & 0x00c00000) >> 22)
{
case 0:
mp = 52;
break;
case 1:
mp = 41;
break;
case 2:
mp = 32;
break;
default:
mp = 52;
LOG(8,("CRTC: Streamer flowcontrol violation in PINS, defaulting to %%00\n"));
break;
}
vc = (8 * colordepth) / 64;
tpixclk = 1000000 / si->dm.timing.pixel_clock;
if (si->ps.v3_option2_reg & 0x08)
{
tmclk = 1000.0 / si->ps.std_engine_clock;
}
else
{
if (si->ps.v3_clk_div & 0x02)
tmclk = 3000.0 / si->ps.std_engine_clock;
else
tmclk = 2000.0 / si->ps.std_engine_clock;
}
refresh = ((si->dm.timing.pixel_clock * 1000) /
((uint32)si->dm.timing.h_total * (uint32)si->dm.timing.v_total));
temp = (((((mp * tmclk) + (11 * vc * tpixclk)) / tpixclk) - (vc - 1)) / (8 * vc)) + 1.0;
if (temp > 7.0) temp = 7.0;
if (temp < 0.0) temp = 0.0;
hiprilvl = 7 - ((uint8) temp);
if (hiprilvl > 4) hiprilvl = 4;
if ((si->dm.timing.v_display > 768) && (hiprilvl > 3)) hiprilvl = 3;
if ((si->dm.timing.v_display > 864) && (hiprilvl > 2) && (refresh >= 76.0)) hiprilvl = 2;
if ((si->dm.timing.v_display > 1024) && (hiprilvl > 2)) hiprilvl = 2;
temp = (vc * (tmclk / tpixclk)) + 0.5;
if (temp > (float)hiprilvl) temp = (float)hiprilvl;
if (temp < 0.0) temp = 0.0;
maxhipri = ((uint8) temp);
prioctl = ((hiprilvl & 0x07) | ((maxhipri & 0x07) << 4));
VGAW_I(CRTCEXT, 6, prioctl);
LOG(4,("CRTC: Vclks/char is %d, pixClk period %02.2fnS, memClk period %02.2fnS\n",
vc, tpixclk, tmclk));
LOG(4,("CRTC: memory priority control register is set to $%02x\n", prioctl));
return B_OK;
}
status_t gx00_crtc_cursor_init()
{
int i;
if (si->ps.card_type >= G100)
{
vuint32 * fb;
const uint32 curadd = 0;
DXIW(CURADDL,curadd >> 10);
DXIW(CURADDH,curadd >> 18);
DXIW(CURADDL,curadd >> 10);
DXIW(CURADDH,curadd >> 18);
DXIW(CURCOL0RED,0XFF);
DXIW(CURCOL0GREEN,0xFF);
DXIW(CURCOL0BLUE,0xFF);
DXIW(CURCOL1RED,0);
DXIW(CURCOL1GREEN,0);
DXIW(CURCOL1BLUE,0);
DXIW(CURCOL2RED,0);
DXIW(CURCOL2GREEN,0);
DXIW(CURCOL2BLUE,0);
fb = (vuint32 *) si->framebuffer + curadd;
for (i=0;i<(1024/4);i++)
{
fb[i]=0;
}
}
else
{
DACW(TVP_CUROVRWTADD,0x00);
DACW(TVP_CUROVRDATA,0xff);
DACW(TVP_CUROVRDATA,0xff);
DACW(TVP_CUROVRDATA,0xff);
DACW(TVP_CUROVRDATA,0xff);
DACW(TVP_CUROVRDATA,0xff);
DACW(TVP_CUROVRDATA,0xff);
DACW(TVP_CUROVRDATA,0x00);
DACW(TVP_CUROVRDATA,0x00);
DACW(TVP_CUROVRDATA,0x00);
DACW(TVP_CUROVRDATA,0x00);
DACW(TVP_CUROVRDATA,0x00);
DACW(TVP_CUROVRDATA,0x00);
DXIW(CURCTRL,(DXIR(CURCTRL) & 0x73));
DACW(PALWTADD,0x00);
for(i=0;i<1024;i++)
{
DACW(TVP_CURRAMDATA,0x00);
}
}
gx00_crtc_cursor_show();
return B_OK;
}
status_t gx00_crtc_cursor_show()
{
if ((si->ps.card_type < G100) && (si->dm.timing.h_total > 2048))
{
DXIW(CURCTRL, 0x11);
}
else
{
DXIW(CURCTRL, 0x01);
}
return B_OK;
}
status_t gx00_crtc_cursor_hide()
{
DXIW(CURCTRL,0);
return B_OK;
}
status_t gx00_crtc_cursor_define(uint8* andMask,uint8* xorMask)
{
int y;
if(si->ps.card_type >= G100)
{
vuint8 * cursor;
cursor = (vuint8*) si->framebuffer;
for(y=0;y<16;y++)
{
cursor[y*16+7]=~*andMask++;
cursor[y*16+15]=*xorMask++;
cursor[y*16+6]=~*andMask++;
cursor[y*16+14]=*xorMask++;
}
}
else
{
uint8 curctrl;
curctrl = (DXIR(CURCTRL));
DXIW(CURCTRL, (curctrl & 0xfc));
DXIW(CURCTRL, (DXIR(CURCTRL) & ~0x0c));
DACW(PALWTADD, 0x00);
for(y = 0; y < 16; y++)
{
DACW(PALWTADD, (y * 8));
DACW(TVP_CURRAMDATA, ~*andMask++);
DACW(TVP_CURRAMDATA, ~*andMask++);
}
DXIW(CURCTRL, (DXIR(CURCTRL) | 0x08));
DACW(PALWTADD, 0x00);
for(y = 0; y < 16; y++)
{
DACW(PALWTADD, y*8);
DACW(TVP_CURRAMDATA, *xorMask++);
DACW(TVP_CURRAMDATA, *xorMask++);
}
snooze(5);
DXIW(CURCTRL, curctrl);
}
return B_OK;
}
status_t gx00_crtc_cursor_position(uint16 x ,uint16 y)
{
int i=64;
x+=i;
y+=i;
while (ACCR(STATUS) & 0x08)
{
snooze(4);
}
DACW(CURSPOSXL,x&0xFF);
DACW(CURSPOSXH,x>>8);
DACW(CURSPOSYL,y&0xFF);
DACW(CURSPOSYH,y>>8);
return B_OK;
}