From 1859d70281224dae97b21c3878a614a0eec7423e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 15 Dec 2011 00:12:05 +0200 Subject: [PATCH] staging: mrst: Add overlay color correction settings MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Allow the overlay brightness, contrast, hue and saturation to be adjusted. Also allows one to select the input range (JPEG vs. MPEG) for the color space conversion. Signed-off-by: Ville Syrjälä Acked-by: Pauli Nieminen Reviewed-by: Jani Nikula Signed-off-by: Kirill A. Shutemov --- drivers/staging/mrst/Makefile | 1 + drivers/staging/mrst/drv/fp_trig.c | 95 ++++++++++++++++++++++++ drivers/staging/mrst/drv/fp_trig.h | 53 +++++++++++++ drivers/staging/mrst/drv/mdfld_overlay.c | 123 ++++++++++++++++++++++++++++++- 4 files changed, 269 insertions(+), 3 deletions(-) create mode 100644 drivers/staging/mrst/drv/fp_trig.c create mode 100644 drivers/staging/mrst/drv/fp_trig.h diff --git a/drivers/staging/mrst/Makefile b/drivers/staging/mrst/Makefile index fa7066a..693cf60 100644 --- a/drivers/staging/mrst/Makefile +++ b/drivers/staging/mrst/Makefile @@ -160,6 +160,7 @@ medfield_gfx-y += \ $(FBDEVDIR)/mrstlfb_linux.o medfield_gfx-y += \ + $(DRMDRVDIR)/fp_trig.o \ $(DRMDRVDIR)/mdfld_dsi_dbi.o \ $(DRMDRVDIR)/mdfld_dsi_dpi.o \ $(DRMDRVDIR)/mdfld_dsi_output.o \ diff --git a/drivers/staging/mrst/drv/fp_trig.c b/drivers/staging/mrst/drv/fp_trig.c new file mode 100644 index 0000000..b73c2e1 --- /dev/null +++ b/drivers/staging/mrst/drv/fp_trig.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 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. + */ + +#include +#include + +#include "fp_trig.h" + +enum { + COS_TAB_SIZE = 128, + LERP_ONE = 1 << 12, +}; + +/* + * cos_tab was generated like this: + * + * for (i = 0; i < COS_TAB_SIZE; i++) + * cos_tab[i] = trunc(cos(M_PI * i / ((COS_TAB_SIZE - 1) * 2)) * (1 << FP_FRAC_BITS)); + * + * The table has one extra element to avoid out of + * bounds access when computing cosine at FP_PI/2. + */ +static const uint16_t cos_tab[COS_TAB_SIZE + 1] = { + 0x8000, 0x7ffd, 0x7ff5, 0x7fe9, 0x7fd7, 0x7fc1, 0x7fa5, 0x7f85, + 0x7f5f, 0x7f35, 0x7f05, 0x7ed1, 0x7e97, 0x7e59, 0x7e15, 0x7dcd, + 0x7d80, 0x7d2e, 0x7cd7, 0x7c7b, 0x7c1a, 0x7bb4, 0x7b4a, 0x7adb, + 0x7a66, 0x79ed, 0x7970, 0x78ed, 0x7866, 0x77da, 0x7749, 0x76b4, + 0x761a, 0x757c, 0x74d9, 0x7431, 0x7385, 0x72d4, 0x721e, 0x7165, + 0x70a6, 0x6fe4, 0x6f1d, 0x6e51, 0x6d82, 0x6cae, 0x6bd5, 0x6af9, + 0x6a18, 0x6934, 0x684b, 0x675e, 0x666d, 0x6578, 0x647e, 0x6382, + 0x6281, 0x617c, 0x6073, 0x5f67, 0x5e57, 0x5d43, 0x5c2c, 0x5b11, + 0x59f2, 0x58d0, 0x57ab, 0x5682, 0x5555, 0x5425, 0x52f2, 0x51bc, + 0x5083, 0x4f46, 0x4e06, 0x4cc3, 0x4b7e, 0x4a35, 0x48e9, 0x479b, + 0x4649, 0x44f5, 0x439e, 0x4245, 0x40e9, 0x3f8a, 0x3e29, 0x3cc6, + 0x3b60, 0x39f8, 0x388d, 0x3721, 0x35b2, 0x3441, 0x32ce, 0x3159, + 0x2fe2, 0x2e69, 0x2cef, 0x2b72, 0x29f4, 0x2874, 0x26f3, 0x2570, + 0x23ec, 0x2266, 0x20df, 0x1f57, 0x1dcd, 0x1c43, 0x1ab7, 0x192a, + 0x179c, 0x160d, 0x147e, 0x12ed, 0x115c, 0x0fca, 0x0e38, 0x0ca5, + 0x0b11, 0x097d, 0x07e9, 0x0654, 0x04bf, 0x032a, 0x0195, 0x0000, +}; + +static unsigned int lerp(unsigned int x1, unsigned int x2, unsigned int alpha) +{ + return ((x1 * (LERP_ONE - alpha)) + (x2 * alpha)) / LERP_ONE; +} + +int fp_cos(unsigned int angle) +{ + unsigned int x, i, quadrant; + int y; + + /* limit angle to [0:FP_PI/2] range */ + quadrant = (angle / (FP_PI / 2)) & 3; + angle &= FP_PI / 2 - 1; + if (quadrant & 1) + angle = FP_PI / 2 - angle; + + /* + * Perform linear interpolation between the points in the table. + * Round x up to keep fp_cos(x) <= cos(x). + */ + x = DIV_ROUND_UP(angle * (COS_TAB_SIZE - 1) * LERP_ONE, FP_PI / 2); + i = x / LERP_ONE; + y = lerp(cos_tab[i], cos_tab[i+1], x & (LERP_ONE - 1)); + + if (quadrant == 1 || quadrant == 2) + y = -y; + + return y; +} + +int fp_sin(unsigned int angle) +{ + return -fp_cos(angle + FP_PI / 2); +} diff --git a/drivers/staging/mrst/drv/fp_trig.h b/drivers/staging/mrst/drv/fp_trig.h new file mode 100644 index 0000000..f3f052d --- /dev/null +++ b/drivers/staging/mrst/drv/fp_trig.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef FP_TRIG_H +#define FP_TRIG_H + +enum { + /* number of fractional bits in results */ + FP_FRAC_BITS = 15, + + /* value of PI */ + FP_PI = 1 << 14, +}; + +/** + * fp_cos - Fixed point cosine + * @angle: positive angle (period 2*FP_PI) + * + * RETURNS: + * Cosine in signed 1. fixed point format + */ +int fp_cos(unsigned int angle); + +/** + * fp_sin - Fixed point sine + * @angle: positive angle (period 2*FP_PI) + * + * RETURNS: + * Sine in signed 1. fixed point format + */ +int fp_sin(unsigned int angle); + +#endif diff --git a/drivers/staging/mrst/drv/mdfld_overlay.c b/drivers/staging/mrst/drv/mdfld_overlay.c index 0e10997..5e821f5 100644 --- a/drivers/staging/mrst/drv/mdfld_overlay.c +++ b/drivers/staging/mrst/drv/mdfld_overlay.c @@ -31,6 +31,8 @@ #include "psb_gtt.h" #include "psb_fb.h" +#include "fp_trig.h" + enum { OVL_DIRTY_REGS = 0x1, OVL_DIRTY_COEFS = 0x2, @@ -542,9 +544,6 @@ static void ovl_setup_regs(struct mfld_overlay *ovl) regs->OCONFIG = OVL_OCONFIG_IEP_BYPASS | OVL_OCONFIG_CSC_MODE; - regs->OCLRC0 = 0x40 << 18; - regs->OCLRC1 = 0x80 << 0; - regs->DCLRKM = OVL_DCLRKM_KEY | 0xffffff; regs->SCHRKEN = 0xff; @@ -934,12 +933,120 @@ mfld_overlay_disable_plane(struct drm_plane *plane) return 0; } +static void ovl_set_brightness_contrast(struct mfld_overlay *ovl, const struct drm_plane_opts *opts) +{ + struct mfld_overlay_regs *regs = ovl->regs.virt; + int bri, con; + + if (opts->csc_range == DRM_CSC_RANGE_MPEG) { + if (opts->contrast >= 0x8000) + /* 255/219 <= contrast <= 7.53125 */ + con = (((opts->contrast - 0x8000) * 815) >> 16) + 75; + else + /* 0.0 <= contrast < 255/219 */ + con = opts->contrast / 440; + } else { + if (opts->contrast >= 0x8000) + /* 1.0 <= contrast <= 7.53125 */ + con = (((opts->contrast - 0x8000) * 837) >> 16) + 64; + else + /* 0.0 <= contrast < 1.0 */ + con = opts->contrast >> 9; + } + + if (opts->csc_range == DRM_CSC_RANGE_MPEG) { + /* 16 * 255/219 = ~19 */ + if (opts->brightness >= 0x8000) + /* -19 <= bri <= 127 */ + bri = ((opts->brightness - 0x8000) / 224 - 19); + else + /* -128 <= bri < -19 */ + bri = (opts->brightness / 300 - 128); + } else { + /* -128 <= bri <= 127 */ + bri = (opts->brightness >> 8) - 128; + } + + /* Scare anyone who touches this code w/o thinking. */ + WARN_ON(con < 0 || con > 482); + WARN_ON(bri < -128 || bri > 127); + + regs->OCLRC0 = ((con & 0x1ff) << 18) | ((bri & 0xff) << 0); + + ovl->dirty |= OVL_DIRTY_REGS; +} + +static void ovl_set_hue_saturation(struct mfld_overlay *ovl, const struct drm_plane_opts *opts) +{ + struct mfld_overlay_regs *regs = ovl->regs.virt; + int sat; + /* [0:0xffff] -> [-FP_PI/2:FP_PI/2] shifted by 2*FP_PI */ + unsigned int deg = ((opts->hue + 2) >> 2) + 3 * FP_PI / 2; + int sh_sin = fp_sin(deg); + int sh_cos = fp_cos(deg); + + if (opts->csc_range == DRM_CSC_RANGE_MPEG) { + if (opts->saturation >= 0x8000) + /* + * abs(sh_sin) + abs(sh_cos) < 8.0, therefore + * 255/224 <= saturation <= 8/(2*sin(PI/4)) + */ + sat = (((opts->saturation - 0x8000) * 1157) >> 16) + 146; + else + /* 0.0 <= saturation < 255/224 */ + sat = opts->saturation / 225; + } else { + if (opts->saturation >= 0x8000) + /* + * abs(sh_sin) + abs(sh_cos) < 8.0, therefore + * 1.0 <= saturation <= 8/(2*sin(PI/4)) + */ + sat = (((opts->saturation - 0x8000) * 1193) >> 16) + 128; + else + /* 0.0 <= saturation < 1.0 */ + sat = opts->saturation >> 8; + } + sh_sin = (sh_sin * sat) / (1 << FP_FRAC_BITS); + sh_cos = (sh_cos * sat) / (1 << FP_FRAC_BITS); + + /* Scare anyone who touches this code w/o thinking. */ + WARN_ON(abs(sh_sin) > 724); + WARN_ON(sh_cos < 0 || sh_cos > 724); + WARN_ON(abs(sh_sin) + sh_cos >= 8 << 7); + + regs->OCLRC1 = ((sh_sin & 0x7ff) << 16) | ((sh_cos & 0x3ff) << 0); + + ovl->dirty |= OVL_DIRTY_REGS; +} + +static int +mfld_overlay_set_plane_opts(struct drm_plane *plane, uint32_t flags, struct drm_plane_opts *opts) +{ + struct mfld_overlay *ovl = to_mfld_overlay(plane); + + /* Must re-compute color correction if YCbCr range is changed */ + if (flags & DRM_MODE_PLANE_CSC_RANGE) + flags |= DRM_MODE_PLANE_BRIGHTNESS | DRM_MODE_PLANE_CONTRAST | + DRM_MODE_PLANE_HUE | DRM_MODE_PLANE_SATURATION; + + if (flags & (DRM_MODE_PLANE_BRIGHTNESS | DRM_MODE_PLANE_CONTRAST)) + ovl_set_brightness_contrast(ovl, opts); + + if (flags & (DRM_MODE_PLANE_HUE | DRM_MODE_PLANE_SATURATION)) + ovl_set_hue_saturation(ovl, opts); + + ovl_commit(ovl); + + return 0; +} + static void mfld_overlay_destroy(struct drm_plane *plane); static const struct drm_plane_funcs mfld_overlay_funcs = { .update_plane = mfld_overlay_update_plane, .disable_plane = mfld_overlay_disable_plane, .destroy = mfld_overlay_destroy, + .set_plane_opts = mfld_overlay_set_plane_opts, }; static const uint32_t mfld_overlay_formats[] = { @@ -1182,6 +1289,16 @@ int mdfld_overlay_init(struct drm_device *dev, int id) /* FIXME move */ ovl_setup_regs(ovl); + /* fill in some defaults */ + drm_plane_opts_defaults(&ovl->base.opts); + ovl->base.opts.csc_range = DRM_CSC_RANGE_MPEG; + ovl->base.opts_flags = DRM_MODE_PLANE_BRIGHTNESS | DRM_MODE_PLANE_CONTRAST | + DRM_MODE_PLANE_HUE | DRM_MODE_PLANE_SATURATION | + DRM_MODE_PLANE_CSC_RANGE; + + ovl_set_brightness_contrast(ovl, &ovl->base.opts); + ovl_set_hue_saturation(ovl, &ovl->base.opts); + drm_plane_init(dev, &ovl->base, possible_crtcs, &mfld_overlay_funcs, mfld_overlay_formats, ARRAY_SIZE(mfld_overlay_formats)); -- 2.7.4