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