]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: adf: hdmi support
authorXia Yang <xiay@nvidia.com>
Tue, 11 Feb 2014 21:49:21 +0000 (13:49 -0800)
committerJon Mayo <jmayo@nvidia.com>
Thu, 20 Mar 2014 01:06:09 +0000 (18:06 -0700)
Add hotplug event handling and fix interface flags.
Pulls in ADF_FBDEV as a hack to convert dc-produced monspecs.

Bug 1459374

Change-Id: I338f733850fc701542c2cf411b2a80e88a9c9748
Signed-off-by: Greg Hackmann <ghackmann@google.com>
Signed-off-by: Xia Yang <xiay@nvidia.com>
Reviewed-on: http://git-master/r/364117
Reviewed-by: Automatic_Commit_Validation_User
Tested-by: Jon Mayo <jmayo@nvidia.com>
Reviewed-by: Jon Mayo <jmayo@nvidia.com>
drivers/video/tegra/Kconfig
drivers/video/tegra/dc/hdmi_state_machine.c
drivers/video/tegra/tegra_adf.c
drivers/video/tegra/tegra_adf.h

index 9aa88822a32be74307e716e13e7659f4d36e87ab..388cb839cb24525c6a5bbb3a9957e3b1507066ee 100644 (file)
@@ -121,6 +121,7 @@ config ADF_TEGRA
        tristate "Tegra ADF driver"
        depends on TEGRA_DC && ADF
        default ADF
+       select ADF_FBDEV
        help
          ADF device support for the Tegra display controller.
 
index 1fdc44d2647f74835e15d859a075b5c5645f89d2..9745431aaf1c7967a23e774d15c583a2a389e95d 100644 (file)
 #include <video/tegrafb.h>
 #include "dc_priv.h"
 
