@@ -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,
};