Merge branch 'pm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspe...
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / i915 / intel_lvds.c
index 0a2e600..4fbb016 100644 (file)
 #include <linux/acpi.h>
 
 /* Private structure for the integrated LVDS support */
-struct intel_lvds_priv {
+struct intel_lvds {
+       struct intel_encoder base;
        int fitting_mode;
        u32 pfit_control;
        u32 pfit_pgm_ratios;
 };
 
+static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
+{
+       return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base);
+}
+
 /**
  * Sets the backlight level.
  *
@@ -90,7 +96,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
 static void intel_lvds_set_power(struct drm_device *dev, bool on)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pp_status, ctl_reg, status_reg, lvds_reg;
+       u32 ctl_reg, status_reg, lvds_reg;
 
        if (HAS_PCH_SPLIT(dev)) {
                ctl_reg = PCH_PP_CONTROL;
@@ -108,9 +114,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
 
                I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
                           POWER_TARGET_ON);
-               do {
-                       pp_status = I915_READ(status_reg);
-               } while ((pp_status & PP_ON) == 0);
+               if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0))
+                       DRM_ERROR("timed out waiting to enable LVDS pipe");
 
                intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
        } else {
@@ -118,9 +123,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
 
                I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
                           ~POWER_TARGET_ON);
-               do {
-                       pp_status = I915_READ(status_reg);
-               } while (pp_status & PP_ON);
+               if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0))
+                       DRM_ERROR("timed out waiting for LVDS pipe to turn off");
 
                I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
                POSTING_READ(lvds_reg);
@@ -219,9 +223,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
        struct drm_encoder *tmp_encoder;
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-       struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
        u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
 
        /* Should never happen!! */
@@ -241,26 +244,20 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        /* If we don't have a panel mode, there is nothing we can do */
        if (dev_priv->panel_fixed_mode == NULL)
                return true;
+
        /*
         * We have timings from the BIOS for the panel, put them in
         * to the adjusted mode.  The CRTC will be set up for this mode,
         * with the panel scaling set up to source from the H/VDisplay
         * of the original mode.
         */
-       adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay;
-       adjusted_mode->hsync_start =
-               dev_priv->panel_fixed_mode->hsync_start;
-       adjusted_mode->hsync_end =
-               dev_priv->panel_fixed_mode->hsync_end;
-       adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal;
-       adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay;
-       adjusted_mode->vsync_start =
-               dev_priv->panel_fixed_mode->vsync_start;
-       adjusted_mode->vsync_end =
-               dev_priv->panel_fixed_mode->vsync_end;
-       adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal;
-       adjusted_mode->clock = dev_priv->panel_fixed_mode->clock;
-       drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+       intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
+
+       if (HAS_PCH_SPLIT(dev)) {
+               intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
+                                       mode, adjusted_mode);
+               return true;
+       }
 
        /* Make sure pre-965s set dither correctly */
        if (!IS_I965G(dev)) {
@@ -273,10 +270,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
            adjusted_mode->vdisplay == mode->vdisplay)
                goto out;
 
-       /* full screen scale for now */
-       if (HAS_PCH_SPLIT(dev))
-               goto out;
-
        /* 965+ wants fuzzy fitting */
        if (IS_I965G(dev))
                pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
@@ -288,12 +281,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
         * to register description and PRM.
         * Change the value here to see the borders for debugging
         */
-       if (!HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(BCLRPAT_A, 0);
-               I915_WRITE(BCLRPAT_B, 0);
-       }
+       I915_WRITE(BCLRPAT_A, 0);
+       I915_WRITE(BCLRPAT_B, 0);
 
