Skip to content

Commit 8d35c2b

Browse files
committed
Merge branch 'pci/controller/microchip'
- Set up the inbound address translation based on whether the platform allows coherent or non-coherent DMA (Daire McNamara) - Update DT binding such that platforms are DMA-coherent by default and must specify 'dma-noncoherent' if needed (Conor Dooley) * pci/controller/microchip: dt-bindings: PCI: microchip,pcie-host: Allow dma-noncoherent PCI: microchip: Set inbound address translation for coherent or non-coherent mode
2 parents 1276ad0 + 04aa999 commit 8d35c2b

File tree

4 files changed

+116
-5
lines changed

4 files changed

+116
-5
lines changed

Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ properties:
5050
items:
5151
pattern: '^fic[0-3]$'
5252

53+
dma-coherent: true
54+
5355
ranges:
5456
minItems: 1
5557
maxItems: 3

drivers/pci/controller/plda/pcie-microchip-host.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,27 @@
77
* Author: Daire McNamara <daire.mcnamara@microchip.com>
88
*/
99

10+
#include <linux/align.h>
11+
#include <linux/bits.h>
1012
#include <linux/bitfield.h>
1113
#include <linux/clk.h>
1214
#include <linux/irqchip/chained_irq.h>
1315
#include <linux/irqdomain.h>
16+
#include <linux/log2.h>
1417
#include <linux/module.h>
1518
#include <linux/msi.h>
1619
#include <linux/of_address.h>
1720
#include <linux/of_pci.h>
1821
#include <linux/pci-ecam.h>
1922
#include <linux/platform_device.h>
23+
#include <linux/wordpart.h>
2024

2125
#include "../../pci.h"
2226
#include "pcie-plda.h"
2327

28+
#define MC_MAX_NUM_INBOUND_WINDOWS 8
29+
#define MPFS_NC_BOUNCE_ADDR 0x80000000
30+
2431
/* PCIe Bridge Phy and Controller Phy offsets */
2532
#define MC_PCIE1_BRIDGE_ADDR 0x00008000u
2633
#define MC_PCIE1_CTRL_ADDR 0x0000a000u
@@ -607,6 +614,91 @@ static void mc_disable_interrupts(struct mc_pcie *port)
607614
writel_relaxed(GENMASK(31, 0), port->bridge_base_addr + ISTATUS_HOST);
608615
}
609616

617+
static void mc_pcie_setup_inbound_atr(struct mc_pcie *port, int window_index,
618+
u64 axi_addr, u64 pcie_addr, u64 size)
619+
{
620+
u32 table_offset = window_index * ATR_ENTRY_SIZE;
621+
void __iomem *table_addr = port->bridge_base_addr + table_offset;
622+
u32 atr_sz;
623+
u32 val;
624+
625+
atr_sz = ilog2(size) - 1;
626+
627+
val = ALIGN_DOWN(lower_32_bits(pcie_addr), SZ_4K);
628+
val |= FIELD_PREP(ATR_SIZE_MASK, atr_sz);
629+
val |= ATR_IMPL_ENABLE;
630+
631+
writel(val, table_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
632+
633+
writel(upper_32_bits(pcie_addr), table_addr + ATR0_PCIE_WIN0_SRC_ADDR);
634+
635+
writel(lower_32_bits(axi_addr), table_addr + ATR0_PCIE_WIN0_TRSL_ADDR_LSB);
636+
writel(upper_32_bits(axi_addr), table_addr + ATR0_PCIE_WIN0_TRSL_ADDR_UDW);
637+
638+
writel(TRSL_ID_AXI4_MASTER_0, table_addr + ATR0_PCIE_WIN0_TRSL_PARAM);
639+
}
640+
641+
static int mc_pcie_setup_inbound_ranges(struct platform_device *pdev,
642+
struct mc_pcie *port)
643+
{
644+
struct device *dev = &pdev->dev;
645+
struct device_node *dn = dev->of_node;
646+
struct of_range_parser parser;
647+
struct of_range range;
648+
int atr_index = 0;
649+
650+
/*
651+
* MPFS PCIe Root Port is 32-bit only, behind a Fabric Interface
652+
* Controller FPGA logic block which contains the AXI-S interface.
653+
*
654+
* From the point of view of the PCIe Root Port, there are only two
655+
* supported Root Port configurations:
656+
*
657+
* Configuration 1: for use with fully coherent designs; supports a
658+
* window from 0x0 (CPU space) to specified PCIe space.
659+
*
660+
* Configuration 2: for use with non-coherent designs; supports two
661+
* 1 GB windows to CPU space; one mapping CPU space 0 to PCIe space
662+
* 0x80000000 and a second mapping CPU space 0x40000000 to PCIe
663+
* space 0xc0000000. This cfg needs two windows because of how the
664+
* MSI space is allocated in the AXI-S range on MPFS.
665+
*
666+
* The FIC interface outside the PCIe block *must* complete the
667+
* inbound address translation as per MCHP MPFS FPGA design
668+
* guidelines.
669+
*/
670+
if (device_property_read_bool(dev, "dma-noncoherent")) {
671+
/*
672+
* Always need same two tables in this case. Need two tables
673+
* due to hardware interactions between address and size.
674+
*/
675+
mc_pcie_setup_inbound_atr(port, 0, 0,
676+
MPFS_NC_BOUNCE_ADDR, SZ_1G);
677+
mc_pcie_setup_inbound_atr(port, 1, SZ_1G,
678+
MPFS_NC_BOUNCE_ADDR + SZ_1G, SZ_1G);
679+
} else {
680+
/* Find any DMA ranges */
681+
if (of_pci_dma_range_parser_init(&parser, dn)) {
682+
/* No DMA range property - setup default */
683+
mc_pcie_setup_inbound_atr(port, 0, 0, 0, SZ_4G);
684+
return 0;
685+
}
686+
687+
for_each_of_range(&parser, &range) {
688+
if (atr_index >= MC_MAX_NUM_INBOUND_WINDOWS) {
689+
dev_err(dev, "too many inbound ranges; %d available tables\n",
690+
MC_MAX_NUM_INBOUND_WINDOWS);
691+
return -EINVAL;
692+
}
693+
mc_pcie_setup_inbound_atr(port, atr_index, 0,
694+
range.pci_addr, range.size);
695+
atr_index++;
696+
}
697+
}
698+
699+
return 0;
700+
}
701+
610702
static int mc_platform_init(struct pci_config_window *cfg)
611703
{
612704
struct device *dev = cfg->parent;
@@ -627,6 +719,10 @@ static int mc_platform_init(struct pci_config_window *cfg)
627719
if (ret)
628720
return ret;
629721

722+
ret = mc_pcie_setup_inbound_ranges(pdev, port);
723+
if (ret)
724+
return ret;
725+
630726
port->plda.event_ops = &mc_event_ops;
631727
port->plda.event_irq_chip = &mc_event_irq_chip;
632728
port->plda.events_bitmap = GENMASK(NUM_EVENTS - 1, 0);

drivers/pci/controller/plda/pcie-plda-host.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
* Author: Daire McNamara <daire.mcnamara@microchip.com>
99
*/
1010

11+
#include <linux/align.h>
12+
#include <linux/bitfield.h>
1113
#include <linux/irqchip/chained_irq.h>
1214
#include <linux/irqdomain.h>
1315
#include <linux/msi.h>
1416
#include <linux/pci_regs.h>
1517
#include <linux/pci-ecam.h>
18+
#include <linux/wordpart.h>
1619

1720
#include "pcie-plda.h"
1821

@@ -502,8 +505,9 @@ void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
502505
writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
503506
ATR0_AXI4_SLV0_TRSL_PARAM);
504507

505-
val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
506-
ATR_IMPL_ENABLE;
508+
val = ALIGN_DOWN(lower_32_bits(axi_addr), SZ_4K);
509+
val |= FIELD_PREP(ATR_SIZE_MASK, atr_sz);
510+
val |= ATR_IMPL_ENABLE;
507511
writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
508512
ATR0_AXI4_SLV0_SRCADDR_PARAM);
509513

