diff options
Diffstat (limited to 'driver/xf86-video-intel/src/i830_tv.c')
-rw-r--r-- | driver/xf86-video-intel/src/i830_tv.c | 526 |
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; |