1 // SPDX-License-Identifier: GPL-2.0-only
3 * STMicroelectronics COMBOPHY STM32MP25 Controller driver.
5 * Copyright (C) 2024 STMicroelectronics
6 * Author: Christian Bruel <christian.bruel@foss.st.com>
9 #include <linux/bitfield.h>
10 #include <linux/clk.h>
11 #include <linux/mfd/syscon.h>
12 #include <linux/platform_device.h>
13 #include <linux/phy/phy.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/regmap.h>
16 #include <linux/reset.h>
17 #include <dt-bindings/phy/phy.h>
19 #define SYSCFG_COMBOPHY_CR1 0x4c00
20 #define SYSCFG_COMBOPHY_CR2 0x4c04
21 #define SYSCFG_COMBOPHY_CR4 0x4c0c
22 #define SYSCFG_COMBOPHY_CR5 0x4c10
23 #define SYSCFG_COMBOPHY_SR 0x4c14
24 #define SYSCFG_PCIEPRGCR 0x6080
26 /* SYSCFG PCIEPRGCR */
27 #define STM32MP25_PCIEPRGCR_EN BIT(0)
28 #define STM32MP25_PCIEPRG_IMPCTRL_OHM GENMASK(3, 1)
29 #define STM32MP25_PCIEPRG_IMPCTRL_VSWING GENMASK(5, 4)
31 /* SYSCFG SYSCFG_COMBOPHY_SR */
32 #define STM32MP25_PIPE0_PHYSTATUS BIT(1)
35 #define SYSCFG_COMBOPHY_CR1_REFUSEPAD BIT(0)
36 #define SYSCFG_COMBOPHY_CR1_MPLLMULT GENMASK(7, 1)
37 #define SYSCFG_COMBOPHY_CR1_REFCLKSEL GENMASK(16, 8)
38 #define SYSCFG_COMBOPHY_CR1_REFCLKDIV2 BIT(17)
39 #define SYSCFG_COMBOPHY_CR1_REFSSPEN BIT(18)
40 #define SYSCFG_COMBOPHY_CR1_SSCEN BIT(19)
43 #define SYSCFG_COMBOPHY_CR4_RX0_EQ GENMASK(2, 0)
45 #define MPLLMULT_19_2 (0x02u << 1)
46 #define MPLLMULT_20 (0x7du << 1)
47 #define MPLLMULT_24 (0x68u << 1)
48 #define MPLLMULT_25 (0x64u << 1)
49 #define MPLLMULT_26 (0x60u << 1)
50 #define MPLLMULT_38_4 (0x41u << 1)
51 #define MPLLMULT_48 (0x6cu << 1)
52 #define MPLLMULT_50 (0x32u << 1)
53 #define MPLLMULT_52 (0x30u << 1)
54 #define MPLLMULT_100 (0x19u << 1)
57 #define REFCLKSEL_1 (0x108u << 8)
62 #define SYSCFG_COMBOPHY_CR2_MODESEL GENMASK(1, 0)
63 #define SYSCFG_COMBOPHY_CR2_ISO_DIS BIT(15)
65 #define COMBOPHY_MODESEL_PCIE 0
66 #define COMBOPHY_MODESEL_USB 3
69 #define SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS BIT(12)
71 #define COMBOPHY_SUP_ANA_MPLL_LOOP_CTL 0xc0
72 #define COMBOPHY_PROP_CNTRL GENMASK(7, 4)
74 /* Required apb/ker clocks first, optional pad last. */
75 static const char * const combophy_clks
[] = {"apb", "ker", "pad"};
80 struct stm32_combophy
{
82 struct regmap
*regmap
;
85 struct reset_control
*phy_reset
;
86 struct clk_bulk_data clks
[ARRAY_SIZE(combophy_clks
)];
94 struct clk_impedance
{
100 * lookup table to hold the settings needed for a ref clock frequency
101 * impedance, the offset is used to set the IMP_CTL and DE_EMP bit of the
102 * PRG_IMP_CTRL register. Use ordered discrete values in the table
104 static const struct clk_impedance imp_lookup
[] = {
105 { 6090000, { 442000, 564000, 684000, 802000 } },
106 { 5662000, { 528000, 621000, 712000, 803000 } },
107 { 5292000, { 491000, 596000, 700000, 802000 } },
108 { 4968000, { 558000, 640000, 722000, 803000 } },
109 { 4684000, { 468000, 581000, 692000, 802000 } },
110 { 4429000, { 554000, 613000, 717000, 803000 } },
111 { 4204000, { 511000, 609000, 706000, 802000 } },
112 { 3999000, { 571000, 648000, 726000, 803000 } }
115 static int stm32_impedance_tune(struct stm32_combophy
*combophy
)
117 u8 imp_size
= ARRAY_SIZE(imp_lookup
);
118 u8 vswing_size
= ARRAY_SIZE(imp_lookup
[0].vswing
);
119 u8 imp_of
, vswing_of
;
120 u32 max_imp
= imp_lookup
[0].microohm
;
121 u32 min_imp
= imp_lookup
[imp_size
- 1].microohm
;
122 u32 max_vswing
= imp_lookup
[imp_size
- 1].vswing
[vswing_size
- 1];
123 u32 min_vswing
= imp_lookup
[0].vswing
[0];
126 if (!of_property_read_u32(combophy
->dev
->of_node
, "st,output-micro-ohms", &val
)) {
127 if (val
< min_imp
|| val
> max_imp
) {
128 dev_err(combophy
->dev
, "Invalid value %u for output ohm\n", val
);
132 for (imp_of
= 0; imp_of
< ARRAY_SIZE(imp_lookup
); imp_of
++)
133 if (imp_lookup
[imp_of
].microohm
<= val
)
136 dev_dbg(combophy
->dev
, "Set %u micro-ohms output impedance\n",
137 imp_lookup
[imp_of
].microohm
);
139 regmap_update_bits(combophy
->regmap
, SYSCFG_PCIEPRGCR
,
140 STM32MP25_PCIEPRG_IMPCTRL_OHM
,
141 FIELD_PREP(STM32MP25_PCIEPRG_IMPCTRL_OHM
, imp_of
));
143 regmap_read(combophy
->regmap
, SYSCFG_PCIEPRGCR
, &val
);
144 imp_of
= FIELD_GET(STM32MP25_PCIEPRG_IMPCTRL_OHM
, val
);
147 if (!of_property_read_u32(combophy
->dev
->of_node
, "st,output-vswing-microvolt", &val
)) {
148 if (val
< min_vswing
|| val
> max_vswing
) {
149 dev_err(combophy
->dev
, "Invalid value %u for output vswing\n", val
);
153 for (vswing_of
= 0; vswing_of
< ARRAY_SIZE(imp_lookup
[imp_of
].vswing
); vswing_of
++)
154 if (imp_lookup
[imp_of
].vswing
[vswing_of
] >= val
)
157 dev_dbg(combophy
->dev
, "Set %u microvolt swing\n",
158 imp_lookup
[imp_of
].vswing
[vswing_of
]);
160 regmap_update_bits(combophy
->regmap
, SYSCFG_PCIEPRGCR
,
161 STM32MP25_PCIEPRG_IMPCTRL_VSWING
,
162 FIELD_PREP(STM32MP25_PCIEPRG_IMPCTRL_VSWING
, vswing_of
));
168 static int stm32_combophy_pll_init(struct stm32_combophy
*combophy
)
171 u32 refclksel
, pllmult
, propcntrl
, val
;
174 u32 cr1_val
= 0, cr1_mask
= 0;
176 if (combophy
->have_pad_clk
)
177 clk
= combophy
->clks
[PAD_CLK
].clk
;
179 clk
= combophy
->clks
[KER_CLK
].clk
;
181 clk_rate
= clk_get_rate(clk
);
183 dev_dbg(combophy
->dev
, "%s pll init rate %d\n",
184 combophy
->have_pad_clk
? "External" : "Ker", clk_rate
);
186 if (combophy
->type
!= PHY_TYPE_PCIE
) {
187 cr1_mask
|= SYSCFG_COMBOPHY_CR1_REFSSPEN
;
188 cr1_val
|= SYSCFG_COMBOPHY_CR1_REFSSPEN
;
191 if (of_property_present(combophy
->dev
->of_node
, "st,ssc-on")) {
192 dev_dbg(combophy
->dev
, "Enabling clock with SSC\n");
193 cr1_mask
|= SYSCFG_COMBOPHY_CR1_SSCEN
;
194 cr1_val
|= SYSCFG_COMBOPHY_CR1_SSCEN
;
199 pllmult
= MPLLMULT_100
;
200 refclksel
= REFCLKSEL_0
;
201 propcntrl
= 0x8u
<< 4;
204 pllmult
= MPLLMULT_19_2
;
205 refclksel
= REFCLKSEL_1
;
206 propcntrl
= 0x8u
<< 4;
209 pllmult
= MPLLMULT_25
;
210 refclksel
= REFCLKSEL_0
;
211 propcntrl
= 0xeu
<< 4;
214 pllmult
= MPLLMULT_24
;
215 refclksel
= REFCLKSEL_1
;
216 propcntrl
= 0xeu
<< 4;
219 pllmult
= MPLLMULT_20
;
220 refclksel
= REFCLKSEL_0
;
221 propcntrl
= 0xeu
<< 4;
224 dev_err(combophy
->dev
, "Invalid rate 0x%x\n", clk_rate
);
228 cr1_mask
|= SYSCFG_COMBOPHY_CR1_REFCLKDIV2
;
229 cr1_val
|= REFCLDIV_0
;
231 cr1_mask
|= SYSCFG_COMBOPHY_CR1_REFCLKSEL
;
232 cr1_val
|= refclksel
;
234 cr1_mask
|= SYSCFG_COMBOPHY_CR1_MPLLMULT
;
238 * vddcombophy is interconnected with vddcore. Isolation bit should be unset
239 * before using the ComboPHY.
241 regmap_update_bits(combophy
->regmap
, SYSCFG_COMBOPHY_CR2
,
242 SYSCFG_COMBOPHY_CR2_ISO_DIS
, SYSCFG_COMBOPHY_CR2_ISO_DIS
);
244 reset_control_assert(combophy
->phy_reset
);
246 if (combophy
->type
== PHY_TYPE_PCIE
) {
247 ret
= stm32_impedance_tune(combophy
);
251 cr1_mask
|= SYSCFG_COMBOPHY_CR1_REFUSEPAD
;
252 cr1_val
|= combophy
->have_pad_clk
? SYSCFG_COMBOPHY_CR1_REFUSEPAD
: 0;
255 if (!of_property_read_u32(combophy
->dev
->of_node
, "st,rx-equalizer", &val
)) {
256 dev_dbg(combophy
->dev
, "Set RX equalizer %u\n", val
);
257 if (val
> SYSCFG_COMBOPHY_CR4_RX0_EQ
) {
258 dev_err(combophy
->dev
, "Invalid value %u for rx0 equalizer\n", val
);
263 regmap_update_bits(combophy
->regmap
, SYSCFG_COMBOPHY_CR4
,
264 SYSCFG_COMBOPHY_CR4_RX0_EQ
, val
);
267 regmap_update_bits(combophy
->regmap
, SYSCFG_COMBOPHY_CR1
, cr1_mask
, cr1_val
);
270 * Force elasticity buffer to be tuned for the reference clock as
271 * the separated clock model is not supported
273 regmap_update_bits(combophy
->regmap
, SYSCFG_COMBOPHY_CR5
,
274 SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS
, SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS
);
276 reset_control_deassert(combophy
->phy_reset
);
278 ret
= regmap_read_poll_timeout(combophy
->regmap
, SYSCFG_COMBOPHY_SR
, val
,
279 !(val
& STM32MP25_PIPE0_PHYSTATUS
),
282 dev_err(combophy
->dev
, "timeout, cannot lock PLL\n");
283 if (combophy
->type
== PHY_TYPE_PCIE
&& !combophy
->have_pad_clk
)
284 regmap_update_bits(combophy
->regmap
, SYSCFG_PCIEPRGCR
,
285 STM32MP25_PCIEPRGCR_EN
, 0);
287 if (combophy
->type
!= PHY_TYPE_PCIE
)
288 regmap_update_bits(combophy
->regmap
, SYSCFG_COMBOPHY_CR1
,
289 SYSCFG_COMBOPHY_CR1_REFSSPEN
, 0);
295 if (combophy
->type
== PHY_TYPE_PCIE
) {
296 if (!combophy
->have_pad_clk
)
297 regmap_update_bits(combophy
->regmap
, SYSCFG_PCIEPRGCR
,
298 STM32MP25_PCIEPRGCR_EN
, STM32MP25_PCIEPRGCR_EN
);
300 val
= readl_relaxed(combophy
->base
+ COMBOPHY_SUP_ANA_MPLL_LOOP_CTL
);
301 val
&= ~COMBOPHY_PROP_CNTRL
;
303 writel_relaxed(val
, combophy
->base
+ COMBOPHY_SUP_ANA_MPLL_LOOP_CTL
);
309 reset_control_deassert(combophy
->phy_reset
);
312 regmap_update_bits(combophy
->regmap
, SYSCFG_COMBOPHY_CR2
,
313 SYSCFG_COMBOPHY_CR2_ISO_DIS
, 0);
318 static struct phy
*stm32_combophy_xlate(struct device
*dev
,
319 const struct of_phandle_args
*args
)
321 struct stm32_combophy
*combophy
= dev_get_drvdata(dev
);
324 if (args
->args_count
!= 1) {
325 dev_err(dev
, "invalid number of cells in 'phy' property\n");
326 return ERR_PTR(-EINVAL
);
329 type
= args
->args
[0];
330 if (type
!= PHY_TYPE_USB3
&& type
!= PHY_TYPE_PCIE
) {
331 dev_err(dev
, "unsupported device type: %d\n", type
);
332 return ERR_PTR(-EINVAL
);
335 if (combophy
->have_pad_clk
&& type
!= PHY_TYPE_PCIE
) {
336 dev_err(dev
, "Invalid use of clk_pad for USB3 mode\n");
337 return ERR_PTR(-EINVAL
);
340 combophy
->type
= type
;
342 return combophy
->phy
;
345 static int stm32_combophy_set_mode(struct stm32_combophy
*combophy
)
347 int type
= combophy
->type
;
352 dev_dbg(combophy
->dev
, "setting PCIe ComboPHY\n");
353 val
= COMBOPHY_MODESEL_PCIE
;
356 dev_dbg(combophy
->dev
, "setting USB3 ComboPHY\n");
357 val
= COMBOPHY_MODESEL_USB
;
360 dev_err(combophy
->dev
, "Invalid PHY mode %d\n", type
);
364 return regmap_update_bits(combophy
->regmap
, SYSCFG_COMBOPHY_CR2
,
365 SYSCFG_COMBOPHY_CR2_MODESEL
, val
);
368 static int stm32_combophy_suspend_noirq(struct device
*dev
)
370 struct stm32_combophy
*combophy
= dev_get_drvdata(dev
);
373 * Clocks should be turned off since it is not needed for
374 * wakeup capability. In case usb-remote wakeup is not enabled,
375 * combo-phy is already turned off by HCD driver using exit callback
377 if (combophy
->is_init
) {
378 clk_bulk_disable_unprepare(combophy
->num_clks
, combophy
->clks
);
380 /* since wakeup is enabled for ctrl */
381 enable_irq_wake(combophy
->irq_wakeup
);
387 static int stm32_combophy_resume_noirq(struct device
*dev
)
389 struct stm32_combophy
*combophy
= dev_get_drvdata(dev
);
393 * If clocks was turned off by suspend call for wakeup then needs
394 * to be turned back ON in resume. In case usb-remote wakeup is not
395 * enabled, clocks already turned ON by HCD driver using init callback
397 if (combophy
->is_init
) {
398 /* since wakeup was enabled for ctrl */
399 disable_irq_wake(combophy
->irq_wakeup
);
401 ret
= clk_bulk_prepare_enable(combophy
->num_clks
, combophy
->clks
);
403 dev_err(dev
, "can't enable clocks (%d)\n", ret
);
411 static int stm32_combophy_exit(struct phy
*phy
)
413 struct stm32_combophy
*combophy
= phy_get_drvdata(phy
);
414 struct device
*dev
= combophy
->dev
;
416 combophy
->is_init
= false;
418 if (combophy
->type
== PHY_TYPE_PCIE
&& !combophy
->have_pad_clk
)
419 regmap_update_bits(combophy
->regmap
, SYSCFG_PCIEPRGCR
,
420 STM32MP25_PCIEPRGCR_EN
, 0);
422 if (combophy
->type
!= PHY_TYPE_PCIE
)
423 regmap_update_bits(combophy
->regmap
, SYSCFG_COMBOPHY_CR1
,
424 SYSCFG_COMBOPHY_CR1_REFSSPEN
, 0);
426 regmap_update_bits(combophy
->regmap
, SYSCFG_COMBOPHY_CR2
,
427 SYSCFG_COMBOPHY_CR2_ISO_DIS
, 0);
429 clk_bulk_disable_unprepare(combophy
->num_clks
, combophy
->clks
);
431 pm_runtime_put_noidle(dev
);
436 static int stm32_combophy_init(struct phy
*phy
)
438 struct stm32_combophy
*combophy
= phy_get_drvdata(phy
);
439 struct device
*dev
= combophy
->dev
;
442 pm_runtime_get_noresume(dev
);
444 ret
= clk_bulk_prepare_enable(combophy
->num_clks
, combophy
->clks
);
446 dev_err(dev
, "can't enable clocks (%d)\n", ret
);
447 pm_runtime_put_noidle(dev
);
451 ret
= stm32_combophy_set_mode(combophy
);
453 dev_err(dev
, "combophy mode not set\n");
454 clk_bulk_disable_unprepare(combophy
->num_clks
, combophy
->clks
);
455 pm_runtime_put_noidle(dev
);
459 ret
= stm32_combophy_pll_init(combophy
);
461 clk_bulk_disable_unprepare(combophy
->num_clks
, combophy
->clks
);
462 pm_runtime_put_noidle(dev
);
466 pm_runtime_disable(dev
);
467 pm_runtime_set_active(dev
);
468 pm_runtime_enable(dev
);
470 combophy
->is_init
= true;
475 static const struct phy_ops stm32_combophy_phy_data
= {
476 .init
= stm32_combophy_init
,
477 .exit
= stm32_combophy_exit
,
481 static irqreturn_t
stm32_combophy_irq_wakeup_handler(int irq
, void *dev_id
)
486 static int stm32_combophy_get_clocks(struct stm32_combophy
*combophy
)
490 for (i
= 0; i
< ARRAY_SIZE(combophy_clks
); i
++)
491 combophy
->clks
[i
].id
= combophy_clks
[i
];
493 combophy
->num_clks
= ARRAY_SIZE(combophy_clks
) - 1;
495 ret
= devm_clk_bulk_get(combophy
->dev
, combophy
->num_clks
, combophy
->clks
);
499 ret
= devm_clk_bulk_get_optional(combophy
->dev
, 1, combophy
->clks
+ combophy
->num_clks
);
503 if (combophy
->clks
[combophy
->num_clks
].clk
!= NULL
) {
504 combophy
->have_pad_clk
= true;
505 combophy
->num_clks
++;
511 static int stm32_combophy_probe(struct platform_device
*pdev
)
513 struct stm32_combophy
*combophy
;
514 struct device
*dev
= &pdev
->dev
;
515 struct phy_provider
*phy_provider
;
518 combophy
= devm_kzalloc(dev
, sizeof(*combophy
), GFP_KERNEL
);
524 dev_set_drvdata(dev
, combophy
);
526 combophy
->base
= devm_platform_ioremap_resource(pdev
, 0);
527 if (IS_ERR(combophy
->base
))
528 return PTR_ERR(combophy
->base
);
530 ret
= stm32_combophy_get_clocks(combophy
);
534 combophy
->phy_reset
= devm_reset_control_get_exclusive(dev
, "phy");
535 if (IS_ERR(combophy
->phy_reset
))
536 return dev_err_probe(dev
, PTR_ERR(combophy
->phy_reset
),
537 "Failed to get PHY reset\n");
539 combophy
->regmap
= syscon_regmap_lookup_by_compatible("st,stm32mp25-syscfg");
540 if (IS_ERR(combophy
->regmap
))
541 return dev_err_probe(dev
, PTR_ERR(combophy
->regmap
),
542 "No syscfg specified\n");
544 combophy
->phy
= devm_phy_create(dev
, NULL
, &stm32_combophy_phy_data
);
545 if (IS_ERR(combophy
->phy
))
546 return dev_err_probe(dev
, PTR_ERR(combophy
->phy
),
547 "failed to create PCIe/USB3 ComboPHY\n");
549 if (device_property_read_bool(dev
, "wakeup-source")) {
550 irq
= platform_get_irq(pdev
, 0);
552 return dev_err_probe(dev
, irq
, "failed to get IRQ\n");
553 combophy
->irq_wakeup
= irq
;
555 ret
= devm_request_threaded_irq(dev
, combophy
->irq_wakeup
, NULL
,
556 stm32_combophy_irq_wakeup_handler
, IRQF_ONESHOT
,
559 return dev_err_probe(dev
, ret
, "unable to request wake IRQ %d\n",
560 combophy
->irq_wakeup
);
563 ret
= devm_pm_runtime_enable(dev
);
565 return dev_err_probe(dev
, ret
, "Failed to enable pm runtime\n");
567 phy_set_drvdata(combophy
->phy
, combophy
);
569 phy_provider
= devm_of_phy_provider_register(dev
, stm32_combophy_xlate
);
571 return PTR_ERR_OR_ZERO(phy_provider
);
574 static const struct dev_pm_ops stm32_combophy_pm_ops
= {
575 NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_combophy_suspend_noirq
,
576 stm32_combophy_resume_noirq
)
579 static const struct of_device_id stm32_combophy_of_match
[] = {
580 { .compatible
= "st,stm32mp25-combophy", },
583 MODULE_DEVICE_TABLE(of
, stm32_combophy_of_match
);
585 static struct platform_driver stm32_combophy_driver
= {
586 .probe
= stm32_combophy_probe
,
588 .name
= "stm32-combophy",
589 .of_match_table
= stm32_combophy_of_match
,
590 .pm
= pm_sleep_ptr(&stm32_combophy_pm_ops
)
594 module_platform_driver(stm32_combophy_driver
);
596 MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>");
597 MODULE_DESCRIPTION("STM32MP25 Combophy USB3/PCIe controller driver");
598 MODULE_LICENSE("GPL");