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