xref: /openbmc/u-boot/drivers/phy/sti_usb_phy.c (revision 8c1de5e08b845eb71c9a247d16bc81ebdab0598d)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2b7ca56dcSPatrice Chotard /*
3fb48bc44SPatrice Chotard  * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
4fb48bc44SPatrice Chotard  * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
5b7ca56dcSPatrice Chotard  */
6b7ca56dcSPatrice Chotard 
7b7ca56dcSPatrice Chotard #include <common.h>
8b7ca56dcSPatrice Chotard #include <asm/io.h>
9b7ca56dcSPatrice Chotard #include <bitfield.h>
10b7ca56dcSPatrice Chotard #include <dm.h>
11b7ca56dcSPatrice Chotard #include <errno.h>
12b7ca56dcSPatrice Chotard #include <fdtdec.h>
13b7ca56dcSPatrice Chotard #include <generic-phy.h>
14b08c8c48SMasahiro Yamada #include <linux/libfdt.h>
15b7ca56dcSPatrice Chotard #include <regmap.h>
16b7ca56dcSPatrice Chotard #include <reset-uclass.h>
17b7ca56dcSPatrice Chotard #include <syscon.h>
18b7ca56dcSPatrice Chotard #include <wait_bit.h>
19b7ca56dcSPatrice Chotard 
20b7ca56dcSPatrice Chotard #include <linux/bitops.h>
21b7ca56dcSPatrice Chotard #include <linux/compat.h>
22b7ca56dcSPatrice Chotard 
23b7ca56dcSPatrice Chotard DECLARE_GLOBAL_DATA_PTR;
24b7ca56dcSPatrice Chotard 
25b7ca56dcSPatrice Chotard /* Default PHY_SEL and REFCLKSEL configuration */
26b7ca56dcSPatrice Chotard #define STIH407_USB_PICOPHY_CTRL_PORT_CONF	0x6
27b7ca56dcSPatrice Chotard 
28b7ca56dcSPatrice Chotard /* ports parameters overriding */
29b7ca56dcSPatrice Chotard #define STIH407_USB_PICOPHY_PARAM_DEF		0x39a4dc
30b7ca56dcSPatrice Chotard 
31b7ca56dcSPatrice Chotard #define PHYPARAM_REG	1
32b7ca56dcSPatrice Chotard #define PHYCTRL_REG	2
33b7ca56dcSPatrice Chotard #define PHYPARAM_NB	3
34b7ca56dcSPatrice Chotard 
35b7ca56dcSPatrice Chotard struct sti_usb_phy {
36b7ca56dcSPatrice Chotard 	struct regmap *regmap;
37b7ca56dcSPatrice Chotard 	struct reset_ctl global_ctl;
38b7ca56dcSPatrice Chotard 	struct reset_ctl port_ctl;
39b7ca56dcSPatrice Chotard 	int param;
40b7ca56dcSPatrice Chotard 	int ctrl;
41b7ca56dcSPatrice Chotard };
42b7ca56dcSPatrice Chotard 
sti_usb_phy_deassert(struct sti_usb_phy * phy)43b7ca56dcSPatrice Chotard static int sti_usb_phy_deassert(struct sti_usb_phy *phy)
44b7ca56dcSPatrice Chotard {
45b7ca56dcSPatrice Chotard 	int ret;
46b7ca56dcSPatrice Chotard 
47b7ca56dcSPatrice Chotard 	ret = reset_deassert(&phy->global_ctl);
48b7ca56dcSPatrice Chotard 	if (ret < 0) {
499b643e31SMasahiro Yamada 		pr_err("PHY global deassert failed: %d", ret);
50b7ca56dcSPatrice Chotard 		return ret;
51b7ca56dcSPatrice Chotard 	}
52b7ca56dcSPatrice Chotard 
53b7ca56dcSPatrice Chotard 	ret = reset_deassert(&phy->port_ctl);
54b7ca56dcSPatrice Chotard 	if (ret < 0)
559b643e31SMasahiro Yamada 		pr_err("PHY port deassert failed: %d", ret);
56b7ca56dcSPatrice Chotard 
57b7ca56dcSPatrice Chotard 	return ret;
58b7ca56dcSPatrice Chotard }
59b7ca56dcSPatrice Chotard 
sti_usb_phy_init(struct phy * usb_phy)60b7ca56dcSPatrice Chotard static int sti_usb_phy_init(struct phy *usb_phy)
61b7ca56dcSPatrice Chotard {
62b7ca56dcSPatrice Chotard 	struct udevice *dev = usb_phy->dev;
63b7ca56dcSPatrice Chotard 	struct sti_usb_phy *phy = dev_get_priv(dev);
64b7ca56dcSPatrice Chotard 	void __iomem *reg;
65b7ca56dcSPatrice Chotard 
66b7ca56dcSPatrice Chotard 	/* set ctrl picophy value */
67*8c1de5e0SMasahiro Yamada 	reg = (void __iomem *)phy->regmap->ranges[0].start + phy->ctrl;
68b7ca56dcSPatrice Chotard 	/* CTRL_PORT mask is 0x1f */
69b7ca56dcSPatrice Chotard 	clrsetbits_le32(reg, 0x1f, STIH407_USB_PICOPHY_CTRL_PORT_CONF);
70b7ca56dcSPatrice Chotard 
71b7ca56dcSPatrice Chotard 	/* set ports parameters overriding */
72*8c1de5e0SMasahiro Yamada 	reg = (void __iomem *)phy->regmap->ranges[0].start + phy->param;
73b7ca56dcSPatrice Chotard 	/* PARAM_DEF mask is 0xffffffff */
74b7ca56dcSPatrice Chotard 	clrsetbits_le32(reg, 0xffffffff, STIH407_USB_PICOPHY_PARAM_DEF);
75b7ca56dcSPatrice Chotard 
76b7ca56dcSPatrice Chotard 	return sti_usb_phy_deassert(phy);
77b7ca56dcSPatrice Chotard }
78b7ca56dcSPatrice Chotard 
sti_usb_phy_exit(struct phy * usb_phy)79b7ca56dcSPatrice Chotard static int sti_usb_phy_exit(struct phy *usb_phy)
80b7ca56dcSPatrice Chotard {
81b7ca56dcSPatrice Chotard 	struct udevice *dev = usb_phy->dev;
82b7ca56dcSPatrice Chotard 	struct sti_usb_phy *phy = dev_get_priv(dev);
83b7ca56dcSPatrice Chotard 	int ret;
84b7ca56dcSPatrice Chotard 
85b7ca56dcSPatrice Chotard 	ret = reset_assert(&phy->port_ctl);
86b7ca56dcSPatrice Chotard 	if (ret < 0) {
879b643e31SMasahiro Yamada 		pr_err("PHY port assert failed: %d", ret);
88b7ca56dcSPatrice Chotard 		return ret;
89b7ca56dcSPatrice Chotard 	}
90b7ca56dcSPatrice Chotard 
91b7ca56dcSPatrice Chotard 	ret = reset_assert(&phy->global_ctl);
92b7ca56dcSPatrice Chotard 	if (ret < 0)
939b643e31SMasahiro Yamada 		pr_err("PHY global assert failed: %d", ret);
94b7ca56dcSPatrice Chotard 
95b7ca56dcSPatrice Chotard 	return ret;
96b7ca56dcSPatrice Chotard }
97b7ca56dcSPatrice Chotard 
98b7ca56dcSPatrice Chotard struct phy_ops sti_usb_phy_ops = {
99b7ca56dcSPatrice Chotard 	.init = sti_usb_phy_init,
100b7ca56dcSPatrice Chotard 	.exit = sti_usb_phy_exit,
101b7ca56dcSPatrice Chotard };
102b7ca56dcSPatrice Chotard 
sti_usb_phy_probe(struct udevice * dev)103b7ca56dcSPatrice Chotard int sti_usb_phy_probe(struct udevice *dev)
104b7ca56dcSPatrice Chotard {
105b7ca56dcSPatrice Chotard 	struct sti_usb_phy *priv = dev_get_priv(dev);
106b7ca56dcSPatrice Chotard 	struct udevice *syscon;
107b7ca56dcSPatrice Chotard 	struct ofnode_phandle_args syscfg_phandle;
108b7ca56dcSPatrice Chotard 	u32 cells[PHYPARAM_NB];
109b7ca56dcSPatrice Chotard 	int ret, count;
110b7ca56dcSPatrice Chotard 
111b7ca56dcSPatrice Chotard 	/* get corresponding syscon phandle */
112b7ca56dcSPatrice Chotard 	ret = dev_read_phandle_with_args(dev, "st,syscfg", NULL, 0, 0,
113b7ca56dcSPatrice Chotard 					 &syscfg_phandle);
114b7ca56dcSPatrice Chotard 
115b7ca56dcSPatrice Chotard 	if (ret < 0) {
1169b643e31SMasahiro Yamada 		pr_err("Can't get syscfg phandle: %d\n", ret);
117b7ca56dcSPatrice Chotard 		return ret;
118b7ca56dcSPatrice Chotard 	}
119b7ca56dcSPatrice Chotard 
120b7ca56dcSPatrice Chotard 	ret = uclass_get_device_by_ofnode(UCLASS_SYSCON, syscfg_phandle.node,
121b7ca56dcSPatrice Chotard 					  &syscon);
122b7ca56dcSPatrice Chotard 	if (ret) {
1239b643e31SMasahiro Yamada 		pr_err("unable to find syscon device (%d)\n", ret);
124b7ca56dcSPatrice Chotard 		return ret;
125b7ca56dcSPatrice Chotard 	}
126b7ca56dcSPatrice Chotard 
127b7ca56dcSPatrice Chotard 	priv->regmap = syscon_get_regmap(syscon);
128b7ca56dcSPatrice Chotard 	if (!priv->regmap) {
1299b643e31SMasahiro Yamada 		pr_err("unable to find regmap\n");
130b7ca56dcSPatrice Chotard 		return -ENODEV;
131b7ca56dcSPatrice Chotard 	}
132b7ca56dcSPatrice Chotard 
133b7ca56dcSPatrice Chotard 	/* get phy param offset */
134b7ca56dcSPatrice Chotard 	count = fdtdec_get_int_array_count(gd->fdt_blob, dev_of_offset(dev),
135b7ca56dcSPatrice Chotard 					   "st,syscfg", cells,
136b7ca56dcSPatrice Chotard 					   ARRAY_SIZE(cells));
137b7ca56dcSPatrice Chotard 
138b7ca56dcSPatrice Chotard 	if (count < 0) {
1399b643e31SMasahiro Yamada 		pr_err("Bad PHY st,syscfg property %d\n", count);
140b7ca56dcSPatrice Chotard 		return -EINVAL;
141b7ca56dcSPatrice Chotard 	}
142b7ca56dcSPatrice Chotard 
143b7ca56dcSPatrice Chotard 	if (count > PHYPARAM_NB) {
1449b643e31SMasahiro Yamada 		pr_err("Unsupported PHY param count %d\n", count);
145b7ca56dcSPatrice Chotard 		return -EINVAL;
146b7ca56dcSPatrice Chotard 	}
147b7ca56dcSPatrice Chotard 
148b7ca56dcSPatrice Chotard 	priv->param = cells[PHYPARAM_REG];
149b7ca56dcSPatrice Chotard 	priv->ctrl = cells[PHYCTRL_REG];
150b7ca56dcSPatrice Chotard 
151b7ca56dcSPatrice Chotard 	/* get global reset control */
152b7ca56dcSPatrice Chotard 	ret = reset_get_by_name(dev, "global", &priv->global_ctl);
153b7ca56dcSPatrice Chotard 	if (ret) {
1549b643e31SMasahiro Yamada 		pr_err("can't get global reset for %s (%d)", dev->name, ret);
155b7ca56dcSPatrice Chotard 		return ret;
156b7ca56dcSPatrice Chotard 	}
157b7ca56dcSPatrice Chotard 
158b7ca56dcSPatrice Chotard 	/* get port reset control */
159b7ca56dcSPatrice Chotard 	ret = reset_get_by_name(dev, "port", &priv->port_ctl);
160b7ca56dcSPatrice Chotard 	if (ret) {
1619b643e31SMasahiro Yamada 		pr_err("can't get port reset for %s (%d)", dev->name, ret);
162b7ca56dcSPatrice Chotard 		return ret;
163b7ca56dcSPatrice Chotard 	}
164b7ca56dcSPatrice Chotard 
165b7ca56dcSPatrice Chotard 	return 0;
166b7ca56dcSPatrice Chotard }
167b7ca56dcSPatrice Chotard 
168b7ca56dcSPatrice Chotard static const struct udevice_id sti_usb_phy_ids[] = {
169b7ca56dcSPatrice Chotard 	{ .compatible = "st,stih407-usb2-phy" },
170b7ca56dcSPatrice Chotard 	{ }
171b7ca56dcSPatrice Chotard };
172b7ca56dcSPatrice Chotard 
173b7ca56dcSPatrice Chotard U_BOOT_DRIVER(sti_usb_phy) = {
174b7ca56dcSPatrice Chotard 	.name = "sti_usb_phy",
175b7ca56dcSPatrice Chotard 	.id = UCLASS_PHY,
176b7ca56dcSPatrice Chotard 	.of_match = sti_usb_phy_ids,
177b7ca56dcSPatrice Chotard 	.probe = sti_usb_phy_probe,
178b7ca56dcSPatrice Chotard 	.ops = &sti_usb_phy_ops,
179b7ca56dcSPatrice Chotard 	.priv_auto_alloc_size = sizeof(struct sti_usb_phy),
180b7ca56dcSPatrice Chotard };
181