blob: 24eba6655435c763808f5271d92c9dc0d3983155 [file] [log] [blame]
Jim Liu9a215e82022-06-21 17:03:38 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2021 Nuvoton Technology Corp.
4 */
5
6#include <common.h>
7#include <dm.h>
8#include <generic-phy.h>
9#include <regmap.h>
10#include <reset.h>
11#include <syscon.h>
12#include <dm/device_compat.h>
13#include <linux/bitfield.h>
14#include <linux/delay.h>
15
16/* GCR Register Offsets */
17#define GCR_INTCR3 0x9C
18#define GCR_USB1PHYCTL 0x140
19#define GCR_USB2PHYCTL 0x144
20#define GCR_USB3PHYCTL 0x148
21
22/* USBnPHYCTL bit fields */
23#define PHYCTL_RS BIT(28)
24
25#define USBPHY2SW GENMASK(13, 12)
26#define USBPHY3SW GENMASK(15, 14)
27
28#define USBPHY2SW_DEV9_PHY1 FIELD_PREP(USBPHY2SW, 0)
29#define USBPHY2SW_HOST1 FIELD_PREP(USBPHY2SW, 1)
30#define USBPHY2SW_DEV9_PHY2 FIELD_PREP(USBPHY2SW, 3)
31#define USBPHY3SW_DEV8_PHY1 FIELD_PREP(USBPHY3SW, 0)
32#define USBPHY3SW_HOST2 FIELD_PREP(USBPHY3SW, 1)
33#define USBPHY3SW_DEV8_PHY3 FIELD_PREP(USBPHY3SW, 3)
34
35enum controller_id {
36 UDC0_7,
37 UDC8,
38 UDC9,
39 USBH1,
40 USBH2,
41};
42
43enum phy_id {
44 PHY1 = 1,
45 PHY2,
46 PHY3,
47};
48
49/* Phy Switch Settings */
50#define USBDPHY1 ((PHY1 << 8) | UDC0_7) /* Connect UDC0~7 to PHY1 */
51#define USBD8PHY1 ((PHY1 << 8) | UDC8) /* Connect UDC8 to PHY1 */
52#define USBD9PHY1 ((PHY1 << 8) | UDC9) /* Connect UDC9 to PHY1 */
53#define USBD9PHY2 ((PHY2 << 8) | UDC9) /* Connect UDC9 to PHY2 */
54#define USBH1PHY2 ((PHY2 << 8) | USBH1) /* Connect USBH1 to PHY2 */
55#define USBD8PHY3 ((PHY3 << 8) | UDC8) /* Connect UDC8 to PHY3 */
56#define USBH2PHY3 ((PHY3 << 8) | USBH2) /* Connect USBH2 to PHY3 */
57
58struct npcm_usbphy {
59 struct regmap *syscon;
60 u8 id;
61 u16 phy_switch; /* (phy_id << 8) | controller_id */
62};
63
64static int npcm_usb_phy_init(struct phy *phy)
65{
66 struct npcm_usbphy *priv = dev_get_priv(phy->dev);
67 struct reset_ctl reset;
68 int ret;
69
70 ret = reset_get_by_index(phy->dev, 0, &reset);
71 if (ret && ret != -ENOENT && ret != -ENOTSUPP) {
72 dev_err(phy->dev, "can't get phy reset ctrl (err %d)", ret);
73 return ret;
74 }
75
76 /* setup PHY switch */
77 switch (priv->phy_switch) {
78 case USBD8PHY1:
79 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY3SW,
80 USBPHY3SW_DEV8_PHY1);
81 break;
82 case USBD8PHY3:
83 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY3SW,
84 USBPHY3SW_DEV8_PHY3);
85 break;
86 case USBD9PHY1:
87 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY2SW,
88 USBPHY2SW_DEV9_PHY1);
89 break;
90 case USBD9PHY2:
91 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY2SW,
92 USBPHY2SW_DEV9_PHY2);
93 break;
94 case USBH1PHY2:
95 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY2SW,
96 USBPHY2SW_HOST1);
97 break;
98 case USBH2PHY3:
99 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY3SW,
100 USBPHY3SW_HOST2);
101 break;
102 default:
103 break;
104 }
105 /* reset phy */
106 if (reset_valid(&reset))
107 reset_assert(&reset);
108
109 /* Wait for PHY clocks to stablize for 50us or more */
110 udelay(100);
111
112 /* release phy from reset */
113 if (reset_valid(&reset))
114 reset_deassert(&reset);
115
116 /* PHY RS bit should be set after reset */
117 switch (priv->id) {
118 case PHY1:
119 regmap_update_bits(priv->syscon, GCR_USB1PHYCTL, PHYCTL_RS, PHYCTL_RS);
120 break;
121 case PHY2:
122 regmap_update_bits(priv->syscon, GCR_USB2PHYCTL, PHYCTL_RS, PHYCTL_RS);
123 break;
124 case PHY3:
125 regmap_update_bits(priv->syscon, GCR_USB3PHYCTL, PHYCTL_RS, PHYCTL_RS);
126 break;
127 default:
128 break;
129 }
130
131 return 0;
132}
133
134static int npcm_usb_phy_exit(struct phy *phy)
135{
136 struct npcm_usbphy *priv = dev_get_priv(phy->dev);
137
138 /* set PHY switch to default state */
139 switch (priv->phy_switch) {
140 case USBD8PHY1:
141 case USBD8PHY3:
142 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY3SW,
143 USBPHY3SW_HOST2);
144 break;
145 case USBD9PHY1:
146 case USBD9PHY2:
147 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY2SW,
148 USBPHY2SW_HOST1);
149 break;
150 default:
151 break;
152 }
153 return 0;
154}
155
156static int npcm_usb_phy_xlate(struct phy *phy, struct ofnode_phandle_args *args)
157{
158 struct npcm_usbphy *priv = dev_get_priv(phy->dev);
159 u16 phy_switch;
160
161 if (args->args_count < 1 || args->args[0] > USBH2)
162 return -EINVAL;
163
164 phy_switch = (priv->id << 8) | args->args[0];
165 switch (phy_switch) {
166 case USBD9PHY1:
167 case USBH2PHY3:
168 case USBD8PHY3:
169 if (!IS_ENABLED(CONFIG_ARCH_NPCM8XX))
170 return -EINVAL;
171 case USBDPHY1:
172 case USBD8PHY1:
173 case USBD9PHY2:
174 case USBH1PHY2:
175 priv->phy_switch = phy_switch;
176 return 0;
177 default:
178 return -EINVAL;
179 }
180}
181
182static int npcm_usb_phy_probe(struct udevice *dev)
183{
184 struct npcm_usbphy *priv = dev_get_priv(dev);
185
186 priv->syscon = syscon_regmap_lookup_by_phandle(dev->parent, "syscon");
187 if (IS_ERR(priv->syscon)) {
188 dev_err(dev, "%s: unable to get syscon\n", __func__);
189 return PTR_ERR(priv->syscon);
190 }
191 priv->id = dev_read_u32_default(dev, "reg", -1);
192
193 return 0;
194}
195
196static const struct udevice_id npcm_phy_ids[] = {
197 { .compatible = "nuvoton,npcm845-usb-phy",},
198 { .compatible = "nuvoton,npcm750-usb-phy",},
199 { }
200};
201
202static struct phy_ops npcm_phy_ops = {
203 .init = npcm_usb_phy_init,
204 .exit = npcm_usb_phy_exit,
205 .of_xlate = npcm_usb_phy_xlate,
206};
207
208U_BOOT_DRIVER(npcm_phy) = {
209 .name = "npcm-usb-phy",
210 .id = UCLASS_PHY,
211 .of_match = npcm_phy_ids,
212 .ops = &npcm_phy_ops,
213 .probe = npcm_usb_phy_probe,
214 .priv_auto = sizeof(struct npcm_usbphy),
215};