Received: by 2002:a05:6a10:5bc5:0:0:0:0 with SMTP id os5csp1616772pxb; Mon, 11 Oct 2021 09:33:40 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzU5Ji9pTt9+eWXDOsjoCO73gTYfmHoBQmF+Va2kUA/kuOSh9vGo++XRNpQoO0jXb4EEyaV X-Received: by 2002:a17:906:3383:: with SMTP id v3mr27158304eja.213.1633970019785; Mon, 11 Oct 2021 09:33:39 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1633970019; cv=none; d=google.com; s=arc-20160816; b=OfCspCd2aIfMlJv2jKceaOjosW/V2TAymFYDHpiWIv7IpiS+C17MpnnQskXQN2lI4i 9lNA0XDXe7uABbWU7F9vun06xh2EyPJbD7s47aJ/thB7crm7ULlj0nPKRJdpFTD7yMtC 0Z++ZviLIuaxcq4jeu+HWHrQVkd7ue2HQ+mpF3ltduEMEKvz/nuTJM5ejobCCjTGUXYV LOSxfCsM2H1RMlTY9xAYFEG2/cP66m80SwpK/VhGJlHnUroNz4bgIDafMHvXuWXaDzMj T5wDtn4Dv9SxZmxBRP0nC/93bFa0U04+hYev5+dshHQDZFOhzDBBixsg2hOQGL0XJKAU ZLoQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=91ygBOssmOc0NTrdMsw7FhxjgVKbtLdW2irxR3I/F1o=; b=aNblNHoPsnUFgqfxMoqWku9y4tcqFNTavXPIoovr/D5pAKL9CIg0Zii/skBibBlvVs gZvcq+SezoDHSPw1aq5DPwN4PzrmtISj3E3+2wNbjTKRf1BepGa+ZHa02jX4ZYIaaYCU 3IUZOhANAkGR4mODl9z8BzHDjONZnQA4QEuVKRN5zvpEbjMhLQaMaf294N0WMC5b5sjo xvCdKv5ATw4thnHHQBJgEmdbxYirj1/YODA0CnJf9uhgSLWV8ihcq+iyCLCNeE7we8Th Or/oAOdNe7tm+ilf+lHlVSWyY8xp0/I5Zd7R1gPJEoHVPlzg9NlXigLt177NpkgceLVE p+Xw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=Ck67CVcP; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id qf42si15507067ejc.257.2021.10.11.09.33.15; Mon, 11 Oct 2021 09:33:39 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=Ck67CVcP; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238058AbhJKN7F (ORCPT + 99 others); Mon, 11 Oct 2021 09:59:05 -0400 Received: from mail.kernel.org ([198.145.29.99]:40550 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237856AbhJKN4k (ORCPT ); Mon, 11 Oct 2021 09:56:40 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 19C5260EFE; Mon, 11 Oct 2021 13:53:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1633960418; bh=j1LIxd310G5te1DnCBq4Db8BBVpfxiJOkq5H8+UILJ4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ck67CVcPFVryCDbnPryfXxZNdswqcSQyBqW0q3eEPveMV0AAfEwlrQ9eygqCyZngv 24UvF0LO4Hf7yrUKQBstqdUW4YrxZUYbxeuWj+X/8nmq+eLk8LNIiA85dpXQpE+jeW T4Qn8jpCqm/z5E7sd81urC8H6R6oWI9Z54YvmIi0= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Jernej Skrabec , Maxime Ripard , Maarten Lankhorst , Sasha Levin Subject: [PATCH 5.10 54/83] drm/sun4i: dw-hdmi: Fix HDMI PHY clock setup Date: Mon, 11 Oct 2021 15:46:14 +0200 Message-Id: <20211011134510.258468982@linuxfoundation.org> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20211011134508.362906295@linuxfoundation.org> References: <20211011134508.362906295@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Jernej Skrabec [ Upstream commit c64c8e04a12ed3e2238761e26cda78e72550dc98 ] Recent rework, which made HDMI PHY driver a platform device, inadvertely reversed clock setup order. HW is very touchy about it. Proper way is to handle controllers resets and clocks first and HDMI PHYs second. Currently, without this fix, first mode set completely fails (nothing on HDMI monitor) on H3 era PHYs. On H6, it still somehow work. Move HDMI PHY reset & clocks handling to sun8i_hdmi_phy_init() which will assure that code is executed after controllers reset & clocks are handled. Additionally, add sun8i_hdmi_phy_deinit() which will deinit them at controllers driver unload. Tested on A64, H3, H6 and R40. Fixes: 9bf3797796f5 ("drm/sun4i: dw-hdmi: Make HDMI PHY into a platform device") Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20210915175836.3158839-1-jernej.skrabec@gmail.com Signed-off-by: Maarten Lankhorst Signed-off-by: Sasha Levin --- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 7 +- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 4 +- drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 97 ++++++++++++++------------ 3 files changed, 61 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index f75fb157f2ff..016b877051da 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -216,11 +216,13 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, goto err_disable_clk_tmds; } + ret = sun8i_hdmi_phy_init(hdmi->phy); + if (ret) + goto err_disable_clk_tmds; + drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs); drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); - sun8i_hdmi_phy_init(hdmi->phy); - plat_data->mode_valid = hdmi->quirks->mode_valid; plat_data->use_drm_infoframe = hdmi->quirks->use_drm_infoframe; sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data); @@ -262,6 +264,7 @@ static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master, struct sun8i_dw_hdmi *hdmi = dev_get_drvdata(dev); dw_hdmi_unbind(hdmi->hdmi); + sun8i_hdmi_phy_deinit(hdmi->phy); clk_disable_unprepare(hdmi->clk_tmds); reset_control_assert(hdmi->rst_ctrl); gpiod_set_value(hdmi->ddc_en, 0); diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 74f6ed0e2570..bffe1b9cd3dc 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -169,6 +169,7 @@ struct sun8i_hdmi_phy { struct clk *clk_phy; struct clk *clk_pll0; struct clk *clk_pll1; + struct device *dev; unsigned int rcal; struct regmap *regs; struct reset_control *rst_phy; @@ -205,7 +206,8 @@ encoder_to_sun8i_dw_hdmi(struct drm_encoder *encoder) int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node); -void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy); +int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy); +void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy); void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy, struct dw_hdmi_plat_data *plat_data); diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index c9239708d398..b64d93da651d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -506,9 +506,60 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy) phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2; } -void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) +int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) { + int ret; + + ret = reset_control_deassert(phy->rst_phy); + if (ret) { + dev_err(phy->dev, "Cannot deassert phy reset control: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(phy->clk_bus); + if (ret) { + dev_err(phy->dev, "Cannot enable bus clock: %d\n", ret); + goto err_assert_rst_phy; + } + + ret = clk_prepare_enable(phy->clk_mod); + if (ret) { + dev_err(phy->dev, "Cannot enable mod clock: %d\n", ret); + goto err_disable_clk_bus; + } + + if (phy->variant->has_phy_clk) { + ret = sun8i_phy_clk_create(phy, phy->dev, + phy->variant->has_second_pll); + if (ret) { + dev_err(phy->dev, "Couldn't create the PHY clock\n"); + goto err_disable_clk_mod; + } + + clk_prepare_enable(phy->clk_phy); + } + phy->variant->phy_init(phy); + + return 0; + +err_disable_clk_mod: + clk_disable_unprepare(phy->clk_mod); +err_disable_clk_bus: + clk_disable_unprepare(phy->clk_bus); +err_assert_rst_phy: + reset_control_assert(phy->rst_phy); + + return ret; +} + +void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy) +{ + clk_disable_unprepare(phy->clk_mod); + clk_disable_unprepare(phy->clk_bus); + clk_disable_unprepare(phy->clk_phy); + + reset_control_assert(phy->rst_phy); } void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy, @@ -638,6 +689,7 @@ static int sun8i_hdmi_phy_probe(struct platform_device *pdev) return -ENOMEM; phy->variant = (struct sun8i_hdmi_phy_variant *)match->data; + phy->dev = dev; ret = of_address_to_resource(node, 0, &res); if (ret) { @@ -696,47 +748,10 @@ static int sun8i_hdmi_phy_probe(struct platform_device *pdev) goto err_put_clk_pll1; } - ret = reset_control_deassert(phy->rst_phy); - if (ret) { - dev_err(dev, "Cannot deassert phy reset control: %d\n", ret); - goto err_put_rst_phy; - } - - ret = clk_prepare_enable(phy->clk_bus); - if (ret) { - dev_err(dev, "Cannot enable bus clock: %d\n", ret); - goto err_deassert_rst_phy; - } - - ret = clk_prepare_enable(phy->clk_mod); - if (ret) { - dev_err(dev, "Cannot enable mod clock: %d\n", ret); - goto err_disable_clk_bus; - } - - if (phy->variant->has_phy_clk) { - ret = sun8i_phy_clk_create(phy, dev, - phy->variant->has_second_pll); - if (ret) { - dev_err(dev, "Couldn't create the PHY clock\n"); - goto err_disable_clk_mod; - } - - clk_prepare_enable(phy->clk_phy); - } - platform_set_drvdata(pdev, phy); return 0; -err_disable_clk_mod: - clk_disable_unprepare(phy->clk_mod); -err_disable_clk_bus: - clk_disable_unprepare(phy->clk_bus); -err_deassert_rst_phy: - reset_control_assert(phy->rst_phy); -err_put_rst_phy: - reset_control_put(phy->rst_phy); err_put_clk_pll1: clk_put(phy->clk_pll1); err_put_clk_pll0: @@ -753,12 +768,6 @@ static int sun8i_hdmi_phy_remove(struct platform_device *pdev) { struct sun8i_hdmi_phy *phy = platform_get_drvdata(pdev); - clk_disable_unprepare(phy->clk_mod); - clk_disable_unprepare(phy->clk_bus); - clk_disable_unprepare(phy->clk_phy); - - reset_control_assert(phy->rst_phy); - reset_control_put(phy->rst_phy); clk_put(phy->clk_pll0); -- 2.33.0