Intel color manager is a new framework to provide control over
few of the color properties (supported by intel Gen 7 and+
hardware) via sysfs interface. Currently supported properties
are:
1. CSC correction (wide gamute)
2. Gamma correction
3. Hue and Saturation correction
4. Brightness and contrast correction

This patch contains basic implementation of color manager
framework consisting:
1. A register function, which gets called from a dispaly
   while initializing its DRM connector(for example eDP
   and Mipi).
2. Read and write functions for /sysfs interface
3. A command and a data parser.
4. Dummy prototypes for color correction functions.

The sysfs entry will be created at:
/sys/class/drm/<connector-name>/color-manager
Signed-off-by: Shashank Sharma <shashank.sha...@intel.com>
Signed-off-by: Uma Shankar <uma.shan...@intel.com>
---
 drivers/gpu/drm/i915/Makefile       |    1 +
 drivers/gpu/drm/i915/i915_drv.h     |   29 ++
 drivers/gpu/drm/i915/intel_clrmgr.c |  643 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_clrmgr.h |  238 +++++++++++++
 drivers/gpu/drm/i915/intel_dp.c     |    4 +
 drivers/gpu/drm/i915/intel_dsi.c    |    4 +
 6 files changed, 919 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/intel_clrmgr.c
 create mode 100644 drivers/gpu/drm/i915/intel_clrmgr.h

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 4850494..0d8d877 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -40,6 +40,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
          intel_sprite.o \
          intel_opregion.o \
          intel_sideband.o \
+         intel_clrmgr.o \
          intel_uncore.o \
          dvo_ch7xxx.o \
          dvo_ch7017.o \
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index b4587ac..6c8cbc3 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -79,6 +79,13 @@ enum plane {
 };
 #define plane_name(p) ((p) + 'A')
 
+enum sprite_plane {
+       SPRITE_PLANE_A = 0,
+       SPRITE_PLANE_B = 1,
+       SPRITE_PLANE_C = 0,
+       SPRITE_PLANE_D = 1,
+};
+
 #define sprite_name(p, s) ((p) * INTEL_INFO(dev)->num_sprites + (s) + 'A')
 
 enum port {
@@ -1391,6 +1398,25 @@ struct intel_pipe_crc {
        wait_queue_head_t wq;
 };
 
+/*
+  * Intel color manager structures.
+  * Used to represent the current status of
+  * color manager parameters
+  */
+struct clrmgr_pipe_status {
+       bool csc_enabled;
+       bool gamma_enabled;
+       bool hs_enabled;
+       bool cb_enabled;
+       bool gamma_s_enabled;
+       int planeid;
+};
+
+struct clrmgr_map {
+       struct drm_connector *connector;
+       struct clrmgr_pipe_status *pstatus;
+};
+
 typedef struct drm_i915_private {
        struct drm_device *dev;
        struct kmem_cache *slab;
@@ -1594,6 +1620,8 @@ typedef struct drm_i915_private {
        struct i915_dri1_state dri1;
        /* Old ums support infrastructure, same warning applies. */
        struct i915_ums_state ums;
+       /* Color manager current status */
+       struct clrmgr_map clrmgr_status;
 } drm_i915_private_t;
 
 static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
@@ -2008,6 +2036,7 @@ extern void intel_uncore_early_sanitize(struct drm_device 
*dev);
 extern void intel_uncore_init(struct drm_device *dev);
 extern void intel_uncore_check_errors(struct drm_device *dev);
 extern void intel_uncore_fini(struct drm_device *dev);
+extern bool intel_clrmgr_register(struct drm_connector *connector);
 
 void
 i915_enable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe,
diff --git a/drivers/gpu/drm/i915/intel_clrmgr.c 
b/drivers/gpu/drm/i915/intel_clrmgr.c
new file mode 100644
index 0000000..2c826f3
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_clrmgr.c
@@ -0,0 +1,643 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Shashank Sharma <shashank.sha...@intel.com>
+ * Uma Shankar <uma.shan...@intel.com>
+ * Shobhit Kumar <shobhit.ku...@intel.com>
+ */
+
+#include <linux/device.h>
+#include "drmP.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "intel_clrmgr.h"
+
+/* Sprite register default gamma values */
+u32 default_sprite_gamma_vals[] = {
+       0, 0, 0, 0, 0, 0
+};
+
+/* Gamma lookup table for Sprite planes */
+u32 gamma_sprite_softlut[GAMMA_SP_MAX_COUNT] = {
+       0, 0, 0, 0, 0, 1023
+};
+
+/* Gamma soft lookup table for default gamma =1.0 */
+u32 gamma_softlut[GAMMA_CORRECT_MAX_COUNT] =  {
+       0x000000, 0x0, 0x020202, 0x0, 0x040404, 0x0, 0x060606, 0x0,
+       0x080808, 0x0, 0x0A0A0A, 0x0, 0x0C0C0C, 0x0, 0x0E0E0E, 0x0,
+       0x101010, 0x0, 0x121212, 0x0, 0x141414, 0x0, 0x161616, 0x0,
+       0x181818, 0x0, 0x1A1A1A, 0x0, 0x1C1C1C, 0x0, 0x1E1E1E, 0x0,
+       0x202020, 0x0, 0x222222, 0x0, 0x242424, 0x0, 0x262626, 0x0,
+       0x282828, 0x0, 0x2A2A2A, 0x0, 0x2C2C2C, 0x0, 0x2E2E2E, 0x0,
+       0x303030, 0x0, 0x323232, 0x0, 0x343434, 0x0, 0x363636, 0x0,
+       0x383838, 0x0, 0x3A3A3A, 0x0, 0x3C3C3C, 0x0, 0x3E3E3E, 0x0,
+       0x404040, 0x0, 0x424242, 0x0, 0x444444, 0x0, 0x464646, 0x0,
+       0x484848, 0x0, 0x4A4A4A, 0x0, 0x4C4C4C, 0x0, 0x4E4E4E, 0x0,
+       0x505050, 0x0, 0x525252, 0x0, 0x545454, 0x0, 0x565656, 0x0,
+       0x585858, 0x0, 0x5A5A5A, 0x0, 0x5C5C5C, 0x0, 0x5E5E5E, 0x0,
+       0x606060, 0x0, 0x626262, 0x0, 0x646464, 0x0, 0x666666, 0x0,
+       0x686868, 0x0, 0x6A6A6A, 0x0, 0x6C6C6C, 0x0, 0x6E6E6E, 0x0,
+       0x707070, 0x0, 0x727272, 0x0, 0x747474, 0x0, 0x767676, 0x0,
+       0x787878, 0x0, 0x7A7A7A, 0x0, 0x7C7C7C, 0x0, 0x7E7E7E, 0x0,
+       0x808080, 0x0, 0x828282, 0x0, 0x848484, 0x0, 0x868686, 0x0,
+       0x888888, 0x0, 0x8A8A8A, 0x0, 0x8C8C8C, 0x0, 0x8E8E8E, 0x0,
+       0x909090, 0x0, 0x929292, 0x0, 0x949494, 0x0, 0x969696, 0x0,
+       0x989898, 0x0, 0x9A9A9A, 0x0, 0x9C9C9C, 0x0, 0x9E9E9E, 0x0,
+       0xA0A0A0, 0x0, 0xA2A2A2, 0x0, 0xA4A4A4, 0x0, 0xA6A6A6, 0x0,
+       0xA8A8A8, 0x0, 0xAAAAAA, 0x0, 0xACACAC, 0x0, 0xAEAEAE, 0x0,
+       0xB0B0B0, 0x0, 0xB2B2B2, 0x0, 0xB4B4B4, 0x0, 0xB6B6B6, 0x0,
+       0xB8B8B8, 0x0, 0xBABABA, 0x0, 0xBCBCBC, 0x0, 0xBEBEBE, 0x0,
+       0xC0C0C0, 0x0, 0xC2C2C2, 0x0, 0xC4C4C4, 0x0, 0xC6C6C6, 0x0,
+       0xC8C8C8, 0x0, 0xCACACA, 0x0, 0xCCCCCC, 0x0, 0xCECECE, 0x0,
+       0xD0D0D0, 0x0, 0xD2D2D2, 0x0, 0xD4D4D4, 0x0, 0xD6D6D6, 0x0,
+       0xD8D8D8, 0x0, 0xDADADA, 0x0, 0xDCDCDC, 0x0, 0xDEDEDE, 0x0,
+       0xE0E0E0, 0x0, 0xE2E2E2, 0x0, 0xE4E4E4, 0x0, 0xE6E6E6, 0x0,
+       0xE8E8E8, 0x0, 0xEAEAEA, 0x0, 0xECECEC, 0x0, 0xEEEEEE, 0x0,
+       0xF0F0F0, 0x0, 0xF2F2F2, 0x0, 0xF4F4F4, 0x0, 0xF6F6F6, 0x0,
+       0xF8F8F8, 0x0, 0xFAFAFA, 0x0, 0xFCFCFC, 0x0, 0xFEFEFE, 0x0
+};
+
+/* Color space conversion coff's */
+u32 csc_softlut[CSC_MAX_COEFF_COUNT] = {
+       1024,    0, 67108864, 0, 0, 1024
+};
+
+u32 cb_softlut[CB_MAX_COEFF_COUNT] = {
+       0x80
+};
+
+u32 hs_softlut[HS_MAX_COEFF_COUNT] = {
+       0x1000000
+};
+
+u32 *clrmgr_luts[] = {
+       csc_softlut,
+       gamma_softlut,
+       cb_softlut,
+       hs_softlut,
+       gamma_sprite_softlut
+};
+
+/* Hue Saturation defaults */
+struct hue_saturationlut saved_hsvals[VLV_NO_SPRITE_REG] = {
+       {sprite_a, 0x1000000},
+       {sprite_b, 0x1000000},
+       {sprite_c, 0x1000000},
+       {sprite_d, 0x1000000}
+};
+
+/* Contrast brightness defaults */
+struct cont_brightlut saved_cbvals[VLV_NO_SPRITE_REG] = {
+       {sprite_a, 0x80},
+       {sprite_b, 0x80},
+       {sprite_c, 0x80},
+       {sprite_d, 0x80}
+};
+
+/* Get no of pipes in SOC */
+static int get_no_of_pipes(struct drm_device *dev)
+{
+       if (!dev) {
+               DRM_ERROR("NULL input to get no of pipes");
+               return 0;
+       }
+
+       if (IS_VALLEYVIEW(dev))
+               return VLV_NO_OF_PIPES;
+       if (IS_HASWELL(dev))
+               return HSW_NO_OF_PIPES;
+
+       return 0;
+}
+
+static bool intel_clrmgr_disable_hs(struct drm_device *dev, int identifier)
+{
+       return true;
+}
+
+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)
+{
+       return true;
+}
+
+static void intel_clrmgr_disable_csc(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_cb(struct drm_device *dev, int identifier)
+{
+       return true;
+}
+
+static bool intel_clrmgr_enable_gamma(struct drm_device *dev, int identifier)
+{
+       return true;
+}
+
+static bool intel_clrmgr_enable_csc(struct drm_device *dev, int identifier)
+{
+       return true;
+}
+
+/*
+* Enable a color manager property
+* This function assumes all the validation is done
+* by the caller
+*/
+static bool intel_clrmgr_enable_property(struct drm_device *dev,
+               int property, int identifier)
+{
+       switch (property) {
+       case clrmgr_csc:
+               intel_clrmgr_enable_csc(dev, identifier);
+               break;
+       case clrmgr_gamma:
+       case clrmgr_gammaspr:
+               intel_clrmgr_enable_gamma(dev, identifier);
+               break;
+       case clrmgr_cb:
+               intel_clrmgr_enable_cb(dev, identifier);
+               break;
+       case clrmgr_hs:
+               intel_clrmgr_enable_hs(dev, identifier);
+               break;
+       default:
+               DRM_ERROR("Clrmgr: Enable, invalid property %d", property);
+               return false;
+       }
+
+       return true;
+}
+
+/*
+* Disable a color manager property
+* This function assumes all the validation is done
+* by the caller
+*/
+static bool intel_clrmgr_disable_property(struct drm_device *dev,
+               int property, int identifier)
+{
+       switch (property) {
+       case clrmgr_csc:
+               intel_clrmgr_disable_csc(dev, identifier);
+               break;
+       case clrmgr_gamma:
+               intel_clrmgr_disable_gamma(dev, identifier);
+               break;
+       case clrmgr_cb:
+               intel_clrmgr_disable_cb(dev, identifier);
+               break;
+       case clrmgr_hs:
+               intel_clrmgr_disable_hs(dev, identifier);
+               break;
+       }
+       DRM_DEBUG_DRIVER("Clrmgr: %s disabled",
+               clrmgr_properties[property]);
+       return true;
+}
+
+/*
+* _parse_clrmgr_data: Extract the data from color manager buffer
+* The data parser follows a strict grammar.
+===============================
+* -The values must start with 0x and
+* -The values must be seperated by a comma
+* -There mustn't be a space after/before comma
+* -No non alphanumeric at start
+* -Sample: 0x5678,0xABCD
+*/
+int _parse_clrmgr_data(uint *dest, char *src, int max)
+{
+       int size = 0;
+       int bytes = 0;
+       char *populate = NULL;
+
+       /* Check grammar */
+       if (!dest || !src || *src != '0') {
+               DRM_ERROR("Clrmgr: Invalid input to parser");
+               return -EINVAL;
+       }
+
+       /* Extract values from buffer */
+       while ((size < max) && (*src != '\n')) {
+               populate = strsep(&src, ",");
+               if (!populate) {
+                       if (size < max)
+                               DRM_ERROR("Clrmgr: Parser: %d values missing",
+                                       max-size);
+                       break;
+               }
+
+               /* Consider ',' also for length */
+               bytes += (strlen(populate)+1);
+               if (kstrtouint((const char *)populate, CLRMGR_PARSE_BASE,
+                       &dest[size++])) {
+                       DRM_ERROR("ClrMgr Parse: Invalid limit\n");
+                       return -EINVAL;
+               }
+
+               if (CLRMGR_DEBUG_ENABLE)
+                       DRM_DEBUG_DRIVER("Parse data: dest[%d] = 0x%x",
+                       size-1, dest[size-1]);
+
+               /* End of data */
+               if (src == NULL || *src == '\0') {
+                       if (size < max)
+                               DRM_ERROR("Clrmgr: Parser: %d values missing",
+                               max-size);
+                       break;
+               }
+       }
+
+       DRM_DEBUG_DRIVER("Clrmgr: Parser: Loaded %d bytes from source", bytes);
+       return bytes;
+}
+
+/*
+* _extract_cmd
+* Actual extraction and interpratation of a
+* color manager command
+*/
+int _extract_cmd(const char *buf)
+{
+       u8 count = 2;
+       u8 update = 0;
+       int cmd = 0;
+
+       if (!buf) {
+               DRM_ERROR("Clrmgr: Apply: invalid input to extract_cmd\n");
+               return -1;
+       }
+
+       /* Check for alphanumeric chars */
+       while (count--) {
+               if (*buf >= 'A' && *buf <= 'F')
+                       update = (*buf - 'A' + CLRMGR_HEX_ADDITION);
+               else if (*buf >= 'a' && *buf <= 'f')
+                       update = (*buf - 'a' + CLRMGR_HEX_ADDITION);
+               else if (*buf >= '0' && *buf <= '9')
+                       update = (*buf - '0');
+               else {
+                       DRM_ERROR("Clrmgr: extract_cmd: Stupid input");
+                       return -1;
+               }
+               cmd = cmd * CLRMGR_PARSE_BASE + update;
+               buf++;
+       }
+       DRM_DEBUG_DRIVER("Clrmgr: Extarcted: %d", cmd);
+       return cmd;
+}
+
+
+/*
+* _parse_clrmgr_cmd:
+* Extract command from color EDID
+*Color EDID (4 bytes) :
+*================
+*Byte 0        : Property to modify
+*Byte 1        : Enable /Disable property
+*Byte 2        : Identifier (Plane/Pipe)
+*Byte 3        : How many data bytes are following this byte
+*
+*      <1Byte>   <1Byte>                      <1Byte>          <1Byte>
+*<<=property=>,<=enable/disable=>,<=identifier=>,<=No of data blocks=>,
+*<0xdata>,<0xdata>,<0xdata> ..... <0xdata>
+* Sample command+ data : 0x01010001,0x1234
+* This is to enable Gamma on Pipe A, with val=0x1234
+*/
+bool _parse_clrmgr_cmd(const char *ubuf, struct clrmgr_cmd *cmd)
+{
+       int ret = 0;
+
+       /* Validate input, command must start with 0x */
+       if (!ubuf || !cmd || *ubuf != '0') {
+               DRM_ERROR("Clrmgr: Apply: invalid input to parse_command\n");
+               return false;
+       }
+
+       /* Extract property to be changed */
+       ret = _extract_cmd(ubuf + CLR_EDID_PROPERTY);
+       if (ret < 0) {
+               DRM_ERROR("Clrmgr: Parse: extract property failed\n");
+               return false;
+       }
+       cmd->property = ret;
+
+       /* Extract enabled/disable choice */
+       ret = _extract_cmd(ubuf + CLR_EDID_ENABLE);
+       if (ret  < 0) {
+               DRM_ERROR("Clrmgr: Parse: extract enable failed\n");
+               return false;
+       }
+       cmd->enable = (ret ? true : false);
+
+       /* Extract Identifier of pipe/plane */
+       ret = _extract_cmd(ubuf + CLR_EDID_IDENTIFIER);
+       if (ret < 0) {
+               DRM_ERROR("Clrmgr: Parse: extract identifier failed\n");
+               return false;
+       }
+       cmd->identifier = ret;
+
+       /* Extract no of data bytes following */
+       ret = _extract_cmd(ubuf + CLR_EDID_SIZE);
+       if (ret < 0) {
+               DRM_ERROR("Clrmgr: Parse: extract size failed\n");
+               return false;
+       }
+       cmd->size = ret;
+       return true;
+}
+
+/*
+* intel_clrmgr_apply:
+* Parse, decode and Apply a change.
+*/
+bool intel_clrmgr_apply(struct drm_device *dev,
+       const char *ubuf, size_t count)
+{
+       bool ret = false;
+       struct clrmgr_cmd cmd = {0, 0, 0, 0};
+       char *raw_data = NULL;
+
+       if (!ubuf || !count) {
+               DRM_ERROR("Clrmgr: Apply: insufficient data\n");
+               return -EINVAL;
+       }
+
+       /* Parse command */
+       if (!_parse_clrmgr_cmd(ubuf, &cmd)) {
+               DRM_ERROR("Clrmgr: Command parsing failed");
+               return false;
+       }
+
+       /* Validate property */
+       if (cmd.property < clrmgr_csc || cmd.property > clrmgr_gammaspr) {
+               DRM_ERROR("Clrmgr: Invalid input, propery Max=%d, Min=%d",
+                       clrmgr_csc, clrmgr_gammaspr);
+               return false;
+       }
+
+       /* Validate Identifier */
+       if (cmd.identifier < pipe_a || cmd.identifier > sprite_d) {
+               DRM_ERROR("Clrmgr: Invalid input, identifier Max=%d, Min=%d",
+                       pipe_a, sprite_d);
+               return false;
+       }
+
+       if (cmd.enable) {
+               /* Validite size, min 1 block of data is required */
+               if (cmd.size > clrmgr_maxsize[cmd.property]  ||
+                       cmd.size < CLR_MGR_PARSE_MIN) {
+                       DRM_ERROR("Clrmgr: Invalid size=%d, range %d to %d",
+                               (int)count, CLR_MGR_PARSE_MIN,
+                               clrmgr_maxsize[cmd.property]);
+                       return false;
+               }
+
+               raw_data = kzalloc(count, GFP_KERNEL);
+               if (!raw_data) {
+                       DRM_ERROR("Clrmgr: Out of memory");
+                       return false;
+               }
+
+               /* Get the data */
+               memcpy((void *)raw_data,
+                       (const void *)&ubuf[CLR_EDID_DATA], count);
+
+               /* Parse data and load corresponsing soft LUT */
+               if (_parse_clrmgr_data(clrmgr_luts[cmd.property], raw_data,
+                               cmd.size) < 0) {
+                       DRM_ERROR("Clrmgr: Parse failed");
+                       ret = false;
+                       goto FREE_AND_RETURN;
+               }
+
+               /* Data loaded, now do changes in property */
+               if (!intel_clrmgr_enable_property(dev, cmd.property,
+                       cmd.identifier)) {
+                       DRM_ERROR("Clrmgr: Enable property %s failed",
+                               clrmgr_properties[cmd.property]);
+                       ret = false;
+                       goto FREE_AND_RETURN;
+               }
+       } else {
+               /* Validite size, for disable just command is enough */
+               if (cmd.size) {
+                       DRM_ERROR("Clrmgr: Invalid input, No data required");
+                       return false;
+               }
+
+               /* Disable specified property */
+               if (!intel_clrmgr_disable_property(dev, cmd.property,
+                       cmd.identifier)) {
+                       DRM_ERROR("Clrmgr: Disable property %s failed",
+                               clrmgr_properties[cmd.property]);
+                       return false;
+               }
+       }
+
+       ret = true;
+       DRM_DEBUG_DRIVER("Clrmgr: apply success");
+
+FREE_AND_RETURN:
+       kfree(raw_data);
+       return ret;
+}
+
+/*
+  * Color manager write function.
+  * Current interface is /sys/class/drm/<connector-name>/color-manager
+  * Shows the current status of color manager features
+*/
+ssize_t intel_clrmgr_write(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *ba, char *ubuf,
+               loff_t offset, size_t count)
+{
+       struct device *connector_dev = container_of(kobj, struct device, kobj);
+       struct drm_connector *connector = dev_get_drvdata(connector_dev);
+       struct drm_device *dev = connector->dev;
+
+       DRM_DEBUG_DRIVER("Clrmgr write");
+
+       /* Validate input */
+       if (!count || !ubuf) {
+               DRM_ERROR("Clrmgr: insufficient data\n");
+               return -EINVAL;
+       }
+
+       /* Parse the color EDID, apply the change */
+       if (!intel_clrmgr_apply(dev, ubuf, count)) {
+               DRM_ERROR("Clrmgr: Parse and apply failed\n");
+               return -1;
+       }
+
+       DRM_DEBUG_DRIVER("Clrmgr: Write success\n");
+       return count;
+}
+
+/*
+  * Color manager read function.
+  * Current interface is /sys/class/drm/<connector-name>/color-manager
+  * Shows the current status of color manager features
+*/
+ssize_t intel_clrmgr_read(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *ba, char *buf, loff_t off, size_t count)
+{
+       u16 size = 0;
+       u8 pipe_count = 0;
+       const char *p = NULL;
+       struct device *connector_dev = container_of(kobj, struct device, kobj);
+       struct drm_connector *connector = dev_get_drvdata(connector_dev);
+       struct drm_device *dev = connector->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct clrmgr_pipe_status *pstatus = dev_priv->clrmgr_status.pstatus;
+
+       if (!pstatus) {
+               DRM_DEBUG_DRIVER("Clrmgr not initialized yet");
+               return 0;
+       }
+
+       /* One page read is enough */
+       if (off)
+               return 0;
+
+       /* Get no of pipes in this arch */
+       pipe_count = get_no_of_pipes(dev);
+       if (!pipe_count) {
+               DRM_ERROR("This Gen device is not supported, cant get pipes\n");
+               return false;
+       }
+
+       /* Load per pipe color status */
+       do {
+               size += sprintf(buf + size, "PIPE %c\n", ('A' + pipe_count-1));
+               size += sprintf(buf + size, "=====\n");
+               p = clrmgr_properties[clrmgr_csc];
+               size += sprintf(buf + size, "1.%s %s\n", p,
+               pstatus[pipe_count-1].csc_enabled ? "Enabled" : "Disabled");
+               p = clrmgr_properties[clrmgr_gamma];
+               size += sprintf(buf + size, "2.%s %s\n", p,
+               pstatus[pipe_count-1].gamma_enabled ? "Enabled" : "Disabled");
+               p = clrmgr_properties[clrmgr_cb];
+               size += sprintf(buf + size, "3.%s %s\n", p,
+               pstatus[pipe_count-1].cb_enabled ? "Enabled" : "Disabled");
+               p = clrmgr_properties[clrmgr_hs];
+               size += sprintf(buf + size, "4.%s %s\n", p,
+               pstatus[pipe_count-1].hs_enabled ? "Enabled" : "Disabled");
+               p = clrmgr_properties[clrmgr_gammaspr];
+               size += sprintf(buf + size, "5.%s %s\n", p,
+               pstatus[pipe_count-1].gamma_s_enabled ? "Enabled" : "Disabled");
+       } while (--pipe_count);
+
+       DRM_DEBUG_DRIVER("Clrmgr Read done, %d bytes", size);
+       return size;
+}
+
+static struct bin_attribute clrmgr_attr = {
+       .attr.name = "color-manager",
+       .attr.mode = 0644,
+       .size = 0,
+       .read = intel_clrmgr_read,
+       .write = intel_clrmgr_write
+};
+
+/* Register color manager with a connector
+  * The connecter init function should call this function
+  * The current implementation is for Primary/Fix panels Like Mipi/EDP
+*/
+bool intel_clrmgr_register(struct drm_connector *connector)
+{
+       int pipe_count = 0;
+       struct clrmgr_pipe_status *pstatus = NULL;
+       struct drm_device *dev = connector->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       /* Clr mgr is available for Gen 7 and + for now */
+       if (INTEL_INFO(dev)->gen < CLRMGR_GEN_THRESHOLD) {
+               DRM_ERROR("Clrmgr: This Gen device is not supported\n");
+               return false;
+       }
+
+       /* Todo: Current implementation supports only VLV.
+       Extend this for HSW and other gen 7+ devices */
+       if (!IS_VALLEYVIEW(dev)) {
+               DRM_ERROR("Clrmgr: Current implementation supports only VLV\n");
+               return false;
+       }
+
+       /* Create sysfs entry for color manager */
+       if (sysfs_create_bin_file(&connector->kdev->kobj, &clrmgr_attr)) {
+               DRM_ERROR("Clrmgr:  %s Register Color interface failed\n",
+                       drm_get_connector_name(connector));
+               return false;
+       }
+
+       /* Get no of pipes of the arch */
+       pipe_count = get_no_of_pipes(dev);
+       if (!pipe_count) {
+               DRM_ERROR("Clrmgr: Cant get pipe info\n");
+               return false;
+       }
+
+       /* Load color status of the pipes */
+       pstatus = kzalloc(pipe_count * sizeof(struct clrmgr_pipe_status),
+                               GFP_KERNEL);
+       if (!pstatus) {
+               DRM_ERROR("Clrmgr: %s Out of memory\n",
+                       drm_get_connector_name(connector));
+               return false;
+       }
+
+       /* Initialize color status of the pipe,
+         * planeid will be filled with specific enable call
+         */
+       do {
+               pstatus[pipe_count-1].planeid = -1;
+               pstatus[pipe_count-1].csc_enabled = false;
+               pstatus[pipe_count-1].gamma_enabled = false;
+               pstatus[pipe_count-1].hs_enabled = false;
+               pstatus[pipe_count-1].cb_enabled = false;
+               pstatus[pipe_count-1].gamma_s_enabled = false;
+       } while (--pipe_count);
+
+       /* Load color manager status */
+       dev_priv->clrmgr_status.pstatus = pstatus;
+       dev_priv->clrmgr_status.connector = connector;
+
+       DRM_DEBUG_DRIVER("Clrmgr: Successfully registered for %s",
+                       drm_get_connector_name(connector));
+       return true;
+}
+EXPORT_SYMBOL(intel_clrmgr_register);
diff --git a/drivers/gpu/drm/i915/intel_clrmgr.h 
b/drivers/gpu/drm/i915/intel_clrmgr.h
new file mode 100644
index 0000000..25d3491
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_clrmgr.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Shashank Sharma <shashank.sha...@intel.com>
+ * Uma Shankar <uma.shan...@intel.com>
+ */
+
+#ifndef _I915_CLR_MNGR_H_
+#define _I915_CLR_MNGR_H_
+
+
+struct cont_brightlut {
+       short sprite_no;
+       u32 val;
+};
+
+struct hue_saturationlut {
+       short sprite_no;
+       u32 val;
+};
+
+/* Debugging support */
+#define CLRMGR_DEBUG_ENABLE            0
+
+/* General defines */
+#define CLR_MGR_PARSE_MAX              256
+#define CLR_MGR_PARSE_MIN              1
+#define VLV_NO_SPRITE_REG                              4
+#define SIZE_STATUS                            10
+#define CLR_EDID_PROPERTY                      2
+#define CLR_EDID_ENABLE                        (CLR_EDID_PROPERTY + 2)
+#define CLR_EDID_IDENTIFIER            (CLR_EDID_ENABLE + 2)
+#define CLR_EDID_SIZE                          (CLR_EDID_IDENTIFIER + 2)
+#define CLR_EDID_DATA                          (CLR_EDID_SIZE + 3)
+#define CLRMGR_GEN_THRESHOLD   7
+#define VLV_NO_OF_PIPES                        2
+#define HSW_NO_OF_PIPES                        3
+#define CLRMGR_PARSE_BASE              16
+#define CLRMGR_HEX_ADDITION            10
+
+/* Pipe level gamma correction defines */
+#define PIPECONF_GAMMA                 (1<<24)
+#define GAMMA_SP_MAX_COUNT             6
+#define GAMMA_MAX_VAL                  1024
+#define SHIFTBY6(val)                          (val<<6)
+#define GAMMA_CORRECT_MAX_COUNT 256
+
+#define PIPEA_MAX_RED          (dev_priv->info.display_mmio_offset + 0x70010)
+#define PIPEA_MAX_GREEN        (dev_priv->info.display_mmio_offset + 0x70014)
+#define PIPEA_MAX_BLUE (dev_priv->info.display_mmio_offset + 0x70018)
+
+/* Sprite gamma correction regs */
+#define GAMMA_SPA_GAMC0                (dev_priv->info.display_mmio_offset + 
0x721F4)
+#define GAMMA_SPB_GAMC0                (dev_priv->info.display_mmio_offset + 
0x722F4)
+#define GAMMA_SPC_GAMC0                (dev_priv->info.display_mmio_offset + 
0x723F4)
+#define GAMMA_SPD_GAMC0                (dev_priv->info.display_mmio_offset + 
0x724F4)
+#define GAMMA_SP_REG_OFFSET    0x100
+
+/* Sprite control regs */
+#define GAMMA_SPA_CNTRL                (dev_priv->info.display_mmio_offset + 
0x72180)
+#define GAMMA_SPB_CNTRL                (dev_priv->info.display_mmio_offset + 
0x72280)
+#define GAMMA_SPC_CNTRL                (dev_priv->info.display_mmio_offset + 
0x72380)
+#define GAMMA_SPD_CNTRL                (dev_priv->info.display_mmio_offset + 
0x72480)
+#define GAMMA_SP_CTL_OFFSET    0x100
+#define GAMMA_ENABLE_SPR               (1<<30)
+#define GET_SPRITE_CTL(plid)   (GAMMA_SPA_CNTRL +              \
+                               ((plid - sprite_a) * GAMMA_SP_CTL_OFFSET))
+#define GET_SPRITE_REG(plid)   (GAMMA_SPA_GAMC0 +              \
+                               ((plid - sprite_a) * GAMMA_SP_REG_OFFSET))
+
+/* CSC defines and Control Register */
+#define        _PIPEACSC               (dev_priv->info.display_mmio_offset + 
0x600b0)
+#define        _PIPEBCSC               (dev_priv->info.display_mmio_offset + 
0x610b0)
+#define        PIPECSC(p)              (p ? _PIPEACSC : _PIPEBCSC)
+#define        PIPECONF_CSC_ENABLE             (1<<15)
+#define        CSC_MAX_COEFF_COUNT     6
+
+
+/* Sprite Contrast and Brightness Registers */
+#define CB_MAX_COEFF_COUNT     1
+#define SPRITEA_CB_REG         (dev_priv->info.display_mmio_offset + 0x721d0)
+#define SPRITEB_CB_REG         (dev_priv->info.display_mmio_offset + 0x722d0)
+#define SPRITEC_CB_REG         (dev_priv->info.display_mmio_offset + 0x723d0)
+#define SPRITED_CB_REG         (dev_priv->info.display_mmio_offset + 0x724d0)
+#define SPRITE_CB_OFFSET               0x100
+#define GET_SPRITE_CB(plid)            (SPRITEA_CB_REG +               \
+                                       (plid * SPRITE_CB_OFFSET))
+#define CB_DEFAULT_VAL         0x80
+
+/* Sprite Hue and Saturation Registers */
+#define HS_MAX_COEFF_COUNT     1
+#define SPRITEA_HS_REG         0x721d4
+#define SPRITEB_HS_REG         0x722d4
+#define SPRITEC_HS_REG         0x723d4
+#define SPRITED_HS_REG         0x724d4
+#define HS_DEFAULT_VAL         0x1000000
+#define SPRITE_HS_OFFSET               0x100
+#define GET_SPRITE_HS(plid)            (SPRITEA_HS_REG +               \
+                                               (plid * SPRITE_HS_OFFSET))
+
+
+/* Color manager properties */
+const char     *clrmgr_properties[] = {
+       "CSC_CORRECTION",
+       "GAMMA CORRECTION",
+       "BRIGHTNESS/CONTRAST",
+       "HUE/SATURATION",
+       "GAMMA CORRECTTION SPRITE"
+};
+
+/* Color manager max values */
+int clrmgr_maxsize[] = {
+       CSC_MAX_COEFF_COUNT,
+       GAMMA_CORRECT_MAX_COUNT,
+       CB_MAX_COEFF_COUNT,
+       HS_MAX_COEFF_COUNT,
+       GAMMA_SP_MAX_COUNT
+};
+
+/* Color manager features */
+enum clrmgr_features {
+       clrmgr_csc = 0,
+       clrmgr_gamma,
+       clrmgr_cb,
+       clrmgr_hs,
+       clrmgr_gammaspr
+};
+
+struct clrmgr_cmd {
+       bool enable;
+       int size;
+       int identifier;
+       enum clrmgr_features property;
+};
+
+/* Color manager features */
+enum clrmgr_identifiers {
+       pipe_a = 0,
+       pipe_b,
+       pipe_c,
+       plane_a,
+       plane_b,
+       plane_c,
+       sprite_a,
+       sprite_b,
+       sprite_c,
+       sprite_d
+};
+
+/* Required for sysfs calls */
+extern u32 csc_softlut[CSC_MAX_COEFF_COUNT];
+extern u32 gamma_softlut[GAMMA_CORRECT_MAX_COUNT];
+extern u32 gamma_sprite_softlut[GAMMA_SP_MAX_COUNT];
+extern u32 cb_softlut[CB_MAX_COEFF_COUNT];
+extern u32 hs_softlut[HS_MAX_COEFF_COUNT];
+extern void intel_crtc_load_lut(struct drm_crtc *crtc);
+
+/* Data dump */
+#define CLR_LIMIT_INTERNAL             1
+
+#if CLR_LIMIT_INTERNAL
+static inline int _validate_pipe(int identifier)
+{
+       if (identifier != pipe_a) {
+               DRM_ERROR("This functionality is only for PIPE A\n");
+               return -ENOSYS;
+       }
+       return 0;
+}
+static inline int _validate_plane(int identifier)
+{
+       if (identifier != plane_a) {
+               DRM_ERROR("This functionality is only for Plane A\n");
+               return -ENOSYS;
+       }
+       return 0;
+}
+static inline int _validate_sprite(int identifier)
+{
+       if (identifier != sprite_a && identifier != sprite_b) {
+               DRM_ERROR("This functionality is only for Sprite A/B\n");
+               return -ENOSYS;
+       }
+       return 0;
+}
+#else
+static inline int _validate_pipe(int identifier)
+{
+       return 0;
+}
+static inline int _validate_plane(int identifier)
+{
+       return 0;
+}
+static inline int _validate_sprite(int identifier)
+{
+       return 0;
+}
+#endif
+#define clrmgr_get_drvdata(d) dev_get_drvdata(d)
+#define _get_pipe_from_plane(pid) (pid - plane_a)
+
+
+/* Prototypes */
+int parse_clrmgr_input(uint *dest, char *src, int max, int read);
+int do_intel_enable_csc(struct drm_device *dev, void *data,
+                               struct drm_crtc *crtc);
+bool intel_pipe_has_type(const struct drm_crtc *crtc, int type);
+void do_intel_disable_csc(struct drm_device *dev, struct drm_crtc *crtc);
+int intel_crtc_enable_gamma(struct drm_device *dev, u32 identifier);
+int intel_crtc_disable_gamma(struct drm_device *dev, u32 identifier);
+int intel_sprite_cb_adjust(struct drm_device *dev,
+               struct cont_brightlut *cb_ptr);
+int intel_sprite_hs_adjust(struct drm_device *dev,
+               struct hue_saturationlut *hs_ptr);
+void intel_save_clr_mgr_status(struct drm_device *dev);
+bool intel_restore_clr_mgr_status(struct drm_device *dev);
+#endif
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1ac4b11..10ef04e 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -3898,6 +3898,10 @@ intel_dp_init_connector(struct intel_digital_port 
*intel_dig_port,
                I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
        }
 
+       /* Register color manager interface */
+       if (!intel_clrmgr_register(connector))
+               DRM_ERROR("DP: Failed to register color manager features");
+
        return true;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 3ee1db1..ff9bbd8 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -627,6 +627,10 @@ bool intel_dsi_init(struct drm_device *dev)
        fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
        intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
 
+       /* Register to color manager interface */
+       if (!intel_clrmgr_register(connector))
+               DRM_ERROR("Mipi: Failed to register color manager features");
+
        return true;
 
 err:
-- 
1.7.10.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to