summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/smi.h1
-rw-r--r--src/smi_501.c112
-rw-r--r--src/smi_501.h2
-rw-r--r--src/smi_driver.c42
4 files changed, 98 insertions, 59 deletions
diff --git a/src/smi.h b/src/smi.h
index 05332f7..5305e54 100644
--- a/src/smi.h
+++ b/src/smi.h
@@ -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