blob: 47f5d6c7e3237157c2f38fdc0b1be7b6233a1bab [file] [log] [blame]
Jagan Teki89f2fa02020-05-09 22:26:22 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Rockchip PCIe PHY driver
4 *
5 * Copyright (c) 2016 Rockchip, Inc.
6 * Copyright (c) 2020 Amarula Solutions(India)
7 */
8
9#include <common.h>
10#include <clk.h>
11#include <dm.h>
12#include <dm/device_compat.h>
13#include <reset.h>
14#include <syscon.h>
15#include <asm/gpio.h>
16#include <asm/io.h>
17#include <linux/iopoll.h>
18#include <asm/arch-rockchip/clock.h>
19
20#include "pcie_rockchip.h"
21
22DECLARE_GLOBAL_DATA_PTR;
23
24static void phy_wr_cfg(struct rockchip_pcie_phy *phy, u32 addr, u32 data)
25{
26 u32 reg;
27
28 reg = HIWORD_UPDATE_MASK(data, PHY_CFG_DATA_MASK, PHY_CFG_DATA_SHIFT);
29 reg |= HIWORD_UPDATE_MASK(addr, PHY_CFG_ADDR_MASK, PHY_CFG_ADDR_SHIFT);
30 writel(reg, phy->reg_base + PCIE_PHY_CONF);
31
32 udelay(1);
33
34 reg = HIWORD_UPDATE_MASK(PHY_CFG_WR_ENABLE,
35 PHY_CFG_WR_MASK,
36 PHY_CFG_WR_SHIFT);
37 writel(reg, phy->reg_base + PCIE_PHY_CONF);
38
39 udelay(1);
40
41 reg = HIWORD_UPDATE_MASK(PHY_CFG_WR_DISABLE,
42 PHY_CFG_WR_MASK,
43 PHY_CFG_WR_SHIFT);
44 writel(reg, phy->reg_base + PCIE_PHY_CONF);
45}
46
47static int rockchip_pcie_phy_power_on(struct rockchip_pcie_phy *phy)
48{
49 int ret = 0;
50 u32 reg, status;
51
52 ret = reset_deassert(&phy->phy_rst);
53 if (ret) {
54 dev_err(dev, "failed to assert phy reset\n");
55 return ret;
56 }
57
58 reg = HIWORD_UPDATE_MASK(PHY_CFG_PLL_LOCK,
59 PHY_CFG_ADDR_MASK,
60 PHY_CFG_ADDR_SHIFT);
61 writel(reg, phy->reg_base + PCIE_PHY_CONF);
62
63 reg = HIWORD_UPDATE_MASK(!PHY_LANE_IDLE_OFF,
64 PHY_LANE_IDLE_MASK,
65 PHY_LANE_IDLE_A_SHIFT);
66 writel(reg, phy->reg_base + PCIE_PHY_LANEOFF);
67
68 ret = -EINVAL;
69 ret = readl_poll_sleep_timeout(phy->reg_base + PCIE_PHY_STATUS,
70 status,
71 status & PHY_PLL_LOCKED,
72 20 * 1000,
73 50);
74 if (ret) {
75 dev_err(&phy->dev, "pll lock timeout!\n");
76 goto err_pll_lock;
77 }
78
79 phy_wr_cfg(phy, PHY_CFG_CLK_TEST, PHY_CFG_SEPE_RATE);
80 phy_wr_cfg(phy, PHY_CFG_CLK_SCC, PHY_CFG_PLL_100M);
81
82 ret = -ETIMEDOUT;
83 ret = readl_poll_sleep_timeout(phy->reg_base + PCIE_PHY_STATUS,
84 status,
85 !(status & PHY_PLL_OUTPUT),
86 20 * 1000,
87 50);
88 if (ret) {
89 dev_err(&phy->dev, "pll output enable timeout!\n");
90 goto err_pll_lock;
91 }
92
93 reg = HIWORD_UPDATE_MASK(PHY_CFG_PLL_LOCK,
94 PHY_CFG_ADDR_MASK,
95 PHY_CFG_ADDR_SHIFT);
96 writel(reg, phy->reg_base + PCIE_PHY_CONF);
97
98 ret = -EINVAL;
99 ret = readl_poll_sleep_timeout(phy->reg_base + PCIE_PHY_STATUS,
100 status,
101 status & PHY_PLL_LOCKED,
102 20 * 1000,
103 50);
104 if (ret) {
105 dev_err(&phy->dev, "pll relock timeout!\n");
106 goto err_pll_lock;
107 }
108
109 return 0;
110
111err_pll_lock:
112 reset_assert(&phy->phy_rst);
113 return ret;
114}
115
116static int rockchip_pcie_phy_power_off(struct rockchip_pcie_phy *phy)
117{
118 int ret;
119 u32 reg;
120
121 reg = HIWORD_UPDATE_MASK(PHY_LANE_IDLE_OFF,
122 PHY_LANE_IDLE_MASK,
123 PHY_LANE_IDLE_A_SHIFT);
124 writel(reg, phy->reg_base + PCIE_PHY_LANEOFF);
125
126 ret = reset_assert(&phy->phy_rst);
127 if (ret) {
128 dev_err(dev, "failed to assert phy reset\n");
129 return ret;
130 }
131
132 return 0;
133}
134
135static int rockchip_pcie_phy_init(struct rockchip_pcie_phy *phy)
136{
137 int ret;
138
139 ret = clk_enable(&phy->refclk);
140 if (ret) {
141 dev_err(dev, "failed to enable refclk clock\n");
142 return ret;
143 }
144
145 ret = reset_assert(&phy->phy_rst);
146 if (ret) {
147 dev_err(dev, "failed to assert phy reset\n");
148 goto err_reset;
149 }
150
151 return 0;
152
153err_reset:
154 clk_disable(&phy->refclk);
155 return ret;
156}
157
158static int rockchip_pcie_phy_exit(struct rockchip_pcie_phy *phy)
159{
160 clk_disable(&phy->refclk);
161
162 return 0;
163}
164
165static struct rockchip_pcie_phy_ops pcie_phy_ops = {
166 .init = rockchip_pcie_phy_init,
167 .power_on = rockchip_pcie_phy_power_on,
168 .power_off = rockchip_pcie_phy_power_off,
169 .exit = rockchip_pcie_phy_exit,
170};
171
172int rockchip_pcie_phy_get(struct udevice *dev)
173{
174 struct rockchip_pcie *priv = dev_get_priv(dev);
175 struct rockchip_pcie_phy *phy_priv = &priv->rk_phy;
176 ofnode phy_node;
177 u32 phandle;
178 int ret;
179
180 phandle = dev_read_u32_default(dev, "phys", 0);
181 phy_node = ofnode_get_by_phandle(phandle);
182 if (!ofnode_valid(phy_node)) {
183 dev_err(dev, "failed to found pcie-phy\n");
184 return -ENODEV;
185 }
186
187 phy_priv->reg_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
188
189 ret = clk_get_by_index_nodev(phy_node, 0, &phy_priv->refclk);
190 if (ret) {
191 dev_err(dev, "failed to get refclk clock phandle\n");
192 return ret;
193 }
194
195 ret = reset_get_by_index_nodev(phy_node, 0, &phy_priv->phy_rst);
196 if (ret) {
197 dev_err(dev, "failed to get phy reset phandle\n");
198 return ret;
199 }
200
201 phy_priv->ops = &pcie_phy_ops;
202 priv->phy = phy_priv;
203
204 return 0;
205}