[PATCH 1/6] drm/i915: Add Color manager framework

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

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.sharma@intel.com>
Signed-off-by: Uma Shankar <uma.shankar@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.sharma@intel.com>
+ * Uma Shankar <uma.shankar@intel.com>
+ * Shobhit Kumar <shobhit.kumar@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.sharma@intel.com>
+ * Uma Shankar <uma.shankar@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