summaryrefslogtreecommitdiff
path: root/driver/xf86-video-intel/src/i830_tv.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/xf86-video-intel/src/i830_tv.c')
-rw-r--r--driver/xf86-video-intel/src/i830_tv.c526
1 files changed, 401 insertions, 125 deletions
diff --git a/driver/xf86-video-intel/src/i830_tv.c b/driver/xf86-video-intel/src/i830_tv.c
index 0a33357c6..8eb3e2634 100644
--- a/driver/xf86-video-intel/src/i830_tv.c
+++ b/driver/xf86-video-intel/src/i830_tv.c
@@ -56,8 +56,13 @@ enum tv_margin {
/** Private structure for the integrated TV support */
struct i830_tv_priv {
int type;
+ Bool force_type;
char *tv_format;
int margin[4];
+ uint8_t brightness;
+ uint8_t contrast;
+ uint8_t saturation;
+ uint8_t hue;
uint32_t save_TV_H_CTL_1;
uint32_t save_TV_H_CTL_2;
uint32_t save_TV_H_CTL_3;
@@ -144,7 +149,7 @@ static const uint32_t filter_table[] = {
0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
- 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
+ 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
0x2D002CC0, 0x30003640, 0x2D0036C0,
0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
@@ -215,7 +220,7 @@ typedef struct {
*
* The constants below were all computed using a 107.520MHz clock
*/
-
+
/**
* Register programming values for TV modes.
*
@@ -225,7 +230,7 @@ typedef struct {
const static tv_mode_t tv_modes[] = {
{
.name = "NTSC-M",
- .clock = 107520,
+ .clock = 108000,
.refresh = 29.97,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
@@ -239,7 +244,7 @@ const static tv_mode_t tv_modes[] = {
.vsync_start_f1 = 6, .vsync_start_f2 = 7,
.vsync_len = 6,
- .veq_ena = TRUE, .veq_start_f1 = 0,
+ .veq_ena = TRUE, .veq_start_f1 = 0,
.veq_start_f2 = 1, .veq_len = 18,
.vi_end_f1 = 20, .vi_end_f2 = 21,
@@ -249,12 +254,12 @@ const static tv_mode_t tv_modes[] = {
.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_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,
+ .dda1_inc = 135,
+ .dda2_inc = 20800, .dda2_size = 27456,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_4,
.pal_burst = FALSE,
@@ -276,7 +281,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "NTSC-443",
- .clock = 107520,
+ .clock = 108000,
.refresh = 29.97,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
@@ -289,7 +294,7 @@ const static tv_mode_t tv_modes[] = {
.vsync_start_f1 = 6, .vsync_start_f2 = 7,
.vsync_len = 6,
- .veq_ena = TRUE, .veq_start_f1 = 0,
+ .veq_ena = TRUE, .veq_start_f1 = 0,
.veq_start_f2 = 1, .veq_len = 18,
.vi_end_f1 = 20, .vi_end_f2 = 21,
@@ -299,15 +304,15 @@ const static tv_mode_t tv_modes[] = {
.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_f3 = 9, .vburst_end_f3 = 240,
.vburst_start_f4 = 10, .vburst_end_f4 = 240,
/* 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,
+ .dda2_inc = 4093, .dda2_size = 27456,
+ .dda3_inc = 310, .dda3_size = 525,
+ .sc_reset = TV_SC_RESET_NEVER,
+ .pal_burst = FALSE,
.composite_levels = { .blank = 225, .black = 267, .burst = 113 },
.composite_color = {
@@ -326,7 +331,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "NTSC-J",
- .clock = 107520,
+ .clock = 108000,
.refresh = 29.97,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
@@ -340,7 +345,7 @@ const static tv_mode_t tv_modes[] = {
.vsync_start_f1 = 6, .vsync_start_f2 = 7,
.vsync_len = 6,
- .veq_ena = TRUE, .veq_start_f1 = 0,
+ .veq_ena = TRUE, .veq_start_f1 = 0,
.veq_start_f2 = 1, .veq_len = 18,
.vi_end_f1 = 20, .vi_end_f2 = 21,
@@ -350,12 +355,12 @@ const static tv_mode_t tv_modes[] = {
.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_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,
+ .dda1_inc = 135,
+ .dda2_inc = 20800, .dda2_size = 27456,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_4,
.pal_burst = FALSE,
@@ -377,7 +382,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "PAL-M",
- .clock = 107520,
+ .clock = 108000,
.refresh = 29.97,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
@@ -391,7 +396,7 @@ const static tv_mode_t tv_modes[] = {
.vsync_start_f1 = 6, .vsync_start_f2 = 7,
.vsync_len = 6,
- .veq_ena = TRUE, .veq_start_f1 = 0,
+ .veq_ena = TRUE, .veq_start_f1 = 0,
.veq_start_f2 = 1, .veq_len = 18,
.vi_end_f1 = 20, .vi_end_f2 = 21,
@@ -401,15 +406,15 @@ const static tv_mode_t tv_modes[] = {
.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_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,
+ .dda1_inc = 135,
+ .dda2_inc = 16704, .dda2_size = 27456,
.dda3_inc = 0, .dda3_size = 0,
- .sc_reset = TV_SC_RESET_EVERY_4,
- .pal_burst = FALSE,
+ .sc_reset = TV_SC_RESET_EVERY_8,
+ .pal_burst = TRUE,
.composite_levels = { .blank = 225, .black = 267, .burst = 113 },
.composite_color = {
@@ -429,7 +434,7 @@ const static tv_mode_t tv_modes[] = {
{
/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
.name = "PAL-N",
- .clock = 107520,
+ .clock = 108000,
.refresh = 25.0,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
@@ -443,24 +448,24 @@ const static tv_mode_t tv_modes[] = {
.vsync_start_f1 = 6, .vsync_start_f2 = 7,
.vsync_len = 6,
- .veq_ena = TRUE, .veq_start_f1 = 0,
+ .veq_ena = TRUE, .veq_start_f1 = 0,
.veq_start_f2 = 1, .veq_len = 18,
.vi_end_f1 = 24, .vi_end_f2 = 25,
.nbr_end = 286,
.burst_ena = TRUE,
- .hburst_start = 73, .hburst_len = 34,
+ .hburst_start = 73, .hburst_len = 34,
.vburst_start_f1 = 8, .vburst_end_f1 = 285,
.vburst_start_f2 = 8, .vburst_end_f2 = 286,
- .vburst_start_f3 = 9, .vburst_end_f3 = 286,
+ .vburst_start_f3 = 9, .vburst_end_f3 = 286,
.vburst_start_f4 = 9, .vburst_end_f4 = 285,
/* desired 4.4336180 actual 4.4336180 clock 107.52 */
- .dda1_inc = 168,
- .dda2_inc = 18557, .dda2_size = 20625,
- .dda3_inc = 0, .dda3_size = 0,
+ .dda1_inc = 135,
+ .dda2_inc = 23578, .dda2_size = 27648,
+ .dda3_inc = 134, .dda3_size = 625,
.sc_reset = TV_SC_RESET_EVERY_8,
.pal_burst = TRUE,
@@ -482,12 +487,12 @@ const static tv_mode_t tv_modes[] = {
{
/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
.name = "PAL",
- .clock = 107520,
+ .clock = 108000,
.refresh = 25.0,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
- .hsync_end = 64, .hblank_end = 128,
+ .hsync_end = 64, .hblank_end = 142,
.hblank_start = 844, .htotal = 863,
.progressive = FALSE, .trilevel_sync = FALSE,
@@ -495,7 +500,7 @@ const static tv_mode_t tv_modes[] = {
.vsync_start_f1 = 5, .vsync_start_f2 = 6,
.vsync_len = 5,
- .veq_ena = TRUE, .veq_start_f1 = 0,
+ .veq_ena = TRUE, .veq_start_f1 = 0,
.veq_start_f2 = 1, .veq_len = 15,
.vi_end_f1 = 24, .vi_end_f2 = 25,
@@ -505,13 +510,13 @@ const static tv_mode_t tv_modes[] = {
.hburst_start = 73, .hburst_len = 32,
.vburst_start_f1 = 8, .vburst_end_f1 = 285,
.vburst_start_f2 = 8, .vburst_end_f2 = 286,
- .vburst_start_f3 = 9, .vburst_end_f3 = 286,
+ .vburst_start_f3 = 9, .vburst_end_f3 = 286,
.vburst_start_f4 = 9, .vburst_end_f4 = 285,
/* desired 4.4336180 actual 4.4336180 clock 107.52 */
.dda1_inc = 168,
- .dda2_inc = 18557, .dda2_size = 20625,
- .dda3_inc = 0, .dda3_size = 0,
+ .dda2_inc = 4122, .dda2_size = 27648,
+ .dda3_inc = 67, .dda3_size = 625,
.sc_reset = TV_SC_RESET_EVERY_8,
.pal_burst = TRUE,
@@ -532,7 +537,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "480p@59.94Hz",
- .clock = 107520,
+ .clock = 107520,
.refresh = 59.94,
.oversample = TV_OVERSAMPLE_4X,
.component_only = 1,
@@ -540,7 +545,7 @@ const static tv_mode_t tv_modes[] = {
.hsync_end = 64, .hblank_end = 122,
.hblank_start = 842, .htotal = 857,
- .progressive = TRUE,.trilevel_sync = FALSE,
+ .progressive = TRUE, .trilevel_sync = FALSE,
.vsync_start_f1 = 12, .vsync_start_f2 = 12,
.vsync_len = 12,
@@ -548,7 +553,7 @@ const static tv_mode_t tv_modes[] = {
.veq_ena = FALSE,
.vi_end_f1 = 44, .vi_end_f2 = 44,
- .nbr_end = 496,
+ .nbr_end = 479,
.burst_ena = FALSE,
@@ -556,7 +561,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "480p@60Hz",
- .clock = 107520,
+ .clock = 107520,
.refresh = 60.0,
.oversample = TV_OVERSAMPLE_4X,
.component_only = 1,
@@ -564,7 +569,7 @@ const static tv_mode_t tv_modes[] = {
.hsync_end = 64, .hblank_end = 122,
.hblank_start = 842, .htotal = 856,
- .progressive = TRUE,.trilevel_sync = FALSE,
+ .progressive = TRUE, .trilevel_sync = FALSE,
.vsync_start_f1 = 12, .vsync_start_f2 = 12,
.vsync_len = 12,
@@ -572,7 +577,7 @@ const static tv_mode_t tv_modes[] = {
.veq_ena = FALSE,
.vi_end_f1 = 44, .vi_end_f2 = 44,
- .nbr_end = 496,
+ .nbr_end = 479,
.burst_ena = FALSE,
@@ -580,7 +585,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "576p",
- .clock = 107520,
+ .clock = 107520,
.refresh = 50.0,
.oversample = TV_OVERSAMPLE_4X,
.component_only = 1,
@@ -588,7 +593,7 @@ const static tv_mode_t tv_modes[] = {
.hsync_end = 64, .hblank_end = 139,
.hblank_start = 859, .htotal = 863,
- .progressive = TRUE, .trilevel_sync = FALSE,
+ .progressive = TRUE, .trilevel_sync = FALSE,
.vsync_start_f1 = 10, .vsync_start_f2 = 10,
.vsync_len = 10,
@@ -604,7 +609,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "720p@60Hz",
- .clock = 148800,
+ .clock = 148800,
.refresh = 60.0,
.oversample = TV_OVERSAMPLE_2X,
.component_only = 1,
@@ -612,7 +617,7 @@ const static tv_mode_t tv_modes[] = {
.hsync_end = 80, .hblank_end = 300,
.hblank_start = 1580, .htotal = 1649,
- .progressive = TRUE, .trilevel_sync = TRUE,
+ .progressive = TRUE, .trilevel_sync = TRUE,
.vsync_start_f1 = 10, .vsync_start_f2 = 10,
.vsync_len = 10,
@@ -628,7 +633,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "720p@59.94Hz",
- .clock = 148800,
+ .clock = 148800,
.refresh = 59.94,
.oversample = TV_OVERSAMPLE_2X,
.component_only = 1,
@@ -636,7 +641,7 @@ const static tv_mode_t tv_modes[] = {
.hsync_end = 80, .hblank_end = 300,
.hblank_start = 1580, .htotal = 1651,
- .progressive = TRUE, .trilevel_sync = TRUE,
+ .progressive = TRUE, .trilevel_sync = TRUE,
.vsync_start_f1 = 10, .vsync_start_f2 = 10,
.vsync_len = 10,
@@ -652,7 +657,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "720p@50Hz",
- .clock = 148800,
+ .clock = 148800,
.refresh = 50.0,
.oversample = TV_OVERSAMPLE_2X,
.component_only = 1,
@@ -660,7 +665,7 @@ const static tv_mode_t tv_modes[] = {
.hsync_end = 80, .hblank_end = 300,
.hblank_start = 1580, .htotal = 1979,
- .progressive = TRUE, .trilevel_sync = TRUE,
+ .progressive = TRUE, .trilevel_sync = TRUE,
.vsync_start_f1 = 10, .vsync_start_f2 = 10,
.vsync_len = 10,
@@ -677,7 +682,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "1080i@50Hz",
- .clock = 148800,
+ .clock = 148800,
.refresh = 25.0,
.oversample = TV_OVERSAMPLE_2X,
.component_only = 1,
@@ -685,14 +690,13 @@ const static tv_mode_t tv_modes[] = {
.hsync_end = 88, .hblank_end = 235,
.hblank_start = 2155, .htotal = 2639,
- .progressive = FALSE, .trilevel_sync = TRUE,
+ .progressive = FALSE, .trilevel_sync = TRUE,
- .vsync_start_f1 = 4, .vsync_start_f2 = 5,
+ .vsync_start_f1 = 4, .vsync_start_f2 = 5,
.vsync_len = 10,
- .veq_ena = TRUE, .veq_start_f1 = 4,
- .veq_start_f2 = 4, .veq_len = 10,
-
+ .veq_ena = TRUE, .veq_start_f1 = 4,
+ .veq_start_f2 = 4, .veq_len = 10,
.vi_end_f1 = 21, .vi_end_f2 = 22,
.nbr_end = 539,
@@ -703,7 +707,7 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "1080i@60Hz",
- .clock = 148800,
+ .clock = 148800,
.refresh = 30.0,
.oversample = TV_OVERSAMPLE_2X,
.component_only = 1,
@@ -711,15 +715,14 @@ const static tv_mode_t tv_modes[] = {
.hsync_end = 88, .hblank_end = 235,
.hblank_start = 2155, .htotal = 2199,
- .progressive = FALSE, .trilevel_sync = TRUE,
+ .progressive = FALSE, .trilevel_sync = TRUE,
- .vsync_start_f1 = 4, .vsync_start_f2 = 5,
+ .vsync_start_f1 = 4, .vsync_start_f2 = 5,
.vsync_len = 10,
- .veq_ena = TRUE, .veq_start_f1 = 4,
+ .veq_ena = TRUE, .veq_start_f1 = 4,
.veq_start_f2 = 4, .veq_len = 10,
-
.vi_end_f1 = 21, .vi_end_f2 = 22,
.nbr_end = 539,
@@ -729,24 +732,24 @@ const static tv_mode_t tv_modes[] = {
},
{
.name = "1080i@59.94Hz",
- .clock = 148800,
+ .clock = 148800,
.refresh = 29.97,
.oversample = TV_OVERSAMPLE_2X,
.component_only = 1,
.hsync_end = 88, .hblank_end = 235,
- .hblank_start = 2155, .htotal = 2200,
+ .hblank_start = 2155, .htotal = 2201,
- .progressive = FALSE, .trilevel_sync = TRUE,
+ .progressive = FALSE, .trilevel_sync = TRUE,
- .vsync_start_f1 = 4, .vsync_start_f2 = 5,
+ .vsync_start_f1 = 4, .vsync_start_f2 = 5,
.vsync_len = 10,
.veq_ena = TRUE, .veq_start_f1 = 4,
- .veq_start_f2 = 4, .veq_len = 10,
+ .veq_start_f2 = 4, .veq_len = 10,
- .vi_end_f1 = 21, .vi_end_f2 = 22,
+ .vi_end_f1 = 21, .vi_end_f2 = 22,
.nbr_end = 539,
.burst_ena = FALSE,
@@ -758,7 +761,7 @@ const static tv_mode_t tv_modes[] = {
#define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0])
static const video_levels_t component_level = {
- .blank = 279, .black = 279
+ .blank = 279, .black = 279, .burst = 0,
};
static const color_conversion_t sdtv_component_color = {
@@ -929,8 +932,8 @@ static const tv_mode_t *
i830_tv_mode_lookup (char *tv_format)
{
int i;
-
- for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++)
+
+ for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++)
{
const tv_mode_t *tv_mode = &tv_modes[i];
@@ -953,7 +956,7 @@ static int
i830_tv_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
{
const tv_mode_t *tv_mode = i830_tv_mode_find (output);
-
+
if (tv_mode && fabs (tv_mode->refresh - xf86ModeVRefresh (mode)) < 1.0)
return MODE_OK;
return MODE_CLOCK_RANGE;
@@ -971,8 +974,8 @@ i830_tv_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
if (!tv_mode)
return FALSE;
-
- for (i = 0; i < xf86_config->num_output; i++)
+
+ for (i = 0; i < xf86_config->num_output; i++)
{
xf86OutputPtr other_output = xf86_config->output[i];
@@ -1021,6 +1024,96 @@ i830_float_to_luma (float f)
return ret;
}
+static uint8_t
+float_to_float_2_6(float fin)
+{
+ uint8_t exp;
+ uint8_t mant;
+ float f = fin;
+ uint32_t tmp;
+
+ if (f < 0) f = -f;
+
+ tmp = f;
+ for (exp = 0; exp <= 3 && tmp > 0; exp++)
+ tmp /= 2;
+
+ mant = (f * (1 << 6) + 0.5);
+ mant >>= exp;
+ if (mant > (1 << 6))
+ mant = (1 << 6) - 1;
+
+ return (exp << 6) | mant;
+}
+
+static uint8_t
+float_to_fix_2_6(float f)
+{
+ uint8_t ret;
+
+ ret = f * (1 << 6);
+ return ret;
+}
+
+static void
+i830_tv_update_brightness(I830Ptr pI830, uint8_t brightness)
+{
+ /* brightness in 2's comp value */
+ uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_BRIGHTNESS_MASK;
+ int8_t bri = brightness - 128; /* remove bias */
+
+ val |= (bri << TV_BRIGHTNESS_SHIFT) & TV_BRIGHTNESS_MASK;
+ OUTREG(TV_CLR_KNOBS, val);
+}
+
+static void
+i830_tv_update_contrast(I830Ptr pI830, uint8_t contrast)
+{
+ uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_CONTRAST_MASK;;
+ float con;
+ uint8_t c;
+
+ if (IS_I965G(pI830)) {
+ /* 2.6 fixed point */
+ con = 3.0 * ((float) contrast / 255);
+ c = float_to_fix_2_6(con);
+ } else {
+ /* 2.6 floating point */
+ con = 2.65625 * ((float) contrast / 255);
+ c = float_to_float_2_6(con);
+ }
+ val |= (c << TV_CONTRAST_SHIFT) & TV_CONTRAST_MASK;
+ OUTREG(TV_CLR_KNOBS, val);
+}
+
+static void
+i830_tv_update_saturation(I830Ptr pI830, uint8_t saturation)
+{
+ uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_SATURATION_MASK;
+ float sat;
+ uint8_t s;
+
+ /* same as contrast */
+ if (IS_I965G(pI830)) {
+ sat = 3.0 * ((float) saturation / 255);
+ s = float_to_fix_2_6(sat);
+ } else {
+ sat = 2.65625 * ((float) saturation / 255);
+ s = float_to_float_2_6(sat);
+ }
+ val |= (s << TV_SATURATION_SHIFT) & TV_SATURATION_MASK;
+ OUTREG(TV_CLR_KNOBS, val);
+}
+
+static void
+i830_tv_update_hue(I830Ptr pI830, uint8_t hue)
+{
+ uint32_t val = INREG(TV_CLR_KNOBS) & ~TV_HUE_MASK;
+
+ val |= (hue << TV_HUE_SHIFT) & TV_HUE_MASK;
+ OUTREG(TV_CLR_KNOBS, val);
+}
+
static void
i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
DisplayModePtr adjusted_mode)
@@ -1040,11 +1133,12 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
const video_levels_t *video_levels;
const color_conversion_t *color_conversion;
Bool burst_ena;
-
+
if (!tv_mode)
return; /* can't happen (mode_prepare prevents this) */
-
- tv_ctl = 0;
+
+ tv_ctl = INREG(TV_CTL);
+ tv_ctl &= TV_CTL_SAVE;
switch (dev_priv->type) {
default:
@@ -1181,7 +1275,6 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
(i830_float_to_csc(color_conversion->bv) << 16) |
(i830_float_to_luma(color_conversion->av)));
- OUTREG(TV_CLR_KNOBS, 0x00606000);
OUTREG(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
(video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
{
@@ -1207,7 +1300,7 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
i830WaitForVblank(pScrn);
/* Filter ctl must be set before TV_WIN_SIZE */
- OUTREG(TV_FILTER_CTL_1, TV_AUTO_SCALE);
+ OUTREG(TV_FILTER_CTL_1, TV_AUTO_SCALE);
xsize = tv_mode->hblank_start - tv_mode->hblank_end;
if (tv_mode->progressive)
ysize = tv_mode->nbr_end + 1;
@@ -1216,9 +1309,9 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
xpos += dev_priv->margin[TV_MARGIN_LEFT];
ypos += dev_priv->margin[TV_MARGIN_TOP];
- xsize -= (dev_priv->margin[TV_MARGIN_LEFT] +
+ xsize -= (dev_priv->margin[TV_MARGIN_LEFT] +
dev_priv->margin[TV_MARGIN_RIGHT]);
- ysize -= (dev_priv->margin[TV_MARGIN_TOP] +
+ ysize -= (dev_priv->margin[TV_MARGIN_TOP] +
dev_priv->margin[TV_MARGIN_BOTTOM]);
OUTREG(TV_WIN_POS, (xpos<<16)|ypos);
OUTREG(TV_WIN_SIZE, (xsize<<16)|ysize);
@@ -1227,7 +1320,7 @@ i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
OUTREG(dspcntr_reg, dspcntr);
/* Flush the plane changes */
OUTREG(dspbase_reg, INREG(dspbase_reg));
- }
+ }
j = 0;
for (i = 0; i < 60; i++)
@@ -1365,6 +1458,10 @@ i830_tv_detect(xf86OutputPtr output)
int dpms_mode;
int type = dev_priv->type;
+ /* If TV connector type set by user, always return connected */
+ if (dev_priv->force_type)
+ return XF86OutputStatusConnected;
+
mode = reported_modes[0];
xf86SetModeCrtc (&mode, INTERLACE_HALVE_V);
crtc = i830GetLoadDetectPipe (output, &mode, &dpms_mode);
@@ -1381,7 +1478,7 @@ i830_tv_detect(xf86OutputPtr output)
i830_tv_format_configure_property (output);
#endif
}
-
+
switch (type) {
case TV_TYPE_NONE:
return XF86OutputStatusDisconnected;
@@ -1394,15 +1491,15 @@ i830_tv_detect(xf86OutputPtr output)
static struct input_res {
char *name;
- int w, h;
-} input_res_table[] =
+ int w, h;
+} input_res_table[] =
{
{"640x480", 640, 480},
{"800x600", 800, 600},
- {"1024x768", 1024, 768},
- {"1280x1024", 1280, 1024},
{"848x480", 848, 480},
+ {"1024x768", 1024, 768},
{"1280x720", 1280, 720},
+ {"1280x1024", 1280, 1024},
{"1920x1080", 1920, 1080},
};
@@ -1425,16 +1522,16 @@ i830_tv_get_modes(xf86OutputPtr output)
struct input_res *input = &input_res_table[j];
unsigned int hactive_s = input->w;
unsigned int vactive_s = input->h;
-
+
if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
continue;
- if (input->w > 1024 && (!tv_mode->progressive
+ if (input->w > 1024 && (!tv_mode->progressive
&& !tv_mode->component_only))
continue;
mode_ptr = xnfcalloc(1, sizeof(DisplayModeRec));
- mode_ptr->name = xnfalloc(strlen(input->name) + 1);
+ mode_ptr->name = xnfalloc(strlen(input->name) + 1);
strcpy (mode_ptr->name, input->name);
mode_ptr->HDisplay = hactive_s;
@@ -1451,17 +1548,17 @@ i830_tv_get_modes(xf86OutputPtr output)
mode_ptr->VSyncEnd = mode_ptr->VSyncStart + 1;
mode_ptr->VTotal = vactive_s + 33;
- mode_ptr->Clock = (int) (tv_mode->refresh *
- mode_ptr->VTotal *
+ mode_ptr->Clock = (int) (tv_mode->refresh *
+ mode_ptr->VTotal *
mode_ptr->HTotal / 1000.0);
-
+
mode_ptr->type = M_T_DRIVER;
mode_ptr->next = ret;
mode_ptr->prev = NULL;
if (ret != NULL)
ret->prev = mode_ptr;
ret = mode_ptr;
- }
+ }
return ret;
}
@@ -1482,6 +1579,26 @@ static char *margin_names[4] = {
"LEFT", "TOP", "RIGHT", "BOTTOM"
};
+/**
+ * contrast and saturation has different format on 915/945 with 965.
+ * On 915/945, it's 2.6 floating point number.
+ * On 965, it's 2.6 fixed point number.
+ */
+#define TV_BRIGHTNESS_NAME "BRIGHTNESS"
+#define TV_BRIGHTNESS_DEFAULT 128 /* bias */
+static Atom brightness_atom;
+#define TV_CONTRAST_NAME "CONTRAST"
+#define TV_CONTRAST_DEFAULT 0x40
+#define TV_CONTRAST_DEFAULT_945G 0x60
+static Atom contrast_atom;
+#define TV_SATURATION_NAME "SATURATION"
+#define TV_SATURATION_DEFAULT 0x40
+#define TV_SATURATION_DEFAULT_945G 0x60
+static Atom saturation_atom;
+#define TV_HUE_NAME "HUE"
+#define TV_HUE_DEFAULT 0
+static Atom hue_atom;
+
static Bool
i830_tv_format_set_property (xf86OutputPtr output)
{
@@ -1499,7 +1616,6 @@ i830_tv_format_set_property (xf86OutputPtr output)
return err == Success;
}
-
/**
* Configure the TV_FORMAT property to list only supported formats
*
@@ -1515,19 +1631,75 @@ i830_tv_format_configure_property (xf86OutputPtr output)
Atom current_atoms[NUM_TV_MODES];
int num_atoms = 0;
int i;
-
+
if (!output->randr_output)
return Success;
for (i = 0; i < NUM_TV_MODES; i++)
if (!tv_modes[i].component_only || dev_priv->type == TV_TYPE_COMPONENT)
current_atoms[num_atoms++] = tv_format_name_atoms[i];
-
+
return RRConfigureOutputProperty(output->randr_output, tv_format_atom,
- TRUE, FALSE, FALSE,
+ TRUE, FALSE, FALSE,
num_atoms, (INT32 *) current_atoms);
}
+static void
+i830_tv_color_set_property(xf86OutputPtr output, Atom property,
+ uint8_t val)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830OutputPrivatePtr intel_output = output->driver_private;
+ struct i830_tv_priv *dev_priv = intel_output->dev_priv;
+
+ if (property == brightness_atom) {
+ dev_priv->brightness = val;
+ i830_tv_update_brightness(pI830, val);
+ } else if (property == contrast_atom) {
+ dev_priv->contrast = val;
+ i830_tv_update_contrast(pI830, val);
+ } else if (property == saturation_atom) {
+ dev_priv->saturation = val;
+ i830_tv_update_saturation(pI830, val);
+ } else if (property == hue_atom) {
+ dev_priv->hue = val;
+ i830_tv_update_hue(pI830, val);
+ }
+}
+
+static void
+i830_tv_color_create_property(xf86OutputPtr output, Atom *property,
+ char *name, int name_len, uint8_t val)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ INT32 range[2];
+ int err = 0;
+
+ *property = MakeAtom(name, name_len - 1, TRUE);
+ range[0] = 0;
+ range[1] = 255;
+ err = RRConfigureOutputProperty(output->randr_output, *property,
+ FALSE, TRUE, FALSE, 2, range);
+ if (err != 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "RRConfigureOutputProperty error, %d\n", err);
+ goto out;
+ }
+ /* Set the current value */
+ i830_tv_color_set_property(output, *property, val);
+
+ err = RRChangeOutputProperty(output->randr_output, *property,
+ XA_INTEGER, 32, PropModeReplace, 1, &val,
+ FALSE, FALSE);
+ if (err != 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "RRChangeOutputProperty error, %d\n", err);
+ }
+out:
+ return;
+}
+
#endif /* RANDR_12_INTERFACE */
static void
@@ -1535,10 +1707,10 @@ i830_tv_create_resources(xf86OutputPtr output)
{
#ifdef RANDR_12_INTERFACE
ScrnInfoPtr pScrn = output->scrn;
+ I830Ptr pI830 = I830PTR(pScrn);
I830OutputPrivatePtr intel_output = output->driver_private;
struct i830_tv_priv *dev_priv = intel_output->dev_priv;
- int err;
- int i;
+ int err, i;
/* Set up the tv_format property, which takes effect on mode set
* and accepts strings that match exactly
@@ -1573,7 +1745,7 @@ i830_tv_create_resources(xf86OutputPtr output)
range[1] = 100;
err = RRConfigureOutputProperty(output->randr_output, margin_atoms[i],
TRUE, TRUE, FALSE, 2, range);
-
+
if (err != 0)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"RRConfigureOutputProperty error, %d\n", err);
@@ -1586,6 +1758,23 @@ i830_tv_create_resources(xf86OutputPtr output)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"RRChangeOutputProperty error, %d\n", err);
}
+
+ i830_tv_color_create_property(output, &brightness_atom,
+ TV_BRIGHTNESS_NAME,
+ sizeof(TV_BRIGHTNESS_NAME),
+ TV_BRIGHTNESS_DEFAULT);
+ i830_tv_color_create_property(output, &contrast_atom,
+ TV_CONTRAST_NAME,
+ sizeof(TV_CONTRAST_NAME),
+ IS_I965G(pI830) ? TV_CONTRAST_DEFAULT :
+ TV_CONTRAST_DEFAULT_945G);
+ i830_tv_color_create_property(output, &saturation_atom,
+ TV_SATURATION_NAME,
+ sizeof(TV_SATURATION_NAME),
+ IS_I965G(pI830) ? TV_SATURATION_DEFAULT :
+ TV_SATURATION_DEFAULT_945G);
+ i830_tv_color_create_property(output, &hue_atom, TV_HUE_NAME,
+ sizeof(TV_HUE_NAME), TV_HUE_DEFAULT);
#endif /* RANDR_12_INTERFACE */
}
@@ -1595,21 +1784,26 @@ i830_tv_set_property(xf86OutputPtr output, Atom property,
RRPropertyValuePtr value)
{
int i;
-
- if (property == tv_format_atom)
+
+ if (property == tv_format_atom)
{
I830OutputPrivatePtr intel_output = output->driver_private;
struct i830_tv_priv *dev_priv = intel_output->dev_priv;
+ I830Ptr pI830 = I830PTR(output->scrn);
Atom atom;
- char *name;
+ const char *name;
char *val;
+ RRCrtcPtr randr_crtc;
+ xRRModeInfo modeinfo;
+ RRModePtr mode;
+ DisplayModePtr crtc_mode;
if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
return FALSE;
memcpy (&atom, value->data, 4);
name = NameForAtom (atom);
-
+
val = xalloc (strlen (name) + 1);
if (!val)
return FALSE;
@@ -1621,6 +1815,51 @@ i830_tv_set_property(xf86OutputPtr output, Atom property,
}
xfree (dev_priv->tv_format);
dev_priv->tv_format = val;
+
+ if (pI830->starting)
+ return TRUE;
+
+ /* TV format change will generate new modelines, try
+ to probe them and update outputs. */
+ xf86ProbeOutputModes(output->scrn, 0, 0);
+ /* Mirror output modes to scrn mode list */
+ xf86SetScrnInfoModes (output->scrn);
+
+ for (crtc_mode = output->probed_modes; crtc_mode;
+ crtc_mode = crtc_mode->next)
+ {
+ if (output->crtc->mode.HDisplay == crtc_mode->HDisplay &&
+ output->crtc->mode.VDisplay == crtc_mode->VDisplay)
+ break;
+ }
+ if (!crtc_mode)
+ crtc_mode = output->probed_modes;
+
+ xf86CrtcSetMode(output->crtc, crtc_mode, output->crtc->rotation,
+ output->crtc->x, output->crtc->y);
+
+ xf86RandR12TellChanged(output->scrn->pScreen);
+
+ modeinfo.width = crtc_mode->HDisplay;
+ modeinfo.height = crtc_mode->VDisplay;
+ modeinfo.dotClock = crtc_mode->Clock * 1000;
+ modeinfo.hSyncStart = crtc_mode->HSyncStart;
+ modeinfo.hSyncEnd = crtc_mode->HSyncEnd;
+ modeinfo.hTotal = crtc_mode->HTotal;
+ modeinfo.hSkew = crtc_mode->HSkew;
+ modeinfo.vSyncStart = crtc_mode->VSyncStart;
+ modeinfo.vSyncEnd = crtc_mode->VSyncEnd;
+ modeinfo.vTotal = crtc_mode->VTotal;
+ modeinfo.nameLength = strlen(crtc_mode->name);
+ modeinfo.modeFlags = crtc_mode->Flags;
+
+ mode = RRModeGet(&modeinfo, crtc_mode->name);
+ randr_crtc = output->crtc->randr_crtc;
+ if (mode != randr_crtc->mode) {
+ if (randr_crtc->mode)
+ RRModeDestroy(randr_crtc->mode);
+ randr_crtc->mode = mode;
+ }
return TRUE;
}
for (i = 0; i < 4; i++)
@@ -1640,6 +1879,18 @@ i830_tv_set_property(xf86OutputPtr output, Atom property,
return TRUE;
}
}
+ if (property == brightness_atom || property == contrast_atom ||
+ property == saturation_atom || property == hue_atom) {
+ uint8_t val;
+
+ /* Make sure value is sane */
+ if (value->type != XA_INTEGER || value->format != 32 ||
+ value->size != 1)
+ return FALSE;
+
+ memcpy (&val, value->data, 1);
+ i830_tv_color_set_property(output, property, val);
+ }
return TRUE;
}
@@ -1652,7 +1903,7 @@ i830_tv_get_crtc(xf86OutputPtr output)
ScrnInfoPtr pScrn = output->scrn;
I830Ptr pI830 = I830PTR(pScrn);
int pipe = !!(INREG(TV_CTL) & TV_ENC_PIPEB_SELECT);
-
+
return i830_pipe_to_crtc(pScrn, pipe);
}
#endif
@@ -1686,6 +1937,9 @@ i830_tv_init(ScrnInfoPtr pScrn)
I830OutputPrivatePtr intel_output;
struct i830_tv_priv *dev_priv;
uint32_t tv_dac_on, tv_dac_off, save_tv_dac;
+ XF86OptionPtr mon_option_lst = NULL;
+ char *tv_format = NULL;
+ char *tv_type = NULL;
if (pI830->quirk_flag & QUIRK_IGNORE_TV)
return;
@@ -1712,7 +1966,7 @@ i830_tv_init(ScrnInfoPtr pScrn)
* bit, (either as a 0 or a 1), assume it doesn't really
* exist
*/
- if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
+ if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
(tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
return;
@@ -1739,24 +1993,46 @@ i830_tv_init(ScrnInfoPtr pScrn)
dev_priv->type = TV_TYPE_UNKNOWN;
dev_priv->tv_format = NULL;
-
- /* BIOS margin values */
- dev_priv->margin[TV_MARGIN_LEFT] = 54;
- dev_priv->margin[TV_MARGIN_TOP] = 36;
- dev_priv->margin[TV_MARGIN_RIGHT] = 46;
- dev_priv->margin[TV_MARGIN_BOTTOM] = 37;
-
+
if (output->conf_monitor)
- {
- char *tv_format;
-
- tv_format = xf86findOptionValue (output->conf_monitor->mon_option_lst, "TV Format");
- if (tv_format)
- dev_priv->tv_format = xstrdup (tv_format);
- }
- if (!dev_priv->tv_format)
+ mon_option_lst = output->conf_monitor->mon_option_lst;
+
+ /* BIOS margin values */
+ dev_priv->margin[TV_MARGIN_LEFT] = xf86SetIntOption (mon_option_lst,
+ "Left", 54);
+ dev_priv->margin[TV_MARGIN_TOP] = xf86SetIntOption (mon_option_lst,
+ "Top", 36);
+ dev_priv->margin[TV_MARGIN_RIGHT] = xf86SetIntOption (mon_option_lst,
+ "Right", 46);
+ dev_priv->margin[TV_MARGIN_BOTTOM] = xf86SetIntOption (mon_option_lst,
+ "Bottom", 37);
+
+ tv_format = xf86findOptionValue (mon_option_lst, "TV_Format");
+ if (tv_format)
+ dev_priv->tv_format = xstrdup (tv_format);
+ else
dev_priv->tv_format = xstrdup (tv_modes[0].name);
-
+
+ tv_type = xf86findOptionValue (mon_option_lst, "TV_Connector");
+ if (tv_type) {
+ dev_priv->force_type = TRUE;
+ if (strcasecmp(tv_type, "S-Video") == 0)
+ dev_priv->type = TV_TYPE_SVIDEO;
+ else if (strcasecmp(tv_type, "Composite") == 0)
+ dev_priv->type = TV_TYPE_COMPOSITE;
+ else if (strcasecmp(tv_type, "Component") == 0)
+ dev_priv->type = TV_TYPE_COMPONENT;
+ else {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Unknown TV Connector type %s\n", tv_type);
+ dev_priv->force_type = FALSE;
+ }
+ }
+
+ if (dev_priv->force_type)
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Force TV Connector type as %s\n", tv_type);
+
output->driver_private = intel_output;
output->interlaceAllowed = FALSE;
output->doubleScanAllowed = FALSE;