[PATCH 3/6] drm/i915: Color manager: Add Gamma correction

Shashank Sharma
2014-02-20T12:34:50Z

This patch is second extension to color manager framework.
It adds implementataion of color manager property Gamma
correction in intel color manager framework.

Gamma correction is possible at various levels like:
1. PIPE level = (primary plane + sprite)
2. Plane level = (primary plane only)
3. Sprote level = (Sprite plane only)
This patch supports all three levels of correction.
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
---
drivers/gpu/drm/i915/intel_clrmgr.c | 424 +++++++++++++++++++++++++++++++++-
drivers/gpu/drm/i915/intel_display.c | 5 +-
2 files changed, 422 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_clrmgr.c b/drivers/gpu/drm/i915/intel_clrmgr.c
index 363e3e6..1297e60 100644
--- a/drivers/gpu/drm/i915/intel_clrmgr.c
+++ b/drivers/gpu/drm/i915/intel_clrmgr.c
@@ -35,12 +35,14 @@

/* Sprite register default gamma values */
u32 default_sprite_gamma_vals[] = {
- 0, 0, 0, 0, 0, 0
+ 0x00080808, 0x00101010, 0x00202020,
+ 0x00404040, 0x00808080, 0x00C0C0C0
};

/* Gamma lookup table for Sprite planes */
u32 gamma_sprite_softlut[GAMMA_SP_MAX_COUNT] = {
- 0, 0, 0, 0, 0, 1023
+ 0x00080808, 0x00101010, 0x00202020,
+ 0x00404040, 0x00808080, 0x00C0C0C0
};

/* Gamma soft lookup table for default gamma =1.0 */
@@ -142,24 +144,436 @@ static bool intel_clrmgr_disable_cb(struct drm_device *dev, int identifier)
return true;
}

