1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2025, The Linux Foundation. All rights reserved.
4 */
5
6 #include <linux/clk.h>
7 #include <linux/clk-provider.h>
8 #include <linux/delay.h>
9 #include <linux/err.h>
10 #include <linux/io.h>
11 #include <linux/mfd/syscon.h>
12 #include <linux/module.h>
13 #include <linux/of_device.h>
14 #include <linux/of.h>
15 #include <linux/phy/phy.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/reset.h>
19 #include <linux/units.h>
20
21 #define RST_ASSERT_DELAY_MIN_US 100
22 #define RST_ASSERT_DELAY_MAX_US 150
23 #define PIPE_CLK_DELAY_MIN_US 5000
24 #define PIPE_CLK_DELAY_MAX_US 5100
25 #define CLK_EN_DELAY_MIN_US 30
26 #define CLK_EN_DELAY_MAX_US 50
27 #define CDR_CTRL_REG_1 0x80
28 #define CDR_CTRL_REG_2 0x84
29 #define CDR_CTRL_REG_3 0x88
30 #define CDR_CTRL_REG_4 0x8c
31 #define CDR_CTRL_REG_5 0x90
32 #define CDR_CTRL_REG_6 0x94
33 #define CDR_CTRL_REG_7 0x98
34 #define SSCG_CTRL_REG_1 0x9c
35 #define SSCG_CTRL_REG_2 0xa0
36 #define SSCG_CTRL_REG_3 0xa4
37 #define SSCG_CTRL_REG_4 0xa8
38 #define SSCG_CTRL_REG_5 0xac
39 #define SSCG_CTRL_REG_6 0xb0
40 #define PCS_INTERNAL_CONTROL_2 0x2d8
41
42 #define PHY_CFG_PLLCFG 0x220
43 #define PHY_CFG_EIOS_DTCT_REG 0x3e4
44 #define PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME 0x3e8
45
46 enum qcom_uniphy_pcie_type {
47 PHY_TYPE_PCIE = 1,
48 PHY_TYPE_PCIE_GEN2,
49 PHY_TYPE_PCIE_GEN3,
50 };
51
52 struct qcom_uniphy_pcie_regs {
53 u32 offset;
54 u32 val;
55 };
56
57 struct qcom_uniphy_pcie_data {
58 int lane_offset; /* offset between the lane register bases */
59 u32 phy_type;
60 const struct qcom_uniphy_pcie_regs *init_seq;
61 u32 init_seq_num;
62 u32 pipe_clk_rate;
63 };
64
65 struct qcom_uniphy_pcie {
66 struct phy phy;
67 struct device *dev;
68 const struct qcom_uniphy_pcie_data *data;
69 struct clk_bulk_data *clks;
70 int num_clks;
71 struct reset_control *resets;
72 void __iomem *base;
73 int lanes;
74 };
75
76 #define phy_to_dw_phy(x) container_of((x), struct qca_uni_pcie_phy, phy)
77
78 static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
79 {
80 .offset = PHY_CFG_PLLCFG,
81 .val = 0x30,
82 }, {
83 .offset = PHY_CFG_EIOS_DTCT_REG,
84 .val = 0x53ef,
85 }, {
86 .offset = PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME,
87 .val = 0xcf,
88 },
89 };
90
91 static const struct qcom_uniphy_pcie_data ipq5332_data = {
92 .lane_offset = 0x800,
93 .phy_type = PHY_TYPE_PCIE_GEN3,
94 .init_seq = ipq5332_regs,
95 .init_seq_num = ARRAY_SIZE(ipq5332_regs),
96 .pipe_clk_rate = 250 * MEGA,
97 };
98
qcom_uniphy_pcie_init(struct qcom_uniphy_pcie * phy)99 static void qcom_uniphy_pcie_init(struct qcom_uniphy_pcie *phy)
100 {
101 const struct qcom_uniphy_pcie_data *data = phy->data;
102 const struct qcom_uniphy_pcie_regs *init_seq;
103 void __iomem *base = phy->base;
104 int lane, i;
105
106 for (lane = 0; lane < phy->lanes; lane++) {
107 init_seq = data->init_seq;
108
109 for (i = 0; i < data->init_seq_num; i++)
110 writel(init_seq[i].val, base + init_seq[i].offset);
111
112 base += data->lane_offset;
113 }
114 }
115
qcom_uniphy_pcie_power_off(struct phy * x)116 static int qcom_uniphy_pcie_power_off(struct phy *x)
117 {
118 struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
119
120 clk_bulk_disable_unprepare(phy->num_clks, phy->clks);
121
122 return reset_control_assert(phy->resets);
123 }
124
qcom_uniphy_pcie_power_on(struct phy * x)125 static int qcom_uniphy_pcie_power_on(struct phy *x)
126 {
127 struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
128 int ret;
129
130 ret = reset_control_assert(phy->resets);
131 if (ret) {
132 dev_err(phy->dev, "reset assert failed (%d)\n", ret);
133 return ret;
134 }
135
136 usleep_range(RST_ASSERT_DELAY_MIN_US, RST_ASSERT_DELAY_MAX_US);
137
138 ret = reset_control_deassert(phy->resets);
139 if (ret) {
140 dev_err(phy->dev, "reset deassert failed (%d)\n", ret);
141 return ret;
142 }
143
144 usleep_range(PIPE_CLK_DELAY_MIN_US, PIPE_CLK_DELAY_MAX_US);
145
146 ret = clk_bulk_prepare_enable(phy->num_clks, phy->clks);
147 if (ret) {
148 dev_err(phy->dev, "clk prepare and enable failed %d\n", ret);
149 return ret;
150 }
151
152 usleep_range(CLK_EN_DELAY_MIN_US, CLK_EN_DELAY_MAX_US);
153
154 qcom_uniphy_pcie_init(phy);
155
156 return 0;
157 }
158
qcom_uniphy_pcie_get_resources(struct platform_device * pdev,struct qcom_uniphy_pcie * phy)159 static inline int qcom_uniphy_pcie_get_resources(struct platform_device *pdev,
160 struct qcom_uniphy_pcie *phy)
161 {
162 struct resource *res;
163
164 phy->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
165 if (IS_ERR(phy->base))
166 return PTR_ERR(phy->base);
167
168 phy->num_clks = devm_clk_bulk_get_all(phy->dev, &phy->clks);
169 if (phy->num_clks < 0)
170 return phy->num_clks;
171
172 phy->resets = devm_reset_control_array_get_exclusive(phy->dev);
173 if (IS_ERR(phy->resets))
174 return PTR_ERR(phy->resets);
175
176 return 0;
177 }
178
179 /*
180 * Register a fixed rate pipe clock.
181 *
182 * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
183 * controls it. The <s>_pipe_clk coming out of the GCC is requested
184 * by the PHY driver for its operations.
185 * We register the <s>_pipe_clksrc here. The gcc driver takes care
186 * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
187 * Below picture shows this relationship.
188 *
189 * +---------------+
190 * | PHY block |<<---------------------------------------+
191 * | | |
192 * | +-------+ | +-----+ |
193 * I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
194 * clk | +-------+ | +-----+
195 * +---------------+
196 */
phy_pipe_clk_register(struct qcom_uniphy_pcie * phy,int id)197 static inline int phy_pipe_clk_register(struct qcom_uniphy_pcie *phy, int id)
198 {
199 const struct qcom_uniphy_pcie_data *data = phy->data;
200 struct clk_hw *hw;
201 char name[64];
202
203 snprintf(name, sizeof(name), "phy%d_pipe_clk_src", id);
204 hw = devm_clk_hw_register_fixed_rate(phy->dev, name, NULL, 0,
205 data->pipe_clk_rate);
206 if (IS_ERR(hw))
207 return dev_err_probe(phy->dev, PTR_ERR(hw),
208 "Unable to register %s\n", name);
209
210 return devm_of_clk_add_hw_provider(phy->dev, of_clk_hw_simple_get, hw);
211 }
212
213 static const struct of_device_id qcom_uniphy_pcie_id_table[] = {
214 {
215 .compatible = "qcom,ipq5332-uniphy-pcie-phy",
216 .data = &ipq5332_data,
217 }, {
218 /* Sentinel */
219 },
220 };
221 MODULE_DEVICE_TABLE(of, qcom_uniphy_pcie_id_table);
222
223 static const struct phy_ops pcie_ops = {
224 .power_on = qcom_uniphy_pcie_power_on,
225 .power_off = qcom_uniphy_pcie_power_off,
226 .owner = THIS_MODULE,
227 };
228
qcom_uniphy_pcie_probe(struct platform_device * pdev)229 static int qcom_uniphy_pcie_probe(struct platform_device *pdev)
230 {
231 struct phy_provider *phy_provider;
232 struct device *dev = &pdev->dev;
233 struct qcom_uniphy_pcie *phy;
234 struct phy *generic_phy;
235 int ret;
236
237 phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
238 if (!phy)
239 return -ENOMEM;
240
241 platform_set_drvdata(pdev, phy);
242 phy->dev = &pdev->dev;
243
244 phy->data = of_device_get_match_data(dev);
245 if (!phy->data)
246 return -EINVAL;
247
248 ret = of_property_read_u32(dev_of_node(dev), "num-lanes", &phy->lanes);
249 if (ret)
250 return dev_err_probe(dev, ret, "Couldn't read num-lanes\n");
251
252 ret = qcom_uniphy_pcie_get_resources(pdev, phy);
253 if (ret < 0)
254 return dev_err_probe(&pdev->dev, ret,
255 "failed to get resources: %d\n", ret);
256
257 generic_phy = devm_phy_create(phy->dev, NULL, &pcie_ops);
258 if (IS_ERR(generic_phy))
259 return PTR_ERR(generic_phy);
260
261 phy_set_drvdata(generic_phy, phy);
262
263 ret = phy_pipe_clk_register(phy, generic_phy->id);
264 if (ret)
265 dev_err(&pdev->dev, "failed to register phy pipe clk\n");
266
267 phy_provider = devm_of_phy_provider_register(phy->dev,
268 of_phy_simple_xlate);
269 if (IS_ERR(phy_provider))
270 return PTR_ERR(phy_provider);
271
272 return 0;
273 }
274
275 static struct platform_driver qcom_uniphy_pcie_driver = {
276 .probe = qcom_uniphy_pcie_probe,
277 .driver = {
278 .name = "qcom-uniphy-pcie",
279 .of_match_table = qcom_uniphy_pcie_id_table,
280 },
281 };
282
283 module_platform_driver(qcom_uniphy_pcie_driver);
284
285 MODULE_DESCRIPTION("PCIE QCOM UNIPHY driver");
286 MODULE_LICENSE("GPL");
287