From patchwork Thu Sep 28 11:16:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Baryshkov X-Patchwork-Id: 727686 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3DF9DE732C0 for ; Thu, 28 Sep 2023 11:18:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231808AbjI1LSn (ORCPT ); Thu, 28 Sep 2023 07:18:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39338 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232186AbjI1LS3 (ORCPT ); Thu, 28 Sep 2023 07:18:29 -0400 Received: from mail-lf1-x136.google.com (mail-lf1-x136.google.com [IPv6:2a00:1450:4864:20::136]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D51737EFD for ; Thu, 28 Sep 2023 04:16:38 -0700 (PDT) Received: by mail-lf1-x136.google.com with SMTP id 2adb3069b0e04-50325ce89e9so21213552e87.0 for ; Thu, 28 Sep 2023 04:16:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1695899797; x=1696504597; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=WaqYa1p7vqN61Nnmz1mMsVu16pc4A060DpWFBkQ5zwA=; b=eghbFeGCOvcFUBGdFu4a8ihouIBpG2DtPjBfEvv25B4+mVOBjwwrLWxzJbkn4lm//z fIbvCrOQIQOPiuCs7Av0Rx01HvCgvjVfX31rTj4nfWpMOByoO+ODWn3g4S/CsWvjqc4+ YvmBX9u9JnTIRPkvsvP3S1ZGMd1OLdwnwZbuuAOk6CytSWjkQI0zGYjZbHEzsK2mYv3o vf8gQdY1eLY5egGrPs4/OS+EmVTZf3zSfk91rgC7yrjrGuA9JEbnfnZx164ixChAC5+T yHXsIo4XmKZKHdWrRj4u4fDWdAsKLjxnFJ/Z2axGrz5uPJ5Vbf5n8XsPr6xkbdNYGB41 Ul6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1695899797; x=1696504597; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=WaqYa1p7vqN61Nnmz1mMsVu16pc4A060DpWFBkQ5zwA=; b=uhPuIoxxwgfYKb9vUoBH3dLoVIi8rbGLqbiddLK2B599AFy/HpzFS4T68Djc0qazQs MBbJCXmwkqnftlUkU6J1qZyKlpN4Zn9m/qhr7HmLYeqUC2Krfc2vdrE9jyABRFqyBKgo irKQBoRwU8OvC9km+TSfEWZNiTmPaKrkbWJi9y+mEyVRLMuGOnsTTO+M8lIekGAXmG0H CRaTCV2UhUM6ANr+jxNleARpO/XcWgIOc52Do2+n+vYb0Z2KmtQIo4LQRZClnC8TdZyJ PWQLr5nV1vcUU0NvlUCyuejb88XQ48TdyBCgrUM4FaXKPnbQCIBP7+avR8gdtRWEIfSX cMZA== X-Gm-Message-State: AOJu0YwZLFeXlpyB/QUIv/PyuxX4s23zXeawD3njr6rFv7Ldv1UwMFfs LRb/DvubI0MWc+eGFvFgyKRI1g== X-Google-Smtp-Source: AGHT+IELwAXbwNWKBM1QMtP91xkOdmLsDx0Ktv/JYhcUeyUVfQBYJWS7Wq0baHGU6E4lXOEPSArOwg== X-Received: by 2002:a05:6512:3c8b:b0:502:ab7b:e480 with SMTP id h11-20020a0565123c8b00b00502ab7be480mr1068705lfv.36.1695899796850; Thu, 28 Sep 2023 04:16:36 -0700 (PDT) Received: from umbar.unikie.fi ([192.130.178.91]) by smtp.gmail.com with ESMTPSA id j18-20020ac253b2000000b004fb738796casm3086623lfh.40.2023.09.28.04.16.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Sep 2023 04:16:36 -0700 (PDT) From: Dmitry Baryshkov To: Rob Clark , Sean Paul , Abhinav Kumar , Marijn Suijten , Vinod Koul , Kishon Vijay Abraham I Cc: Philipp Zabel , Stephen Boyd , David Airlie , Daniel Vetter , Bjorn Andersson , Konrad Dybcio , linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org, freedreno@lists.freedesktop.org, linux-phy@lists.infradead.org Subject: [PATCH v3 07/15] phy: qualcomm: add MSM8x60 HDMI PHY support Date: Thu, 28 Sep 2023 14:16:21 +0300 Message-Id: <20230928111630.1217419-8-dmitry.baryshkov@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230928111630.1217419-1-dmitry.baryshkov@linaro.org> References: <20230928111630.1217419-1-dmitry.baryshkov@linaro.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Add support for HDMI PHY on Qualcomm MSM8x60 / APQ8060 platforms. Signed-off-by: Dmitry Baryshkov --- drivers/phy/qualcomm/Makefile | 1 + drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c | 184 ++++++++++++++++++++ drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c | 32 ++-- drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h | 1 + 4 files changed, 204 insertions(+), 14 deletions(-) create mode 100644 drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index 082020af7fc1..79df2f1e9bc8 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -10,6 +10,7 @@ phy-qcom-hdmi-y := \ phy-qcom-hdmi-preqmp.o \ phy-qcom-hdmi-28hpm.o \ phy-qcom-hdmi-28lpm.o \ + phy-qcom-hdmi-45nm.o \ obj-$(CONFIG_PHY_QCOM_M31_USB) += phy-qcom-m31.o obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c b/drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c new file mode 100644 index 000000000000..31e1e9f2d037 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark + * Copyright (c) 2023, Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-qcom-hdmi-preqmp.h" + +#define REG_HDMI_8x60_PHY_REG0 0x00000000 +#define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK 0x0000001c + +#define REG_HDMI_8x60_PHY_REG1 0x00000004 +#define HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK 0x000000f0 +#define HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK 0x0000000f + +#define REG_HDMI_8x60_PHY_REG2 0x00000008 +#define HDMI_8x60_PHY_REG2_PD_DESER 0x00000001 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_1 0x00000002 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_2 0x00000004 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_3 0x00000008 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_4 0x00000010 +#define HDMI_8x60_PHY_REG2_PD_PLL 0x00000020 +#define HDMI_8x60_PHY_REG2_PD_PWRGEN 0x00000040 +#define HDMI_8x60_PHY_REG2_RCV_SENSE_EN 0x00000080 + +#define REG_HDMI_8x60_PHY_REG3 0x0000000c +#define HDMI_8x60_PHY_REG3_PLL_ENABLE 0x00000001 + +#define REG_HDMI_8x60_PHY_REG4 0x00000010 + +#define REG_HDMI_8x60_PHY_REG5 0x00000014 + +#define REG_HDMI_8x60_PHY_REG6 0x00000018 + +#define REG_HDMI_8x60_PHY_REG7 0x0000001c + +#define REG_HDMI_8x60_PHY_REG8 0x00000020 + +#define REG_HDMI_8x60_PHY_REG9 0x00000024 + +#define REG_HDMI_8x60_PHY_REG10 0x00000028 + +#define REG_HDMI_8x60_PHY_REG11 0x0000002c + +#define REG_HDMI_8x60_PHY_REG12 0x00000030 +#define HDMI_8x60_PHY_REG12_RETIMING_EN 0x00000001 +#define HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN 0x00000002 +#define HDMI_8x60_PHY_REG12_FORCE_LOCK 0x00000010 + +static int qcom_hdmi_msm8x60_phy_power_on(struct qcom_hdmi_preqmp_phy *hdmi_phy) +{ + unsigned long pixclock = hdmi_phy->hdmi_opts.pixel_clk_rate; + + /* De-serializer delay D/C for non-lbk mode: */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG0, + FIELD_PREP(HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK, 3)); + + if (pixclock == 27000) { + /* video_format == HDMI_VFRMT_720x480p60_16_9 */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG1, + FIELD_PREP(HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK, 5) | + FIELD_PREP(HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK, 3)); + } else { + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG1, + FIELD_PREP(HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK, 5) | + FIELD_PREP(HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK, 4)); + } + + /* No matter what, start from the power down mode: */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG2, + HDMI_8x60_PHY_REG2_PD_PWRGEN | + HDMI_8x60_PHY_REG2_PD_PLL | + HDMI_8x60_PHY_REG2_PD_DRIVE_4 | + HDMI_8x60_PHY_REG2_PD_DRIVE_3 | + HDMI_8x60_PHY_REG2_PD_DRIVE_2 | + HDMI_8x60_PHY_REG2_PD_DRIVE_1 | + HDMI_8x60_PHY_REG2_PD_DESER); + + /* Turn PowerGen on: */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG2, + HDMI_8x60_PHY_REG2_PD_PLL | + HDMI_8x60_PHY_REG2_PD_DRIVE_4 | + HDMI_8x60_PHY_REG2_PD_DRIVE_3 | + HDMI_8x60_PHY_REG2_PD_DRIVE_2 | + HDMI_8x60_PHY_REG2_PD_DRIVE_1 | + HDMI_8x60_PHY_REG2_PD_DESER); + + /* Turn PLL power on: */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG2, + HDMI_8x60_PHY_REG2_PD_DRIVE_4 | + HDMI_8x60_PHY_REG2_PD_DRIVE_3 | + HDMI_8x60_PHY_REG2_PD_DRIVE_2 | + HDMI_8x60_PHY_REG2_PD_DRIVE_1 | + HDMI_8x60_PHY_REG2_PD_DESER); + + /* Write to HIGH after PLL power down de-assert: */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG3, + HDMI_8x60_PHY_REG3_PLL_ENABLE); + + /* ASIC power on; PHY REG9 = 0 */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG9, 0); + + /* Enable PLL lock detect, PLL lock det will go high after lock + * Enable the re-time logic + */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG12, + HDMI_8x60_PHY_REG12_RETIMING_EN | + HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN); + + /* Drivers are on: */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG2, + HDMI_8x60_PHY_REG2_PD_DESER); + + /* If the RX detector is needed: */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG2, + HDMI_8x60_PHY_REG2_RCV_SENSE_EN | + HDMI_8x60_PHY_REG2_PD_DESER); + + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG4, 0); + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG5, 0); + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG6, 0); + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG7, 0); + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG8, 0); + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG9, 0); + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG10, 0); + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG11, 0); + + /* If we want to use lock enable based on counting: */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG12, + HDMI_8x60_PHY_REG12_RETIMING_EN | + HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN | + HDMI_8x60_PHY_REG12_FORCE_LOCK); + + return 0; +} + +static int qcom_hdmi_msm8x60_phy_power_off(struct qcom_hdmi_preqmp_phy *hdmi_phy) +{ + /* Turn off Driver */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG2, + HDMI_8x60_PHY_REG2_PD_DRIVE_4 | + HDMI_8x60_PHY_REG2_PD_DRIVE_3 | + HDMI_8x60_PHY_REG2_PD_DRIVE_2 | + HDMI_8x60_PHY_REG2_PD_DRIVE_1 | + HDMI_8x60_PHY_REG2_PD_DESER); + udelay(10); + /* Disable PLL */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG3, 0); + /* Power down PHY, but keep RX-sense: */ + hdmi_phy_write(hdmi_phy, REG_HDMI_8x60_PHY_REG2, + HDMI_8x60_PHY_REG2_RCV_SENSE_EN | + HDMI_8x60_PHY_REG2_PD_PWRGEN | + HDMI_8x60_PHY_REG2_PD_PLL | + HDMI_8x60_PHY_REG2_PD_DRIVE_4 | + HDMI_8x60_PHY_REG2_PD_DRIVE_3 | + HDMI_8x60_PHY_REG2_PD_DRIVE_2 | + HDMI_8x60_PHY_REG2_PD_DRIVE_1 | + HDMI_8x60_PHY_REG2_PD_DESER); + + return 0; +} + +const struct qcom_hdmi_preqmp_cfg msm8x60_hdmi_phy_cfg = { + .clk_names = { "slave_iface" }, + .num_clks = 1, + + .reg_names = { "core-vdda" }, + .num_regs = 1, + + .power_on = qcom_hdmi_msm8x60_phy_power_on, + .power_off = qcom_hdmi_msm8x60_phy_power_off, + + /* FIXME: no PLL support */ +}; diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c index e181a45df2dc..66aa199424b8 100644 --- a/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c +++ b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c @@ -147,20 +147,23 @@ static int qcom_hdmi_preqmp_probe(struct platform_device *pdev) if (ret) return ret; - init.name = "hdmipll"; - init.ops = cfg->pll_ops; - init.flags = CLK_GET_RATE_NOCACHE; - init.parent_data = cfg->pll_parent; - init.num_parents = 1; - - hdmi_phy->pll_hw.init = &init; - ret = devm_clk_hw_register(hdmi_phy->dev, &hdmi_phy->pll_hw); - if (ret) - goto err; - - ret = devm_of_clk_add_hw_provider(hdmi_phy->dev, of_clk_hw_simple_get, &hdmi_phy->pll_hw); - if (ret) - goto err; + /* FIXME: msm8x60 doesn't yet have PLL ops */ + if (cfg->pll_ops) { + init.name = "hdmipll"; + init.ops = cfg->pll_ops; + init.flags = CLK_GET_RATE_NOCACHE; + init.parent_data = cfg->pll_parent; + init.num_parents = 1; + + hdmi_phy->pll_hw.init = &init; + ret = devm_clk_hw_register(hdmi_phy->dev, &hdmi_phy->pll_hw); + if (ret) + goto err; + + ret = devm_of_clk_add_hw_provider(hdmi_phy->dev, of_clk_hw_simple_get, &hdmi_phy->pll_hw); + if (ret) + goto err; + } hdmi_phy->phy = devm_phy_create(dev, pdev->dev.of_node, &qcom_hdmi_preqmp_phy_ops); if (IS_ERR(hdmi_phy->phy)) { @@ -180,6 +183,7 @@ static int qcom_hdmi_preqmp_probe(struct platform_device *pdev) } static const struct of_device_id qcom_hdmi_preqmp_of_match_table[] = { + { .compatible = "qcom,hdmi-phy-8x60", .data = &msm8x60_hdmi_phy_cfg, }, { .compatible = "qcom,hdmi-phy-8960", .data = &msm8960_hdmi_phy_cfg, }, { .compatible = "qcom,hdmi-phy-8974", .data = &msm8974_hdmi_phy_cfg, }, { }, diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h index bc81d68463ec..66fb9235520a 100644 --- a/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h +++ b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h @@ -74,6 +74,7 @@ static inline u32 hdmi_pll_read(struct qcom_hdmi_preqmp_phy *phy, int offset) return readl(phy->pll_reg + offset); } +extern const struct qcom_hdmi_preqmp_cfg msm8x60_hdmi_phy_cfg; extern const struct qcom_hdmi_preqmp_cfg msm8960_hdmi_phy_cfg; extern const struct qcom_hdmi_preqmp_cfg msm8974_hdmi_phy_cfg;