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