Commit 3189650d authored by Rob Clark's avatar Rob Clark

drm/msm/hdmi: use gpio and HPD polling

The hotplug detect and irq does not seem to be reliable on all devices
for some reason.  For now it is more reliable to use polling, and give
preference to raw gpio status if it disagrees with the debounced hpd
status.
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent 8a57e950
...@@ -247,36 +247,49 @@ void hdmi_connector_irq(struct drm_connector *connector) ...@@ -247,36 +247,49 @@ void hdmi_connector_irq(struct drm_connector *connector)
} }
} }
static enum drm_connector_status detect_reg(struct hdmi *hdmi)
{
uint32_t hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ?
connector_status_connected : connector_status_disconnected;
}
static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
{
const struct hdmi_platform_config *config = hdmi->config;
return gpio_get_value(config->hpd_gpio) ?
connector_status_connected :
connector_status_disconnected;
}
static enum drm_connector_status hdmi_connector_detect( static enum drm_connector_status hdmi_connector_detect(
struct drm_connector *connector, bool force) struct drm_connector *connector, bool force)
{ {
struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
struct hdmi *hdmi = hdmi_connector->hdmi; struct hdmi *hdmi = hdmi_connector->hdmi;
const struct hdmi_platform_config *config = hdmi->config; enum drm_connector_status stat_gpio, stat_reg;
uint32_t hpd_int_status;
int retry = 20; int retry = 20;
hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); do {
stat_gpio = detect_gpio(hdmi);
stat_reg = detect_reg(hdmi);
/* sense seems to in some cases be momentarily de-asserted, don't if (stat_gpio == stat_reg)
* let that trick us into thinking the monitor is gone:
*/
while (retry-- && !(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED)) {
/* hdmi debounce logic seems to get stuck sometimes,
* read directly the gpio to get a second opinion:
*/
if (gpio_get_value(config->hpd_gpio)) {
DBG("gpio tells us we are connected!");
hpd_int_status |= HDMI_HPD_INT_STATUS_CABLE_DETECTED;
break; break;
}
mdelay(10); mdelay(10);
hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); } while (--retry);
DBG("status=%08x", hpd_int_status);
/* the status we get from reading gpio seems to be more reliable,
* so trust that one the most if we didn't manage to get hdmi and
* gpio status to agree:
*/
if (stat_gpio != stat_reg) {
DBG("HDMI_HPD_INT_STATUS tells us: %d", stat_reg);
DBG("hpd gpio tells us: %d", stat_gpio);
} }
return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ? return stat_gpio;
connector_status_connected : connector_status_disconnected;
} }
static void hdmi_connector_destroy(struct drm_connector *connector) static void hdmi_connector_destroy(struct drm_connector *connector)
...@@ -389,7 +402,8 @@ struct drm_connector *hdmi_connector_init(struct hdmi *hdmi) ...@@ -389,7 +402,8 @@ struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
DRM_MODE_CONNECTOR_HDMIA); DRM_MODE_CONNECTOR_HDMIA);
drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
connector->polled = DRM_CONNECTOR_POLL_HPD; connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
connector->interlace_allowed = 1; connector->interlace_allowed = 1;
connector->doublescan_allowed = 0; connector->doublescan_allowed = 0;
......
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