Merge branch 'modesetting-origin' into modesetting
This commit is contained in:
commit
896ffe78fe
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,3 +27,4 @@
|
|||
|
||||
void i830TakeRegSnapshot(ScrnInfoPtr pScrn);
|
||||
void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn);
|
||||
void i830DumpRegs (ScrnInfoPtr pScrn);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
366
src/i830_modes.c
366
src/i830_modes.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue