1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. |
4 | * Copyright (c) 2019, Linaro Ltd. |
5 | */ |
6 | |
7 | #include <linux/clk-provider.h> |
8 | #include <linux/clk.h> |
9 | #include <linux/iopoll.h> |
10 | #include <linux/module.h> |
11 | #include <linux/phy/phy.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/reset.h> |
14 | #include <linux/slab.h> |
15 | |
16 | #include <dt-bindings/phy/phy.h> |
17 | |
18 | #define PCIE20_PARF_PHY_STTS 0x3c |
19 | #define PCIE2_PHY_RESET_CTRL 0x44 |
20 | #define PCIE20_PARF_PHY_REFCLK_CTRL2 0xa0 |
21 | #define PCIE20_PARF_PHY_REFCLK_CTRL3 0xa4 |
22 | #define PCIE20_PARF_PCS_SWING_CTRL1 0x88 |
23 | #define PCIE20_PARF_PCS_SWING_CTRL2 0x8c |
24 | #define PCIE20_PARF_PCS_DEEMPH1 0x74 |
25 | #define PCIE20_PARF_PCS_DEEMPH2 0x78 |
26 | #define PCIE20_PARF_PCS_DEEMPH3 0x7c |
27 | #define PCIE20_PARF_CONFIGBITS 0x84 |
28 | #define PCIE20_PARF_PHY_CTRL3 0x94 |
29 | #define PCIE20_PARF_PCS_CTRL 0x80 |
30 | |
31 | #define TX_AMP_VAL 120 |
32 | #define PHY_RX0_EQ_GEN1_VAL 0 |
33 | #define PHY_RX0_EQ_GEN2_VAL 4 |
34 | #define TX_DEEMPH_GEN1_VAL 24 |
35 | #define TX_DEEMPH_GEN2_3_5DB_VAL 26 |
36 | #define TX_DEEMPH_GEN2_6DB_VAL 36 |
37 | #define PHY_TX0_TERM_OFFST_VAL 0 |
38 | |
39 | struct qcom_phy { |
40 | struct device *dev; |
41 | void __iomem *base; |
42 | |
43 | struct regulator_bulk_data vregs[2]; |
44 | |
45 | struct reset_control *phy_reset; |
46 | struct reset_control *pipe_reset; |
47 | struct clk *pipe_clk; |
48 | }; |
49 | |
50 | static int qcom_pcie2_phy_init(struct phy *phy) |
51 | { |
52 | struct qcom_phy *qphy = phy_get_drvdata(phy); |
53 | int ret; |
54 | |
55 | ret = reset_control_deassert(rstc: qphy->phy_reset); |
56 | if (ret) { |
57 | dev_err(qphy->dev, "cannot deassert pipe reset\n" ); |
58 | return ret; |
59 | } |
60 | |
61 | ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), consumers: qphy->vregs); |
62 | if (ret) |
63 | reset_control_assert(rstc: qphy->phy_reset); |
64 | |
65 | return ret; |
66 | } |
67 | |
68 | static int qcom_pcie2_phy_power_on(struct phy *phy) |
69 | { |
70 | struct qcom_phy *qphy = phy_get_drvdata(phy); |
71 | int ret; |
72 | u32 val; |
73 | |
74 | /* Program REF_CLK source */ |
75 | val = readl(addr: qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2); |
76 | val &= ~BIT(1); |
77 | writel(val, addr: qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2); |
78 | |
79 | usleep_range(min: 1000, max: 2000); |
80 | |
81 | /* Don't use PAD for refclock */ |
82 | val = readl(addr: qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2); |
83 | val &= ~BIT(0); |
84 | writel(val, addr: qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2); |
85 | |
86 | /* Program SSP ENABLE */ |
87 | val = readl(addr: qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3); |
88 | val |= BIT(0); |
89 | writel(val, addr: qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3); |
90 | |
91 | usleep_range(min: 1000, max: 2000); |
92 | |
93 | /* Assert Phy SW Reset */ |
94 | val = readl(addr: qphy->base + PCIE2_PHY_RESET_CTRL); |
95 | val |= BIT(0); |
96 | writel(val, addr: qphy->base + PCIE2_PHY_RESET_CTRL); |
97 | |
98 | /* Program Tx Amplitude */ |
99 | val = readl(addr: qphy->base + PCIE20_PARF_PCS_SWING_CTRL1); |
100 | val &= ~0x7f; |
101 | val |= TX_AMP_VAL; |
102 | writel(val, addr: qphy->base + PCIE20_PARF_PCS_SWING_CTRL1); |
103 | |
104 | val = readl(addr: qphy->base + PCIE20_PARF_PCS_SWING_CTRL2); |
105 | val &= ~0x7f; |
106 | val |= TX_AMP_VAL; |
107 | writel(val, addr: qphy->base + PCIE20_PARF_PCS_SWING_CTRL2); |
108 | |
109 | /* Program De-Emphasis */ |
110 | val = readl(addr: qphy->base + PCIE20_PARF_PCS_DEEMPH1); |
111 | val &= ~0x3f; |
112 | val |= TX_DEEMPH_GEN2_6DB_VAL; |
113 | writel(val, addr: qphy->base + PCIE20_PARF_PCS_DEEMPH1); |
114 | |
115 | val = readl(addr: qphy->base + PCIE20_PARF_PCS_DEEMPH2); |
116 | val &= ~0x3f; |
117 | val |= TX_DEEMPH_GEN2_3_5DB_VAL; |
118 | writel(val, addr: qphy->base + PCIE20_PARF_PCS_DEEMPH2); |
119 | |
120 | val = readl(addr: qphy->base + PCIE20_PARF_PCS_DEEMPH3); |
121 | val &= ~0x3f; |
122 | val |= TX_DEEMPH_GEN1_VAL; |
123 | writel(val, addr: qphy->base + PCIE20_PARF_PCS_DEEMPH3); |
124 | |
125 | /* Program Rx_Eq */ |
126 | val = readl(addr: qphy->base + PCIE20_PARF_CONFIGBITS); |
127 | val &= ~0x7; |
128 | val |= PHY_RX0_EQ_GEN2_VAL; |
129 | writel(val, addr: qphy->base + PCIE20_PARF_CONFIGBITS); |
130 | |
131 | /* Program Tx0_term_offset */ |
132 | val = readl(addr: qphy->base + PCIE20_PARF_PHY_CTRL3); |
133 | val &= ~0x1f; |
134 | val |= PHY_TX0_TERM_OFFST_VAL; |
135 | writel(val, addr: qphy->base + PCIE20_PARF_PHY_CTRL3); |
136 | |
137 | /* disable Tx2Rx Loopback */ |
138 | val = readl(addr: qphy->base + PCIE20_PARF_PCS_CTRL); |
139 | val &= ~BIT(1); |
140 | writel(val, addr: qphy->base + PCIE20_PARF_PCS_CTRL); |
141 | |
142 | /* De-assert Phy SW Reset */ |
143 | val = readl(addr: qphy->base + PCIE2_PHY_RESET_CTRL); |
144 | val &= ~BIT(0); |
145 | writel(val, addr: qphy->base + PCIE2_PHY_RESET_CTRL); |
146 | |
147 | usleep_range(min: 1000, max: 2000); |
148 | |
149 | ret = reset_control_deassert(rstc: qphy->pipe_reset); |
150 | if (ret) { |
151 | dev_err(qphy->dev, "cannot deassert pipe reset\n" ); |
152 | goto out; |
153 | } |
154 | |
155 | clk_set_rate(clk: qphy->pipe_clk, rate: 250000000); |
156 | |
157 | ret = clk_prepare_enable(clk: qphy->pipe_clk); |
158 | if (ret) { |
159 | dev_err(qphy->dev, "failed to enable pipe clock\n" ); |
160 | goto out; |
161 | } |
162 | |
163 | ret = readl_poll_timeout(qphy->base + PCIE20_PARF_PHY_STTS, val, |
164 | !(val & BIT(0)), 1000, 10); |
165 | if (ret) |
166 | dev_err(qphy->dev, "phy initialization failed\n" ); |
167 | |
168 | out: |
169 | return ret; |
170 | } |
171 | |
172 | static int qcom_pcie2_phy_power_off(struct phy *phy) |
173 | { |
174 | struct qcom_phy *qphy = phy_get_drvdata(phy); |
175 | u32 val; |
176 | |
177 | val = readl(addr: qphy->base + PCIE2_PHY_RESET_CTRL); |
178 | val |= BIT(0); |
179 | writel(val, addr: qphy->base + PCIE2_PHY_RESET_CTRL); |
180 | |
181 | clk_disable_unprepare(clk: qphy->pipe_clk); |
182 | reset_control_assert(rstc: qphy->pipe_reset); |
183 | |
184 | return 0; |
185 | } |
186 | |
187 | static int qcom_pcie2_phy_exit(struct phy *phy) |
188 | { |
189 | struct qcom_phy *qphy = phy_get_drvdata(phy); |
190 | |
191 | regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), consumers: qphy->vregs); |
192 | reset_control_assert(rstc: qphy->phy_reset); |
193 | |
194 | return 0; |
195 | } |
196 | |
197 | static const struct phy_ops qcom_pcie2_ops = { |
198 | .init = qcom_pcie2_phy_init, |
199 | .power_on = qcom_pcie2_phy_power_on, |
200 | .power_off = qcom_pcie2_phy_power_off, |
201 | .exit = qcom_pcie2_phy_exit, |
202 | .owner = THIS_MODULE, |
203 | }; |
204 | |
205 | /* |
206 | * Register a fixed rate pipe clock. |
207 | * |
208 | * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate |
209 | * controls it. The <s>_pipe_clk coming out of the GCC is requested |
210 | * by the PHY driver for its operations. |
211 | * We register the <s>_pipe_clksrc here. The gcc driver takes care |
212 | * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk. |
213 | * Below picture shows this relationship. |
214 | * |
215 | * +---------------+ |
216 | * | PHY block |<<---------------------------------------+ |
217 | * | | | |
218 | * | +-------+ | +-----+ | |
219 | * I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+ |
220 | * clk | +-------+ | +-----+ |
221 | * +---------------+ |
222 | */ |
223 | static int phy_pipe_clksrc_register(struct qcom_phy *qphy) |
224 | { |
225 | struct device_node *np = qphy->dev->of_node; |
226 | struct clk_fixed_rate *fixed; |
227 | struct clk_init_data init = { }; |
228 | int ret; |
229 | |
230 | ret = of_property_read_string(np, propname: "clock-output-names" , out_string: &init.name); |
231 | if (ret) { |
232 | dev_err(qphy->dev, "%s: No clock-output-names\n" , np->name); |
233 | return ret; |
234 | } |
235 | |
236 | fixed = devm_kzalloc(dev: qphy->dev, size: sizeof(*fixed), GFP_KERNEL); |
237 | if (!fixed) |
238 | return -ENOMEM; |
239 | |
240 | init.ops = &clk_fixed_rate_ops; |
241 | |
242 | /* controllers using QMP phys use 250MHz pipe clock interface */ |
243 | fixed->fixed_rate = 250000000; |
244 | fixed->hw.init = &init; |
245 | |
246 | ret = devm_clk_hw_register(dev: qphy->dev, hw: &fixed->hw); |
247 | if (ret < 0) |
248 | return ret; |
249 | |
250 | return devm_of_clk_add_hw_provider(dev: qphy->dev, get: of_clk_hw_simple_get, data: &fixed->hw); |
251 | } |
252 | |
253 | static int qcom_pcie2_phy_probe(struct platform_device *pdev) |
254 | { |
255 | struct phy_provider *phy_provider; |
256 | struct qcom_phy *qphy; |
257 | struct device *dev = &pdev->dev; |
258 | struct phy *phy; |
259 | int ret; |
260 | |
261 | qphy = devm_kzalloc(dev, size: sizeof(*qphy), GFP_KERNEL); |
262 | if (!qphy) |
263 | return -ENOMEM; |
264 | |
265 | qphy->dev = dev; |
266 | qphy->base = devm_platform_ioremap_resource(pdev, index: 0); |
267 | if (IS_ERR(ptr: qphy->base)) |
268 | return PTR_ERR(ptr: qphy->base); |
269 | |
270 | ret = phy_pipe_clksrc_register(qphy); |
271 | if (ret) { |
272 | dev_err(dev, "failed to register pipe_clk\n" ); |
273 | return ret; |
274 | } |
275 | |
276 | qphy->vregs[0].supply = "vdda-vp" ; |
277 | qphy->vregs[1].supply = "vdda-vph" ; |
278 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(qphy->vregs), consumers: qphy->vregs); |
279 | if (ret < 0) |
280 | return ret; |
281 | |
282 | qphy->pipe_clk = devm_clk_get(dev, NULL); |
283 | if (IS_ERR(ptr: qphy->pipe_clk)) { |
284 | dev_err(dev, "failed to acquire pipe clock\n" ); |
285 | return PTR_ERR(ptr: qphy->pipe_clk); |
286 | } |
287 | |
288 | qphy->phy_reset = devm_reset_control_get_exclusive(dev, id: "phy" ); |
289 | if (IS_ERR(ptr: qphy->phy_reset)) { |
290 | dev_err(dev, "failed to acquire phy reset\n" ); |
291 | return PTR_ERR(ptr: qphy->phy_reset); |
292 | } |
293 | |
294 | qphy->pipe_reset = devm_reset_control_get_exclusive(dev, id: "pipe" ); |
295 | if (IS_ERR(ptr: qphy->pipe_reset)) { |
296 | dev_err(dev, "failed to acquire pipe reset\n" ); |
297 | return PTR_ERR(ptr: qphy->pipe_reset); |
298 | } |
299 | |
300 | phy = devm_phy_create(dev, node: dev->of_node, ops: &qcom_pcie2_ops); |
301 | if (IS_ERR(ptr: phy)) { |
302 | dev_err(dev, "failed to create phy\n" ); |
303 | return PTR_ERR(ptr: phy); |
304 | } |
305 | |
306 | phy_set_drvdata(phy, data: qphy); |
307 | |
308 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
309 | if (IS_ERR(ptr: phy_provider)) |
310 | dev_err(dev, "failed to register phy provider\n" ); |
311 | |
312 | return PTR_ERR_OR_ZERO(ptr: phy_provider); |
313 | } |
314 | |
315 | static const struct of_device_id qcom_pcie2_phy_match_table[] = { |
316 | { .compatible = "qcom,pcie2-phy" }, |
317 | {} |
318 | }; |
319 | MODULE_DEVICE_TABLE(of, qcom_pcie2_phy_match_table); |
320 | |
321 | static struct platform_driver qcom_pcie2_phy_driver = { |
322 | .probe = qcom_pcie2_phy_probe, |
323 | .driver = { |
324 | .name = "phy-qcom-pcie2" , |
325 | .of_match_table = qcom_pcie2_phy_match_table, |
326 | }, |
327 | }; |
328 | |
329 | module_platform_driver(qcom_pcie2_phy_driver); |
330 | |
331 | MODULE_DESCRIPTION("Qualcomm PCIe PHY driver" ); |
332 | MODULE_LICENSE("GPL v2" ); |
333 | |