Signed-off-by: Peter Seiderer <ps.report at gmx.net>
---
 arch/arm/boot/dts/imx6q-sabrelite.dts       |  3 +++
 drivers/staging/imx-drm/imx-drm-core.c      | 27 +++++++++++++++++++++++
 drivers/staging/imx-drm/imx-drm.h           |  4 ++++
 drivers/staging/imx-drm/imx-ldb.c           | 18 ++++++++++++++++
 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h |  2 ++
 drivers/staging/imx-drm/ipu-v3/ipu-dp.c     | 33 +++++++++++++++++++++++++++++
 drivers/staging/imx-drm/ipuv3-crtc.c        |  9 ++++++++
 7 files changed, 96 insertions(+)

diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts 
b/arch/arm/boot/dts/imx6q-sabrelite.dts
index fca8f220..5dabc45 100644
--- a/arch/arm/boot/dts/imx6q-sabrelite.dts
+++ b/arch/arm/boot/dts/imx6q-sabrelite.dts
@@ -171,6 +171,9 @@
        lvds-channel at 0 {
                fsl,data-mapping = "spwg";
                fsl,data-width = <18>;
+               /* gamma = 0.6 */
+               fsl,gamma-constk = /bits/ 16 <0x000 0x000 0x000 0x000 0x1ff 
0x001 0x009 0x015 0x025 0x037 0x04d 0x064 0x07f 0x09c 0x0bb 0x0dc>;
+               fsl,gamma-slopek = /bits/ 16 <0x000 0x000 0x000 0x000 0x002 
0x008 0x00c 0x010 0x012 0x016 0x017 0x01b 0x01d 0x01f 0x021 0x022>;
                status = "okay";

                display-timings {
diff --git a/drivers/staging/imx-drm/imx-drm-core.c 
b/drivers/staging/imx-drm/imx-drm-core.c
index 0507b66..6e205fb 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -139,6 +139,33 @@ int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 
encoder_type,
 }
 EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);

+int imx_drm_crtc_panel_gamma(struct drm_crtc *crtc,
+               u16 *gamma_constk, u16 *gamma_slopek)
+{
+       struct imx_drm_device *imxdrm = crtc->dev->dev_private;
+       struct imx_drm_crtc *imx_crtc;
+       struct imx_drm_crtc_helper_funcs *helper;
+
+       mutex_lock(&imxdrm->mutex);
+
+       list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
+               if (imx_crtc->crtc == crtc)
+                       goto found;
+
+       mutex_unlock(&imxdrm->mutex);
+
+       return -EINVAL;
+found:
+       mutex_unlock(&imxdrm->mutex);
+
+       helper = &imx_crtc->imx_drm_helper_funcs;
+       if (helper->set_interface_gamma)
+               return helper->set_interface_gamma(crtc,
+                               gamma_constk, gamma_slopek);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_gamma);
+
 int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
 {
        return drm_vblank_get(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
diff --git a/drivers/staging/imx-drm/imx-drm.h 
b/drivers/staging/imx-drm/imx-drm.h
index ae90c9c..995e29f 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -21,6 +21,8 @@ struct imx_drm_crtc_helper_funcs {
        void (*disable_vblank)(struct drm_crtc *crtc);
        int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
                        u32 pix_fmt, int hsync_pin, int vsync_pin);
+       int (*set_interface_gamma)(struct drm_crtc *crtc,
+                       u16 *gamma_constk, u16 *gamma_slopek);
        const struct drm_crtc_helper_funcs *crtc_helper_funcs;
        const struct drm_crtc_funcs *crtc_funcs;
 };
@@ -60,6 +62,8 @@ int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 
encoder_type,
                u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
 int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
                u32 interface_pix_fmt);
+int imx_drm_crtc_panel_gamma(struct drm_crtc *crtc,
+               u16 *gamma_constk, u16 *gamma_slopek);
 void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);

 struct device_node;
diff --git a/drivers/staging/imx-drm/imx-ldb.c 
b/drivers/staging/imx-drm/imx-ldb.c
index 7e59329..5dc9d6c 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -64,6 +64,8 @@ struct imx_ldb_channel {
        int chno;
        void *edid;
        int edid_len;
+       u16 *gamma_constk;
+       u16 *gamma_slopek;
        struct drm_display_mode mode;
        int mode_valid;
 };
@@ -209,6 +211,10 @@ static void imx_ldb_encoder_prepare(struct drm_encoder 
*encoder)

        imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_LVDS,
                        pixel_fmt);
+
+       if (imx_ldb_ch->gamma_constk && imx_ldb_ch->gamma_slopek)
+               imx_drm_crtc_panel_gamma(encoder->crtc, 
imx_ldb_ch->gamma_constk,
+                               imx_ldb_ch->gamma_slopek);
 }

 static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
@@ -468,6 +474,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
        const u8 *edidp;
        struct imx_ldb *imx_ldb;
        int datawidth;
+       u16 gamma_val[16];
        int mapping;
        int dual;
        int ret;
