Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[linux-2.6.git] / drivers / gpu / drm / i915 / intel_tv.c
index 56485d6..c64eab4 100644 (file)
@@ -217,8 +217,8 @@ static const u32 filter_table[] = {
  */
 static const struct color_conversion ntsc_m_csc_composite = {
        .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
-       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
-       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
 };
 
 static const struct video_levels ntsc_m_levels_composite = {
@@ -226,9 +226,9 @@ static const struct video_levels ntsc_m_levels_composite = {
 };
 
 static const struct color_conversion ntsc_m_csc_svideo = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
-       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
-       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
 };
 
 static const struct video_levels ntsc_m_levels_svideo = {
@@ -237,8 +237,8 @@ static const struct video_levels ntsc_m_levels_svideo = {
 
 static const struct color_conversion ntsc_j_csc_composite = {
        .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
-       .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0f00,
-       .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0f00,
+       .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
+       .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
 };
 
 static const struct video_levels ntsc_j_levels_composite = {
@@ -247,8 +247,8 @@ static const struct video_levels ntsc_j_levels_composite = {
 
 static const struct color_conversion ntsc_j_csc_svideo = {
        .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
-       .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0f00,
-       .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0f00,
+       .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
+       .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
 };
 
 static const struct video_levels ntsc_j_levels_svideo = {
@@ -257,8 +257,8 @@ static const struct video_levels ntsc_j_levels_svideo = {
 
 static const struct color_conversion pal_csc_composite = {
        .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
-       .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0f00,
-       .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0f00,
+       .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
+       .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
 };
 
 static const struct video_levels pal_levels_composite = {
@@ -267,8 +267,8 @@ static const struct video_levels pal_levels_composite = {
 
 static const struct color_conversion pal_csc_svideo = {
        .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
-       .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0f00,
-       .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0f00,
+       .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
+       .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
 };
 
 static const struct video_levels pal_levels_svideo = {
@@ -277,8 +277,8 @@ static const struct video_levels pal_levels_svideo = {
 
 static const struct color_conversion pal_m_csc_composite = {
        .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
-       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
-       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
 };
 
 static const struct video_levels pal_m_levels_composite = {
@@ -286,9 +286,9 @@ static const struct video_levels pal_m_levels_composite = {
 };
 
 static const struct color_conversion pal_m_csc_svideo = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
-       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
-       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
 };
 
 static const struct video_levels pal_m_levels_svideo = {
@@ -297,8 +297,8 @@ static const struct video_levels pal_m_levels_svideo = {
 
 static const struct color_conversion pal_n_csc_composite = {
        .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
-       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
-       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
 };
 
 static const struct video_levels pal_n_levels_composite = {
@@ -306,9 +306,9 @@ static const struct video_levels pal_n_levels_composite = {
 };
 
 static const struct color_conversion pal_n_csc_svideo = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
-       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
-       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
 };
 
 static const struct video_levels pal_n_levels_svideo = {
@@ -319,9 +319,9 @@ static const struct video_levels pal_n_levels_svideo = {
  * Component connections
  */
 static const struct color_conversion sdtv_csc_yprpb = {
-       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0146,
-       .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0f00,
-       .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0f00,
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
+       .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
+       .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
 };
 
 static const struct color_conversion sdtv_csc_rgb = {
@@ -331,9 +331,9 @@ static const struct color_conversion sdtv_csc_rgb = {
 };
 
 static const struct color_conversion hdtv_csc_yprpb = {
-       .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0146,
-       .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0f00,
-       .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0f00,
+       .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
+       .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
+       .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
 };
 
 static const struct color_conversion hdtv_csc_rgb = {
@@ -414,7 +414,7 @@ struct tv_mode {
 static const struct tv_mode tv_modes[] = {
        {
                .name           = "NTSC-M",
-               .clock          = 107520,
+               .clock          = 108000,
                .refresh        = 29970,
                .oversample     = TV_OVERSAMPLE_8X,
                .component_only = 0,
@@ -442,8 +442,8 @@ static const struct tv_mode tv_modes[] = {
                .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,
@@ -457,7 +457,7 @@ static const struct tv_mode tv_modes[] = {
        },
        {
                .name           = "NTSC-443",
-               .clock          = 107520,
+               .clock          = 108000,
                .refresh        = 29970,
                .oversample     = TV_OVERSAMPLE_8X,
                .component_only = 0,
@@ -485,10 +485,10 @@ static const struct tv_mode tv_modes[] = {
 
                /* 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 = &ntsc_m_levels_composite,
                .composite_color = &ntsc_m_csc_composite,
@@ -499,7 +499,7 @@ static const struct tv_mode tv_modes[] = {
        },
        {
                .name           = "NTSC-J",
-               .clock          = 107520,
+               .clock          = 108000,
                .refresh        = 29970,
                .oversample     = TV_OVERSAMPLE_8X,
                .component_only = 0,
@@ -527,8 +527,8 @@ static const struct tv_mode tv_modes[] = {
                .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,
@@ -542,7 +542,7 @@ static const struct tv_mode tv_modes[] = {
        },
        {
                .name           = "PAL-M",
-               .clock          = 107520,
+               .clock          = 108000,
                .refresh        = 29970,
                .oversample     = TV_OVERSAMPLE_8X,
                .component_only = 0,
@@ -570,11 +570,11 @@ static const struct tv_mode tv_modes[] = {
                .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 = &pal_m_levels_composite,
                .composite_color = &pal_m_csc_composite,
@@ -586,7 +586,7 @@ static const struct tv_mode tv_modes[] = {
        {
                /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
                .name       = "PAL-N",
-               .clock          = 107520,
+               .clock          = 108000,
                .refresh        = 25000,
                .oversample     = TV_OVERSAMPLE_8X,
                .component_only = 0,
@@ -615,9 +615,9 @@ static const struct tv_mode tv_modes[] = {
 
 
                /* 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,
 
@@ -631,12 +631,12 @@ static const struct tv_mode tv_modes[] = {
        {
                /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
                .name       = "PAL",
-               .clock          = 107520,
+               .clock          = 108000,
                .refresh        = 25000,
                .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,
@@ -659,8 +659,8 @@ static const struct tv_mode tv_modes[] = {
 
                /* 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,
 
@@ -689,7 +689,7 @@ static const struct tv_mode tv_modes[] = {
                .veq_ena        = false,
 
                .vi_end_f1      = 44,               .vi_end_f2          = 44,
-               .nbr_end        = 496,
+               .nbr_end        = 479,
 
                .burst_ena      = false,
 
@@ -713,7 +713,7 @@ static const struct tv_mode tv_modes[] = {
                .veq_ena        = false,
 
                .vi_end_f1      = 44,               .vi_end_f2          = 44,
-               .nbr_end        = 496,
+               .nbr_end        = 479,
 
                .burst_ena      = false,
 
@@ -876,7 +876,7 @@ static const struct tv_mode tv_modes[] = {
                .component_only = 1,
 
                .hsync_end      = 88,               .hblank_end         = 235,
-               .hblank_start   = 2155,             .htotal             = 2200,
+               .hblank_start   = 2155,             .htotal             = 2201,
 
                .progressive    = false,            .trilevel_sync = true,
 
@@ -1082,7 +1082,7 @@ intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mo
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
 
        /* Ensure TV refresh is close to desired refresh */
-       if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1)
+       if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 10)
                return MODE_OK;
        return MODE_CLOCK_RANGE;
 }
@@ -1135,7 +1135,8 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        if (!tv_mode)
                return; /* can't happen (mode_prepare prevents this) */
 
-       tv_ctl = 0;
+       tv_ctl = I915_READ(TV_CTL);
+       tv_ctl &= TV_CTL_SAVE;
 
        switch (tv_priv->type) {
        default:
@@ -1215,7 +1216,6 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        /* dda1 implies valid video levels */
        if (tv_mode->dda1_inc) {
                scctl1 |= TV_SC_DDA1_EN;
-               scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
        }
 
        if (tv_mode->dda2_inc)
@@ -1225,6 +1225,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                scctl1 |= TV_SC_DDA3_EN;
 
        scctl1 |= tv_mode->sc_reset;
+       scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
        scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
 
        scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
@@ -1266,7 +1267,11 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                           color_conversion->av);
        }
 
-       I915_WRITE(TV_CLR_KNOBS, 0x00606000);
+       if (IS_I965G(dev))
+               I915_WRITE(TV_CLR_KNOBS, 0x00404000);
+       else
+               I915_WRITE(TV_CLR_KNOBS, 0x00606000);
+
        if (video_levels)
                I915_WRITE(TV_CLR_LEVEL,
                           ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
@@ -1378,30 +1383,31 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
        /*
         * Detect TV by polling)
         */
-       if (intel_output->load_detect_temp) {
-               /* TV not currently running, prod it with destructive detect */
-               save_tv_dac = tv_dac;
-               tv_ctl = I915_READ(TV_CTL);
-               save_tv_ctl = tv_ctl;
-               tv_ctl &= ~TV_ENC_ENABLE;
-               tv_ctl &= ~TV_TEST_MODE_MASK;
-               tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
-               tv_dac &= ~TVDAC_SENSE_MASK;
-               tv_dac |= (TVDAC_STATE_CHG_EN |
-                          TVDAC_A_SENSE_CTL |
-                          TVDAC_B_SENSE_CTL |
-                          TVDAC_C_SENSE_CTL |
-                          DAC_CTL_OVERRIDE |
-                          DAC_A_0_7_V |
-                          DAC_B_0_7_V |
-                          DAC_C_0_7_V);
-               I915_WRITE(TV_CTL, tv_ctl);
-               I915_WRITE(TV_DAC, tv_dac);
-               intel_wait_for_vblank(dev);
-               tv_dac = I915_READ(TV_DAC);
-               I915_WRITE(TV_DAC, save_tv_dac);
-               I915_WRITE(TV_CTL, save_tv_ctl);
-       }
+       save_tv_dac = tv_dac;
+       tv_ctl = I915_READ(TV_CTL);
+       save_tv_ctl = tv_ctl;
+       tv_ctl &= ~TV_ENC_ENABLE;
+       tv_ctl &= ~TV_TEST_MODE_MASK;
+       tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
+       tv_dac &= ~TVDAC_SENSE_MASK;
+       tv_dac &= ~DAC_A_MASK;
+       tv_dac &= ~DAC_B_MASK;
+       tv_dac &= ~DAC_C_MASK;
+       tv_dac |= (TVDAC_STATE_CHG_EN |
+                  TVDAC_A_SENSE_CTL |
+                  TVDAC_B_SENSE_CTL |
+                  TVDAC_C_SENSE_CTL |
+                  DAC_CTL_OVERRIDE |
+                  DAC_A_0_7_V |
+                  DAC_B_0_7_V |
+                  DAC_C_0_7_V);
+       I915_WRITE(TV_CTL, tv_ctl);
+       I915_WRITE(TV_DAC, tv_dac);
+       intel_wait_for_vblank(dev);
+       tv_dac = I915_READ(TV_DAC);
+       I915_WRITE(TV_DAC, save_tv_dac);
+       I915_WRITE(TV_CTL, save_tv_ctl);
+       intel_wait_for_vblank(dev);
        /*
         *  A B C
         *  0 1 1 Composite
@@ -1431,6 +1437,35 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
        return type;
 }
 
+/*
+ * Here we set accurate tv format according to connector type
+ * i.e Component TV should not be assigned by NTSC or PAL
+ */
+static void intel_tv_find_better_format(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+       int i;
+
+       if ((tv_priv->type == DRM_MODE_CONNECTOR_Component) ==
+               tv_mode->component_only)
+               return;
+
+
+       for (i = 0; i < sizeof(tv_modes) / sizeof(*tv_modes); i++) {
+               tv_mode = tv_modes + i;
+
+               if ((tv_priv->type == DRM_MODE_CONNECTOR_Component) ==
+                       tv_mode->component_only)
+                       break;
+       }
+
+       tv_priv->tv_format = tv_mode->name;
+       drm_connector_property_set_value(connector,
+               connector->dev->mode_config.tv_mode_property, i);
+}
+
 /**
  * Detect the TV connection.
  *
@@ -1451,7 +1486,7 @@ intel_tv_detect(struct drm_connector *connector)
        mode = reported_modes[0];
        drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
 
-       if (encoder->crtc) {
+       if (encoder->crtc && encoder->crtc->enabled) {
                type = intel_tv_detect_type(encoder->crtc, intel_output);
        } else {
                crtc = intel_get_load_detect_pipe(intel_output, &mode, &dpms_mode);
@@ -1462,9 +1497,12 @@ intel_tv_detect(struct drm_connector *connector)
                        type = -1;
        }
 
+       tv_priv->type = type;
+
        if (type < 0)
                return connector_status_disconnected;
 
+       intel_tv_find_better_format(connector);
        return connector_status_connected;
 }
 
@@ -1482,6 +1520,27 @@ static struct input_res {
        {"1920x1080", 1920, 1080},
 };
 
+/*
+ * Chose preferred mode  according to line number of TV format
+ */
+static void
+intel_tv_chose_preferred_modes(struct drm_connector *connector,
+                              struct drm_display_mode *mode_ptr)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+
+       if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
+               mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
+       else if (tv_mode->nbr_end > 480) {
+               if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
+                       if (mode_ptr->vdisplay == 720)
+                               mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
+               } else if (mode_ptr->vdisplay == 1080)
+                               mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
+       }
+}
+
 /**
  * Stub get_modes function.
  *
@@ -1495,7 +1554,8 @@ intel_tv_get_modes(struct drm_connector *connector)
        struct drm_display_mode *mode_ptr;
        struct intel_output *intel_output = to_intel_output(connector);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
-       int j;
+       int j, count = 0;
+       u64 tmp;
 
        for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]);
             j++) {
@@ -1510,8 +1570,9 @@ intel_tv_get_modes(struct drm_connector *connector)
                                        && !tv_mode->component_only))
                        continue;
 
-               mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode),
-                                     DRM_MEM_DRIVER);
+               mode_ptr = drm_mode_create(connector->dev);
+               if (!mode_ptr)
+                       continue;
                strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
 
                mode_ptr->hdisplay = hactive_s;
@@ -1528,15 +1589,18 @@ intel_tv_get_modes(struct drm_connector *connector)
                        mode_ptr->vsync_end = mode_ptr->vsync_start  + 1;
                mode_ptr->vtotal = vactive_s + 33;
 
-               mode_ptr->clock = (int) (tv_mode->refresh *
-                                        mode_ptr->vtotal *
-                                        mode_ptr->htotal / 1000) / 1000;
+               tmp = (u64) tv_mode->refresh * mode_ptr->vtotal;
+               tmp *= mode_ptr->htotal;
+               tmp = div_u64(tmp, 1000000);
+               mode_ptr->clock = (int) tmp;
 
                mode_ptr->type = DRM_MODE_TYPE_DRIVER;
+               intel_tv_chose_preferred_modes(connector, mode_ptr);
                drm_mode_probed_add(connector, mode_ptr);
+               count++;
        }
 
-       return 0;
+       return count;
 }
 
 static void
@@ -1546,8 +1610,7 @@ intel_tv_destroy (struct drm_connector *connector)
 
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
-       drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv),
-                DRM_MEM_DRIVER);
+       kfree(intel_output);
 }
 
 
@@ -1558,33 +1621,49 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
        struct drm_device *dev = connector->dev;
        struct intel_output *intel_output = to_intel_output(connector);
        struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       struct drm_encoder *encoder = &intel_output->enc;
+       struct drm_crtc *crtc = encoder->crtc;
        int ret = 0;
+       bool changed = false;
 
        ret = drm_connector_property_set_value(connector, property, val);
        if (ret < 0)
                goto out;
 
-       if (property == dev->mode_config.tv_left_margin_property)
+       if (property == dev->mode_config.tv_left_margin_property &&
+               tv_priv->margin[TV_MARGIN_LEFT] != val) {
                tv_priv->margin[TV_MARGIN_LEFT] = val;
-       else if (property == dev->mode_config.tv_right_margin_property)
+               changed = true;
+       } else if (property == dev->mode_config.tv_right_margin_property &&
+               tv_priv->margin[TV_MARGIN_RIGHT] != val) {
                tv_priv->margin[TV_MARGIN_RIGHT] = val;
-       else if (property == dev->mode_config.tv_top_margin_property)
+               changed = true;
+       } else if (property == dev->mode_config.tv_top_margin_property &&
+               tv_priv->margin[TV_MARGIN_TOP] != val) {
                tv_priv->margin[TV_MARGIN_TOP] = val;
-       else if (property == dev->mode_config.tv_bottom_margin_property)
+               changed = true;
+       } else if (property == dev->mode_config.tv_bottom_margin_property &&
+               tv_priv->margin[TV_MARGIN_BOTTOM] != val) {
                tv_priv->margin[TV_MARGIN_BOTTOM] = val;
-       else if (property == dev->mode_config.tv_mode_property) {
+               changed = true;
+       } else if (property == dev->mode_config.tv_mode_property) {
                if (val >= NUM_TV_MODES) {
                        ret = -EINVAL;
                        goto out;
                }
+               if (!strcmp(tv_priv->tv_format, tv_modes[val].name))
+                       goto out;
+
                tv_priv->tv_format = tv_modes[val].name;
-               intel_tv_mode_set(&intel_output->enc, NULL, NULL);
+               changed = true;
        } else {
                ret = -EINVAL;
                goto out;
        }
 
-       intel_tv_mode_set(&intel_output->enc, NULL, NULL);
+       if (changed && crtc)
+               drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
+                               crtc->y, crtc->fb);
 out:
        return ret;
 }
@@ -1598,6 +1677,7 @@ static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
 };
 
 static const struct drm_connector_funcs intel_tv_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
        .save = intel_tv_save,
        .restore = intel_tv_restore,
        .detect = intel_tv_detect,
@@ -1663,11 +1743,12 @@ intel_tv_init(struct drm_device *dev)
            (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
                return;
 
-       intel_output = drm_calloc(1, sizeof(struct intel_output) +
-                                 sizeof(struct intel_tv_priv), DRM_MEM_DRIVER);
+       intel_output = kzalloc(sizeof(struct intel_output) +
+                              sizeof(struct intel_tv_priv), GFP_KERNEL);
        if (!intel_output) {
                return;
        }
+
        connector = &intel_output->base;
 
        drm_connector_init(dev, connector, &intel_tv_connector_funcs,
@@ -1679,6 +1760,8 @@ intel_tv_init(struct drm_device *dev)
        drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
        tv_priv = (struct intel_tv_priv *)(intel_output + 1);
        intel_output->type = INTEL_OUTPUT_TVOUT;
+       intel_output->crtc_mask = (1 << 0) | (1 << 1);
+       intel_output->clone_mask = (1 << INTEL_TV_CLONE_BIT);
        intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1));
        intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
        intel_output->dev_priv = tv_priv;
@@ -1698,8 +1781,8 @@ intel_tv_init(struct drm_device *dev)
        connector->doublescan_allowed = false;
 
        /* Create TV properties then attach current values */
-       tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES,
-                                   DRM_MEM_DRIVER);
+       tv_format_names = kmalloc(sizeof(char *) * NUM_TV_MODES,
+                                 GFP_KERNEL);
        if (!tv_format_names)
                goto out;
        for (i = 0; i < NUM_TV_MODES; i++)