xref: /openbmc/u-boot/drivers/phy/meson-gxl-usb3.c (revision f1b1f770)
1 /*
2  * Meson GXL USB3 PHY driver
3  *
4  * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
5  * Copyright (C) 2018 BayLibre, SAS
6  * Author: Neil Armstrong <narmstron@baylibre.com>
7  *
8  * SPDX-License-Identifier:	GPL-2.0+
9  */
10 
11 #include <common.h>
12 #include <asm/io.h>
13 #include <bitfield.h>
14 #include <dm.h>
15 #include <errno.h>
16 #include <generic-phy.h>
17 #include <regmap.h>
18 #include <clk.h>
19 
20 #include <linux/bitops.h>
21 #include <linux/compat.h>
22 #include <linux/bitfield.h>
23 
24 DECLARE_GLOBAL_DATA_PTR;
25 
26 #define USB_R0							0x00
27 	#define USB_R0_P30_FSEL_MASK				GENMASK(5, 0)
28 	#define USB_R0_P30_PHY_RESET				BIT(6)
29 	#define USB_R0_P30_TEST_POWERDOWN_HSP			BIT(7)
30 	#define USB_R0_P30_TEST_POWERDOWN_SSP			BIT(8)
31 	#define USB_R0_P30_ACJT_LEVEL_MASK			GENMASK(13, 9)
32 	#define USB_R0_P30_TX_BOOST_LEVEL_MASK			GENMASK(16, 14)
33 	#define USB_R0_P30_LANE0_TX2RX_LOOPBACK			BIT(17)
34 	#define USB_R0_P30_LANE0_EXT_PCLK_REQ			BIT(18)
35 	#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK		GENMASK(28, 19)
36 	#define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK		GENMASK(30, 29)
37 	#define USB_R0_U2D_ACT					BIT(31)
38 
39 #define USB_R1							0x04
40 	#define USB_R1_U3H_BIGENDIAN_GS				BIT(0)
41 	#define USB_R1_U3H_PME_ENABLE				BIT(1)
42 	#define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK		GENMASK(6, 2)
43 	#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK		GENMASK(11, 7)
44 	#define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK		GENMASK(15, 12)
45 	#define USB_R1_U3H_HOST_U3_PORT_DISABLE			BIT(16)
46 	#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT	BIT(17)
47 	#define USB_R1_U3H_HOST_MSI_ENABLE			BIT(18)
48 	#define USB_R1_U3H_FLADJ_30MHZ_REG_MASK			GENMASK(24, 19)
49 	#define USB_R1_P30_PCS_TX_SWING_FULL_MASK		GENMASK(31, 25)
50 
51 #define USB_R2							0x08
52 	#define USB_R2_P30_CR_DATA_IN_MASK			GENMASK(15, 0)
53 	#define USB_R2_P30_CR_READ				BIT(16)
54 	#define USB_R2_P30_CR_WRITE				BIT(17)
55 	#define USB_R2_P30_CR_CAP_ADDR				BIT(18)
56 	#define USB_R2_P30_CR_CAP_DATA				BIT(19)
57 	#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK		GENMASK(25, 20)
58 	#define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK		GENMASK(31, 26)
59 
60 #define USB_R3							0x0c
61 	#define USB_R3_P30_SSC_ENABLE				BIT(0)
62 	#define USB_R3_P30_SSC_RANGE_MASK			GENMASK(3, 1)
63 	#define USB_R3_P30_SSC_REF_CLK_SEL_MASK			GENMASK(12, 4)
64 	#define USB_R3_P30_REF_SSP_EN				BIT(13)
65 	#define USB_R3_P30_LOS_BIAS_MASK			GENMASK(18, 16)
66 	#define USB_R3_P30_LOS_LEVEL_MASK			GENMASK(23, 19)
67 	#define USB_R3_P30_MPLL_MULTIPLIER_MASK			GENMASK(30, 24)
68 
69 #define USB_R4							0x10
70 	#define USB_R4_P21_PORT_RESET_0				BIT(0)
71 	#define USB_R4_P21_SLEEP_M0				BIT(1)
72 	#define USB_R4_MEM_PD_MASK				GENMASK(3, 2)
73 	#define USB_R4_P21_ONLY					BIT(4)
74 
75 #define USB_R5							0x14
76 	#define USB_R5_ID_DIG_SYNC				BIT(0)
77 	#define USB_R5_ID_DIG_REG				BIT(1)
78 	#define USB_R5_ID_DIG_CFG_MASK				GENMASK(3, 2)
79 	#define USB_R5_ID_DIG_EN_0				BIT(4)
80 	#define USB_R5_ID_DIG_EN_1				BIT(5)
81 	#define USB_R5_ID_DIG_CURR				BIT(6)
82 	#define USB_R5_ID_DIG_IRQ				BIT(7)
83 	#define USB_R5_ID_DIG_TH_MASK				GENMASK(15, 8)
84 	#define USB_R5_ID_DIG_CNT_MASK				GENMASK(23, 16)
85 
86 /* read-only register */
87 #define USB_R6							0x18
88 	#define USB_R6_P30_CR_DATA_OUT_MASK			GENMASK(15, 0)
89 	#define USB_R6_P30_CR_ACK				BIT(16)
90 
91 struct phy_meson_gxl_usb3_priv {
92 	struct regmap		*regmap;
93 #if CONFIG_IS_ENABLED(CLK)
94 	struct clk		clk;
95 #endif
96 };
97 
98 static int
99 phy_meson_gxl_usb3_set_host_mode(struct phy_meson_gxl_usb3_priv *priv)
100 {
101 	uint val;
102 
103 	regmap_read(priv->regmap, USB_R0, &val);
104 	val &= ~USB_R0_U2D_ACT;
105 	regmap_write(priv->regmap, USB_R0, val);
106 
107 	regmap_read(priv->regmap, USB_R4, &val);
108 	val &= ~USB_R4_P21_SLEEP_M0;
109 	regmap_write(priv->regmap, USB_R4, val);
110 
111 	return 0;
112 }
113 
114 static int phy_meson_gxl_usb3_power_on(struct phy *phy)
115 {
116 	struct udevice *dev = phy->dev;
117 	struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev);
118 	uint val;
119 
120 	regmap_read(priv->regmap, USB_R5, &val);
121 	val |= USB_R5_ID_DIG_EN_0;
122 	val |= USB_R5_ID_DIG_EN_1;
123 	val &= ~USB_R5_ID_DIG_TH_MASK;
124 	val |= FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff);
125 	regmap_write(priv->regmap, USB_R5, val);
126 
127 	return phy_meson_gxl_usb3_set_host_mode(priv);
128 }
129 
130 static int phy_meson_gxl_usb3_power_off(struct phy *phy)
131 {
132 	struct udevice *dev = phy->dev;
133 	struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev);
134 	uint val;
135 
136 	regmap_read(priv->regmap, USB_R5, &val);
137 	val &= ~USB_R5_ID_DIG_EN_0;
138 	val &= ~USB_R5_ID_DIG_EN_1;
139 	regmap_write(priv->regmap, USB_R5, val);
140 
141 	return 0;
142 }
143 
144 static int phy_meson_gxl_usb3_init(struct phy *phy)
145 {
146 	struct udevice *dev = phy->dev;
147 	struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev);
148 	uint val;
149 
150 	regmap_read(priv->regmap, USB_R1, &val);
151 	val &= ~USB_R1_U3H_FLADJ_30MHZ_REG_MASK;
152 	val |= FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20);
153 	regmap_write(priv->regmap, USB_R1, val);
154 
155 	return 0;
156 }
157 
158 struct phy_ops meson_gxl_usb3_phy_ops = {
159 	.init = phy_meson_gxl_usb3_init,
160 	.power_on = phy_meson_gxl_usb3_power_on,
161 	.power_off = phy_meson_gxl_usb3_power_off,
162 };
163 
164 int meson_gxl_usb3_phy_probe(struct udevice *dev)
165 {
166 	struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev);
167 	int ret;
168 
169 	ret = regmap_init_mem(dev, &priv->regmap);
170 	if (ret)
171 		return ret;
172 
173 #if CONFIG_IS_ENABLED(CLK)
174 	ret = clk_get_by_index(dev, 0, &priv->clk);
175 	if (ret < 0)
176 		return ret;
177 
178 	ret = clk_enable(&priv->clk);
179 	if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
180 		pr_err("failed to enable PHY clock\n");
181 		clk_free(&priv->clk);
182 		return ret;
183 	}
184 #endif
185 
186 	return 0;
187 }
188 
189 static const struct udevice_id meson_gxl_usb3_phy_ids[] = {
190 	{ .compatible = "amlogic,meson-gxl-usb3-phy" },
191 	{ }
192 };
193 
194 U_BOOT_DRIVER(meson_gxl_usb3_phy) = {
195 	.name = "meson_gxl_usb3_phy",
196 	.id = UCLASS_PHY,
197 	.of_match = meson_gxl_usb3_phy_ids,
198 	.probe = meson_gxl_usb3_phy_probe,
199 	.ops = &meson_gxl_usb3_phy_ops,
200 	.priv_auto_alloc_size = sizeof(struct phy_meson_gxl_usb3_priv),
201 };
202