From patchwork Thu Feb 20 12:37:22 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Sharma, Shashank" X-Patchwork-Id: 3686801 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 58C2F9F390 for ; Thu, 20 Feb 2014 12:34:51 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4172B2018A for ; Thu, 20 Feb 2014 12:34:49 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id A85C920114 for ; Thu, 20 Feb 2014 12:34:46 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9B0EFFB237; Thu, 20 Feb 2014 04:34:45 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by gabe.freedesktop.org (Postfix) with ESMTP id 26B54FB237 for ; Thu, 20 Feb 2014 04:34:42 -0800 (PST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga102.jf.intel.com with ESMTP; 20 Feb 2014 04:30:22 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.97,512,1389772800"; d="scan'208";a="486539019" Received: from shashanks-desktop.iind.intel.com ([10.223.25.92]) by orsmga002.jf.intel.com with ESMTP; 20 Feb 2014 04:34:38 -0800 From: Shashank Sharma To: intel-gfx@lists.freedesktop.org Date: Thu, 20 Feb 2014 18:07:22 +0530 Message-Id: <1392899847-2641-2-git-send-email-shashank.sharma@intel.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1392899847-2641-1-git-send-email-shashank.sharma@intel.com> References: <1392899847-2641-1-git-send-email-shashank.sharma@intel.com> MIME-Version: 1.0 Cc: uma.shankar@intel.com Subject: [Intel-gfx] =?utf-8?q?=5BPATCH_1/6=5D_drm/i915=3A_Add_Color_manag?= =?utf-8?q?er_framework?= X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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//color-manager Signed-off-by: Shashank Sharma Signed-off-by: Uma Shankar --- 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 + * Uma Shankar + * Shobhit Kumar + */ + +#include +#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//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//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 + * Uma Shankar + */ + +#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: