1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * PCIe phy driver for Kirin 970 |
4 | * |
5 | * Copyright (C) 2017 HiSilicon Electronics Co., Ltd. |
6 | * https://www.huawei.com |
7 | * Copyright (C) 2021 Huawei Technologies Co., Ltd. |
8 | * https://www.huawei.com |
9 | * |
10 | * Authors: |
11 | * Mauro Carvalho Chehab <mchehab+huawei@kernel.org> |
12 | * Manivannan Sadhasivam <mani@kernel.org> |
13 | * |
14 | * Based on: |
15 | * https://lore.kernel.org/lkml/4c9d6581478aa966698758c0420933f5defab4dd.1612335031.git.mchehab+huawei@kernel.org/ |
16 | */ |
17 | |
18 | #include <linux/bitfield.h> |
19 | #include <linux/clk.h> |
20 | #include <linux/gpio.h> |
21 | #include <linux/kernel.h> |
22 | #include <linux/mfd/syscon.h> |
23 | #include <linux/module.h> |
24 | #include <linux/of_gpio.h> |
25 | #include <linux/phy/phy.h> |
26 | #include <linux/platform_device.h> |
27 | #include <linux/regmap.h> |
28 | |
29 | #define AXI_CLK_FREQ 207500000 |
30 | #define REF_CLK_FREQ 100000000 |
31 | |
32 | /* PCIe CTRL registers */ |
33 | #define SOC_PCIECTRL_CTRL7_ADDR 0x01c |
34 | #define SOC_PCIECTRL_CTRL12_ADDR 0x030 |
35 | #define SOC_PCIECTRL_CTRL20_ADDR 0x050 |
36 | #define SOC_PCIECTRL_CTRL21_ADDR 0x054 |
37 | |
38 | #define PCIE_OUTPUT_PULL_BITS GENMASK(3, 0) |
39 | #define SOC_PCIECTRL_CTRL20_2P_MEM_CTRL 0x02605550 |
40 | #define SOC_PCIECTRL_CTRL21_DEFAULT 0x20000070 |
41 | #define PCIE_PULL_UP_SYS_AUX_PWR_DET BIT(10) |
42 | #define PCIE_OUTPUT_PULL_DOWN BIT(1) |
43 | |
44 | /* PCIe PHY registers */ |
45 | #define SOC_PCIEPHY_CTRL0_ADDR 0x000 |
46 | #define SOC_PCIEPHY_CTRL1_ADDR 0x004 |
47 | #define SOC_PCIEPHY_CTRL38_ADDR 0x0098 |
48 | #define SOC_PCIEPHY_STATE0_ADDR 0x400 |
49 | |
50 | #define RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1 0xc004 |
51 | #define SUP_DIG_LVL_OVRD_IN 0x003c |
52 | #define LANEN_DIG_ASIC_TX_OVRD_IN_1 0x4008 |
53 | #define LANEN_DIG_ASIC_TX_OVRD_IN_2 0x400c |
54 | |
55 | #define PCIEPHY_RESET_BIT BIT(17) |
56 | #define PCIEPHY_PIPE_LINE0_RESET_BIT BIT(19) |
57 | #define PCIE_TXDETECT_RX_FAIL BIT(2) |
58 | #define PCIE_CLK_SOURCE BIT(8) |
59 | #define PCIE_IS_CLOCK_STABLE BIT(19) |
60 | #define PCIE_PULL_DOWN_PHY_TEST_POWERDOWN BIT(22) |
61 | #define PCIE_DEASSERT_CONTROLLER_PERST BIT(2) |
62 | |
63 | #define EYEPARAM_NOCFG 0xffffffff |
64 | #define EYE_PARM0_MASK GENMASK(8, 6) |
65 | #define EYE_PARM1_MASK GENMASK(11, 8) |
66 | #define EYE_PARM2_MASK GENMASK(5, 0) |
67 | #define EYE_PARM3_MASK GENMASK(12, 7) |
68 | #define EYE_PARM4_MASK GENMASK(14, 9) |
69 | #define EYE_PARM0_EN BIT(9) |
70 | #define EYE_PARM1_EN BIT(12) |
71 | #define EYE_PARM2_EN BIT(6) |
72 | #define EYE_PARM3_EN BIT(13) |
73 | #define EYE_PARM4_EN BIT(15) |
74 | |
75 | /* hi3670 pciephy register */ |
76 | #define APB_PHY_START_ADDR 0x40000 |
77 | #define SOC_PCIEPHY_MMC1PLL_CTRL1 0xc04 |
78 | #define SOC_PCIEPHY_MMC1PLL_CTRL16 0xC40 |
79 | #define SOC_PCIEPHY_MMC1PLL_CTRL17 0xC44 |
80 | #define SOC_PCIEPHY_MMC1PLL_CTRL20 0xC50 |
81 | #define SOC_PCIEPHY_MMC1PLL_CTRL21 0xC54 |
82 | #define SOC_PCIEPHY_MMC1PLL_STAT0 0xE00 |
83 | |
84 | #define CRGPERIPH_PEREN12 0x470 |
85 | #define CRGPERIPH_PERDIS12 0x474 |
86 | #define CRGPERIPH_PCIECTRL0 0x800 |
87 | |
88 | #define PCIE_FNPLL_FBDIV_MASK GENMASK(27, 16) |
89 | #define PCIE_FNPLL_FRACDIV_MASK GENMASK(23, 0) |
90 | #define PCIE_FNPLL_POSTDIV1_MASK GENMASK(10, 8) |
91 | #define PCIE_FNPLL_POSTDIV2_MASK GENMASK(14, 12) |
92 | #define PCIE_FNPLL_PLL_MODE_MASK BIT(25) |
93 | |
94 | #define PCIE_FNPLL_DLL_EN BIT(27) |
95 | #define PCIE_FNPLL_FBDIV 0xd0 |
96 | #define PCIE_FNPLL_FRACDIV 0x555555 |
97 | #define PCIE_FNPLL_POSTDIV1 0x5 |
98 | #define PCIE_FNPLL_POSTDIV2 0x4 |
99 | #define PCIE_FNPLL_PLL_MODE 0x0 |
100 | |
101 | #define PCIE_PHY_MMC1PLL 0x20 |
102 | #define PCIE_PHY_CHOOSE_FNPLL BIT(27) |
103 | #define PCIE_PHY_MMC1PLL_DISABLE BIT(0) |
104 | #define PCIE_PHY_PCIEPL_BP BIT(16) |
105 | |
106 | /* define ie,oe cfg */ |
107 | #define IO_OE_HARD_GT_MODE BIT(1) |
108 | #define IO_IE_EN_HARD_BYPASS BIT(27) |
109 | #define IO_OE_EN_HARD_BYPASS BIT(11) |
110 | #define IO_HARD_CTRL_DEBOUNCE_BYPASS BIT(10) |
111 | #define IO_OE_GT_MODE BIT(8) |
112 | #define DEBOUNCE_WAITCFG_IN GENMASK(23, 20) |
113 | #define DEBOUNCE_WAITCFG_OUT GENMASK(16, 13) |
114 | |
115 | #define IO_HP_DEBOUNCE_GT (BIT(12) | BIT(15)) |
116 | #define IO_PHYREF_SOFT_GT_MODE BIT(14) |
117 | #define IO_REF_SOFT_GT_MODE BIT(13) |
118 | #define IO_REF_HARD_GT_MODE BIT(0) |
119 | |
120 | /* noc power domain */ |
121 | #define NOC_POWER_IDLEREQ_1 0x38c |
122 | #define NOC_POWER_IDLE_1 0x394 |
123 | #define NOC_PW_MASK 0x10000 |
124 | #define NOC_PW_SET_BIT 0x1 |
125 | |
126 | #define NUM_EYEPARAM 5 |
127 | |
128 | /* info located in sysctrl */ |
129 | #define SCTRL_PCIE_CMOS_OFFSET 0x60 |
130 | #define SCTRL_PCIE_CMOS_BIT 0x10 |
131 | #define SCTRL_PCIE_ISO_OFFSET 0x44 |
132 | #define SCTRL_PCIE_ISO_BIT 0x30 |
133 | #define SCTRL_PCIE_HPCLK_OFFSET 0x190 |
134 | #define SCTRL_PCIE_HPCLK_BIT 0x184000 |
135 | #define SCTRL_PCIE_OE_OFFSET 0x14a |
136 | #define PCIE_DEBOUNCE_PARAM 0xf0f400 |
137 | #define PCIE_OE_BYPASS GENMASK(29, 28) |
138 | |
139 | /* peri_crg ctrl */ |
140 | #define CRGCTRL_PCIE_ASSERT_OFFSET 0x88 |
141 | #define CRGCTRL_PCIE_ASSERT_BIT 0x8c000000 |
142 | |
143 | #define FNPLL_HAS_LOCKED BIT(4) |
144 | |
145 | /* Time for delay */ |
146 | #define TIME_CMOS_MIN 100 |
147 | #define TIME_CMOS_MAX 105 |
148 | #define PIPE_CLK_STABLE_TIME 100 |
149 | #define PLL_CTRL_WAIT_TIME 200 |
150 | #define NOC_POWER_TIME 100 |
151 | |
152 | struct hi3670_pcie_phy { |
153 | struct device *dev; |
154 | void __iomem *base; |
155 | struct regmap *apb; |
156 | struct regmap *crgctrl; |
157 | struct regmap *sysctrl; |
158 | struct regmap *pmctrl; |
159 | struct clk *apb_sys_clk; |
160 | struct clk *apb_phy_clk; |
161 | struct clk *phy_ref_clk; |
162 | struct clk *aclk; |
163 | struct clk *aux_clk; |
164 | u32 eye_param[NUM_EYEPARAM]; |
165 | }; |
166 | |
167 | /* Registers in PCIePHY */ |
168 | static inline void hi3670_apb_phy_writel(struct hi3670_pcie_phy *phy, u32 val, |
169 | u32 reg) |
170 | { |
171 | writel(val, addr: phy->base + APB_PHY_START_ADDR + reg); |
172 | } |
173 | |
174 | static inline u32 hi3670_apb_phy_readl(struct hi3670_pcie_phy *phy, u32 reg) |
175 | { |
176 | return readl(addr: phy->base + APB_PHY_START_ADDR + reg); |
177 | } |
178 | |
179 | static inline void hi3670_apb_phy_updatel(struct hi3670_pcie_phy *phy, |
180 | u32 val, u32 mask, u32 reg) |
181 | { |
182 | u32 regval; |
183 | |
184 | regval = hi3670_apb_phy_readl(phy, reg); |
185 | regval &= ~mask; |
186 | regval |= val; |
187 | hi3670_apb_phy_writel(phy, val: regval, reg); |
188 | } |
189 | |
190 | static inline void kirin_apb_natural_phy_writel(struct hi3670_pcie_phy *phy, |
191 | u32 val, u32 reg) |
192 | { |
193 | writel(val, addr: phy->base + reg); |
194 | } |
195 | |
196 | static inline u32 kirin_apb_natural_phy_readl(struct hi3670_pcie_phy *phy, |
197 | u32 reg) |
198 | { |
199 | return readl(addr: phy->base + reg); |
200 | } |
201 | |
202 | static void hi3670_pcie_phy_oe_enable(struct hi3670_pcie_phy *phy, bool enable) |
203 | { |
204 | u32 val; |
205 | |
206 | regmap_read(map: phy->sysctrl, SCTRL_PCIE_OE_OFFSET, val: &val); |
207 | val |= PCIE_DEBOUNCE_PARAM; |
208 | if (enable) |
209 | val &= ~PCIE_OE_BYPASS; |
210 | else |
211 | val |= PCIE_OE_BYPASS; |
212 | regmap_write(map: phy->sysctrl, SCTRL_PCIE_OE_OFFSET, val); |
213 | } |
214 | |
215 | static void hi3670_pcie_get_eyeparam(struct hi3670_pcie_phy *phy) |
216 | { |
217 | struct device *dev = phy->dev; |
218 | struct device_node *np; |
219 | int ret, i; |
220 | |
221 | np = dev->of_node; |
222 | |
223 | ret = of_property_read_u32_array(np, propname: "hisilicon,eye-diagram-param" , |
224 | out_values: phy->eye_param, NUM_EYEPARAM); |
225 | if (!ret) |
226 | return; |
227 | |
228 | /* There's no optional eye_param property. Set array to default */ |
229 | for (i = 0; i < NUM_EYEPARAM; i++) |
230 | phy->eye_param[i] = EYEPARAM_NOCFG; |
231 | } |
232 | |
233 | static void hi3670_pcie_set_eyeparam(struct hi3670_pcie_phy *phy) |
234 | { |
235 | u32 val; |
236 | |
237 | val = kirin_apb_natural_phy_readl(phy, RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1); |
238 | |
239 | if (phy->eye_param[1] != EYEPARAM_NOCFG) { |
240 | val &= ~EYE_PARM1_MASK; |
241 | val |= FIELD_PREP(EYE_PARM1_MASK, phy->eye_param[1]); |
242 | val |= EYE_PARM1_EN; |
243 | } |
244 | kirin_apb_natural_phy_writel(phy, val, |
245 | RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1); |
246 | |
247 | val = kirin_apb_natural_phy_readl(phy, LANEN_DIG_ASIC_TX_OVRD_IN_2); |
248 | val &= ~(EYE_PARM2_MASK | EYE_PARM3_MASK); |
249 | if (phy->eye_param[2] != EYEPARAM_NOCFG) { |
250 | val |= FIELD_PREP(EYE_PARM2_MASK, phy->eye_param[2]); |
251 | val |= EYE_PARM2_EN; |
252 | } |
253 | |
254 | if (phy->eye_param[3] != EYEPARAM_NOCFG) { |
255 | val |= FIELD_PREP(EYE_PARM3_MASK, phy->eye_param[3]); |
256 | val |= EYE_PARM3_EN; |
257 | } |
258 | |
259 | kirin_apb_natural_phy_writel(phy, val, LANEN_DIG_ASIC_TX_OVRD_IN_2); |
260 | |
261 | val = kirin_apb_natural_phy_readl(phy, SUP_DIG_LVL_OVRD_IN); |
262 | if (phy->eye_param[0] != EYEPARAM_NOCFG) { |
263 | val &= ~EYE_PARM0_MASK; |
264 | val |= FIELD_PREP(EYE_PARM0_MASK, phy->eye_param[0]); |
265 | val |= EYE_PARM0_EN; |
266 | } |
267 | kirin_apb_natural_phy_writel(phy, val, SUP_DIG_LVL_OVRD_IN); |
268 | |
269 | val = kirin_apb_natural_phy_readl(phy, LANEN_DIG_ASIC_TX_OVRD_IN_1); |
270 | if (phy->eye_param[4] != EYEPARAM_NOCFG) { |
271 | val &= ~EYE_PARM4_MASK; |
272 | val |= FIELD_PREP(EYE_PARM4_MASK, phy->eye_param[4]); |
273 | val |= EYE_PARM4_EN; |
274 | } |
275 | kirin_apb_natural_phy_writel(phy, val, LANEN_DIG_ASIC_TX_OVRD_IN_1); |
276 | } |
277 | |
278 | static void hi3670_pcie_natural_cfg(struct hi3670_pcie_phy *phy) |
279 | { |
280 | u32 val; |
281 | |
282 | /* change 2p mem_ctrl */ |
283 | regmap_write(map: phy->apb, SOC_PCIECTRL_CTRL20_ADDR, |
284 | SOC_PCIECTRL_CTRL20_2P_MEM_CTRL); |
285 | |
286 | regmap_read(map: phy->apb, SOC_PCIECTRL_CTRL7_ADDR, val: &val); |
287 | val |= PCIE_PULL_UP_SYS_AUX_PWR_DET; |
288 | regmap_write(map: phy->apb, SOC_PCIECTRL_CTRL7_ADDR, val); |
289 | |
290 | /* output, pull down */ |
291 | regmap_read(map: phy->apb, SOC_PCIECTRL_CTRL12_ADDR, val: &val); |
292 | val &= ~PCIE_OUTPUT_PULL_BITS; |
293 | val |= PCIE_OUTPUT_PULL_DOWN; |
294 | regmap_write(map: phy->apb, SOC_PCIECTRL_CTRL12_ADDR, val); |
295 | |
296 | /* Handle phy_reset and lane0_reset to HW */ |
297 | hi3670_apb_phy_updatel(phy, PCIEPHY_RESET_BIT, |
298 | PCIEPHY_PIPE_LINE0_RESET_BIT | PCIEPHY_RESET_BIT, |
299 | SOC_PCIEPHY_CTRL1_ADDR); |
300 | |
301 | /* fix chip bug: TxDetectRx fail */ |
302 | hi3670_apb_phy_updatel(phy, PCIE_TXDETECT_RX_FAIL, PCIE_TXDETECT_RX_FAIL, |
303 | SOC_PCIEPHY_CTRL38_ADDR); |
304 | } |
305 | |
306 | static void hi3670_pcie_pll_init(struct hi3670_pcie_phy *phy) |
307 | { |
308 | hi3670_apb_phy_updatel(phy, PCIE_PHY_CHOOSE_FNPLL, PCIE_PHY_CHOOSE_FNPLL, |
309 | SOC_PCIEPHY_MMC1PLL_CTRL1); |
310 | |
311 | hi3670_apb_phy_updatel(phy, |
312 | FIELD_PREP(PCIE_FNPLL_FBDIV_MASK, PCIE_FNPLL_FBDIV), |
313 | PCIE_FNPLL_FBDIV_MASK, |
314 | SOC_PCIEPHY_MMC1PLL_CTRL16); |
315 | |
316 | hi3670_apb_phy_updatel(phy, |
317 | FIELD_PREP(PCIE_FNPLL_FRACDIV_MASK, PCIE_FNPLL_FRACDIV), |
318 | PCIE_FNPLL_FRACDIV_MASK, SOC_PCIEPHY_MMC1PLL_CTRL17); |
319 | |
320 | hi3670_apb_phy_updatel(phy, |
321 | PCIE_FNPLL_DLL_EN | |
322 | FIELD_PREP(PCIE_FNPLL_POSTDIV1_MASK, PCIE_FNPLL_POSTDIV1) | |
323 | FIELD_PREP(PCIE_FNPLL_POSTDIV2_MASK, PCIE_FNPLL_POSTDIV2) | |
324 | FIELD_PREP(PCIE_FNPLL_PLL_MODE_MASK, PCIE_FNPLL_PLL_MODE), |
325 | PCIE_FNPLL_POSTDIV1_MASK | |
326 | PCIE_FNPLL_POSTDIV2_MASK | |
327 | PCIE_FNPLL_PLL_MODE_MASK | PCIE_FNPLL_DLL_EN, |
328 | SOC_PCIEPHY_MMC1PLL_CTRL20); |
329 | |
330 | hi3670_apb_phy_writel(phy, PCIE_PHY_MMC1PLL, |
331 | SOC_PCIEPHY_MMC1PLL_CTRL21); |
332 | } |
333 | |
334 | static int hi3670_pcie_pll_ctrl(struct hi3670_pcie_phy *phy, bool enable) |
335 | { |
336 | struct device *dev = phy->dev; |
337 | u32 val; |
338 | int time = PLL_CTRL_WAIT_TIME; |
339 | |
340 | if (enable) { |
341 | /* pd = 0 */ |
342 | hi3670_apb_phy_updatel(phy, val: 0, PCIE_PHY_MMC1PLL_DISABLE, |
343 | SOC_PCIEPHY_MMC1PLL_CTRL16); |
344 | |
345 | /* choose FNPLL */ |
346 | val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_MMC1PLL_STAT0); |
347 | while (!(val & FNPLL_HAS_LOCKED)) { |
348 | if (!time) { |
349 | dev_err(dev, "wait for pll_lock timeout\n" ); |
350 | return -EINVAL; |
351 | } |
352 | time--; |
353 | udelay(1); |
354 | val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_MMC1PLL_STAT0); |
355 | } |
356 | |
357 | hi3670_apb_phy_updatel(phy, val: 0, PCIE_PHY_PCIEPL_BP, |
358 | SOC_PCIEPHY_MMC1PLL_CTRL20); |
359 | |
360 | } else { |
361 | hi3670_apb_phy_updatel(phy, |
362 | PCIE_PHY_MMC1PLL_DISABLE, |
363 | PCIE_PHY_MMC1PLL_DISABLE, |
364 | SOC_PCIEPHY_MMC1PLL_CTRL16); |
365 | |
366 | hi3670_apb_phy_updatel(phy, PCIE_PHY_PCIEPL_BP, |
367 | PCIE_PHY_PCIEPL_BP, |
368 | SOC_PCIEPHY_MMC1PLL_CTRL20); |
369 | } |
370 | |
371 | return 0; |
372 | } |
373 | |
374 | static void hi3670_pcie_hp_debounce_gt(struct hi3670_pcie_phy *phy, bool open) |
375 | { |
376 | if (open) |
377 | /* gt_clk_pcie_hp/gt_clk_pcie_debounce open */ |
378 | regmap_write(map: phy->crgctrl, CRGPERIPH_PEREN12, |
379 | IO_HP_DEBOUNCE_GT); |
380 | else |
381 | /* gt_clk_pcie_hp/gt_clk_pcie_debounce close */ |
382 | regmap_write(map: phy->crgctrl, CRGPERIPH_PERDIS12, |
383 | IO_HP_DEBOUNCE_GT); |
384 | } |
385 | |
386 | static void hi3670_pcie_phyref_gt(struct hi3670_pcie_phy *phy, bool open) |
387 | { |
388 | unsigned int val; |
389 | |
390 | regmap_read(map: phy->crgctrl, CRGPERIPH_PCIECTRL0, val: &val); |
391 | |
392 | if (open) |
393 | val &= ~IO_OE_HARD_GT_MODE; /* enable hard gt mode */ |
394 | else |
395 | val |= IO_OE_HARD_GT_MODE; /* disable hard gt mode */ |
396 | |
397 | regmap_write(map: phy->crgctrl, CRGPERIPH_PCIECTRL0, val); |
398 | |
399 | /* disable soft gt mode */ |
400 | regmap_write(map: phy->crgctrl, CRGPERIPH_PERDIS12, IO_PHYREF_SOFT_GT_MODE); |
401 | } |
402 | |
403 | static void hi3670_pcie_oe_ctrl(struct hi3670_pcie_phy *phy, bool en_flag) |
404 | { |
405 | unsigned int val; |
406 | |
407 | regmap_read(map: phy->crgctrl, CRGPERIPH_PCIECTRL0, val: &val); |
408 | |
409 | /* set ie cfg */ |
410 | val |= IO_IE_EN_HARD_BYPASS; |
411 | |
412 | /* set oe cfg */ |
413 | val &= ~IO_HARD_CTRL_DEBOUNCE_BYPASS; |
414 | |
415 | /* set phy_debounce in&out time */ |
416 | val |= (DEBOUNCE_WAITCFG_IN | DEBOUNCE_WAITCFG_OUT); |
417 | |
418 | /* select oe_gt_mode */ |
419 | val |= IO_OE_GT_MODE; |
420 | |
421 | if (en_flag) |
422 | val &= ~IO_OE_EN_HARD_BYPASS; |
423 | else |
424 | val |= IO_OE_EN_HARD_BYPASS; |
425 | |
426 | regmap_write(map: phy->crgctrl, CRGPERIPH_PCIECTRL0, val); |
427 | } |
428 | |
429 | static void hi3670_pcie_ioref_gt(struct hi3670_pcie_phy *phy, bool open) |
430 | { |
431 | unsigned int val; |
432 | |
433 | if (open) { |
434 | regmap_write(map: phy->apb, SOC_PCIECTRL_CTRL21_ADDR, |
435 | SOC_PCIECTRL_CTRL21_DEFAULT); |
436 | |
437 | hi3670_pcie_oe_ctrl(phy, en_flag: true); |
438 | |
439 | /* en hard gt mode */ |
440 | regmap_read(map: phy->crgctrl, CRGPERIPH_PCIECTRL0, val: &val); |
441 | val &= ~IO_REF_HARD_GT_MODE; |
442 | regmap_write(map: phy->crgctrl, CRGPERIPH_PCIECTRL0, val); |
443 | |
444 | /* disable soft gt mode */ |
445 | regmap_write(map: phy->crgctrl, CRGPERIPH_PERDIS12, |
446 | IO_REF_SOFT_GT_MODE); |
447 | |
448 | } else { |
449 | /* disable hard gt mode */ |
450 | regmap_read(map: phy->crgctrl, CRGPERIPH_PCIECTRL0, val: &val); |
451 | val |= IO_REF_HARD_GT_MODE; |
452 | regmap_write(map: phy->crgctrl, CRGPERIPH_PCIECTRL0, val); |
453 | |
454 | /* disable soft gt mode */ |
455 | regmap_write(map: phy->crgctrl, CRGPERIPH_PERDIS12, |
456 | IO_REF_SOFT_GT_MODE); |
457 | |
458 | hi3670_pcie_oe_ctrl(phy, en_flag: false); |
459 | } |
460 | } |
461 | |
462 | static int hi3670_pcie_allclk_ctrl(struct hi3670_pcie_phy *phy, bool clk_on) |
463 | { |
464 | struct device *dev = phy->dev; |
465 | int ret = 0; |
466 | |
467 | if (!clk_on) |
468 | goto close_clocks; |
469 | |
470 | /* choose 100MHz clk src: Bit[8]==1 pad, Bit[8]==0 pll */ |
471 | hi3670_apb_phy_updatel(phy, val: 0, PCIE_CLK_SOURCE, |
472 | SOC_PCIEPHY_CTRL1_ADDR); |
473 | |
474 | hi3670_pcie_pll_init(phy); |
475 | |
476 | ret = hi3670_pcie_pll_ctrl(phy, enable: true); |
477 | if (ret) { |
478 | dev_err(dev, "Failed to enable pll\n" ); |
479 | return -EINVAL; |
480 | } |
481 | hi3670_pcie_hp_debounce_gt(phy, open: true); |
482 | hi3670_pcie_phyref_gt(phy, open: true); |
483 | hi3670_pcie_ioref_gt(phy, open: true); |
484 | |
485 | ret = clk_set_rate(clk: phy->aclk, AXI_CLK_FREQ); |
486 | if (ret) { |
487 | dev_err(dev, "Failed to set rate\n" ); |
488 | goto close_clocks; |
489 | } |
490 | |
491 | return 0; |
492 | |
493 | close_clocks: |
494 | hi3670_pcie_ioref_gt(phy, open: false); |
495 | hi3670_pcie_phyref_gt(phy, open: false); |
496 | hi3670_pcie_hp_debounce_gt(phy, open: false); |
497 | |
498 | hi3670_pcie_pll_ctrl(phy, enable: false); |
499 | |
500 | return ret; |
501 | } |
502 | |
503 | static bool is_pipe_clk_stable(struct hi3670_pcie_phy *phy) |
504 | { |
505 | struct device *dev = phy->dev; |
506 | u32 val; |
507 | u32 time = PIPE_CLK_STABLE_TIME; |
508 | u32 pipe_clk_stable = PCIE_IS_CLOCK_STABLE; |
509 | |
510 | val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_STATE0_ADDR); |
511 | while (val & pipe_clk_stable) { |
512 | mdelay(1); |
513 | if (!time) { |
514 | dev_err(dev, "PIPE clk is not stable\n" ); |
515 | return false; |
516 | } |
517 | time--; |
518 | val = hi3670_apb_phy_readl(phy, SOC_PCIEPHY_STATE0_ADDR); |
519 | } |
520 | |
521 | return true; |
522 | } |
523 | |
524 | static int hi3670_pcie_noc_power(struct hi3670_pcie_phy *phy, bool enable) |
525 | { |
526 | struct device *dev = phy->dev; |
527 | u32 time = NOC_POWER_TIME; |
528 | unsigned int val = NOC_PW_MASK; |
529 | int rst; |
530 | |
531 | if (enable) |
532 | val = NOC_PW_MASK | NOC_PW_SET_BIT; |
533 | else |
534 | val = NOC_PW_MASK; |
535 | rst = enable ? 1 : 0; |
536 | |
537 | regmap_write(map: phy->pmctrl, NOC_POWER_IDLEREQ_1, val); |
538 | |
539 | time = NOC_POWER_TIME; |
540 | regmap_read(map: phy->pmctrl, NOC_POWER_IDLE_1, val: &val); |
541 | while ((val & NOC_PW_SET_BIT) != rst) { |
542 | udelay(10); |
543 | if (!time) { |
544 | dev_err(dev, "Failed to reverse noc power-status\n" ); |
545 | return -EINVAL; |
546 | } |
547 | time--; |
548 | regmap_read(map: phy->pmctrl, NOC_POWER_IDLE_1, val: &val); |
549 | } |
550 | |
551 | return 0; |
552 | } |
553 | |
554 | static int hi3670_pcie_get_resources_from_pcie(struct hi3670_pcie_phy *phy) |
555 | { |
556 | struct device_node *pcie_port; |
557 | struct device *dev = phy->dev; |
558 | struct device *pcie_dev; |
559 | |
560 | pcie_port = of_get_child_by_name(node: dev->parent->of_node, name: "pcie" ); |
561 | if (!pcie_port) { |
562 | dev_err(dev, "no pcie node found in %s\n" , |
563 | dev->parent->of_node->full_name); |
564 | return -ENODEV; |
565 | } |
566 | |
567 | pcie_dev = bus_find_device_by_of_node(bus: &platform_bus_type, np: pcie_port); |
568 | if (!pcie_dev) { |
569 | dev_err(dev, "Didn't find pcie device\n" ); |
570 | return -ENODEV; |
571 | } |
572 | |
573 | /* |
574 | * We might just use NULL instead of the APB name, as the |
575 | * pcie-kirin currently registers directly just one regmap (although |
576 | * the DWC driver register other regmaps). |
577 | * |
578 | * Yet, it sounds safer to warrant that it will be accessing the |
579 | * right regmap. So, let's use the named version. |
580 | */ |
581 | phy->apb = dev_get_regmap(dev: pcie_dev, name: "kirin_pcie_apb" ); |
582 | if (!phy->apb) { |
583 | dev_err(dev, "Failed to get APB regmap\n" ); |
584 | return -ENODEV; |
585 | } |
586 | |
587 | return 0; |
588 | } |
589 | |
590 | static int kirin_pcie_clk_ctrl(struct hi3670_pcie_phy *phy, bool enable) |
591 | { |
592 | int ret = 0; |
593 | |
594 | if (!enable) |
595 | goto close_clk; |
596 | |
597 | ret = clk_set_rate(clk: phy->phy_ref_clk, REF_CLK_FREQ); |
598 | if (ret) |
599 | return ret; |
600 | |
601 | ret = clk_prepare_enable(clk: phy->phy_ref_clk); |
602 | if (ret) |
603 | return ret; |
604 | |
605 | ret = clk_prepare_enable(clk: phy->apb_sys_clk); |
606 | if (ret) |
607 | goto apb_sys_fail; |
608 | |
609 | ret = clk_prepare_enable(clk: phy->apb_phy_clk); |
610 | if (ret) |
611 | goto apb_phy_fail; |
612 | |
613 | ret = clk_prepare_enable(clk: phy->aclk); |
614 | if (ret) |
615 | goto aclk_fail; |
616 | |
617 | ret = clk_prepare_enable(clk: phy->aux_clk); |
618 | if (ret) |
619 | goto aux_clk_fail; |
620 | |
621 | return 0; |
622 | |
623 | close_clk: |
624 | clk_disable_unprepare(clk: phy->aux_clk); |
625 | aux_clk_fail: |
626 | clk_disable_unprepare(clk: phy->aclk); |
627 | aclk_fail: |
628 | clk_disable_unprepare(clk: phy->apb_phy_clk); |
629 | apb_phy_fail: |
630 | clk_disable_unprepare(clk: phy->apb_sys_clk); |
631 | apb_sys_fail: |
632 | clk_disable_unprepare(clk: phy->phy_ref_clk); |
633 | |
634 | return ret; |
635 | } |
636 | |
637 | static int hi3670_pcie_phy_init(struct phy *generic_phy) |
638 | { |
639 | struct hi3670_pcie_phy *phy = phy_get_drvdata(phy: generic_phy); |
640 | int ret; |
641 | |
642 | /* |
643 | * The code under hi3670_pcie_get_resources_from_pcie() need to |
644 | * access the reset-gpios and the APB registers, both from the |
645 | * pcie-kirin driver. |
646 | * |
647 | * The APB is obtained via the pcie driver's regmap |
648 | * Such kind of resource can only be obtained during the PCIe |
649 | * power_on sequence, as the code inside pcie-kirin needs to |
650 | * be already probed, as it needs to register the APB regmap. |
651 | */ |
652 | |
653 | ret = hi3670_pcie_get_resources_from_pcie(phy); |
654 | if (ret) |
655 | return ret; |
656 | |
657 | return 0; |
658 | } |
659 | |
660 | static int hi3670_pcie_phy_power_on(struct phy *generic_phy) |
661 | { |
662 | struct hi3670_pcie_phy *phy = phy_get_drvdata(phy: generic_phy); |
663 | int val, ret; |
664 | |
665 | /* Power supply for Host */ |
666 | regmap_write(map: phy->sysctrl, SCTRL_PCIE_CMOS_OFFSET, SCTRL_PCIE_CMOS_BIT); |
667 | usleep_range(TIME_CMOS_MIN, TIME_CMOS_MAX); |
668 | |
669 | hi3670_pcie_phy_oe_enable(phy, enable: true); |
670 | |
671 | ret = kirin_pcie_clk_ctrl(phy, enable: true); |
672 | if (ret) |
673 | return ret; |
674 | |
675 | /* ISO disable, PCIeCtrl, PHY assert and clk gate clear */ |
676 | regmap_write(map: phy->sysctrl, SCTRL_PCIE_ISO_OFFSET, SCTRL_PCIE_ISO_BIT); |
677 | regmap_write(map: phy->crgctrl, CRGCTRL_PCIE_ASSERT_OFFSET, |
678 | CRGCTRL_PCIE_ASSERT_BIT); |
679 | regmap_write(map: phy->sysctrl, SCTRL_PCIE_HPCLK_OFFSET, |
680 | SCTRL_PCIE_HPCLK_BIT); |
681 | |
682 | hi3670_pcie_natural_cfg(phy); |
683 | |
684 | ret = hi3670_pcie_allclk_ctrl(phy, clk_on: true); |
685 | if (ret) |
686 | goto disable_clks; |
687 | |
688 | /* pull down phy_test_powerdown signal */ |
689 | hi3670_apb_phy_updatel(phy, val: 0, PCIE_PULL_DOWN_PHY_TEST_POWERDOWN, |
690 | SOC_PCIEPHY_CTRL0_ADDR); |
691 | |
692 | /* deassert controller perst_n */ |
693 | regmap_read(map: phy->apb, SOC_PCIECTRL_CTRL12_ADDR, val: &val); |
694 | val |= PCIE_DEASSERT_CONTROLLER_PERST; |
695 | regmap_write(map: phy->apb, SOC_PCIECTRL_CTRL12_ADDR, val); |
696 | udelay(10); |
697 | |
698 | ret = is_pipe_clk_stable(phy); |
699 | if (!ret) |
700 | goto disable_clks; |
701 | |
702 | hi3670_pcie_set_eyeparam(phy); |
703 | |
704 | ret = hi3670_pcie_noc_power(phy, enable: false); |
705 | if (ret) |
706 | goto disable_clks; |
707 | |
708 | return 0; |
709 | |
710 | disable_clks: |
711 | kirin_pcie_clk_ctrl(phy, enable: false); |
712 | return ret; |
713 | } |
714 | |
715 | static int hi3670_pcie_phy_power_off(struct phy *generic_phy) |
716 | { |
717 | struct hi3670_pcie_phy *phy = phy_get_drvdata(phy: generic_phy); |
718 | |
719 | hi3670_pcie_phy_oe_enable(phy, enable: false); |
720 | |
721 | hi3670_pcie_allclk_ctrl(phy, clk_on: false); |
722 | |
723 | /* Drop power supply for Host */ |
724 | regmap_write(map: phy->sysctrl, SCTRL_PCIE_CMOS_OFFSET, val: 0); |
725 | |
726 | /* |
727 | * FIXME: The enabled clocks should be disabled here by calling |
728 | * kirin_pcie_clk_ctrl(phy, false); |
729 | * However, some clocks used at Kirin 970 should be marked as |
730 | * CLK_IS_CRITICAL at clk-hi3670 driver, as powering such clocks off |
731 | * cause an Asynchronous SError interrupt, which produces panic(). |
732 | * While clk-hi3670 is not fixed, we cannot risk disabling clocks here. |
733 | */ |
734 | |
735 | return 0; |
736 | } |
737 | |
738 | static const struct phy_ops hi3670_phy_ops = { |
739 | .init = hi3670_pcie_phy_init, |
740 | .power_on = hi3670_pcie_phy_power_on, |
741 | .power_off = hi3670_pcie_phy_power_off, |
742 | .owner = THIS_MODULE, |
743 | }; |
744 | |
745 | static int hi3670_pcie_phy_get_resources(struct hi3670_pcie_phy *phy, |
746 | struct platform_device *pdev) |
747 | { |
748 | struct device *dev = &pdev->dev; |
749 | |
750 | /* syscon */ |
751 | phy->crgctrl = syscon_regmap_lookup_by_compatible(s: "hisilicon,hi3670-crgctrl" ); |
752 | if (IS_ERR(ptr: phy->crgctrl)) |
753 | return PTR_ERR(ptr: phy->crgctrl); |
754 | |
755 | phy->sysctrl = syscon_regmap_lookup_by_compatible(s: "hisilicon,hi3670-sctrl" ); |
756 | if (IS_ERR(ptr: phy->sysctrl)) |
757 | return PTR_ERR(ptr: phy->sysctrl); |
758 | |
759 | phy->pmctrl = syscon_regmap_lookup_by_compatible(s: "hisilicon,hi3670-pmctrl" ); |
760 | if (IS_ERR(ptr: phy->pmctrl)) |
761 | return PTR_ERR(ptr: phy->pmctrl); |
762 | |
763 | /* clocks */ |
764 | phy->phy_ref_clk = devm_clk_get(dev, id: "phy_ref" ); |
765 | if (IS_ERR(ptr: phy->phy_ref_clk)) |
766 | return PTR_ERR(ptr: phy->phy_ref_clk); |
767 | |
768 | phy->aux_clk = devm_clk_get(dev, id: "aux" ); |
769 | if (IS_ERR(ptr: phy->aux_clk)) |
770 | return PTR_ERR(ptr: phy->aux_clk); |
771 | |
772 | phy->apb_phy_clk = devm_clk_get(dev, id: "apb_phy" ); |
773 | if (IS_ERR(ptr: phy->apb_phy_clk)) |
774 | return PTR_ERR(ptr: phy->apb_phy_clk); |
775 | |
776 | phy->apb_sys_clk = devm_clk_get(dev, id: "apb_sys" ); |
777 | if (IS_ERR(ptr: phy->apb_sys_clk)) |
778 | return PTR_ERR(ptr: phy->apb_sys_clk); |
779 | |
780 | phy->aclk = devm_clk_get(dev, id: "aclk" ); |
781 | if (IS_ERR(ptr: phy->aclk)) |
782 | return PTR_ERR(ptr: phy->aclk); |
783 | |
784 | /* registers */ |
785 | phy->base = devm_platform_ioremap_resource(pdev, index: 0); |
786 | if (IS_ERR(ptr: phy->base)) |
787 | return PTR_ERR(ptr: phy->base); |
788 | |
789 | hi3670_pcie_get_eyeparam(phy); |
790 | |
791 | return 0; |
792 | } |
793 | |
794 | static int hi3670_pcie_phy_probe(struct platform_device *pdev) |
795 | { |
796 | struct phy_provider *phy_provider; |
797 | struct device *dev = &pdev->dev; |
798 | struct hi3670_pcie_phy *phy; |
799 | struct phy *generic_phy; |
800 | int ret; |
801 | |
802 | phy = devm_kzalloc(dev, size: sizeof(*phy), GFP_KERNEL); |
803 | if (!phy) |
804 | return -ENOMEM; |
805 | |
806 | phy->dev = dev; |
807 | |
808 | ret = hi3670_pcie_phy_get_resources(phy, pdev); |
809 | if (ret) |
810 | return ret; |
811 | |
812 | generic_phy = devm_phy_create(dev, node: dev->of_node, ops: &hi3670_phy_ops); |
813 | if (IS_ERR(ptr: generic_phy)) { |
814 | dev_err(dev, "failed to create PHY\n" ); |
815 | return PTR_ERR(ptr: generic_phy); |
816 | } |
817 | |
818 | phy_set_drvdata(phy: generic_phy, data: phy); |
819 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
820 | |
821 | return PTR_ERR_OR_ZERO(ptr: phy_provider); |
822 | } |
823 | |
824 | static const struct of_device_id hi3670_pcie_phy_match[] = { |
825 | { |
826 | .compatible = "hisilicon,hi970-pcie-phy" , |
827 | }, |
828 | {}, |
829 | }; |
830 | |
831 | static struct platform_driver hi3670_pcie_phy_driver = { |
832 | .probe = hi3670_pcie_phy_probe, |
833 | .driver = { |
834 | .of_match_table = hi3670_pcie_phy_match, |
835 | .name = "hi3670_pcie_phy" , |
836 | .suppress_bind_attrs = true, |
837 | } |
838 | }; |
839 | builtin_platform_driver(hi3670_pcie_phy_driver); |
840 | |
841 | MODULE_DEVICE_TABLE(of, hi3670_pcie_phy_match); |
842 | MODULE_DESCRIPTION("PCIe phy driver for Kirin 970" ); |
843 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>" ); |
844 | MODULE_AUTHOR("Manivannan Sadhasivam <mani@kernel.org>" ); |
845 | MODULE_LICENSE("GPL v2" ); |
846 | |