From: Ville Syrjälä Date: Wed, 14 Dec 2011 22:12:05 +0000 (+0200) Subject: staging: mrst: Add overlay color correction settings X-Git-Tag: 2.1b_release~431 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1859d70281224dae97b21c3878a614a0eec7423e;p=kernel%2Fkernel-mfld-blackbay.git staging: mrst: Add overlay color correction settings 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 --- 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));