+#ifdef CONFIG_ADF_TEGRA
+#include "tegra_adf.h"
+#endif
+
 #include "hdmi_state_machine.h"
 
 /************************************************************
@@ -181,7 +185,11 @@ static void hdmi_disable_l(struct tegra_dc_hdmi_data *hdmi, bool power_gate)
                pr_info("HDMI from connected to disconnected\n");
                hdmi->dc->connected = false;
                tegra_dc_disable(hdmi->dc);
+#ifdef CONFIG_ADF_TEGRA
+               tegra_adf_process_hotplug_disconnected(hdmi->dc->adf);
+#else
                tegra_fb_update_monspecs(hdmi->dc->fb, NULL, NULL);
+#endif
                tegra_dc_ext_process_hotplug(hdmi->dc->ndev->id);
        }
        if (power_gate && tegra_powergate_is_powered(hdmi->dc->powergate_id))
@@ -270,9 +278,12 @@ static void handle_check_edid_l(struct tegra_dc_hdmi_data *hdmi)
 
        hdmi->dvi = !(specs.misc & FB_MISC_HDMI);
 
+#ifdef CONFIG_ADF_TEGRA
+       tegra_adf_process_hotplug_connected(hdmi->dc->adf, &specs);
+#else
        tegra_fb_update_monspecs(hdmi->dc->fb, &specs,
                tegra_dc_hdmi_mode_filter);
-
+#endif
 #ifdef CONFIG_SWITCH
        state = tegra_edid_audio_supported(hdmi->edid) ? 1 : 0;
        switch_set_state(&hdmi->audio_switch, state);
@@ -281,6 +292,7 @@ static void handle_check_edid_l(struct tegra_dc_hdmi_data *hdmi)
        pr_info("Display connected, hpd_switch 1\n");
 #endif
        hdmi->dc->connected = true;
+
        tegra_dc_ext_process_hotplug(hdmi->dc->ndev->id);
 
        if (unlikely(tegra_is_clk_enabled(hdmi->clk))) {
index d0dedd181b90358a0d18342fecd5492bb04b6e60..5300ae052fb486aaf695b57add2e02247dc6f3c0 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/nvmap.h>
 #include <video/adf.h>
+#include <video/adf_fbdev.h>
 #include <video/adf_format.h>
 
 #include "dc/dc_config.h"
@@ -145,47 +146,100 @@ static int tegra_dc_to_drm_modeinfo(struct drm_mode_modeinfo *dmode,
        return 0;
 }
 
-static int tegra_adf_hotplug(struct tegra_adf_info *adf_info)
+static int tegra_adf_convert_monspecs(struct tegra_adf_info *adf_info,
+               struct fb_monspecs *specs, struct drm_mode_modeinfo **modelist,
+               size_t *n_modes)
 {
-       struct tegra_dc_out *out = adf_info->dc->out;
-       struct tegra_dc_mode *dc_modes;
-       struct tegra_dc_mode calc_mode;
-
-       struct drm_mode_modeinfo *modelist;
-       size_t n_modes, i;
-       int err;
+       struct tegra_dc *dc = adf_info->dc;
+       struct drm_mode_modeinfo *modes;
+       size_t n = 0;
+       u32 i;
 
-       if (out->n_modes) {
-               dc_modes = out->modes;
-               n_modes = out->n_modes;
-       } else {
-               memset(&calc_mode, 0, sizeof(calc_mode));
+       modes = kmalloc(specs->modedb_len * sizeof(modes[0]), GFP_KERNEL);
+       if (!modes)
+               return -ENOMEM;
 
-               dc_modes = &calc_mode;
-               n_modes = 1;
+       for (i = 0; i < specs->modedb_len; i++) {
+               struct fb_videomode *fb_mode = &specs->modedb[i];
+               if (dc->out_ops->mode_filter &&
+                               !dc->out_ops->mode_filter(dc, fb_mode))
+                       continue;
+               adf_modeinfo_from_fb_videomode(fb_mode, &modes[n]);
+               n++;
        }
 
-       modelist = kmalloc(n_modes * sizeof(modelist[0]), GFP_KERNEL);
-       if (!modelist)
+       *modelist = modes;
+       *n_modes = n;
+       return 0;
+}
+
+static int tegra_adf_convert_builtin_modes(struct tegra_adf_info *adf_info,
+               struct drm_mode_modeinfo **modelist, size_t *n_modes)
+{
+       struct tegra_dc *dc = adf_info->dc;
+       struct drm_mode_modeinfo *modes;
+       u32 i;
+
+       modes = kmalloc(dc->out->n_modes * sizeof(modes[0]), GFP_KERNEL);
+       if (!modes)
                return -ENOMEM;
 
-       for (i = 0; i < n_modes; i++) {
-               err = tegra_dc_to_drm_modeinfo(&modelist[i], &dc_modes[i]);
+       for (i = 0; i < dc->out->n_modes; i++) {
+               int err = tegra_dc_to_drm_modeinfo(&modes[i],
+                               &dc->out->modes[i]);
                if (err < 0)
-                       goto done;
+                       return err;
        }
 
-       err = tegra_dc_set_mode(adf_info->dc, dc_modes);
+       *modelist = modes;
+       *n_modes = dc->out->n_modes;
+       return 0;
+}
+
+static int tegra_adf_do_hotplug(struct tegra_adf_info *adf_info,
+               struct drm_mode_modeinfo *modelist, size_t n_modes)
+{
+       int err = tegra_dc_set_drm_mode(adf_info->dc, modelist, false);
        if (err < 0)
-               goto done;
+               return err;
        memcpy(&adf_info->intf.current_mode, &modelist[0], sizeof(modelist[0]));
 
-       err = adf_hotplug_notify_connected(&adf_info->intf, modelist, n_modes);
-done:
-       kfree(modelist);
+       return adf_hotplug_notify_connected(&adf_info->intf, modelist, n_modes);
+}
+
+int tegra_adf_process_hotplug_connected(struct tegra_adf_info *adf_info,
+               struct fb_monspecs *specs)
+{
+       struct tegra_dc_out *out = adf_info->dc->out;
+       struct drm_mode_modeinfo *modes;
+       size_t n_modes;
+       int err;
+
+       if (!specs && !out->modes) {
+               struct drm_mode_modeinfo reset_mode = {0};
+               return tegra_adf_do_hotplug(adf_info, &reset_mode, 1);
+       }
+
+       if (specs)
+               err = tegra_adf_convert_monspecs(adf_info, specs, &modes,
+                               &n_modes);
+       else
+               err = tegra_adf_convert_builtin_modes(adf_info, &modes,
+                               &n_modes);
+
+       if (err < 0)
+               return err;
+
+       err = tegra_adf_do_hotplug(adf_info, modes, n_modes);
+       kfree(modes);
        return err;
 }
 
+void tegra_adf_process_hotplug_disconnected(struct tegra_adf_info *adf_info)
+{
+       adf_hotplug_notify_disconnected(&adf_info->intf);
+}
+
 static int tegra_adf_dev_custom_data(struct adf_obj *obj, void *data,
                size_t *size)
 {
@@ -689,7 +743,6 @@ static void tegra_adf_intf_set_event(struct adf_obj *obj,
                return;
 
        case ADF_EVENT_HOTPLUG:
-               /* TODO */
                return;
 
        default:
@@ -858,6 +911,7 @@ struct tegra_adf_info *tegra_adf_init(struct platform_device *ndev,
 {
        struct tegra_adf_info *adf_info;
        int err;
+       enum adf_interface_type intf_type;
        u32 intf_flags = 0;
 
        adf_info = kzalloc(sizeof(*adf_info), GFP_KERNEL);
@@ -871,11 +925,16 @@ struct tegra_adf_info *tegra_adf_init(struct platform_device *ndev,
        if (err < 0)
                goto err_dev_init;
 
+       intf_type = tegra_adf_interface_type(dc);
+
        if (ndev->id == 0)
                intf_flags |= ADF_INTF_FLAG_PRIMARY;
 
+       if (intf_type == ADF_INTF_HDMI)
+               intf_flags |= ADF_INTF_FLAG_EXTERNAL;
+
        err = adf_interface_init(&adf_info->intf, &adf_info->base,
-                       tegra_adf_interface_type(dc), 0, intf_flags,
+                       intf_type, 0, intf_flags,
                        &tegra_adf_intf_ops, "%s", dev_name(&ndev->dev));
        if (err < 0)
                goto err_intf_init;
@@ -891,7 +950,7 @@ struct tegra_adf_info *tegra_adf_init(struct platform_device *ndev,
                goto err_attach;
 
        if (dc->out->n_modes) {
-               err = tegra_adf_hotplug(adf_info);
+               err = tegra_adf_process_hotplug_connected(adf_info, NULL);
                if (err < 0)
                        goto err_attach;
        }
index e85c0fd6e019446219034c73452e586d55c5163f..a3ab78acb6ba5b26d29a979bc8533879d0264ac1 100644 (file)
@@ -23,6 +23,9 @@
 struct tegra_adf_info;
 
 #ifdef CONFIG_ADF_TEGRA
+int tegra_adf_process_hotplug_connected(struct tegra_adf_info *adf_info,
+               struct fb_monspecs *specs);
+void tegra_adf_process_hotplug_disconnected(struct tegra_adf_info *adf_info);
 void tegra_adf_process_vblank(struct tegra_adf_info *adf_info,
                ktime_t timestamp);
 
@@ -30,6 +33,17 @@ struct tegra_adf_info *tegra_adf_init(struct platform_device *ndev,
                struct tegra_dc *dc, struct tegra_fb_data *fb_data);
 void tegra_adf_unregister(struct tegra_adf_info *adf_info);
 #else
+static inline int tegra_adf_process_hotplug_connected(
+               struct tegra_adf_info *adf_info, struct fb_monspecs *specs)
+{
+       return -ENOENT;
+}
+
+static inline void tegra_adf_process_hotplug_disconnected(
+               struct tegra_adf_info *adf_info)
+{
+}
+
 static inline void tegra_adf_process_vblank(struct tegra_adf_info *adf_info,
                ktime_t timestamp)
 {