summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2020-02-18 08:36:44 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2020-02-18 08:36:44 +0100
commit0a54a21f182751a0f256119d8b048d8d169ed395 (patch)
tree2daba2f3e62dcf27e86a014163c3cf53604ed506 /drivers
parenteae12f79400400f65a824832e0204e4ce9f92758 (diff)
parentab174ea015c36bfe501b29eb296262e03f652091 (diff)
downloadbarebox-0a54a21f182751a0f256119d8b048d8d169ed395.tar.gz
barebox-0a54a21f182751a0f256119d8b048d8d169ed395.tar.xz
Merge branch 'for-next/layerscape'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/pci-layerscape.c130
1 files changed, 89 insertions, 41 deletions
diff --git a/drivers/pci/pci-layerscape.c b/drivers/pci/pci-layerscape.c
index e20dd55b1f..c4ed529181 100644
--- a/drivers/pci/pci-layerscape.c
+++ b/drivers/pci/pci-layerscape.c
@@ -22,6 +22,8 @@
#include <of_address.h>
#include <of_pci.h>
#include <regmap.h>
+#include <magicvar.h>
+#include <globalvar.h>
#include <mfd/syscon.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
@@ -57,6 +59,13 @@ struct ls_pcie_drvdata {
const struct dw_pcie_ops *dw_pcie_ops;
};
+#define PCIE_LUT_ENTRY_COUNT 32
+
+struct ls_pcie_lut_entry {
+ int stream_id;
+ uint16_t devid;
+};
+
struct ls_pcie {
struct dw_pcie pci;
void __iomem *lut;
@@ -65,6 +74,7 @@ struct ls_pcie {
const struct ls_pcie_drvdata *drvdata;
int index;
int next_lut_index;
+ struct ls_pcie_lut_entry luts[PCIE_LUT_ENTRY_COUNT];
};
static struct ls_pcie *to_ls_pcie(struct dw_pcie *pci)
@@ -72,11 +82,6 @@ static struct ls_pcie *to_ls_pcie(struct dw_pcie *pci)
return container_of(pci, struct ls_pcie, pci);
}
-static u32 lut_readl(struct ls_pcie *pcie, unsigned int offset)
-{
- return in_be32(pcie->lut + offset);
-}
-
static void lut_writel(struct ls_pcie *pcie, unsigned int value,
unsigned int offset)
{
@@ -98,8 +103,6 @@ static int ls_pcie_next_streamid(struct ls_pcie *pcie)
return current;
}
-#define PCIE_LUT_ENTRY_COUNT 32
-
static int ls_pcie_next_lut_index(struct ls_pcie *pcie)
{
if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT)
@@ -108,14 +111,6 @@ static int ls_pcie_next_lut_index(struct ls_pcie *pcie)
return -ENOSPC; /* LUT is full */
}
-static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid,
- u32 stream_id)
-{
- /* leave mask as all zeroes, want to match all bits */
- lut_writel(pcie, devid << 16, PCIE_LUT_UDR(index));
- lut_writel(pcie, stream_id | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index));
-}
-
static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
{
struct dw_pcie *pci = &pcie->pci;
@@ -354,6 +349,24 @@ static phandle ls_pcie_get_iommu_handle(struct device_node *np, phandle *handle)
return 0;
}
+/*
+ * Normally every device gets its own stream_id. The stream_ids are communicated
+ * to the kernel in the device tree and are also configured in the controllers
+ * LUT table.
+ * This only works when all PCI devices are known in the bootloader which may not
+ * always be the case. For example, when a PCI device is a FPGA and its firmware
+ * is only loaded under Linux, then the device is not known to barebox and thus
+ * not assigned a stream_id.
+ *
+ * With ls_pcie_share_stream_id = true all devices on a host controller get the
+ * same stream_id assigned.
+ */
+static int ls_pcie_share_stream_id;
+
+BAREBOX_MAGICVAR_NAMED(global_ls_pcie_share_stream_id,
+ global.layerscape_pcie.share_stream_ids,
+ "If true, use a stream_id per host controller and not per device");
+
static int ls_pcie_of_fixup(struct device_node *root, void *ctx)
{
struct ls_pcie *pcie = ctx;
@@ -375,8 +388,6 @@ static int ls_pcie_of_fixup(struct device_node *root, void *ctx)
return -ENODEV;
} while (!of_device_is_compatible(np, pcie->compatible));
- nluts = pcie->next_lut_index;
-
ret = of_property_read_u32(np, "msi-parent", &phandle);
if (ret) {
dev_err(pcie->pci.dev, "Unable to get \"msi-parent\" phandle\n");
@@ -389,28 +400,56 @@ static int ls_pcie_of_fixup(struct device_node *root, void *ctx)
return ret;
}
- msi_map = xmalloc(nluts * sizeof(u32) * 4);
- iommu_map = xmalloc(nluts * sizeof(u32) * 4);
-
- for (i = 0; i < nluts; i++) {
- u32 udr = lut_readl(pcie, PCIE_LUT_UDR(i));
- u32 ldr = lut_readl(pcie, PCIE_LUT_LDR(i));
-
- if (!(ldr & PCIE_LUT_ENABLE))
- break;
-
- devid = udr >> 16;
- stream_id = ldr & 0x7fff;
-
- msi_map[i * 4] = devid;
- msi_map[i * 4 + 1] = phandle;
- msi_map[i * 4 + 2] = stream_id;
- msi_map[i * 4 + 3] = 1;
+ if (ls_pcie_share_stream_id) {
+ nluts = 1;
+ iommu_map = xmalloc(nluts * sizeof(u32) * 4);
+ msi_map = xmalloc(nluts * sizeof(u32) * 4);
+ stream_id = pcie->luts[0].stream_id;
+
+ dev_dbg(pcie->pci.dev, "Using stream_id %d\n", stream_id);
+
+ msi_map[0] = 0;
+ msi_map[1] = phandle;
+ msi_map[2] = stream_id;
+ msi_map[3] = 0x10000;
+
+ iommu_map[0] = 0;
+ iommu_map[1] = iommu_handle;
+ iommu_map[2] = stream_id;
+ iommu_map[3] = 0x10000;
+
+ lut_writel(pcie, 0xffff, PCIE_LUT_UDR(0));
+ lut_writel(pcie, pcie->luts[0].stream_id | PCIE_LUT_ENABLE, PCIE_LUT_LDR(0));
+ } else {
+ nluts = pcie->next_lut_index;
+ iommu_map = xmalloc(nluts * sizeof(u32) * 4);
+ msi_map = xmalloc(nluts * sizeof(u32) * 4);
+
+ for (i = 0; i < nluts; i++) {
+ devid = pcie->luts[i].devid;
+ stream_id = pcie->luts[i].stream_id;
+
+ dev_dbg(pcie->pci.dev, "Using stream_id %d for device 0x%04x\n",
+ stream_id, devid);
+
+ msi_map[i * 4] = devid;
+ msi_map[i * 4 + 1] = phandle;
+ msi_map[i * 4 + 2] = stream_id;
+ msi_map[i * 4 + 3] = 1;
+
+ iommu_map[i * 4] = devid;
+ iommu_map[i * 4 + 1] = iommu_handle;
+ iommu_map[i * 4 + 2] = stream_id;
+ iommu_map[i * 4 + 3] = 1;
+
+ lut_writel(pcie, pcie->luts[i].devid << 16, PCIE_LUT_UDR(i));
+ lut_writel(pcie, pcie->luts[i].stream_id | PCIE_LUT_ENABLE, PCIE_LUT_LDR(i));
+ }
+ }
- iommu_map[i * 4] = devid;
- iommu_map[i * 4 + 1] = iommu_handle;
- iommu_map[i * 4 + 2] = stream_id;
- iommu_map[i * 4 + 3] = 1;
+ for (i = nluts; i < PCIE_LUT_ENTRY_COUNT; i++) {
+ lut_writel(pcie, 0, PCIE_LUT_UDR(i));
+ lut_writel(pcie, 0, PCIE_LUT_LDR(i));
}
/*
@@ -448,6 +487,13 @@ static int __init ls_pcie_probe(struct device_d *dev)
struct resource *dbi_base;
const struct of_device_id *match;
int ret;
+ static int once;
+
+ if (!once) {
+ globalvar_add_simple_bool("layerscape_pcie.share_stream_ids",
+ &ls_pcie_share_stream_id);
+ once = 1;
+ }
pcie = xzalloc(sizeof(*pcie));
if (!pcie)
@@ -502,6 +548,7 @@ static void ls_pcie_fixup(struct pci_dev *pcidev)
struct dw_pcie *dwpcie = container_of(pp, struct dw_pcie, pp);
struct ls_pcie *lspcie = container_of(dwpcie, struct ls_pcie, pci);
int stream_id, index;
+ uint32_t devid;
int base_bus_num = 0;
stream_id = ls_pcie_next_streamid(lspcie);
@@ -513,9 +560,10 @@ static void ls_pcie_fixup(struct pci_dev *pcidev)
p = p->parent_bus;
}
- ls_pcie_lut_set_mapping(lspcie, index,
- (pcidev->bus->number - base_bus_num) << 8 | pcidev->devfn,
- stream_id);
+ devid = (pcidev->bus->number - base_bus_num) << 8 | pcidev->devfn;
+
+ lspcie->luts[index].devid = devid;
+ lspcie->luts[index].stream_id = stream_id;
}
DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ls_pcie_fixup);