summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKeith Packard <keithp@guitar.keithp.com>2006-11-19 00:40:46 -0800
committerKeith Packard <keithp@guitar.keithp.com>2006-11-19 00:40:46 -0800
commit28224af3d90a1a08d54a865dfaf20184330fe8a4 (patch)
tree6e4482eb9ab961e26efc2b43374339d41d311189 /src
parent816fc1a76a5ac738e41b172ba8f43137c1521328 (diff)
Preliminary 945 TV output. Color key is broken. Fixed mode.
TV output is generating video with this patch, but the color burst signal is incorrect somehow.
Diffstat (limited to 'src')
-rw-r--r--src/i810_reg.h20
-rw-r--r--src/i830_debug.c35
-rw-r--r--src/i830_display.c6
-rw-r--r--src/i830_driver.c14
-rw-r--r--src/i830_tv.c176
5 files changed, 226 insertions, 25 deletions
diff --git a/src/i810_reg.h b/src/i810_reg.h
index 0ece7ee8..a61bc6b6 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -1044,6 +1044,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# define TV_ENC_OUTPUT_SVIDEO (1 << 28)
/** Outputs Component video (DAC A/B/C) */
# define TV_ENC_OUTPUT_COMPONENT (2 << 28)
+/** Outputs Composite and SVideo (DAC A/B/C) */
+# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE (3 << 28)
# define TV_TRILEVEL_SYNC (1 << 21)
/** Enables slow sync generation (945GM only) */
# define TV_SLOW_SYNC (1 << 20)
@@ -1078,6 +1080,18 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# define TV_FUSE_STATE_NO_MACROVISION (1 << 4)
/** Read-only state that reports that TV-out is disabled in hardware. */
# define TV_FUSE_STATE_DISABLED (2 << 4)
+/** Normal operation */
+# define TV_TEST_MODE_NORMAL (0 << 0)
+/** Encoder test pattern 1 - combo pattern */
+# define TV_TEST_MODE_PATTERN_1 (1 << 0)
+/** Encoder test pattern 2 - full screen vertical 75% color bars */
+# define TV_TEST_MODE_PATTERN_2 (2 << 0)
+/** Encoder test pattern 3 - full screen horizontal 75% color bars */
+# define TV_TEST_MODE_PATTERN_3 (3 << 0)
+/** Encoder test pattern 4 - random noise */
+# define TV_TEST_MODE_PATTERN_4 (4 << 0)
+/** Encoder test pattern 5 - linear color ramps */
+# define TV_TEST_MODE_PATTERN_5 (5 << 0)
/**
* This test mode forces the DACs to 50% of full output.
*
@@ -1417,7 +1431,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/** @defgroup TV_SC_CTL_2
* @{
*/
-#define TV_SC_CTL_2 0x68068
+#define TV_SC_CTL_2 0x68064
/** Sets the rollover for the second subcarrier phase generation DDA */
# define TV_SCDDA2_SIZE_MASK 0x7fff0000
# define TV_SCDDA2_SIZE_SHIFT 16
@@ -1586,6 +1600,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define TV_H_LUMA_59 0x681ec
#define TV_H_CHROMA_0 0x68200
#define TV_H_CHROMA_59 0x682ec
+#define TV_V_LUMA_0 0x68300
+#define TV_V_LUMA_42 0x683a8
+#define TV_V_CHROMA_0 0x68400
+#define TV_V_CHROMA_42 0x684a8
/** @} */
#define PIPEACONF 0x70008
diff --git a/src/i830_debug.c b/src/i830_debug.c
index 7922af0a..185988e4 100644
--- a/src/i830_debug.c
+++ b/src/i830_debug.c
@@ -126,6 +126,41 @@ static struct i830SnapshotRec {
DEFINEREG(VCLK_DIVISOR_VGA1),
DEFINEREG(VCLK_POST_DIV),
DEFINEREG(VGACNTRL),
+
+ DEFINEREG(TV_CTL),
+ DEFINEREG(TV_DAC),
+ DEFINEREG(TV_CSC_Y),
+ DEFINEREG(TV_CSC_Y2),
+ DEFINEREG(TV_CSC_U),
+ DEFINEREG(TV_CSC_U2),
+ DEFINEREG(TV_CSC_V),
+ DEFINEREG(TV_CSC_V2),
+ DEFINEREG(TV_CLR_KNOBS),
+ DEFINEREG(TV_CLR_LEVEL),
+ DEFINEREG(TV_H_CTL_1),
+ DEFINEREG(TV_H_CTL_2),
+ DEFINEREG(TV_H_CTL_3),
+ DEFINEREG(TV_V_CTL_1),
+ DEFINEREG(TV_V_CTL_2),
+ DEFINEREG(TV_V_CTL_3),
+ DEFINEREG(TV_V_CTL_4),
+ DEFINEREG(TV_V_CTL_5),
+ DEFINEREG(TV_V_CTL_6),
+ DEFINEREG(TV_V_CTL_7),
+ DEFINEREG(TV_SC_CTL_1),
+ DEFINEREG(TV_SC_CTL_2),
+ DEFINEREG(TV_SC_CTL_3),
+ DEFINEREG(TV_WIN_POS),
+ DEFINEREG(TV_WIN_SIZE),
+ DEFINEREG(TV_FILTER_CTL_1),
+ DEFINEREG(TV_FILTER_CTL_2),
+ DEFINEREG(TV_FILTER_CTL_3),
+ DEFINEREG(TV_CC_CONTROL),
+ DEFINEREG(TV_CC_DATA),
+ DEFINEREG(TV_H_LUMA_0),
+ DEFINEREG(TV_H_LUMA_59),
+ DEFINEREG(TV_H_CHROMA_0),
+ DEFINEREG(TV_H_CHROMA_59),
};
#undef DEFINEREG
#define NUM_I830_SNAPSHOTREGS (sizeof(i830_snapshot) / sizeof(i830_snapshot[0]))
diff --git a/src/i830_display.c b/src/i830_display.c
index bd40e4ee..04f85cc2 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -587,7 +587,11 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe,
}
if (is_tv)
- dpll |= PLL_REF_INPUT_TVCLKINBC;
+ {
+ /* XXX: just matching BIOS for now */
+/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
+ dpll |= 3;
+ }
#if 0
else if (is_lvds)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
diff --git a/src/i830_driver.c b/src/i830_driver.c
index c9e06a61..aaa2628e 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -667,6 +667,10 @@ I830SetupOutputs(ScrnInfoPtr pScrn)
} else {
i830_dvo_init(pScrn);
}
+#if 1
+ if (IS_I915GM(pI830) || IS_I945GM(pI830))
+ i830_tv_init(pScrn);
+#endif
}
static void
@@ -702,7 +706,8 @@ PreInitCleanup(ScrnInfoPtr pScrn)
I830Ptr pI830 = I830PTR(pScrn);
if (I830IsPrimary(pScrn)) {
- pI830->entityPrivate->pScrn_1 = NULL;
+ if (pI830->entityPrivate)
+ pI830->entityPrivate->pScrn_1 = NULL;
if (pI830->LpRing)
xfree(pI830->LpRing);
pI830->LpRing = NULL;
@@ -1434,6 +1439,12 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
}
}
break;
+ case I830_OUTPUT_TVOUT:
+ if (!i830PipeInUse(pScrn, 0)) {
+ pI830->output[i].pipe = 0;
+ pI830->output[i].enabled = TRUE;
+ }
+ break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unhandled output type\n");
break;
@@ -3551,6 +3562,7 @@ I830EnterVT(int scrnIndex, int flags)
i830DisableUnusedFunctions(pScrn);
+ i830DumpRegs (pScrn);
i830DescribeOutputConfiguration(pScrn);
#ifdef XF86DRI
diff --git a/src/i830_tv.c b/src/i830_tv.c
index c597db53..f938d5cc 100644
--- a/src/i830_tv.c
+++ b/src/i830_tv.c
@@ -279,8 +279,74 @@ i830_tv_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
/* Disable the encoder while we set up the pipe. */
OUTREG(TV_CTL, INREG(TV_CTL) & ~TV_ENC_ENABLE);
+ /* XXX match BIOS for now */
+ OUTREG(ADPA, 0x40008C18);
}
+static const CARD32 h_luma[60] = {
+ 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
+ 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
+ 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
+ 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
+ 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
+ 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
+ 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
+ 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
+ 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
+ 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
+ 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
+ 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
+ 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
+ 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
+ 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
+};
+
+static const CARD32 h_chroma[60] = {
+ 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
+ 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
+ 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
+ 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
+ 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
+ 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
+ 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
+ 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
+ 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
+ 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
+ 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
+ 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
+ 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
+ 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
+ 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
+};
+
+static const CARD32 v_luma[43] = {
+ 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
+ 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
+ 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
+ 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
+ 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
+ 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
+ 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
+ 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
+ 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
+ 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
+ 0x28003100, 0x28002F00, 0x00003100,
+};
+
+static const CARD32 v_chroma[43] = {
+ 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
+ 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
+ 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
+ 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
+ 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
+ 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
+ 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
+ 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
+ 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
+ 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
+ 0x28003100, 0x28002F00, 0x00003100,
+};
+
static void
i830_tv_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
@@ -293,6 +359,7 @@ i830_tv_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
CARD32 hctl1, hctl2, hctl3;
CARD32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
CARD32 scctl1, scctl2, scctl3;
+ int i;
/* Need to actually choose or construct the appropriate
* mode. For now, just set the first one in the list, with
@@ -302,10 +369,6 @@ i830_tv_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
sc_mode = &tv_sc_modes[TV_SC_NTSC_MJ];
type = i830_tv_detect_type(pScrn, output);
- if (type == TV_TYPE_UNKNOWN) {
- xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Defaulting TV to SVIDEO\n");
- type = TV_TYPE_SVIDEO;
- }
hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
(tv_mode->htotal << TV_HTOTAL_SHIFT);
@@ -355,10 +418,13 @@ i830_tv_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
case TV_TYPE_COMPONENT:
tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
break;
- default:
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)
@@ -366,11 +432,12 @@ i830_tv_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
if (sc_mode->pal_burst)
tv_ctl |= TV_PAL_BURST;
- scctl1 = TV_SC_DDA1_EN | TV_SC_DDA1_EN;
+ scctl1 = TV_SC_DDA1_EN | TV_SC_DDA2_EN;
if (sc_mode->dda3_size != 0)
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;
scctl2 = sc_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
@@ -400,6 +467,28 @@ i830_tv_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
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_CLR_KNOBS, 0x00606000);
+ OUTREG(TV_CLR_LEVEL, 0x013C010A);
+ 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);
+ for (i = 0; i < 60; i++)
+ OUTREG(TV_H_LUMA_0 + (i <<2), h_luma[i]);
+ for (i = 0; i < 60; i++)
+ OUTREG(TV_H_CHROMA_0 + (i <<2), h_chroma[i]);
+ for (i = 0; i < 43; i++)
+ OUTREG(TV_V_LUMA_0 + (i <<2), v_luma[i]);
+ for (i = 0; i < 43; i++)
+ OUTREG(TV_V_CHROMA_0 + (i <<2), v_chroma[i]);
OUTREG(TV_DAC, 0);
OUTREG(TV_CTL, tv_ctl);
@@ -414,7 +503,7 @@ i830_tv_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
static enum detect_status
i830_tv_detect(ScrnInfoPtr pScrn, I830OutputPtr output)
{
- return OUTPUT_STATUS_UNKNOWN;
+ return OUTPUT_STATUS_CONNECTED;
}
/**
@@ -426,31 +515,74 @@ i830_tv_detect(ScrnInfoPtr pScrn, I830OutputPtr output)
static DisplayModePtr
i830_tv_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output)
{
- return NULL;
+ I830Ptr pI830 = I830PTR(pScrn);
+ DisplayModePtr new;
+ char stmp[32];
+
+ (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_PREFERRED;
+
+ return new;
}
void
i830_tv_init(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
-
+ I830OutputPtr output = &pI830->output[pI830->num_outputs];
+ struct i830_tv_priv *dev_priv;
+
if ((INREG(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
return;
- pI830->output[pI830->num_outputs].dev_priv =
- malloc(sizeof(struct i830_tv_priv));
- if (pI830->output[pI830->num_outputs].dev_priv == NULL)
+ output->type = I830_OUTPUT_TVOUT;
+ output->pipe = 0;
+ output->enabled = FALSE;
+ output->load_detect_temp = FALSE;
+
+ output->dpms = i830_tv_dpms;
+ output->save = i830_tv_save;
+ output->restore = i830_tv_restore;
+ output->mode_valid = i830_tv_mode_valid;
+ output->pre_set_mode = i830_tv_pre_set_mode;
+ output->post_set_mode = i830_tv_post_set_mode;
+ output->detect = i830_tv_detect;
+ output->get_modes = i830_tv_get_modes;
+
+ dev_priv = xnfcalloc(1, sizeof(struct i830_tv_priv));
+
+ if (dev_priv == NULL)
return;
- pI830->output[pI830->num_outputs].type = I830_OUTPUT_ANALOG;
- pI830->output[pI830->num_outputs].dpms = i830_tv_dpms;
- pI830->output[pI830->num_outputs].save = i830_tv_save;
- pI830->output[pI830->num_outputs].restore = i830_tv_restore;
- pI830->output[pI830->num_outputs].mode_valid = i830_tv_mode_valid;
- pI830->output[pI830->num_outputs].pre_set_mode = i830_tv_pre_set_mode;
- pI830->output[pI830->num_outputs].post_set_mode = i830_tv_post_set_mode;
- pI830->output[pI830->num_outputs].detect = i830_tv_detect;
- pI830->output[pI830->num_outputs].get_modes = i830_tv_get_modes;
-
+ output->dev_priv = dev_priv;
+ ErrorF ("TV out is output %d\n", pI830->num_outputs);
pI830->num_outputs++;
}