blob: 3053543a3329ca7099309664d65f2172f1d12441 [file] [log] [blame]
Shawn Lin6ec62b62021-01-15 18:01:21 +08001// 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 <generic-phy.h>
12#include <regmap.h>
13#include <reset-uclass.h>
14#include <syscon.h>
15#include <asm/io.h>
16#include <dm/device_compat.h>
17#include <dm/lists.h>
18
19#define GRF_PCIE30PHY_CON1 0x4
20#define GRF_PCIE30PHY_CON6 0x18
21#define GRF_PCIE30PHY_CON9 0x24
22
23/**
24 * struct rockchip_p3phy_priv - RK DW PCIe PHY state
25 *
26 * @mmio: The base address of PHY internal registers
27 * @phy_grf: The regmap for controlling pipe signal
28 * @p30phy: The reset signal for PHY
Jonas Karlman3b395922023-08-02 19:04:29 +000029 * @clks: The clocks for PHY
Shawn Lin6ec62b62021-01-15 18:01:21 +080030 */
31struct rockchip_p3phy_priv {
32 void __iomem *mmio;
33 struct regmap *phy_grf;
34 struct reset_ctl p30phy;
Jonas Karlman3b395922023-08-02 19:04:29 +000035 struct clk_bulk clks;
Shawn Lin6ec62b62021-01-15 18:01:21 +080036};
37
38static int rochchip_p3phy_init(struct phy *phy)
39{
40 struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
41 int ret;
42
Jonas Karlman3b395922023-08-02 19:04:29 +000043 ret = clk_enable_bulk(&priv->clks);
44 if (ret)
Shawn Lin6ec62b62021-01-15 18:01:21 +080045 return ret;
46
Shawn Lin6ec62b62021-01-15 18:01:21 +080047 reset_assert(&priv->p30phy);
48 udelay(1);
49
50 /* Deassert PCIe PMA output clamp mode */
51 regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9,
52 (0x1 << 15) | (0x1 << 31));
53
54 reset_deassert(&priv->p30phy);
55 udelay(1);
56
57 return 0;
Shawn Lin6ec62b62021-01-15 18:01:21 +080058}
59
60static int rochchip_p3phy_exit(struct phy *phy)
61{
62 struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
63
Jonas Karlman3b395922023-08-02 19:04:29 +000064 clk_disable_bulk(&priv->clks);
Shawn Lin6ec62b62021-01-15 18:01:21 +080065 reset_assert(&priv->p30phy);
66
67 return 0;
68}
69
70static int rockchip_p3phy_probe(struct udevice *dev)
71{
72 struct rockchip_p3phy_priv *priv = dev_get_priv(dev);
Shawn Lin6ec62b62021-01-15 18:01:21 +080073 int ret;
74
Johan Jonkera12a73b2023-03-13 01:32:04 +010075 priv->mmio = dev_read_addr_ptr(dev);
76 if (!priv->mmio)
Shawn Lin6ec62b62021-01-15 18:01:21 +080077 return -EINVAL;
78
Jonas Karlman3b395922023-08-02 19:04:29 +000079 priv->phy_grf = syscon_regmap_lookup_by_phandle(dev, "rockchip,phy-grf");
Shawn Lin6ec62b62021-01-15 18:01:21 +080080 if (IS_ERR(priv->phy_grf)) {
81 dev_err(dev, "failed to find rockchip,phy_grf regmap\n");
82 return PTR_ERR(priv->phy_grf);
83 }
84
85 ret = reset_get_by_name(dev, "phy", &priv->p30phy);
86 if (ret) {
87 dev_err(dev, "no phy reset control specified\n");
88 return ret;
89 }
90
Jonas Karlman3b395922023-08-02 19:04:29 +000091 ret = clk_get_bulk(dev, &priv->clks);
Shawn Lin6ec62b62021-01-15 18:01:21 +080092 if (ret) {
Jonas Karlman3b395922023-08-02 19:04:29 +000093 dev_err(dev, "failed to get clocks\n");
94 return ret;
Shawn Lin6ec62b62021-01-15 18:01:21 +080095 }
96
97 return 0;
98}
99
100static struct phy_ops rochchip_p3phy_ops = {
101 .init = rochchip_p3phy_init,
102 .exit = rochchip_p3phy_exit,
103};
104
105static const struct udevice_id rockchip_p3phy_of_match[] = {
106 { .compatible = "rockchip,rk3568-pcie3-phy" },
107 { },
108};
109
110U_BOOT_DRIVER(rockchip_pcie3phy) = {
111 .name = "rockchip_pcie3phy",
112 .id = UCLASS_PHY,
113 .of_match = rockchip_p3phy_of_match,
114 .ops = &rochchip_p3phy_ops,
115 .probe = rockchip_p3phy_probe,
116 .priv_auto = sizeof(struct rockchip_p3phy_priv),
117};