From patchwork Mon Jan 13 21:52:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Melody Olvera X-Patchwork-Id: 856970 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 254A21F9AA6; Mon, 13 Jan 2025 21:52:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736805158; cv=none; b=mCpSwpXAYRYcTejaHYtHr8YqGSiTrXQiGXOqKN2QB4RftkYbD4PF6qWNa/gVE2Gm8i12KILjpqrMTdLhRunYeztCpqlnk7cW/VvjVFJPnXU+MM4bqBwuXVrQeuWxsvIRPQhTKHBv1vvKcetp/8RJ3Sggib+KQDau0ZqqJiewNmo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736805158; c=relaxed/simple; bh=nxyNPG/qi3RGmai8rva7D17lgOivgkxfETZS8iuFDto=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=Ih11JVo5D+ryoP702YKaEZ7QQNnb/pmeT5QgsgccRMEmo/HxZaGH9UlY+/1VUrmN2eYNsZP6sICclsFlvHvLf3cRyGhHHg+Eqt1zHeURA5h27LlR/8zXDUh0soHlPAnP5qrmxXEBCli+55BmcqDlYDSFpmBGiV5RX9qdihyWKS4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com; spf=pass smtp.mailfrom=quicinc.com; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b=P1yE4LQI; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=quicinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="P1yE4LQI" Received: from pps.filterd (m0279868.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 50DIinoJ007916; Mon, 13 Jan 2025 21:52:21 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= Oq7ZiiXdqCWiSuoAFKvETU+AL0s3kTQVRBiCI00FBe8=; b=P1yE4LQIisFC0RPV 4dL73DYNnH/Mdy/9nG+9zrhm2ORZvbL78BXvGoxKnP3rDy13whBGhyn4Wvt/QocA WkkUio29f727rgFcflNK+i+7hv1hoIU9N7fXiayXXPwpUVM2ZVXa+SlmdQoFHFM/ pl0BII4pzASCGVUOHV07OqMDFTDkk1oivKjo87t75/BK8aju6DInINQMbA3cQKjH Y36X0LmAV0kOR7RxSBI1AeImuxkaD59yaaG/jD0vWFrKbal4iDOF2dN0AehvvOEx cMyhZPWnb1AaQEi/q5Kaq8wx5WXY7+LBvjR2ZdDO3wXIqmoUoUJrpuG5S2a/TdvQ LaczeQ== Received: from nasanppmta02.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4458cn0crc-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 13 Jan 2025 21:52:20 +0000 (GMT) Received: from nasanex01b.na.qualcomm.com (nasanex01b.na.qualcomm.com [10.46.141.250]) by NASANPPMTA02.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id 50DLqJDD018747 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 13 Jan 2025 21:52:19 GMT Received: from hu-molvera-lv.qualcomm.com (10.49.16.6) by nasanex01b.na.qualcomm.com (10.46.141.250) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.9; Mon, 13 Jan 2025 13:52:18 -0800 From: Melody Olvera Date: Mon, 13 Jan 2025 13:52:11 -0800 Subject: [PATCH 5/7] phy: qcom: Add M31 based eUSB2 PHY driver Precedence: bulk X-Mailing-List: linux-arm-msm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <20250113-sm8750_usb_master-v1-5-09afe1dc2524@quicinc.com> References: <20250113-sm8750_usb_master-v1-0-09afe1dc2524@quicinc.com> In-Reply-To: <20250113-sm8750_usb_master-v1-0-09afe1dc2524@quicinc.com> To: Vinod Koul , Kishon Vijay Abraham I , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Wesley Cheng , Greg Kroah-Hartman , Philipp Zabel , Catalin Marinas , "Will Deacon" , Bjorn Andersson , "Konrad Dybcio" , Satya Durga Srinivasu Prabhala , Trilok Soni CC: , , , , , , "Melody Olvera" X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1736805135; l=10310; i=quic_molvera@quicinc.com; s=20241204; h=from:subject:message-id; bh=zh3fLZ1YAp8bN2OfzZTLMVNywL/L8gGAPTbeGKcffJQ=; b=BC/MXcfuZ/OjD2nBR83k9nw90aVN5EvPQ72y9xW+sD7ccHXD/MPWfsVaKvfH1MG7dxo8r/INs GBVPNXbiZSkCL5NeQnnbPk+tKG/V1+eNGy6mxNvHv1KcraFKEVdlyL9 X-Developer-Key: i=quic_molvera@quicinc.com; a=ed25519; pk=1DGLp3zVYsHAWipMaNZZTHR321e8xK52C9vuAoeca5c= X-ClientProxiedBy: nalasex01a.na.qualcomm.com (10.47.209.196) To nasanex01b.na.qualcomm.com (10.46.141.250) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: 9xBNFy5qw4YGVykCmfMroUxJbLZRcOS0 X-Proofpoint-GUID: 9xBNFy5qw4YGVykCmfMroUxJbLZRcOS0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.60.29 definitions=2024-09-06_09,2024-09-06_01,2024-09-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 impostorscore=0 phishscore=0 clxscore=1015 mlxlogscore=999 mlxscore=0 priorityscore=1501 malwarescore=0 suspectscore=0 spamscore=0 bulkscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2411120000 definitions=main-2501130171 From: Wesley Cheng On SM8750, the eUSB2 PHY used is M31 based. Add the initialization sequences to bring it out of reset, and to initialize the associated eUSB2 repeater as well. Signed-off-by: Wesley Cheng Signed-off-by: Melody Olvera --- drivers/phy/qualcomm/Kconfig | 12 +- drivers/phy/qualcomm/Makefile | 1 + drivers/phy/qualcomm/phy-qcom-m31-eusb2.c | 269 ++++++++++++++++++++++++++++++ 3 files changed, 281 insertions(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index 846f8c99547fd5132feaa1e41093b8eab51714f9..8c265ae86c7b9ddcb66b42626557ea130b674001 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -140,7 +140,7 @@ config PHY_QCOM_EUSB2_REPEATER select GENERIC_PHY help Enable support for the USB high-speed SNPS eUSB2 repeater on Qualcomm - PMICs. The repeater is paired with a Synopsys eUSB2 Phy + PMICs. The repeater can be paired with a Synopsys or M31 eUSB2 Phy on Qualcomm SOCs. config PHY_QCOM_M31_USB @@ -154,6 +154,16 @@ config PHY_QCOM_M31_USB management. This driver is required even for peripheral only or host only mode configurations. +config PHY_QCOM_M31_EUSB + tristate "Qualcomm M31 eUSB2 PHY driver support" + depends on USB && (ARCH_QCOM || COMPILE_TEST) + select GENERIC_PHY + help + Enable this to support M31 EUSB2 PHY transceivers on Qualcomm + chips with DWC3 USB core. It supports initializing and cleaning + up of the associated USB repeater that is paired with the eUSB2 + PHY. + config PHY_QCOM_USB_HS tristate "Qualcomm USB HS PHY module" depends on USB_ULPI_BUS diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index eb60e950ad53334a3ada3db618aa584afb33fb93..f88ba0f71a73cd6935184c8831d6cd6488d6551f 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PHY_QCOM_EDP) += phy-qcom-edp.o obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o obj-$(CONFIG_PHY_QCOM_M31_USB) += phy-qcom-m31.o +obj-$(CONFIG_PHY_QCOM_M31_EUSB) += phy-qcom-m31-eusb2.o obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o phy-qcom-qmp-usbc.o diff --git a/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c new file mode 100644 index 0000000000000000000000000000000000000000..e15529673e358db914936a60fa605c872cd2511a --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-m31-eusb2.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USB_PHY_UTMI_CTRL0 (0x3c) + +#define USB_PHY_UTMI_CTRL5 (0x50) + +#define USB_PHY_HS_PHY_CTRL_COMMON0 (0x54) +#define FSEL (0x7 << 4) +#define FSEL_38_4_MHZ_VAL (0x6 << 4) + +#define USB_PHY_HS_PHY_CTRL2 (0x64) + +#define USB_PHY_CFG0 (0x94) +#define USB_PHY_CFG1 (0x154) + +#define USB_PHY_FSEL_SEL (0xb8) + +#define USB_PHY_XCFGI_39_32 (0x16c) +#define USB_PHY_XCFGI_71_64 (0x17c) +#define USB_PHY_XCFGI_31_24 (0x168) +#define USB_PHY_XCFGI_7_0 (0x15c) + +#define M31_EUSB_PHY_INIT_CFG(o, b, v) \ +{ \ + .off = o, \ + .mask = b, \ + .val = v, \ +} + +struct m31_phy_tbl_entry { + u32 off; + u32 mask; + u32 val; +}; + +struct m31_eusb2_priv_data { + const struct m31_phy_tbl_entry *setup_seq; + unsigned int setup_seq_nregs; + const struct m31_phy_tbl_entry *override_seq; + unsigned int override_seq_nregs; + const struct m31_phy_tbl_entry *reset_seq; + unsigned int reset_seq_nregs; + unsigned int fsel; +}; + +static const struct m31_phy_tbl_entry m31_eusb2_setup_tbl[] = { + M31_EUSB_PHY_INIT_CFG(USB_PHY_CFG0, BIT(1), 1), + M31_EUSB_PHY_INIT_CFG(USB_PHY_UTMI_CTRL5, BIT(1), 1), + M31_EUSB_PHY_INIT_CFG(USB_PHY_CFG1, BIT(0), 1), + M31_EUSB_PHY_INIT_CFG(USB_PHY_FSEL_SEL, BIT(0), 1), +}; + +static const struct m31_phy_tbl_entry m31_eusb_phy_override_tbl[] = { + M31_EUSB_PHY_INIT_CFG(USB_PHY_XCFGI_39_32, GENMASK(3, 2), 0), + M31_EUSB_PHY_INIT_CFG(USB_PHY_XCFGI_71_64, GENMASK(3, 0), 7), + M31_EUSB_PHY_INIT_CFG(USB_PHY_XCFGI_31_24, GENMASK(2, 0), 0), + M31_EUSB_PHY_INIT_CFG(USB_PHY_XCFGI_7_0, GENMASK(1, 0), 0), +}; + +static const struct m31_phy_tbl_entry m31_eusb_phy_reset_tbl[] = { + M31_EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL2, BIT(3), 1), + M31_EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL2, BIT(2), 1), + M31_EUSB_PHY_INIT_CFG(USB_PHY_UTMI_CTRL0, BIT(0), 1), + M31_EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL_COMMON0, BIT(1), 1), + M31_EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL_COMMON0, BIT(2), 0), + M31_EUSB_PHY_INIT_CFG(USB_PHY_UTMI_CTRL5, BIT(1), 0), + M31_EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL2, BIT(3), 0), + M31_EUSB_PHY_INIT_CFG(USB_PHY_CFG0, BIT(1), 0), +}; + +struct m31eusb2_phy { + struct phy *phy; + void __iomem *base; + const struct m31_eusb2_priv_data *data; + + struct regulator *vreg; + struct clk *clk; + struct reset_control *reset; + + struct phy *repeater; +}; + +static void msm_m31_eusb2_write_readback(void __iomem *base, u32 offset, + const u32 mask, u32 val) +{ + u32 write_val, tmp = readl_relaxed(base + offset); + + tmp &= ~mask; + write_val = tmp | val; + + writel_relaxed(write_val, base + offset); + + tmp = readl_relaxed(base + offset); + tmp &= mask; + + if (tmp != val) + pr_err("write: %x to offset: %x FAILED\n", val, offset); +} + +static void m31eusb2_phy_write_sequence(struct m31eusb2_phy *phy, + const struct m31_phy_tbl_entry *tbl, + int num) +{ + int i; + + for (i = 0 ; i < num; i++, tbl++) { + dev_dbg(&phy->phy->dev, "Offset:%x BitMask:%x Value:%x", + tbl->off, tbl->mask, tbl->val); + + msm_m31_eusb2_write_readback(phy->base, + tbl->off, tbl->mask, + tbl->val << __ffs(tbl->mask)); + } +} + +static int m31eusb2_phy_init(struct phy *uphy) +{ + struct m31eusb2_phy *phy = phy_get_drvdata(uphy); + const struct m31_eusb2_priv_data *data = phy->data; + int ret; + + ret = regulator_enable(phy->vreg); + if (ret) { + dev_err(&uphy->dev, "failed to enable regulator, %d\n", ret); + return ret; + } + + ret = phy_init(phy->repeater); + if (ret) { + dev_err(&uphy->dev, "repeater init failed. %d\n", ret); + goto disable_vreg; + } + + if (ret) { + dev_err(&uphy->dev, "failed to enable cfg ahb clock, %d\n", ret); + goto disable_repeater; + } + + /* Perform phy reset */ + reset_control_assert(phy->reset); + udelay(5); + reset_control_deassert(phy->reset); + + m31eusb2_phy_write_sequence(phy, data->setup_seq, data->setup_seq_nregs); + msm_m31_eusb2_write_readback(phy->base, + USB_PHY_HS_PHY_CTRL_COMMON0, FSEL, + data->fsel); + m31eusb2_phy_write_sequence(phy, data->override_seq, data->override_seq_nregs); + m31eusb2_phy_write_sequence(phy, data->reset_seq, data->reset_seq_nregs); + + return 0; + +disable_repeater: + phy_exit(phy->repeater); +disable_vreg: + regulator_disable(phy->vreg); + + return 0; +} + +static int m31eusb2_phy_exit(struct phy *uphy) +{ + struct m31eusb2_phy *phy = phy_get_drvdata(uphy); + + regulator_disable(phy->vreg); + phy_exit(phy->repeater); + + return 0; +} + +static const struct phy_ops m31eusb2_phy_gen_ops = { + .init = m31eusb2_phy_init, + .exit = m31eusb2_phy_exit, + .owner = THIS_MODULE, +}; + +static int m31eusb2_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + const struct m31_eusb2_priv_data *data; + struct device *dev = &pdev->dev; + struct m31eusb2_phy *phy; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + data = of_device_get_match_data(dev); + if (IS_ERR(data)) + return -EINVAL; + phy->data = data; + + phy->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy->base)) + return PTR_ERR(phy->base); + + phy->reset = devm_reset_control_get_exclusive_by_index(dev, 0); + if (IS_ERR(phy->reset)) + return PTR_ERR(phy->reset); + + phy->clk = devm_clk_get(dev, NULL); + + phy->phy = devm_phy_create(dev, NULL, &m31eusb2_phy_gen_ops); + if (IS_ERR(phy->phy)) + return dev_err_probe(dev, PTR_ERR(phy->phy), + "failed to create phy\n"); + + phy->vreg = devm_regulator_get(dev, "vdd"); + if (IS_ERR(phy->vreg)) + return dev_err_probe(dev, PTR_ERR(phy->vreg), + "failed to get vreg\n"); + + phy_set_drvdata(phy->phy, phy); + + phy->repeater = devm_of_phy_get_by_index(dev, dev->of_node, 0); + if (IS_ERR(phy->repeater)) + return dev_err_probe(dev, PTR_ERR(phy->repeater), + "failed to get repeater\n"); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (!IS_ERR(phy_provider)) + dev_info(dev, "Registered M31 USB phy\n"); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct m31_eusb2_priv_data m31_eusb_v1_data = { + .setup_seq = m31_eusb2_setup_tbl, + .setup_seq_nregs = ARRAY_SIZE(m31_eusb2_setup_tbl), + .override_seq = m31_eusb_phy_override_tbl, + .override_seq_nregs = ARRAY_SIZE(m31_eusb_phy_override_tbl), + .reset_seq = m31_eusb_phy_reset_tbl, + .reset_seq_nregs = ARRAY_SIZE(m31_eusb_phy_reset_tbl), + .fsel = FSEL_38_4_MHZ_VAL, +}; + +static const struct of_device_id m31eusb2_phy_id_table[] = { + { .compatible = "qcom,sm8750-m31-eusb2-phy", .data = &m31_eusb_v1_data }, + { }, +}; +MODULE_DEVICE_TABLE(of, m31eusb2_phy_id_table); + +static struct platform_driver m31eusb2_phy_driver = { + .probe = m31eusb2_phy_probe, + .driver = { + .name = "qcom-m31eusb2-phy", + .of_match_table = m31eusb2_phy_id_table, + }, +}; + +module_platform_driver(m31eusb2_phy_driver); + +MODULE_DESCRIPTION("eUSB2 Qualcomm M31 HSPHY driver"); +MODULE_LICENSE("GPL");