Merge branch 'modesetting' into crestline

This commit is contained in:
Keith Packard 2006-12-21 02:51:33 -08:00
commit c5205595f2
7 changed files with 580 additions and 145 deletions

14
src/fix.5c Normal file
View File

@ -0,0 +1,14 @@
/*
* Convert CSC fix point values to floats
*/
real fixval (int fix)
{
int exp = fix >> 9;
int mant = fix & ((1 << 9) - 1);
real ret;
if (exp == 0x7)
return 1.0;
ret = (2 ** -exp) * mant / (1 << 9);
return ret;
}

View File

@ -511,6 +511,7 @@ extern void I830SelectBuffer(ScrnInfoPtr pScrn, int buffer);
extern void I830RefreshRing(ScrnInfoPtr pScrn);
extern void I830EmitFlush(ScrnInfoPtr pScrn);
extern Bool I830DGAReInit(ScreenPtr pScreen);
extern Bool I830DGAInit(ScreenPtr pScreen);
#ifdef I830_XV

View File

@ -83,8 +83,8 @@ DGAFunctionRec I830DGAFuncs = {
#endif
};
Bool
I830DGAInit(ScreenPtr pScreen)
static DGAModePtr
I830DGAModes (ScreenPtr pScreen, int *nump)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
I830Ptr pI830 = I830PTR(pScrn);
@ -93,8 +93,6 @@ I830DGAInit(ScreenPtr pScreen)
int Bpp = pScrn->bitsPerPixel >> 3;
int num = 0;
MARKER();
pMode = firstMode = pScrn->modes;
while (pMode) {
@ -103,7 +101,7 @@ I830DGAInit(ScreenPtr pScreen)
if (!newmodes) {
xfree(modes);
return FALSE;
return NULL;
}
modes = newmodes;
@ -159,7 +157,42 @@ I830DGAInit(ScreenPtr pScreen)
if (pMode == firstMode)
break;
}
*nump = num;
return modes;
}
Bool
I830DGAReInit(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
I830Ptr pI830 = I830PTR(pScrn);
int num;
DGAModePtr modes;
modes = I830DGAModes (pScreen, &num);
if (!modes)
return FALSE;
if (pI830->DGAModes)
xfree (pI830->DGAModes);
pI830->numDGAModes = num;
pI830->DGAModes = modes;
return DGAReInitModes (pScreen, modes, num);
}
Bool
I830DGAInit(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
I830Ptr pI830 = I830PTR(pScrn);
int num;
DGAModePtr modes;
modes = I830DGAModes (pScreen, &num);
if (!modes)
return FALSE;
pI830->numDGAModes = num;
pI830->DGAModes = modes;

View File

@ -3604,6 +3604,7 @@ I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg)
xf86ProbeOutputModes (pScrn);
xf86SetScrnInfoModes (pScrn);
I830DGAReInit (pScrn->pScreen);
xf86SwitchMode(pScrn->pScreen, pScrn->currentMode);
/* Clear the BIOS's hotkey press flags */

View File

@ -97,6 +97,7 @@ xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations)
/* Re-probe the outputs for new monitors or modes */
xf86ProbeOutputModes (scrp);
xf86SetScrnInfoModes (scrp);
I830DGAReInit (pScreen);
for (mode = scrp->modes; ; mode = mode->next)
{
@ -787,6 +788,7 @@ xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations)
xf86ProbeOutputModes (pScrn);
xf86SetScrnInfoModes (pScrn);
I830DGAReInit (pScreen);
return xf86RandR12SetInfo12 (pScreen);
}

View File

