|
@@ -126,7 +126,9 @@ struct dw_hdmi {
|
|
|
bool sink_has_audio;
|
|
|
|
|
|
struct mutex mutex; /* for state below and previous_mode */
|
|
|
+ enum drm_connector_force force; /* mutex-protected force state */
|
|
|
bool disabled; /* DRM has disabled our bridge */
|
|
|
+ bool bridge_is_on; /* indicates the bridge is on */
|
|
|
|
|
|
spinlock_t audio_lock;
|
|
|
struct mutex audio_mutex;
|
|
@@ -1378,12 +1380,36 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
|
|
|
|
|
|
static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
|
|
|
{
|
|
|
+ hdmi->bridge_is_on = true;
|
|
|
dw_hdmi_setup(hdmi, &hdmi->previous_mode);
|
|
|
}
|
|
|
|
|
|
static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
|
|
|
{
|
|
|
dw_hdmi_phy_disable(hdmi);
|
|
|
+ hdmi->bridge_is_on = false;
|
|
|
+}
|
|
|
+
|
|
|
+static void dw_hdmi_update_power(struct dw_hdmi *hdmi)
|
|
|
+{
|
|
|
+ int force = hdmi->force;
|
|
|
+
|
|
|
+ if (hdmi->disabled) {
|
|
|
+ force = DRM_FORCE_OFF;
|
|
|
+ } else if (force == DRM_FORCE_UNSPECIFIED) {
|
|
|
+ if (hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD)
|
|
|
+ force = DRM_FORCE_ON;
|
|
|
+ else
|
|
|
+ force = DRM_FORCE_OFF;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (force == DRM_FORCE_OFF) {
|
|
|
+ if (hdmi->bridge_is_on)
|
|
|
+ dw_hdmi_poweroff(hdmi);
|
|
|
+ } else {
|
|
|
+ if (!hdmi->bridge_is_on)
|
|
|
+ dw_hdmi_poweron(hdmi);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
|
|
@@ -1413,7 +1439,7 @@ static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
|
|
|
|
|
|
mutex_lock(&hdmi->mutex);
|
|
|
hdmi->disabled = true;
|
|
|
- dw_hdmi_poweroff(hdmi);
|
|
|
+ dw_hdmi_update_power(hdmi);
|
|
|
mutex_unlock(&hdmi->mutex);
|
|
|
}
|
|
|
|
|
@@ -1422,8 +1448,8 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
|
|
|
struct dw_hdmi *hdmi = bridge->driver_private;
|
|
|
|
|
|
mutex_lock(&hdmi->mutex);
|
|
|
- dw_hdmi_poweron(hdmi);
|
|
|
hdmi->disabled = false;
|
|
|
+ dw_hdmi_update_power(hdmi);
|
|
|
mutex_unlock(&hdmi->mutex);
|
|
|
}
|
|
|
|
|
@@ -1438,6 +1464,11 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
|
|
struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
|
|
|
connector);
|
|
|
|
|
|
+ mutex_lock(&hdmi->mutex);
|
|
|
+ hdmi->force = DRM_FORCE_UNSPECIFIED;
|
|
|
+ dw_hdmi_update_power(hdmi);
|
|
|
+ mutex_unlock(&hdmi->mutex);
|
|
|
+
|
|
|
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
|
|
|
connector_status_connected : connector_status_disconnected;
|
|
|
}
|
|
@@ -1502,11 +1533,23 @@ static void dw_hdmi_connector_destroy(struct drm_connector *connector)
|
|
|
drm_connector_cleanup(connector);
|
|
|
}
|
|
|
|
|
|
+static void dw_hdmi_connector_force(struct drm_connector *connector)
|
|
|
+{
|
|
|
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
|
|
|
+ connector);
|
|
|
+
|
|
|
+ mutex_lock(&hdmi->mutex);
|
|
|
+ hdmi->force = connector->force;
|
|
|
+ dw_hdmi_update_power(hdmi);
|
|
|
+ mutex_unlock(&hdmi->mutex);
|
|
|
+}
|
|
|
+
|
|
|
static struct drm_connector_funcs dw_hdmi_connector_funcs = {
|
|
|
.dpms = drm_helper_connector_dpms,
|
|
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
|
|
.detect = dw_hdmi_connector_detect,
|
|
|
.destroy = dw_hdmi_connector_destroy,
|
|
|
+ .force = dw_hdmi_connector_force,
|
|
|
};
|
|
|
|
|
|
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
|
|
@@ -1552,12 +1595,12 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
|
|
|
if (phy_int_pol & HDMI_PHY_HPD) {
|
|
|
dev_dbg(hdmi->dev, "EVENT=plugin\n");
|
|
|
|
|
|
- if (!hdmi->disabled)
|
|
|
+ if (!hdmi->disabled && !hdmi->force)
|
|
|
dw_hdmi_poweron(hdmi);
|
|
|
} else {
|
|
|
dev_dbg(hdmi->dev, "EVENT=plugout\n");
|
|
|
|
|
|
- if (!hdmi->disabled)
|
|
|
+ if (!hdmi->disabled && !hdmi->force)
|
|
|
dw_hdmi_poweroff(hdmi);
|
|
|
}
|
|
|
mutex_unlock(&hdmi->mutex);
|