1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2016-2018 Broadcom
4  */
5 
6 #include <linux/delay.h>
7 #include <linux/io.h>
8 #include <linux/module.h>
9 #include <linux/of.h>
10 #include <linux/phy/phy.h>
11 #include <linux/platform_device.h>
12 
13 enum bcm_usb_phy_version {
14 	BCM_SR_USB_COMBO_PHY,
15 	BCM_SR_USB_HS_PHY,
16 };
17 
18 enum bcm_usb_phy_reg {
19 	PLL_CTRL,
20 	PHY_CTRL,
21 	PHY_PLL_CTRL,
22 };
23 
24 /* USB PHY registers */
25 
26 static const u8 bcm_usb_combo_phy_ss[] = {
27 	[PLL_CTRL]		= 0x18,
28 	[PHY_CTRL]		= 0x14,
29 };
30 
31 static const u8 bcm_usb_combo_phy_hs[] = {
32 	[PLL_CTRL]	= 0x0c,
33 	[PHY_CTRL]	= 0x10,
34 };
35 
36 static const u8 bcm_usb_hs_phy[] = {
37 	[PLL_CTRL]	= 0x8,
38 	[PHY_CTRL]	= 0xc,
39 };
40 
41 enum pll_ctrl_bits {
42 	PLL_RESETB,
43 	SSPLL_SUSPEND_EN,
44 	PLL_SEQ_START,
45 	PLL_LOCK,
46 };
47 
48 static const u8 u3pll_ctrl[] = {
49 	[PLL_RESETB]		= 0,
50 	[SSPLL_SUSPEND_EN]	= 1,
51 	[PLL_SEQ_START]		= 2,
52 	[PLL_LOCK]		= 3,
53 };
54 
55 #define HSPLL_PDIV_MASK		0xF
56 #define HSPLL_PDIV_VAL		0x1
57 
58 static const u8 u2pll_ctrl[] = {
59 	[PLL_RESETB]	= 5,
60 	[PLL_LOCK]	= 6,
61 };
62 
63 enum bcm_usb_phy_ctrl_bits {
64 	CORERDY,
65 	PHY_RESETB,
66 	PHY_PCTL,
67 };
68 
69 #define PHY_PCTL_MASK	0xffff
70 #define SSPHY_PCTL_VAL	0x0006
71 
72 static const u8 u3phy_ctrl[] = {
73 	[PHY_RESETB]	= 1,
74 	[PHY_PCTL]	= 2,
75 };
76 
77 static const u8 u2phy_ctrl[] = {
78 	[CORERDY]		= 0,
79 	[PHY_RESETB]		= 5,
80 	[PHY_PCTL]		= 6,
81 };
82 
83 struct bcm_usb_phy_cfg {
84 	uint32_t type;
85 	uint32_t version;
86 	void __iomem *regs;
87 	struct phy *phy;
88 	const u8 *offset;
89 };
90 
91 #define PLL_LOCK_RETRY_COUNT	1000
92 
93 enum bcm_usb_phy_type {
94 	USB_HS_PHY,
95 	USB_SS_PHY,
96 };
97 
98 #define NUM_BCM_SR_USB_COMBO_PHYS	2
99 
100 static inline void bcm_usb_reg32_clrbits(void __iomem *addr, uint32_t clear)
101 {
102 	writel(readl(addr) & ~clear, addr);
103 }
104 
105 static inline void bcm_usb_reg32_setbits(void __iomem *addr, uint32_t set)
106 {
107 	writel(readl(addr) | set, addr);
108 }
109 
110 static int bcm_usb_pll_lock_check(void __iomem *addr, u32 bit)
111 {
112 	int retry;
113 	u32 rd_data;
114 
115 	retry = PLL_LOCK_RETRY_COUNT;
116 	do {
117 		rd_data = readl(addr);
118 		if (rd_data & bit)
119 			return 0;
120 		udelay(1);
121 	} while (--retry > 0);
122 
123 	pr_err("%s: FAIL\n", __func__);
124 	return -ETIMEDOUT;
125 }
126 
127 static int bcm_usb_ss_phy_init(struct bcm_usb_phy_cfg *phy_cfg)
128 {
129 	int ret = 0;
130 	void __iomem *regs = phy_cfg->regs;
131 	const u8 *offset;
132 	u32 rd_data;
133 
134 	offset = phy_cfg->offset;
135 
136 	/* Set pctl with mode and soft reset */
137 	rd_data = readl(regs + offset[PHY_CTRL]);
138 	rd_data &= ~(PHY_PCTL_MASK << u3phy_ctrl[PHY_PCTL]);
139 	rd_data |= (SSPHY_PCTL_VAL << u3phy_ctrl[PHY_PCTL]);
140 	writel(rd_data, regs + offset[PHY_CTRL]);
141 
142 	bcm_usb_reg32_clrbits(regs + offset[PLL_CTRL],
143 			      BIT(u3pll_ctrl[SSPLL_SUSPEND_EN]));
144 	bcm_usb_reg32_setbits(regs + offset[PLL_CTRL],
145 			      BIT(u3pll_ctrl[PLL_SEQ_START]));
146 	bcm_usb_reg32_setbits(regs + offset[PLL_CTRL],
147 			      BIT(u3pll_ctrl[PLL_RESETB]));
148 
149 	/* Maximum timeout for PLL reset done */
150 	msleep(30);
151 
152 	ret = bcm_usb_pll_lock_check(regs + offset[PLL_CTRL],
153 				     BIT(u3pll_ctrl[PLL_LOCK]));
154 
155 	return ret;
156 }
157 
158 static int bcm_usb_hs_phy_init(struct bcm_usb_phy_cfg *phy_cfg)
159 {
160 	int ret = 0;
161 	void __iomem *regs = phy_cfg->regs;
162 	const u8 *offset;
163 
164 	offset = phy_cfg->offset;
165 
166 	bcm_usb_reg32_clrbits(regs + offset[PLL_CTRL],
167 			      BIT(u2pll_ctrl[PLL_RESETB]));
168 	bcm_usb_reg32_setbits(regs + offset[PLL_CTRL],
169 			      BIT(u2pll_ctrl[PLL_RESETB]));
170 
171 	ret = bcm_usb_pll_lock_check(regs + offset[PLL_CTRL],
172 				     BIT(u2pll_ctrl[PLL_LOCK]));
173 
174 	return ret;
175 }
176 
177 static int bcm_usb_phy_reset(struct phy *phy)
178 {
179 	struct bcm_usb_phy_cfg *phy_cfg = phy_get_drvdata(phy);
180 	void __iomem *regs = phy_cfg->regs;
181 	const u8 *offset;
182 
183 	offset = phy_cfg->offset;
184 
185 	if (phy_cfg->type == USB_HS_PHY) {
186 		bcm_usb_reg32_clrbits(regs + offset[PHY_CTRL],
187 				      BIT(u2phy_ctrl[CORERDY]));
188 		bcm_usb_reg32_setbits(regs + offset[PHY_CTRL],
189 				      BIT(u2phy_ctrl[CORERDY]));
190 	}
191 
192 	return 0;
193 }
194 
195 static int bcm_usb_phy_init(struct phy *phy)
196 {
197 	struct bcm_usb_phy_cfg *phy_cfg = phy_get_drvdata(phy);
198 	int ret = -EINVAL;
199 
200 	if (phy_cfg->type == USB_SS_PHY)
201 		ret = bcm_usb_ss_phy_init(phy_cfg);
202 	else if (phy_cfg->type == USB_HS_PHY)
203 		ret = bcm_usb_hs_phy_init(phy_cfg);
204 
205 	return ret;
206 }
207 
208 static const struct phy_ops sr_phy_ops = {
209 	.init		= bcm_usb_phy_init,
210 	.reset		= bcm_usb_phy_reset,
211 	.owner		= THIS_MODULE,
212 };
213 
214 static struct phy *bcm_usb_phy_xlate(struct device *dev,
215 				     struct of_phandle_args *args)
216 {
217 	struct bcm_usb_phy_cfg *phy_cfg;
218 	int phy_idx;
219 
220 	phy_cfg = dev_get_drvdata(dev);
221 	if (!phy_cfg)
222 		return ERR_PTR(-EINVAL);
223 
224 	if (phy_cfg->version == BCM_SR_USB_COMBO_PHY) {
225 		phy_idx = args->args[0];
226 
227 		if (WARN_ON(phy_idx > 1))
228 			return ERR_PTR(-ENODEV);
229 
230 		return phy_cfg[phy_idx].phy;
231 	} else
232 		return phy_cfg->phy;
233 }
234 
235 static int bcm_usb_phy_create(struct device *dev, struct device_node *node,
236 			      void __iomem *regs, uint32_t version)
237 {
238 	struct bcm_usb_phy_cfg *phy_cfg;
239 	int idx;
240 
241 	if (version == BCM_SR_USB_COMBO_PHY) {
242 		phy_cfg = devm_kzalloc(dev, NUM_BCM_SR_USB_COMBO_PHYS *
243 				       sizeof(struct bcm_usb_phy_cfg),
244 				       GFP_KERNEL);
245 		if (!phy_cfg)
246 			return -ENOMEM;
247 
248 		for (idx = 0; idx < NUM_BCM_SR_USB_COMBO_PHYS; idx++) {
249 			phy_cfg[idx].regs = regs;
250 			phy_cfg[idx].version = version;
251 			if (idx == 0) {
252 				phy_cfg[idx].offset = bcm_usb_combo_phy_hs;
253 				phy_cfg[idx].type = USB_HS_PHY;
254 			} else {
255 				phy_cfg[idx].offset = bcm_usb_combo_phy_ss;
256 				phy_cfg[idx].type = USB_SS_PHY;
257 			}
258 			phy_cfg[idx].phy = devm_phy_create(dev, node,
259 							   &sr_phy_ops);
260 			if (IS_ERR(phy_cfg[idx].phy))
261 				return PTR_ERR(phy_cfg[idx].phy);
262 
263 			phy_set_drvdata(phy_cfg[idx].phy, &phy_cfg[idx]);
264 		}
265 	} else if (version == BCM_SR_USB_HS_PHY) {
266 		phy_cfg = devm_kzalloc(dev, sizeof(struct bcm_usb_phy_cfg),
267 				       GFP_KERNEL);
268 		if (!phy_cfg)
269 			return -ENOMEM;
270 
271 		phy_cfg->regs = regs;
272 		phy_cfg->version = version;
273 		phy_cfg->offset = bcm_usb_hs_phy;
274 		phy_cfg->type = USB_HS_PHY;
275 		phy_cfg->phy = devm_phy_create(dev, node, &sr_phy_ops);
276 		if (IS_ERR(phy_cfg->phy))
277 			return PTR_ERR(phy_cfg->phy);
278 
279 		phy_set_drvdata(phy_cfg->phy, phy_cfg);
280 	} else
281 		return -ENODEV;
282 
283 	dev_set_drvdata(dev, phy_cfg);
284 
285 	return 0;
286 }
287 
288 static const struct of_device_id bcm_usb_phy_of_match[] = {
289 	{
290 		.compatible = "brcm,sr-usb-combo-phy",
291 		.data = (void *)BCM_SR_USB_COMBO_PHY,
292 	},
293 	{
294 		.compatible = "brcm,sr-usb-hs-phy",
295 		.data = (void *)BCM_SR_USB_HS_PHY,
296 	},
297 	{ /* sentinel */ },
298 };
299 MODULE_DEVICE_TABLE(of, bcm_usb_phy_of_match);
300 
301 static int bcm_usb_phy_probe(struct platform_device *pdev)
302 {
303 	struct device *dev = &pdev->dev;
304 	struct device_node *dn = dev->of_node;
305 	const struct of_device_id *of_id;
306 	struct resource *res;
307 	void __iomem *regs;
308 	int ret;
309 	enum bcm_usb_phy_version version;
310 	struct phy_provider *phy_provider;
311 
312 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
313 	regs = devm_ioremap_resource(dev, res);
314 	if (IS_ERR(regs))
315 		return PTR_ERR(regs);
316 
317 	of_id = of_match_node(bcm_usb_phy_of_match, dn);
318 	if (of_id)
319 		version = (enum bcm_usb_phy_version)of_id->data;
320 	else
321 		return -ENODEV;
322 
323 	ret = bcm_usb_phy_create(dev, dn, regs, version);
324 	if (ret)
325 		return ret;
326 
327 	phy_provider = devm_of_phy_provider_register(dev, bcm_usb_phy_xlate);
328 
329 	return PTR_ERR_OR_ZERO(phy_provider);
330 }
331 
332 static struct platform_driver bcm_usb_phy_driver = {
333 	.driver = {
334 		.name = "phy-bcm-sr-usb",
335 		.of_match_table = bcm_usb_phy_of_match,
336 	},
337 	.probe = bcm_usb_phy_probe,
338 };
339 module_platform_driver(bcm_usb_phy_driver);
340 
341 MODULE_AUTHOR("Broadcom");
342 MODULE_DESCRIPTION("Broadcom stingray USB Phy driver");
343 MODULE_LICENSE("GPL v2");
344