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