File Index
Files and directories
Sign in
FILE

pcie-stm32-ep.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/controller/dwc/pcie-stm32-ep.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * STMicroelectronics STM32MP25 PCIe endpoint 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/gpio/consumer.h>
 11#include <linux/mfd/syscon.h>
 12#include <linux/of_platform.h>
 13#include <linux/phy/phy.h>
 14#include <linux/platform_device.h>
 15#include <linux/pm_runtime.h>
 16#include <linux/regmap.h>
 17#include <linux/reset.h>
 18#include "pcie-designware.h"
 19#include "pcie-stm32.h"
 20
 21struct stm32_pcie {
 22	struct dw_pcie pci;
 23	struct regmap *regmap;
 24	struct reset_control *rst;
 25	struct phy *phy;
 26	struct clk *clk;
 27	struct gpio_desc *perst_gpio;
 28	unsigned int perst_irq;
 29};
 30
 31static void stm32_pcie_ep_init(struct dw_pcie_ep *ep)
 32{
 33	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 34	enum pci_barno bar;
 35
 36	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
 37		dw_pcie_ep_reset_bar(pci, bar);
 38}
 39
 40static int stm32_pcie_start_link(struct dw_pcie *pci)
 41{
 42	struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
 43
 44	enable_irq(stm32_pcie->perst_irq);
 45
 46	return 0;
 47}
 48
 49static void stm32_pcie_stop_link(struct dw_pcie *pci)
 50{
 51	struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
 52
 53	disable_irq(stm32_pcie->perst_irq);
 54}
 55
 56static int stm32_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
 57				unsigned int type, u16 interrupt_num)
 58{
 59	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 60
 61	switch (type) {
 62	case PCI_IRQ_INTX:
 63		return dw_pcie_ep_raise_intx_irq(ep, func_no);
 64	case PCI_IRQ_MSI:
 65		return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
 66	default:
 67		dev_err(pci->dev, "UNKNOWN IRQ type\n");
 68		return -EINVAL;
 69	}
 70}
 71
 72static const struct pci_epc_features stm32_pcie_epc_features = {
 73	DWC_EPC_COMMON_FEATURES,
 74	.msi_capable = true,
 75	.align = SZ_64K,
 76};
 77
 78static const struct pci_epc_features*
 79stm32_pcie_get_features(struct dw_pcie_ep *ep)
 80{
 81	return &stm32_pcie_epc_features;
 82}
 83
 84static const struct dw_pcie_ep_ops stm32_pcie_ep_ops = {
 85	.init = stm32_pcie_ep_init,
 86	.raise_irq = stm32_pcie_raise_irq,
 87	.get_features = stm32_pcie_get_features,
 88};
 89
 90static const struct dw_pcie_ops dw_pcie_ops = {
 91	.start_link = stm32_pcie_start_link,
 92	.stop_link = stm32_pcie_stop_link,
 93};
 94
 95static int stm32_pcie_enable_resources(struct stm32_pcie *stm32_pcie)
 96{
 97	int ret;
 98
 99	ret = phy_init(stm32_pcie->phy);
100	if (ret)
101		return ret;
102
103	ret = clk_prepare_enable(stm32_pcie->clk);
104	if (ret)
105		phy_exit(stm32_pcie->phy);
106
107	return ret;
108}
109
110static void stm32_pcie_disable_resources(struct stm32_pcie *stm32_pcie)
111{
112	clk_disable_unprepare(stm32_pcie->clk);
113
114	phy_exit(stm32_pcie->phy);
115}
116
117static void stm32_pcie_perst_assert(struct dw_pcie *pci)
118{
119	struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
120	struct dw_pcie_ep *ep = &stm32_pcie->pci.ep;
121	struct device *dev = pci->dev;
122
123	dev_dbg(dev, "PERST asserted by host\n");
124
125	regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
126			   STM32MP25_PCIECR_LTSSM_EN, 0);
127
128	pci_epc_deinit_notify(ep->epc);
129
130	stm32_pcie_disable_resources(stm32_pcie);
131
132	pm_runtime_put_sync(dev);
133}
134
135static void stm32_pcie_perst_deassert(struct dw_pcie *pci)
136{
137	struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
138	struct device *dev = pci->dev;
139	struct dw_pcie_ep *ep = &pci->ep;
140	int ret;
141
142	dev_dbg(dev, "PERST de-asserted by host\n");
143
144	ret = pm_runtime_resume_and_get(dev);
145	if (ret < 0) {
146		dev_err(dev, "Failed to resume runtime PM: %d\n", ret);
147		return;
148	}
149
150	ret = stm32_pcie_enable_resources(stm32_pcie);
151	if (ret) {
152		dev_err(dev, "Failed to enable resources: %d\n", ret);
153		goto err_pm_put_sync;
154	}
155
156	/*
157	 * Reprogram the configuration space registers here because the DBI
158	 * registers were reset by the PHY RCC during phy_init().
159	 */
160	ret = dw_pcie_ep_init_registers(ep);
161	if (ret) {
162		dev_err(dev, "Failed to complete initialization: %d\n", ret);
163		goto err_disable_resources;
164	}
165
166	pci_epc_init_notify(ep->epc);
167
168	/* Enable link training */
169	regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
170			   STM32MP25_PCIECR_LTSSM_EN,
171			   STM32MP25_PCIECR_LTSSM_EN);
172
173	return;
174
175err_disable_resources:
176	stm32_pcie_disable_resources(stm32_pcie);
177
178err_pm_put_sync:
179	pm_runtime_put_sync(dev);
180}
181
182static irqreturn_t stm32_pcie_ep_perst_irq_thread(int irq, void *data)
183{
184	struct stm32_pcie *stm32_pcie = data;
185	struct dw_pcie *pci = &stm32_pcie->pci;
186	u32 perst;
187
188	perst = gpiod_get_value(stm32_pcie->perst_gpio);
189	if (perst)
190		stm32_pcie_perst_assert(pci);
191	else
192		stm32_pcie_perst_deassert(pci);
193
194	irq_set_irq_type(gpiod_to_irq(stm32_pcie->perst_gpio),
195			 (perst ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW));
196
197	return IRQ_HANDLED;
198}
199
200static int stm32_add_pcie_ep(struct stm32_pcie *stm32_pcie,
201			     struct platform_device *pdev)
202{
203	struct dw_pcie_ep *ep = &stm32_pcie->pci.ep;
204	struct device *dev = &pdev->dev;
205	int ret;
206
207	ret = regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
208				 STM32MP25_PCIECR_TYPE_MASK,
209				 STM32MP25_PCIECR_EP);
210	if (ret)
211		return ret;
212
213	reset_control_assert(stm32_pcie->rst);
214	reset_control_deassert(stm32_pcie->rst);
215
216	ep->ops = &stm32_pcie_ep_ops;
217
218	ep->page_size = stm32_pcie_epc_features.align;
219
220	ret = dw_pcie_ep_init(ep);
221	if (ret) {
222		dev_err(dev, "Failed to initialize ep: %d\n", ret);
223		return ret;
224	}
225
226	ret = stm32_pcie_enable_resources(stm32_pcie);
227	if (ret) {
228		dev_err(dev, "Failed to enable resources: %d\n", ret);
229		dw_pcie_ep_deinit(ep);
230		return ret;
231	}
232
233	return 0;
234}
235
236static int stm32_pcie_probe(struct platform_device *pdev)
237{
238	struct stm32_pcie *stm32_pcie;
239	struct device *dev = &pdev->dev;
240	int ret;
241
242	stm32_pcie = devm_kzalloc(dev, sizeof(*stm32_pcie), GFP_KERNEL);
243	if (!stm32_pcie)
244		return -ENOMEM;
245
246	stm32_pcie->pci.dev = dev;
247	stm32_pcie->pci.ops = &dw_pcie_ops;
248
249	stm32_pcie->regmap = syscon_regmap_lookup_by_compatible("st,stm32mp25-syscfg");
250	if (IS_ERR(stm32_pcie->regmap))
251		return dev_err_probe(dev, PTR_ERR(stm32_pcie->regmap),
252				     "No syscfg specified\n");
253
254	stm32_pcie->phy = devm_phy_get(dev, NULL);
255	if (IS_ERR(stm32_pcie->phy))
256		return dev_err_probe(dev, PTR_ERR(stm32_pcie->phy),
257				     "failed to get pcie-phy\n");
258
259	stm32_pcie->clk = devm_clk_get(dev, NULL);
260	if (IS_ERR(stm32_pcie->clk))
261		return dev_err_probe(dev, PTR_ERR(stm32_pcie->clk),
262				     "Failed to get PCIe clock source\n");
263
264	stm32_pcie->rst = devm_reset_control_get_exclusive(dev, NULL);
265	if (IS_ERR(stm32_pcie->rst))
266		return dev_err_probe(dev, PTR_ERR(stm32_pcie->rst),
267				     "Failed to get PCIe reset\n");
268
269	stm32_pcie->perst_gpio = devm_gpiod_get(dev, "reset", GPIOD_IN);
270	if (IS_ERR(stm32_pcie->perst_gpio))
271		return dev_err_probe(dev, PTR_ERR(stm32_pcie->perst_gpio),
272				     "Failed to get reset GPIO\n");
273
274	ret = phy_set_mode(stm32_pcie->phy, PHY_MODE_PCIE);
275	if (ret)
276		return ret;
277
278	platform_set_drvdata(pdev, stm32_pcie);
279
280	pm_runtime_get_noresume(dev);
281
282	ret = devm_pm_runtime_enable(dev);
283	if (ret < 0) {
284		pm_runtime_put_noidle(&pdev->dev);
285		return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
286	}
287
288	stm32_pcie->perst_irq = gpiod_to_irq(stm32_pcie->perst_gpio);
289
290	/* Will be enabled in start_link when device is initialized. */
291	irq_set_status_flags(stm32_pcie->perst_irq, IRQ_NOAUTOEN);
292
293	ret = devm_request_threaded_irq(dev, stm32_pcie->perst_irq, NULL,
294					stm32_pcie_ep_perst_irq_thread,
295					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
296					"perst_irq", stm32_pcie);
297	if (ret) {
298		pm_runtime_put_noidle(&pdev->dev);
299		return dev_err_probe(dev, ret, "Failed to request PERST IRQ\n");
300	}
301
302	ret = stm32_add_pcie_ep(stm32_pcie, pdev);
303	if (ret)
304		pm_runtime_put_noidle(&pdev->dev);
305
306	return ret;
307}
308
309static void stm32_pcie_remove(struct platform_device *pdev)
310{
311	struct stm32_pcie *stm32_pcie = platform_get_drvdata(pdev);
312	struct dw_pcie *pci = &stm32_pcie->pci;
313	struct dw_pcie_ep *ep = &pci->ep;
314
315	dw_pcie_stop_link(pci);
316
317	pci_epc_deinit_notify(ep->epc);
318	dw_pcie_ep_deinit(ep);
319
320	stm32_pcie_disable_resources(stm32_pcie);
321
322	pm_runtime_put_sync(&pdev->dev);
323}
324
325static const struct of_device_id stm32_pcie_ep_of_match[] = {
326	{ .compatible = "st,stm32mp25-pcie-ep" },
327	{},
328};
329
330static struct platform_driver stm32_pcie_ep_driver = {
331	.probe = stm32_pcie_probe,
332	.remove = stm32_pcie_remove,
333	.driver = {
334		.name = "stm32-ep-pcie",
335		.of_match_table = stm32_pcie_ep_of_match,
336	},
337};
338
339module_platform_driver(stm32_pcie_ep_driver);
340
341MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>");
342MODULE_DESCRIPTION("STM32MP25 PCIe Endpoint Controller driver");
343MODULE_LICENSE("GPL");
344MODULE_DEVICE_TABLE(of, stm32_pcie_ep_of_match);
~/ Read-only file preview.