blob: 9e5ac9bfde67315533e29e71c3e6f3bd35bc8dac [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Patrice Chotard6b336512017-09-05 11:04:21 +02002/*
Patrice Chotard9e216242017-10-23 09:53:57 +02003 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
Patrice Chotard5d9950d2020-12-02 18:47:30 +01004 * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics.
Patrice Chotard6b336512017-09-05 11:04:21 +02005 */
6
7#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06009#include <asm/global_data.h>
Patrice Chotard6b336512017-09-05 11:04:21 +020010#include <asm/io.h>
11#include <bitfield.h>
12#include <dm.h>
13#include <errno.h>
14#include <fdtdec.h>
15#include <generic-phy.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090016#include <linux/libfdt.h>
Patrice Chotard6b336512017-09-05 11:04:21 +020017#include <regmap.h>
18#include <reset-uclass.h>
19#include <syscon.h>
20#include <wait_bit.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060021#include <linux/printk.h>
Patrice Chotard6b336512017-09-05 11:04:21 +020022
23#include <linux/bitops.h>
24#include <linux/compat.h>
25
26DECLARE_GLOBAL_DATA_PTR;
27
28/* Default PHY_SEL and REFCLKSEL configuration */
29#define STIH407_USB_PICOPHY_CTRL_PORT_CONF 0x6
30
31/* ports parameters overriding */
32#define STIH407_USB_PICOPHY_PARAM_DEF 0x39a4dc
33
34#define PHYPARAM_REG 1
35#define PHYCTRL_REG 2
36#define PHYPARAM_NB 3
37
38struct sti_usb_phy {
39 struct regmap *regmap;
40 struct reset_ctl global_ctl;
41 struct reset_ctl port_ctl;
42 int param;
43 int ctrl;
44};
45
46static int sti_usb_phy_deassert(struct sti_usb_phy *phy)
47{
48 int ret;
49
50 ret = reset_deassert(&phy->global_ctl);
51 if (ret < 0) {
Masahiro Yamada81e10422017-09-16 14:10:41 +090052 pr_err("PHY global deassert failed: %d", ret);
Patrice Chotard6b336512017-09-05 11:04:21 +020053 return ret;
54 }
55
56 ret = reset_deassert(&phy->port_ctl);
57 if (ret < 0)
Masahiro Yamada81e10422017-09-16 14:10:41 +090058 pr_err("PHY port deassert failed: %d", ret);
Patrice Chotard6b336512017-09-05 11:04:21 +020059
60 return ret;
61}
62
63static int sti_usb_phy_init(struct phy *usb_phy)
64{
65 struct udevice *dev = usb_phy->dev;
66 struct sti_usb_phy *phy = dev_get_priv(dev);
67 void __iomem *reg;
68
69 /* set ctrl picophy value */
Masahiro Yamada54c5ecb2018-04-19 12:14:01 +090070 reg = (void __iomem *)phy->regmap->ranges[0].start + phy->ctrl;
Patrice Chotard6b336512017-09-05 11:04:21 +020071 /* CTRL_PORT mask is 0x1f */
72 clrsetbits_le32(reg, 0x1f, STIH407_USB_PICOPHY_CTRL_PORT_CONF);
73
74 /* set ports parameters overriding */
Masahiro Yamada54c5ecb2018-04-19 12:14:01 +090075 reg = (void __iomem *)phy->regmap->ranges[0].start + phy->param;
Patrice Chotard6b336512017-09-05 11:04:21 +020076 /* PARAM_DEF mask is 0xffffffff */
77 clrsetbits_le32(reg, 0xffffffff, STIH407_USB_PICOPHY_PARAM_DEF);
78
79 return sti_usb_phy_deassert(phy);
80}
81
82static int sti_usb_phy_exit(struct phy *usb_phy)
83{
84 struct udevice *dev = usb_phy->dev;
85 struct sti_usb_phy *phy = dev_get_priv(dev);
86 int ret;
87
88 ret = reset_assert(&phy->port_ctl);
89 if (ret < 0) {
Masahiro Yamada81e10422017-09-16 14:10:41 +090090 pr_err("PHY port assert failed: %d", ret);
Patrice Chotard6b336512017-09-05 11:04:21 +020091 return ret;
92 }
93
94 ret = reset_assert(&phy->global_ctl);
95 if (ret < 0)
Masahiro Yamada81e10422017-09-16 14:10:41 +090096 pr_err("PHY global assert failed: %d", ret);
Patrice Chotard6b336512017-09-05 11:04:21 +020097
98 return ret;
99}
100
101struct phy_ops sti_usb_phy_ops = {
102 .init = sti_usb_phy_init,
103 .exit = sti_usb_phy_exit,
104};
105
106int sti_usb_phy_probe(struct udevice *dev)
107{
108 struct sti_usb_phy *priv = dev_get_priv(dev);
109 struct udevice *syscon;
110 struct ofnode_phandle_args syscfg_phandle;
111 u32 cells[PHYPARAM_NB];
112 int ret, count;
113
114 /* get corresponding syscon phandle */
115 ret = dev_read_phandle_with_args(dev, "st,syscfg", NULL, 0, 0,
116 &syscfg_phandle);
117
118 if (ret < 0) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900119 pr_err("Can't get syscfg phandle: %d\n", ret);
Patrice Chotard6b336512017-09-05 11:04:21 +0200120 return ret;
121 }
122
123 ret = uclass_get_device_by_ofnode(UCLASS_SYSCON, syscfg_phandle.node,
124 &syscon);
125 if (ret) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900126 pr_err("unable to find syscon device (%d)\n", ret);
Patrice Chotard6b336512017-09-05 11:04:21 +0200127 return ret;
128 }
129
130 priv->regmap = syscon_get_regmap(syscon);
131 if (!priv->regmap) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900132 pr_err("unable to find regmap\n");
Patrice Chotard6b336512017-09-05 11:04:21 +0200133 return -ENODEV;
134 }
135
136 /* get phy param offset */
137 count = fdtdec_get_int_array_count(gd->fdt_blob, dev_of_offset(dev),
138 "st,syscfg", cells,
139 ARRAY_SIZE(cells));
140
141 if (count < 0) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900142 pr_err("Bad PHY st,syscfg property %d\n", count);
Patrice Chotard6b336512017-09-05 11:04:21 +0200143 return -EINVAL;
144 }
145
146 if (count > PHYPARAM_NB) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900147 pr_err("Unsupported PHY param count %d\n", count);
Patrice Chotard6b336512017-09-05 11:04:21 +0200148 return -EINVAL;
149 }
150
151 priv->param = cells[PHYPARAM_REG];
152 priv->ctrl = cells[PHYCTRL_REG];
153
154 /* get global reset control */
155 ret = reset_get_by_name(dev, "global", &priv->global_ctl);
156 if (ret) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900157 pr_err("can't get global reset for %s (%d)", dev->name, ret);
Patrice Chotard6b336512017-09-05 11:04:21 +0200158 return ret;
159 }
160
161 /* get port reset control */
162 ret = reset_get_by_name(dev, "port", &priv->port_ctl);
163 if (ret) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900164 pr_err("can't get port reset for %s (%d)", dev->name, ret);
Patrice Chotard6b336512017-09-05 11:04:21 +0200165 return ret;
166 }
167
168 return 0;
169}
170
171static const struct udevice_id sti_usb_phy_ids[] = {
172 { .compatible = "st,stih407-usb2-phy" },
173 { }
174};
175
176U_BOOT_DRIVER(sti_usb_phy) = {
177 .name = "sti_usb_phy",
178 .id = UCLASS_PHY,
179 .of_match = sti_usb_phy_ids,
180 .probe = sti_usb_phy_probe,
181 .ops = &sti_usb_phy_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700182 .priv_auto = sizeof(struct sti_usb_phy),
Patrice Chotard6b336512017-09-05 11:04:21 +0200183};