1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2021 Nuvoton Technology Corp.
4  */
5 
6 #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 #include <dt-bindings/phy/nuvoton,npcm-usbphy.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 
35 enum phy_id {
36 	PHY1 = 1,
37 	PHY2,
38 	PHY3,
39 };
40 
41 /* Phy Switch Settings */
42 #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 */
49 
50 struct npcm_usbphy {
51 	struct regmap *syscon;
52 	u8 id;
53 	u16 phy_switch;	/* (phy_id << 8) | controller_id */
54 };
55 
npcm_usb_phy_init(struct phy * phy)56 static 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 
npcm_usb_phy_exit(struct phy * phy)126 static 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 
npcm_usb_phy_xlate(struct phy * phy,struct ofnode_phandle_args * args)148 static int npcm_usb_phy_xlate(struct phy *phy, struct ofnode_phandle_args *args)
149 {
150 	struct npcm_usbphy *priv = dev_get_priv(phy->dev);
151 	u16 phy_switch;
152 
153 	if (args->args_count < 1 || args->args[0] > NPCM_MAX_USB_CTRL_ID)
154 		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 
npcm_usb_phy_probe(struct udevice * dev)174 static 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 
188 static const struct udevice_id npcm_phy_ids[] = {
189 	{ .compatible = "nuvoton,npcm845-usb-phy",},
190 	{ .compatible = "nuvoton,npcm750-usb-phy",},
191 	{ }
192 };
193 
194 static 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 
200 U_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 };
208