struct i2c_adapter *ddc;
void __iomem *regs;
bool sink_is_hdmi;
+ bool sink_has_audio;
+
+ struct mutex mutex; /* for state below and previous_mode */
+ bool disabled; /* DRM has disabled our bridge */
spinlock_t audio_lock;
struct mutex audio_mutex;
return 0;
}
-static void dw_hdmi_phy_enable_power(struct dw_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_PDZ_OFFSET,
HDMI_PHY_CONF0_PDZ_MASK);
}
/* REMOVE CLK TERM */
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
- dw_hdmi_phy_enable_power(hdmi, 1);
+ dw_hdmi_phy_enable_powerdown(hdmi, false);
/* toggle TMDS enable */
dw_hdmi_phy_enable_tmds(hdmi, 0);
dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
dw_hdmi_phy_sel_interface_control(hdmi, 0);
dw_hdmi_phy_enable_tmds(hdmi, 0);
- dw_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_enable_powerdown(hdmi, true);
/* Enable CSC */
ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
return;
dw_hdmi_phy_enable_tmds(hdmi, 0);
- dw_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_enable_powerdown(hdmi, true);
hdmi->phy_enabled = false;
}
/* HDMI Initialization Step B.3 */
dw_hdmi_enable_video_path(hdmi);
- /* not for DVI mode */
- if (hdmi->sink_is_hdmi) {
- dev_dbg(hdmi->dev, "%s HDMI mode\n", __func__);
+ if (hdmi->sink_has_audio) {
+ dev_dbg(hdmi->dev, "sink has audio support\n");
/* HDMI Initialization Step E - Configure audio */
hdmi_clk_regenerator_update_pixel_clock(hdmi);
hdmi_enable_audio_clk(hdmi);
+ }
+
+ /* not for DVI mode */
+ if (hdmi->sink_is_hdmi) {
+ dev_dbg(hdmi->dev, "%s HDMI mode\n", __func__);
/* HDMI Initialization Step F - Configure AVI InfoFrame */
hdmi_config_AVI(hdmi, mode);
{
struct dw_hdmi *hdmi = bridge->driver_private;
- dw_hdmi_setup(hdmi, mode);
+ mutex_lock(&hdmi->mutex);
/* Store the display mode for plugin/DKMS poweron events */
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+
+ mutex_unlock(&hdmi->mutex);
}
static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
{
struct dw_hdmi *hdmi = bridge->driver_private;
+ mutex_lock(&hdmi->mutex);
+ hdmi->disabled = true;
dw_hdmi_poweroff(hdmi);
+ mutex_unlock(&hdmi->mutex);
}
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;
+ mutex_unlock(&hdmi->mutex);
}
static void dw_hdmi_bridge_nop(struct drm_bridge *bridge)
struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
struct edid *edid;
- int ret;
+ int ret = 0;
if (!hdmi->ddc)
return 0;
edid->width_cm, edid->height_cm);
hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid);
+ hdmi->sink_has_audio = drm_detect_monitor_audio(edid);
drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
kfree(edid);
dev_dbg(hdmi->dev, "failed to get edid\n");
}
- return 0;
+ return ret;
}
static enum drm_mode_status
.best_encoder = dw_hdmi_connector_best_encoder,
};
-struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+static struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
.enable = dw_hdmi_bridge_enable,
.disable = dw_hdmi_bridge_disable,
.pre_enable = dw_hdmi_bridge_nop,
phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
+ hdmi_modb(hdmi, ~phy_int_pol, HDMI_PHY_HPD, HDMI_PHY_POL0);
+ mutex_lock(&hdmi->mutex);
if (phy_int_pol & HDMI_PHY_HPD) {
dev_dbg(hdmi->dev, "EVENT=plugin\n");
- hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
-
- dw_hdmi_poweron(hdmi);
+ if (!hdmi->disabled)
+ dw_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
- hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
- HDMI_PHY_POL0);
-
- dw_hdmi_poweroff(hdmi);
+ if (!hdmi->disabled)
+ dw_hdmi_poweroff(hdmi);
}
+ mutex_unlock(&hdmi->mutex);
drm_helper_hpd_irq_event(hdmi->bridge->dev);
}
hdmi->sample_rate = 48000;
hdmi->ratio = 100;
hdmi->encoder = encoder;
+ hdmi->disabled = true;
+ mutex_init(&hdmi->mutex);
mutex_init(&hdmi->audio_mutex);
spin_lock_init(&hdmi->audio_lock);