File Index
Files and directories
Sign in
FILE

pcie-mobiveil-host.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * PCIe host controller driver for Mobiveil PCIe Host controller
  4 *
  5 * Copyright (c) 2018 Mobiveil Inc.
  6 * Copyright 2019-2020 NXP
  7 *
  8 * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>
  9 *	   Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
 10 */
 11
 12#include <linux/init.h>
 13#include <linux/interrupt.h>
 14#include <linux/irq.h>
 15#include <linux/irqchip/irq-msi-lib.h>
 16#include <linux/irqchip/chained_irq.h>
 17#include <linux/irqdomain.h>
 18#include <linux/kernel.h>
 19#include <linux/module.h>
 20#include <linux/msi.h>
 21#include <linux/of_pci.h>
 22#include <linux/pci.h>
 23#include <linux/platform_device.h>
 24#include <linux/slab.h>
 25
 26#include "pcie-mobiveil.h"
 27
 28static bool mobiveil_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
 29{
 30	/* Only one device down on each root port */
 31	if (pci_is_root_bus(bus) && (devfn > 0))
 32		return false;
 33
 34	/*
 35	 * Do not read more than one device on the bus directly
 36	 * attached to RC
 37	 */
 38	if ((bus->primary == to_pci_host_bridge(bus->bridge)->busnr) && (PCI_SLOT(devfn) > 0))
 39		return false;
 40
 41	return true;
 42}
 43
 44/*
 45 * mobiveil_pcie_map_bus - routine to get the configuration base of either
 46 * root port or endpoint
 47 */
 48static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
 49					   unsigned int devfn, int where)
 50{
 51	struct mobiveil_pcie *pcie = bus->sysdata;
 52	struct mobiveil_root_port *rp = &pcie->rp;
 53	u32 value;
 54
 55	if (!mobiveil_pcie_valid_device(bus, devfn))
 56		return NULL;
 57
 58	/* RC config access */
 59	if (pci_is_root_bus(bus))
 60		return pcie->csr_axi_slave_base + where;
 61
 62	/*
 63	 * EP config access (in Config/APIO space)
 64	 * Program PEX Address base (31..16 bits) with appropriate value
 65	 * (BDF) in PAB_AXI_AMAP_PEX_WIN_L0 Register.
 66	 * Relies on pci_lock serialization
 67	 */
 68	value = bus->number << PAB_BUS_SHIFT |
 69		PCI_SLOT(devfn) << PAB_DEVICE_SHIFT |
 70		PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT;
 71
 72	mobiveil_csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
 73
 74	return rp->config_axi_slave_base + where;
 75}
 76
 77static struct pci_ops mobiveil_pcie_ops = {
 78	.map_bus = mobiveil_pcie_map_bus,
 79	.read = pci_generic_config_read,
 80	.write = pci_generic_config_write,
 81};
 82
 83static void mobiveil_pcie_isr(struct irq_desc *desc)
 84{
 85	struct irq_chip *chip = irq_desc_get_chip(desc);
 86	struct mobiveil_pcie *pcie = irq_desc_get_handler_data(desc);
 87	struct device *dev = &pcie->pdev->dev;
 88	struct mobiveil_root_port *rp = &pcie->rp;
 89	struct mobiveil_msi *msi = &rp->msi;
 90	u32 msi_data, msi_addr_lo, msi_addr_hi;
 91	u32 intr_status, msi_status;
 92	unsigned long shifted_status;
 93	u32 bit, val, mask;
 94
 95	/*
 96	 * The core provides a single interrupt for both INTx/MSI messages.
 97	 * So we'll read both INTx and MSI status
 98	 */
 99
100	chained_irq_enter(chip, desc);
101
102	/* read INTx status */
103	val = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
104	mask = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
105	intr_status = val & mask;
106
107	/* Handle INTx */
108	if (intr_status & PAB_INTP_INTX_MASK) {
109		shifted_status = mobiveil_csr_readl(pcie,
110						    PAB_INTP_AMBA_MISC_STAT);
111		shifted_status &= PAB_INTP_INTX_MASK;
112		shifted_status >>= PAB_INTX_START;
113		do {
114			for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) {
115				int ret;
116				ret = generic_handle_domain_irq(rp->intx_domain,
117								bit + 1);
118				if (ret)
119					dev_err_ratelimited(dev, "unexpected IRQ, INT%d\n",
120							    bit);
121
122				/* clear interrupt handled */
123				mobiveil_csr_writel(pcie,
124						    1 << (PAB_INTX_START + bit),
125						    PAB_INTP_AMBA_MISC_STAT);
126			}
127
128			shifted_status = mobiveil_csr_readl(pcie,
129							    PAB_INTP_AMBA_MISC_STAT);
130			shifted_status &= PAB_INTP_INTX_MASK;
131			shifted_status >>= PAB_INTX_START;
132		} while (shifted_status != 0);
133	}
134
135	/* read extra MSI status register */
136	msi_status = readl_relaxed(pcie->apb_csr_base + MSI_STATUS_OFFSET);
137
138	/* handle MSI interrupts */
139	while (msi_status & 1) {
140		msi_data = readl_relaxed(pcie->apb_csr_base + MSI_DATA_OFFSET);
141
142		/*
143		 * MSI_STATUS_OFFSET register gets updated to zero
144		 * once we pop not only the MSI data but also address
145		 * from MSI hardware FIFO. So keeping these following
146		 * two dummy reads.
147		 */
148		msi_addr_lo = readl_relaxed(pcie->apb_csr_base +
149					    MSI_ADDR_L_OFFSET);
150		msi_addr_hi = readl_relaxed(pcie->apb_csr_base +
151					    MSI_ADDR_H_OFFSET);
152		dev_dbg(dev, "MSI registers, data: %08x, addr: %08x:%08x\n",
153			msi_data, msi_addr_hi, msi_addr_lo);
154
155		generic_handle_domain_irq(msi->dev_domain, msi_data);
156
157		msi_status = readl_relaxed(pcie->apb_csr_base +
158					   MSI_STATUS_OFFSET);
159	}
160
161	/* Clear the interrupt status */
162	mobiveil_csr_writel(pcie, intr_status, PAB_INTP_AMBA_MISC_STAT);
163	chained_irq_exit(chip, desc);
164}
165
166static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
167{
168	struct device *dev = &pcie->pdev->dev;
169	struct platform_device *pdev = pcie->pdev;
170	struct device_node *node = dev->of_node;
171	struct mobiveil_root_port *rp = &pcie->rp;
172	struct resource *res;
173
174	/* map config resource */
175	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
176					   "config_axi_slave");
177	rp->config_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
178	if (IS_ERR(rp->config_axi_slave_base))
179		return PTR_ERR(rp->config_axi_slave_base);
180	rp->ob_io_res = res;
181
182	/* map csr resource */
183	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
184					   "csr_axi_slave");
185	pcie->csr_axi_slave_base = devm_pci_remap_cfg_resource(dev, res);
186	if (IS_ERR(pcie->csr_axi_slave_base))
187		return PTR_ERR(pcie->csr_axi_slave_base);
188	pcie->pcie_reg_base = res->start;
189
190	/* read the number of windows requested */
191	if (of_property_read_u32(node, "apio-wins", &pcie->apio_wins))
192		pcie->apio_wins = MAX_PIO_WINDOWS;
193
194	if (of_property_read_u32(node, "ppio-wins", &pcie->ppio_wins))
195		pcie->ppio_wins = MAX_PIO_WINDOWS;
196
197	return 0;
198}
199
200static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie)
201{
202	phys_addr_t msg_addr = pcie->pcie_reg_base;
203	struct mobiveil_msi *msi = &pcie->rp.msi;
204
205	msi->num_of_vectors = PCI_NUM_MSI;
206	msi->msi_pages_phys = (phys_addr_t)msg_addr;
207
208	writel_relaxed(lower_32_bits(msg_addr),
209		       pcie->apb_csr_base + MSI_BASE_LO_OFFSET);
210	writel_relaxed(upper_32_bits(msg_addr),
211		       pcie->apb_csr_base + MSI_BASE_HI_OFFSET);
212	writel_relaxed(4096, pcie->apb_csr_base + MSI_SIZE_OFFSET);
213	writel_relaxed(1, pcie->apb_csr_base + MSI_ENABLE_OFFSET);
214}
215
216int mobiveil_host_init(struct mobiveil_pcie *pcie, bool reinit)
217{
218	struct mobiveil_root_port *rp = &pcie->rp;
219	struct pci_host_bridge *bridge = rp->bridge;
220	u32 value, pab_ctrl, type;
221	struct resource_entry *win;
222
223	pcie->ib_wins_configured = 0;
224	pcie->ob_wins_configured = 0;
225
226	if (!reinit) {
227		/* setup bus numbers */
228		value = mobiveil_csr_readl(pcie, PCI_PRIMARY_BUS);
229		value &= 0xff000000;
230		value |= 0x00ff0100;
231		mobiveil_csr_writel(pcie, value, PCI_PRIMARY_BUS);
232	}
233
234	/*
235	 * program Bus Master Enable Bit in Command Register in PAB Config
236	 * Space
237	 */
238	value = mobiveil_csr_readl(pcie, PCI_COMMAND);
239	value |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
240	mobiveil_csr_writel(pcie, value, PCI_COMMAND);
241
242	/*
243	 * program PIO Enable Bit to 1 (and PEX PIO Enable to 1) in PAB_CTRL
244	 * register
245	 */
246	pab_ctrl = mobiveil_csr_readl(pcie, PAB_CTRL);
247	pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
248	mobiveil_csr_writel(pcie, pab_ctrl, PAB_CTRL);
249
250	/*
251	 * program PIO Enable Bit to 1 and Config Window Enable Bit to 1 in
252	 * PAB_AXI_PIO_CTRL Register
253	 */
254	value = mobiveil_csr_readl(pcie, PAB_AXI_PIO_CTRL);
255	value |= APIO_EN_MASK;
256	mobiveil_csr_writel(pcie, value, PAB_AXI_PIO_CTRL);
257
258	/* Enable PCIe PIO master */
259	value = mobiveil_csr_readl(pcie, PAB_PEX_PIO_CTRL);
260	value |= 1 << PIO_ENABLE_SHIFT;
261	mobiveil_csr_writel(pcie, value, PAB_PEX_PIO_CTRL);
262
263	/*
264	 * we'll program one outbound window for config reads and
265	 * another default inbound window for all the upstream traffic
266	 * rest of the outbound windows will be configured according to
267	 * the "ranges" field defined in device tree
268	 */
269
270	/* config outbound translation window */
271	program_ob_windows(pcie, WIN_NUM_0, rp->ob_io_res->start, 0,
272			   CFG_WINDOW_TYPE, resource_size(rp->ob_io_res));
273
274	/* memory inbound translation window */
275	program_ib_windows(pcie, WIN_NUM_0, 0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
276
277	/* Get the I/O and memory ranges from DT */
278	resource_list_for_each_entry(win, &bridge->windows) {
279		if (resource_type(win->res) == IORESOURCE_MEM)
280			type = MEM_WINDOW_TYPE;
281		else if (resource_type(win->res) == IORESOURCE_IO)
282			type = IO_WINDOW_TYPE;
283		else
284			continue;
285
286		/* configure outbound translation window */
287		program_ob_windows(pcie, pcie->ob_wins_configured,
288				   win->res->start,
289				   win->res->start - win->offset,
290				   type, resource_size(win->res));
291	}
292
293	/* fixup for PCIe class register */
294	value = mobiveil_csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
295	value &= 0xff;
296	value |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8;
297	mobiveil_csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
298
299	return 0;
300}
301
302static void mobiveil_mask_intx_irq(struct irq_data *data)
303{
304	struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(data);
305	struct mobiveil_root_port *rp;
306	unsigned long flags;
307	u32 mask, shifted_val;
308
309	rp = &pcie->rp;
310	mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
311	raw_spin_lock_irqsave(&rp->intx_mask_lock, flags);
312	shifted_val = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
313	shifted_val &= ~mask;
314	mobiveil_csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
315	raw_spin_unlock_irqrestore(&rp->intx_mask_lock, flags);
316}
317
318static void mobiveil_unmask_intx_irq(struct irq_data *data)
319{
320	struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(data);
321	struct mobiveil_root_port *rp;
322	unsigned long flags;
323	u32 shifted_val, mask;
324
325	rp = &pcie->rp;
326	mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
327	raw_spin_lock_irqsave(&rp->intx_mask_lock, flags);
328	shifted_val = mobiveil_csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
329	shifted_val |= mask;
330	mobiveil_csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
331	raw_spin_unlock_irqrestore(&rp->intx_mask_lock, flags);
332}
333
334static struct irq_chip intx_irq_chip = {
335	.name = "mobiveil_pcie:intx",
336	.irq_enable = mobiveil_unmask_intx_irq,
337	.irq_disable = mobiveil_mask_intx_irq,
338	.irq_mask = mobiveil_mask_intx_irq,
339	.irq_unmask = mobiveil_unmask_intx_irq,
340};
341
342/* routine to setup the INTx related data */
343static int mobiveil_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
344				  irq_hw_number_t hwirq)
345{
346	irq_set_chip_and_handler(irq, &intx_irq_chip, handle_level_irq);
347	irq_set_chip_data(irq, domain->host_data);
348
349	return 0;
350}
351
352/* INTx domain operations structure */
353static const struct irq_domain_ops intx_domain_ops = {
354	.map = mobiveil_pcie_intx_map,
355};
356
357#define MOBIVEIL_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS		| \
358				     MSI_FLAG_USE_DEF_CHIP_OPS		| \
359				     MSI_FLAG_NO_AFFINITY)
360
361#define MOBIVEIL_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK		| \
362				      MSI_FLAG_PCI_MSIX)
363
364static const struct msi_parent_ops mobiveil_msi_parent_ops = {
365	.required_flags		= MOBIVEIL_MSI_FLAGS_REQUIRED,
366	.supported_flags	= MOBIVEIL_MSI_FLAGS_SUPPORTED,
367	.bus_select_token	= DOMAIN_BUS_PCI_MSI,
368	.prefix			= "Mobiveil-",
369	.init_dev_msi_info	= msi_lib_init_dev_msi_info,
370};
371
372static void mobiveil_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
373{
374	struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(data);
375	phys_addr_t addr = pcie->pcie_reg_base + (data->hwirq * sizeof(int));
376
377	msg->address_lo = lower_32_bits(addr);
378	msg->address_hi = upper_32_bits(addr);
379	msg->data = data->hwirq;
380
381	dev_dbg(&pcie->pdev->dev, "msi#%d address_hi %#x address_lo %#x\n",
382		(int)data->hwirq, msg->address_hi, msg->address_lo);
383}
384
385static struct irq_chip mobiveil_msi_bottom_irq_chip = {
386	.name			= "Mobiveil MSI",
387	.irq_compose_msi_msg	= mobiveil_compose_msi_msg,
388};
389
390static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain,
391					 unsigned int virq,
392					 unsigned int nr_irqs, void *args)
393{
394	struct mobiveil_pcie *pcie = domain->host_data;
395	struct mobiveil_msi *msi = &pcie->rp.msi;
396	unsigned long bit;
397
398	WARN_ON(nr_irqs != 1);
399	mutex_lock(&msi->lock);
400
401	bit = find_first_zero_bit(msi->msi_irq_in_use, msi->num_of_vectors);
402	if (bit >= msi->num_of_vectors) {
403		mutex_unlock(&msi->lock);
404		return -ENOSPC;
405	}
406
407	set_bit(bit, msi->msi_irq_in_use);
408
409	mutex_unlock(&msi->lock);
410
411	irq_domain_set_info(domain, virq, bit, &mobiveil_msi_bottom_irq_chip,
412			    domain->host_data, handle_level_irq, NULL, NULL);
413	return 0;
414}
415
416static void mobiveil_irq_msi_domain_free(struct irq_domain *domain,
417					 unsigned int virq,
418					 unsigned int nr_irqs)
419{
420	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
421	struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(d);
422	struct mobiveil_msi *msi = &pcie->rp.msi;
423
424	mutex_lock(&msi->lock);
425
426	if (!test_bit(d->hwirq, msi->msi_irq_in_use))
427		dev_err(&pcie->pdev->dev, "trying to free unused MSI#%lu\n",
428			d->hwirq);
429	else
430		__clear_bit(d->hwirq, msi->msi_irq_in_use);
431
432	mutex_unlock(&msi->lock);
433}
434static const struct irq_domain_ops msi_domain_ops = {
435	.alloc	= mobiveil_irq_msi_domain_alloc,
436	.free	= mobiveil_irq_msi_domain_free,
437};
438
439static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie)
440{
441	struct device *dev = &pcie->pdev->dev;
442	struct mobiveil_msi *msi = &pcie->rp.msi;
443
444	mutex_init(&msi->lock);
445
446	struct irq_domain_info info = {
447		.fwnode		= dev_fwnode(dev),
448		.ops		= &msi_domain_ops,
449		.host_data	= pcie,
450		.size		= msi->num_of_vectors,
451	};
452
453	msi->dev_domain = msi_create_parent_irq_domain(&info, &mobiveil_msi_parent_ops);
454	if (!msi->dev_domain) {
455		dev_err(dev, "failed to create MSI domain\n");
456		return -ENOMEM;
457	}
458
459	return 0;
460}
461
462static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
463{
464	struct device *dev = &pcie->pdev->dev;
465	struct mobiveil_root_port *rp = &pcie->rp;
466
467	/* setup INTx */
468	rp->intx_domain = irq_domain_create_linear(dev_fwnode(dev), PCI_NUM_INTX, &intx_domain_ops,
469						   pcie);
470	if (!rp->intx_domain) {
471		dev_err(dev, "Failed to get a INTx IRQ domain\n");
472		return -ENOMEM;
473	}
474
475	raw_spin_lock_init(&rp->intx_mask_lock);
476
477	/* setup MSI */
478	return mobiveil_allocate_msi_domains(pcie);
479}
480
481static int mobiveil_pcie_integrated_interrupt_init(struct mobiveil_pcie *pcie)
482{
483	struct platform_device *pdev = pcie->pdev;
484	struct device *dev = &pdev->dev;
485	struct mobiveil_root_port *rp = &pcie->rp;
486	struct resource *res;
487	int ret;
488
489	/* map MSI config resource */
490	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apb_csr");
491	pcie->apb_csr_base = devm_pci_remap_cfg_resource(dev, res);
492	if (IS_ERR(pcie->apb_csr_base))
493		return PTR_ERR(pcie->apb_csr_base);
494
495	/* setup MSI hardware registers */
496	mobiveil_pcie_enable_msi(pcie);
497
498	rp->irq = platform_get_irq(pdev, 0);
499	if (rp->irq < 0)
500		return rp->irq;
501
502	/* initialize the IRQ domains */
503	ret = mobiveil_pcie_init_irq_domain(pcie);
504	if (ret) {
505		dev_err(dev, "Failed creating IRQ Domain\n");
506		return ret;
507	}
508
509	irq_set_chained_handler_and_data(rp->irq, mobiveil_pcie_isr, pcie);
510
511	/* Enable interrupts */
512	mobiveil_csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
513			    PAB_INTP_AMBA_MISC_ENB);
514
515
516	return 0;
517}
518
519static int mobiveil_pcie_interrupt_init(struct mobiveil_pcie *pcie)
520{
521	struct mobiveil_root_port *rp = &pcie->rp;
522
523	if (rp->ops->interrupt_init)
524		return rp->ops->interrupt_init(pcie);
525
526	return mobiveil_pcie_integrated_interrupt_init(pcie);
527}
528
529static bool mobiveil_pcie_is_bridge(struct mobiveil_pcie *pcie)
530{
531	u32 header_type;
532
533	header_type = mobiveil_csr_readb(pcie, PCI_HEADER_TYPE);
534	header_type &= PCI_HEADER_TYPE_MASK;
535
536	return header_type == PCI_HEADER_TYPE_BRIDGE;
537}
538
539int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie)
540{
541	struct mobiveil_root_port *rp = &pcie->rp;
542	struct pci_host_bridge *bridge = rp->bridge;
543	struct device *dev = &pcie->pdev->dev;
544	int ret;
545
546	ret = mobiveil_pcie_parse_dt(pcie);
547	if (ret) {
548		dev_err(dev, "Parsing DT failed, ret: %x\n", ret);
549		return ret;
550	}
551
552	if (!mobiveil_pcie_is_bridge(pcie))
553		return -ENODEV;
554
555	/*
556	 * configure all inbound and outbound windows and prepare the RC for
557	 * config access
558	 */
559	ret = mobiveil_host_init(pcie, false);
560	if (ret) {
561		dev_err(dev, "Failed to initialize host\n");
562		return ret;
563	}
564
565	ret = mobiveil_pcie_interrupt_init(pcie);
566	if (ret) {
567		dev_err(dev, "Interrupt init failed\n");
568		return ret;
569	}
570
571	/* Initialize bridge */
572	bridge->sysdata = pcie;
573	bridge->ops = &mobiveil_pcie_ops;
574
575	ret = mobiveil_bringup_link(pcie);
576	if (ret) {
577		dev_info(dev, "link bring-up failed\n");
578		return ret;
579	}
580
581	return pci_host_probe(bridge);
582}
~/ Read-only file preview.