summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaulo Cesar Pereira de Andrade <pcpa@mandriva.com.br>2008-09-24 18:58:35 -0300
committerPaulo Cesar Pereira de Andrade <pcpa@mandriva.com.br>2008-09-24 18:58:35 -0300
commitbdba7c1397186cd15d519db55c2345db44990be4 (patch)
tree2de96c04aa4d32cbbc9cc82cf2f6cf783288f843
parente64b3d63be2a4148c4d10ac160e2bd2f3e8c7fd3 (diff)
Fix incorrect understanding of the pixel clock from specs.
The clock that should be programmed is the bandwidth, and not the pixel clock itself. Based on analysis of register contents, after "importing" a slightly modified version of xf86ModeBandwidth() and properly converting values, now it properly programs both, the LCD and a "clone" CRT or just a secondary panel. Modes generated by either gtf or cvt correctly works. A (hopefully temporary) fallback was also added, and if the option "UseFBDev" is used, the driver will not attempt to set/modify the current video mode. TODO: Generate a modeline "on the fly", based on monitor configured specs, or some set of defaults, so that it should not be required to specify a modeline in xorg.conf.
-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 */