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