1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2023 Bhupesh Sharma <bhupesh.sharma@linaro.org>
5 *
6 * Based on Linux driver
7 */
8
9#include <dm.h>
10#include <dm/device_compat.h>
11#include <dm/devres.h>
12#include <generic-phy.h>
13#include <malloc.h>
14#include <reset.h>
15
16#include <asm/io.h>
17#include <linux/bitops.h>
18#include <linux/delay.h>
19#include <linux/iopoll.h>
20
21#define USB2_PHY_USB_PHY_UTMI_CTRL0 (0x3c)
22#define SLEEPM BIT(0)
23#define OPMODE_MASK GENMASK(4, 3)
24#define OPMODE_NORMAL (0x00)
25#define OPMODE_NONDRIVING BIT(3)
26#define TERMSEL BIT(5)
27
28#define USB2_PHY_USB_PHY_UTMI_CTRL5 (0x50)
29#define POR BIT(1)
30
31#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0 (0x54)
32#define SIDDQ BIT(2)
33#define RETENABLEN BIT(3)
34#define FSEL_MASK GENMASK(6, 4)
35#define FSEL_DEFAULT (0x3 << 4)
36
37#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1 (0x58)
38#define VBUSVLDEXTSEL0 BIT(4)
39#define PLLBTUNE BIT(5)
40
41#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2 (0x5c)
42#define VREGBYPASS BIT(0)
43
44#define USB2_PHY_USB_PHY_HS_PHY_CTRL1 (0x60)
45#define VBUSVLDEXT0 BIT(0)
46
47#define USB2_PHY_USB_PHY_HS_PHY_CTRL2 (0x64)
48#define USB2_AUTO_RESUME BIT(0)
49#define USB2_SUSPEND_N BIT(2)
50#define USB2_SUSPEND_N_SEL BIT(3)
51
52#define USB2_PHY_USB_PHY_CFG0 (0x94)
53#define UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN BIT(0)
54#define UTMI_PHY_CMN_CTRL_OVERRIDE_EN BIT(1)
55
56#define USB2_PHY_USB_PHY_REFCLK_CTRL (0xa0)
57#define REFCLK_SEL_MASK GENMASK(1, 0)
58#define REFCLK_SEL_DEFAULT (0x2 << 0)
59
60struct qcom_snps_hsphy {
61	void __iomem *base;
62	struct reset_ctl_bulk resets;
63};
64
65/*
66 * We should just be able to use clrsetbits_le32() here, but this results
67 * in crashes on some boards. This is suspected to be because of some bus
68 * arbitration quirks with the PHY (i.e. it takes several bus clock cycles
69 * for the write to actually go through). The readl_relaxed() at the end will
70 * block until the write is completed (and all registers updated), and thus
71 * ensure that we don't access the PHY registers when they're in an
72 * undetermined state.
73 */
74static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset,
75					      u32 mask, u32 val)
76{
77	u32 reg;
78
79	reg = readl_relaxed(base + offset);
80
81	reg &= ~mask;
82	reg |= val & mask;
83	writel_relaxed(reg, base + offset);
84
85	/* Ensure above write is completed */
86	readl_relaxed(base + offset);
87}
88
89static int qcom_snps_hsphy_usb_init(struct phy *phy)
90{
91	struct qcom_snps_hsphy *priv = dev_get_priv(phy->dev);
92
93	qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_CFG0,
94				   UTMI_PHY_CMN_CTRL_OVERRIDE_EN,
95				   UTMI_PHY_CMN_CTRL_OVERRIDE_EN);
96	qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_UTMI_CTRL5, POR,
97				   POR);
98	qcom_snps_hsphy_write_mask(priv->base,
99				   USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0, FSEL_MASK, 0);
100	qcom_snps_hsphy_write_mask(priv->base,
101				   USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
102				   PLLBTUNE, PLLBTUNE);
103	qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_REFCLK_CTRL,
104				   REFCLK_SEL_DEFAULT, REFCLK_SEL_MASK);
105	qcom_snps_hsphy_write_mask(priv->base,
106				   USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
107				   VBUSVLDEXTSEL0, VBUSVLDEXTSEL0);
108	qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1,
109				   VBUSVLDEXT0, VBUSVLDEXT0);
110
111	qcom_snps_hsphy_write_mask(priv->base,
112				   USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2,
113				   VREGBYPASS, VREGBYPASS);
114
115	qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
116				   USB2_SUSPEND_N_SEL | USB2_SUSPEND_N,
117				   USB2_SUSPEND_N_SEL | USB2_SUSPEND_N);
118
119	qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
120				   SLEEPM, SLEEPM);
121
122	qcom_snps_hsphy_write_mask(
123		priv->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0, SIDDQ, 0);
124
125	qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_UTMI_CTRL5, POR,
126				   0);
127
128	qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
129				   USB2_SUSPEND_N_SEL, 0);
130
131	qcom_snps_hsphy_write_mask(priv->base, USB2_PHY_USB_PHY_CFG0,
132				   UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0);
133
134	return 0;
135}
136
137static int qcom_snps_hsphy_power_on(struct phy *phy)
138{
139	struct qcom_snps_hsphy *priv = dev_get_priv(phy->dev);
140	int ret;
141
142	ret = reset_deassert_bulk(&priv->resets);
143	if (ret)
144		return ret;
145
146	ret = qcom_snps_hsphy_usb_init(phy);
147	if (ret)
148		return ret;
149
150	return 0;
151}
152
153static int qcom_snps_hsphy_power_off(struct phy *phy)
154{
155	struct qcom_snps_hsphy *priv = dev_get_priv(phy->dev);
156
157	reset_assert_bulk(&priv->resets);
158
159	return 0;
160}
161
162static int qcom_snps_hsphy_phy_probe(struct udevice *dev)
163{
164	struct qcom_snps_hsphy *priv = dev_get_priv(dev);
165	int ret;
166
167	priv->base = dev_read_addr_ptr(dev);
168	if (IS_ERR(priv->base))
169		return PTR_ERR(priv->base);
170
171	ret = reset_get_bulk(dev, &priv->resets);
172	if (ret < 0) {
173		printf("failed to get resets, ret = %d\n", ret);
174		return ret;
175	}
176
177	reset_deassert_bulk(&priv->resets);
178
179	return 0;
180}
181
182static struct phy_ops qcom_snps_hsphy_phy_ops = {
183	.power_on = qcom_snps_hsphy_power_on,
184	.power_off = qcom_snps_hsphy_power_off,
185};
186
187static const struct udevice_id qcom_snps_hsphy_phy_ids[] = {
188	{ .compatible = "qcom,sm8150-usb-hs-phy" },
189	{ .compatible = "qcom,usb-snps-hs-5nm-phy" },
190	{ .compatible = "qcom,usb-snps-hs-7nm-phy" },
191	{ .compatible = "qcom,usb-snps-femto-v2-phy" },
192	{}
193};
194
195U_BOOT_DRIVER(qcom_usb_qcom_snps_hsphy) = {
196	.name = "qcom-snps-hsphy",
197	.id = UCLASS_PHY,
198	.of_match = qcom_snps_hsphy_phy_ids,
199	.ops = &qcom_snps_hsphy_phy_ops,
200	.probe = qcom_snps_hsphy_phy_probe,
201	.priv_auto = sizeof(struct qcom_snps_hsphy),
202};
203