From aabbd64ef46deac68cdea28be010be9eb80a8fa9 Mon Sep 17 00:00:00 2001 From: Ray Zhang Date: Tue, 18 Apr 2017 15:49:46 +0800 Subject: [PATCH] drm/msm: add irq mapping for cec in hdmi driver Make HDMI device as the interrupt parent of CEC device, so add the new IRQ domain in HDMI driver dealing with the necessary IRQ mapping. Change-Id: Id935da1d1e488ccee01b831b9f085a83d67268f2 Signed-off-by: Ray Zhang --- drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c | 49 ++++++++++++++++++++- drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h | 3 ++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index c377f3759e67..4c70472bd338 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "sde_kms.h" #include "sde_connector.h" @@ -967,6 +968,18 @@ static void _sde_hdmi_connector_irq(struct sde_hdmi *sde_hdmi) } } +static void _sde_hdmi_cec_irq(struct sde_hdmi *sde_hdmi) +{ + struct hdmi *hdmi = sde_hdmi->ctrl.ctrl; + u32 cec_intr = hdmi_read(hdmi, REG_HDMI_CEC_INT); + + /* Routing interrupt to external CEC drivers */ + if (cec_intr) + generic_handle_irq(irq_find_mapping( + sde_hdmi->irq_domain, 1)); +} + + static irqreturn_t _sde_hdmi_irq(int irq, void *dev_id) { struct sde_hdmi *sde_hdmi = dev_id; @@ -987,7 +1000,8 @@ static irqreturn_t _sde_hdmi_irq(int irq, void *dev_id) if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported) hdmi_hdcp_ctrl_irq(hdmi->hdcp_ctrl); - /* TODO audio.. */ + /* Process CEC: */ + _sde_hdmi_cec_irq(sde_hdmi); return IRQ_HANDLED; } @@ -2017,6 +2031,29 @@ static struct platform_driver sde_hdmi_driver = { }, }; +static int sde_hdmi_irqdomain_map(struct irq_domain *domain, + unsigned int irq, irq_hw_number_t hwirq) +{ + struct sde_hdmi *display; + int rc; + + if (!domain || !domain->host_data) { + pr_err("invalid parameters domain\n"); + return -EINVAL; + } + display = domain->host_data; + + irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_level_irq); + rc = irq_set_chip_data(irq, display); + + return rc; +} + +static const struct irq_domain_ops sde_hdmi_irqdomain_ops = { + .map = sde_hdmi_irqdomain_map, + .xlate = irq_domain_xlate_onecell, +}; + int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc) { int rc = 0; @@ -2071,6 +2108,13 @@ int sde_hdmi_drm_init(struct sde_hdmi *display, struct drm_encoder *enc) goto error; } + display->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 8, + &sde_hdmi_irqdomain_ops, display); + if (!display->irq_domain) { + SDE_ERROR("failed to create IRQ domain\n"); + goto error; + } + enc->bridge = hdmi->bridge; priv->bridges[priv->num_bridges++] = hdmi->bridge; @@ -2096,6 +2140,9 @@ int sde_hdmi_drm_deinit(struct sde_hdmi *display) return -EINVAL; } + if (display->irq_domain) + irq_domain_remove(display->irq_domain); + return rc; } diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h index ffa9a27e7dfe..54506da4f9b0 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h @@ -86,6 +86,7 @@ struct sde_hdmi_ctrl { * @hpd_work: HPD work structure. * @codec_ready: If audio codec is ready. * @client_notify_pending: If there is client notification pending. + * @irq_domain: IRQ domain structure. * @root: Debug fs root entry. */ struct sde_hdmi { @@ -114,6 +115,8 @@ struct sde_hdmi { bool codec_ready; bool client_notify_pending; + struct irq_domain *irq_domain; + /* DEBUG FS */ struct dentry *root; };