@ -83,61 +83,20 @@ struct i830_tv_priv {
CARD32 save_TV_CTL;
};
enum burst_modes {
TV_SC_NTSC_MJ,
TV_SC_PAL,
TV_SC_PAL_NC,
TV_SC_PAL_M,
TV_SC_NTSC_443
};
typedef struct {
int blank, black, burst;
} video_levels_t;
const struct tv_sc_mode {
char *name;
int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
CARD32 sc_reset;
Bool pal_burst;
} tv_sc_modes[] = {
[TV_SC_NTSC_MJ] = {
"NTSC M/J",
27456, 0, 135, 20800, 0,
TV_SC_RESET_EVERY_4,
FALSE
},
[TV_SC_PAL] = {
"PAL",
27648, 625, 168, 4122, 67,
TV_SC_RESET_EVERY_8,
TRUE
},
[TV_SC_PAL_NC] = {
"PAL Nc",
27648, 625, 135, 23578, 134,
TV_SC_RESET_EVERY_8,
TRUE
},
[TV_SC_PAL_M] = {
"PAL M",
27456, 0, 135, 16704, 0,
TV_SC_RESET_EVERY_8,
TRUE
},
[TV_SC_NTSC_443] = {
"NTSC-4.43",
27456, 525, 168, 4093, 310,
TV_SC_RESET_NEVER,
FALSE
},
};
typedef struct {
float ry, gy, by, ay;
float ru, gu, bu, au;
float rv, gv, bv, av;
} color_conversion_t;
/**
* Register programming values for TV modes.
*
* These values account for -1s required.
*/
const struct tv_mode {
typedef struct {
char *name;
CARD32 oversample;
int hsync_end, hblank_end, hblank_start, htotal;
int hsync_end, hblank_start, hblank_end, htotal;
Bool progressive;
int vsync_start_f1, vsync_start_f2, vsync_len;
Bool veq_ena;
@ -149,20 +108,264 @@ const struct tv_mode {
int vburst_start_f2, vburst_end_f2;
int vburst_start_f3, vburst_end_f3;
int vburst_start_f4, vburst_end_f4;
} tv_modes[] = {
/*
* subcarrier programming
*/
int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
CARD32 sc_reset;
Bool pal_burst;
/*
* blank/black levels
*/
video_levels_t composite_levels, svideo_levels;
color_conversion_t composite_color, svideo_color;
} tv_mode_t;
#define TV_PLL_CLOCK 107520
/*
* Sub carrier DDA
*
* I think this works as follows:
*
* subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
*
* Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
*
* So,
* dda1_ideal = subcarrier/pixel * 4096
* dda1_inc = floor (dda1_ideal)
* dda2 = dda1_ideal - dda1_inc
*
* then pick a ratio for dda2 that gives the closest approximation. If
* you can't get close enough, you can play with dda3 as well. This
* seems likely to happen when dda2 is small as the jumps would be larger
*
* To invert this,
*
* pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
*
* The constants below were all computed using a 107.520MHz clock
*/
/**
* Register programming values for TV modes.
*
* These values account for -1s required.
*/
const tv_mode_t tv_modes[] = {
{
"480i",
TV_OVERSAMPLE_8X,
64, 124, 836, 857,
FALSE,
6, 7, 6,
TRUE, 0, 1, 18,
20, 21, 240,
TRUE,
72, 34, 9, 240, 10, 240, 9, 240, 10, 240
.name = "NTSC 480i",
.oversample = TV_OVERSAMPLE_8X,
/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
.hsync_end = 64, .hblank_end = 124,
.hblank_start = 836, .htotal = 857,
.progressive = FALSE,
.vsync_start_f1 = 6, .vsync_start_f2 = 7,
.vsync_len = 6,
.veq_ena = TRUE, .veq_start_f1 = 0,
.veq_start_f2 = 1, .veq_len = 18,
.vi_end_f1 = 20, .vi_end_f2 = 21,
.nbr_end = 240,
.burst_ena = TRUE,
.hburst_start = 72, .hburst_len = 34,
.vburst_start_f1 = 9, .vburst_end_f1 = 240,
.vburst_start_f2 = 10, .vburst_end_f2 = 240,
.vburst_start_f3 = 9, .vburst_end_f3 = 240,
.vburst_start_f4 = 10, .vburst_end_f4 = 240,
/* desired 3.5800000 actual 3.5800000 clock 107.52 */
.dda1_inc = 136,
.dda2_inc = 7624, .dda2_size = 20013,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_4,
.pal_burst = FALSE,
.composite_levels = { .blank = 225, .black = 267, .burst = 113 },
.composite_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5082,
.ru =-0.0749, .gu =-0.1471, .bu = 0.2220, .au = 1.0000,
.rv = 0.3125, .gv =-0.2616, .bv =-0.0508, .av = 1.0000,
},
.svideo_levels = { .blank = 266, .black = 316, .burst = 133 },
.svideo_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6006,
.ru =-0.0885, .gu =-0.1738, .bu = 0.2624, .au = 1.0000,
.rv = 0.3693, .gv =-0.3092, .bv =-0.0601, .av = 1.0000,
},
},
{
.name = "NTSC-Japan 480i",
.oversample = TV_OVERSAMPLE_8X,
/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
.hsync_end = 64, .hblank_end = 124,
.hblank_start = 836, .htotal = 857,
.progressive = FALSE,
.vsync_start_f1 = 6, .vsync_start_f2 = 7,
.vsync_len = 6,
.veq_ena = TRUE, .veq_start_f1 = 0,
.veq_start_f2 = 1, .veq_len = 18,
.vi_end_f1 = 20, .vi_end_f2 = 21,
.nbr_end = 240,
.burst_ena = TRUE,
.hburst_start = 72, .hburst_len = 34,
.vburst_start_f1 = 9, .vburst_end_f1 = 240,
.vburst_start_f2 = 10, .vburst_end_f2 = 240,
.vburst_start_f3 = 9, .vburst_end_f3 = 240,
.vburst_start_f4 = 10, .vburst_end_f4 = 240,
/* desired 3.5800000 actual 3.5800000 clock 107.52 */
.dda1_inc = 136,
.dda2_inc = 7624, .dda2_size = 20013,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_4,
.pal_burst = FALSE,
.composite_levels = { .blank = 225, .black = 225, .burst = 113 },
.composite_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5495,
.ru =-0.0810, .gu =-0.1590, .bu = 0.2400, .au = 1.0000,
.rv = 0.3378, .gv =-0.2829, .bv =-0.0549, .av = 1.0000,
},
.svideo_levels = { .blank = 266, .black = 266, .burst = 133 },
.svideo_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6494,
.ru =-0.0957, .gu =-0.1879, .bu = 0.2836, .au = 1.0000,
.rv = 0.3992, .gv =-0.3343, .bv =-0.0649, .av = 1.0000,
},
}
#if 0
{
/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
.name = "PAL",
/* desired 4.4336180 actual 4.4336180 clock 107.52 */
.dda1_inc = 168,
.dda2_inc = 18557, .dda2_size = 20625,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_8,
.pal_burst = TRUE
.composite_levels = { .blank = 237, .black = 237, .burst = 118 },
.composite_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5379,
.ru =-0.0793, .gu =-0.1557, .bu = 0.2350, .au = 1.0000,
.rv = 0.3307, .gv =-0.2769, .bv =-0.0538, .av = 1.0000,
},
.svideo_levels = { .blank = 280, .black = 280, .burst = 139 },
.svideo_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6357,
.ru =-0.0937, .gu =-0.1840, .bu = 0.2777, .au = 1.0000,
.rv = 0.3908, .gv =-0.3273, .bv =-0.0636, .av = 1.0000,
},
},
{
/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.576MHz */
.name = "PAL M",
/* desired 3.5756110 actual 3.5756110 clock 107.52 */
.dda1_inc = 136,
.dda2_inc = 5611, .dda2_size = 26250,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_8,
.pal_burst = TRUE
.composite_levels = { .blank = 225, .black = 267, .burst = 113 },
.composite_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5082,
.ru =-0.0749, .gu =-0.1471, .bu = 0.2220, .au = 1.0000,
.rv = 0.3125, .gv =-0.2616, .bv =-0.0508, .av = 1.0000,
},
.svideo_levels = { .blank = 266, .black = 316, .burst = 133 },
.svideo_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6006,
.ru =-0.0885, .gu =-0.1738, .bu = 0.2624, .au = 1.0000,
.rv = 0.3693, .gv =-0.3092, .bv =-0.0601, .av = 1.0000,
},
},
{
/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 3.582MHz */
.name = "PAL Nc",
/* desired 3.5820560 actual 3.5820560 clock 107.52 */
.dda1_inc = 136,
.dda2_inc = 12056, .dda2_size = 26250,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_8,
.pal_burst = TRUE
.composite_levels = { .blank = 225, .black = 267, .burst = 113 },
.composite_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5082,
.ru =-0.0749, .gu =-0.1471, .bu = 0.2220, .au = 1.0000,
.rv = 0.3125, .gv =-0.2616, .bv =-0.0508, .av = 1.0000,
},
.svideo_levels = { .blank = 266, .black = 316, .burst = 133 },
.svideo_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6006,
.ru =-0.0885, .gu =-0.1738, .bu = 0.2624, .au = 1.0000,
.rv = 0.3693, .gv =-0.3092, .bv =-0.0601, .av = 1.0000,
},
},
{
/* 525 lines, 60 fields, 15.734KHz line, Sub-Carrier 4.43MHz */
.name = "NTSC-4.43(nonstandard)",
/* desired 4.4336180 actual 4.4336180 clock 107.52 */
.dda1_inc = 168,
.dda2_inc = 18557, .dda2_size = 20625,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_NEVER,
.pal_burst = FALSE
.composite_levels = { .blank = 225, .black = 267, .burst = 113 },
.composite_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.5082,
.ru =-0.0749, .gu =-0.1471, .bu = 0.2220, .au = 1.0000,
.rv = 0.3125, .gv =-0.2616, .bv =-0.0508, .av = 1.0000,
},
.svideo_levels = { .blank = 266, .black = 316, .burst = 133 },
.svideo_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6006,
.ru =-0.0885, .gu =-0.1738, .bu = 0.2624, .au = 1.0000,
.rv = 0.3693, .gv =-0.3092, .bv =-0.0601, .av = 1.0000,
},
},
#endif
};
static const video_levels_t component_level = {
.blank = 279, .black = 279
};
static const color_conversion_t sdtv_component_color = {
.ry = 0.2990, .gy = 0.5870, .by = 0.1140, .ay = 0.6364,
.ru =-0.1687, .gu =-0.3313, .bu = 0.5000, .au = 1.0000,
.rv = 0.5000, .gv =-0.4187, .bv =-0.0813, .av = 1.0000,
};
static const color_conversion_t hdtv_component_color = {
.ry = 0.2126, .gy = 0.7152, .by = 0.0722, .ay = 0.6364,
.ru =-0.1146, .gu =-0.3854, .bu = 0.5000, .au = 1.0000,
.rv = 0.5000, .gv =-0.4542, .bv =-0.0458, .av = 1.0000,
};
static void
i830_tv_dpms(xf86OutputPtr output, int mode)
{
@ -377,6 +580,43 @@ i830_tv_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
return TRUE;
}
static CARD32
i830_float_to_csc (float fin)
{
CARD32 exp;
CARD32 mant;
CARD32 ret;
float f = fin;
/* somehow the color conversion knows the signs of all the values */
if (f < 0) f = -f;
if (f >= 1)
{
exp = 0x7;
mant = 1 << 8;
}
else
{
for (exp = 0; exp < 3 && f < 0.5; exp++)
f *= 2.0;
mant = (f * (1 << 9) + 0.5);
if (mant >= (1 << 9))
mant = (1 << 9) - 1;
}
ret = (exp << 9) | mant;
return ret;
}
static CARD16
i830_float_to_luma (float f)
{
CARD16 ret;
ret = (f * (1 << 9));
return ret;
}
static void
i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
DisplayModePtr adjusted_mode)
@ -387,14 +627,15 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
I830OutputPrivatePtr intel_output = output->driver_private;
I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
struct i830_tv_priv *dev_priv = intel_output->dev_priv;
enum tv_type type;
const struct tv_mode *tv_mode;
const struct tv_sc_mode *sc_mode;
const tv_mode_t *tv_mode;
CARD32 tv_ctl, tv_filter_ctl;
CARD32 hctl1, hctl2, hctl3;
CARD32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
CARD32 scctl1, scctl2, scctl3;
int i;
const video_levels_t *video_levels;
const color_conversion_t *color_conversion;
Bool burst_ena;
/* Need to actually choose or construct the appropriate
* mode. For now, just set the first one in the list, with
@ -402,16 +643,40 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
*/
OUTREG(TV_CTL, INREG(TV_CTL) & ~TV_ENC_ENABLE);
tv_mode = &tv_modes[0];
sc_mode = &tv_sc_modes[TV_SC_NTSC_MJ];
type = dev_priv->type;
tv_ctl = 0;
switch (dev_priv->type) {
default:
case TV_TYPE_UNKNOWN:
case TV_TYPE_COMPOSITE:
tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
video_levels = &tv_mode->composite_levels;
color_conversion = &tv_mode->composite_color;
burst_ena = tv_mode->burst_ena;
break;
case TV_TYPE_COMPONENT:
tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
video_levels = &component_level;
if (tv_mode->burst_ena)
color_conversion = &sdtv_component_color;
else
color_conversion = &hdtv_component_color;
burst_ena = FALSE;
break;
case TV_TYPE_SVIDEO:
tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
video_levels = &tv_mode->svideo_levels;
color_conversion = &tv_mode->svideo_color;
burst_ena = tv_mode->burst_ena;
break;
}
hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
(tv_mode->htotal << TV_HTOTAL_SHIFT);
hctl2 = (tv_mode->hburst_start << 16) |
(tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
if (tv_mode->burst_ena)
if (burst_ena)
hctl2 |= TV_BURST_ENA;
hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
@ -443,44 +708,32 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
(tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
tv_ctl = 0;
if (intel_crtc->pipe == 1)
tv_ctl |= TV_ENC_PIPEB_SELECT;
switch (type) {
case TV_TYPE_COMPOSITE:
tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
break;
case TV_TYPE_COMPONENT:
tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
break;
case TV_TYPE_SVIDEO:
tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
break;
default:
case TV_TYPE_UNKNOWN:
tv_ctl |= TV_ENC_OUTPUT_SVIDEO_COMPOSITE;
break;
}
tv_ctl |= tv_mode->oversample;
if (tv_mode->progressive)
tv_ctl |= TV_PROGRESSIVE;
if (sc_mode->pal_burst)
if (tv_mode->pal_burst)
tv_ctl |= TV_PAL_BURST;
scctl1 = TV_SC_DDA1_EN | TV_SC_DDA2_EN;
if (sc_mode->dda3_size != 0)
scctl1 = TV_SC_DDA1_EN;
if (tv_mode->dda2_inc)
scctl1 |= TV_SC_DDA2_EN;
if (tv_mode->dda3_inc)
scctl1 |= TV_SC_DDA3_EN;
scctl1 |= sc_mode->sc_reset;
/* XXX: set the burst level */
scctl1 |= 113 << TV_BURST_LEVEL_SHIFT; /* from BIOS */
scctl1 |= sc_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
scctl1 |= tv_mode->sc_reset;
scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
scctl2 = sc_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
sc_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
scctl3 = sc_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
sc_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
/* Enable two fixes for the chips that need them. */
if (pI830->PciInfo->chipType < PCI_CHIP_I945_G)
@ -503,17 +756,37 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
OUTREG(TV_SC_CTL_1, scctl1);
OUTREG(TV_SC_CTL_2, scctl2);
OUTREG(TV_SC_CTL_3, scctl3);
/* XXX match BIOS */
OUTREG(TV_CSC_Y, 0x0332012D);
OUTREG(TV_CSC_Y2, 0x07D30133);
OUTREG(TV_CSC_U, 0x076A0564);
OUTREG(TV_CSC_U2, 0x030D0200);
OUTREG(TV_CSC_V, 0x037A033D);
OUTREG(TV_CSC_V2, 0x06F60200);
OUTREG(TV_CSC_Y,
(i830_float_to_csc(color_conversion->ry) << 16) |
(i830_float_to_csc(color_conversion->gy)));
OUTREG(TV_CSC_Y2,
(i830_float_to_csc(color_conversion->by) << 16) |
(i830_float_to_luma(color_conversion->ay)));
OUTREG(TV_CSC_U,
(i830_float_to_csc(color_conversion->ru) << 16) |
(i830_float_to_csc(color_conversion->gu)));
OUTREG(TV_CSC_U2,
(i830_float_to_csc(color_conversion->bu) << 16) |
(i830_float_to_luma(color_conversion->au)));
OUTREG(TV_CSC_V,
(i830_float_to_csc(color_conversion->rv) << 16) |
(i830_float_to_csc(color_conversion->gv)));
OUTREG(TV_CSC_V2,
(i830_float_to_csc(color_conversion->bv) << 16) |
(i830_float_to_luma(color_conversion->av)));
OUTREG(TV_CLR_KNOBS, 0x00606000);
OUTREG(TV_CLR_LEVEL, 0x013C010A);
OUTREG(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
(video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
OUTREG(TV_WIN_POS, 0x00360024);
OUTREG(TV_WIN_SIZE, 0x02640198);
OUTREG(TV_FILTER_CTL_1, 0x8000085E);
OUTREG(TV_FILTER_CTL_2, 0x00017878);
OUTREG(TV_FILTER_CTL_3, 0x0000BC3C);
@ -530,10 +803,10 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
OUTREG(TV_CTL, tv_ctl);
}
static const DisplayModeRec tvModes[] = {
static const DisplayModeRec reported_modes[] = {
{
.name = "NTSC 480i",
.Clock = 108000,
.Clock = TV_PLL_CLOCK,
.HDisplay = 1024,
.HSyncStart = 1048,
@ -545,7 +818,7 @@ static const DisplayModeRec tvModes[] = {
.VSyncEnd = 777,
.VTotal = 806,
.type = M_T_DEFAULT
.type = M_T_DRIVER
}
};
@ -644,7 +917,8 @@ i830_tv_detect(xf86OutputPtr output)
{
if (intel_output->load_detect_temp)
{
mode = tvModes[0];
/* we only need the pixel clock set correctly here */
mode = reported_modes[0];
xf86SetModeCrtc (&mode, INTERLACE_HALVE_V);
i830PipeSetMode (crtc, &mode, FALSE);
}
@ -671,43 +945,25 @@ i830_tv_detect(xf86OutputPtr output)
static DisplayModePtr
i830_tv_get_modes(xf86OutputPtr output)
{
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
DisplayModePtr new;
char stmp[32];
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
DisplayModePtr new, first = NULL, *tail = &first;;
int i;
(void) pI830;
new = xnfcalloc(1, sizeof (DisplayModeRec));
sprintf(stmp, "480i");
new->name = xnfalloc(strlen(stmp) + 1);
strcpy(new->name, stmp);
new->Clock = 108000;
/*
new->HDisplay = 640;
new->HSyncStart = 664;
new->HSyncEnd = 704;
new->HTotal = 832;
new->VDisplay = 480;
new->VSyncStart = 489;
new->VSyncEnd = 491;
new->VTotal = 520;
*/
new->HDisplay = 1024;
new->HSyncStart = 1048;
new->HSyncEnd = 1184;
new->HTotal = 1344;
new->VDisplay = 768;
new->VSyncStart = 771;
new->VSyncEnd = 777;
new->VTotal = 806;
new->type = M_T_DRIVER;
for (i = 0; i < sizeof (reported_modes) / sizeof (reported_modes[0]); i++)
{
new = xnfcalloc(1, sizeof (DisplayModeRec));
return new;
*new = reported_modes[i];
new->name = xnfalloc(strlen(reported_modes[i].name) + 1);
strcpy(new->name, reported_modes[i].name);
*tail = new;
tail = &new->next;
}
return first;
}
static void

128
src/tv.5c Normal file
View File

@ -0,0 +1,128 @@
/*
* tv.5c
*
* Compute tv encoder subcarrier dda constants
*
* The TV encoder subcarrier must be set precisely to the
* required frequency or the cumulative phase errors will be
* quite visible in the output. To accomplish this, the TV encoder
* has a complex circuit that takes a fixed clock, generated by the PLL
* and generates a precise subcarrier clock from that using the following
* formula:
*
* subcarrier = pixel_clock * (S1 + (S2 + (S3/Z3)) / Z2) / 4096
*
* Careful selection of the constants will provide the necessarily
* precise clock.
*
* In the code below, S1 is represented by dda1, S2/Z2 by dda2 and S3/Z3
* by dda3.
*/
typedef struct {
int step;
int size;
} term_t;
/*
* Find the approximation closest, but no larger than 'v', where
* 0 <= v < 1, and the result denominator must be less than 30000.
*/
term_t approx (rational v)
{
rational best_dist = 1.0;
term_t best;
for (int den = 20000; den < 30000; den++)
{
int num = floor (v * den);
term_t approx = { step = num, size = den };
rational dist = v - approx.step/approx.size;
if (dist >= 0 && dist < best_dist)
{
best_dist = dist;
best = approx;
}
}
return best;
}
typedef struct {
rational subcarrier;
rational pixel;
rational result;
term_t dda1;
term_t dda2;
term_t dda3;
} dda;
/*
* Compute the dda constants for the given pixel clock and
* desired subcarrier frequency
*/
dda find_dda (rational pixel, rational subcarrier)
{
dda d;
d.subcarrier = subcarrier;
d.pixel = pixel;
rational dda1 = subcarrier / pixel * 4096;
d.dda1 = (term_t) { step = floor (dda1), size = 4096 };
rational dda2 = dda1 - d.dda1.step;
d.dda2 = approx (dda2);
rational dda3 = dda2 * d.dda2.size - d.dda2.step;
d.dda3 = approx (dda3);
/* Compute the resulting pixel clock to compare */
d.result = d.pixel * (d.dda1.step +
(d.dda2.step + d.dda3.step/d.dda3.size) /
d.dda2.size) / d.dda1.size;
return d;
}
/*
* Print out the computed constants
*/
void print_dda (dda d)
{
printf ("\t/* desired %9.7f actual %9.7f clock %g */\n",
d.subcarrier, d.result, d.pixel);
printf ("\t.dda1_inc\t= %6d,\n", d.dda1.step);
printf ("\t.dda2_inc\t= %6d,\t.dda2_size\t= %6d,\n",
d.dda2.step, d.dda2.step != 0 ? d.dda2.size : 0);
printf ("\t.dda3_inc\t= %6d,\t.dda3_size\t= %6d,\n",
d.dda3.step, d.dda3.step != 0 ? d.dda3.size : 0);
}
/*
* These are all of the required subcarrier frequencies
*/
rational[] subcarriers = {
/* these are the values we use; for some reason, this generates
* a more stable image (at least for NTSC) */
3.580, 4.434, 3.582, 3.576, 4.430,
/* these are the values pulled out of the various specs */
3.579545, 4.433618, 3.582056, 3.575611, 4.433618
};
/*
* We fix the pixel clock to a value which the hardware can
* generate exactly
*/
rational pixel = 107.520;
void main ()
{
for (int i = 0; i < dim(subcarriers); i++)
{
dda d = find_dda (pixel, subcarriers[i]);
print_dda (d);
}
}
main ();