Commit 3c983905 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Tomi Valkeinen

drm/omap: hdmi4: 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-34-laurent.pinchart@ideasonboard.com
parent 6c623d6b
......@@ -28,6 +28,9 @@
#include <sound/omap-hdmi-audio.h>
#include <media/cec.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_state_helper.h>
#include "omapdss.h"
#include "hdmi4_core.h"
#include "hdmi4_cec.h"
......@@ -237,20 +240,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;
......@@ -284,62 +273,6 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
hdmi_wp_audio_enable(&hd->wp, false);
}
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 = hdmi4_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);
}
int hdmi4_core_enable(struct hdmi_core_data *core)
{
struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
......@@ -491,39 +424,14 @@ static void hdmi_lost_hotplug(struct omap_dss_device *dssdev)
hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);
}
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 = {
.lost_hotplug = hdmi_lost_hotplug,
.set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode,
},
};
......@@ -543,6 +451,108 @@ static int hdmi4_bridge_attach(struct drm_bridge *bridge,
bridge, flags);
}
static void hdmi4_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 hdmi4_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 = hdmi4_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 hdmi4_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 *hdmi4_bridge_read_edid(struct omap_hdmi *hdmi,
struct drm_connector *connector)
{
......@@ -559,6 +569,12 @@ static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
static const struct drm_bridge_funcs hdmi4_bridge_funcs = {
.attach = hdmi4_bridge_attach,
.mode_set = hdmi4_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 = hdmi4_bridge_enable,
.atomic_disable = hdmi4_bridge_disable,
.get_edid = hdmi4_bridge_get_edid,
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment