diff mbox series

pci: mediatek: add support for upstream split PCIe node

Message ID 20240812123150.20598-1-ansuelsmth@gmail.com
State Accepted
Delegated to: Tom Rini
Headers show
Series pci: mediatek: add support for upstream split PCIe node | expand

Commit Message

Christian Marangi Aug. 12, 2024, 12:31 p.m. UTC
Add support for upstream linux split PCIe node.

Upstream linux have an alternative way to declare PCIe nodes that splits
them in dedicated nodes for each line instead of putting them all in one
node.

Detect this by checking if the mediatek,generic-pciecfg node is passed
as it's used to reference the common address for all the PCIe lines.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/pci/pcie_mediatek.c | 127 ++++++++++++++++++++++++++++--------
 1 file changed, 100 insertions(+), 27 deletions(-)

Comments

Tom Rini Aug. 27, 2024, 6:35 p.m. UTC | #1
On Mon, 12 Aug 2024 14:31:48 +0200, Christian Marangi wrote:

> Add support for upstream linux split PCIe node.
> 
> Upstream linux have an alternative way to declare PCIe nodes that splits
> them in dedicated nodes for each line instead of putting them all in one
> node.
> 
> Detect this by checking if the mediatek,generic-pciecfg node is passed
> as it's used to reference the common address for all the PCIe lines.
> 
> [...]

Applied to u-boot/next, thanks!
diff mbox series

Patch

diff --git a/drivers/pci/pcie_mediatek.c b/drivers/pci/pcie_mediatek.c
index 04d8cc29afd..d88d850924c 100644
--- a/drivers/pci/pcie_mediatek.c
+++ b/drivers/pci/pcie_mediatek.c
@@ -524,7 +524,7 @@  exit:
 	mtk_pcie_port_free(port);
 }
 
-static int mtk_pcie_parse_port(struct udevice *dev, u32 slot)
+static int mtk_pcie_parse_port(struct udevice *dev, u32 slot, int index)
 {
 	struct mtk_pcie *pcie = dev_get_priv(dev);
 	struct mtk_pcie_port *port;
@@ -545,11 +545,11 @@  static int mtk_pcie_parse_port(struct udevice *dev, u32 slot)
 	if (err)
 		return err;
 
-	err = reset_get_by_index(dev, slot, &port->reset);
+	err = reset_get_by_index(dev, index, &port->reset);
 	if (err)
 		return err;
 
-	err = generic_phy_get_by_index(dev, slot, &port->phy);
+	err = generic_phy_get_by_index(dev, index, &port->phy);
 	if (err)
 		return err;
 
@@ -631,18 +631,58 @@  static int mtk_pcie_parse_port_v2(struct udevice *dev, u32 slot)
 	return 0;
 }
 
