From patchwork Tue Nov 15 18:39:51 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Philipp Zabel
X-Patchwork-Id: 9430337
Return-Path:
Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org
[172.30.200.125])
by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id
D605D6047D for ;
Tue, 15 Nov 2016 18:40:04 +0000 (UTC)
Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1])
by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C5A6F28C68
for ;
Tue, 15 Nov 2016 18:40:04 +0000 (UTC)
Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486)
id B971528C67; Tue, 15 Nov 2016 18:40:04 +0000 (UTC)
X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on
pdx-wl-mail.web.codeaurora.org
X-Spam-Level:
X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED
autolearn=ham version=3.3.1
Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177])
(using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256
bits)) (No client certificate requested)
by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E044428C67
for ;
Tue, 15 Nov 2016 18:40:03 +0000 (UTC)
Received: from gabe.freedesktop.org (localhost [127.0.0.1])
by gabe.freedesktop.org (Postfix) with ESMTP id 19CD16E23E;
Tue, 15 Nov 2016 18:40:01 +0000 (UTC)
X-Original-To: dri-devel@lists.freedesktop.org
Delivered-To: dri-devel@lists.freedesktop.org
Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de
[IPv6:2001:67c:670:201:290:27ff:fe1d:cc33])
by gabe.freedesktop.org (Postfix) with ESMTPS id AADE46E23E
for ;
Tue, 15 Nov 2016 18:39:58 +0000 (UTC)
Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]
helo=dude.pengutronix.de.)
by metis.ext.pengutronix.de with esmtp (Exim 4.80)
(envelope-from )
id 1c6ieD-0001Zo-1C; Tue, 15 Nov 2016 19:39:57 +0100
From: Philipp Zabel
To: dri-devel@lists.freedesktop.org
Subject: [PATCH] drm/mediatek: use HDMI state notifier support
Date: Tue, 15 Nov 2016 19:39:51 +0100
Message-Id: <20161115183951.840-1-p.zabel@pengutronix.de>
X-Mailer: git-send-email 2.10.2
X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7
X-SA-Exim-Mail-From: p.zabel@pengutronix.de
X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de);
SAEximRunCond expanded to false
X-PTX-Original-Recipient: dri-devel@lists.freedesktop.org
Cc: Russell King ,
Hans Verkuil ,
PC Liao , linux-mediatek@lists.infradead.org
X-BeenThere: dri-devel@lists.freedesktop.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: Direct Rendering Infrastructure - Development
List-Unsubscribe: ,
List-Archive:
List-Post:
List-Help:
List-Subscribe: ,
MIME-Version: 1.0
Errors-To: dri-devel-bounces@lists.freedesktop.org
Sender: "dri-devel"
X-Virus-Scanned: ClamAV using ClamSMTP
Issue hot-plug detection, EDID update, and ELD update notifications
from the CEC and HDMI drivers using the HDMI state notifier support.
Signed-off-by: Philipp Zabel
---
This patch depends on the "video: add HDMI state notifier support" patch [1] by
Hans Verkuil, based on Russell King's earlier version. With this we can replace
the custom callback interface between HDMI and CEC drivers with a common
mechanism. It will also allow other drivers such as hdmi-codec to react to the
emitted events.
[1] https://patchwork.linuxtv.org/patch/38109/
---
drivers/gpu/drm/mediatek/mtk_cec.c | 56 +++++++++++--------------------------
drivers/gpu/drm/mediatek/mtk_cec.h | 26 -----------------
drivers/gpu/drm/mediatek/mtk_hdmi.c | 46 ++++++++++++++++++------------
3 files changed, 44 insertions(+), 84 deletions(-)
delete mode 100644 drivers/gpu/drm/mediatek/mtk_cec.h
diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c b/drivers/gpu/drm/mediatek/mtk_cec.c
index 7a3eb8c..9a1807b 100644
--- a/drivers/gpu/drm/mediatek/mtk_cec.c
+++ b/drivers/gpu/drm/mediatek/mtk_cec.c
@@ -13,12 +13,11 @@
*/
#include
#include
+#include
#include
#include
#include
-#include "mtk_cec.h"
-
#define TR_CONFIG 0x00
#define CLEAR_CEC_IRQ BIT(15)
@@ -55,12 +54,9 @@
struct mtk_cec {
void __iomem *regs;
+ struct hdmi_notifier *notifier;
struct clk *clk;
int irq;
- bool hpd;
- void (*hpd_event)(bool hpd, struct device *dev);
- struct device *hdmi_dev;
- spinlock_t lock;
};
static void mtk_cec_clear_bits(struct mtk_cec *cec, unsigned int offset,
@@ -94,20 +90,7 @@ static void mtk_cec_mask(struct mtk_cec *cec, unsigned int offset,
writel(val, cec->regs + offset);
}
-void mtk_cec_set_hpd_event(struct device *dev,
- void (*hpd_event)(bool hpd, struct device *dev),
- struct device *hdmi_dev)
-{
- struct mtk_cec *cec = dev_get_drvdata(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&cec->lock, flags);
- cec->hdmi_dev = hdmi_dev;
- cec->hpd_event = hpd_event;
- spin_unlock_irqrestore(&cec->lock, flags);
-}
-
-bool mtk_cec_hpd_high(struct device *dev)
+static bool mtk_cec_hpd_high(struct device *dev)
{
struct mtk_cec *cec = dev_get_drvdata(dev);
unsigned int status;
@@ -152,21 +135,6 @@ static void mtk_cec_clear_htplg_irq(struct mtk_cec *cec)
RX_INT_32K_CLR | HDMI_HTPLG_INT_32K_CLR);
}
-static void mtk_cec_hpd_event(struct mtk_cec *cec, bool hpd)
-{
- void (*hpd_event)(bool hpd, struct device *dev);
- struct device *hdmi_dev;
- unsigned long flags;
-
- spin_lock_irqsave(&cec->lock, flags);
- hpd_event = cec->hpd_event;
- hdmi_dev = cec->hdmi_dev;
- spin_unlock_irqrestore(&cec->lock, flags);
-
- if (hpd_event)
- hpd_event(hpd, hdmi_dev);
-}
-
static irqreturn_t mtk_cec_htplg_isr_thread(int irq, void *arg)
{
struct device *dev = arg;
@@ -176,11 +144,13 @@ static irqreturn_t mtk_cec_htplg_isr_thread(int irq, void *arg)
mtk_cec_clear_htplg_irq(cec);
hpd = mtk_cec_hpd_high(dev);
- if (cec->hpd != hpd) {
+ if (cec->notifier->connected != hpd) {
dev_dbg(dev, "hotplug event! cur hpd = %d, hpd = %d\n",
- cec->hpd, hpd);
- cec->hpd = hpd;
- mtk_cec_hpd_event(cec, hpd);
+ cec->notifier->connected, hpd);
+ if (hpd)
+ hdmi_event_connect(cec->notifier);
+ else
+ hdmi_event_disconnect(cec->notifier);
}
return IRQ_HANDLED;
}
@@ -197,7 +167,6 @@ static int mtk_cec_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, cec);
- spin_lock_init(&cec->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
cec->regs = devm_ioremap_resource(dev, res);
@@ -220,6 +189,12 @@ static int mtk_cec_probe(struct platform_device *pdev)
return cec->irq;
}
+ cec->notifier = hdmi_notifier_get(dev);
+ if (!cec->notifier) {
+ clk_disable_unprepare(cec->clk);
+ return -ENOMEM;
+ }
+
ret = devm_request_threaded_irq(dev, cec->irq, NULL,
mtk_cec_htplg_isr_thread,
IRQF_SHARED | IRQF_TRIGGER_LOW |
@@ -245,6 +220,7 @@ static int mtk_cec_remove(struct platform_device *pdev)
{
struct mtk_cec *cec = platform_get_drvdata(pdev);
+ hdmi_notifier_put(cec->notifier);
mtk_cec_htplg_irq_disable(cec);
clk_disable_unprepare(cec->clk);
return 0;
diff --git a/drivers/gpu/drm/mediatek/mtk_cec.h b/drivers/gpu/drm/mediatek/mtk_cec.h
deleted file mode 100644
index 10057b7..0000000
--- a/drivers/gpu/drm/mediatek/mtk_cec.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2014 MediaTek Inc.
- * Author: Jie Qiu
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#ifndef _MTK_CEC_H
-#define _MTK_CEC_H
-
-#include
-
-struct device;
-
-void mtk_cec_set_hpd_event(struct device *dev,
- void (*hotplug_event)(bool hpd, struct device *dev),
- struct device *hdmi_dev);
-bool mtk_cec_hpd_high(struct device *dev);
-
-#endif /* _MTK_CEC_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 71227de..c04a71a 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -32,7 +33,6 @@
#include
#include
#include
-#include "mtk_cec.h"
#include "mtk_hdmi.h"
#include "mtk_hdmi_regs.h"
@@ -153,6 +153,8 @@ struct mtk_hdmi {
struct device *dev;
struct phy *phy;
struct device *cec_dev;
+ struct hdmi_notifier *notifier;
+ struct notifier_block nb;
struct i2c_adapter *ddc_adpt;
struct clk *clk[MTK_HDMI_CLK_COUNT];
struct drm_display_mode mode;
@@ -1196,19 +1198,10 @@ static enum drm_connector_status hdmi_conn_detect(struct drm_connector *conn,
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_conn(conn);
- return mtk_cec_hpd_high(hdmi->cec_dev) ?
+ return hdmi->notifier->connected ?
connector_status_connected : connector_status_disconnected;
}
-static void hdmi_conn_destroy(struct drm_connector *conn)
-{
- struct mtk_hdmi *hdmi = hdmi_ctx_from_conn(conn);
-
- mtk_cec_set_hpd_event(hdmi->cec_dev, NULL, NULL);
-
- drm_connector_cleanup(conn);
-}
-
static int mtk_hdmi_conn_get_modes(struct drm_connector *conn)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_conn(conn);
@@ -1225,9 +1218,11 @@ static int mtk_hdmi_conn_get_modes(struct drm_connector *conn)
hdmi->dvi_mode = !drm_detect_monitor_audio(edid);
drm_mode_connector_update_edid_property(conn, edid);
+ hdmi_event_new_edid(hdmi->notifier, edid, sizeof(*edid));
ret = drm_add_edid_modes(conn, edid);
drm_edid_to_eld(conn, edid);
+ hdmi_event_new_eld(hdmi->notifier, conn->eld);
kfree(edid);
return ret;
}
@@ -1269,7 +1264,7 @@ static const struct drm_connector_funcs mtk_hdmi_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.detect = hdmi_conn_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = hdmi_conn_destroy,
+ .destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
@@ -1282,12 +1277,16 @@ static const struct drm_connector_helper_funcs
.best_encoder = mtk_hdmi_conn_best_enc,
};
-static void mtk_hdmi_hpd_event(bool hpd, struct device *dev)
+static int mtk_hdmi_notify(struct notifier_block *nb, unsigned long event,
+ void *data)
{
- struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
+ struct mtk_hdmi *hdmi = container_of(nb, struct mtk_hdmi, nb);
- if (hdmi && hdmi->bridge.encoder && hdmi->bridge.encoder->dev)
+ if ((event == HDMI_CONNECTED || event == HDMI_DISCONNECTED) &&
+ (hdmi->bridge.encoder && hdmi->bridge.encoder->dev))
drm_helper_hpd_irq_event(hdmi->bridge.encoder->dev);
+
+ return NOTIFY_OK;
}
/*
@@ -1330,8 +1329,6 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
}
}
- mtk_cec_set_hpd_event(hdmi->cec_dev, mtk_hdmi_hpd_event, hdmi->dev);
-
return 0;
}
@@ -1707,6 +1704,15 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
return ret;
}
+ hdmi->notifier = hdmi_notifier_get(hdmi->cec_dev);
+ if (!hdmi->notifier)
+ return -ENOMEM;
+
+ hdmi->nb.notifier_call = mtk_hdmi_notify;
+ ret = hdmi_notifier_register(hdmi->notifier, &hdmi->nb);
+ if (ret)
+ goto err_notifier_put;
+
mtk_hdmi_register_audio_driver(dev);
hdmi->bridge.funcs = &mtk_hdmi_bridge_funcs;
@@ -1714,7 +1720,7 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
ret = drm_bridge_add(&hdmi->bridge);
if (ret) {
dev_err(dev, "failed to add bridge, ret = %d\n", ret);
- return ret;
+ goto err_notifier_unregister;
}
ret = mtk_hdmi_clk_enable_audio(hdmi);
@@ -1728,6 +1734,10 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
err_bridge_remove:
drm_bridge_remove(&hdmi->bridge);
+err_notifier_unregister:
+ hdmi_notifier_unregister(hdmi->notifier, &hdmi->nb);
+err_notifier_put:
+ hdmi_notifier_put(hdmi->notifier);
return ret;
}