File Index
Files and directories
Sign in
FILE

pcie-stm32.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/controller/dwc/pcie-stm32.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * STMicroelectronics STM32MP25 PCIe root complex driver.
  4 *
  5 * Copyright (C) 2025 STMicroelectronics
  6 * Author: Christian Bruel <christian.bruel@foss.st.com>
  7 */
  8
  9#include <linux/clk.h>
 10#include <linux/delay.h>
 11#include <linux/device.h>
 12#include <linux/err.h>
 13#include <linux/gpio/consumer.h>
 14#include <linux/irq.h>
 15#include <linux/mfd/syscon.h>
 16#include <linux/mod_devicetable.h>
 17#include <linux/module.h>
 18#include <linux/of.h>
 19#include <linux/of_platform.h>
 20#include <linux/phy/phy.h>
 21#include <linux/pinctrl/consumer.h>
 22#include <linux/platform_device.h>
 23#include <linux/pm.h>
 24#include <linux/pm_runtime.h>
 25#include <linux/pm_wakeirq.h>
 26#include <linux/regmap.h>
 27#include <linux/reset.h>
 28#include <linux/stddef.h>
 29
 30#include "../../pci.h"
 31
 32#include "pcie-designware.h"
 33#include "pcie-stm32.h"
 34
 35struct stm32_pcie {
 36	struct dw_pcie pci;
 37	struct regmap *regmap;
 38	struct reset_control *rst;
 39	struct phy *phy;
 40	struct clk *clk;
 41	struct gpio_desc *perst_gpio;
 42	struct gpio_desc *wake_gpio;
 43};
 44
 45static void stm32_pcie_deassert_perst(struct stm32_pcie *stm32_pcie)
 46{
 47	if (stm32_pcie->perst_gpio) {
 48		msleep(PCIE_T_PVPERL_MS);
 49		gpiod_set_value(stm32_pcie->perst_gpio, 0);
 50	}
 51
 52	msleep(PCIE_RESET_CONFIG_WAIT_MS);
 53}
 54
 55static void stm32_pcie_assert_perst(struct stm32_pcie *stm32_pcie)
 56{
 57	gpiod_set_value(stm32_pcie->perst_gpio, 1);
 58}
 59
 60static int stm32_pcie_start_link(struct dw_pcie *pci)
 61{
 62	struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
 63
 64	return regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
 65				  STM32MP25_PCIECR_LTSSM_EN,
 66				  STM32MP25_PCIECR_LTSSM_EN);
 67}
 68
 69static void stm32_pcie_stop_link(struct dw_pcie *pci)
 70{
 71	struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
 72
 73	regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
 74			   STM32MP25_PCIECR_LTSSM_EN, 0);
 75}
 76
 77static int stm32_pcie_suspend_noirq(struct device *dev)
 78{
 79	struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
 80	int ret;
 81
 82	ret = dw_pcie_suspend_noirq(&stm32_pcie->pci);
 83	if (ret)
 84		return ret;
 85
 86	stm32_pcie_assert_perst(stm32_pcie);
 87
 88	clk_disable_unprepare(stm32_pcie->clk);
 89
 90	if (!device_wakeup_path(dev))
 91		phy_exit(stm32_pcie->phy);
 92
 93	return pinctrl_pm_select_sleep_state(dev);
 94}
 95
 96static int stm32_pcie_resume_noirq(struct device *dev)
 97{
 98	struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
 99	int ret;
100
101	/*
102	 * The core clock is gated with CLKREQ# from the COMBOPHY REFCLK,
103	 * thus if no device is present, must deassert it with a GPIO from
104	 * pinctrl pinmux before accessing the DBI registers.
105	 */
106	ret = pinctrl_pm_select_init_state(dev);
107	if (ret) {
108		dev_err(dev, "Failed to activate pinctrl pm state: %d\n", ret);
109		return ret;
110	}
111
112	if (!device_wakeup_path(dev)) {
113		ret = phy_init(stm32_pcie->phy);
114		if (ret) {
115			pinctrl_pm_select_default_state(dev);
116			return ret;
117		}
118	}
119
120	ret = clk_prepare_enable(stm32_pcie->clk);
121	if (ret)
122		goto err_phy_exit;
123
124	stm32_pcie_deassert_perst(stm32_pcie);
125
126	ret = dw_pcie_resume_noirq(&stm32_pcie->pci);
127	if (ret)
128		goto err_disable_clk;
129
130	pinctrl_pm_select_default_state(dev);
131
132	return 0;
133
134err_disable_clk:
135	stm32_pcie_assert_perst(stm32_pcie);
136	clk_disable_unprepare(stm32_pcie->clk);
137
138err_phy_exit:
139	phy_exit(stm32_pcie->phy);
140	pinctrl_pm_select_default_state(dev);
141
142	return ret;
143}
144
145static const struct dev_pm_ops stm32_pcie_pm_ops = {
146	NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend_noirq,
147				  stm32_pcie_resume_noirq)
148};
149
150static const struct dw_pcie_host_ops stm32_pcie_host_ops = {
151};
152
153static const struct dw_pcie_ops dw_pcie_ops = {
154	.start_link = stm32_pcie_start_link,
155	.stop_link = stm32_pcie_stop_link
156};
157
158static int stm32_add_pcie_port(struct stm32_pcie *stm32_pcie)
159{
160	struct device *dev = stm32_pcie->pci.dev;
161	unsigned int wake_irq;
162	int ret;
163
164	ret = phy_set_mode(stm32_pcie->phy, PHY_MODE_PCIE);
165	if (ret)
166		return ret;
167
168	ret = phy_init(stm32_pcie->phy);
169	if (ret)
170		return ret;
171
172	ret = regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
173				 STM32MP25_PCIECR_TYPE_MASK,
174				 STM32MP25_PCIECR_RC);
175	if (ret)
176		goto err_phy_exit;
177
178	stm32_pcie_deassert_perst(stm32_pcie);
179
180	if (stm32_pcie->wake_gpio) {
181		wake_irq = gpiod_to_irq(stm32_pcie->wake_gpio);
182		ret = dev_pm_set_dedicated_wake_irq(dev, wake_irq);
183		if (ret) {
184			dev_err(dev, "Failed to enable wakeup irq %d\n", ret);
185			goto err_assert_perst;
186		}
187		irq_set_irq_type(wake_irq, IRQ_TYPE_EDGE_FALLING);
188	}
189
190	return 0;
191
192err_assert_perst:
193	stm32_pcie_assert_perst(stm32_pcie);
194
195err_phy_exit:
196	phy_exit(stm32_pcie->phy);
197
198	return ret;
199}
200
201static void stm32_remove_pcie_port(struct stm32_pcie *stm32_pcie)
202{
203	dev_pm_clear_wake_irq(stm32_pcie->pci.dev);
204
205	stm32_pcie_assert_perst(stm32_pcie);
206
207	phy_exit(stm32_pcie->phy);
208}
209
210static int stm32_pcie_parse_port(struct stm32_pcie *stm32_pcie)
211{
212	struct device *dev = stm32_pcie->pci.dev;
213	struct device_node *root_port;
214
215	root_port = of_get_next_available_child(dev->of_node, NULL);
216
217	stm32_pcie->phy = devm_of_phy_get(dev, root_port, NULL);
218	if (IS_ERR(stm32_pcie->phy)) {
219		of_node_put(root_port);
220		return dev_err_probe(dev, PTR_ERR(stm32_pcie->phy),
221				     "Failed to get pcie-phy\n");
222	}
223
224	stm32_pcie->perst_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(root_port),
225						       "reset", GPIOD_OUT_HIGH, NULL);
226	if (IS_ERR(stm32_pcie->perst_gpio)) {
227		if (PTR_ERR(stm32_pcie->perst_gpio) != -ENOENT) {
228			of_node_put(root_port);
229			return dev_err_probe(dev, PTR_ERR(stm32_pcie->perst_gpio),
230					     "Failed to get reset GPIO\n");
231		}
232		stm32_pcie->perst_gpio = NULL;
233	}
234
235	stm32_pcie->wake_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(root_port),
236						      "wake", GPIOD_IN, NULL);
237
238	if (IS_ERR(stm32_pcie->wake_gpio)) {
239		if (PTR_ERR(stm32_pcie->wake_gpio) != -ENOENT) {
240			of_node_put(root_port);
241			return dev_err_probe(dev, PTR_ERR(stm32_pcie->wake_gpio),
242					     "Failed to get wake GPIO\n");
243		}
244		stm32_pcie->wake_gpio = NULL;
245	}
246
247	of_node_put(root_port);
248
249	return 0;
250}
251
252static int stm32_pcie_probe(struct platform_device *pdev)
253{
254	struct stm32_pcie *stm32_pcie;
255	struct device *dev = &pdev->dev;
256	int ret;
257
258	stm32_pcie = devm_kzalloc(dev, sizeof(*stm32_pcie), GFP_KERNEL);
259	if (!stm32_pcie)
260		return -ENOMEM;
261
262	stm32_pcie->pci.dev = dev;
263	stm32_pcie->pci.ops = &dw_pcie_ops;
264	stm32_pcie->pci.pp.ops = &stm32_pcie_host_ops;
265
266	stm32_pcie->regmap = syscon_regmap_lookup_by_compatible("st,stm32mp25-syscfg");
267	if (IS_ERR(stm32_pcie->regmap))
268		return dev_err_probe(dev, PTR_ERR(stm32_pcie->regmap),
269				     "No syscfg specified\n");
270
271	stm32_pcie->clk = devm_clk_get(dev, NULL);
272	if (IS_ERR(stm32_pcie->clk))
273		return dev_err_probe(dev, PTR_ERR(stm32_pcie->clk),
274				     "Failed to get PCIe clock source\n");
275
276	stm32_pcie->rst = devm_reset_control_get_exclusive(dev, NULL);
277	if (IS_ERR(stm32_pcie->rst))
278		return dev_err_probe(dev, PTR_ERR(stm32_pcie->rst),
279				     "Failed to get PCIe reset\n");
280
281	ret = stm32_pcie_parse_port(stm32_pcie);
282	if (ret)
283		return ret;
284
285	platform_set_drvdata(pdev, stm32_pcie);
286
287	ret = stm32_add_pcie_port(stm32_pcie);
288	if (ret)
289		return ret;
290
291	reset_control_assert(stm32_pcie->rst);
292	reset_control_deassert(stm32_pcie->rst);
293
294	ret = clk_prepare_enable(stm32_pcie->clk);
295	if (ret) {
296		dev_err(dev, "Core clock enable failed %d\n", ret);
297		goto err_remove_port;
298	}
299
300	ret = pm_runtime_set_active(dev);
301	if (ret < 0) {
302		dev_err_probe(dev, ret, "Failed to activate runtime PM\n");
303		goto err_disable_clk;
304	}
305
306	pm_runtime_no_callbacks(dev);
307
308	ret = devm_pm_runtime_enable(dev);
309	if (ret < 0) {
310		dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
311		goto err_disable_clk;
312	}
313
314	ret = dw_pcie_host_init(&stm32_pcie->pci.pp);
315	if (ret)
316		goto err_disable_clk;
317
318	if (stm32_pcie->wake_gpio)
319		device_init_wakeup(dev, true);
320
321	return 0;
322
323err_disable_clk:
324	clk_disable_unprepare(stm32_pcie->clk);
325
326err_remove_port:
327	stm32_remove_pcie_port(stm32_pcie);
328
329	return ret;
330}
331
332static void stm32_pcie_remove(struct platform_device *pdev)
333{
334	struct stm32_pcie *stm32_pcie = platform_get_drvdata(pdev);
335	struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
336
337	if (stm32_pcie->wake_gpio)
338		device_init_wakeup(&pdev->dev, false);
339
340	dw_pcie_host_deinit(pp);
341
342	clk_disable_unprepare(stm32_pcie->clk);
343
344	stm32_remove_pcie_port(stm32_pcie);
345
346	pm_runtime_put_noidle(&pdev->dev);
347}
348
349static const struct of_device_id stm32_pcie_of_match[] = {
350	{ .compatible = "st,stm32mp25-pcie-rc" },
351	{},
352};
353
354static struct platform_driver stm32_pcie_driver = {
355	.probe = stm32_pcie_probe,
356	.remove = stm32_pcie_remove,
357	.driver = {
358		.name = "stm32-pcie",
359		.of_match_table = stm32_pcie_of_match,
360		.pm = &stm32_pcie_pm_ops,
361		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
362	},
363};
364
365module_platform_driver(stm32_pcie_driver);
366
367MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>");
368MODULE_DESCRIPTION("STM32MP25 PCIe Controller driver");
369MODULE_LICENSE("GPL");
370MODULE_DEVICE_TABLE(of, stm32_pcie_of_match);
~/ Read-only file preview.