0008-pcie-microsemi-Add-support-for-the-Vera-board-root-c.patch 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. From 9ecb60c4fd1cd7e85973427527167eaac137bfe9 Mon Sep 17 00:00:00 2001
  2. From: "Wesley W. Terpstra" <wesley@sifive.com>
  3. Date: Wed, 25 Apr 2018 12:10:15 -0700
  4. Subject: [PATCH 08/10] pcie-microsemi: Add support for the Vera-board root
  5. complex
  6. Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
  7. ---
  8. drivers/pci/controller/Kconfig | 6 +
  9. drivers/pci/controller/Makefile | 1 +
  10. drivers/pci/controller/pcie-microsemi.c | 778 ++++++++++++++++++++++++
  11. 3 files changed, 785 insertions(+)
  12. create mode 100644 drivers/pci/controller/pcie-microsemi.c
  13. diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
  14. index 6012f3059acd..284cea1b6ba1 100644
  15. --- a/drivers/pci/controller/Kconfig
  16. +++ b/drivers/pci/controller/Kconfig
  17. @@ -280,5 +280,11 @@ config VMD
  18. To compile this driver as a module, choose M here: the
  19. module will be called vmd.
  20. +config PCIE_MICROSEMI
  21. + bool "Microsemi AXI PCIe host bridge support"
  22. + depends on OF || COMPILE_TEST
  23. + help
  24. + Say 'Y' here if you want kernel to support the Microsemi AXI PCIe
  25. + Host Bridge driver.
  26. source "drivers/pci/controller/dwc/Kconfig"
  27. endmenu
  28. diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
  29. index d56a507495c5..c3b76ff221be 100644
  30. --- a/drivers/pci/controller/Makefile
  31. +++ b/drivers/pci/controller/Makefile
  32. @@ -28,6 +28,7 @@ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
  33. obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
  34. obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
  35. obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
  36. +obj-$(CONFIG_PCIE_MICROSEMI) += pcie-microsemi.o
  37. obj-$(CONFIG_VMD) += vmd.o
  38. # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
  39. obj-y += dwc/
  40. diff --git a/drivers/pci/controller/pcie-microsemi.c b/drivers/pci/controller/pcie-microsemi.c
  41. new file mode 100644
  42. index 000000000000..8e65059e4cf0
  43. --- /dev/null
  44. +++ b/drivers/pci/controller/pcie-microsemi.c
  45. @@ -0,0 +1,778 @@
  46. +/*
  47. + * PCIe host controller driver for Microsemi AXI PCIe Bridge
  48. + *
  49. + * Copyright (c) 2018 - Microsemi.
  50. + *
  51. + * Based on:
  52. + * pcie-rcar.c
  53. + * pcie-xilinx.c
  54. + * pcie-altera.c
  55. + *
  56. + * This program is free software: you can redistribute it and/or modify
  57. + * it under the terms of the GNU General Public License as published by
  58. + * the Free Software Foundation, either version 2 of the License, or
  59. + * (at your option) any later version.
  60. + */
  61. +
  62. +#include <linux/bitmap.h>
  63. +#include <linux/interrupt.h>
  64. +#include <linux/irq.h>
  65. +#include <linux/irqdomain.h>
  66. +#include <linux/kernel.h>
  67. +#include <linux/init.h>
  68. +#include <linux/msi.h>
  69. +#include <linux/of_address.h>
  70. +#include <linux/of_pci.h>
  71. +#include <linux/of_platform.h>
  72. +#include <linux/of_irq.h>
  73. +#include <linux/pci.h>
  74. +#include <linux/platform_device.h>
  75. +
  76. +#include "../pci.h"
  77. +
  78. +/* ECAM definitions */
  79. +#define ECAM_BUS_NUM_SHIFT 20
  80. +#define ECAM_DEV_NUM_SHIFT 12
  81. +
  82. +/* Number of MSI IRQs */
  83. +#define MICROSEMI_NUM_MSI_IRQS 32
  84. +#define MICROSEMI_NUM_MSI_IRQS_CODED 5
  85. +
  86. +/* PCIe Bridge Phy and Controller Phy offsets */
  87. +#define MICROSEMI_PCIE0_BRIDGE_ADDR 0x00004000u
  88. +#define MICROSEMI_PCIE0_CTRL_ADDR 0x00006000u
  89. +
  90. +#define MICROSEMI_PCIE1_BRIDGE_ADDR 0x00008000u
  91. +#define MICROSEMI_PCIE1_CTRL_ADDR 0x0000A000u
  92. +
  93. +/* PCIe Controller Phy Regs */
  94. +#define MICROSEMI_SEC_ERROR_INT 0x28
  95. +#define SEC_ERROR_INT_TX_RAM_SEC_ERR_INT GENMASK(3,0)
  96. +#define SEC_ERROR_INT_RX_RAM_SEC_ERR_INT GENMASK(7,4)
  97. +#define SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT GENMASK(11,8)
  98. +#define SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT GENMASK(15,12)
  99. +#define MICROSEMI_SEC_ERROR_INT_MASK 0x2c
  100. +#define MICROSEMI_DED_ERROR_INT 0x30
  101. +#define DED_ERROR_INT_TX_RAM_DED_ERR_INT GENMASK(3,0)
  102. +#define DED_ERROR_INT_RX_RAM_DED_ERR_INT GENMASK(7,4)
  103. +#define DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT GENMASK(11,8)
  104. +#define DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT GENMASK(15,12)
  105. +#define MICROSEMI_DED_ERROR_INT_MASK 0x34
  106. +#define MICROSEMI_ECC_CONTROL 0x38
  107. +#define ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS BIT(27)
  108. +#define ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS BIT(26)
  109. +#define ECC_CONTROL_RX_RAM_ECC_BYPASS BIT(25)
  110. +#define ECC_CONTROL_TX_RAM_ECC_BYPASS BIT(24)
  111. +#define MICROSEMI_LTSSM_STATE 0x5c
  112. +#define MICROSEMI_LTSSM_L0_STATE 0x10
  113. +#define MICROSEMI_PCIE_EVENT_INT 0x14c
  114. +#define PCIE_EVENT_INT_L2_EXIT_INT BIT(0)
  115. +#define PCIE_EVENT_INT_HOTRST_EXIT_INT BIT(1)
  116. +#define PCIE_EVENT_INT_DLUP_EXIT_INT BIT(2)
  117. +#define PCIE_EVENT_INT_L2_EXIT_INT_MASK BIT(16)
  118. +#define PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK BIT(17)
  119. +#define PCIE_EVENT_INT_DLUP_EXIT_INT_MASK BIT(18)
  120. +
  121. +/* PCIe Bridge Phy Regs */
  122. +#define MICROSEMI_PCIE_PCI_IDS_DW1 0x9c
  123. +#define MICROSEMI_IMASK_LOCAL 0x180
  124. +#define MICROSEMI_PCIE_LOCAL_INT_ENABLE 0x0F000000u
  125. +#define MICROSEMI_PCI_INTS 0x0F000000u
  126. +#define MICROSEMI_PM_MSI_INT_SHIFT 24
  127. +#define MICROSEMI_PCIE_ENABLE_MSI 0x10000000u
  128. +#define MICROSEMI_MSI_INT 0x10000000u
  129. +#define MICROSEMI_MSI_INT_SHIFT 28
  130. +#define MICROSEMI_ISTATUS_LOCAL 0x184
  131. +#define MICROSEMI_IMASK_HOST 0x188
  132. +#define MICROSEMI_ISTATUS_HOST 0x18c
  133. +#define MICROSEMI_ISTATUS_MSI 0x194
  134. +
  135. +/* PCIe AXI slave table init defines */
  136. +#define MICROSEMI_ATR0_AXI4_SLV0_SRCADDR_PARAM 0x800u
  137. +#define ATR_SIZE_SHIFT (1)
  138. +#define ATR_IMPL_ENABLE (1)
  139. +#define MICROSEMI_ATR0_AXI4_SLV0_SRC_ADDR 0x804u
  140. +#define MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_LSB 0x808u
  141. +#define MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_UDW 0x80cu
  142. +#define MICROSEMI_ATR0_AXI4_SLV0_TRSL_PARAM 0x810u
  143. +#define MICROSEMI_PCIE_TX_RX_INTERFACE 0x00000000u
  144. +#define MICROSEMI_PCIE_CONFIG_INTERFACE 0x00000001u
  145. +
  146. +
  147. +#define MICROSEMI_ATR0_AXI4_SLV_SIZE (32)
  148. +
  149. +/* PCIe Master table init defines */
  150. +#define MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_31_12 0x600u
  151. +#define MICROSEMI_ATR0_PCIE_WIN0_SIZE (0x1f)
  152. +#define MICROSEMI_ATR0_PCIE_WIN0_SIZE_SHIFT (1)
  153. +#define MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_63_32 0x604u
  154. +
  155. +#define MICROSEMI_MSI_MSG_ADDR 0x190u
  156. +
  157. +/* PCIe Config space MSI capability structure */
  158. +#define MSI_CAP_CTRL_OFFSET 0xE0u
  159. +#define MSI_ENABLE (0x01u << 16)
  160. +#define MSI_ENABLE_MULTI (MICROSEMI_NUM_MSI_IRQS_CODED << 20)
  161. +#define MSI_MSG_ADDR_OFFSET 0xE4u
  162. +#define MSI_MSG_UPPER_ADDR_OFFSET 0xE8u
  163. +#define MSI_MSG_DATA_OFFSET 0xF0u
  164. +
  165. +
  166. +/**
  167. + * struct microsemi_pcie_port - PCIe port information
  168. + * @pcie_base_addr: IO Mapped Register Base
  169. + * @axi_base_addr: AMBA Mapped Register Base
  170. + * @irq: Interrupt number
  171. + * @root_busno: Root Bus number
  172. + * @dev: Device pointer
  173. + * @msi_domain: MSI IRQ domain pointer
  174. + * @leg_domain: Legacy IRQ domain pointer
  175. + * @resources: Bus Resources
  176. + */
  177. +struct microsemi_pcie_port {
  178. + struct platform_device *pdev;
  179. + void __iomem *pcie_base_addr;
  180. + void __iomem *axi_base_addr;
  181. + int bridge;
  182. + u32 irq;
  183. + u8 root_busno;
  184. + struct device *dev;
  185. + struct irq_domain *msi_domain;
  186. + struct irq_domain *leg_domain;
  187. + struct list_head resources;
  188. +};
  189. +
  190. +static DECLARE_BITMAP(msi_irq_in_use, MICROSEMI_NUM_MSI_IRQS);
  191. +
  192. +static inline u32 pcie_read(struct microsemi_pcie_port *port, u32 reg)
  193. +{
  194. + return readl(port->pcie_base_addr + reg);
  195. +}
  196. +
  197. +static inline void pcie_write(struct microsemi_pcie_port *port,
  198. + u32 val, u32 reg)
  199. +{
  200. + writel(val, port->pcie_base_addr + reg);
  201. +}
  202. +
  203. +static inline bool microsemi_pcie_link_up(struct microsemi_pcie_port *port)
  204. +{
  205. + void *base_addr;
  206. +
  207. + if(port->bridge == 0)
  208. + base_addr = port->axi_base_addr + MICROSEMI_PCIE0_CTRL_ADDR;
  209. + else
  210. + base_addr = port->axi_base_addr + MICROSEMI_PCIE1_CTRL_ADDR;
  211. +
  212. + return (readl(base_addr + MICROSEMI_LTSSM_STATE)
  213. + & MICROSEMI_LTSSM_L0_STATE) ? 1 : 0;
  214. +}
  215. +
  216. +/**
  217. + * microsemi_pcie_valid_device - Check if a valid device is present on bus
  218. + * @bus: PCI Bus structure
  219. + * @devfn: device/function
  220. + *
  221. + * Return: 'true' on success and 'false' if invalid device is found
  222. + */
  223. +static bool microsemi_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
  224. +{
  225. + struct microsemi_pcie_port *port = bus->sysdata;
  226. +
  227. + /* Check if link is up when trying to access downstream ports */
  228. + if (bus->number != port->root_busno)
  229. + if (!microsemi_pcie_link_up(port))
  230. + return false;
  231. +
  232. + /* Only one device down on each root port */
  233. + if (bus->number == port->root_busno && devfn > 0)
  234. + return false;
  235. +
  236. + return true;
  237. +}
  238. +
  239. +/**
  240. + * microsemi_pcie_map_bus - Get configuration base
  241. + * @bus: PCI Bus structure
  242. + * @devfn: Device/function
  243. + * @where: Offset from base
  244. + *
  245. + * Return: Base address of the configuration space needed to be
  246. + * accessed.
  247. + */
  248. +static void __iomem *microsemi_pcie_map_bus(struct pci_bus *bus,
  249. + unsigned int devfn, int where)
  250. +{
  251. + struct microsemi_pcie_port *port = bus->sysdata;
  252. + int relbus;
  253. +
  254. + if (!microsemi_pcie_valid_device(bus, devfn))
  255. + return NULL;
  256. +
  257. + relbus = (bus->number << ECAM_BUS_NUM_SHIFT) |
  258. + (devfn << ECAM_DEV_NUM_SHIFT);
  259. +
  260. + return port->pcie_base_addr + relbus + where;
  261. +}
  262. +
  263. +/* PCIe operations */
  264. +static struct pci_ops microsemi_pcie_ops = {
  265. + .map_bus = microsemi_pcie_map_bus,
  266. + .read = pci_generic_config_read,
  267. + .write = pci_generic_config_write,
  268. +};
  269. +
  270. +/* MSI functions */
  271. +
  272. +/**
  273. + * microsemi_pcie_destroy_msi - Free MSI number
  274. + * @irq: IRQ to be freed
  275. + */
  276. +static void microsemi_pcie_destroy_msi(unsigned int irq)
  277. +{
  278. + struct msi_desc *msi;
  279. + struct microsemi_pcie_port *port;
  280. + struct irq_data *d = irq_get_irq_data(irq);
  281. + irq_hw_number_t hwirq = irqd_to_hwirq(d);
  282. +
  283. + if (!test_bit(hwirq, msi_irq_in_use)) {
  284. + msi = irq_get_msi_desc(irq);
  285. + port = msi_desc_to_pci_sysdata(msi);
  286. + dev_err(port->dev, "Trying to free unused MSI#%d\n", irq);
  287. + } else
  288. + clear_bit(hwirq, msi_irq_in_use);
  289. +}
  290. +
  291. +/**
  292. + * microsemi_pcie_assign_msi - Allocate MSI number
  293. + *
  294. + * Return: A valid IRQ on success and error value on failure.
  295. + */
  296. +static int microsemi_pcie_assign_msi(void)
  297. +{
  298. + int pos;
  299. +
  300. + pos = find_first_zero_bit(msi_irq_in_use, MICROSEMI_NUM_MSI_IRQS);
  301. + if (pos < MICROSEMI_NUM_MSI_IRQS)
  302. + set_bit(pos, msi_irq_in_use);
  303. + else
  304. + return -ENOSPC;
  305. +
  306. + return pos;
  307. +}
  308. +
  309. +/**
  310. + * microsemi_msi_teardown_irq - Destroy the MSI
  311. + * @chip: MSI Chip descriptor
  312. + * @irq: MSI IRQ to destroy
  313. + */
  314. +static void microsemi_msi_teardown_irq(struct msi_controller *chip,
  315. + unsigned int irq)
  316. +{
  317. + microsemi_pcie_destroy_msi(irq);
  318. + irq_dispose_mapping(irq);
  319. +}
  320. +
  321. +/**
  322. + * microsemi_pcie_msi_setup_irq - Setup MSI request
  323. + * @chip: MSI chip pointer
  324. + * @pdev: PCIe device pointer
  325. + * @desc: MSI descriptor pointer
  326. + *
  327. + * Return: '0' on success and error value on failure
  328. + */
  329. +static int microsemi_pcie_msi_setup_irq(struct msi_controller *chip,
  330. + struct pci_dev *pdev,
  331. + struct msi_desc *desc)
  332. +{
  333. + struct microsemi_pcie_port *port = pdev->bus->sysdata;
  334. + unsigned int irq;
  335. + int hwirq;
  336. + struct msi_msg msg;
  337. +
  338. + hwirq = microsemi_pcie_assign_msi();
  339. + if (hwirq < 0)
  340. + return hwirq;
  341. +
  342. + irq = irq_create_mapping(port->msi_domain, hwirq);
  343. + if (!irq)
  344. + return -EINVAL;
  345. +
  346. + irq_set_msi_desc(irq, desc);
  347. +
  348. + msg.address_hi = upper_32_bits(MICROSEMI_MSI_MSG_ADDR);
  349. + msg.address_lo = lower_32_bits(MICROSEMI_MSI_MSG_ADDR);
  350. + msg.data = hwirq;
  351. +
  352. + pci_write_msi_msg(irq, &msg);
  353. +
  354. + return 0;
  355. +}
  356. +
  357. +/* MSI Chip Descriptor */
  358. +static struct msi_controller microsemi_pcie_msi_chip = {
  359. + .setup_irq = microsemi_pcie_msi_setup_irq,
  360. + .teardown_irq = microsemi_msi_teardown_irq,
  361. +};
  362. +
  363. +/* HW Interrupt Chip Descriptor */
  364. +static struct irq_chip microsemi_msi_irq_chip = {
  365. + .name = "Microsemi PCIe MSI",
  366. + .irq_enable = pci_msi_unmask_irq,
  367. + .irq_disable = pci_msi_mask_irq,
  368. + .irq_mask = pci_msi_mask_irq,
  369. + .irq_unmask = pci_msi_unmask_irq,
  370. +};
  371. +
  372. +/**
  373. + * microsemi_pcie_msi_map - Set the handler for the MSI and mark IRQ as valid
  374. + * @domain: IRQ domain
  375. + * @irq: Virtual IRQ number
  376. + * @hwirq: HW interrupt number
  377. + *
  378. + * Return: Always returns 0.
  379. + */
  380. +static int microsemi_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
  381. + irq_hw_number_t hwirq)
  382. +{
  383. + irq_set_chip_and_handler(irq,
  384. + &microsemi_msi_irq_chip, handle_simple_irq);
  385. + irq_set_chip_data(irq, domain->host_data);
  386. +
  387. + return 0;
  388. +}
  389. +
  390. +/* IRQ Domain operations */
  391. +static const struct irq_domain_ops msi_domain_ops = {
  392. + .map = microsemi_pcie_msi_map,
  393. +};
  394. +
  395. +/**
  396. + * microsemi_pcie_enable_msi - Enable MSI support
  397. + * @port: PCIe port information
  398. + */
  399. +static void microsemi_pcie_enable_msi(struct microsemi_pcie_port *port)
  400. +{
  401. + u32 cap_ctrl;
  402. +
  403. + cap_ctrl = pcie_read(port, MSI_CAP_CTRL_OFFSET);
  404. +
  405. + pcie_write(port, cap_ctrl | MSI_ENABLE_MULTI |
  406. + MSI_ENABLE, MSI_CAP_CTRL_OFFSET);
  407. + pcie_write(port, MICROSEMI_MSI_MSG_ADDR, MSI_MSG_ADDR_OFFSET);
  408. +}
  409. +
  410. +/* INTx Functions */
  411. +
  412. +/**
  413. + * microsemi_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid
  414. + * @domain: IRQ domain
  415. + * @irq: Virtual IRQ number
  416. + * @hwirq: HW interrupt number
  417. + *
  418. + * Return: Always returns 0.
  419. + */
  420. +static int microsemi_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
  421. + irq_hw_number_t hwirq)
  422. +{
  423. + irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
  424. + irq_set_chip_data(irq, domain->host_data);
  425. +
  426. + return 0;
  427. +}
  428. +
  429. +/* INTx IRQ Domain operations */
  430. +static const struct irq_domain_ops intx_domain_ops = {
  431. + .map = microsemi_pcie_intx_map,
  432. + .xlate = pci_irqd_intx_xlate,
  433. +};
  434. +
  435. +/* PCIe HW Functions */
  436. +
  437. +/**
  438. + * microsemi_pcie_intr_handler - Interrupt Service Handler
  439. + * @irq: IRQ number
  440. + * @data: PCIe port information
  441. + *
  442. + * Return: IRQ_HANDLED on success and IRQ_NONE on failure
  443. + */
  444. +static irqreturn_t microsemi_pcie_intr_handler(int irq, void *data)
  445. +{
  446. + struct microsemi_pcie_port *port = (struct microsemi_pcie_port *) data;
  447. + struct device *dev = port->dev;
  448. + unsigned long status;
  449. + unsigned long msi;
  450. + u32 bit;
  451. + u32 virq;
  452. + void *base_addr;
  453. +
  454. + if(port->bridge == 0)
  455. + base_addr = port->axi_base_addr + MICROSEMI_PCIE0_BRIDGE_ADDR;
  456. + else
  457. + base_addr = port->axi_base_addr + MICROSEMI_PCIE1_BRIDGE_ADDR;
  458. +
  459. + status = readl(base_addr + MICROSEMI_ISTATUS_LOCAL);
  460. +
  461. + status = (status & MICROSEMI_PCI_INTS) >> MICROSEMI_PM_MSI_INT_SHIFT;
  462. + for_each_set_bit(bit, &status, PCI_NUM_INTX) {
  463. + /* clear that interrupt bit */
  464. + writel(1 << (bit+MICROSEMI_PM_MSI_INT_SHIFT),
  465. + base_addr + MICROSEMI_ISTATUS_LOCAL);
  466. + virq = irq_find_mapping(port->leg_domain, bit);
  467. +
  468. + if (virq)
  469. + generic_handle_irq(virq);
  470. + else
  471. + dev_err(dev, "unexpected IRQ, INT%d\n", bit);
  472. + }
  473. +
  474. + status = readl(base_addr + MICROSEMI_ISTATUS_LOCAL);
  475. + if (status & MICROSEMI_MSI_INT) {
  476. + // Clear the ISTATUS MSI bit
  477. + writel((1 << MICROSEMI_MSI_INT_SHIFT), base_addr + MICROSEMI_ISTATUS_LOCAL);
  478. + msi = readl(base_addr + MICROSEMI_ISTATUS_MSI);
  479. + for_each_set_bit(bit, &msi, MICROSEMI_NUM_MSI_IRQS) {
  480. + /* clear that MSI interrupt bit */
  481. + writel((1 << bit),
  482. + base_addr + MICROSEMI_ISTATUS_MSI);
  483. + virq = irq_find_mapping(port->msi_domain, bit);
  484. + if (virq)
  485. + generic_handle_irq(virq);
  486. + else
  487. + dev_err(dev, "unexpected IRQ, INT%d\n", bit);
  488. + }
  489. + }
  490. +
  491. + return IRQ_HANDLED;
  492. +}
  493. +
  494. +/**
  495. + * microsemi_pcie_init_irq_domain - Initialize IRQ domain
  496. + * @port: PCIe port information
  497. + *
  498. + * Return: '0' on success and error value on failure
  499. + */
  500. +static int microsemi_pcie_init_irq_domain(struct microsemi_pcie_port *port)
  501. +{
  502. + struct device *dev = port->dev;
  503. + struct device_node *node = dev->of_node;
  504. + struct device_node *pcie_intc_node;
  505. + void *bridge_base_addr;
  506. +
  507. + if(port->bridge == 0) {
  508. + bridge_base_addr = port->axi_base_addr + MICROSEMI_PCIE0_BRIDGE_ADDR;
  509. + } else {
  510. + bridge_base_addr = port->axi_base_addr + MICROSEMI_PCIE1_BRIDGE_ADDR;
  511. + }
  512. +
  513. + /* Setup INTx */
  514. + pcie_intc_node = of_get_next_child(node, NULL);
  515. + if (!pcie_intc_node) {
  516. + dev_err(dev, "No PCIe Intc node found\n");
  517. + return -ENODEV;
  518. + }
  519. + dev_info(dev, "Intc node foundi %s\n", pcie_intc_node->name);
  520. +
  521. + port->leg_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
  522. + &intx_domain_ops,
  523. + port);
  524. + if (!port->leg_domain) {
  525. + dev_err(dev, "Failed to get a INTx IRQ domain\n");
  526. + return -ENODEV;
  527. + }
  528. +
  529. + /* Setup MSI */
  530. + if (IS_ENABLED(CONFIG_PCI_MSI)) {
  531. + port->msi_domain = irq_domain_add_linear(node,
  532. + MICROSEMI_NUM_MSI_IRQS,
  533. + &msi_domain_ops,
  534. + &microsemi_pcie_msi_chip);
  535. + if (!port->msi_domain) {
  536. + dev_err(dev, "Failed to get a MSI IRQ domain\n");
  537. + return -ENODEV;
  538. + }
  539. + microsemi_pcie_enable_msi(port);
  540. + }
  541. +
  542. + /* Enable interrupts */
  543. + writel(MICROSEMI_PCIE_ENABLE_MSI | MICROSEMI_PCIE_LOCAL_INT_ENABLE,
  544. + bridge_base_addr + MICROSEMI_IMASK_LOCAL);
  545. +
  546. + return 0;
  547. +}
  548. +
  549. +/**
  550. + * microsemi_pcie_init_port - Parse Device tree, Initialize hardware
  551. + * @port: PCIe port information
  552. + *
  553. + * Return: '0' on success and error value on failure
  554. + */
  555. +static int microsemi_pcie_init_port(struct microsemi_pcie_port *port)
  556. +{
  557. + struct device *dev = port->dev;
  558. + struct device_node *node = dev->of_node;
  559. + struct of_pci_range_parser parser;
  560. + struct of_pci_range range;
  561. + struct resource regs;
  562. + struct resource regs1;
  563. + resource_size_t size;
  564. + u32 atr_sz;
  565. + const char *type;
  566. + int err;
  567. + void *bridge_base_addr;
  568. + void *ctrl_base_addr;
  569. + u32 val;
  570. + int index = 1;
  571. +
  572. + type = of_get_property(node, "device_type", NULL);
  573. + if (!type || strcmp(type, "pci")) {
  574. + dev_err(dev, "invalid \"device_type\" %s\n", type);
  575. + return -EINVAL;
  576. + }
  577. +
  578. + /* Only supporting bridge 1 */
  579. + port->bridge = 1;
  580. +
  581. + err = of_address_to_resource(node, 0, &regs);
  582. + if (err) {
  583. + dev_err(dev, "missing \"reg\" property\n");
  584. + return err;
  585. + }
  586. +
  587. + port->pcie_base_addr = devm_pci_remap_cfg_resource(dev, &regs);
  588. + if (IS_ERR(port->pcie_base_addr))
  589. + return PTR_ERR(port->pcie_base_addr);
  590. +
  591. + err = of_address_to_resource(node, 1, &regs1);
  592. + if (err) {
  593. + dev_err(dev, "missing \"reg\" property\n");
  594. + return err;
  595. + }
  596. +
  597. + port->axi_base_addr = devm_ioremap_resource(dev, &regs1);
  598. + if (IS_ERR(port->axi_base_addr))
  599. + return PTR_ERR(port->axi_base_addr);
  600. +
  601. + if(port->bridge == 0) {
  602. + bridge_base_addr = port->axi_base_addr + MICROSEMI_PCIE0_BRIDGE_ADDR;
  603. + ctrl_base_addr = port->axi_base_addr + MICROSEMI_PCIE0_CTRL_ADDR;
  604. + } else {
  605. + bridge_base_addr = port->axi_base_addr + MICROSEMI_PCIE1_BRIDGE_ADDR;
  606. + ctrl_base_addr = port->axi_base_addr + MICROSEMI_PCIE1_CTRL_ADDR;
  607. + }
  608. +
  609. + port->irq = irq_of_parse_and_map(node, 0);
  610. +
  611. + err = devm_request_irq(dev, port->irq, microsemi_pcie_intr_handler,
  612. + IRQF_SHARED | IRQF_NO_THREAD,
  613. + "microsemi-pcie", port);
  614. + if (err) {
  615. + dev_err(dev, "unable to request irq %d\n", port->irq);
  616. + return err;
  617. + }
  618. +
  619. + /* Clear and Disable interrupts */
  620. + val = ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS
  621. + | ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS
  622. + | ECC_CONTROL_RX_RAM_ECC_BYPASS
  623. + | ECC_CONTROL_TX_RAM_ECC_BYPASS;
  624. + writel(val, ctrl_base_addr + MICROSEMI_ECC_CONTROL);
  625. +
  626. + val = PCIE_EVENT_INT_L2_EXIT_INT
  627. + | PCIE_EVENT_INT_HOTRST_EXIT_INT
  628. + | PCIE_EVENT_INT_DLUP_EXIT_INT
  629. + | PCIE_EVENT_INT_L2_EXIT_INT_MASK
  630. + | PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK
  631. + | PCIE_EVENT_INT_DLUP_EXIT_INT_MASK;
  632. + writel(val, ctrl_base_addr + MICROSEMI_PCIE_EVENT_INT);
  633. +
  634. + val = SEC_ERROR_INT_TX_RAM_SEC_ERR_INT
  635. + | SEC_ERROR_INT_RX_RAM_SEC_ERR_INT
  636. + | SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT
  637. + | SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT;
  638. + writel(val, ctrl_base_addr + MICROSEMI_SEC_ERROR_INT);
  639. + writel(val, ctrl_base_addr + MICROSEMI_SEC_ERROR_INT_MASK);
  640. +
  641. + val = DED_ERROR_INT_TX_RAM_DED_ERR_INT
  642. + | DED_ERROR_INT_RX_RAM_DED_ERR_INT
  643. + | DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT
  644. + | DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT;
  645. + writel(val, ctrl_base_addr + MICROSEMI_DED_ERROR_INT);
  646. + writel(val, ctrl_base_addr + MICROSEMI_DED_ERROR_INT_MASK);
  647. +
  648. + writel(0x00000000, bridge_base_addr + MICROSEMI_IMASK_LOCAL);
  649. + writel(GENMASK(31,0), bridge_base_addr + MICROSEMI_ISTATUS_LOCAL);
  650. + writel(0x00000000, bridge_base_addr + MICROSEMI_IMASK_HOST);
  651. + writel(GENMASK(31,0), bridge_base_addr + MICROSEMI_ISTATUS_HOST);
  652. +
  653. + dev_info(dev, "interrupt disabled\n");
  654. +
  655. + /* Configure Address Translation Table 0 for pcie config space */
  656. + writel(MICROSEMI_PCIE_CONFIG_INTERFACE,
  657. + bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_TRSL_PARAM);
  658. +
  659. + size = resource_size(&regs);
  660. +
  661. + atr_sz = find_first_bit((const unsigned long *)&size, 64) - 1;
  662. +
  663. + writel(lower_32_bits(regs.start) | atr_sz << ATR_SIZE_SHIFT | ATR_IMPL_ENABLE,
  664. + bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_SRCADDR_PARAM);
  665. +
  666. + //writel(upper_32_bits(regs.start),
  667. + // bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_SRC_ADDR);
  668. +
  669. + writel(lower_32_bits(regs.start),
  670. + bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
  671. +
  672. + //writel(upper_32_bits(regs.start),
  673. + // bridge_base_addr + MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
  674. +
  675. + if (of_pci_range_parser_init(&parser, node)) {
  676. + dev_err(dev, "missing \"ranges\" property\n");
  677. + return -EINVAL;
  678. + }
  679. +
  680. +
  681. + for_each_of_pci_range(&parser, &range) {
  682. + switch (range.flags & IORESOURCE_TYPE_BITS) {
  683. + case IORESOURCE_MEM:
  684. + size = range.size;
  685. + atr_sz = find_first_bit((const unsigned long *)&size, 64) - 1;
  686. +
  687. + /* Configure Address Translation Table index for pcie mem space */
  688. + writel(MICROSEMI_PCIE_TX_RX_INTERFACE,
  689. + bridge_base_addr + (index * MICROSEMI_ATR0_AXI4_SLV_SIZE ) +
  690. + MICROSEMI_ATR0_AXI4_SLV0_TRSL_PARAM);
  691. +
  692. + writel(lower_32_bits(range.cpu_addr) | atr_sz << ATR_SIZE_SHIFT | ATR_IMPL_ENABLE,
  693. + bridge_base_addr + (index * MICROSEMI_ATR0_AXI4_SLV_SIZE ) +
  694. + MICROSEMI_ATR0_AXI4_SLV0_SRCADDR_PARAM);
  695. +
  696. + //writel(upper_32_bits(range.cpu_addr),
  697. + // bridge_base_addr + (index * MICROSEMI_ATR0_AXI4_SLV_SIZE ) +
  698. + // MICROSEMI_ATR0_AXI4_SLV0_SRC_ADDR);
  699. +
  700. + writel(lower_32_bits(range.pci_addr),
  701. + bridge_base_addr + (index * MICROSEMI_ATR0_AXI4_SLV_SIZE ) +
  702. + MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
  703. +
  704. + //writel(upper_32_bits(range.pci_addr),
  705. + // bridge_base_addr + (index * MICROSEMI_ATR0_AXI4_SLV_SIZE ) +
  706. + // MICROSEMI_ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
  707. +
  708. + break;
  709. + }
  710. + index++;
  711. + }
  712. +
  713. + writel(readl(bridge_base_addr + MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_31_12)
  714. + | MICROSEMI_ATR0_PCIE_WIN0_SIZE << MICROSEMI_ATR0_PCIE_WIN0_SIZE_SHIFT,
  715. + bridge_base_addr + MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_31_12);
  716. +
  717. + writel(0x0, bridge_base_addr + MICROSEMI_ATR0_PCIE_WIN0_SRCADDR_63_32);
  718. +
  719. + writel((readl(bridge_base_addr + MICROSEMI_PCIE_PCI_IDS_DW1) & 0xffff)
  720. + | (PCI_CLASS_BRIDGE_PCI << 16),
  721. + bridge_base_addr + MICROSEMI_PCIE_PCI_IDS_DW1);
  722. +
  723. + return 0;
  724. +}
  725. +
  726. +/**
  727. + * microsemi_pcie_probe - Probe function
  728. + * @pdev: Platform device pointer
  729. + *
  730. + * Return: '0' on success and error value on failure
  731. + */
  732. +static int microsemi_pcie_probe(struct platform_device *pdev)
  733. +{
  734. + struct device *dev = &pdev->dev;
  735. + struct microsemi_pcie_port *port;
  736. + struct pci_bus *bus, *child;
  737. + struct pci_host_bridge *bridge;
  738. + int err;
  739. + resource_size_t iobase = 0;
  740. + LIST_HEAD(res);
  741. +
  742. + if (!dev->of_node)
  743. + return -ENODEV;
  744. +
  745. + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port));
  746. + if (!bridge)
  747. + return -ENODEV;
  748. +
  749. + port = pci_host_bridge_priv(bridge);
  750. +
  751. + port->dev = dev;
  752. + port->pdev = pdev;
  753. +
  754. + err = microsemi_pcie_init_port(port);
  755. + if (err) {
  756. + dev_err(dev, "Pcie port initialization failed\n");
  757. + return err;
  758. + }
  759. +
  760. +
  761. + err = microsemi_pcie_init_irq_domain(port);
  762. + if (err) {
  763. + dev_err(dev, "Failed creating IRQ Domain\n");
  764. + return err;
  765. + }
  766. +
  767. + err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res,
  768. + &iobase);
  769. + if (err) {
  770. + dev_err(dev, "Getting bridge resources failed\n");
  771. + return err;
  772. + }
  773. +
  774. + err = devm_request_pci_bus_resources(dev, &res);
  775. + if (err)
  776. + goto error;
  777. +
  778. +
  779. + list_splice_init(&res, &bridge->windows);
  780. + bridge->dev.parent = dev;
  781. + bridge->sysdata = port;
  782. + bridge->busnr = 0;
  783. + bridge->ops = &microsemi_pcie_ops;
  784. + bridge->map_irq = of_irq_parse_and_map_pci;
  785. + bridge->swizzle_irq = pci_common_swizzle;
  786. +
  787. +#ifdef CONFIG_PCI_MSI
  788. + microsemi_pcie_msi_chip.dev = dev;
  789. + bridge->msi = &microsemi_pcie_msi_chip;
  790. +#endif
  791. + err = pci_scan_root_bus_bridge(bridge);
  792. + dev_info(dev, "pci_scan_root_bus_bridge done\n");
  793. + if (err < 0)
  794. + goto error;
  795. +
  796. + bus = bridge->bus;
  797. +
  798. + pci_assign_unassigned_bus_resources(bus);
  799. + list_for_each_entry(child, &bus->children, node)
  800. + pcie_bus_configure_settings(child);
  801. + pci_bus_add_devices(bus);
  802. +
  803. + return 0;
  804. +
  805. +error:
  806. + pci_free_resource_list(&res);
  807. + return err;
  808. +}
  809. +
  810. +static const struct of_device_id microsemi_pcie_of_match[] = {
  811. + { .compatible = "ms-pf,axi-pcie-host", },
  812. + {}
  813. +};
  814. +
  815. +static struct platform_driver microsemi_pcie_driver = {
  816. + .driver = {
  817. + .name = "microsemi-pcie",
  818. + .of_match_table = microsemi_pcie_of_match,
  819. + .suppress_bind_attrs = true,
  820. + },
  821. + .probe = microsemi_pcie_probe,
  822. +};
  823. +builtin_platform_driver(microsemi_pcie_driver);
  824. --
  825. 2.21.0