@@ -548,6 +555,14 @@ static int imx_ldb_probe(struct platform_device *pdev)
                else if (datawidth != 18 && datawidth != 24)
                        return -EINVAL;

+               ret = of_property_read_u16_array(child, "fsl,gamma-constk", 
gamma_val, 16);
+               if (!ret)
+                       channel->gamma_constk = kmemdup(gamma_val, sizeof(u16) 
* 16, GFP_KERNEL);
+
+               ret = of_property_read_u16_array(child, "fsl,gamma-slopek", 
gamma_val, 16);
+               if (!ret)
+                       channel->gamma_slopek = kmemdup(gamma_val, sizeof(u16) 
* 16, GFP_KERNEL);
+
                mapping = of_get_data_mapping(child);
                switch (mapping) {
                case LVDS_BIT_MAP_SPWG:
@@ -599,6 +614,9 @@ static int imx_ldb_remove(struct platform_device *pdev)

                imx_drm_remove_connector(channel->imx_drm_connector);
                imx_drm_remove_encoder(channel->imx_drm_encoder);
+
+               kfree(channel->gamma_constk);
+               kfree(channel->gamma_slopek);
        }

        return 0;
diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h 
b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
index 4826b5c..6f821dc 100644
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
@@ -154,6 +154,8 @@ int ipu_dp_enable_channel(struct ipu_dp *dp);
 void ipu_dp_disable_channel(struct ipu_dp *dp);
 int ipu_dp_setup_channel(struct ipu_dp *dp,
                enum ipu_color_space in, enum ipu_color_space out);
+int ipu_dp_set_gamma(struct ipu_dp *dp,
+                u16 *gamma_constk, u16 *gamma_slopek);
 int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
 int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
                bool bg_chan);
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c 
b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
index 58f87c8..56ab92e 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
@@ -29,6 +29,8 @@
 #define DP_COM_CONF            0x0
 #define DP_GRAPH_WIND_CTRL     0x0004
 #define DP_FG_POS              0x0008
+#define DP_GAMMA_C_SYNC                0x0014
+#define DP_GAMMA_S_SYNC                0x0034
 #define DP_CSC_A_0             0x0044
 #define DP_CSC_A_1             0x0048
 #define DP_CSC_A_2             0x004C
@@ -45,6 +47,7 @@
 #define DP_COM_CONF_CSC_DEF_FG         (3 << 8)
 #define DP_COM_CONF_CSC_DEF_BG         (2 << 8)
 #define DP_COM_CONF_CSC_DEF_BOTH       (1 << 8)
+#define DP_COM_CONF_GAMMA_EN           (1 << 12)

 #define IPUV3_NUM_FLOWS                3

@@ -215,6 +218,36 @@ int ipu_dp_setup_channel(struct ipu_dp *dp,
 }
 EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);

+int ipu_dp_set_gamma(struct ipu_dp *dp,
+               u16 *gamma_constk, u16 *gamma_slopek)
+{
+       struct ipu_flow *flow = to_flow(dp);
+       u32 reg;
+       int i;
+
+       /* set DP_GAMMA_C_SYNC registers */
+       for(i = 0; i < 8 ; i++) {
+               reg = (gamma_constk[i*2+1] << 16) | (gamma_constk[i*2]);
+               writel(reg, flow->base + DP_GAMMA_C_SYNC + 4 * i);
+       }
+       /* set DP_GAMMA_S_SYNC registers */
+       for(i = 0; i < 4 ; i++) {
+               reg = (gamma_slopek[i*4+3] << 24)|
+                     (gamma_slopek[i*4+2] << 16) |
+                     (gamma_slopek[i*4+1] << 8) |
+                     gamma_slopek[i*4];
+               writel(reg, flow->base + DP_GAMMA_S_SYNC + 4 * i);
+       }
+
+       /* enable gammma correction */
+       reg = readl(flow->base + DP_COM_CONF);
+       reg |= DP_COM_CONF_GAMMA_EN;
+       writel(reg, flow->base + DP_COM_CONF);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_gamma);
+
 int ipu_dp_enable_channel(struct ipu_dp *dp)
 {
        struct ipu_flow *flow = to_flow(dp);
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c 
b/drivers/staging/imx-drm/ipuv3-crtc.c
index ce6ba98..b227ace 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -291,10 +291,19 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc 
*crtc, u32 encoder_type,
        return 0;
 }

+static int ipu_set_interface_gamma(struct drm_crtc *crtc,
+               u16 *gamma_constk, u16 *gamma_slopek)
+{
+       struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+       return ipu_dp_set_gamma(ipu_crtc->plane[0]->dp, gamma_constk, 
gamma_slopek);
+}
+
 static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = {
        .enable_vblank = ipu_enable_vblank,
        .disable_vblank = ipu_disable_vblank,
        .set_interface_pix_fmt = ipu_set_interface_pix_fmt,
+       .set_interface_gamma = ipu_set_interface_gamma,
        .crtc_funcs = &ipu_crtc_funcs,
        .crtc_helper_funcs = &ipu_helper_funcs,
 };
-- 
1.8.1.4

Reply via email to