FILE
pcie-stm32-ep.c
File preview with syntax highlighting.
linux-6.19.14/drivers/pci/controller/dwc/pcie-stm32-ep.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.