Commit d94905e0 authored by Russell King's avatar Russell King

imx-drm: imx-hdmi: add hotplug support to HDMI component

Add hotplug support.  We have to make the interrupt handler threaded so
we can call drm_helper_hpd_irq_event().  Keeping in mind that we will
want to share the interrupt with other HDMI interface drivers (eg, audio
and CEC) put the groundwork in now for that, rather than just using
IRQF_ONESHOT.

Also, we must not call drm_helper_hpd_irq_event() until we have fully
setup the connector; keep the interrupt(s) muted until after that point.
Acked-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
Acked-by: default avatarShawn Guo <shawn.guo@linaro.org>
Reviewed-by: default avatarFabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 3e68439b
...@@ -120,6 +120,8 @@ struct imx_hdmi { ...@@ -120,6 +120,8 @@ struct imx_hdmi {
struct clk *isfr_clk; struct clk *isfr_clk;
struct clk *iahb_clk; struct clk *iahb_clk;
enum drm_connector_status connector_status;
struct hdmi_data_info hdmi_data; struct hdmi_data_info hdmi_data;
int vic; int vic;
...@@ -1301,9 +1303,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi) ...@@ -1301,9 +1303,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
/* Clear Hotplug interrupts */ /* Clear Hotplug interrupts */
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
/* Unmute interrupts */
hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
return 0; return 0;
} }
...@@ -1372,8 +1371,9 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi) ...@@ -1372,8 +1371,9 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
*connector, bool force) *connector, bool force)
{ {
/* FIXME */ struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
return connector_status_connected; connector);
return hdmi->connector_status;
} }
static int imx_hdmi_connector_get_modes(struct drm_connector *connector) static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
...@@ -1487,6 +1487,18 @@ static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { ...@@ -1487,6 +1487,18 @@ static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
.best_encoder = imx_hdmi_connector_best_encoder, .best_encoder = imx_hdmi_connector_best_encoder,
}; };
static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
{
struct imx_hdmi *hdmi = dev_id;
u8 intr_stat;
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
if (intr_stat)
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
}
static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
{ {
struct imx_hdmi *hdmi = dev_id; struct imx_hdmi *hdmi = dev_id;
...@@ -1503,17 +1515,21 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) ...@@ -1503,17 +1515,21 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0); hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
hdmi->connector_status = connector_status_connected;
imx_hdmi_poweron(hdmi); imx_hdmi_poweron(hdmi);
} else { } else {
dev_dbg(hdmi->dev, "EVENT=plugout\n"); dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0); hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0);
hdmi->connector_status = connector_status_disconnected;
imx_hdmi_poweroff(hdmi); imx_hdmi_poweroff(hdmi);
} }
drm_helper_hpd_irq_event(hdmi->connector.dev);
} }
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1527,6 +1543,8 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) ...@@ -1527,6 +1543,8 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
if (ret) if (ret)
return ret; return ret;
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs); drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs, drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
DRM_MODE_ENCODER_TMDS); DRM_MODE_ENCODER_TMDS);
...@@ -1578,6 +1596,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) ...@@ -1578,6 +1596,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
return -ENOMEM; return -ENOMEM;
hdmi->dev = dev; hdmi->dev = dev;
hdmi->connector_status = connector_status_disconnected;
hdmi->sample_rate = 48000; hdmi->sample_rate = 48000;
hdmi->ratio = 100; hdmi->ratio = 100;
...@@ -1601,8 +1620,9 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) ...@@ -1601,8 +1620,9 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (irq < 0) if (irq < 0)
return -EINVAL; return -EINVAL;
ret = devm_request_irq(dev, irq, imx_hdmi_irq, 0, ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
dev_name(dev), hdmi); imx_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
if (ret) if (ret)
return ret; return ret;
...@@ -1678,6 +1698,9 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) ...@@ -1678,6 +1698,9 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (ret) if (ret)
goto err_iahb; goto err_iahb;
/* Unmute interrupts */
hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
dev_set_drvdata(dev, hdmi); dev_set_drvdata(dev, hdmi);
return 0; return 0;
...@@ -1695,6 +1718,9 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master, ...@@ -1695,6 +1718,9 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
{ {
struct imx_hdmi *hdmi = dev_get_drvdata(dev); struct imx_hdmi *hdmi = dev_get_drvdata(dev);
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
hdmi->connector.funcs->destroy(&hdmi->connector); hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.funcs->destroy(&hdmi->encoder); hdmi->encoder.funcs->destroy(&hdmi->encoder);
......
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