summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/smi.h1
-rw-r--r--src/smi_501.c94
-rw-r--r--src/smi_driver.c12
3 files changed, 77 insertions, 30 deletions
diff --git a/src/smi.h b/src/smi.h
index cdd12d8..11bb060 100644
--- a/src/smi.h
+++ b/src/smi.h
@@ -266,6 +266,7 @@ typedef struct
EntityInfoPtr pEnt;
Bool IsSwitching; /* when switching modes */
+ Bool UseFBDev;
} SMIRec, *SMIPtr;
diff --git a/src/smi_501.c b/src/smi_501.c
index 53ba0a8..480a48d 100644
--- a/src/smi_501.c
+++ b/src/smi_501.c
@@ -51,6 +51,8 @@ authorization from The XFree86 Project or Silicon Motion.
static void SMI501_ModeSet(ScrnInfoPtr pScrn, MSOCRegPtr mode);
static char *format_integer_base2(int32_t word);
+static int32_t SMI501_FindClock(double clock, Bool lcd, int32_t *x2_select,
+ int32_t *x2_divider, int32_t *x2_shift);
static void SMI501_PrintRegs(ScrnInfoPtr pScrn);
static void SMI501_SetClock(SMIPtr pSmi, int32_t port,
int32_t pll, int32_t value);
@@ -223,14 +225,30 @@ SMI501_DisplayPowerManagementSet(ScrnInfoPtr pScrn,
}
}
+static double
+xf86ModeBandwidth(DisplayModePtr mode, int depth)
+{
+ float a_active, a_total, active_percent, pixels_per_second;
+ int bytes_per_pixel = (depth + 7) / 8;
+
+ if (!mode->HTotal || !mode->VTotal || !mode->Clock)
+ return 0.0;
+
+ a_active = mode->HDisplay * mode->VDisplay;
+ a_total = mode->HTotal * mode->VTotal;
+ active_percent = a_active / a_total;
+ pixels_per_second = active_percent * mode->Clock * 1000.0;
+
+ return ((double)(pixels_per_second * bytes_per_pixel));
+}
+
Bool
SMI501_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr xf86mode)
{
MSOCRegPtr save;
MSOCRegPtr mode;
SMIPtr pSmi = SMIPTR(pScrn);
- double mclk;
- int diff, best, divider, shift, x2_divider, x2_shift;
+ int32_t x2_select, x2_divider, x2_shift;
save = pSmi->save;
mode = pSmi->mode;
@@ -250,6 +268,9 @@ SMI501_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr xf86mode)
/* Start with a fresh copy of registers before any mode change */
memcpy(mode, save, sizeof(MSOCRegRec));
+ if (pSmi->UseFBDev)
+ return (TRUE);
+
/* Enable DAC -- 0: enable - 1: disable */
field(mode->misc_ctl, dac) = 0;
@@ -295,30 +316,12 @@ SMI501_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr xf86mode)
break;
}
- /* Find clock best matching mode */
- best = 0x7fffffff;
- for (mclk = 288000.0; mclk <= 336000.0; mclk += 48000.0) {
- for (divider = 1; divider <= (pSmi->lcd ? 5 : 3); divider += 2) {
- /* Start at 1 to match division by 2 */
- for (shift = 1; shift <= 8; shift++) {
- /* Shift starts at 1 to add a division by two, matching
- * description of P2XCLK and V2XCLK. */
- diff = (mclk / (divider << shift)) - xf86mode->Clock;
- if (diff < 0)
- diff = -diff;
- if (diff < best) {
- x2_shift = shift - 1;
- x2_divider = divider == 1 ? 0 : divider == 3 ? 1 : 2;
-
- /* Remember best diff */
- best = diff;
- }
- }
- }
- }
+ (void)SMI501_FindClock(xf86ModeBandwidth(xf86mode, pScrn->depth),
+ pSmi->lcd,
+ &x2_select, &x2_divider, &x2_shift);
if (pSmi->lcd) {
- field(mode->clock, p2_select) = mclk == 288000.0 ? 0 : 1;
+ field(mode->clock, p2_select) = x2_select;
field(mode->clock, p2_divider) = x2_divider;
field(mode->clock, p2_shift) = x2_shift;
@@ -371,7 +374,7 @@ SMI501_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr xf86mode)
xf86mode->VSyncStart;
}
else {
- field(mode->clock, v2_select) = mclk == 288000.0 ? 0 : 1;
+ field(mode->clock, v2_select) = x2_select;
field(mode->clock, v2_divider) = x2_divider;
field(mode->clock, v2_shift) = x2_shift;
@@ -384,12 +387,12 @@ SMI501_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr xf86mode)
field(mode->crt_display_ctl, enable) = 1;
/* FIXME if non clone dual head, and secondary, need to
- * properly set crt fb address properly ... */
+ * properly set crt fb address ... */
field(mode->crt_fb_address, address) = 0;
field(mode->crt_fb_address, mextern) = 0; /* local memory */
field(mode->crt_fb_address, pending) = 0; /* FIXME required? */
- /* >> 4 because of the "unused fields" that should be set to 0 */
+ /* >> 4 because of the "unused bits" that should be set to 0 */
/* FIXME this should be used for virtual size? */
field(mode->crt_fb_width, offset) = pSmi->Stride >> 4;
field(mode->crt_fb_width, width) = pSmi->Stride >> 4;
@@ -434,7 +437,6 @@ SMI501_ModeSet(ScrnInfoPtr pScrn, MSOCRegPtr mode)
/* Update gate first */
WRITE_SCR(pSmi, mode->current_gate, mode->gate.value);
- /* Start with current value */
clock.value = READ_SCR(pSmi, mode->current_clock);
field(clock, m_select) = field(mode->clock, m_select);
@@ -556,6 +558,40 @@ format_integer_base2(int32_t word)
return (buffer);
}
+static int32_t
+SMI501_FindClock(double clock, Bool lcd,
+ int32_t *x2_select, int32_t *x2_divider, int32_t *x2_shift)
+{
+ double mclk;
+ int32_t diff, best, divider, shift;
+
+ /* Find clock best matching mode */
+ best = 0x7fffffff;
+ for (mclk = 288000.0; mclk <= 336000.0; mclk += 48000.0) {
+ for (divider = 1; divider <= (lcd ? 5 : 3); divider += 2) {
+ /* Start at 1 to match division by 2 */
+ for (shift = 1; shift <= 8; shift++) {
+ /* Shift starts at 1 to add a division by two, matching
+ * description of P2XCLK and V2XCLK. */
+ diff = (mclk / (divider << shift)) - clock;
+ if (diff < 0)
+ diff = -diff;
+ if (diff < best) {
+ *x2_shift = shift - 1;
+ *x2_divider = divider == 1 ? 0 : divider == 3 ? 1 : 2;
+
+ /* Remember best diff */
+ best = diff;
+ }
+ }
+ }
+ }
+
+ *x2_select = mclk == 288000.0 ? 0 : 1;
+
+ return (diff);
+}
+
static void
SMI501_PrintRegs(ScrnInfoPtr pScrn)
{
@@ -626,6 +662,6 @@ SMI501_SetClock(SMIPtr pSmi, int32_t port, int32_t pll, int32_t value)
SMI501_WaitVSync(pSmi, 1);
/* full register contents */
- WRITE_SCR(pSmi, port, pll);
+ WRITE_SCR(pSmi, port, value);
SMI501_WaitVSync(pSmi, 1);
}
diff --git a/src/smi_driver.c b/src/smi_driver.c
index fe48c8a..507e6c7 100644
--- a/src/smi_driver.c
+++ b/src/smi_driver.c
@@ -179,6 +179,7 @@ typedef enum
OPTION_ACCELMETHOD,
OPTION_RANDRROTATION,
OPTION_PANEL_SIZE,
+ OPTION_USE_FBDEV,
NUMBER_OF_OPTIONS
} SMIOpts;
@@ -206,7 +207,8 @@ static const OptionInfoRec SMIOptions[] =
{ OPTION_DUALHEAD, "Dualhead", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_ACCELMETHOD, "AccelMethod", OPTV_STRING, {0}, FALSE },
{ OPTION_RANDRROTATION, "RandRRotation", OPTV_BOOLEAN, {0}, FALSE },
- { OPTION_PANEL_SIZE, "PanelSize", OPTV_ANYSTR, {0}, FALSE },
+ { OPTION_PANEL_SIZE, "PanelSize", OPTV_ANYSTR, {0}, FALSE },
+ { OPTION_USE_FBDEV, "UseFBDev", OPTV_BOOLEAN, {0}, FALSE },
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};
@@ -728,6 +730,14 @@ SMI_PreInit(ScrnInfoPtr pScrn, int flags)
pSmi->randrRotation ? "enabled" : "disabled");
}
+ if (IS_MSOC(pSmi)) {
+ from = X_DEFAULT;
+ if (xf86GetOptValBool(pSmi->Options, OPTION_USE_FBDEV, &pSmi->UseFBDev))
+ from = X_CONFIG;
+ xf86DrvMsg(pScrn->scrnIndex, from, "UseFBDev %s.\n",
+ pSmi->UseFBDev ? "enabled" : "disabled");
+ }
+
from = X_CONFIG;
pSmi->HwCursor = TRUE;
/* SWCursor overrides HWCusor if both specified */