-       switch (lvds_priv->fitting_mode) {
+       switch (intel_lvds->fitting_mode) {
        case DRM_MODE_SCALE_CENTER:
                /*
                 * For centered modes, we have to calculate border widths &
@@ -378,8 +369,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        }
 
 out:
-       lvds_priv->pfit_control = pfit_control;
-       lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios;
+       intel_lvds->pfit_control = pfit_control;
+       intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
        dev_priv->lvds_border_bits = border;
 
        /*
@@ -427,8 +418,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
 {
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-       struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
+       struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
 
        /*
         * The LVDS pin pair will already have been turned on in the
@@ -444,8 +434,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
         * screen.  Should be enabled before the pipe is enabled, according to
         * register description and PRM.
         */
-       I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios);
-       I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control);
+       I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
+       I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
 }
 
 /**
@@ -600,18 +590,17 @@ static int intel_lvds_set_property(struct drm_connector *connector,
                                connector->encoder) {
                struct drm_crtc *crtc = connector->encoder->crtc;
                struct drm_encoder *encoder = connector->encoder;
-               struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-               struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
+               struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
 
                if (value == DRM_MODE_SCALE_NONE) {
                        DRM_DEBUG_KMS("no scaling not supported\n");
                        return 0;
                }
-               if (lvds_priv->fitting_mode == value) {
+               if (intel_lvds->fitting_mode == value) {
                        /* the LVDS scaling property is not changed */
                        return 0;
                }
-               lvds_priv->fitting_mode = value;
+               intel_lvds->fitting_mode = value;
                if (crtc && crtc->enabled) {
                        /*
                         * If the CRTC is enabled, the display will be changed
@@ -647,19 +636,8 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
        .destroy = intel_lvds_destroy,
 };
 
-
-static void intel_lvds_enc_destroy(struct drm_encoder *encoder)
-{
-       struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
-       if (intel_encoder->ddc_bus)
-               intel_i2c_destroy(intel_encoder->ddc_bus);
-       drm_encoder_cleanup(encoder);
-       kfree(intel_encoder);
-}
-
 static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
-       .destroy = intel_lvds_enc_destroy,
+       .destroy = intel_encoder_destroy,
 };
 
 static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
@@ -843,13 +821,13 @@ static int lvds_is_present_in_vbt(struct drm_device *dev)
 void intel_lvds_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_lvds *intel_lvds;
        struct intel_encoder *intel_encoder;
        struct intel_connector *intel_connector;
        struct drm_connector *connector;
        struct drm_encoder *encoder;
        struct drm_display_mode *scan; /* *modes, *bios_mode; */
        struct drm_crtc *crtc;
-       struct intel_lvds_priv *lvds_priv;
        u32 lvds;
        int pipe, gpio = GPIOC;
 
@@ -872,20 +850,20 @@ void intel_lvds_init(struct drm_device *dev)
                gpio = PCH_GPIOC;
        }
 
-       intel_encoder = kzalloc(sizeof(struct intel_encoder) +
-                               sizeof(struct intel_lvds_priv), GFP_KERNEL);
-       if (!intel_encoder) {
+       intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL);
+       if (!intel_lvds) {
                return;
        }
 
        intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
        if (!intel_connector) {
-               kfree(intel_encoder);
+               kfree(intel_lvds);
                return;
        }
 
-       connector = &intel_connector->base;
+       intel_encoder = &intel_lvds->base;
        encoder = &intel_encoder->enc;
+       connector = &intel_connector->base;
        drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
                           DRM_MODE_CONNECTOR_LVDS);
 
@@ -897,16 +875,12 @@ void intel_lvds_init(struct drm_device *dev)
 
        intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
        intel_encoder->crtc_mask = (1 << 1);
-       if (IS_I965G(dev))
-               intel_encoder->crtc_mask |= (1 << 0);
        drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
        drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
        connector->display_info.subpixel_order = SubPixelHorizontalRGB;
        connector->interlace_allowed = false;
        connector->doublescan_allowed = false;
 
-       lvds_priv = (struct intel_lvds_priv *)(intel_encoder + 1);
-       intel_encoder->dev_priv = lvds_priv;
        /* create the scaling mode property */
        drm_mode_create_scaling_mode_property(dev);
        /*
@@ -916,7 +890,7 @@ void intel_lvds_init(struct drm_device *dev)
        drm_connector_attach_property(&intel_connector->base,
                                      dev->mode_config.scaling_mode_property,
                                      DRM_MODE_SCALE_ASPECT);
-       lvds_priv->fitting_mode = DRM_MODE_SCALE_ASPECT;
+       intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT;
        /*
         * LVDS discovery:
         * 1) check for EDID on DDC
@@ -1024,6 +998,6 @@ failed:
                intel_i2c_destroy(intel_encoder->ddc_bus);
        drm_connector_cleanup(connector);
        drm_encoder_cleanup(encoder);
-       kfree(intel_encoder);
+       kfree(intel_lvds);
        kfree(intel_connector);
 }