diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/smi.h | 1 | ||||
-rw-r--r-- | src/smi_501.c | 112 | ||||
-rw-r--r-- | src/smi_501.h | 2 | ||||
-rw-r--r-- | src/smi_driver.c | 42 |
4 files changed, 98 insertions, 59 deletions
@@ -144,6 +144,7 @@ typedef struct { int Bpp; /* Bytes per pixel */ int MCLK; /* Memory Clock */ + int MXCLK; /* MSOC Clock for local sdram */ ClockRanges clockRange; /* Allowed pixel clock range */ CloseScreenProcPtr CloseScreen; /* Pointer used to save wrapped CloseScreen function */ diff --git a/src/smi_501.c b/src/smi_501.c index 465b8f3..3aa81de 100644 --- a/src/smi_501.c +++ b/src/smi_501.c @@ -168,6 +168,7 @@ SMI501_HWInit(ScrnInfoPtr pScrn) MSOCRegPtr save; MSOCRegPtr mode; SMIPtr pSmi = SMIPTR(pScrn); + int32_t x_select, x_divider, x_shift; save = pSmi->save; mode = pSmi->mode; @@ -194,38 +195,25 @@ SMI501_HWInit(ScrnInfoPtr pScrn) mode->power_ctl.f.status = 0; mode->power_ctl.f.mode = 0; - /* FIXME fixed at 336/3/0 as in the smi sources */ - mode->clock.f.m_select = 1; - mode->clock.f.m_divider = 1; - mode->clock.f.m_shift = 0; - - switch (pSmi->MCLK) { - case 168000: /* 336/1/1 */ - mode->clock.f.m1_select = 1; - mode->clock.f.m1_divider = 0; - mode->clock.f.m1_shift = 1; - break; - case 96000: /* 288/3/0 */ - mode->clock.f.m1_select = 0; - mode->clock.f.m1_divider = 1; - mode->clock.f.m1_shift = 0; - break; - case 144000: /* 288/1/1 */ - mode->clock.f.m1_select = 0; - mode->clock.f.m1_divider = 0; - mode->clock.f.m1_shift = 1; - break; - case 112000: /* 336/3/0 */ - mode->clock.f.m1_select = 1; - mode->clock.f.m1_divider = 1; - mode->clock.f.m1_shift = 0; - break; - default: - /* Do nothing. Use what was configured by the kernel. - * Accordingly to SMI, this should be 144Mhz for 6ns sdram, - * or 112Mhz for other types of sdram. */ - break; + if (pSmi->MCLK) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "MCLK request %d\n", pSmi->MCLK); + (void)SMI501_FindMemClock(pSmi->MCLK, &x_select, &x_divider, &x_shift); + mode->clock.f.m_select = x_select; + mode->clock.f.m_divider = x_divider; + mode->clock.f.m_shift = x_shift; } + /* Else use what was configured by the kernel. */ + + if (pSmi->MXCLK) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV, + "MXCLK request %d\n", pSmi->MXCLK); + (void)SMI501_FindMemClock(pSmi->MXCLK, &x_select, &x_divider, &x_shift); + mode->clock.f.m1_select = x_select; + mode->clock.f.m1_divider = x_divider; + mode->clock.f.m1_shift = x_shift; + } + /* Else use what was configured by the kernel. */ if (!pSmi->Dualhead) { /* crt clones panel */ @@ -253,17 +241,21 @@ SMI501_WriteMode_common(ScrnInfoPtr pScrn, MSOCRegPtr mode) clock.value = READ_SCR(pSmi, mode->current_clock); - clock.f.m_select = mode->clock.f.m_select; - pll = clock.value; - clock.f.m_divider = mode->clock.f.m_divider; - clock.f.m_shift = mode->clock.f.m_shift; - SMI501_SetClock(pSmi, mode->current_clock, pll, clock.value); + if (pSmi->MCLK) { + clock.f.m_select = mode->clock.f.m_select; + pll = clock.value; + clock.f.m_divider = mode->clock.f.m_divider; + clock.f.m_shift = mode->clock.f.m_shift; + SMI501_SetClock(pSmi, mode->current_clock, pll, clock.value); + } - clock.f.m1_select = mode->clock.f.m1_select; - pll = clock.value; - clock.f.m1_divider = mode->clock.f.m1_divider; - clock.f.m1_shift = mode->clock.f.m1_shift; - SMI501_SetClock(pSmi, mode->current_clock, pll, clock.value); + if (pSmi->MXCLK) { + clock.f.m1_select = mode->clock.f.m1_select; + pll = clock.value; + clock.f.m1_divider = mode->clock.f.m1_divider; + clock.f.m1_shift = mode->clock.f.m1_shift; + SMI501_SetClock(pSmi, mode->current_clock, pll, clock.value); + } WRITE_SCR(pSmi, MISC_CTL, mode->misc_ctl.value); @@ -469,7 +461,7 @@ SMI501_FindClock(double clock, int32_t max_divider, Bool has1xclck, multiplier += 2, mclk = multiplier * 24 * 1000.0) { for (divider = 1; divider <= max_divider; divider += 2) { for (shift = 0; shift < 8; shift++) { - /* Divider 1 not in specs form cards older then 502 */ + /* Divider 1 not in specs for cards older then 502 */ for (xclck = 1; xclck >= !has1xclck; xclck--) { diff = (mclk / (divider << shift << xclck)) - clock; if (fabs(diff) < best) { @@ -497,6 +489,42 @@ SMI501_FindClock(double clock, int32_t max_divider, Bool has1xclck, } double +SMI501_FindMemClock(double clock, int32_t *x1_select, + int32_t *x1_divider, int32_t *x1_shift) +{ + double diff, best, mclk; + int32_t multiplier, divider, shift; + + best = 0x7fffffff; + for (multiplier = 12, mclk = multiplier * 24 * 1000.0; + mclk <= 14 * 24 * 1000.0; + multiplier += 2, mclk = multiplier * 24 * 1000.0) { + for (divider = 1; divider <= 3; divider += 2) { + for (shift = 0; shift < 8; shift++) { + diff = (mclk / (divider << shift)) - clock; + if (fabs(diff) < best) { + *x1_shift = shift; + *x1_divider = divider == 1 ? 0 : 1; + *x1_select = mclk == 12 * 24 * 1000.0 ? 0 : 1; + + /* Remember best diff */ + best = fabs(diff); + } + } + } + } + + xf86ErrorFVerb(VERBLEV, + "\tMatching clock %5.2f, diff %5.2f (%d/%d/%d)\n", + ((*x1_select ? 14 : 12) * 24 * 1000.0) / + ((*x1_divider == 0 ? 1 : 3) << *x1_shift), + best, *x1_shift, *x1_divider, *x1_select); + + return (best); +} + + +double SMI501_FindPLLClock(double clock, int32_t *m, int32_t *n, int32_t *xclck) { int32_t M, N, K; diff --git a/src/smi_501.h b/src/smi_501.h index c79b75c..378a99a 100644 --- a/src/smi_501.h +++ b/src/smi_501.h @@ -1011,6 +1011,8 @@ void SMI501_PrintRegs(ScrnInfoPtr pScrn); double SMI501_FindClock(double clock, int max_divider, Bool has1xclck, int32_t *x2_1xclck, int32_t *x2_select, int32_t *x2_divider, int32_t *x2_shift); +double SMI501_FindMemClock(double clock, int32_t *x1_select, + int32_t *x1_divider, int32_t *x1_shift); double SMI501_FindPLLClock(double clock, int32_t *m, int32_t *n, int32_t *xclck); void SMI501_WaitVSync(SMIPtr pSmi, int vsync_count); diff --git a/src/smi_driver.c b/src/smi_driver.c index e251448..b36fc7f 100644 --- a/src/smi_driver.c +++ b/src/smi_driver.c @@ -150,6 +150,7 @@ typedef enum OPTION_PCI_RETRY, OPTION_NOACCEL, OPTION_MCLK, + OPTION_MXCLK, OPTION_SWCURSOR, OPTION_HWCURSOR, OPTION_VIDEOKEY, @@ -171,7 +172,8 @@ static const OptionInfoRec SMIOptions[] = { OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN, {0}, TRUE }, { OPTION_PCI_RETRY, "pci_retry", OPTV_BOOLEAN, {0}, TRUE }, { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_MCLK, "set_mclk", OPTV_FREQ, {0}, FALSE }, + { OPTION_MCLK, "MCLK", OPTV_FREQ, {0}, FALSE }, + { OPTION_MXCLK, "MXCLK", OPTV_FREQ, {0}, FALSE }, { OPTION_HWCURSOR, "HWCursor", OPTV_BOOLEAN, {0}, TRUE }, { OPTION_SWCURSOR, "SWCursor", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_VIDEOKEY, "VideoKey", OPTV_INTEGER, {0}, FALSE }, @@ -1194,12 +1196,12 @@ SMI_DetectPanelSize(ScrnInfoPtr pScrn) static void SMI_DetectMCLK(ScrnInfoPtr pScrn) { - double real; - int mclk; - SMIPtr pSmi = SMIPTR(pScrn); - - pSmi->MCLK = 0; + double real; + MSOCClockRec clock; + int mclk, mxclk; + SMIPtr pSmi = SMIPTR(pScrn); + pSmi->MCLK = pSmi->MXCLK = 0; if (xf86GetOptValFreq(pSmi->Options, OPTION_MCLK, OPTUNITS_MHZ, &real)) { pSmi->MCLK = (int)(real * 1000.0); if (!IS_MSOC(pSmi) && pSmi->MCLK > 120000) { @@ -1211,17 +1213,17 @@ SMI_DetectMCLK(ScrnInfoPtr pScrn) } mclk = pSmi->MCLK; + if (IS_MSOC(pSmi)) { + clock.value = READ_SCR(pSmi, CURRENT_CLOCK); + if (xf86GetOptValFreq(pSmi->Options, OPTION_MXCLK, OPTUNITS_MHZ, &real)) + pSmi->MXCLK = (int)(real * 1000.0); + mxclk = pSmi->MXCLK; + } + if (pSmi->MCLK == 0) { - if (IS_MSOC(pSmi)) { - int clock, shift, divider; - - /* FIXME this should just read smi_501.h's bitfields... */ - clock = READ_SCR(pSmi, CURRENT_CLOCK); - shift = clock & ((1 << 3) - 1); - divider = (clock >> 3) & 1 ? 3 : 1; - clock = clock & (1 << 4) ? 336 : 288; - mclk = (clock / (divider << shift)) * 1000; - } + if (IS_MSOC(pSmi)) + mclk = (clock.f.m_select ? 336 : 288) / + ((clock.f.m_divider ? 3 : 1) << (unsigned)clock.f.m_shift); else { unsigned char shift, m, n; @@ -1243,8 +1245,14 @@ SMI_DetectMCLK(ScrnInfoPtr pScrn) } } - /* FIXME Don't actually set pSmi->MCLK */ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MCLK = %1.3f\n", mclk / 1000.0); + if (IS_MSOC(pSmi)) { + if (pSmi->MXCLK == 0) + mxclk = (clock.f.m1_select ? 336 : 288) / + ((clock.f.m1_divider ? 3 : 1) << (unsigned)clock.f.m1_shift); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MXCLK = %1.3f\n", + mxclk / 1000.0); + } } static Bool |