pci: layerscape: add pci driver based on DM

There are more than five kinds of Layerscape SoCs. unfortunately,
PCIe controller of each SoC is a little bit different. In order
to avoid too many macro definitions, the patch addes a new
implementation of PCIe driver based on DM. PCIe dts node is
used to describe the difference.

Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: York Sun <york.sun@nxp.com>
diff --git a/drivers/pci/pcie_layerscape_fixup.c b/drivers/pci/pcie_layerscape_fixup.c
index 6de9355..c30a330 100644
--- a/drivers/pci/pcie_layerscape_fixup.c
+++ b/drivers/pci/pcie_layerscape_fixup.c
@@ -37,7 +37,11 @@
 
 	return next_stream_id++;
 }
+#endif
 
+#ifndef CONFIG_DM_PCI
+
+#ifdef CONFIG_FSL_LSCH3
 /*
  * Program a single LUT entry
  */
@@ -197,6 +201,152 @@
 #endif
 }
 
+#else /* CONFIG_DM_PCI */
+
+#ifdef CONFIG_FSL_LSCH3
+static void lut_writel(struct ls_pcie *pcie, unsigned int value,
+		       unsigned int offset)
+{
+	if (pcie->big_endian)
+		out_be32(pcie->lut + offset, value);
+	else
+		out_le32(pcie->lut + offset, value);
+}
+
+/*
+ * Program a single LUT entry
+ */
+static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid,
+				    u32 streamid)
+{
+	/* leave mask as all zeroes, want to match all bits */
+	lut_writel(pcie, devid << 16, PCIE_LUT_UDR(index));
+	lut_writel(pcie, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index));
+}
+
+/*
+ * An msi-map is a property to be added to the pci controller
+ * node.  It is a table, where each entry consists of 4 fields
+ * e.g.:
+ *
+ *      msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count]
+ *                 [devid] [phandle-to-msi-ctrl] [stream-id] [count]>;
+ */
+static void fdt_pcie_set_msi_map_entry(void *blob, struct ls_pcie *pcie,
+				       u32 devid, u32 streamid)
+{
+	u32 *prop;
+	u32 phandle;
+	int nodeoffset;
+
+	/* find pci controller node */
+	nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
+						   pcie->dbi_res.start);
+	if (nodeoffset < 0) {
+#ifdef FSL_PCIE_COMPAT /* Compatible with older version of dts node */
+		nodeoffset = fdt_node_offset_by_compat_reg(blob,
+				FSL_PCIE_COMPAT, pcie->dbi_res.start);
+		if (nodeoffset < 0)
+			return;
+#else
+		return;
+#endif
+	}
+
+	/* get phandle to MSI controller */
+	prop = (u32 *)fdt_getprop(blob, nodeoffset, "msi-parent", 0);
+	if (prop == NULL) {
+		debug("\n%s: ERROR: missing msi-parent: PCIe%d\n",
+		      __func__, pcie->idx);
+		return;
+	}
+	phandle = fdt32_to_cpu(*prop);
+
+	/* set one msi-map row */
+	fdt_appendprop_u32(blob, nodeoffset, "msi-map", devid);
+	fdt_appendprop_u32(blob, nodeoffset, "msi-map", phandle);
+	fdt_appendprop_u32(blob, nodeoffset, "msi-map", streamid);
+	fdt_appendprop_u32(blob, nodeoffset, "msi-map", 1);
+}
+
+static void fdt_fixup_pcie(void *blob)
+{
+	struct udevice *dev, *bus;
+	struct ls_pcie *pcie;
+	int streamid;
+	int index;
+	pci_dev_t bdf;
+
+	/* Scan all known buses */
+	for (pci_find_first_device(&dev);
+	     dev;
+	     pci_find_next_device(&dev)) {
+		for (bus = dev; device_is_on_pci_bus(bus);)
+			bus = bus->parent;
+		pcie = dev_get_priv(bus);
+
+		streamid = ls_pcie_next_streamid();
+		if (streamid < 0) {
+			debug("ERROR: no stream ids free\n");
+			continue;
+		}
+
+		index = ls_pcie_next_lut_index(pcie);
+		if (index < 0) {
+			debug("ERROR: no LUT indexes free\n");
+			continue;
+		}
+
+		/* the DT fixup must be relative to the hose first_busno */
+		bdf = dm_pci_get_bdf(dev) - PCI_BDF(bus->seq, 0, 0);
+		/* map PCI b.d.f to streamID in LUT */
+		ls_pcie_lut_set_mapping(pcie, index, bdf >> 8,
+					streamid);
+		/* update msi-map in device tree */
+		fdt_pcie_set_msi_map_entry(blob, pcie, bdf >> 8,
+					   streamid);
+	}
+}
+#endif
+
+static void ft_pcie_ls_setup(void *blob, struct ls_pcie *pcie)
+{
+	int off;
+
+	off = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
+					    pcie->dbi_res.start);
+	if (off < 0) {
+#ifdef FSL_PCIE_COMPAT /* Compatible with older version of dts node */
+		off = fdt_node_offset_by_compat_reg(blob,
+						    FSL_PCIE_COMPAT,
+						    pcie->dbi_res.start);
+		if (off < 0)
+			return;
+#else
+		return;
+#endif
+	}
+
+	if (pcie->enabled)
+		fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0);
+	else
+		fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+}
+
+/* Fixup Kernel DT for PCIe */
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+	struct ls_pcie *pcie;
+
+	list_for_each_entry(pcie, &ls_pcie_list, list)
+		ft_pcie_ls_setup(blob, pcie);
+
+#ifdef CONFIG_FSL_LSCH3
+	fdt_fixup_pcie(blob);
+#endif
+}
+#endif /* CONFIG_DM_PCI */
+
 #else /* !CONFIG_OF_BOARD_SETUP */
 void ft_pci_setup(void *blob, bd_t *bd)
 {