]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: dc: address VRR monitor quirks
authorDaniel Solomon <daniels@nvidia.com>
Fri, 18 Dec 2015 05:14:12 +0000 (21:14 -0800)
committermobile promotions <svcmobile_promotions@nvidia.com>
Fri, 4 Mar 2016 02:24:30 +0000 (18:24 -0800)
Address a couple of quirks in VRR monitors. Details
here: http://nvbugs/1711087/23

Bug 1711087

Change-Id: I6ba44d0d03af1f56381762db441a36bb4393a3f9
Signed-off-by: Daniel Solomon <daniels@nvidia.com>
Reviewed-on: http://git-master/r/924588
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
arch/arm/mach-tegra/include/mach/fb.h
drivers/video/tegra/dc/hdmi2.0.c
drivers/video/tegra/dc/hdmivrr.c
drivers/video/tegra/dc/hdmivrr.h
drivers/video/tegra/fb.c

index 1d0685003b055d8b6172e3024705eefa8b62fcb5..34fba983bc7b79054ecbdd38dd8f9355ced2c782 100644 (file)
@@ -48,6 +48,7 @@ void tegra_fb_remove_sysfs(struct device *dev);
 int tegra_fb_update_modelist(struct tegra_dc *dc, int fblistindex);
 struct tegra_dc_win *tegra_fb_get_win(struct tegra_fb_info *tegra_fb);
 struct tegra_dc_win *tegra_fb_get_blank_win(struct tegra_fb_info *tegra_fb);
