#define MODULE_BIT 0x00001000
#include "mga_std.h"
status_t g450_g550_maven_set_vid_pll(display_mode target);
status_t g100_g400max_maven_set_vid_pll(display_mode target);
status_t gx00_maven_clrline()
{
uint32 x, screensize, pointer_reservation;
uint8* adr;
if (si->ps.card_type > G400MAX) return B_OK;
pointer_reservation = 0;
if ((si->ps.card_type >= G100) && si->settings.hardcursor) pointer_reservation = 1024;
screensize = si->fbc.bytes_per_row * si->dm.virtual_height;
if ((screensize + si->fbc.bytes_per_row + pointer_reservation) <=
(si->ps.memory_size * 1024 * 1024))
{
LOG(4,("MAVEN: clearing line directly below screen\n"));
adr = (uint8*)si->fbc.frame_buffer;
adr += screensize;
for (x = 0; x < si->fbc.bytes_per_row; x++)
{
*(adr + x) = 0x00;
}
}
else
LOG(4,("MAVEN: not clearing line directly below screen: no memory left\n"));
return B_OK;
}
status_t gx00_maven_dpms(bool display, bool h, bool v)
{
if (si->ps.card_type > G400MAX) return B_OK;
if (display && h && v)
{
if (!(si->dm.flags & TV_BITS))
{
MAVW(MONEN, 0xb2);
MAVW(MONSET, 0x20);
MAVW(OUTMODE, 0x03);
MAVW(STABLE, 0x22);
MAVW(TEST, 0x00);
}
else
{
MAVW(MONEN, 0xb3);
MAVW(MONSET, 0x20);
MAVW(OUTMODE, 0x08);
MAVW(STABLE, 0x02);
MAVW(TEST, (MAVR(TEST) & 0x10));
}
}
else
{
MAVW(STABLE, 0x6a);
MAVW(OUTMODE, 0x00);
}
return B_OK;
}
status_t gx00_maven_set_timing(display_mode target)
{
uint8 temp, cnt, offset, loop;
if (si->ps.card_type > G400MAX) return B_OK;
LOG(4,("MAVEN: setting timing\n"));
if ((target.timing.h_display & 0x07) |
(target.timing.h_sync_start & 0x07) |
(target.timing.h_sync_end & 0x07) |
(target.timing.h_total & 0x07))
{
LOG(8,("MAVEN: Horizontal timing is not multiples of 8 pixels\n"));
return B_ERROR;
}
MAVWW(LASTLINEL, target.timing.h_total);
MAVWW(HSYNCLENL, (target.timing.h_sync_end - target.timing.h_sync_start));
MAVWW(HSYNCSTRL, (target.timing.h_total - target.timing.h_sync_start));
MAVWW(HDISPLAYL, ((target.timing.h_total - target.timing.h_sync_start) +
target.timing.h_display));
MAVWW(HTOTALL, (target.timing.h_total + 1));
MAVWW(VSYNCLENL, (target.timing.v_sync_end - target.timing.v_sync_start - 1));
MAVWW(VSYNCSTRL, (target.timing.v_total - target.timing.v_sync_start));
MAVWW(VDISPLAYL, (target.timing.v_total - 1));
MAVWW(VTOTALL, (target.timing.v_total - 1));
MAVWW(HVIDRSTL, (target.timing.h_total - si->crtc_delay));
MAVWW(VVIDRSTL, (target.timing.v_total - 2));
LOG(2,("MAVEN: sync polarity: "));
temp = MAVR(LUMA);
switch (((target.timing.flags & B_POSITIVE_HSYNC) >> (29 - 0)) |
((target.timing.flags & B_POSITIVE_VSYNC) >> (30 - 1)))
{
case 0:
LOG(2,("H:neg V:neg\n"));
offset = 2;
break;
case 1:
LOG(2,("H:pos V:neg\n"));
offset = 3;
break;
case 2:
LOG(2,("H:neg V:pos\n"));
offset = 1;
break;
case 3:
default:
LOG(2,("H:pos V:pos\n"));
offset = 0;
break;
}
cnt = 0;
if ((offset - ((int)si->maven_syncpol_offset)) < 0) cnt = 4;
cnt += offset - si->maven_syncpol_offset;
si->maven_syncpol_offset = offset;
temp &= ~0x20;
MAVW(LUMA, temp);
snooze(5);
temp |= 0x10;
MAVW(LUMA, temp);
snooze(5);
for (loop = 0; loop < cnt; loop++)
{
MAVW(LUMA, (temp | 0x20));
snooze(5);
MAVW(LUMA, (temp & ~0x20));
snooze(5);
}
MAVW(LUMA, (temp & ~0x30));
return B_OK;
}
status_t gx00_maven_mode(int mode,float brightness)
{
uint8 luma;
if (si->ps.card_type > G400MAX) return B_OK;
luma = (uint8)(0x0a * brightness);
if (luma > 0x0f) luma = 0x0f;
MAVW(LUMA, luma);
LOG(4,("MAVEN: LUMA setting - %x\n", luma));
return B_OK;
}
void gx00_maven_shutoff()
{
switch (si->ps.card_type)
{
case G100:
case G200:
MAVW(TEST, 0x03);
MAVW(MONEN, 0x00);
MAVW(MONSET, 0x00);
break;
default:
break;
}
}
status_t gx00_maven_set_vid_pll(display_mode target)
{
switch (si->ps.card_type)
{
case G450:
case G550:
return g450_g550_maven_set_vid_pll(target);
break;
default:
return g100_g400max_maven_set_vid_pll(target);
break;
}
return B_ERROR;
}
status_t g450_g550_maven_set_vid_pll(display_mode target)
{
uint8 m=0,n=0,p=0;
uint time = 0;
float pix_setting, req_pclk;
status_t result;
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk));
result = g450_g550_maven_vid_pll_find(target,&pix_setting,&m,&n,&p, 1);
if (result != B_OK)
{
return result;
}
CR2W(CTL, (CR2R(CTL) | 0x08));
CR2W(CTL, (CR2R(CTL) | 0x06));
DXIW(VIDPLLM,(m));
DXIW(VIDPLLN,(n));
DXIW(VIDPLLP,(p));
while((!(DXIR(VIDPLLSTAT) & 0x40)) & (time <= 2000))
{
time++;
snooze(1);
}
if (time > 2000)
LOG(2,("MAVEN: VID PLL frequency not locked!\n"));
else
LOG(2,("MAVEN: VID PLL frequency locked\n"));
CR2W(CTL, (CR2R(CTL) & ~0x08));
return B_OK;
}
status_t g100_g400max_maven_set_vid_pll(display_mode target)
{
uint8 m=0,n=0,p=0;
float pix_setting, req_pclk;
status_t result;
req_pclk = (target.timing.pixel_clock)/1000.0;
LOG(4,("MAVEN: Setting VID PLL for pixelclock %f\n", req_pclk));
result = g100_g400max_maven_vid_pll_find(target,&pix_setting,&m,&n,&p);
if (result != B_OK)
{
return result;
}
MAVW(PIXPLLM,(m));
MAVW(PIXPLLN,(n));
MAVW(PIXPLLP,(p | 0x80));
snooze(2000);
LOG(2,("MAVEN: VID PLL frequency should be locked now...\n"));
return B_OK;
}
status_t g100_g400max_maven_vid_pll_find(
display_mode target, float* calc_pclk, uint8* m_result, uint8* n_result,
uint8* p_result)
{
int m = 0, n = 0, p = 0, m_max;
float error, error_best = INT_MAX;
int best[3] = {0, 0, 0};
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
switch (si->ps.card_type)
{
case G100:
LOG(4, ("MAVEN: G100 restrictions apply\n"));
m_max = 32;
break;
case G200:
LOG(4, ("MAVEN: G200 restrictions apply\n"));
m_max = 32;
break;
default:
LOG(4, ("MAVEN: G400/G400MAX restrictions apply\n"));
m_max = 32;
break;
}
switch (target.space)
{
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac2_clock_32;
break;
default:
max_pclk = si->ps.max_dac2_clock_32;
break;
}
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac2_clock_32dh;
if (req_pclk < (si->ps.min_video_vco / 8.0))
{
LOG(4, ("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_video_vco / 8.0)));
req_pclk = (si->ps.min_video_vco / 8.0);
}
if (req_pclk > max_pclk)
{
LOG(4, ("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
for (p=0x01; p < 0x10; p = p<<1)
{
f_vco = req_pclk * p;
if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco))
{
for (m = 2; m <= m_max; m++)
{
n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5);
if ((n < 8) || (n > 128)) continue;
error = fabs(req_pclk - (((si->ps.f_ref / m) * n) / p));
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
m=best[0] - 1;
n=best[1] - 1;
p=best[2] - 1;
f_vco = (si->ps.f_ref / (m + 1)) * (n + 1);
LOG(2, ("MAVEN: vid VCO frequency found %fMhz\n", f_vco));
switch (si->ps.card_type)
{
case G100:
case G200:
for (;;)
{
if (f_vco >= 180) {p |= (0x03 << 3); break;};
if (f_vco >= 140) {p |= (0x02 << 3); break;};
if (f_vco >= 100) {p |= (0x01 << 3); break;};
break;
}
break;
default:
for (;;)
{
if (f_vco >= 240) {p |= (0x03 << 3); break;};
if (f_vco >= 170) {p |= (0x02 << 3); break;};
if (f_vco >= 110) {p |= (0x01 << 3); break;};
break;
}
break;
}
*calc_pclk = f_vco / ((p & 0x07) + 1);
*m_result = m;
*n_result = n;
*p_result = p;
LOG(2, ("MAVEN: vid PLL check: req. %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}
static status_t gx50_maven_check_vid_pll(uint8 m, uint8 n, uint8 p)
{
uint time = 0, count = 0;
CR2W(CTL, (CR2R(CTL) | 0x06));
DXIW(VIDPLLM,(m));
DXIW(VIDPLLN,(n));
DXIW(VIDPLLP,(p));
time = 0;
while((!(DXIR(VIDPLLSTAT) & 0x40)) & (time <= 1000))
{
time++;
snooze(1);
}
if (time > 1000) return B_ERROR;
for (time = 0, count = 0; time <= 1000; time++)
{
if(DXIR(VIDPLLSTAT) & 0x40) count++;
snooze(1);
}
if (count >= 900) return B_OK;
return B_ERROR;
}
static status_t gx50_maven_check_vid_pll_range(uint8 m, uint8 n, uint8 *p, uint8 *q)
{
uint8 s=0, p_backup = *p;
*q = 0;
*p &= 0x47;
CR2W(CTL, (CR2R(CTL) | 0x08));
for (s = 0; s < 8 ;s++)
{
if (gx50_maven_check_vid_pll(m, n, *p)== B_OK)
{
if ((gx50_maven_check_vid_pll(m, n - 3, *p)== B_OK) &&
(gx50_maven_check_vid_pll(m, n - 2, *p)== B_OK) &&
(gx50_maven_check_vid_pll(m, n - 1, *p)== B_OK) &&
(gx50_maven_check_vid_pll(m, n + 1, *p)== B_OK) &&
(gx50_maven_check_vid_pll(m, n + 2, *p)== B_OK) &&
(gx50_maven_check_vid_pll(m, n + 3, *p)== B_OK))
{
LOG(2,("MAVEN: found optimal working VCO filter: #%d\n",s));
*q = 1;
CR2W(CTL, (CR2R(CTL) & ~0x08));
return B_OK;
}
else
{
LOG(2,("MAVEN: found critical but working VCO filter: #%d\n",s));
*q = 2;
p_backup = *p;
}
}
*p += (1 << 3);
}
*p = p_backup;
CR2W(CTL, (CR2R(CTL) & ~0x08));
if (*q == 2) return B_OK;
LOG(2,("MAVEN: no working VCO filter found!\n"));
return B_ERROR;
}
status_t g450_g550_maven_vid_pll_find
(display_mode target, float* calc_pclk, uint8* m_result, uint8* n_result,
uint8* p_result, uint8 test)
{
int m = 0, n = 0;
uint8 p = 0, q = 0;
float error, error_best = INFINITY;
int best[3] = {0, 0, 0};
float f_vco, max_pclk;
float req_pclk = target.timing.pixel_clock/1000.0;
LOG(4, ("MAVEN: G450/G550 restrictions apply\n"));
switch (target.space)
{
case B_RGB16_LITTLE:
max_pclk = si->ps.max_dac2_clock_16;
break;
case B_RGB32_LITTLE:
max_pclk = si->ps.max_dac2_clock_32;
break;
default:
max_pclk = si->ps.max_dac2_clock_32;
break;
}
if ((target.flags & DUALHEAD_BITS) && (target.space == B_RGB32_LITTLE))
max_pclk = si->ps.max_dac2_clock_32dh;
if (req_pclk < (si->ps.min_video_vco / 16.0))
{
LOG(4, ("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)(si->ps.min_video_vco / 16.0)));
req_pclk = (si->ps.min_video_vco / 16.0);
}
if (req_pclk > max_pclk)
{
LOG(4, ("MAVEN: clamping vidclock: requested %fMHz, set to %fMHz\n",
req_pclk, (float)max_pclk));
req_pclk = max_pclk;
}
for (p=0x01; p < 0x20; p = p<<1)
{
f_vco = req_pclk * p;
if ((f_vco >= si->ps.min_video_vco) && (f_vco <= si->ps.max_video_vco))
{
for (m = 2; m <= 32; m++)
{
n = (int)(((f_vco * m) / (si->ps.f_ref * 2)) + 0.5);
if ((n < (8 + 3)) || (n > (128 - 3))) continue;
error = fabs(req_pclk - ((((si->ps.f_ref * 2)/ m) * n) / p));
if (error < error_best)
{
error_best = error;
best[0]=m;
best[1]=n;
best[2]=p;
}
}
}
}
m=best[0] - 1;
n=best[1] - 2;
switch (best[2])
{
case 1:
p = 0x40;
break;
case 2:
p = 0x00;
break;
case 4:
p = 0x01;
break;
case 8:
p = 0x02;
break;
case 16:
p = 0x03;
break;
}
f_vco = ((si->ps.f_ref * 2) / (m + 1)) * (n + 2);
LOG(2, ("MAVEN: vid VCO frequency found %fMhz\n", f_vco));
if (test)
gx50_maven_check_vid_pll_range(m, n, &p, &q);
else
LOG(2, ("MAVEN: Not testing G450/G550 VCO feedback filters\n"));
*calc_pclk = f_vco / best[2];
*m_result = m;
*n_result = n;
*p_result = p;
LOG(2, ("MAVEN: vid PLL check: req. %fMHz got %fMHz, mnp 0x%02x 0x%02x 0x%02x\n",
req_pclk, *calc_pclk, *m_result, *n_result, *p_result));
return B_OK;
}