1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Adding PCI-E MSI support for PPC4XX SoCs.
5 * Copyright (c) 2010, Applied Micro Circuits Corporation
6 * Authors: Tirumala R Marri <tmarri@apm.com>
7 * Feng Kan <fkan@apm.com>
10 #include <linux/irq.h>
11 #include <linux/pci.h>
12 #include <linux/msi.h>
13 #include <linux/of_platform.h>
14 #include <linux/interrupt.h>
15 #include <linux/export.h>
16 #include <linux/kernel.h>
18 #include <asm/hw_irq.h>
19 #include <asm/ppc-pci.h>
21 #include <asm/dcr-regs.h>
22 #include <asm/msi_bitmap.h>
24 #define PEIH_TERMADH 0x00
25 #define PEIH_TERMADL 0x08
26 #define PEIH_MSIED 0x10
27 #define PEIH_MSIMK 0x18
28 #define PEIH_MSIASS 0x20
29 #define PEIH_FLUSH0 0x30
30 #define PEIH_FLUSH1 0x38
31 #define PEIH_CNTRST 0x48
38 void __iomem
*msi_regs
;
40 struct msi_bitmap bitmap
;
41 struct device_node
*msi_dev
;
44 static struct ppc4xx_msi ppc4xx_msi
;
46 static int ppc4xx_msi_init_allocator(struct platform_device
*dev
,
47 struct ppc4xx_msi
*msi_data
)
51 err
= msi_bitmap_alloc(&msi_data
->bitmap
, msi_irqs
,
56 err
= msi_bitmap_reserve_dt_hwirqs(&msi_data
->bitmap
);
58 msi_bitmap_free(&msi_data
->bitmap
);
65 static int ppc4xx_setup_msi_irqs(struct pci_dev
*dev
, int nvec
, int type
)
70 struct msi_desc
*entry
;
71 struct ppc4xx_msi
*msi_data
= &ppc4xx_msi
;
73 dev_dbg(&dev
->dev
, "PCIE-MSI:%s called. vec %x type %d\n",
74 __func__
, nvec
, type
);
75 if (type
== PCI_CAP_ID_MSIX
)
76 pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n");
78 msi_data
->msi_virqs
= kmalloc_array(msi_irqs
, sizeof(int), GFP_KERNEL
);
79 if (!msi_data
->msi_virqs
)
82 for_each_pci_msi_entry(entry
, dev
) {
83 int_no
= msi_bitmap_alloc_hwirqs(&msi_data
->bitmap
, 1);
87 pr_debug("%s: fail allocating msi interrupt\n",
90 virq
= irq_of_parse_and_map(msi_data
->msi_dev
, int_no
);
92 dev_err(&dev
->dev
, "%s: fail mapping irq\n", __func__
);
93 msi_bitmap_free_hwirqs(&msi_data
->bitmap
, int_no
, 1);
96 dev_dbg(&dev
->dev
, "%s: virq = %d\n", __func__
, virq
);
98 /* Setup msi address space */
99 msg
.address_hi
= msi_data
->msi_addr_hi
;
100 msg
.address_lo
= msi_data
->msi_addr_lo
;
102 irq_set_msi_desc(virq
, entry
);
104 pci_write_msi_msg(virq
, &msg
);
109 void ppc4xx_teardown_msi_irqs(struct pci_dev
*dev
)
111 struct msi_desc
*entry
;
112 struct ppc4xx_msi
*msi_data
= &ppc4xx_msi
;
113 irq_hw_number_t hwirq
;
115 dev_dbg(&dev
->dev
, "PCIE-MSI: tearing down msi irqs\n");
117 for_each_pci_msi_entry(entry
, dev
) {
120 hwirq
= virq_to_hw(entry
->irq
);
121 irq_set_msi_desc(entry
->irq
, NULL
);
122 irq_dispose_mapping(entry
->irq
);
123 msi_bitmap_free_hwirqs(&msi_data
->bitmap
, hwirq
, 1);
127 static int ppc4xx_setup_pcieh_hw(struct platform_device
*dev
,
128 struct resource res
, struct ppc4xx_msi
*msi
)
137 sdr_addr
= of_get_property(dev
->dev
.of_node
, "sdr-base", NULL
);
141 msi_data
= of_get_property(dev
->dev
.of_node
, "msi-data", NULL
);
145 msi_mask
= of_get_property(dev
->dev
.of_node
, "msi-mask", NULL
);
149 msi
->msi_dev
= of_find_node_by_name(NULL
, "ppc4xx-msi");
153 msi
->msi_regs
= of_iomap(msi
->msi_dev
, 0);
154 if (!msi
->msi_regs
) {
155 dev_err(&dev
->dev
, "of_iomap failed\n");
159 dev_dbg(&dev
->dev
, "PCIE-MSI: msi register mapped 0x%x 0x%x\n",
160 (u32
) (msi
->msi_regs
+ PEIH_TERMADH
), (u32
) (msi
->msi_regs
));
162 msi_virt
= dma_alloc_coherent(&dev
->dev
, 64, &msi_phys
, GFP_KERNEL
);
167 msi
->msi_addr_hi
= upper_32_bits(msi_phys
);
168 msi
->msi_addr_lo
= lower_32_bits(msi_phys
& 0xffffffff);
169 dev_dbg(&dev
->dev
, "PCIE-MSI: msi address high 0x%x, low 0x%x\n",
170 msi
->msi_addr_hi
, msi
->msi_addr_lo
);
172 mtdcri(SDR0
, *sdr_addr
, upper_32_bits(res
.start
)); /*HIGH addr */
173 mtdcri(SDR0
, *sdr_addr
+ 1, lower_32_bits(res
.start
)); /* Low addr */
175 /* Progam the Interrupt handler Termination addr registers */
176 out_be32(msi
->msi_regs
+ PEIH_TERMADH
, msi
->msi_addr_hi
);
177 out_be32(msi
->msi_regs
+ PEIH_TERMADL
, msi
->msi_addr_lo
);
179 /* Program MSI Expected data and Mask bits */
180 out_be32(msi
->msi_regs
+ PEIH_MSIED
, *msi_data
);
181 out_be32(msi
->msi_regs
+ PEIH_MSIMK
, *msi_mask
);
183 dma_free_coherent(&dev
->dev
, 64, msi_virt
, msi_phys
);
188 iounmap(msi
->msi_regs
);
190 of_node_put(msi
->msi_dev
);
194 static int ppc4xx_of_msi_remove(struct platform_device
*dev
)
196 struct ppc4xx_msi
*msi
= dev
->dev
.platform_data
;
200 for (i
= 0; i
< msi_irqs
; i
++) {
201 virq
= msi
->msi_virqs
[i
];
203 irq_dispose_mapping(virq
);
206 if (msi
->bitmap
.bitmap
)
207 msi_bitmap_free(&msi
->bitmap
);
208 iounmap(msi
->msi_regs
);
209 of_node_put(msi
->msi_dev
);
214 static int ppc4xx_msi_probe(struct platform_device
*dev
)
216 struct ppc4xx_msi
*msi
;
219 struct pci_controller
*phb
;
221 dev_dbg(&dev
->dev
, "PCIE-MSI: Setting up MSI support...\n");
223 msi
= devm_kzalloc(&dev
->dev
, sizeof(*msi
), GFP_KERNEL
);
226 dev
->dev
.platform_data
= msi
;
229 err
= of_address_to_resource(dev
->dev
.of_node
, 0, &res
);
231 dev_err(&dev
->dev
, "%pOF resource error!\n", dev
->dev
.of_node
);
235 msi_irqs
= of_irq_count(dev
->dev
.of_node
);
239 err
= ppc4xx_setup_pcieh_hw(dev
, res
, msi
);
243 err
= ppc4xx_msi_init_allocator(dev
, msi
);
245 dev_err(&dev
->dev
, "Error allocating MSI bitmap\n");
250 list_for_each_entry(phb
, &hose_list
, list_node
) {
251 phb
->controller_ops
.setup_msi_irqs
= ppc4xx_setup_msi_irqs
;
252 phb
->controller_ops
.teardown_msi_irqs
= ppc4xx_teardown_msi_irqs
;
257 ppc4xx_of_msi_remove(dev
);
260 static const struct of_device_id ppc4xx_msi_ids
[] = {
262 .compatible
= "amcc,ppc4xx-msi",
266 static struct platform_driver ppc4xx_msi_driver
= {
267 .probe
= ppc4xx_msi_probe
,
268 .remove
= ppc4xx_of_msi_remove
,
270 .name
= "ppc4xx-msi",
271 .of_match_table
= ppc4xx_msi_ids
,
276 static __init
int ppc4xx_msi_init(void)
278 return platform_driver_register(&ppc4xx_msi_driver
);
281 subsys_initcall(ppc4xx_msi_init
);