pcie-amd-mdb.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * PCIe host controller driver for AMD MDB PCIe Bridge
  4. *
  5. * Copyright (C) 2024-2025, Advanced Micro Devices, Inc.
  6. */
  7. #include <linux/clk.h>
  8. #include <linux/delay.h>
  9. #include <linux/gpio.h>
  10. #include <linux/interrupt.h>
  11. #include <linux/irqdomain.h>
  12. #include <linux/kernel.h>
  13. #include <linux/init.h>
  14. #include <linux/of_device.h>
  15. #include <linux/pci.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/resource.h>
  18. #include <linux/types.h>
  19. #include "../../pci.h"
  20. #include "pcie-designware.h"
  21. #define AMD_MDB_TLP_IR_STATUS_MISC 0x4C0
  22. #define AMD_MDB_TLP_IR_MASK_MISC 0x4C4
  23. #define AMD_MDB_TLP_IR_ENABLE_MISC 0x4C8
  24. #define AMD_MDB_TLP_IR_DISABLE_MISC 0x4CC
  25. #define AMD_MDB_TLP_PCIE_INTX_MASK GENMASK(23, 16)
  26. #define AMD_MDB_PCIE_INTR_INTX_ASSERT(x) BIT((x) * 2)
  27. /* Interrupt registers definitions. */
  28. #define AMD_MDB_PCIE_INTR_CMPL_TIMEOUT 15
  29. #define AMD_MDB_PCIE_INTR_INTX 16
  30. #define AMD_MDB_PCIE_INTR_PM_PME_RCVD 24
  31. #define AMD_MDB_PCIE_INTR_PME_TO_ACK_RCVD 25
  32. #define AMD_MDB_PCIE_INTR_MISC_CORRECTABLE 26
  33. #define AMD_MDB_PCIE_INTR_NONFATAL 27
  34. #define AMD_MDB_PCIE_INTR_FATAL 28
  35. #define IMR(x) BIT(AMD_MDB_PCIE_INTR_ ##x)
  36. #define AMD_MDB_PCIE_IMR_ALL_MASK \
  37. ( \
  38. IMR(CMPL_TIMEOUT) | \
  39. IMR(PM_PME_RCVD) | \
  40. IMR(PME_TO_ACK_RCVD) | \
  41. IMR(MISC_CORRECTABLE) | \
  42. IMR(NONFATAL) | \
  43. IMR(FATAL) | \
  44. AMD_MDB_TLP_PCIE_INTX_MASK \
  45. )
  46. /**
  47. * struct amd_mdb_pcie - PCIe port information
  48. * @pci: DesignWare PCIe controller structure
  49. * @slcr: MDB System Level Control and Status Register (SLCR) base
  50. * @intx_domain: INTx IRQ domain pointer
  51. * @mdb_domain: MDB IRQ domain pointer
  52. * @perst_gpio: GPIO descriptor for PERST# signal handling
  53. * @intx_irq: INTx IRQ interrupt number
  54. */
  55. struct amd_mdb_pcie {
  56. struct dw_pcie pci;
  57. void __iomem *slcr;
  58. struct irq_domain *intx_domain;
  59. struct irq_domain *mdb_domain;
  60. struct gpio_desc *perst_gpio;
  61. int intx_irq;
  62. };
  63. static const struct dw_pcie_host_ops amd_mdb_pcie_host_ops = {
  64. };
  65. static void amd_mdb_intx_irq_mask(struct irq_data *data)
  66. {
  67. struct amd_mdb_pcie *pcie = irq_data_get_irq_chip_data(data);
  68. struct dw_pcie *pci = &pcie->pci;
  69. struct dw_pcie_rp *port = &pci->pp;
  70. unsigned long flags;
  71. u32 val;
  72. raw_spin_lock_irqsave(&port->lock, flags);
  73. val = FIELD_PREP(AMD_MDB_TLP_PCIE_INTX_MASK,
  74. AMD_MDB_PCIE_INTR_INTX_ASSERT(data->hwirq));
  75. /*
  76. * Writing '1' to a bit in AMD_MDB_TLP_IR_DISABLE_MISC disables that
  77. * interrupt, writing '0' has no effect.
  78. */
  79. writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_DISABLE_MISC);
  80. raw_spin_unlock_irqrestore(&port->lock, flags);
  81. }
  82. static void amd_mdb_intx_irq_unmask(struct irq_data *data)
  83. {
  84. struct amd_mdb_pcie *pcie = irq_data_get_irq_chip_data(data);
  85. struct dw_pcie *pci = &pcie->pci;
  86. struct dw_pcie_rp *port = &pci->pp;
  87. unsigned long flags;
  88. u32 val;
  89. raw_spin_lock_irqsave(&port->lock, flags);
  90. val = FIELD_PREP(AMD_MDB_TLP_PCIE_INTX_MASK,
  91. AMD_MDB_PCIE_INTR_INTX_ASSERT(data->hwirq));
  92. /*
  93. * Writing '1' to a bit in AMD_MDB_TLP_IR_ENABLE_MISC enables that
  94. * interrupt, writing '0' has no effect.
  95. */
  96. writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_ENABLE_MISC);
  97. raw_spin_unlock_irqrestore(&port->lock, flags);
  98. }
  99. static struct irq_chip amd_mdb_intx_irq_chip = {
  100. .name = "AMD MDB INTx",
  101. .irq_mask = amd_mdb_intx_irq_mask,
  102. .irq_unmask = amd_mdb_intx_irq_unmask,
  103. };
  104. /**
  105. * amd_mdb_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid
  106. * @domain: IRQ domain
  107. * @irq: Virtual IRQ number
  108. * @hwirq: Hardware interrupt number
  109. *
  110. * Return: Always returns '0'.
  111. */
  112. static int amd_mdb_pcie_intx_map(struct irq_domain *domain,
  113. unsigned int irq, irq_hw_number_t hwirq)
  114. {
  115. irq_set_chip_and_handler(irq, &amd_mdb_intx_irq_chip,
  116. handle_level_irq);
  117. irq_set_chip_data(irq, domain->host_data);
  118. irq_set_status_flags(irq, IRQ_LEVEL);
  119. return 0;
  120. }
  121. /* INTx IRQ domain operations. */
  122. static const struct irq_domain_ops amd_intx_domain_ops = {
  123. .map = amd_mdb_pcie_intx_map,
  124. };
  125. static irqreturn_t dw_pcie_rp_intx(int irq, void *args)
  126. {
  127. struct amd_mdb_pcie *pcie = args;
  128. unsigned long val;
  129. int i, int_status;
  130. val = readl_relaxed(pcie->slcr + AMD_MDB_TLP_IR_STATUS_MISC);
  131. int_status = FIELD_GET(AMD_MDB_TLP_PCIE_INTX_MASK, val);
  132. for (i = 0; i < PCI_NUM_INTX; i++) {
  133. if (int_status & AMD_MDB_PCIE_INTR_INTX_ASSERT(i))
  134. generic_handle_domain_irq(pcie->intx_domain, i);
  135. }
  136. return IRQ_HANDLED;
  137. }
  138. #define _IC(x, s)[AMD_MDB_PCIE_INTR_ ## x] = { __stringify(x), s }
  139. static const struct {
  140. const char *sym;
  141. const char *str;
  142. } intr_cause[32] = {
  143. _IC(CMPL_TIMEOUT, "Completion timeout"),
  144. _IC(PM_PME_RCVD, "PM_PME message received"),
  145. _IC(PME_TO_ACK_RCVD, "PME_TO_ACK message received"),
  146. _IC(MISC_CORRECTABLE, "Correctable error message"),
  147. _IC(NONFATAL, "Non fatal error message"),
  148. _IC(FATAL, "Fatal error message"),
  149. };
  150. static void amd_mdb_event_irq_mask(struct irq_data *d)
  151. {
  152. struct amd_mdb_pcie *pcie = irq_data_get_irq_chip_data(d);
  153. struct dw_pcie *pci = &pcie->pci;
  154. struct dw_pcie_rp *port = &pci->pp;
  155. unsigned long flags;
  156. u32 val;
  157. raw_spin_lock_irqsave(&port->lock, flags);
  158. val = BIT(d->hwirq);
  159. writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_DISABLE_MISC);
  160. raw_spin_unlock_irqrestore(&port->lock, flags);
  161. }
  162. static void amd_mdb_event_irq_unmask(struct irq_data *d)
  163. {
  164. struct amd_mdb_pcie *pcie = irq_data_get_irq_chip_data(d);
  165. struct dw_pcie *pci = &pcie->pci;
  166. struct dw_pcie_rp *port = &pci->pp;
  167. unsigned long flags;
  168. u32 val;
  169. raw_spin_lock_irqsave(&port->lock, flags);
  170. val = BIT(d->hwirq);
  171. writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_ENABLE_MISC);
  172. raw_spin_unlock_irqrestore(&port->lock, flags);
  173. }
  174. static struct irq_chip amd_mdb_event_irq_chip = {
  175. .name = "AMD MDB RC-Event",
  176. .irq_mask = amd_mdb_event_irq_mask,
  177. .irq_unmask = amd_mdb_event_irq_unmask,
  178. };
  179. static int amd_mdb_pcie_event_map(struct irq_domain *domain,
  180. unsigned int irq, irq_hw_number_t hwirq)
  181. {
  182. irq_set_chip_and_handler(irq, &amd_mdb_event_irq_chip,
  183. handle_level_irq);
  184. irq_set_chip_data(irq, domain->host_data);
  185. irq_set_status_flags(irq, IRQ_LEVEL);
  186. return 0;
  187. }
  188. static const struct irq_domain_ops event_domain_ops = {
  189. .map = amd_mdb_pcie_event_map,
  190. };
  191. static irqreturn_t amd_mdb_pcie_event(int irq, void *args)
  192. {
  193. struct amd_mdb_pcie *pcie = args;
  194. unsigned long val;
  195. int i;
  196. val = readl_relaxed(pcie->slcr + AMD_MDB_TLP_IR_STATUS_MISC);
  197. val &= ~readl_relaxed(pcie->slcr + AMD_MDB_TLP_IR_MASK_MISC);
  198. for_each_set_bit(i, &val, 32)
  199. generic_handle_domain_irq(pcie->mdb_domain, i);
  200. writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_STATUS_MISC);
  201. return IRQ_HANDLED;
  202. }
  203. static void amd_mdb_pcie_free_irq_domains(struct amd_mdb_pcie *pcie)
  204. {
  205. if (pcie->intx_domain) {
  206. irq_domain_remove(pcie->intx_domain);
  207. pcie->intx_domain = NULL;
  208. }
  209. if (pcie->mdb_domain) {
  210. irq_domain_remove(pcie->mdb_domain);
  211. pcie->mdb_domain = NULL;
  212. }
  213. }
  214. static int amd_mdb_pcie_init_port(struct amd_mdb_pcie *pcie)
  215. {
  216. unsigned long val;
  217. /* Disable all TLP interrupts. */
  218. writel_relaxed(AMD_MDB_PCIE_IMR_ALL_MASK,
  219. pcie->slcr + AMD_MDB_TLP_IR_DISABLE_MISC);
  220. /* Clear pending TLP interrupts. */
  221. val = readl_relaxed(pcie->slcr + AMD_MDB_TLP_IR_STATUS_MISC);
  222. val &= AMD_MDB_PCIE_IMR_ALL_MASK;
  223. writel_relaxed(val, pcie->slcr + AMD_MDB_TLP_IR_STATUS_MISC);
  224. /* Enable all TLP interrupts. */
  225. writel_relaxed(AMD_MDB_PCIE_IMR_ALL_MASK,
  226. pcie->slcr + AMD_MDB_TLP_IR_ENABLE_MISC);
  227. return 0;
  228. }
  229. /**
  230. * amd_mdb_pcie_init_irq_domains - Initialize IRQ domain
  231. * @pcie: PCIe port information
  232. * @pdev: Platform device
  233. *
  234. * Return: Returns '0' on success and error value on failure.
  235. */
  236. static int amd_mdb_pcie_init_irq_domains(struct amd_mdb_pcie *pcie,
  237. struct platform_device *pdev)
  238. {
  239. struct dw_pcie *pci = &pcie->pci;
  240. struct dw_pcie_rp *pp = &pci->pp;
  241. struct device *dev = &pdev->dev;
  242. struct device_node *node = dev->of_node;
  243. struct device_node *pcie_intc_node;
  244. int err;
  245. pcie_intc_node = of_get_child_by_name(node, "interrupt-controller");
  246. if (!pcie_intc_node) {
  247. dev_err(dev, "No PCIe Intc node found\n");
  248. return -ENODEV;
  249. }
  250. pcie->mdb_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node), 32,
  251. &event_domain_ops, pcie);
  252. if (!pcie->mdb_domain) {
  253. err = -ENOMEM;
  254. dev_err(dev, "Failed to add MDB domain\n");
  255. goto out;
  256. }
  257. irq_domain_update_bus_token(pcie->mdb_domain, DOMAIN_BUS_NEXUS);
  258. pcie->intx_domain = irq_domain_create_linear(of_fwnode_handle(pcie_intc_node),
  259. PCI_NUM_INTX, &amd_intx_domain_ops, pcie);
  260. if (!pcie->intx_domain) {
  261. err = -ENOMEM;
  262. dev_err(dev, "Failed to add INTx domain\n");
  263. goto mdb_out;
  264. }
  265. of_node_put(pcie_intc_node);
  266. irq_domain_update_bus_token(pcie->intx_domain, DOMAIN_BUS_WIRED);
  267. raw_spin_lock_init(&pp->lock);
  268. return 0;
  269. mdb_out:
  270. amd_mdb_pcie_free_irq_domains(pcie);
  271. out:
  272. of_node_put(pcie_intc_node);
  273. return err;
  274. }
  275. static irqreturn_t amd_mdb_pcie_intr_handler(int irq, void *args)
  276. {
  277. struct amd_mdb_pcie *pcie = args;
  278. struct device *dev;
  279. struct irq_data *d;
  280. dev = pcie->pci.dev;
  281. /*
  282. * In the future, error reporting will be hooked to the AER subsystem.
  283. * Currently, the driver prints a warning message to the user.
  284. */
  285. d = irq_domain_get_irq_data(pcie->mdb_domain, irq);
  286. if (intr_cause[d->hwirq].str)
  287. dev_warn(dev, "%s\n", intr_cause[d->hwirq].str);
  288. else
  289. dev_warn_once(dev, "Unknown IRQ %ld\n", d->hwirq);
  290. return IRQ_HANDLED;
  291. }
  292. static int amd_mdb_setup_irq(struct amd_mdb_pcie *pcie,
  293. struct platform_device *pdev)
  294. {
  295. struct dw_pcie *pci = &pcie->pci;
  296. struct dw_pcie_rp *pp = &pci->pp;
  297. struct device *dev = &pdev->dev;
  298. int i, irq, err;
  299. amd_mdb_pcie_init_port(pcie);
  300. pp->irq = platform_get_irq(pdev, 0);
  301. if (pp->irq < 0)
  302. return pp->irq;
  303. for (i = 0; i < ARRAY_SIZE(intr_cause); i++) {
  304. if (!intr_cause[i].str)
  305. continue;
  306. irq = irq_create_mapping(pcie->mdb_domain, i);
  307. if (!irq) {
  308. dev_err(dev, "Failed to map MDB domain interrupt\n");
  309. return -ENOMEM;
  310. }
  311. err = devm_request_irq(dev, irq, amd_mdb_pcie_intr_handler,
  312. IRQF_NO_THREAD, intr_cause[i].sym, pcie);
  313. if (err) {
  314. dev_err(dev, "Failed to request IRQ %d, err=%d\n",
  315. irq, err);
  316. return err;
  317. }
  318. }
  319. pcie->intx_irq = irq_create_mapping(pcie->mdb_domain,
  320. AMD_MDB_PCIE_INTR_INTX);
  321. if (!pcie->intx_irq) {
  322. dev_err(dev, "Failed to map INTx interrupt\n");
  323. return -ENXIO;
  324. }
  325. err = devm_request_irq(dev, pcie->intx_irq, dw_pcie_rp_intx,
  326. IRQF_NO_THREAD, NULL, pcie);
  327. if (err) {
  328. dev_err(dev, "Failed to request INTx IRQ %d, err=%d\n",
  329. irq, err);
  330. return err;
  331. }
  332. /* Plug the main event handler. */
  333. err = devm_request_irq(dev, pp->irq, amd_mdb_pcie_event, IRQF_NO_THREAD,
  334. "amd_mdb pcie_irq", pcie);
  335. if (err) {
  336. dev_err(dev, "Failed to request event IRQ %d, err=%d\n",
  337. pp->irq, err);
  338. return err;
  339. }
  340. return 0;
  341. }
  342. static int amd_mdb_parse_pcie_port(struct amd_mdb_pcie *pcie)
  343. {
  344. struct device *dev = pcie->pci.dev;
  345. struct device_node *pcie_port_node __maybe_unused;
  346. /*
  347. * This platform currently supports only one Root Port, so the loop
  348. * will execute only once.
  349. * TODO: Enhance the driver to handle multiple Root Ports in the future.
  350. */
  351. for_each_child_of_node_with_prefix(dev->of_node, pcie_port_node, "pcie") {
  352. pcie->perst_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(pcie_port_node),
  353. "reset", GPIOD_OUT_HIGH, NULL);
  354. if (IS_ERR(pcie->perst_gpio))
  355. return dev_err_probe(dev, PTR_ERR(pcie->perst_gpio),
  356. "Failed to request reset GPIO\n");
  357. return 0;
  358. }
  359. return -ENODEV;
  360. }
  361. static int amd_mdb_add_pcie_port(struct amd_mdb_pcie *pcie,
  362. struct platform_device *pdev)
  363. {
  364. struct dw_pcie *pci = &pcie->pci;
  365. struct dw_pcie_rp *pp = &pci->pp;
  366. struct device *dev = &pdev->dev;
  367. int err;
  368. pcie->slcr = devm_platform_ioremap_resource_byname(pdev, "slcr");
  369. if (IS_ERR(pcie->slcr))
  370. return PTR_ERR(pcie->slcr);
  371. err = amd_mdb_pcie_init_irq_domains(pcie, pdev);
  372. if (err)
  373. return err;
  374. err = amd_mdb_setup_irq(pcie, pdev);
  375. if (err) {
  376. dev_err(dev, "Failed to set up interrupts, err=%d\n", err);
  377. goto out;
  378. }
  379. pp->ops = &amd_mdb_pcie_host_ops;
  380. if (pcie->perst_gpio) {
  381. mdelay(PCIE_T_PVPERL_MS);
  382. gpiod_set_value_cansleep(pcie->perst_gpio, 0);
  383. mdelay(PCIE_RESET_CONFIG_WAIT_MS);
  384. }
  385. err = dw_pcie_host_init(pp);
  386. if (err) {
  387. dev_err(dev, "Failed to initialize host, err=%d\n", err);
  388. goto out;
  389. }
  390. return 0;
  391. out:
  392. amd_mdb_pcie_free_irq_domains(pcie);
  393. return err;
  394. }
  395. static int amd_mdb_pcie_probe(struct platform_device *pdev)
  396. {
  397. struct device *dev = &pdev->dev;
  398. struct amd_mdb_pcie *pcie;
  399. struct dw_pcie *pci;
  400. int ret;
  401. pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
  402. if (!pcie)
  403. return -ENOMEM;
  404. pci = &pcie->pci;
  405. pci->dev = dev;
  406. platform_set_drvdata(pdev, pcie);
  407. ret = amd_mdb_parse_pcie_port(pcie);
  408. /*
  409. * If amd_mdb_parse_pcie_port returns -ENODEV, it indicates that the
  410. * PCIe Bridge node was not found in the device tree. This is not
  411. * considered a fatal error and will trigger a fallback where the
  412. * reset GPIO is acquired directly from the PCIe Host Bridge node.
  413. */
  414. if (ret) {
  415. if (ret != -ENODEV)
  416. return ret;
  417. pcie->perst_gpio = devm_gpiod_get_optional(dev, "reset",
  418. GPIOD_OUT_HIGH);
  419. if (IS_ERR(pcie->perst_gpio))
  420. return dev_err_probe(dev, PTR_ERR(pcie->perst_gpio),
  421. "Failed to request reset GPIO\n");
  422. }
  423. return amd_mdb_add_pcie_port(pcie, pdev);
  424. }
  425. static const struct of_device_id amd_mdb_pcie_of_match[] = {
  426. {
  427. .compatible = "amd,versal2-mdb-host",
  428. },
  429. {},
  430. };
  431. static struct platform_driver amd_mdb_pcie_driver = {
  432. .driver = {
  433. .name = "amd-mdb-pcie",
  434. .of_match_table = amd_mdb_pcie_of_match,
  435. .suppress_bind_attrs = true,
  436. },
  437. .probe = amd_mdb_pcie_probe,
  438. };
  439. builtin_platform_driver(amd_mdb_pcie_driver);