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: 9430339 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 CF3B56047D for ; Tue, 15 Nov 2016 18:40:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BC5BB28A37 for ; Tue, 15 Nov 2016 18:40:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AD78328C69; Tue, 15 Nov 2016 18:40:28 +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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3E7AC28A37 for ; Tue, 15 Nov 2016 18:40:26 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1c6ief-0008Tz-Bf; Tue, 15 Nov 2016 18:40:25 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1c6ieZ-0007aF-64 for linux-mediatek@lists.infradead.org; Tue, 15 Nov 2016 18:40:23 +0000 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: linux-mediatek@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161115_104019_712205_D6B8D4F4 X-CRM114-Status: GOOD ( 16.76 ) X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Russell King , Hans Verkuil , Philipp Zabel , PC Liao , CK Hu , linux-mediatek@lists.infradead.org MIME-Version: 1.0 Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org 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; }