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

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@linux.intel.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Ville Syrjälä 2013-01-18 19:11:38 +02:00 committed by Daniel Vetter
parent ac4199e0f0
commit 86d3efce2c
3 changed files with 124 additions and 2 deletions

View File

@ -2949,6 +2949,7 @@
#define CURSOR_ENABLE 0x80000000 #define CURSOR_ENABLE 0x80000000
#define CURSOR_GAMMA_ENABLE 0x40000000 #define CURSOR_GAMMA_ENABLE 0x40000000
#define CURSOR_STRIDE_MASK 0x30000000 #define CURSOR_STRIDE_MASK 0x30000000
#define CURSOR_PIPE_CSC_ENABLE (1<<24)
#define CURSOR_FORMAT_SHIFT 24 #define CURSOR_FORMAT_SHIFT 24
#define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) #define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT)
#define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) #define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT)
@ -3010,6 +3011,7 @@
#define DISPPLANE_RGBA888 (0xf<<26) #define DISPPLANE_RGBA888 (0xf<<26)
#define DISPPLANE_STEREO_ENABLE (1<<25) #define DISPPLANE_STEREO_ENABLE (1<<25)
#define DISPPLANE_STEREO_DISABLE 0 #define DISPPLANE_STEREO_DISABLE 0
#define DISPPLANE_PIPE_CSC_ENABLE (1<<24)
#define DISPPLANE_SEL_PIPE_SHIFT 24 #define DISPPLANE_SEL_PIPE_SHIFT 24
#define DISPPLANE_SEL_PIPE_MASK (3<<DISPPLANE_SEL_PIPE_SHIFT) #define DISPPLANE_SEL_PIPE_MASK (3<<DISPPLANE_SEL_PIPE_SHIFT)
#define DISPPLANE_SEL_PIPE_A 0 #define DISPPLANE_SEL_PIPE_A 0
@ -3098,6 +3100,7 @@
#define DVS_FORMAT_RGBX101010 (1<<25) #define DVS_FORMAT_RGBX101010 (1<<25)
#define DVS_FORMAT_RGBX888 (2<<25) #define DVS_FORMAT_RGBX888 (2<<25)
#define DVS_FORMAT_RGBX161616 (3<<25) #define DVS_FORMAT_RGBX161616 (3<<25)
#define DVS_PIPE_CSC_ENABLE (1<<24)
#define DVS_SOURCE_KEY (1<<22) #define DVS_SOURCE_KEY (1<<22)
#define DVS_RGB_ORDER_XBGR (1<<20) #define DVS_RGB_ORDER_XBGR (1<<20)
#define DVS_YUV_BYTE_ORDER_MASK (3<<16) #define DVS_YUV_BYTE_ORDER_MASK (3<<16)
@ -3165,7 +3168,7 @@
#define SPRITE_FORMAT_RGBX161616 (3<<25) #define SPRITE_FORMAT_RGBX161616 (3<<25)
#define SPRITE_FORMAT_YUV444 (4<<25) #define SPRITE_FORMAT_YUV444 (4<<25)
#define SPRITE_FORMAT_XR_BGR101010 (5<<25) /* Extended range */ #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_SOURCE_KEY (1<<22)
#define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */ #define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */
#define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19) #define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19)
@ -4645,4 +4648,51 @@
#define WM_DBG_DISALLOW_MAXFIFO (1<<1) #define WM_DBG_DISALLOW_MAXFIFO (1<<1)
#define WM_DBG_DISALLOW_SPRITE (1<<2) #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_ */ #endif /* _I915_REG_H_ */

View File

@ -5126,6 +5126,71 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
POSTING_READ(PIPECONF(pipe)); 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, static void haswell_set_pipeconf(struct drm_crtc *crtc,
struct drm_display_mode *adjusted_mode, struct drm_display_mode *adjusted_mode,
bool dither) bool dither)
@ -5714,8 +5779,10 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
haswell_set_pipeconf(crtc, adjusted_mode, dither); haswell_set_pipeconf(crtc, adjusted_mode, dither);
intel_set_pipe_csc(crtc, adjusted_mode);
/* Set up the display plane register */ /* 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)); POSTING_READ(DSPCNTR(plane));
ret = intel_pipe_set_base(crtc, x, y, fb); ret = intel_pipe_set_base(crtc, x, y, fb);
@ -6120,6 +6187,8 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
cntl |= CURSOR_MODE_DISABLE; cntl |= CURSOR_MODE_DISABLE;
} }
if (IS_HASWELL(dev))
cntl |= CURSOR_PIPE_CSC_ENABLE;
I915_WRITE(CURCNTR_IVB(pipe), cntl); I915_WRITE(CURCNTR_IVB(pipe), cntl);
intel_crtc->cursor_visible = visible; intel_crtc->cursor_visible = visible;

View File

@ -90,6 +90,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
sprctl |= SPRITE_TRICKLE_FEED_DISABLE; sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
sprctl |= SPRITE_ENABLE; sprctl |= SPRITE_ENABLE;
if (IS_HASWELL(dev))
sprctl |= SPRITE_PIPE_CSC_ENABLE;
/* Sizes are 0 based */ /* Sizes are 0 based */
src_w--; src_w--;
src_h--; src_h--;