@@ -518,13 +522,20 @@ void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
518522
val = upper_32_bits(pci_addr);
519523
writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
520524
ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
525+
}
526+
EXPORT_SYMBOL_GPL(plda_pcie_setup_window);
527+
528+
void plda_pcie_setup_inbound_address_translation(struct plda_pcie_rp *port)
529+
{
530+
void __iomem *bridge_base_addr = port->bridge_addr;
531+
u32 val;
521532

522533
val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
523534
val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
524535
writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
525536
writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
526537
}
527-
EXPORT_SYMBOL_GPL(plda_pcie_setup_window);
538+
EXPORT_SYMBOL_GPL(plda_pcie_setup_inbound_address_translation);
528539

529540
int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
530541
struct plda_pcie_rp *port)

drivers/pci/controller/plda/pcie-plda.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,15 @@
8989

9090
/* PCIe AXI slave table init defines */
9191
#define ATR0_AXI4_SLV0_SRCADDR_PARAM 0x800u
92-
#define ATR_SIZE_SHIFT 1
93-
#define ATR_IMPL_ENABLE 1
92+
#define ATR_SIZE_MASK GENMASK(6, 1)
93+
#define ATR_IMPL_ENABLE BIT(0)
9494
#define ATR0_AXI4_SLV0_SRC_ADDR 0x804u
9595
#define ATR0_AXI4_SLV0_TRSL_ADDR_LSB 0x808u
9696
#define ATR0_AXI4_SLV0_TRSL_ADDR_UDW 0x80cu
9797
#define ATR0_AXI4_SLV0_TRSL_PARAM 0x810u
9898
#define PCIE_TX_RX_INTERFACE 0x00000000u
9999
#define PCIE_CONFIG_INTERFACE 0x00000001u
100+
#define TRSL_ID_AXI4_MASTER_0 0x00000004u
100101

101102
#define CONFIG_SPACE_ADDR_OFFSET 0x1000u
102103

@@ -204,6 +205,7 @@ int plda_init_interrupts(struct platform_device *pdev,
204205
void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
205206
phys_addr_t axi_addr, phys_addr_t pci_addr,
206207
size_t size);
208+
void plda_pcie_setup_inbound_address_translation(struct plda_pcie_rp *port);
207209
int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
208210
struct plda_pcie_rp *port);
209211
int plda_pcie_host_init(struct plda_pcie_rp *port, struct pci_ops *ops,

0 commit comments

Comments
 (0)