[PATCH] drm/i915: Implement pipe CSC based limited range RGB output

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jan 18, 2013 at 6:11 PM,  <ville.syrjala at linux.intel.com> wrote:
> From: Ville Syrj?l? <ville.syrjala at linux.intel.com>
>
> HSW no longer has the PIPECONF bit for limited range RGB output.
> Instead the pipe CSC unit must be used to perform that task.
>
> The CSC pre offset are set to 0, since the incoming data is full
> [0:255] range RGB, the coefficients are programmed to compress the
> data into [0:219] range, and then we use either the CSC_MODE black
> screen offset bit, or the CSC post offsets to shift the data to
> the correct [16:235] range.
>
> Also have to change the confiuration of all planes so that the
> data is sent through the pipe CSC unit. For simplicity send the
> plane data through the pipe CSC unit always, and in case full
> range output is requested, the pipe CSC unit is set up with an
> identity transform to pass the plane data through unchanged.
>
> I've been told by some hardware people that the use of the pipe
> CSC unit shouldn't result in any measurable increase in power
> consumption numbers.
>
> Signed-off-by: Ville Syrj?l? <ville.syrjala at linux.intel.com>
> ---
> Note that I haven't actually tested this on HSW. I did test the earlier
> prototype version on ILK and IVB. The pipe CSC unit on ILK isn't programmed
> in quite the same as on HSW, but the IVB unit _should_ be identical to HSW.
>
> The main risk involves the coefficient registers. If the channel mapping
> changed for some reason, we could get swapped channels. For some reason
> reality and documenation didn't seem to agree how the channels are mapped
> even on ILK and IVB. So I'd like someone to try this out on HSW to make
> sure the output still looks correct.

Two questions from the clueless:
- Since there's some question whether the CSC blows through additional
power: Can't we just enable it only when we need it? It looks like
updating the broadcast property requires a full modeset anyway, so we
don't gain anything by keeping the csc on when not required.
- I might just be mislead by the 256/219 values, but: How does this
work for non-8bpc pipe configurations? Or does the CSC thing not care
and only scale the normalized 0.0 - 1.0 range?

Cheers, Daniel

