#include <video/tegrafb.h>
#include "dc_priv.h"
+#ifdef CONFIG_ADF_TEGRA
+#include "tegra_adf.h"
+#endif
+
#include "hdmi_state_machine.h"
/************************************************************
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))
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);
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))) {
#include <linux/nvmap.h>
#include <video/adf.h>
+#include <video/adf_fbdev.h>
#include <video/adf_format.h>
#include "dc/dc_config.h"
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)
{
return;
case ADF_EVENT_HOTPLUG:
- /* TODO */
return;
default:
{
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);
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;
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;
}