Merge branch 'modesetting-origin' into modesetting

This commit is contained in:
Eric Anholt 2006-06-20 15:10:35 -07:00
commit 896ffe78fe
11 changed files with 586 additions and 30 deletions

View File

@ -728,6 +728,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# define SDVO_MULTIPLIER_MASK 0x000000ff
# define SDVO_DEFAULT_MULTIPLIER 0x00000003
#define BLC_PWM_CTL 0x61254
#define BACKLIGHT_MODULATION_FREQ_SHIFT (17)
#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17)
#define BLM_LEGACY_MODE (1 << 16)
#define BACKLIGHT_DUTY_CYCLE_SHIFT (0)
#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff)
#define FPA0 0x06040
#define FPA1 0x06044
#define FPB0 0x06048
@ -752,6 +759,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# define CRT_HOTPLUG_MONITOR_NONE (0 << 8)
# define SDVOC_HOTPLUG_INT_STATUS (1 << 7)
# define SDVOB_HOTPLUG_INT_STATUS (1 << 6)
#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14))
#define SDVOB 0x61140
#define SDVOC 0x61160
@ -769,7 +777,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SDVOB_PCIE_CONCURRENCY (1 << 3)
#define SDVO_DETECTED (1 << 2)
/* Bits to be preserved when writing */
#define SDVO_PRESERVE_MASK (1 << 17)
#define SDVOC_PRESERVE_MASK (1 << 17)
#define I830_HTOTAL_MASK 0xfff0000
#define I830_HACTIVE_MASK 0x7ff

View File

@ -419,6 +419,7 @@ typedef struct _I830Rec {
Bool devicePresence;
OsTimerPtr devicesTimer;
int MaxClock;
int ddc2;
int num_outputs;
@ -439,6 +440,8 @@ typedef struct _I830Rec {
int panel_fixed_vsyncoff;
int panel_fixed_vsyncwidth;
int backlight_duty_cycle; /* restore backlight to this value */
Bool panel_wants_dither;
unsigned char *VBIOS;
@ -492,6 +495,7 @@ typedef struct _I830Rec {
CARD32 savePaletteA[256];
CARD32 savePaletteB[256];
CARD32 saveSWF[17];
CARD32 saveBLC_PWM_CTL;
} I830Rec;
#define I830PTR(p) ((I830Ptr)((p)->driverPrivate))
@ -542,6 +546,7 @@ extern void I830DRIUnmapScreenRegions(ScrnInfoPtr pScrn, drmI830Sarea *sarea);
extern Bool I830DRIMapScreenRegions(ScrnInfoPtr pScrn, drmI830Sarea *sarea);
extern void I830DRIUnlock(ScrnInfoPtr pScrn);
extern Bool I830DRILock(ScrnInfoPtr pScrn);
extern Bool I830DRISetVBlankInterrupt (ScrnInfoPtr pScrn, Bool on);
#endif
extern Bool I830AccelInit(ScreenPtr pScreen);
@ -588,6 +593,7 @@ extern Rotation I830GetRotation(ScreenPtr pScreen);
extern Bool I830RandRInit(ScreenPtr pScreen, int rotation);
extern Bool I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg,
char *name);
int I830xf86ValidateDDCModes(ScrnInfoPtr pScrn1, char **ppModeName);
/*
* 12288 is set as the maximum, chosen because it is enough for

View File

@ -52,6 +52,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#define DRM_I830_INIT_HEAP 0x0a
#define DRM_I830_CMDBUFFER 0x0b
#define DRM_I830_DESTROY_HEAP 0x0c
#define DRM_I830_SET_VBLANK_PIPE 0x0d
#define DRM_I830_GET_VBLANK_PIPE 0x0e
typedef struct {
enum {
@ -193,5 +196,11 @@ typedef struct {
int region;
} drmI830MemDestroyHeap;
#define DRM_I830_VBLANK_PIPE_A 1
#define DRM_I830_VBLANK_PIPE_B 2
typedef struct {
int pipe;
} drmI830VBlankPipe;
#endif /* _I830_DRM_H_ */

View File

@ -35,7 +35,7 @@
/* XXX: What was the syntax for sticking quotes around the "reg" argument? */
#define DEFINEREG(reg) \
{ reg, NULL, 0 }
{ reg, #reg, 0 }
static struct i830SnapshotRec {
int reg;
@ -129,3 +129,14 @@ void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn)
}
}
}
void i830DumpRegs (ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
int i;
for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) {
xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "%10.10s: 0x%08x\n",
i830_snapshot[i].name, (unsigned int) INREG(i830_snapshot[i].reg));
}
}