>
>  drivers/gpu/drm/i915/i915_reg.h      |   52 ++++++++++++++++++++++++-
>  drivers/gpu/drm/i915/intel_display.c |   71 +++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/i915/intel_sprite.c  |    3 +
>  3 files changed, 124 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index a2550c5..63ebda8 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -2944,6 +2944,7 @@
>  #define   CURSOR_ENABLE                0x80000000
>  #define   CURSOR_GAMMA_ENABLE  0x40000000
>  #define   CURSOR_STRIDE_MASK   0x30000000
> +#define   CURSOR_PIPE_CSC_ENABLE (1<<24)
>  #define   CURSOR_FORMAT_SHIFT  24
>  #define   CURSOR_FORMAT_MASK   (0x07 << CURSOR_FORMAT_SHIFT)
>  #define   CURSOR_FORMAT_2C     (0x00 << CURSOR_FORMAT_SHIFT)
> @@ -3005,6 +3006,7 @@
>  #define   DISPPLANE_RGBA888                    (0xf<<26)
>  #define   DISPPLANE_STEREO_ENABLE              (1<<25)
>  #define   DISPPLANE_STEREO_DISABLE             0
> +#define   DISPPLANE_PIPE_CSC_ENABLE            (1<<24)
>  #define   DISPPLANE_SEL_PIPE_SHIFT             24
>  #define   DISPPLANE_SEL_PIPE_MASK              (3<<DISPPLANE_SEL_PIPE_SHIFT)
>  #define   DISPPLANE_SEL_PIPE_A                 0
> @@ -3093,6 +3095,7 @@
>  #define   DVS_FORMAT_RGBX101010        (1<<25)
>  #define   DVS_FORMAT_RGBX888   (2<<25)
>  #define   DVS_FORMAT_RGBX161616        (3<<25)
> +#define   DVS_PIPE_CSC_ENABLE   (1<<24)
>  #define   DVS_SOURCE_KEY       (1<<22)
>  #define   DVS_RGB_ORDER_XBGR   (1<<20)
>  #define   DVS_YUV_BYTE_ORDER_MASK (3<<16)
> @@ -3160,7 +3163,7 @@
>  #define   SPRITE_FORMAT_RGBX161616     (3<<25)
>  #define   SPRITE_FORMAT_YUV444         (4<<25)
>  #define   SPRITE_FORMAT_XR_BGR101010   (5<<25) /* Extended range */
> -#define   SPRITE_CSC_ENABLE            (1<<24)
> +#define   SPRITE_PIPE_CSC_ENABLE       (1<<24)
>  #define   SPRITE_SOURCE_KEY            (1<<22)
>  #define   SPRITE_RGB_ORDER_RGBX                (1<<20) /* only for 888 and 161616 */
>  #define   SPRITE_YUV_TO_RGB_CSC_DISABLE        (1<<19)
> @@ -4635,4 +4638,51 @@
>  #define  WM_DBG_DISALLOW_MAXFIFO       (1<<1)
>  #define  WM_DBG_DISALLOW_SPRITE                (1<<2)
>
> +/* pipe CSC */
> +#define _PIPE_A_CSC_COEFF_RY_GY        0x49010
> +#define _PIPE_A_CSC_COEFF_BY   0x49014
> +#define _PIPE_A_CSC_COEFF_RU_GU        0x49018
> +#define _PIPE_A_CSC_COEFF_BU   0x4901c
> +#define _PIPE_A_CSC_COEFF_RV_GV        0x49020
> +#define _PIPE_A_CSC_COEFF_BV   0x49024
> +#define _PIPE_A_CSC_MODE       0x49028
> +#define _PIPE_A_CSC_PREOFF_HI  0x49030
> +#define _PIPE_A_CSC_PREOFF_ME  0x49034
> +#define _PIPE_A_CSC_PREOFF_LO  0x49038
> +#define _PIPE_A_CSC_POSTOFF_HI 0x49040
> +#define _PIPE_A_CSC_POSTOFF_ME 0x49044
> +#define _PIPE_A_CSC_POSTOFF_LO 0x49048
> +
> +#define _PIPE_B_CSC_COEFF_RY_GY        0x49110
> +#define _PIPE_B_CSC_COEFF_BY   0x49114
> +#define _PIPE_B_CSC_COEFF_RU_GU        0x49118
> +#define _PIPE_B_CSC_COEFF_BU   0x4911c
> +#define _PIPE_B_CSC_COEFF_RV_GV        0x49120
> +#define _PIPE_B_CSC_COEFF_BV   0x49124
> +#define _PIPE_B_CSC_MODE       0x49128
> +#define _PIPE_B_CSC_PREOFF_HI  0x49130
> +#define _PIPE_B_CSC_PREOFF_ME  0x49134
> +#define _PIPE_B_CSC_PREOFF_LO  0x49138
> +#define _PIPE_B_CSC_POSTOFF_HI 0x49140
> +#define _PIPE_B_CSC_POSTOFF_ME 0x49144
> +#define _PIPE_B_CSC_POSTOFF_LO 0x49148
> +
> +#define CSC_BLACK_SCREEN_OFFSET (1 << 2)
> +#define CSC_POSITION_BEFORE_GAMMA (1 << 1)
> +#define CSC_MODE_YUV_TO_RGB (1 << 0)
> +
> +#define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY)
> +#define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY)
> +#define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU)
> +#define PIPE_CSC_COEFF_BU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU)
> +#define PIPE_CSC_COEFF_RV_GV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV)
> +#define PIPE_CSC_COEFF_BV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV)
> +#define PIPE_CSC_MODE(pipe) _PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE)
> +#define PIPE_CSC_PREOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI)
> +#define PIPE_CSC_PREOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME)
> +#define PIPE_CSC_PREOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO)
> +#define PIPE_CSC_POSTOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI)
> +#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
> +#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO)
> +
>  #endif /* _I915_REG_H_ */
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index f48f698..f22b0a8 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -5106,6 +5106,71 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
>         POSTING_READ(PIPECONF(pipe));
>  }
>
> +/*
> + * Set up the pipe CSC unit.
> + *
> + * Currently only full range RGB to limited range RGB conversion
> + * is supported, but eventually this should handle various
> + * RGB<->YCbCr scenarios as well.
> + */
> +static void intel_set_pipe_csc(struct drm_crtc *crtc,
> +                              const struct drm_display_mode *adjusted_mode)
> +{
> +       struct drm_device *dev = crtc->dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +       int pipe = intel_crtc->pipe;
> +       uint16_t coeff = 0x7800; /* 1.0 */
> +
> +       /*
> +        * TODO: Check what kind of values actually come out of the pipe
> +        * with these coeff/postoff values and adjust to get the best
> +        * accuracy. Perhaps we even need to take the bpc value into
> +        * consideration.
> +        */
> +
> +       if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
> +               coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
> +
> +       /*
> +        * GY/GU and RY/RU should be the other way around according
> +        * to BSpec, but reality doesn't agree. Just set them up in
> +        * a way that results in the correct picture.
> +        */
> +       I915_WRITE(PIPE_CSC_COEFF_RY_GY(pipe), coeff << 16);
> +       I915_WRITE(PIPE_CSC_COEFF_BY(pipe), 0);
> +
> +       I915_WRITE(PIPE_CSC_COEFF_RU_GU(pipe), coeff);
> +       I915_WRITE(PIPE_CSC_COEFF_BU(pipe), 0);
> +
> +       I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), 0);
> +       I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeff << 16);
> +
> +       I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0);
> +       I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0);
> +       I915_WRITE(PIPE_CSC_PREOFF_LO(pipe), 0);
> +
> +       if (INTEL_INFO(dev)->gen > 6) {
> +               uint16_t postoff = 0;
> +
> +               if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
> +                       postoff = (16 * (1 << 13) / 255) & 0x1fff;
> +
> +               I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
> +               I915_WRITE(PIPE_CSC_POSTOFF_ME(pipe), postoff);
> +               I915_WRITE(PIPE_CSC_POSTOFF_LO(pipe), postoff);
> +
> +               I915_WRITE(PIPE_CSC_MODE(pipe), 0);
> +       } else {
> +               uint32_t mode = CSC_MODE_YUV_TO_RGB;
> +
> +               if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
> +                       mode |= CSC_BLACK_SCREEN_OFFSET;
> +
> +               I915_WRITE(PIPE_CSC_MODE(pipe), mode);
> +       }
> +}
> +
>  static void haswell_set_pipeconf(struct drm_crtc *crtc,
>                                  struct drm_display_mode *adjusted_mode,
>                                  bool dither)
> @@ -5670,8 +5735,10 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
>
>         haswell_set_pipeconf(crtc, adjusted_mode, dither);
>
> +       intel_set_pipe_csc(crtc, adjusted_mode);
> +
>         /* Set up the display plane register */
> -       I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE);
> +       I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE);
>         POSTING_READ(DSPCNTR(plane));
>
>         ret = intel_pipe_set_base(crtc, x, y, fb);
> @@ -6069,6 +6136,8 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
>                         cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
>                         cntl |= CURSOR_MODE_DISABLE;
>                 }
> +               if (IS_HASWELL(dev))
> +                       cntl |= CURSOR_PIPE_CSC_ENABLE;
>                 I915_WRITE(CURCNTR_IVB(pipe), cntl);
>
>                 intel_crtc->cursor_visible = visible;
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index d7b060e..9dedf68 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -89,6 +89,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
>         sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
>         sprctl |= SPRITE_ENABLE;
>
> +       if (IS_HASWELL(dev))
> +               sprctl |= SPRITE_PIPE_CSC_ENABLE;
> +
>         /* Sizes are 0 based */
>         src_w--;
>         src_h--;
> --
> 1.7.8.6
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch


[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux