Commit 615de6ce authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Tomi Valkeinen
Browse files

drm/omap: hdmi5: Move mode set, enable and disable operations to bridge



Move the omap_dss_device .set_timings(), .enable() and .disable()
operations to the drm_bridge functions. As the drm_bridge for the HDMI
encoder is unconditionally registered and attached, those operations
will be called at the appropriate time.

The omapdss device .set_infoframe() and .set_hdmi_mode() operations have
no equivalent in drm_bridge. Thir content is thus moved to the bridge
.enable() operation as the data they store is not needed before the HDMI
encoder gets enabled.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
Tested-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
Reviewed-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200226112514.12455-35-laurent.pinchart@ideasonboard.com
parent 3c983905
Loading
Loading
Loading
Loading
+111 −98
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@
#include <linux/of_graph.h>
#include <sound/omap-hdmi-audio.h>

#include <drm/drm_atomic.h>
#include <drm/drm_atomic_state_helper.h>

#include "omapdss.h"
#include "hdmi5_core.h"
#include "dss.h"
@@ -236,20 +239,6 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)
	hdmi_power_off_core(hdmi);
}

static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
				     const struct drm_display_mode *mode)
{
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	mutex_lock(&hdmi->lock);

	drm_display_mode_to_videomode(mode, &hdmi->cfg.vm);

	dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000);

	mutex_unlock(&hdmi->lock);
}

static int hdmi_dump_regs(struct seq_file *s, void *p)
{
	struct omap_hdmi *hdmi = s->private;
@@ -285,62 +274,6 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
	REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
}

static void hdmi_display_enable(struct omap_dss_device *dssdev)
{
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
	unsigned long flags;
	int r;

	DSSDBG("ENTER hdmi_display_enable\n");

	mutex_lock(&hdmi->lock);

	r = hdmi_power_on_full(hdmi);
	if (r) {
		DSSERR("failed to power on device\n");
		goto done;
	}

	if (hdmi->audio_configured) {
		r = hdmi5_audio_config(&hdmi->core, &hdmi->wp,
				       &hdmi->audio_config,
				       hdmi->cfg.vm.pixelclock);
		if (r) {
			DSSERR("Error restoring audio configuration: %d", r);
			hdmi->audio_abort_cb(&hdmi->pdev->dev);
			hdmi->audio_configured = false;
		}
	}

	spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
	if (hdmi->audio_configured && hdmi->audio_playing)
		hdmi_start_audio_stream(hdmi);
	hdmi->display_enabled = true;
	spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);

done:
	mutex_unlock(&hdmi->lock);
}

static void hdmi_display_disable(struct omap_dss_device *dssdev)
{
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
	unsigned long flags;

	DSSDBG("Enter hdmi_display_disable\n");

	mutex_lock(&hdmi->lock);

	spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
	hdmi_stop_audio_stream(hdmi);
	hdmi->display_enabled = false;
	spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);

	hdmi_power_off_full(hdmi);

	mutex_unlock(&hdmi->lock);
}

static int hdmi_core_enable(struct omap_hdmi *hdmi)
{
	int r = 0;
@@ -473,39 +406,11 @@ static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev)
				 NULL);
}

static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
		const struct hdmi_avi_infoframe *avi)
{
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.infoframe = *avi;
	return 0;
}

static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
		bool hdmi_mode)
{
	struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);

	hdmi->cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
	return 0;
}

static const struct omap_dss_device_ops hdmi_ops = {
	.connect		= hdmi_connect,
	.disconnect		= hdmi_disconnect,

	.enable			= hdmi_display_enable,
	.disable		= hdmi_display_disable,

	.set_timings		= hdmi_display_set_timings,

	.read_edid		= hdmi_read_edid,

	.hdmi = {
		.set_infoframe		= hdmi_set_infoframe,
		.set_hdmi_mode		= hdmi_set_hdmi_mode,
	},
};

/* -----------------------------------------------------------------------------
@@ -524,6 +429,108 @@ static int hdmi5_bridge_attach(struct drm_bridge *bridge,
				 bridge, flags);
}

static void hdmi5_bridge_mode_set(struct drm_bridge *bridge,
				  const struct drm_display_mode *mode,
				  const struct drm_display_mode *adjusted_mode)
{
	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);

	mutex_lock(&hdmi->lock);

	drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm);

	dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000);

	mutex_unlock(&hdmi->lock);
}

static void hdmi5_bridge_enable(struct drm_bridge *bridge,
				struct drm_bridge_state *bridge_state)
{
	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
	struct drm_atomic_state *state = bridge_state->base.state;
	struct drm_connector_state *conn_state;
	struct drm_connector *connector;
	struct drm_crtc_state *crtc_state;
	unsigned long flags;
	int ret;

	/*
	 * None of these should fail, as the bridge can't be enabled without a
	 * valid CRTC to connector path with fully populated new states.
	 */
	connector = drm_atomic_get_new_connector_for_encoder(state,
							     bridge->encoder);
	if (WARN_ON(!connector))
		return;
	conn_state = drm_atomic_get_new_connector_state(state, connector);
	if (WARN_ON(!conn_state))
		return;
	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
	if (WARN_ON(!crtc_state))
		return;

	hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi
				? HDMI_HDMI : HDMI_DVI;

	if (connector->display_info.is_hdmi) {
		const struct drm_display_mode *mode;
		struct hdmi_avi_infoframe avi;

		mode = &crtc_state->adjusted_mode;
		ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector,
							       mode);
		if (ret == 0)
			hdmi->cfg.infoframe = avi;
	}

	mutex_lock(&hdmi->lock);

	ret = hdmi_power_on_full(hdmi);
	if (ret) {
		DSSERR("failed to power on device\n");
		goto done;
	}

	if (hdmi->audio_configured) {
		ret = hdmi5_audio_config(&hdmi->core, &hdmi->wp,
					 &hdmi->audio_config,
					 hdmi->cfg.vm.pixelclock);
		if (ret) {
			DSSERR("Error restoring audio configuration: %d", ret);
			hdmi->audio_abort_cb(&hdmi->pdev->dev);
			hdmi->audio_configured = false;
		}
	}

	spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
	if (hdmi->audio_configured && hdmi->audio_playing)
		hdmi_start_audio_stream(hdmi);
	hdmi->display_enabled = true;
	spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);

done:
	mutex_unlock(&hdmi->lock);
}

static void hdmi5_bridge_disable(struct drm_bridge *bridge,
				 struct drm_bridge_state *bridge_state)
{
	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
	unsigned long flags;

	mutex_lock(&hdmi->lock);

	spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
	hdmi_stop_audio_stream(hdmi);
	hdmi->display_enabled = false;
	spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);

	hdmi_power_off_full(hdmi);

	mutex_unlock(&hdmi->lock);
}

static struct edid *hdmi5_bridge_read_edid(struct omap_hdmi *hdmi,
					   struct drm_connector *connector)
{
@@ -540,6 +547,12 @@ static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge,

static const struct drm_bridge_funcs hdmi5_bridge_funcs = {
	.attach = hdmi5_bridge_attach,
	.mode_set = hdmi5_bridge_mode_set,
	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
	.atomic_reset = drm_atomic_helper_bridge_reset,
	.atomic_enable = hdmi5_bridge_enable,
	.atomic_disable = hdmi5_bridge_disable,
	.get_edid = hdmi5_bridge_get_edid,
};