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