On Mon, 2009-03-23 at 11:21 +0800, yakui_zhao wrote: > Subject: DRM/I915: Sync the panel fitting property with 2D driver > From: Zhao Yakui <yakui.z...@intel.com> > > Sync the panel fitting property with 2D driver > This covers: > a. create the scaling mode property and attach it to LVDS > b. add the support of panel fitting property for LVDS > c. update the display mode according to the panel fitting mode > > Fix the code-style based on Eric's suggestion.
checkpatch.pl, commit message in your email is mangled (compare your output to git send-email. Or just use git send-email), and please keep using kzalloc/kfree. > > Signed-off-by: Zhao Yakui <yakui.z...@intel.com> > --- > drivers/gpu/drm/i915/i915_reg.h | 16 ++ > drivers/gpu/drm/i915/intel_lvds.c | 282 > +++++++++++++++++++++++++++++++++++--- > 2 files changed, 277 insertions(+), 21 deletions(-) > > Index: linux-2.6/drivers/gpu/drm/i915/i915_reg.h > =================================================================== > --- linux-2.6.orig/drivers/gpu/drm/i915/i915_reg.h 2009-03-23 > 11:08:45.000000000 +0800 > +++ linux-2.6/drivers/gpu/drm/i915/i915_reg.h 2009-03-23 11:09:37.000000000 > +0800 > @@ -808,9 +808,25 @@ > #define HORIZ_INTERP_MASK (3 << 6) > #define HORIZ_AUTO_SCALE (1 << 5) > #define PANEL_8TO6_DITHER_ENABLE (1 << 3) > +#define PFIT_FILTER_FUZZY (0 << 24) > +#define PFIT_SCALING_AUTO (0 << 26) > +#define PFIT_SCALING_PROGRAMMED (1 << 26) > +#define PFIT_SCALING_PILLAR (2 << 26) > +#define PFIT_SCALING_LETTER (3 << 26) > #define PFIT_PGM_RATIOS 0x61234 > #define PFIT_VERT_SCALE_MASK 0xfff00000 > #define PFIT_HORIZ_SCALE_MASK 0x0000fff0 > +/* Pre-965 */ > +#define PFIT_VERT_SCALE_SHIFT 20 > +#define PFIT_VERT_SCALE_MASK 0xfff00000 > +#define PFIT_HORIZ_SCALE_SHIFT 4 > +#define PFIT_HORIZ_SCALE_MASK 0x0000fff0 > +/* 965+ */ > +#define PFIT_VERT_SCALE_SHIFT_965 16 > +#define PFIT_VERT_SCALE_MASK_965 0x1fff0000 > +#define PFIT_HORIZ_SCALE_SHIFT_965 0 > +#define PFIT_HORIZ_SCALE_MASK_965 0x00001fff > + > #define PFIT_AUTO_RATIOS 0x61238 > > /* Backlight control */ > Index: linux-2.6/drivers/gpu/drm/i915/intel_lvds.c > =================================================================== > --- linux-2.6.orig/drivers/gpu/drm/i915/intel_lvds.c 2009-03-23 > 11:08:45.000000000 +0800 > +++ linux-2.6/drivers/gpu/drm/i915/intel_lvds.c 2009-03-23 > 11:19:40.000000000 +0800 > @@ -37,6 +37,21 @@ > #include "i915_drm.h" > #include "i915_drv.h" > > +/* > + * the following four scaling options are defined. > + * #define DRM_MODE_SCALE_NON_GPU 0 > + * #define DRM_MODE_SCALE_FULLSCREEN 1 > + * #define DRM_MODE_SCALE_NO_SCALE 2 > + * #define DRM_MODE_SCALE_ASPECT 3 > + */ > + > +/* Private structure for the integrated LVDS support */ > +struct intel_lvds_priv { > + int fitting_mode; > + u32 pfit_control; > + u32 pfit_pgm_ratios; > +}; > + > /** > * Sets the backlight level. > * > @@ -160,10 +175,24 @@ > struct drm_display_mode *mode, > struct drm_display_mode *adjusted_mode) > { > + /* > + * float point operation is not supported . So the PANEL_RATIO_FACTOR > + * is defined, which can avoid the float point computation when > + * calculating the panel ratio. > + */ > +#define PANEL_RATIO_FACTOR 8192 > 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 drm_encoder *tmp_encoder; > + struct intel_output *intel_output = enc_to_intel_output(encoder); > + struct intel_lvds_priv *lvds_priv = intel_output->dev_priv; > + u32 pfit_control = 0, pfit_pgm_ratios = 0; > + int left_border = 0, right_border = 0, top_border = 0; > + int bottom_border = 0; > + bool border = 0; > + int panel_ratio, desired_ratio, vert_scale, horiz_scale; > + int horiz_ratio, vert_ratio; > > /* Should never happen!! */ > if (!IS_I965G(dev) && intel_crtc->pipe == 0) { > @@ -179,7 +208,9 @@ > return false; > } > } > - > + /* If we don't have a panel mode, there is nothing we can do */ > + if (dev_priv->panel_fixed_mode == NULL) > + return true; > /* > * If 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, > @@ -203,6 +234,191 @@ > drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); > } > > + /* Make sure pre-965s set dither correctly */ > + if (!IS_I965G(dev)) { > + if (dev_priv->panel_wants_dither || dev_priv->lvds_dither) > + pfit_control |= PANEL_8TO6_DITHER_ENABLE; > + } > + > + /* Native modes don't need fitting */ > + if (adjusted_mode->hdisplay == mode->hdisplay && > + adjusted_mode->vdisplay == mode->vdisplay) { > + pfit_pgm_ratios = 0; > + border = 0; > + goto out; > + } > + > + /* 965+ wants fuzzy fitting */ > + if (IS_I965G(dev)) > + pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) | > + PFIT_FILTER_FUZZY; > + > + /* > + * Deal with panel fitting options. Figure out how to stretch the > + * image based on its aspect ratio & the current panel fitting mode. > + */ > + panel_ratio = adjusted_mode->hdisplay * PANEL_RATIO_FACTOR / > + adjusted_mode->vdisplay; > + desired_ratio = mode->hdisplay * PANEL_RATIO_FACTOR / > + mode->vdisplay; > + /* > + * Enable automatic panel scaling for non-native modes so that they fill > + * the screen. Should be enabled before the pipe is enabled, according > + * to register description and PRM. > + * Change the value here to see the borders for debugging > + */ > + I915_WRITE(BCLRPAT_A, 0); > + I915_WRITE(BCLRPAT_B, 0); > + > + switch (lvds_priv->fitting_mode) { > + case DRM_MODE_SCALE_NO_SCALE: > + /* > + * For centered modes, we have to calculate border widths & > + * heights and modify the values programmed into the CRTC. > + */ > + left_border = (adjusted_mode->hdisplay - mode->hdisplay) / 2; > + right_border = left_border; > + if (mode->hdisplay & 1) > + right_border++; > + top_border = (adjusted_mode->vdisplay - mode->vdisplay) / 2; > + bottom_border = top_border; > + if (mode->vdisplay & 1) > + bottom_border++; > + /* Set active & border values */ > + adjusted_mode->crtc_hdisplay = mode->hdisplay; > + adjusted_mode->crtc_hblank_start = mode->hdisplay + > + right_border - 1; > + adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_htotal - > + left_border - 1; > + adjusted_mode->crtc_hsync_start = > + adjusted_mode->crtc_hblank_start; > + adjusted_mode->crtc_hsync_end = > + adjusted_mode->crtc_hblank_end; > + adjusted_mode->crtc_vdisplay = mode->vdisplay; > + adjusted_mode->crtc_vblank_start = mode->vdisplay + > + bottom_border - 1; > + adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vtotal - > + top_border - 1; > + adjusted_mode->crtc_vsync_start = > + adjusted_mode->crtc_vblank_start; > + adjusted_mode->crtc_vsync_end = > + adjusted_mode->crtc_vblank_end; > + border = 1; > + break; > + case DRM_MODE_SCALE_ASPECT: > + /* Scale but preserve the spect ratio */ > + pfit_control |= PFIT_ENABLE; > + if (IS_I965G(dev)) { > + /* 965+ is easy, it does everything in hw */ > + if (panel_ratio > desired_ratio) > + pfit_control |= PFIT_SCALING_PILLAR; > + else if (panel_ratio < desired_ratio) > + pfit_control |= PFIT_SCALING_LETTER; > + else > + pfit_control |= PFIT_SCALING_AUTO; > + } else { > + /* > + * For earlier chips we have to calculate the scaling > + * ratio by hand and program it into the > + * PFIT_PGM_RATIO register > + */ > + u32 horiz_bits, vert_bits, bits = 12; > + horiz_ratio = mode->hdisplay * PANEL_RATIO_FACTOR/ > + adjusted_mode->hdisplay; > + vert_ratio = mode->vdisplay * PANEL_RATIO_FACTOR/ > + adjusted_mode->vdisplay; > + horiz_scale = adjusted_mode->hdisplay * > + PANEL_RATIO_FACTOR / mode->hdisplay; > + vert_scale = adjusted_mode->vdisplay * > + PANEL_RATIO_FACTOR / mode->vdisplay; > + > + /* retain aspect ratio */ > + if (panel_ratio > desired_ratio) { /* Pillar */ > + u32 scaled_width; > + scaled_width = mode->hdisplay * vert_scale / > + PANEL_RATIO_FACTOR; > + horiz_ratio = vert_ratio; > + pfit_control |= (VERT_AUTO_SCALE | > + VERT_INTERP_BILINEAR | > + HORIZ_INTERP_BILINEAR); > + /* Pillar will have left/right borders */ > + left_border = (adjusted_mode->hdisplay - > + scaled_width) / 2; > + right_border = left_border; > + if (mode->hdisplay & 1) /* odd resolutions */ > + right_border++; > + adjusted_mode->crtc_hdisplay = scaled_width; > + adjusted_mode->crtc_hblank_start = > + scaled_width + right_border - 1; > + adjusted_mode->crtc_hblank_end = > + adjusted_mode->crtc_htotal - left_border - 1; > + adjusted_mode->crtc_hsync_start = > + adjusted_mode->crtc_hblank_start; > + adjusted_mode->crtc_hsync_end = > + adjusted_mode->crtc_hblank_end; > + border = 1; > + } else if (panel_ratio < desired_ratio) { /* letter */ > + u32 scaled_height = mode->vdisplay * > + horiz_scale / PANEL_RATIO_FACTOR; > + vert_ratio = horiz_ratio; > + pfit_control |= (HORIZ_AUTO_SCALE | > + VERT_INTERP_BILINEAR | > + HORIZ_INTERP_BILINEAR); > + /* Letterbox will have top/bottom border */ > + top_border = (adjusted_mode->vdisplay - > + scaled_height) / 2; > + bottom_border = top_border; > + if (mode->vdisplay & 1) > + bottom_border++; > + adjusted_mode->crtc_vdisplay = scaled_height; > + adjusted_mode->crtc_vblank_start = > + scaled_height + bottom_border - 1; > + adjusted_mode->crtc_vblank_end = > + adjusted_mode->crtc_vtotal - top_border - 1; > + adjusted_mode->crtc_vsync_start = > + adjusted_mode->crtc_vblank_start; > + adjusted_mode->crtc_vsync_end = > + adjusted_mode->crtc_vblank_end; > + border = 1; > + } else { > + /* Aspects match, Let hw scale both directions */ > + pfit_control |= (VERT_AUTO_SCALE | > + HORIZ_AUTO_SCALE | > + VERT_INTERP_BILINEAR | > + HORIZ_INTERP_BILINEAR); > + } > + horiz_bits = (1 << bits) * horiz_ratio / > + PANEL_RATIO_FACTOR; > + vert_bits = (1 << bits) * vert_ratio / > + PANEL_RATIO_FACTOR; > + pfit_pgm_ratios = > + ((vert_bits << PFIT_VERT_SCALE_SHIFT) & > + PFIT_VERT_SCALE_MASK) | > + ((horiz_bits << PFIT_HORIZ_SCALE_SHIFT) & > + PFIT_HORIZ_SCALE_MASK); > + } > + break; > + > + case DRM_MODE_SCALE_FULLSCREEN: > + /* > + * Full scaling, even if it changes the aspect ratio. > + * Fortunately this is all done for us in hw. > + */ > + pfit_control |= PFIT_ENABLE; > + if (IS_I965G(dev)) > + pfit_control |= PFIT_SCALING_AUTO; > + else > + pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | > + VERT_INTERP_BILINEAR | > + HORIZ_INTERP_BILINEAR); > + break; > + default: > + break; > + } > + > +out: > + lvds_priv->pfit_control = pfit_control; > + lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios; > /* > * XXX: It would be nice to support lower refresh rates on the > * panels to reduce power consumption, and perhaps match the > @@ -242,8 +458,8 @@ > { > 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); > - u32 pfit_control; > + struct intel_output *intel_output = enc_to_intel_output(encoder); > + struct intel_lvds_priv *lvds_priv = intel_output->dev_priv; > > /* > * The LVDS pin pair will already have been turned on in the > @@ -256,22 +472,8 @@ > * screen. Should be enabled before the pipe is enabled, according to > * register description and PRM. > */ > - if (mode->hdisplay != adjusted_mode->hdisplay || > - mode->vdisplay != adjusted_mode->vdisplay) > - pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | > - HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | > - HORIZ_INTERP_BILINEAR); > - else > - pfit_control = 0; > - > - if (!IS_I965G(dev)) { > - if (dev_priv->panel_wants_dither || dev_priv->lvds_dither) > - pfit_control |= PANEL_8TO6_DITHER_ENABLE; > - } > - else > - pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT; > - > - I915_WRITE(PFIT_CONTROL, pfit_control); > + I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios); > + I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control); > } > > /** > @@ -344,10 +546,34 @@ > uint64_t value) > { > struct drm_device *dev = connector->dev; > + struct intel_output *intel_output = > + to_intel_output(connector); > > if (property == dev->mode_config.dpms_property && connector->encoder) > intel_lvds_dpms(connector->encoder, (uint32_t)(value & 0xf)); > > + if (property == dev->mode_config.scaling_mode_property && > + connector->encoder) { > + struct drm_crtc *crtc = connector->encoder->crtc; > + struct intel_lvds_priv *lvds_priv = intel_output->dev_priv; > + if (value == DRM_MODE_SCALE_NON_GPU) { > + DRM_DEBUG("non_GPU property is unsupported.\n"); > + return 0; > + } > + > + if (lvds_priv->fitting_mode == value) > + return 0; > + > + lvds_priv->fitting_mode = value; > + if (crtc && crtc->enabled) { > + /* > + * If the CRTC is enabled, the display will be changed > + * according to the new panel fitting mode. > + */ > + drm_crtc_helper_set_mode(crtc, &crtc->mode, > + crtc->x, crtc->y, crtc->fb); > + } > + } > return 0; > } > > @@ -401,6 +627,7 @@ > 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; > > @@ -419,7 +646,8 @@ > return; > } > > - intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); > + intel_output = drm_calloc(1, sizeof(struct intel_output) + > + sizeof(struct intel_lvds_priv), DRM_MEM_DRIVER); > if (!intel_output) { > return; > } > @@ -441,7 +669,18 @@ > connector->interlace_allowed = false; > connector->doublescan_allowed = false; > > + lvds_priv = (struct intel_lvds_priv *)(intel_output + 1); > + intel_output->dev_priv = lvds_priv; > + /* create the scaling mode property */ > + drm_mode_create_scaling_mode_property(dev); > + /* > + * the initial panel fitting mode will be FULL_ASPECT > + */ > > + drm_connector_attach_property(&intel_output->base, > + dev->mode_config.scaling_mode_property, > + DRM_MODE_SCALE_ASPECT); > + lvds_priv->fitting_mode = DRM_MODE_SCALE_ASPECT; > /* > * LVDS discovery: > * 1) check for EDID on DDC > @@ -521,5 +760,6 @@ > if (intel_output->ddc_bus) > intel_i2c_destroy(intel_output->ddc_bus); > drm_connector_cleanup(connector); > - kfree(connector); > + drm_free(intel_output, sizeof(struct intel_output) + > + sizeof(struct intel_lvds_priv), DRM_MEM_DRIVER); > } > > -- Eric Anholt e...@anholt.net eric.anh...@intel.com
signature.asc
Description: This is a digitally signed message part
------------------------------------------------------------------------------
-- _______________________________________________ Dri-devel mailing list Dri-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/dri-devel