xref: /rk3399_rockchip-uboot/drivers/phy/phy-rockchip-snps-pcie3.c (revision 2d0aa96ced08bf51dbae6d4ad93663e38ae3d959)
176ab7341SShawn Lin // SPDX-License-Identifier: GPL-2.0
276ab7341SShawn Lin /*
376ab7341SShawn Lin  * Rockchip PCIE3.0 phy driver
476ab7341SShawn Lin  *
576ab7341SShawn Lin  * Copyright (C) 2021 Rockchip Electronics Co., Ltd.
676ab7341SShawn Lin  */
776ab7341SShawn Lin 
876ab7341SShawn Lin #include <common.h>
976ab7341SShawn Lin #include <clk.h>
1076ab7341SShawn Lin #include <dm.h>
1176ab7341SShawn Lin #include <dm/lists.h>
1276ab7341SShawn Lin #include <generic-phy.h>
1376ab7341SShawn Lin #include <syscon.h>
1476ab7341SShawn Lin #include <asm/io.h>
1576ab7341SShawn Lin #include <asm/arch/clock.h>
1676ab7341SShawn Lin #include <regmap.h>
1776ab7341SShawn Lin #include <reset-uclass.h>
1876ab7341SShawn Lin 
1976ab7341SShawn Lin #define GRF_PCIE30PHY_CON1 0x4
2076ab7341SShawn Lin #define GRF_PCIE30PHY_CON6 0x18
2176ab7341SShawn Lin #define GRF_PCIE30PHY_CON9 0x24
2276ab7341SShawn Lin 
2376ab7341SShawn Lin struct rockchip_p3phy_priv {
2476ab7341SShawn Lin 	void __iomem *mmio;
2576ab7341SShawn Lin 	int mode;
2676ab7341SShawn Lin 	struct regmap *phy_grf;
2776ab7341SShawn Lin 	struct reset_ctl p30phy;
2876ab7341SShawn Lin 	struct clk ref_clk_m;
2976ab7341SShawn Lin 	struct clk ref_clk_n;
3076ab7341SShawn Lin 	struct clk pclk;
31c2482762SShawn Lin 	bool is_bifurcation;
3276ab7341SShawn Lin };
3376ab7341SShawn Lin 
3476ab7341SShawn Lin static int rochchip_p3phy_init(struct phy *phy)
3576ab7341SShawn Lin {
3676ab7341SShawn Lin 	struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
3776ab7341SShawn Lin 	int ret;
3876ab7341SShawn Lin 
3976ab7341SShawn Lin 	ret = clk_enable(&priv->ref_clk_m);
4076ab7341SShawn Lin 	if (ret < 0 && ret != -ENOSYS)
4176ab7341SShawn Lin 		return ret;
4276ab7341SShawn Lin 
4376ab7341SShawn Lin 	ret = clk_enable(&priv->ref_clk_n);
4476ab7341SShawn Lin 	if (ret < 0 && ret != -ENOSYS)
4576ab7341SShawn Lin 		goto err_ref;
4676ab7341SShawn Lin 
4776ab7341SShawn Lin 	ret = clk_enable(&priv->pclk);
4876ab7341SShawn Lin 	if (ret < 0 && ret != -ENOSYS)
4976ab7341SShawn Lin 		goto err_pclk;
5076ab7341SShawn Lin 
5176ab7341SShawn Lin 	reset_assert(&priv->p30phy);
5276ab7341SShawn Lin 	udelay(1);
5376ab7341SShawn Lin 
5476ab7341SShawn Lin 	/* Deassert PCIe PMA output clamp mode */
5576ab7341SShawn Lin 	regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9,
5676ab7341SShawn Lin 		     (0x1 << 15) | (0x1 << 31));
5776ab7341SShawn Lin 
58c2482762SShawn Lin 	/* Set bifurcation if needed */
59c2482762SShawn Lin 	if (priv->is_bifurcation) {
60c2482762SShawn Lin 		regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON6,
61c2482762SShawn Lin 			     0x1 | (0xf << 16));
62c2482762SShawn Lin 		regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON1,
63c2482762SShawn Lin 			     (0x1 << 15) | (0x1 << 31));
64c2482762SShawn Lin 	}
65c2482762SShawn Lin 
6676ab7341SShawn Lin 	reset_deassert(&priv->p30phy);
6776ab7341SShawn Lin 	udelay(1);
6876ab7341SShawn Lin 
6976ab7341SShawn Lin 	return 0;
7076ab7341SShawn Lin err_pclk:
7176ab7341SShawn Lin 	clk_disable(&priv->ref_clk_n);
7276ab7341SShawn Lin err_ref:
7376ab7341SShawn Lin 	clk_disable(&priv->ref_clk_m);
7476ab7341SShawn Lin 	return ret;
7576ab7341SShawn Lin }
7676ab7341SShawn Lin 
7776ab7341SShawn Lin static int rochchip_p3phy_exit(struct phy *phy)
7876ab7341SShawn Lin {
7976ab7341SShawn Lin 	struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
8076ab7341SShawn Lin 
8176ab7341SShawn Lin 	clk_disable(&priv->ref_clk_m);
8276ab7341SShawn Lin 	clk_disable(&priv->ref_clk_n);
8376ab7341SShawn Lin 	clk_disable(&priv->pclk);
8476ab7341SShawn Lin 	reset_assert(&priv->p30phy);
8576ab7341SShawn Lin 	return 0;
8676ab7341SShawn Lin }
8776ab7341SShawn Lin 
8876ab7341SShawn Lin static int rockchip_p3phy_probe(struct udevice *dev)
8976ab7341SShawn Lin {
9076ab7341SShawn Lin 	struct rockchip_p3phy_priv *priv = dev_get_priv(dev);
9176ab7341SShawn Lin 	struct udevice *syscon;
9276ab7341SShawn Lin 	int ret;
9376ab7341SShawn Lin 
9476ab7341SShawn Lin 	priv->mmio = (void __iomem *)dev_read_addr(dev);
9576ab7341SShawn Lin 	if ((fdt_addr_t)priv->mmio == FDT_ADDR_T_NONE)
9676ab7341SShawn Lin 		return -EINVAL;
9776ab7341SShawn Lin 
9876ab7341SShawn Lin 	ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
9976ab7341SShawn Lin 					   "rockchip,phy-grf",  &syscon);
10076ab7341SShawn Lin 	if (ret) {
10176ab7341SShawn Lin 		pr_err("unable to find syscon device for rockchip,phy-grf\n");
10276ab7341SShawn Lin 		return ret;
10376ab7341SShawn Lin 	}
10476ab7341SShawn Lin 
10576ab7341SShawn Lin 	priv->phy_grf = syscon_get_regmap(syscon);
10676ab7341SShawn Lin 	if (IS_ERR(priv->phy_grf)) {
10776ab7341SShawn Lin 		dev_err(dev, "failed to find rockchip,phy_grf regmap\n");
10876ab7341SShawn Lin 		return PTR_ERR(priv->phy_grf);
10976ab7341SShawn Lin 	}
11076ab7341SShawn Lin 
11176ab7341SShawn Lin 	dev_dbg(priv->dev, "phy_grf is 0x%llx\n", priv->phy_grf->base);
11276ab7341SShawn Lin 
11376ab7341SShawn Lin 	ret = reset_get_by_name(dev, "phy", &priv->p30phy);
11476ab7341SShawn Lin 	if (ret) {
11576ab7341SShawn Lin 		dev_err(dev, "no phy reset control specified\n");
11676ab7341SShawn Lin 		return ret;
11776ab7341SShawn Lin 	}
11876ab7341SShawn Lin 
11976ab7341SShawn Lin 	ret = clk_get_by_name(dev, "refclk_m", &priv->ref_clk_m);
12076ab7341SShawn Lin 	if (ret) {
12176ab7341SShawn Lin 		dev_err(dev, "failed to find ref clock M\n");
12276ab7341SShawn Lin 		return PTR_ERR(&priv->ref_clk_m);
12376ab7341SShawn Lin 	}
12476ab7341SShawn Lin 
12576ab7341SShawn Lin 	ret = clk_get_by_name(dev, "refclk_n", &priv->ref_clk_n);
12676ab7341SShawn Lin 	if (ret) {
12776ab7341SShawn Lin 		dev_err(dev, "failed to find ref clock N\n");
12876ab7341SShawn Lin 		return PTR_ERR(&priv->ref_clk_n);
12976ab7341SShawn Lin 	}
13076ab7341SShawn Lin 
13176ab7341SShawn Lin 	ret = clk_get_by_name(dev, "pclk", &priv->pclk);
13276ab7341SShawn Lin 	if (ret) {
13376ab7341SShawn Lin 		dev_err(dev, "failed to find pclk\n");
13476ab7341SShawn Lin 		return PTR_ERR(&priv->pclk);
13576ab7341SShawn Lin 	}
13676ab7341SShawn Lin 
13776ab7341SShawn Lin 	return 0;
13876ab7341SShawn Lin }
13976ab7341SShawn Lin 
140c2482762SShawn Lin static int rockchip_p3phy_configure(struct phy *phy, union phy_configure_opts *opts)
141c2482762SShawn Lin {
142c2482762SShawn Lin 	struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
143c2482762SShawn Lin 
144*2d0aa96cSShawn Lin 	priv->is_bifurcation = opts->pcie.is_bifurcation;
145c2482762SShawn Lin 
146c2482762SShawn Lin 	return 0;
147c2482762SShawn Lin }
148c2482762SShawn Lin 
14976ab7341SShawn Lin static struct phy_ops rochchip_p3phy_ops = {
15076ab7341SShawn Lin 	.init = rochchip_p3phy_init,
15176ab7341SShawn Lin 	.exit = rochchip_p3phy_exit,
152c2482762SShawn Lin 	.configure = rockchip_p3phy_configure,
15376ab7341SShawn Lin };
15476ab7341SShawn Lin 
15576ab7341SShawn Lin static const struct udevice_id rockchip_p3phy_of_match[] = {
15676ab7341SShawn Lin 	{ .compatible = "rockchip,rk3568-pcie3-phy" },
15776ab7341SShawn Lin 	{ },
15876ab7341SShawn Lin };
15976ab7341SShawn Lin 
16076ab7341SShawn Lin U_BOOT_DRIVER(rockchip_pcie3phy) = {
16176ab7341SShawn Lin 	.name		= "rockchip_pcie3phy",
16276ab7341SShawn Lin 	.id		= UCLASS_PHY,
16376ab7341SShawn Lin 	.of_match	= rockchip_p3phy_of_match,
16476ab7341SShawn Lin 	.ops		= &rochchip_p3phy_ops,
16576ab7341SShawn Lin 	.probe		= rockchip_p3phy_probe,
16676ab7341SShawn Lin 	.priv_auto_alloc_size = sizeof(struct rockchip_p3phy_priv),
16776ab7341SShawn Lin };
168