xref: /rk3399_rockchip-uboot/drivers/phy/phy-rockchip-snps-pcie3.c (revision 2a7051be6cb4eddfbb7c8a7288750ec77adc42f3)
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 };
32 
33 static int rochchip_p3phy_init(struct phy *phy)
34 {
35 	struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
36 	int ret;
37 
38 	ret = clk_enable(&priv->ref_clk_m);
39 	if (ret < 0 && ret != -ENOSYS)
40 		return ret;
41 
42 	ret = clk_enable(&priv->ref_clk_n);
43 	if (ret < 0 && ret != -ENOSYS)
44 		goto err_ref;
45 
46 	ret = clk_enable(&priv->pclk);
47 	if (ret < 0 && ret != -ENOSYS)
48 		goto err_pclk;
49 
50 	reset_assert(&priv->p30phy);
51 	udelay(1);
52 
53 	/* Deassert PCIe PMA output clamp mode */
54 	regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9,
55 		     (0x1 << 15) | (0x1 << 31));
56 
57 	reset_deassert(&priv->p30phy);
58 	udelay(1);
59 
60 	return 0;
61 err_pclk:
62 	clk_disable(&priv->ref_clk_n);
63 err_ref:
64 	clk_disable(&priv->ref_clk_m);
65 	return ret;
66 }
67 
68 static int rochchip_p3phy_exit(struct phy *phy)
69 {
70 	struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
71 
72 	clk_disable(&priv->ref_clk_m);
73 	clk_disable(&priv->ref_clk_n);
74 	clk_disable(&priv->pclk);
75 	reset_assert(&priv->p30phy);
76 	return 0;
77 }
78 
79 static int rockchip_p3phy_probe(struct udevice *dev)
80 {
81 	struct rockchip_p3phy_priv *priv = dev_get_priv(dev);
82 	struct udevice *syscon;
83 	int ret;
84 
85 	priv->mmio = (void __iomem *)dev_read_addr(dev);
86 	if ((fdt_addr_t)priv->mmio == FDT_ADDR_T_NONE)
87 		return -EINVAL;
88 
89 	ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
90 					   "rockchip,phy-grf",  &syscon);
91 	if (ret) {
92 		pr_err("unable to find syscon device for rockchip,phy-grf\n");
93 		return ret;
94 	}
95 
96 	priv->phy_grf = syscon_get_regmap(syscon);
97 	if (IS_ERR(priv->phy_grf)) {
98 		dev_err(dev, "failed to find rockchip,phy_grf regmap\n");
99 		return PTR_ERR(priv->phy_grf);
100 	}
101 
102 	dev_dbg(priv->dev, "phy_grf is 0x%llx\n", priv->phy_grf->base);
103 
104 	ret = reset_get_by_name(dev, "phy", &priv->p30phy);
105 	if (ret) {
106 		dev_err(dev, "no phy reset control specified\n");
107 		return ret;
108 	}
109 
110 	ret = clk_get_by_name(dev, "refclk_m", &priv->ref_clk_m);
111 	if (ret) {
112 		dev_err(dev, "failed to find ref clock M\n");
113 		return PTR_ERR(&priv->ref_clk_m);
114 	}
115 
116 	ret = clk_get_by_name(dev, "refclk_n", &priv->ref_clk_n);
117 	if (ret) {
118 		dev_err(dev, "failed to find ref clock N\n");
119 		return PTR_ERR(&priv->ref_clk_n);
120 	}
121 
122 	ret = clk_get_by_name(dev, "pclk", &priv->pclk);
123 	if (ret) {
124 		dev_err(dev, "failed to find pclk\n");
125 		return PTR_ERR(&priv->pclk);
126 	}
127 
128 	return 0;
129 }
130 
131 static struct phy_ops rochchip_p3phy_ops = {
132 	.init = rochchip_p3phy_init,
133 	.exit = rochchip_p3phy_exit,
134 };
135 
136 static const struct udevice_id rockchip_p3phy_of_match[] = {
137 	{ .compatible = "rockchip,rk3568-pcie3-phy" },
138 	{ },
139 };
140 
141 U_BOOT_DRIVER(rockchip_pcie3phy) = {
142 	.name		= "rockchip_pcie3phy",
143 	.id		= UCLASS_PHY,
144 	.of_match	= rockchip_p3phy_of_match,
145 	.ops		= &rochchip_p3phy_ops,
146 	.probe		= rockchip_p3phy_probe,
147 	.priv_auto_alloc_size = sizeof(struct rockchip_p3phy_priv),
148 };
149