From patchwork Tue Jan 17 12:31:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 9520677 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 CF78460244 for ; Tue, 17 Jan 2017 12:32:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A8B4028500 for ; Tue, 17 Jan 2017 12:32:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9D6FC28522; Tue, 17 Jan 2017 12:32:12 +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.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 6FEED28500 for ; Tue, 17 Jan 2017 12:32:11 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1cTSvq-0003IJ-Ar; Tue, 17 Jan 2017 12:32:10 +0000 Received: from mail-wm0-x230.google.com ([2a00:1450:400c:c09::230]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1cTSvm-0003F0-9Q for linux-amlogic@lists.infradead.org; Tue, 17 Jan 2017 12:32:08 +0000 Received: by mail-wm0-x230.google.com with SMTP id c206so220457276wme.0 for ; Tue, 17 Jan 2017 04:31:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=bayIDHKmt9FnWz3B0omosDJUDwoDdKpU86Quc484XEM=; b=dKOP4mtjIXy5CZlHALe9/yqx2wnON/Q2ArfIO4NkSB0NiNAg0TObXcXslT8P9xViNG uL7GQv+s9DjBgwfAELDdkILtJCwVF37uAASyBlPC+bE3Rd85nZSsvar7Er5EgMYpT3Gm LfFx9q1MwUw4jBo8ty0NgwBsG03f9nwanLMv6ib+gCxpEi8dPIHh8aaSwScwNG8tRJgu bW+OF3f96o7EWnGKBuHEZNYZ9EpOcUaAiuRMhhEBuGh9RAO/07ebW4cWHEYDWL/jkS8H DtaEBDZHNjFKHonn/gpRG1gnKcQaAfUsl6foPqojESP9Jh9iWMuT96sl42HayDYD4UV7 LNng== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=bayIDHKmt9FnWz3B0omosDJUDwoDdKpU86Quc484XEM=; b=HBAV+ybuwRXG7/a1I09F4F1eFvf/Kb4hk4VH2HOd+NuI2Nhax5A9b8udrXfmfWl3ba FTTiGTJUWXVNYYMlZ8guc8z9m/5x5deqc3M2DmpH1cxefJXOyTQj6bN4+BsRJDeJ4ldO Fd//FHxDa2GVYRT8YO2UZzLkMor43j4f33e4GDxU63lw3nDp4frHRrAUlbAgBVDYrFWA trXGyuq+iFHdTu2Lh2T7aCqc0+lrGB6AIZ9aTyZ7CKvyNwOXc0SAVxd8nC6RdS1m3qyt do6fSJOncooteVnY6vkbFfzs6WA3+nR6KFvH+mt9dYYBHOVkQa1/Da3h+eBSNZ8sz4Dg N/rg== X-Gm-Message-State: AIkVDXLil0MOetSWbL4qa5L24JsNwznM5k9OV4jMbqXlH6TM7Vem9aG6DvnZ3eGVj3Dh3J9C X-Received: by 10.223.148.2 with SMTP id 2mr11666936wrq.75.1484656308403; Tue, 17 Jan 2017 04:31:48 -0800 (PST) Received: from localhost.localdomain (home.amouriers.starnux.net. [82.228.250.61]) by smtp.gmail.com with ESMTPSA id l74sm36678858wmg.2.2017.01.17.04.31.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 17 Jan 2017 04:31:47 -0800 (PST) From: Neil Armstrong To: dri-devel@lists.freedesktop.org, laurent.pinchart+renesas@ideasonboard.com Subject: [RFC/RFT PATCH 2/4] drm/bridge: dw-hdmi: Add support for custom PHY handling Date: Tue, 17 Jan 2017 13:31:32 +0100 Message-Id: <1484656294-6140-3-git-send-email-narmstrong@baylibre.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1484656294-6140-1-git-send-email-narmstrong@baylibre.com> References: <1484656294-6140-1-git-send-email-narmstrong@baylibre.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170117_043206_503340_CE97B42C X-CRM114-Status: GOOD ( 16.62 ) X-BeenThere: linux-amlogic@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Jose.Abreu@synopsys.com, linux-amlogic@lists.infradead.org, kieran.bingham@ideasonboard.com, linux-kernel@vger.kernel.org, Neil Armstrong MIME-Version: 1.0 Sender: "linux-amlogic" Errors-To: linux-amlogic-bounces+patchwork-linux-amlogic=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The Synopsys DesignWare HDMI TX Controller support various Transceivers (PHY) attached to the controller, but also allows fully custom PHYs to be connected. Add PHY init, disable functions in plat_data to handle fully custom PHY init. Some custom PHYs also handles the HPD and RxSense separately and do not use the internal signals exported in the Controller's IRQ stat, so a read_hpd is provided to switch to HPD status polling. To complete the implementation, add a function to mimic the Controllers interrupt HPD and RxSense handling from the vendor PHY wrapper code. Signed-off-by: Neil Armstrong --- drivers/gpu/drm/bridge/dw-hdmi.c | 78 +++++++++++++++++++++++++++++++--------- include/drm/bridge/dw_hdmi.h | 8 +++++ 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 13747fe..923e250 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1434,9 +1434,18 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) hdmi_av_composer(hdmi, mode); /* HDMI Initializateion Step B.2 */ - ret = dw_hdmi_phy_init(hdmi); - if (ret) - return ret; + if (hdmi->plat_data->hdmi_phy_init) { + ret = hdmi->plat_data->hdmi_phy_init(hdmi, hdmi->plat_data, + &hdmi->previous_mode); + if (ret) + return ret; + + hdmi->phy_enabled = true; + } else { + ret = dw_hdmi_phy_init(hdmi); + if (ret) + return ret; + } /* HDMI Initialization Step B.3 */ dw_hdmi_enable_video_path(hdmi); @@ -1551,7 +1560,11 @@ static void dw_hdmi_poweron(struct dw_hdmi *hdmi) static void dw_hdmi_poweroff(struct dw_hdmi *hdmi) { - dw_hdmi_phy_disable(hdmi); + if (hdmi->phy_enabled && hdmi->plat_data->hdmi_phy_disable) { + hdmi->plat_data->hdmi_phy_disable(hdmi, hdmi->plat_data); + hdmi->phy_enabled = false; + } else + dw_hdmi_phy_disable(hdmi); hdmi->bridge_is_on = false; } @@ -1593,6 +1606,9 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) { u8 old_mask = hdmi->phy_mask; + if (hdmi->plat_data && hdmi->plat_data->hdmi_read_hpd) + return; + if (hdmi->force || hdmi->disabled || !hdmi->rxsense) hdmi->phy_mask |= HDMI_PHY_RX_SENSE; else @@ -1614,6 +1630,11 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) dw_hdmi_update_phy_mask(hdmi); mutex_unlock(&hdmi->mutex); + if (hdmi->plat_data && hdmi->plat_data->hdmi_read_hpd) + return hdmi->plat_data->hdmi_read_hpd(hdmi, hdmi->plat_data) ? + connector_status_connected : + connector_status_disconnected; + return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? connector_status_connected : connector_status_disconnected; } @@ -1901,6 +1922,26 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) } }; +void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense) +{ + struct dw_hdmi *hdmi = dev_get_drvdata(dev); + + mutex_lock(&hdmi->mutex); + + if (!hdmi->disabled && !hdmi->force) { + if (!rx_sense) + hdmi->rxsense = false; + + if (hpd) + hdmi->rxsense = true; + + dw_hdmi_update_power(hdmi); + dw_hdmi_update_phy_mask(hdmi); + } + mutex_unlock(&hdmi->mutex); +} +EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense); + static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi) { unsigned int i; @@ -1921,7 +1962,9 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi) return -ENODEV; } - if (!hdmi->phy->configure && !hdmi->plat_data->configure_phy) { + if (!hdmi->phy->configure && + !hdmi->plat_data->configure_phy && + !hdmi->plat_data->hdmi_phy_init) { dev_err(hdmi->dev, "%s requires platform support\n", hdmi->phy->name); return -ENODEV; @@ -2101,15 +2144,17 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi) hdmi->ddc = NULL; } - /* - * Configure registers related to HDMI interrupt - * generation before registering IRQ. - */ - hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); + if (!hdmi->plat_data || !hdmi->plat_data->hdmi_read_hpd) { + /* + * Configure registers related to HDMI interrupt + * generation before registering IRQ. + */ + hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); - /* Clear Hotplug interrupts */ - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, - HDMI_IH_PHY_STAT0); + /* Clear Hotplug interrupts */ + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, + HDMI_IH_PHY_STAT0); + } hdmi->bridge.driver_private = hdmi; hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; @@ -2119,9 +2164,10 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi) if (ret) goto err_iahb; - /* Unmute interrupts */ - hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), - HDMI_IH_MUTE_PHY_STAT0); + if (!hdmi->plat_data || !hdmi->plat_data->hdmi_read_hpd) + /* Unmute interrupts */ + hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), + HDMI_IH_MUTE_PHY_STAT0); memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.parent = dev; diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 163842d..d6a0ab3 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -61,6 +61,13 @@ struct dw_hdmi_plat_data { enum drm_mode_status (*mode_valid)(struct drm_connector *connector, struct drm_display_mode *mode); struct regmap *regm; + int (*hdmi_phy_init)(struct dw_hdmi *hdmi, + const struct dw_hdmi_plat_data *data, + struct drm_display_mode *mode); + void (*hdmi_phy_disable)(struct dw_hdmi *hdmi, + const struct dw_hdmi_plat_data *data); + bool (*hdmi_read_hpd)(struct dw_hdmi *hdmi, + const struct dw_hdmi_plat_data *data); }; int dw_hdmi_probe(struct platform_device *pdev, @@ -70,6 +77,7 @@ int dw_hdmi_probe(struct platform_device *pdev, int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, const struct dw_hdmi_plat_data *plat_data); +void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense); void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);