-static bool intel_clrmgr_disable_gamma(struct drm_device *dev, int identifier)
+static bool intel_clrmgr_enable_hs(struct drm_device *dev, int identifier)
{
return true;
}
-static bool intel_clrmgr_enable_hs(struct drm_device *dev, int identifier)
+static bool intel_clrmgr_enable_cb(struct drm_device *dev, int identifier)
{
return true;
}
-static bool intel_clrmgr_enable_cb(struct drm_device *dev, int identifier)
+
+/* Reset palette registers for gamma disabling */
+static int intel_clrmgr_reset_lut(struct drm_device *dev)
+{
+ struct drm_crtc *crtc = NULL;
+
+ /* Search for fix panel CRTC,
+ Assumption: Either MIPI or EDP is fix panel */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP) ||
+ intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI))
+ break;
+ }
+
+ if (!crtc) {
+ DRM_ERROR("No CRTC for fix panel??");
+ return -1;
+ }
+
+ /* Reset pal regs */
+ intel_crtc_load_lut(crtc);
+ return 0;
+}
+
+
+/* Disable gamma correction for sprite planes */
+int intel_disable_sprite_gamma(struct drm_device *dev, u32 identifier)
+{
+ u32 count = 0;
+ u32 status = 0;
+ u32 controlreg = 0;
+ u32 correctreg = 0;
+ u32 *lut = default_sprite_gamma_vals;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct clrmgr_pipe_status *pstatus = dev_priv->clrmgr_status.pstatus;
+
+ if (!pstatus) {
+ DRM_ERROR("Clrmgr: color manager not initialized");
+ return false;
+ }
+
+ /* Validate input */
+ if (identifier < sprite_a || identifier > sprite_d) {
+ DRM_ERROR("Clrmgr: Invalid sprite input to disable gamma\n");
+ return -ENOSYS;
+ }
+
+ /* Enable this check if we want to restrict clr mgr to
+ internal panel only */
+ if (_validate_sprite(identifier))
+ return -ENOSYS;
+
+ /* Load control and correcttion register */
+ controlreg = GET_SPRITE_CTL(identifier);
+ correctreg = GET_SPRITE_REG(identifier);
+
+ /* Disable gamma due to PIPE */
+ status = I915_READ(controlreg);
+ status &= ~(GAMMA_ENABLE_SPR);
+ I915_WRITE(controlreg, status);
+
+ /*
+ * To disable plane level gamma correction, Write default
+ * values on sprite gamma regs
+ */
+ while (count < GAMMA_SP_MAX_COUNT) {
+ /* Write and read */
+ I915_WRITE(correctreg - 4 * count, lut[count]);
+ status = I915_READ(correctreg - 4 * count++);
+ }
+
+ pstatus->gamma_s_enabled = false;
+ /* TODO: Reset gamma table default */
+ DRM_DEBUG_DRIVER("Gamma on Sprite %c disabled\n",
+ (identifier == sprite_a) ? 'A' : 'B');
+
+ return 0;
+}
+
+/* Disable gamma correction on Primary display */
+int intel_disable_plane_gamma(struct drm_device *dev, u32 identifier)
+{
+ u32 pipe = 0;
+ u32 status = 0;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct clrmgr_pipe_status *pstatus = dev_priv->clrmgr_status.pstatus;
+
+ if (!pstatus) {
+ DRM_ERROR("Clrmgr: color manager not initialized");
+ return false;
+ }
+
+ /* Enable this check if we want to restrict clr mgr to
+ internal panel only */
+ if (_validate_plane(identifier))
+ return -ENOSYS;
+
+ if (intel_clrmgr_reset_lut(dev)) {
+ DRM_ERROR("Reset LUT failed\n");
+ return -1;
+ }
+
+ pipe = _get_pipe_from_plane(identifier);
+ if (pipe < pipe_a || pipe > pipe_c) {
+ DRM_ERROR("Clrmgr: Cant enable plane gamma, invalid pipe\n");
+ return -ENOSYS;
+ }
+
+ /* Disable gamma on PIPE config */
+ status = I915_READ(PIPECONF(pipe));
+ status &= ~(PIPECONF_GAMMA);
+ I915_WRITE(PIPECONF(pipe), status);
+
+ pstatus->gamma_enabled = false;
+ /* TODO: Reset gamma table default */
+ DRM_DEBUG("Gamma disabled on Pipe\n");
+ return 0;
+}
+
+
+/* Disable gamma correction on Primary display */
+int intel_disable_pipe_gamma(struct drm_device *dev, u32 identifier)
{
+ u32 status = 0;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct clrmgr_pipe_status *pstatus = dev_priv->clrmgr_status.pstatus;
+
+ if (!pstatus) {
+ DRM_ERROR("Clrmgr: color manager not initialized");
+ return false;
+ }
+
+ /* Enable this check if we want to restrict clr mgr to
+ internal panel only */
+ if (_validate_pipe(identifier))
+ return -ENOSYS;
+
+ if (intel_clrmgr_reset_lut(dev)) {
+ DRM_ERROR("Reset LUT failed\n");
+ return -1;
+ }
+
+ /* Disable gamma on PIPE config */
+ status = I915_READ(PIPECONF(identifier));
+ status &= ~(PIPECONF_GAMMA);
+ I915_WRITE(PIPECONF(identifier), status);
+
+ /* Disable gamma on sprite_a */
+ status = I915_READ(GAMMA_SPA_CNTRL);
+ status &= ~(GAMMA_ENABLE_SPR);
+ I915_WRITE(GAMMA_SPA_CNTRL, status);
+
+ /* Disable gamma on sprite_b */
+ status = I915_READ(GAMMA_SPB_CNTRL);
+ status &= ~(GAMMA_ENABLE_SPR);
+ I915_WRITE(GAMMA_SPB_CNTRL, status);
+
+ pstatus->gamma_enabled = false;
+ /* TODO: Reset gamma table default */
+ DRM_DEBUG("Gamma disabled on Pipe\n");
+ return 0;
+}
+
+/* Load gamma correction values corresponding to supplied
+gamma and program palette accordingly */
+int intel_crtc_disable_gamma(struct drm_device *dev, u32 identifier)
+{
+ switch (identifier) {
+
+ /* Whole pipe level correction disable */
+ case pipe_a:
+ case pipe_b:
+ return intel_disable_pipe_gamma(dev, identifier);
+
+ /* Primary planes */
+ case plane_a:
+ case plane_b:
+ return intel_disable_plane_gamma(dev, identifier);
+
+ /* Sprite planes */
+ case sprite_a:
+ case sprite_b:
+ case sprite_c:
+ case sprite_d:
+ return intel_disable_sprite_gamma(dev, identifier);
+
+ default:
+ DRM_ERROR("Invalid panel ID to Gamma enabled\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Disable Gamma correction */
+static bool intel_clrmgr_disable_gamma(struct drm_device *dev, int identifier)
+{
+ if (intel_crtc_disable_gamma(dev, identifier)) {
+ DRM_ERROR("\nClrmgr: Gamma disable failed");
+ return false;
+ }
+
return true;
}

+
+
+/* Load palette registers for gamma correction */
+static void intel_clrmgr_load_palette(struct drm_device *dev, int identifier)
+{
+ u32 count = 0;
+ u32 odd = 0;
+ u32 even = 0;
+ u32 palreg = 0;
+ u32 *lut = clrmgr_luts[clrmgr_gamma];
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ palreg = PALETTE(identifier);
+ DRM_DEBUG_DRIVER("Loading gamma palette from %x to %x",
+ palreg, palreg+GAMMA_CORRECT_MAX_COUNT-1);
+
+ /* 10.6 mode Gamma Implementation */
+ while (count < GAMMA_CORRECT_MAX_COUNT) {
+ /* Get the gamma corrected value from table */
+ odd = lut[count];
+ even = lut[count + 1];
+
+ /* Write even and odd parts in palette regs*/
+ I915_WRITE(palreg + 4 * count, even);
+ I915_WRITE(palreg + 4 * ++count, odd);
+ count++;
+ }
+
+ /* Write max values in 11.6 format */
+ I915_WRITE(PIPEA_MAX_BLUE, SHIFTBY6(GAMMA_MAX_VAL));
+ I915_WRITE(PIPEA_MAX_GREEN, SHIFTBY6(GAMMA_MAX_VAL));
+ I915_WRITE(PIPEA_MAX_RED, SHIFTBY6(GAMMA_MAX_VAL));
+}
+
+
+/* Enable gamma correction on sprite plane level */
+int intel_enable_sprite_gamma(struct drm_device *dev, int planeid)
+{
+ u32 count = 0;
+ u32 status = 0;
+ u32 controlreg = 0;
+ u32 correctreg = 0;
+ u32 *lut = clrmgr_luts[clrmgr_gammaspr];
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct clrmgr_pipe_status *pstatus = dev_priv->clrmgr_status.pstatus;
+
+ if (!pstatus) {
+ DRM_ERROR("Clrmgr: color manager not initialized");
+ return false;
+ }
+
+ /* Validate plane */
+ if (planeid < sprite_a || planeid > sprite_d) {
+ DRM_ERROR("Clrmgr: Invalid sprite object to gamma enable\n");
+ return -EINVAL;
+ }
+
+ /* Load control and correcttion register */
+ controlreg = GET_SPRITE_CTL(planeid);
+ correctreg = GET_SPRITE_REG(planeid);
+
+ /* Restore default gamma cofficients in gamma regs*/
+ while (count < GAMMA_SP_MAX_COUNT) {
+ I915_WRITE(correctreg - 4 * count, lut[count]);
+ status = I915_READ(correctreg - 4 * count++);
+ }
+
+ /*
+ * Disable PIPE level gamma correction effect on sprite.
+ * Set sprite gamma control bit = 0 to enable the plane specific
+ * gamma. If this bit is enabled, sprite will follow the gamma
+ * correction on PIPE not plane.
+ */
+ status = I915_READ(controlreg);
+ status &= ~GAMMA_ENABLE_SPR;
+ I915_WRITE(controlreg, status);
+
+ pstatus->gamma_s_enabled = true;
+ DRM_DEBUG("Gamma applied on plane sprite%c\n",
+ (planeid == sprite_a) ? 'A' : 'B');
+
+ return 0;
+}
+
+
+/*
+* Gamma correction at Plane level */
+int intel_enable_plane_gamma(struct drm_device *dev, u32 identifier)
+{
+ u32 status = 0;
+ u32 pipe = 0;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct clrmgr_pipe_status *pstatus = dev_priv->clrmgr_status.pstatus;
+
+ if (!pstatus) {
+ DRM_ERROR("Clrmgr: color manager not initialized");
+ return false;
+ }
+
+ /* Enable this check if we want to restrict clr mgr to
+ internal panel only */
+ if (_validate_plane(identifier))
+ return -ENOSYS;
+
+ pipe = _get_pipe_from_plane(identifier);
+ if (pipe < pipe_a || pipe > pipe_c) {
+ DRM_ERROR("Clrmgr: Cant enable plane gamma, invalid pipe\n");
+ return -ENOSYS;
+ }
+
+ /* Load palette */
+ intel_clrmgr_load_palette(dev, pipe);
+
+ /* Enable gamma on PLANE A */
+ status = I915_READ(PIPECONF(pipe));
+ status |= PIPECONF_GAMMA;
+ I915_WRITE(PIPECONF(pipe), status);
+
+ /* Shashank:
+ =========
+ Disable Sprite gamma for PIPE
+ correction here */
+
+ pstatus->gamma_enabled = true;
+ DRM_DEBUG("Gamma enabled on Plane A\n");
+
+ return 0;
+}
+
+
+/*
+* Gamma correction at PIPE level:
+* This function applies gamma correction Primary as well as Sprite planes
+* assosiated with this PIPE. Assumptions are:
+* Plane A is internal display primary panel.
+* Sprite A and B are interal display's sprite planes.
+*/
+int intel_enable_pipe_gamma(struct drm_device *dev, u32 identifier)
+{
+ u32 status = 0;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct clrmgr_pipe_status *pstatus = dev_priv->clrmgr_status.pstatus;
+
+ if (!pstatus) {
+ DRM_ERROR("Clrmgr: color manager not initialized");
+ return false;
+ }
+
+ /* Enable this check if we want to restrict clr mgr to
+ internal panel only */
+ if (_validate_pipe(identifier))
+ return -ENOSYS;
+
+ /* Load palette */
+ intel_clrmgr_load_palette(dev, identifier);
+
+ /* Set palette in 10bit mode gamma for PIPE */
+ status = I915_READ(PIPECONF(identifier));
+ status |= PIPECONF_GAMMA;
+ I915_WRITE(PIPECONF(identifier), status);
+
+ /* Enable gamma on Sprite plane A */
+ status = I915_READ(GAMMA_SPA_CNTRL);
+ status |= GAMMA_ENABLE_SPR;
+ I915_WRITE(GAMMA_SPA_CNTRL, status);
+
+ /* Enable gamma on Sprite plane B */
+ status = I915_READ(GAMMA_SPB_CNTRL);
+ status |= GAMMA_ENABLE_SPR;
+ I915_WRITE(GAMMA_SPB_CNTRL, status);
+
+ pstatus->gamma_enabled = true;
+ DRM_DEBUG("Gamma enabled on Pipe A\n");
+ return 0;
+}
+
+
+/* Load gamma correction values corresponding to supplied
+gamma and program palette accordingly */
+int intel_crtc_enable_gamma(struct drm_device *dev, u32 identifier)
+{
+ switch (identifier) {
+ /* Whole pipe level correction */
+ case pipe_a:
+ case pipe_b:
+ return intel_enable_pipe_gamma(dev, identifier);
+
+ /* Primary display planes */
+ case plane_a:
+ case plane_b:
+ return intel_enable_plane_gamma(dev, identifier);
+
+ /* Sprite planes */
+ case sprite_a:
+ case sprite_b:
+ case sprite_c:
+ case sprite_d:
+ return intel_enable_sprite_gamma(dev, identifier);
+
+ default:
+ DRM_ERROR("Invalid identifier to enable gamma\n");
+ return -EINVAL;
+ }
+}
+
static bool intel_clrmgr_enable_gamma(struct drm_device *dev, int identifier)
{
+ if (intel_crtc_enable_gamma(dev, identifier)) {
+ DRM_ERROR("\nClrmgr: Gamma enable failed");
+ return false;
+ }
+
+ DRM_DEBUG("\nClrmgr: Gamma successfully enabled");
return true;
}

+
/*
* intel_disable_csc
* Disable color space conversion on PIPE
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e0b7d06..1dd2d72 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -341,7 +341,7 @@ static void vlv_clock(int refclk, intel_clock_t *clock)
/**
* Returns whether any output on the specified pipe is of the specified type
*/
-static bool intel_pipe_has_type(struct drm_crtc *crtc, int type)
+bool intel_pipe_has_type(struct drm_crtc *crtc, int type)
{
struct drm_device *dev = crtc->dev;
struct intel_encoder *encoder;
@@ -3492,7 +3492,7 @@ void hsw_disable_ips(struct intel_crtc *crtc)
}

/** Loads the palette/gamma unit for the CRTC with the prepared values */
-static void intel_crtc_load_lut(struct drm_crtc *crtc)
+void intel_crtc_load_lut(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3537,6 +3537,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
if (reenable_ips)
hsw_enable_ips(intel_crtc);
}
+EXPORT_SYMBOL(intel_crtc_load_lut);

static void ironlake_crtc_enable(struct drm_crtc *crtc)
{
--
1.7.10.4