From patchwork Thu May 26 08:35:46 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jyri Sarha X-Patchwork-Id: 9136797 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 37C34607D3 for ; Thu, 26 May 2016 08:36:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2B65525EF7 for ; Thu, 26 May 2016 08:36:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 200CF28299; Thu, 26 May 2016 08:36:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7502C25EF7 for ; Thu, 26 May 2016 08:36:11 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 169916EA46; Thu, 26 May 2016 08:36:06 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bear.ext.ti.com (bear.ext.ti.com [198.47.19.11]) by gabe.freedesktop.org (Postfix) with ESMTPS id CB32E6EA45 for ; Thu, 26 May 2016 08:36:03 +0000 (UTC) Received: from dflxv15.itg.ti.com ([128.247.5.124]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id u4Q8ZwfU027539; Thu, 26 May 2016 03:35:58 -0500 Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id u4Q8Zw8C029925; Thu, 26 May 2016 03:35:58 -0500 Received: from dlep32.itg.ti.com (157.170.170.100) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.3.294.0; Thu, 26 May 2016 03:35:57 -0500 Received: from jadmar.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id u4Q8ZohY013825; Thu, 26 May 2016 03:35:56 -0500 From: Jyri Sarha To: Subject: [PATCH v5 2/4] drm/omapdrm: Add gamma table support to DSS dispc Date: Thu, 26 May 2016 11:35:46 +0300 Message-ID: <566122fedd6f19f26ecdf0fa75d1de2c24045192.1464251087.git.jsarha@ti.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: References: MIME-Version: 1.0 Cc: Jyri Sarha , peter.ujfalusi@ti.com, tomi.valkeinen@ti.com, laurent.pinchart@ideasonboard.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP Add gamma table support to DSS dispc. DSS driver initializes the default gamma table at component bind time and holds a copy of all gamma tables in its internal data structure. Each call to dispc_mgr_set_gamma() updates the internal table and triggers write to the HW, if it is enabled. The tables are restored to HW in PM resume callback. The drivers internal data structure match the HW tables in size and in number of significant bits per color component. The dispc_mgr_set_gamma() converts the size of any given table for the internal data structure using linear interpolation. Default gamma table is restored if NULL is given in place of gamma lut. dispc_mgr_gamma_size() gives HW gamma table size for the channel and returns 0 if gamma table is not supported by the HW or the DSS driver. Signed-off-by: Jyri Sarha --- drivers/gpu/drm/omapdrm/dss/dispc.c | 200 +++++++++++++++++++++++++++++++--- drivers/gpu/drm/omapdrm/dss/dispc.h | 5 + drivers/gpu/drm/omapdrm/dss/hdmi4.c | 3 - drivers/gpu/drm/omapdrm/dss/hdmi5.c | 3 - drivers/gpu/drm/omapdrm/dss/omapdss.h | 5 + 5 files changed, 194 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index f83608b..dbe5ab3 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -113,9 +113,12 @@ struct dispc_features { * never both, we can just use this flag for now. */ bool reverse_ilace_field_order:1; + + bool has_gamma_table:1; }; #define DISPC_MAX_NR_FIFOS 5 +#define DISPC_MAX_CHANNEL_GAMMA 4 static struct { struct platform_device *pdev; @@ -135,6 +138,8 @@ static struct { bool ctx_valid; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; + u32 *gamma_table[DISPC_MAX_CHANNEL_GAMMA]; + const struct dispc_features *feat; bool is_enabled; @@ -178,11 +183,19 @@ struct dispc_reg_field { u8 low; }; +struct dispc_gamma_desc { + u32 len; + u32 bits; + u16 reg; + bool has_index; +}; + static const struct { const char *name; u32 vsync_irq; u32 framedone_irq; u32 sync_lost_irq; + struct dispc_gamma_desc gamma; struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM]; } mgr_desc[] = { [OMAP_DSS_CHANNEL_LCD] = { @@ -190,6 +203,12 @@ static const struct { .vsync_irq = DISPC_IRQ_VSYNC, .framedone_irq = DISPC_IRQ_FRAMEDONE, .sync_lost_irq = DISPC_IRQ_SYNC_LOST, + .gamma = { + .len = 256, + .bits = 8, + .reg = DISPC_GAMMA_TABLE0, + .has_index = true, + }, .reg_desc = { [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 }, [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 }, @@ -207,6 +226,12 @@ static const struct { .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN, .framedone_irq = DISPC_IRQ_FRAMEDONETV, .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT, + .gamma = { + .len = 1024, + .bits = 10, + .reg = DISPC_GAMMA_TABLE2, + .has_index = false, + }, .reg_desc = { [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 }, [DISPC_MGR_FLD_STNTFT] = { }, @@ -224,6 +249,12 @@ static const struct { .vsync_irq = DISPC_IRQ_VSYNC2, .framedone_irq = DISPC_IRQ_FRAMEDONE2, .sync_lost_irq = DISPC_IRQ_SYNC_LOST2, + .gamma = { + .len = 256, + .bits = 8, + .reg = DISPC_GAMMA_TABLE1, + .has_index = true, + }, .reg_desc = { [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 }, [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 }, @@ -241,6 +272,12 @@ static const struct { .vsync_irq = DISPC_IRQ_VSYNC3, .framedone_irq = DISPC_IRQ_FRAMEDONE3, .sync_lost_irq = DISPC_IRQ_SYNC_LOST3, + .gamma = { + .len = 256, + .bits = 8, + .reg = DISPC_GAMMA_TABLE3, + .has_index = true, + }, .reg_desc = { [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 }, [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 }, @@ -1084,20 +1121,6 @@ static u32 dispc_ovl_get_burst_size(enum omap_plane plane) return unit * 8; } -void dispc_enable_gamma_table(bool enable) -{ - /* - * This is partially implemented to support only disabling of - * the gamma table. - */ - if (enable) { - DSSWARN("Gamma table enabling for TV not yet supported"); - return; - } - - REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); -} - static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) { if (channel == OMAP_DSS_CHANNEL_DIGIT) @@ -3814,6 +3837,136 @@ void dispc_disable_sidle(void) REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ } +u32 dispc_mgr_gamma_size(enum omap_channel channel) +{ + const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; + + if (!dispc.feat->has_gamma_table) + return 0; + + return gdesc->len; +} +EXPORT_SYMBOL(dispc_mgr_gamma_size); + +static void dispc_mgr_write_gamma_table(enum omap_channel channel) +{ + const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; + u32 *table = dispc.gamma_table[channel]; + unsigned int i; + + DSSDBG("%s: channel %d\n", __func__, channel); + + for (i = 0; i < gdesc->len; ++i) { + u32 v = table[i]; + + if (gdesc->has_index) + v |= i << 24; + else if (i == 0) + v |= 1 << 31; + + dispc_write_reg(gdesc->reg, v); + } +} + +static void dispc_restore_gamma_tables(void) +{ + DSSDBG("%s()\n", __func__); + + if (!dispc.feat->has_gamma_table) + return; + + dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD); + + dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_DIGIT); + + if (dss_has_feature(FEAT_MGR_LCD2)) + dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD2); + + if (dss_has_feature(FEAT_MGR_LCD3)) + dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD3); +} + +static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = { + { .red = 0, .green = 0, .blue = 0, }, + { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, }, +}; + +void dispc_mgr_set_gamma(enum omap_channel channel, + const struct drm_color_lut *lut, + unsigned int length) +{ + const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; + u32 *table = dispc.gamma_table[channel]; + uint i; + + DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__, + channel, length, gdesc->len); + + if (!dispc.feat->has_gamma_table) + return; + + if (lut == NULL) { + lut = dispc_mgr_gamma_default_lut; + length = ARRAY_SIZE(dispc_mgr_gamma_default_lut); + } + + for (i = 0; i < length - 1; ++i) { + uint first = i * (gdesc->len - 1) / (length - 1); + uint last = (i + 1) * (gdesc->len - 1) / (length - 1); + uint w = last - first; + u16 r, g, b; + uint j; + + for (j = 0; j <= w; j++) { + r = (lut[i].red * (w - j) + lut[i+1].red * j) / w; + g = (lut[i].green * (w - j) + lut[i+1].green * j) / w; + b = (lut[i].blue * (w - j) + lut[i+1].blue * j) / w; + + r >>= 16 - gdesc->bits; + g >>= 16 - gdesc->bits; + b >>= 16 - gdesc->bits; + + table[first + j] = (r << (gdesc->bits * 2)) | + (g << gdesc->bits) | b; + } + } + + if (dispc.is_enabled) + dispc_mgr_write_gamma_table(channel); +} +EXPORT_SYMBOL(dispc_mgr_set_gamma); + +static int dispc_init_gamma_tables(void) +{ + int channel; + + if (!dispc.feat->has_gamma_table) + return 0; + + for (channel = 0; channel < ARRAY_SIZE(dispc.gamma_table); channel++) { + const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; + u32 *gt; + + if (channel == OMAP_DSS_CHANNEL_LCD2 && + !dss_has_feature(FEAT_MGR_LCD2)) + continue; + + if (channel == OMAP_DSS_CHANNEL_LCD3 && + !dss_has_feature(FEAT_MGR_LCD3)) + continue; + + gt = devm_kmalloc_array(&dispc.pdev->dev, gdesc->len, + sizeof(u32), GFP_KERNEL); + if (!gt) + return -ENOMEM; + + dispc.gamma_table[channel] = gt; + + dispc_mgr_set_gamma(channel, NULL, 0); + } + return 0; +} + static void _omap_dispc_initial_config(void) { u32 l; @@ -3829,8 +3982,15 @@ static void _omap_dispc_initial_config(void) dispc.core_clk_rate = dispc_fclk_rate(); } - /* FUNCGATED */ - if (dss_has_feature(FEAT_FUNCGATED)) + /* Use gamma table mode, instead of palette mode */ + if (dispc.feat->has_gamma_table) + REG_FLD_MOD(DISPC_CONFIG, 1, 3, 3); + + /* For older DSS versions (FEAT_FUNCGATED) this enables + * func-clock auto-gating. For newer versions + * (dispc.feat->has_gamma_table) this enables tv-out gamma tables. + */ + if (dss_has_feature(FEAT_FUNCGATED) || dispc.feat->has_gamma_table) REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); dispc_setup_color_conv_coef(); @@ -3934,6 +4094,7 @@ static const struct dispc_features omap44xx_dispc_feats = { .has_writeback = true, .supports_double_pixel = true, .reverse_ilace_field_order = true, + .has_gamma_table = true, }; static const struct dispc_features omap54xx_dispc_feats = { @@ -3959,6 +4120,7 @@ static const struct dispc_features omap54xx_dispc_feats = { .has_writeback = true, .supports_double_pixel = true, .reverse_ilace_field_order = true, + .has_gamma_table = true, }; static int dispc_init_features(struct platform_device *pdev) @@ -4100,6 +4262,10 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) } } + r = dispc_init_gamma_tables(); + if (r) + return r; + pm_runtime_enable(&pdev->dev); r = dispc_runtime_get(); @@ -4170,6 +4336,8 @@ static int dispc_runtime_resume(struct device *dev) _omap_dispc_initial_config(); dispc_restore_context(); + + dispc_restore_gamma_tables(); } dispc.is_enabled = true; diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.h b/drivers/gpu/drm/omapdrm/dss/dispc.h index 4837442..bc1d812 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.h +++ b/drivers/gpu/drm/omapdrm/dss/dispc.h @@ -42,6 +42,11 @@ #define DISPC_MSTANDBY_CTRL 0x0858 #define DISPC_GLOBAL_MFLAG_ATTRIBUTE 0x085C +#define DISPC_GAMMA_TABLE0 0x0630 +#define DISPC_GAMMA_TABLE1 0x0634 +#define DISPC_GAMMA_TABLE2 0x0638 +#define DISPC_GAMMA_TABLE3 0x0850 + /* DISPC overlay registers */ #define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \ DISPC_BA0_OFFSET(n)) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index f892ae15..12bef2d 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -213,9 +213,6 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); - /* bypass TV gamma table */ - dispc_enable_gamma_table(0); - /* tv size */ dss_mgr_set_timings(channel, p); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index a43f7b1..10530c5 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -230,9 +230,6 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); - /* bypass TV gamma table */ - dispc_enable_gamma_table(0); - /* tv size */ dss_mgr_set_timings(channel, p); diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index d7e7c90..adcd315 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -19,6 +19,7 @@ #define __OMAP_DRM_DSS_H #include