View File

@ -27,3 +27,4 @@
void i830TakeRegSnapshot(ScrnInfoPtr pScrn);
void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn);
void i830DumpRegs (ScrnInfoPtr pScrn);

View File

@ -34,6 +34,7 @@
#include "i830.h"
#include "i830_bios.h"
#include "i830_display.h"
#include "i830_debug.h"
/** Returns the pixel clock for the given refclk and divisors. */
static int i830_clock(int refclk, int m1, int m2, int n, int p1, int p2)
@ -255,7 +256,8 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
int m1 = 0, m2 = 0, n = 0, p1 = 0, p2 = 0;
CARD32 dpll = 0, fp = 0, temp;
CARD32 htot, hblank, hsync, vtot, vblank, vsync, dspcntr;
CARD32 pipesrc, dspsize, adpa, sdvoc = 0;
CARD32 pipesrc, dspsize, adpa;
CARD32 sdvob = 0, sdvoc= 0;
Bool ok, is_sdvo;
int refclk, pixel_clock;
int outputs;
@ -391,13 +393,14 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
ErrorF("DVOB: %08x\nDVOC: %08x\n", (int)INREG(SDVOB), (int)INREG(SDVOC));
sdvoc = INREG(SDVOC) & SDVO_PRESERVE_MASK;
sdvoc |= SDVO_ENABLE;
sdvob = INREG(SDVOB) & SDVOB_PRESERVE_MASK;
sdvoc = INREG(SDVOC) & SDVOC_PRESERVE_MASK;
sdvob |= SDVO_ENABLE | (9 << 19) | SDVO_BORDER_ENABLE;
sdvoc |= 9 << 19;
if (pipe == 1)
sdvoc |= SDVO_PIPE_B_SELECT;
// sdvoc |= SDVO_PHASE_SELECT_DEFAULT;
sdvoc |= SDVO_BORDER_ENABLE;
sdvob |= SDVO_PIPE_B_SELECT;
OUTREG(SDVOC, INREG(SDVOC) & ~SDVO_ENABLE);
OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE);
}
fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2);
@ -437,7 +440,10 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
FatalError("unknown display bpp\n");
}
adpa = ADPA_DAC_ENABLE;
if (is_sdvo)
adpa = ADPA_DAC_DISABLE;
else
adpa = ADPA_DAC_ENABLE;
if (pMode->Flags & V_PHSYNC)
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
if (pMode->Flags & V_PVSYNC)
@ -469,9 +475,6 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
OUTREG(FPA0, fp);
OUTREG(DPLL_A, dpll);
if (is_sdvo)
OUTREG(SDVOC, sdvoc);
OUTREG(HTOTAL_A, htot);
OUTREG(HBLANK_A, hblank);
OUTREG(HSYNC_A, hsync);
@ -490,6 +493,11 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
/* And then turn the plane on */
OUTREG(DSPACNTR, dspcntr);
if (is_sdvo) {
OUTREG(SDVOB, sdvob);
OUTREG(SDVOC, sdvoc);
}
} else {
/* Always make sure the LVDS is off before we play with DPLLs and pipe
* configuration.
@ -634,12 +642,17 @@ i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
pI830->planeEnabled[1] ? "enabled" : "disabled",
planeB & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A");
#ifdef XF86DRI
I830DRISetVBlankInterrupt (pScrn, TRUE);
#endif
done:
#ifdef XF86DRI
if (didLock)
I830DRIUnlock(pScrn);
#endif
i830DumpRegs (pScrn);
I830DumpSDVO (pScrn);
return ok;
}
@ -798,7 +811,14 @@ i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on)
{
I830Ptr pI830 = I830PTR(pScrn);
CARD32 pp_status, pp_control;
CARD32 blc_pwm_ctl;
int backlight_duty_cycle;
blc_pwm_ctl = INREG (BLC_PWM_CTL);
backlight_duty_cycle = blc_pwm_ctl & BACKLIGHT_DUTY_CYCLE_MASK;
if (backlight_duty_cycle)
pI830->backlight_duty_cycle = backlight_duty_cycle;
if (on) {
OUTREG(PP_STATUS, INREG(PP_STATUS) | PP_ON);
OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON);
@ -806,7 +826,13 @@ i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on)
pp_status = INREG(PP_STATUS);
pp_control = INREG(PP_CONTROL);
} while (!(pp_status & PP_ON) && !(pp_control & POWER_TARGET_ON));
OUTREG(BLC_PWM_CTL,
(blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK) |
pI830->backlight_duty_cycle);
} else {
OUTREG(BLC_PWM_CTL,
(blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK));
OUTREG(PP_STATUS, INREG(PP_STATUS) & ~PP_ON);
OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON);
do {

View File

@ -1448,6 +1448,31 @@ I830UpdateDRIBuffers(ScrnInfoPtr pScrn, drmI830Sarea *sarea)
return success;
}
Bool
I830DRISetVBlankInterrupt (ScrnInfoPtr pScrn, Bool on)
{
I830Ptr pI830 = I830PTR(pScrn);
drmI830VBlankPipe pipe;
if (pI830->directRenderingEnabled && pI830->drmMinor >= 5) {
if (on) {
if (pI830->planeEnabled[1])
pipe.pipe = DRM_I830_VBLANK_PIPE_B;
else
pipe.pipe = DRM_I830_VBLANK_PIPE_A;
} else {
pipe.pipe = 0;
}
if (drmCommandWrite(pI830->drmSubFD, DRM_I830_SET_VBLANK_PIPE,
&pipe, sizeof (pipe))) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I830 Vblank Pipe Setup Failed\n");
return FALSE;
}
}
return TRUE;
}
Bool
I830DRILock(ScrnInfoPtr pScrn)
{

View File

@ -2358,14 +2358,17 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"Maximum space available for video modes: %d kByte\n", memsize);
pI830->MaxClock = 300000;
/*
* Setup the ClockRanges, which describe what clock ranges are available,
* and what sort of modes they can be used for.
*/
clockRanges = xnfcalloc(sizeof(ClockRange), 1);
clockRanges->next = NULL;
clockRanges->minClock = 12000; /* XXX: Random number */
clockRanges->maxClock = 400000; /* XXX: May be lower */
/* 25MHz appears to be the smallest that works. */
clockRanges->minClock = 25000;
clockRanges->maxClock = pI830->MaxClock;
clockRanges->clockIndex = -1; /* programmable */
clockRanges->interlaceAllowed = TRUE; /* XXX check this */
clockRanges->doubleScanAllowed = FALSE; /* XXX check this */
@ -2384,16 +2387,17 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
}
n = i830ValidateFPModes(pScrn, pScrn->display->modes);
} else {
I830xf86ValidateDDCModes(pScrn, pScrn->display->modes);
/* XXX minPitch, minHeight are random numbers. */
n = xf86ValidateModes(pScrn,
pScrn->monitor->Modes, /* availModes */
pScrn->display->modes, /* modeNames */
clockRanges, /* clockRanges */
NULL, /* linePitches */
256, /* minPitch */
320, /* minPitch */
MAX_DISPLAY_PITCH, /* maxPitch */
64, /* pitchInc */
pScrn->bitsPerPixel, /* minHeight */
64 * pScrn->bitsPerPixel, /* pitchInc */
200, /* minHeight */
MAX_DISPLAY_HEIGHT, /* maxHeight */
pScrn->display->virtualX, /* virtualX */
pScrn->display->virtualY, /* virtualY */
@ -2416,6 +2420,24 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
/*
* Fix up modes to make hblank start at hsync start.
* I don't know why the xf86 code mangles this...
*/
{
DisplayModePtr p;
for (p = pScrn->modes; p;) {
xf86DrvMsg (pScrn->scrnIndex,
X_INFO, "move blank start from %d to %d\n",
p->CrtcHBlankStart, p->CrtcHDisplay);
p->CrtcHBlankStart = p->CrtcHDisplay;
p = p->next;
if (p == pScrn->modes)
break;
}
}
pScrn->currentMode = pScrn->modes;
#ifndef USE_PITCHES
@ -2897,6 +2919,17 @@ SaveHWState(ScrnInfoPtr pScrn)
pI830->saveLVDS = INREG(LVDS);
pI830->savePP_CONTROL = INREG(PP_CONTROL);
pI830->savePP_CYCLE = INREG(PP_CYCLE);
pI830->saveBLC_PWM_CTL = INREG(BLC_PWM_CTL);
pI830->backlight_duty_cycle = (pI830->saveBLC_PWM_CTL &
BACKLIGHT_DUTY_CYCLE_MASK);
/*
* If the light is off at server startup, just make it full brightness
*/
if (!pI830->backlight_duty_cycle)
pI830->backlight_duty_cycle = ((pI830->saveBLC_PWM_CTL &
BACKLIGHT_MODULATION_FREQ_MASK) >>
BACKLIGHT_MODULATION_FREQ_SHIFT);
if (!IS_I9XX(pI830)) {
pI830->saveDVOA = INREG(DVOA);
@ -2937,6 +2970,9 @@ RestoreHWState(ScrnInfoPtr pScrn)
DPRINTF(PFX, "RestoreHWState\n");
#ifdef XF86DRI
I830DRISetVBlankInterrupt (pScrn, FALSE);
#endif
vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
vgaHWLock(hwp);
@ -3003,6 +3039,7 @@ RestoreHWState(ScrnInfoPtr pScrn)
}
}
OUTREG(BLC_PWM_CTL, pI830->saveBLC_PWM_CTL);
OUTREG(LVDSPP_ON, pI830->savePP_ON);
OUTREG(LVDSPP_OFF, pI830->savePP_OFF);
OUTREG(PP_CYCLE, pI830->savePP_CYCLE);

View File

@ -44,6 +44,52 @@
#include "xf86.h"
#include "i830.h"
#include <math.h>
#define rint(x) floor(x)
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MARGIN_PERCENT 1.8 /* % of active vertical image */
#define CELL_GRAN 8.0 /* assumed character cell granularity */
#define MIN_PORCH 1 /* minimum front porch */
#define V_SYNC_RQD 3 /* width of vsync in lines */
#define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */
#define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
#define M 600.0 /* blanking formula gradient */
#define C 40.0 /* blanking formula offset */
#define K 128.0 /* blanking formula scaling factor */
#define J 20.0 /* blanking formula scaling factor */
/* C' and M' are part of the Blanking Duty Cycle computation */
#define C_PRIME (((C - J) * K/256.0) + J)
#define M_PRIME (K/256.0 * M)
/* Established timings from EDID standard */
static struct
{
int hsize;
int vsize;
int refresh;
} est_timings[] = {
{1280, 1024, 75},
{1024, 768, 75},
{1024, 768, 70},
{1024, 768, 60},
{1024, 768, 87},
{832, 624, 75},
{800, 600, 75},
{800, 600, 72},
{800, 600, 60},
{800, 600, 56},
{640, 480, 75},
{640, 480, 72},
{640, 480, 67},
{640, 480, 60},
{720, 400, 88},
{720, 400, 70},
};
extern const int i830refreshes[];
void
@ -108,3 +154,323 @@ I830PrintModes(ScrnInfoPtr scrp)
p = p->next;
} while (p != NULL && p != scrp->modes);
}
/* This function will sort all modes according to their resolution.
* Highest resolution first.
*/
void
I830xf86SortModes(DisplayModePtr *new, DisplayModePtr *first,
DisplayModePtr *last)
{
DisplayModePtr p;
p = *last;
while (p) {
if ((((*new)->HDisplay < p->HDisplay) &&
((*new)->VDisplay < p->VDisplay)) ||
(((*new)->HDisplay == p->HDisplay) &&
((*new)->VDisplay == p->VDisplay) &&
((*new)->Clock < p->Clock))) {
if (p->next) p->next->prev = *new;
(*new)->prev = p;
(*new)->next = p->next;
p->next = *new;
if (!((*new)->next)) *last = *new;
break;
}
if (!p->prev) {
(*new)->prev = NULL;
(*new)->next = p;
p->prev = *new;
*first = *new;
break;
}
p = p->prev;
}
if (!*first) {
*first = *new;
(*new)->prev = NULL;
(*new)->next = NULL;
*last = *new;
}
}
DisplayModePtr I830xf86DDCModes(ScrnInfoPtr pScrn)
{
DisplayModePtr p;
DisplayModePtr last = NULL;
DisplayModePtr new = NULL;
DisplayModePtr first = NULL;
int count = 0;
int j, tmp;
char stmp[32];
xf86MonPtr ddc = pScrn->monitor->DDC;
/* Go thru detailed timing table first */
for (j = 0; j < 4; j++) {
if (ddc->det_mon[j].type == 0) {
struct detailed_timings *d_timings =
&ddc->det_mon[j].section.d_timings;
if (d_timings->h_active == 0 || d_timings->v_active == 0) break;
new = xnfcalloc(1, sizeof (DisplayModeRec));
memset(new, 0, sizeof (DisplayModeRec));
new->HDisplay = d_timings->h_active;
new->VDisplay = d_timings->v_active;
sprintf(stmp, "%dx%d", new->HDisplay, new->VDisplay);
new->name = xnfalloc(strlen(stmp) + 1);
strcpy(new->name, stmp);
new->HTotal = new->HDisplay + d_timings->h_blanking;
new->HSyncStart = new->HDisplay + d_timings->h_sync_off;
new->HSyncEnd = new->HSyncStart + d_timings->h_sync_width;
new->VTotal = new->VDisplay + d_timings->v_blanking;
new->VSyncStart = new->VDisplay + d_timings->v_sync_off;
new->VSyncEnd = new->VSyncStart + d_timings->v_sync_width;
new->Clock = d_timings->clock / 1000;
new->Flags = (d_timings->interlaced ? V_INTERLACE : 0);
new->status = MODE_OK;
new->type = M_T_DEFAULT;
if (d_timings->sync == 3) {
switch (d_timings->misc) {
case 0: new->Flags |= V_NHSYNC | V_NVSYNC; break;
case 1: new->Flags |= V_PHSYNC | V_NVSYNC; break;
case 2: new->Flags |= V_NHSYNC | V_PVSYNC; break;
case 3: new->Flags |= V_PHSYNC | V_PVSYNC; break;
}
}
count++;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Valid Mode from Detailed timing table: %s (ht %d hss %d hse %d vt %d vss %d vse %d)\n",
new->name,
new->HTotal, new->HSyncStart, new->HSyncEnd,
new->VTotal, new->VSyncStart, new->VSyncEnd);
I830xf86SortModes(&new, &first, &last);
}
}
/* Search thru standard VESA modes from EDID */
for (j = 0; j < 8; j++) {
if (ddc->timings2[j].hsize == 0 || ddc->timings2[j].vsize == 0)
continue;
for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) {
/* Ignore all double scan modes */
if ((ddc->timings2[j].hsize == p->HDisplay) &&
(ddc->timings2[j].vsize == p->VDisplay)) {
float refresh =
(float)p->Clock * 1000.0 / p->HTotal / p->VTotal;
float err = (float)ddc->timings2[j].refresh - refresh;
if (err < 0) err = -err;
if (err < 1.0) {
/* Is this good enough? */
new = xnfcalloc(1, sizeof (DisplayModeRec));
memcpy(new, p, sizeof(DisplayModeRec));
new->name = xnfalloc(strlen(p->name) + 1);
strcpy(new->name, p->name);
new->status = MODE_OK;
new->type = M_T_DEFAULT;
count++;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Valid Mode from standard timing table: %s\n",
new->name);
I830xf86SortModes(&new, &first, &last);
break;
}
}
}
}
/* Search thru established modes from EDID */
tmp = (ddc->timings1.t1 << 8) | ddc->timings1.t2;
for (j = 0; j < 16; j++) {
if (tmp & (1 << j)) {
for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) {
if ((est_timings[j].hsize == p->HDisplay) &&
(est_timings[j].vsize == p->VDisplay)) {
float refresh =
(float)p->Clock * 1000.0 / p->HTotal / p->VTotal;
float err = (float)est_timings[j].refresh - refresh;
if (err < 1.0) {
/* Is this good enough? */
new = xnfcalloc(1, sizeof (DisplayModeRec));
memcpy(new, p, sizeof(DisplayModeRec));
new->name = xnfalloc(strlen(p->name) + 1);
strcpy(new->name, p->name);
new->status = MODE_OK;
new->type = M_T_DEFAULT;
count++;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Valid Mode from established timing "
"table: %s\n", new->name);
I830xf86SortModes(&new, &first, &last);
break;
}
}
}
}
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Total of %d mode(s) found.\n", count);
return first;
}
/* XFree86's xf86ValidateModes routine doesn't work well with DDC modes,
* so here is our own validation routine.
*/
int I830xf86ValidateDDCModes(ScrnInfoPtr pScrn1, char **ppModeName)
{
DisplayModePtr p;
DisplayModePtr last = NULL;
DisplayModePtr first = NULL;
DisplayModePtr ddcModes = NULL;
int count = 0;
int i, width, height;
ScrnInfoPtr pScrn = pScrn1;
pScrn->virtualX = pScrn1->display->virtualX;
pScrn->virtualY = pScrn1->display->virtualY;
if (pScrn->monitor->DDC) {
int maxVirtX = pScrn->virtualX;
int maxVirtY = pScrn->virtualY;
/* Collect all of the DDC modes */
first = last = ddcModes = I830xf86DDCModes(pScrn);
for (p = ddcModes; p; p = p->next) {
maxVirtX = MAX(maxVirtX, p->HDisplay);
maxVirtY = MAX(maxVirtY, p->VDisplay);
count++;
last = p;
}
/* Match up modes that are specified in the XF86Config file */
if (ppModeName[0]) {
DisplayModePtr next;
/* Reset the max virtual dimensions */
maxVirtX = pScrn->virtualX;
maxVirtY = pScrn->virtualY;
/* Reset list */
first = last = NULL;
for (i = 0; ppModeName[i]; i++) {
/* FIXME: Use HDisplay and VDisplay instead of mode string */
if (sscanf(ppModeName[i], "%dx%d", &width, &height) == 2) {
for (p = ddcModes; p; p = next) {
next = p->next;
if (p->HDisplay == width && p->VDisplay == height) {
/* We found a DDC mode that matches the one
requested in the XF86Config file */
p->type |= M_T_USERDEF;
/* Update the max virtual setttings */
maxVirtX = MAX(maxVirtX, width);
maxVirtY = MAX(maxVirtY, height);
/* Unhook from DDC modes */
if (p->prev) p->prev->next = p->next;
if (p->next) p->next->prev = p->prev;
if (p == ddcModes) ddcModes = p->next;
/* Add to used modes */
if (last) {
last->next = p;
p->prev = last;
} else {
first = p;
p->prev = NULL;
}
p->next = NULL;
last = p;
break;
}
}
}
}
/*
* Add remaining DDC modes if they're smaller than the user
* specified modes
*/
for (p = ddcModes; p; p = next) {
next = p->next;
if (p->HDisplay <= maxVirtX && p->VDisplay <= maxVirtY) {
/* Unhook from DDC modes */
if (p->prev) p->prev->next = p->next;
if (p->next) p->next->prev = p->prev;
if (p == ddcModes) ddcModes = p->next;
/* Add to used modes */
if (last) {
last->next = p;
p->prev = last;
} else {
first = p;
p->prev = NULL;
}
p->next = NULL;
last = p;
}
}
/* Delete unused modes */
while (ddcModes)
xf86DeleteMode(&ddcModes, ddcModes);
} else {
/*
* No modes were configured, so we make the DDC modes
* available for the user to cycle through.
*/
for (p = ddcModes; p; p = p->next)
p->type |= M_T_USERDEF;
}
pScrn->virtualX = pScrn->display->virtualX = maxVirtX;
pScrn->virtualY = pScrn->display->virtualY = maxVirtY;
}
/* Close the doubly-linked mode list, if we found any usable modes */
if (last) {
DisplayModePtr temp = NULL;
/* we should add these to pScrn monitor modes */
last->next = pScrn->monitor->Modes;
temp = pScrn->monitor->Modes->prev;
pScrn->monitor->Modes->prev = first;
pScrn->monitor->Modes->prev = last;
first->prev = temp;
if (temp)
temp->next = first;
pScrn->monitor->Modes = first;
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Total number of valid DDC mode(s) found: %d\n", count);
return count;
}

View File

@ -139,7 +139,7 @@ I830SDVOSetTargetInput(I830SDVOPtr s, Bool target_1, Bool target_2)
s->sdvo_regs[SDVO_I2C_ARG_0] = target_1;
s->sdvo_regs[SDVO_I2C_ARG_1] = target_2;
I830SDVOWriteOutputs(s, 1);
I830SDVOWriteOutputs(s, 2);
I830SDVOReadInputRegs(s);
@ -218,7 +218,7 @@ I830SDVOSetTargetOutput(I830SDVOPtr s, Bool target_1, Bool target_2)
s->sdvo_regs[SDVO_I2C_ARG_0] = target_1;
s->sdvo_regs[SDVO_I2C_ARG_1] = target_2;
I830SDVOWriteOutputs(s, 1);
I830SDVOWriteOutputs(s, 2);
I830SDVOReadInputRegs(s);
return TRUE;
@ -259,7 +259,7 @@ I830SDVOGetTimings(I830SDVOPtr s, i830_sdvo_dtd *dtd, CARD8 cmd)
return TRUE;
}
/* Fetches either input or output timings to *dtd, depending on cmd. */
/* Sets either input or output timings to *dtd, depending on cmd. */
Bool
I830SDVOSetTimings(I830SDVOPtr s, i830_sdvo_dtd *dtd, CARD8 cmd)
{
@ -286,7 +286,7 @@ I830SDVOSetTimings(I830SDVOPtr s, i830_sdvo_dtd *dtd, CARD8 cmd)
s->sdvo_regs[SDVO_I2C_ARG_5] = dtd->sdvo_flags;
s->sdvo_regs[SDVO_I2C_ARG_6] = dtd->v_sync_off_high;
s->sdvo_regs[SDVO_I2C_ARG_7] = dtd->reserved;
I830SDVOWriteOutputs(s, 8);
I830SDVOWriteOutputs(s, 7);
I830SDVOReadInputRegs(s);
return TRUE;
@ -477,6 +477,7 @@ I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode)
CARD8 c17a[8];
CARD16 out_timings[6];
CARD16 clock_min, clock_max;
Bool out1, out2;
/* do some mode translations */
h_blank_len = mode->CrtcHBlankEnd - mode->CrtcHBlankStart;
@ -516,30 +517,41 @@ I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode)
out_timings[4] = c17a[5] | ((short)c17a[4] << 8);
out_timings[5] = c17a[3] | ((short)c17a[2] << 8);
I830SDVOSetTargetInput(s, TRUE, TRUE);
I830SDVOSetTargetInput(s, FALSE, FALSE);
I830SDVOGetInputPixelClockRange(s, &clock_min, &clock_max);
ErrorF("clock min/max: %d %d\n", clock_min, clock_max);
I830SDVOGetActiveOutputs(s, &out1, &out2);
I830SDVOSetActiveOutputs(s, FALSE, FALSE);
I830SDVOSetTargetOutput(s, TRUE, TRUE);
I830SDVOSetTargetOutput(s, TRUE, FALSE);
I830SDVOSetOutputTimingsPart1(s, clock, out_timings[0], out_timings[1],
out_timings[2]);
I830SDVOSetOutputTimingsPart2(s, out_timings[3], out_timings[4],
out_timings[5]);
I830SDVOSetTargetInput (s, FALSE, FALSE);
I830SDVOCreatePreferredInputTiming(s, clock, width, height);
I830SDVOGetPreferredInputTimingPart1(s);
I830SDVOGetPreferredInputTimingPart2(s);
I830SDVOSetTargetInput (s, FALSE, FALSE);
I830SDVOSetInputTimingsPart1(s, clock, curr_table[0], curr_table[1],
curr_table[2]);
I830SDVOSetInputTimingsPart2(s, curr_table[3], curr_table[4],
out_timings[5]);
/*if (mode->PrivFlags & I830_MFLAG_DOUBLE)
I830SDVOSetClockRateMult(s, 0x02);
else */
I830SDVOSetClockRateMult(s, 0x01);
I830SDVOSetTargetInput (s, FALSE, FALSE);
if (clock >= 10000)
I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_1X);
else if (clock >= 5000)
I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_2X);
else
I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_4X);
return TRUE;
}
@ -548,6 +560,7 @@ Bool
I830SDVOPostSetMode(I830SDVOPtr s, DisplayModePtr mode)
{
Bool ret = TRUE;
Bool out1, out2;
/* the BIOS writes out 6 commands post mode set */
/* two 03s, 04 05, 10, 1d */
@ -564,7 +577,9 @@ I830SDVOPostSetMode(I830SDVOPtr s, DisplayModePtr mode)
ret = FALSE;
}
I830SDVOSetActiveOutputs(s, TRUE, TRUE);
I830SDVOGetActiveOutputs (s, &out1, &out2);
I830SDVOSetActiveOutputs(s, TRUE, FALSE);
I830SDVOSetTargetInput (s, FALSE, FALSE);
return ret;
}
@ -580,7 +595,7 @@ i830SDVOSave(ScrnInfoPtr pScrn, int output_index)
&sdvo->save_sdvo_active_2);
if (sdvo->caps.caps & 0x1) {
I830SDVOSetTargetInput(sdvo, TRUE, FALSE);
I830SDVOSetTargetInput(sdvo, FALSE, FALSE);
I830SDVOGetTimings(sdvo, &sdvo->save_input_dtd_1,
SDVO_CMD_GET_INPUT_TIMINGS_PART1);
}
@ -622,7 +637,7 @@ i830SDVOPostRestore(ScrnInfoPtr pScrn, int output_index)
I830SDVOPtr sdvo = pI830->output[output_index].sdvo_drv;
if (sdvo->caps.caps & 0x1) {
I830SDVOSetTargetInput(sdvo, TRUE, FALSE);
I830SDVOSetTargetInput(sdvo, FALSE, FALSE);
I830SDVOSetTimings(sdvo, &sdvo->save_input_dtd_1,
SDVO_CMD_SET_INPUT_TIMINGS_PART1);
}
@ -830,3 +845,53 @@ I830SDVOInit(ScrnInfoPtr pScrn, int output_index, CARD32 output_device)
return sdvo;
}
static void
I830DumpSDVOCmd (I830SDVOPtr s, int opcode)
{
memset (s->sdvo_regs, 0, sizeof (s->sdvo_regs));
s->sdvo_regs[SDVO_I2C_OPCODE] = opcode;
I830SDVOWriteOutputs (s, 0);
I830SDVOReadInputRegs (s);
}
static void
I830DumpOneSDVO (I830SDVOPtr s)
{
ErrorF ("Dump %s\n", s->d.DevName);
I830DumpSDVOCmd (s, SDVO_CMD_GET_DEVICE_CAPS);
I830DumpSDVOCmd (s, SDVO_CMD_GET_FIRMWARE_REV);
I830DumpSDVOCmd (s, SDVO_CMD_GET_TRAINED_INPUTS);
I830DumpSDVOCmd (s, SDVO_CMD_GET_ACTIVE_OUTPUTS);
I830DumpSDVOCmd (s, SDVO_CMD_GET_IN_OUT_MAP);
I830DumpSDVOCmd (s, SDVO_CMD_GET_ATTACHED_DISPLAYS);
I830DumpSDVOCmd (s, SDVO_CMD_GET_HOT_PLUG_SUPPORT);
I830DumpSDVOCmd (s, SDVO_CMD_GET_ACTIVE_HOT_PLUG);
I830DumpSDVOCmd (s, SDVO_CMD_GET_INTR_EVENT_SOURCE);
I830DumpSDVOCmd (s, SDVO_CMD_GET_INPUT_TIMINGS_PART1);
I830DumpSDVOCmd (s, SDVO_CMD_GET_INPUT_TIMINGS_PART2);
I830DumpSDVOCmd (s, SDVO_CMD_GET_OUTPUT_TIMINGS_PART1);
I830DumpSDVOCmd (s, SDVO_CMD_GET_OUTPUT_TIMINGS_PART2);
I830DumpSDVOCmd (s, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1);
I830DumpSDVOCmd (s, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2);
I830DumpSDVOCmd (s, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE);
I830DumpSDVOCmd (s, SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE);
I830DumpSDVOCmd (s, SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS);
I830DumpSDVOCmd (s, SDVO_CMD_GET_CLOCK_RATE_MULT);
I830DumpSDVOCmd (s, SDVO_CMD_GET_SUPPORTED_TV_FORMATS);
I830DumpSDVOCmd (s, SDVO_CMD_GET_TV_FORMAT);
}
void
I830DumpSDVO (ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
I830SDVOPtr s;
int i;
for (i = 0; i < 4; i++) {
s = pI830->output[i].sdvo_drv;
if (s)
I830DumpOneSDVO (s);
}
}

View File

@ -157,7 +157,9 @@
#define SDVO_CMD_SET_CLOCK_RATE_MULT 0x21
# define SDVO_CLOCK_RATE_MULT_1X (1 << 0)
# define SDVO_CLOCK_RATE_MULT_2X (1 << 1)
# define SDVO_CLOCK_RATE_MULT_3X (1 << 2)
# define SDVO_CLOCK_RATE_MULT_4X (1 << 3)
# define SDVO_CLOCK_RATE_MULT_5X (1 << 4)
#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27