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