xref: /rk3399_rockchip-uboot/drivers/phy/phy-rockchip-snps-pcie3.c (revision f36ea2f6e17621c4d9dd97c4dbfab62d03d061df)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Rockchip PCIE3.0 phy driver
4  *
5  * Copyright (C) 2021 Rockchip Electronics Co., Ltd.
6  */
7 
8 #include <common.h>
9 #include <clk.h>
10 #include <dm.h>
11 #include <dm/lists.h>
12 #include <generic-phy.h>
13 #include <syscon.h>
14 #include <asm/io.h>
15 #include <asm/arch/clock.h>
16 #include <regmap.h>
17 #include <reset-uclass.h>
18 
19 #define GRF_PCIE30PHY_CON1 0x4
20 #define GRF_PCIE30PHY_CON6 0x18
21 #define GRF_PCIE30PHY_CON9 0x24
22 
23 struct rockchip_p3phy_priv {
24 	void __iomem *mmio;
25 	int mode;
26 	struct regmap *phy_grf;
27 	struct reset_ctl p30phy;
28 	struct clk ref_clk_m;
29 	struct clk ref_clk_n;
30 	struct clk pclk;
31 	bool is_bifurcation;
32 };
33 
34 static int rochchip_p3phy_init(struct phy *phy)
35 {
36 	struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
37 	int ret;
38 
39 	ret = clk_enable(&priv->ref_clk_m);
40 	if (ret < 0 && ret != -ENOSYS)
41 		return ret;
42 
43 	ret = clk_enable(&priv->ref_clk_n);
44 	if (ret < 0 && ret != -ENOSYS)
45 		goto err_ref;
46 
47 	ret = clk_enable(&priv->pclk);
48 	if (ret < 0 && ret != -ENOSYS)
49 		goto err_pclk;
50 
51 	reset_assert(&priv->p30phy);
52 	udelay(1);
53 
54 	/* Deassert PCIe PMA output clamp mode */
55 	regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9,
56 		     (0x1 << 15) | (0x1 << 31));
57 
58 	/* Set bifurcation if needed */
59 	if (priv->is_bifurcation) {
60 		regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6,
61 			     0x1 | (0xf << 16));
62 		regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON1,
63 			     (0x1 << 15) | (0x1 << 31));
64 	}
65 
66 	reset_deassert(&priv->p30phy);
67 	udelay(1);
68 
69 	return 0;
70 err_pclk:
71 	clk_disable(&priv->ref_clk_n);
72 err_ref:
73 	clk_disable(&priv->ref_clk_m);
74 	return ret;
75 }
76 
77 static int rochchip_p3phy_exit(struct phy *phy)
78 {
79 	struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
80 
81 	clk_disable(&priv->ref_clk_m);
82 	clk_disable(&priv->ref_clk_n);
83 	clk_disable(&priv->pclk);
84 	reset_assert(&priv->p30phy);
85 	return 0;
86 }
87 
88 static int rockchip_p3phy_probe(struct udevice *dev)
89 {
90 	struct rockchip_p3phy_priv *priv = dev_get_priv(dev);
91 	struct udevice *syscon;
92 	int ret;
93 
94 	priv->mmio = (void __iomem *)dev_read_addr(dev);
95 	if ((fdt_addr_t)priv->mmio == FDT_ADDR_T_NONE)
96 		return -EINVAL;
97 
98 	ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
99 					   "rockchip,phy-grf",  &syscon);
100 	if (ret) {
101 		pr_err("unable to find syscon device for rockchip,phy-grf\n");
102 		return ret;
103 	}
104 
105 	priv->phy_grf = syscon_get_regmap(syscon);
106 	if (IS_ERR(priv->phy_grf)) {
107 		dev_err(dev, "failed to find rockchip,phy_grf regmap\n");
108 		return PTR_ERR(priv->phy_grf);
109 	}
110 
111 	dev_dbg(priv->dev, "phy_grf is 0x%llx\n", priv->phy_grf->base);
112 
113 	ret = reset_get_by_name(dev, "phy", &priv->p30phy);
114 	if (ret) {
115 		dev_err(dev, "no phy reset control specified\n");
116 		return ret;
117 	}
118 
119 	ret = clk_get_by_name(dev, "refclk_m", &priv->ref_clk_m);
120 	if (ret) {
121 		dev_err(dev, "failed to find ref clock M\n");
122 		return PTR_ERR(&priv->ref_clk_m);
123 	}
124 
125 	ret = clk_get_by_name(dev, "refclk_n", &priv->ref_clk_n);
126 	if (ret) {
127 		dev_err(dev, "failed to find ref clock N\n");
128 		return PTR_ERR(&priv->ref_clk_n);
129 	}
130 
131 	ret = clk_get_by_name(dev, "pclk", &priv->pclk);
132 	if (ret) {
133 		dev_err(dev, "failed to find pclk\n");
134 		return PTR_ERR(&priv->pclk);
135 	}
136 
137 	return 0;
138 }
139 
140 static int rockchip_p3phy_configure(struct phy *phy, union phy_configure_opts *opts)
141 {
142 	struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
143 
144 	priv->pcie.is_bifurcation = opts->pcie.is_bifurcation;
145 
146 	return 0;
147 }
148 
149 static struct phy_ops rochchip_p3phy_ops = {
150 	.init = rochchip_p3phy_init,
151 	.exit = rochchip_p3phy_exit,
152 	.configure = rockchip_p3phy_configure,
153 };
154 
155 static const struct udevice_id rockchip_p3phy_of_match[] = {
156 	{ .compatible = "rockchip,rk3568-pcie3-phy" },
157 	{ },
158 };
159 
160 U_BOOT_DRIVER(rockchip_pcie3phy) = {
161 	.name		= "rockchip_pcie3phy",
162 	.id		= UCLASS_PHY,
163 	.of_match	= rockchip_p3phy_of_match,
164 	.ops		= &rochchip_p3phy_ops,
165 	.probe		= rockchip_p3phy_probe,
166 	.priv_auto_alloc_size = sizeof(struct rockchip_p3phy_priv),
167 };
168