+struct fb_videomode *tegra_fb_get_mode(struct tegra_dc *dc);
 #else
 static inline struct tegra_fb_info *tegra_fb_register(
        struct platform_device *ndev, struct tegra_dc *dc,
@@ -99,6 +100,12 @@ static inline struct tegra_dc_win *tegra_fb_get_blank_win(
                                struct tegra_fb_info *tegra_fb)
 {
        return NULL;
+
+}
+
+static inline struct fb_videomode *tegra_fb_get_mode(struct tegra_dc *dc)
+{
+       return NULL;
 }
 #endif
 #endif
index 44af1df0e582ab3e2560695241fe1c752e1abb7d..4f0f560f3f31dce52daaa99fa54b4dad0d3c055b 100644 (file)
@@ -2015,6 +2015,7 @@ static void tegra_dc_hdmi_shutdown(struct tegra_dc *dc)
 {
        struct tegra_hdmi *hdmi = tegra_dc_get_outdata(dc);
 
+       _tegra_hdmivrr_activate(hdmi, false);
        hdmi->device_shutdown = true;
        tegra_nvhdcp_shutdown(hdmi->nvhdcp);
 
@@ -2025,6 +2026,7 @@ static void tegra_dc_hdmi_disable(struct tegra_dc *dc)
 {
        struct tegra_hdmi *hdmi = tegra_dc_get_outdata(dc);
 
+       _tegra_hdmivrr_activate(hdmi, false);
        hdmi->enabled = false;
 #ifdef CONFIG_SWITCH
        switch_set_state(&hdmi->audio_switch, 0);
@@ -2057,6 +2059,8 @@ static void tegra_dc_hdmi_suspend(struct tegra_dc *dc)
 {
        struct tegra_hdmi *hdmi = tegra_dc_get_outdata(dc);
 
+       _tegra_hdmivrr_activate(hdmi, false);
+
        if (dc->out->flags & TEGRA_DC_OUT_HOTPLUG_WAKE_LP0) {
                int wake_irq = gpio_to_irq(dc->out->hotplug_gpio);
                int ret;
@@ -2082,6 +2086,11 @@ static void tegra_dc_hdmi_resume(struct tegra_dc *dc)
                disable_irq_wake(gpio_to_irq(dc->out->hotplug_gpio));
 
        cancel_delayed_work(&hdmi->hpd_worker);
+
+       /* If resume happens with a non-VRR monitor, the HPD
+          worker will correct the mode based on the new EDID */
+       _tegra_hdmivrr_activate(hdmi, true);
+
        schedule_delayed_work(&hdmi->hpd_worker,
                                msecs_to_jiffies(HDMI_HPD_DEBOUNCE_DELAY_MS + HDMI_HPD_DROP_TIMEOUT_MS));
 }
@@ -2292,11 +2301,17 @@ static void tegra_dc_hdmi_vrr_enable(struct tegra_dc *dc, bool enable)
        if (!vrr)
                return;
 
-       if (dc->mode.vmode & FB_VMODE_VRR)
-               vrr->enable = enable;
-       else
+       if (!(dc->mode.vmode & FB_VMODE_VRR)) {
                WARN(enable, "VRR enable request in non-VRR mode\n");
+               return;
+       }
+
+       vrr->enable = enable;
+}
 
+static void tegra_dc_hdmi_postpoweron(struct tegra_dc *dc)
+{
+       _tegra_hdmivrr_activate(tegra_dc_get_outdata(dc), true);
 }
 
 struct tegra_dc_out_ops tegra_dc_hdmi2_0_ops = {
@@ -2317,4 +2332,5 @@ struct tegra_dc_out_ops tegra_dc_hdmi2_0_ops = {
        .vrr_enable = tegra_dc_hdmi_vrr_enable,
        .vrr_update_monspecs = tegra_hdmivrr_update_monspecs,
        .set_hdr = tegra_dc_hdmi_set_hdr,
+       .postpoweron = tegra_dc_hdmi_postpoweron,
 };
index 05601ef0b6c01c973367082e3b126cc8d8ac52a6..e76a8f3e9907ad835e527c226b46bbe65863e6c1 100644 (file)
@@ -33,6 +33,7 @@
 #endif
 
 #include <mach/dc.h>
+#include <mach/fb.h>
 
 #include "dc_priv.h"
 #include "edid.h"
@@ -48,6 +49,8 @@
 #define HDMIVRR_CHLNG_SRC_MON 0
 #define HDMIVRR_CHLNG_SRC_DRV 1
 
+#define NS_IN_MS (1000 * 1000)
+
 static int hdmivrr_i2c_read(struct tegra_hdmi *hdmi, size_t len, void *data)
 {
        int status;
@@ -758,6 +761,34 @@ void tegra_hdmivrr_update_monspecs(struct tegra_dc *dc,
        }
 }
 
+/* Active or deactivate VRR mode on the monitor side */
+void _tegra_hdmivrr_activate(struct tegra_hdmi *hdmi, bool activate)
+{
+       struct tegra_dc *dc = hdmi->dc;
+       struct tegra_vrr *vrr  = dc->out->vrr;
+       struct fb_videomode *fbmode = tegra_fb_get_mode(dc);
+       int frametime_ms = (int)div64_s64(dc->frametime_ns, NS_IN_MS);
+
+       if (!vrr || !fbmode || !(dc->mode.vmode & FB_VMODE_VRR))
+               return;
+
+       if (activate) {
+               /*
+                  Inform VRR monitor to turn on VRR mode by increase
+                  vertical backporch by 2.
+                  The monitor needs a few frames of standard timing
+                  before activating VRR mode.
+                  */
+               msleep(frametime_ms * 20);
+               dc->mode.v_back_porch = fbmode->upper_margin + 2;
+       } else
+               dc->mode.v_back_porch = fbmode->upper_margin;
+
+       _tegra_dc_set_mode(dc, &dc->mode);
+       tegra_dc_update_mode(dc);
+       msleep(frametime_ms * 2);
+}
+
 int tegra_hdmivrr_setup(struct tegra_hdmi *hdmi)
 {
        int status;
index 12d42ffadc7071e63025e7551cc896790ec62463..94c22b40e994a2dabcfdef410bc02269145edf27 100644 (file)
@@ -92,11 +92,14 @@ void tegra_hdmivrr_update_monspecs(struct tegra_dc *dc,
        struct list_head *head);
 int tegra_hdmi_vrr_init(struct tegra_hdmi *hdmi);
 void te_authenticate_vrr(u8 *buf_ptr, u32 buflen);
+void _tegra_hdmivrr_activate(struct tegra_hdmi *hdmi, bool activate);
 #else
 int tegra_hdmivrr_setup(struct tegra_hdmi *hdmi) { return -EPROTONOSUPPORT; }
 void tegra_hdmivrr_update_monspecs(struct tegra_dc *dc,
        struct list_head *head) { return; }
 int tegra_hdmi_vrr_init(struct tegra_hdmi *hdmi) { return -EPROTONOSUPPORT; }
+void _tegra_hdmivrr_activate(struct tegra_hdmi *hdmi, bool activate)
+{ return; }
 #endif
 
 #endif
index d31f0663814009063a880639384ec95c98d0d66f..0a0b9bbc9dadd49126f5cc76412a6dd9ae8ccfeb 100644 (file)
@@ -569,13 +569,21 @@ int tegra_fb_update_modelist(struct tegra_dc *dc, int fblistindex)
        return index;
 }
 
-static int tegra_fb_get_mode(struct tegra_dc *dc)
+static int tegra_fb_get_mode_refresh(struct tegra_dc *dc)
 {
        if (!dc->fb->info->mode)
                return -1;
        return dc->fb->info->mode->refresh;
 }
 
+struct fb_videomode *tegra_fb_get_mode(struct tegra_dc *dc)
+{
+       if (dc && dc->fb && dc->fb->info && dc->fb->info->mode)
+               return dc->fb->info->mode;
+       else
+               return NULL;
+}
+
 static int tegra_fb_set_mode(struct tegra_dc *dc, int fps)
 {
        size_t stereo;
@@ -763,7 +771,7 @@ static ssize_t nvdps_show(struct device *device,
        struct platform_device *ndev = to_platform_device(device);
        struct tegra_dc *dc = platform_get_drvdata(ndev);
 
-       refresh_rate = tegra_fb_get_mode(dc);
+       refresh_rate = tegra_fb_get_mode_refresh(dc);
        return snprintf(buf, PAGE_SIZE, "%d\n", refresh_rate);
 }