diff mbox

[55/72] imx-drm: Implement DRM gamma set

Message ID 1414796095-10107-56-git-send-email-steve_longerbeam@mentor.com (mailing list archive)
State New, archived
Headers show

Commit Message

Steve Longerbeam Oct. 31, 2014, 10:54 p.m. UTC
Implement the DRM gamma set API. This API expects that the adapter
will use a gamma-corrected CLUT, but the CLUT on i.MX6 is insufficient
for that purpose.

But the i.MX6 does support gamma correction via a set of registers
that define a piecewise linear approximation to a luminance
gamma correction curve, which is what this implementation uses.

The input gamma-corrected luminance values to ipu_drm_gamma_set() must
be in a specific format defined in the i.MX6 reference manual.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/imx-drm-core.c |    3 +-
 drivers/staging/imx-drm/imx-drm.h      |    2 +
 drivers/staging/imx-drm/ipuv3-crtc.c   |   85 ++++++++++++++++++++++++++++++++
 drivers/staging/imx-drm/ipuv3-plane.c  |   10 ++++
 drivers/staging/imx-drm/ipuv3-plane.h  |    3 ++
 5 files changed, 102 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index e0178d6..084ed53 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -387,7 +387,8 @@  int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 
 	*new_crtc = imx_drm_crtc;
 
-	ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
+	ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc,
+					   DRM_IMX_GAMMA_SIZE);
 	if (ret)
 		goto err_register;
 
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index ec084fe..bf6b06b 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -52,4 +52,6 @@  int imx_drm_encoder_parse_of(struct drm_device *drm,
 void imx_drm_connector_destroy(struct drm_connector *connector);
 void imx_drm_encoder_destroy(struct drm_encoder *encoder);
 
+#define DRM_IMX_GAMMA_SIZE 16
+
 #endif /* _IMX_DRM_H_ */
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 3040f8e..4f2ba40 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -171,10 +171,95 @@  static int ipu_crtc_page_flip(struct drm_crtc *crtc,
 	return ipu_plane_page_flip(crtc->primary, fb, event, page_flip_flags);
 }
 
+/*
+ * Normally the DRM Gamma API is used to program a color LUT that contains
+ * gamma-corrected pixel values for red, green, and blue input pixel values
+ * (normally in the range 0 to 255).
+ *
+ * However the i.MX6 LUT is only 256 entries, so it only supports 8 bpp
+ * indexed pixel format. Therefore if the i.MX6 LUT were used to implement
+ * gamma correction, th DRM framebuffer would have to use 8 bpp indexed pixel
+ * format which is insufficient for most use cases. To support a gamma
+ * correcting LUT with full RGB24 or YUV444 pixel formats, there would have
+ * to be 3 separate 256-entry LUTs for each color component.
+ *
+ * But the i.MX6 does support gamma correction via a set of registers that
+ * define a piecewise linear approximation to a luminance gamma correction
+ * curve. This function uses this approach.
+ *
+ * The input pixel values to this function must be in a specific format
+ * according to the i.MX6 reference manual (see Table 37-28 in the
+ * Rev. 1 TRM, dated 04/2013). This info is reprinted here:
+ *
+ * "The required Gamma correction slope for a specific display should be
+ * provided by the display manufacture. This information can be provided
+ * in various forms, as graph or formula. The gamma correction input pixel
+ * level (Gin) should be normalized to a maximum of 383. The gamma correction
+ * output pixel level (Gout) should be normalized to a maximum of 255. Then
+ * the following data should be collected:
+ *
+ * Table 37-28. Gamma correction values
+ *   Gin   Gout
+ *   ---   -----
+ *     0   Gout0
+ *     2   Gout1
+ *     4   Gout2
+ *     8   Gout3
+ *    16   Gout4
+ *    32   Gout5
+ *    64   Gout6
+ *    96   Gout7
+ *   128   Gout8
+ *   160   Gout9
+ *   192   Gout10
+ *   224   Gout11
+ *   256   Gout12
+ *   288   Gout13
+ *   320   Gout14
+ *   352   Gout15"
+ *
+ *
+ * The 16 Gout values must be placed in the input lum[] array. The green
+ * and blue input arrays are ignored.
+ *
+ * The gamma register values are then computed according to Table 37-29
+ * in the Rev. 1 TRM.
+ */
+static void ipu_crtc_gamma_set(struct drm_crtc *crtc,
+			       u16 *lum, u16 *g_unused, u16 *b_unused,
+			       uint32_t start, uint32_t size)
+{
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	u32 m[DRM_IMX_GAMMA_SIZE], b[DRM_IMX_GAMMA_SIZE];
+	int i;
+
+	if (size != DRM_IMX_GAMMA_SIZE)
+		return;
+
+	for (i = 0; i < size; i++) {
+		if (i == 0) {
+			b[0] = lum[0];
+			m[0] = 16 * (lum[1] - lum[0]);
+		} else if (i == 15) {
+			b[15] = lum[15];
+			m[15] = 255 - lum[15];
+		} else if (i < 5) {
+			b[i] = 2 * lum[i] - lum[i+1];
+			m[i] = (lum[i+1] - lum[i]) << (5 - i);
+		} else {
+			b[i] = lum[i];
+			m[i] = lum[i+1] - lum[i];
+		}
+	}
+
+	ipu_plane_gamma_set(&ipu_crtc->plane[0], true, m, b);
+}
+
 static const struct drm_crtc_funcs ipu_crtc_funcs = {
 	.set_config = drm_crtc_helper_set_config,
 	.destroy = drm_crtc_cleanup,
 	.page_flip = ipu_crtc_page_flip,
+	.gamma_set = ipu_crtc_gamma_set,
 };
 
 static int ipu_crtc_mode_set(struct drm_crtc *crtc,
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
index 3293e84..2912aa6 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.c
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -380,6 +380,16 @@  void ipu_plane_disable(struct ipu_plane *ipu_plane)
 		ipu_dp_disable(ipu_plane->dp);
 }
 
+int ipu_plane_gamma_set(struct ipu_plane *ipu_plane,
+			bool enable, u32 *m, u32 *b)
+{
+	if (!ipu_plane->dp)
+		return -EINVAL;
+
+	return ipu_dp_set_gamma_correction(ipu_plane->dp, enable, m, b);
+}
+
+
 /*
  * drm_plane API
  */
diff --git a/drivers/staging/imx-drm/ipuv3-plane.h b/drivers/staging/imx-drm/ipuv3-plane.h
index 4d856e9..912902a 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.h
+++ b/drivers/staging/imx-drm/ipuv3-plane.h
@@ -70,4 +70,7 @@  void ipu_plane_disable(struct ipu_plane *plane);
 int ipu_plane_get_resources(struct ipu_plane *plane);
 void ipu_plane_put_resources(struct ipu_plane *plane);
 
+int ipu_plane_gamma_set(struct ipu_plane *ipu_plane,
+			bool enable, u32 *m, u32 *b);
+
 #endif