+static int mtk_pcie_subsys_get(struct udevice *dev)
+{
+	struct mtk_pcie *pcie = dev_get_priv(dev);
+	ofnode cfg_node;
+	fdt_addr_t addr;
+
+	cfg_node = ofnode_by_compatible(ofnode_null(),
+					"mediatek,generic-pciecfg");
+	if (!ofnode_valid(cfg_node))
+		return -ENOENT;
+
+	addr = ofnode_get_addr(cfg_node);
+	if (addr == FDT_ADDR_T_NONE)
+		return -ENODEV;
+
+	pcie->base = map_physmem(addr, 0, MAP_NOCACHE);
+	if (!pcie->base)
+		return -ENOENT;
+
+	return 0;
+}
+
 static int mtk_pcie_probe(struct udevice *dev)
 {
 	struct mtk_pcie *pcie = dev_get_priv(dev);
 	struct mtk_pcie_port *port, *tmp;
+	bool split_pcie_node = false;
 	ofnode subnode;
+	unsigned int slot;
 	int err;
 
 	INIT_LIST_HEAD(&pcie->ports);
 
-	pcie->base = dev_remap_addr_name(dev, "subsys");
-	if (!pcie->base)
-		return -ENOENT;
+	/* Check if upstream implementation is used */
+	err = mtk_pcie_subsys_get(dev);
+	if (!err) {
+		/*
+		 * Assume split port node implementation with "mediatek,generic-pciecfg"
+		 * found. We check reg-names and check if the node is for port0 or port1.
+		 */
+		split_pcie_node = true;
+		if (!strcmp(dev_read_string(dev, "reg-names"), "port0"))
+			slot = 0;
+		else if (!strcmp(dev_read_string(dev, "reg-names"), "port1"))
+			slot = 1;
+		else
+			return -EINVAL;
+	} else {
+		pcie->base = dev_remap_addr_name(dev, "subsys");
+		if (!pcie->base)
+			return -ENOENT;
+	}
 
 	err = clk_get_by_name(dev, "free_ck", &pcie->free_ck);
 	if (err)
@@ -653,20 +693,27 @@  static int mtk_pcie_probe(struct udevice *dev)
 	if (err)
 		return err;
 
-	dev_for_each_subnode(subnode, dev) {
-		struct fdt_pci_addr addr;
-		u32 slot = 0;
+	if (!split_pcie_node) {
+		dev_for_each_subnode(subnode, dev) {
+			struct fdt_pci_addr addr;
 
-		if (!ofnode_is_enabled(subnode))
-			continue;
+			slot = 0;
 
-		err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL);
-		if (err)
-			return err;
+			if (!ofnode_is_enabled(subnode))
+				continue;
 
-		slot = PCI_DEV(addr.phys_hi);
+			err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL);
+			if (err)
+				return err;
 
-		err = mtk_pcie_parse_port(dev, slot);
+			slot = PCI_DEV(addr.phys_hi);
+
+			err = mtk_pcie_parse_port(dev, slot, slot);
+			if (err)
+				return err;
+		}
+	} else {
+		err = mtk_pcie_parse_port(dev, slot, 0);
 		if (err)
 			return err;
 	}
@@ -682,28 +729,54 @@  static int mtk_pcie_probe_v2(struct udevice *dev)
 {
 	struct mtk_pcie *pcie = dev_get_priv(dev);
 	struct mtk_pcie_port *port, *tmp;
-	struct fdt_pci_addr addr;
+	bool split_pcie_node = false;
 	ofnode subnode;
 	unsigned int slot;
 	int err;
 
 	INIT_LIST_HEAD(&pcie->ports);
 
-	pcie->base = dev_remap_addr_name(dev, "subsys");
-	if (!pcie->base)
-		return -ENOENT;
+	/* Check if upstream implementation is used */
+	err = mtk_pcie_subsys_get(dev);
+	if (!err) {
+		/*
+		 * Assume split port node implementation with "mediatek,generic-pciecfg"
+		 * found. We check reg-names and check if the node is for port0 or port1.
+		 */
+		split_pcie_node = true;
+		if (!strcmp(dev_read_string(dev, "reg-names"), "port0"))
+			slot = 0;
+		else if (!strcmp(dev_read_string(dev, "reg-names"), "port1"))
+			slot = 1;
+		else
+			return -EINVAL;
+	} else {
+		pcie->base = dev_remap_addr_name(dev, "subsys");
+		if (!pcie->base)
+			return -ENOENT;
+	}
 
 	pcie->priv = dev;
 
-	dev_for_each_subnode(subnode, dev) {
-		if (!ofnode_is_enabled(subnode))
-			continue;
+	if (!split_pcie_node) {
+		dev_for_each_subnode(subnode, dev) {
+			struct fdt_pci_addr addr;
 
-		err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL);
-		if (err)
-			return err;
+			slot = 0;
 
-		slot = PCI_DEV(addr.phys_hi);
+			if (!ofnode_is_enabled(subnode))
+				continue;
+
+			err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL);
+			if (err)
+				return err;
+
+			slot = PCI_DEV(addr.phys_hi);
+			err = mtk_pcie_parse_port_v2(dev, slot);
+			if (err)
+				return err;
+		}
+	} else {
 		err = mtk_pcie_parse_port_v2(dev, slot);
 		if (err)
 			return err;