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
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};
215