[PATCH 2/2] pci: apple: Add support for M2 Pro/Max

Mark Kettenis kettenis at openbsd.org
Tue May 2 21:30:41 CEST 2023


The PCIe controller on the M2 Pro/Max is different from the one
found on earlier Apple SoCs.  Some registers moved and te meaning
of the bits in some other registers changed.  But they are still
similar enough to handle both controllers in the same driver.

Signed-off-by: Mark Kettenis <kettenis at openbsd.org>
---
 drivers/pci/pcie_apple.c | 100 +++++++++++++++++++++++++++------------
 1 file changed, 71 insertions(+), 29 deletions(-)

diff --git a/drivers/pci/pcie_apple.c b/drivers/pci/pcie_apple.c
index b934fdbc35..21bafba3b0 100644
--- a/drivers/pci/pcie_apple.c
+++ b/drivers/pci/pcie_apple.c
@@ -37,14 +37,18 @@
 #define   CORE_RC_STAT_READY		BIT(0)
 #define CORE_FABRIC_STAT		0x04000
 #define   CORE_FABRIC_STAT_MASK		0x001F001F
-#define CORE_LANE_CFG(port)		(0x84000 + 0x4000 * (port))
-#define   CORE_LANE_CFG_REFCLK0REQ	BIT(0)
-#define   CORE_LANE_CFG_REFCLK1REQ	BIT(1)
-#define   CORE_LANE_CFG_REFCLK0ACK	BIT(2)
-#define   CORE_LANE_CFG_REFCLK1ACK	BIT(3)
-#define   CORE_LANE_CFG_REFCLKEN	(BIT(9) | BIT(10))
-#define CORE_LANE_CTL(port)		(0x84004 + 0x4000 * (port))
-#define   CORE_LANE_CTL_CFGACC		BIT(15)
+
+#define CORE_PHY_DEFAULT_BASE(port)	(0x84000 + 0x4000 * (port))
+
+#define PHY_LANE_CFG			0x00000
+#define   PHY_LANE_CFG_REFCLK0REQ	BIT(0)
+#define   PHY_LANE_CFG_REFCLK1REQ	BIT(1)
+#define   PHY_LANE_CFG_REFCLK0ACK	BIT(2)
+#define   PHY_LANE_CFG_REFCLK1ACK	BIT(3)
+#define   PHY_LANE_CFG_REFCLKEN		(BIT(9) | BIT(10))
+#define   PHY_LANE_CFG_REFCLKCGEN	(BIT(30) | BIT(31))
+#define PHY_LANE_CTL			0x00004
+#define   PHY_LANE_CTL_CFGACC		BIT(15)
 
 #define PORT_LTSSMCTL			0x00080
 #define   PORT_LTSSMCTL_START		BIT(0)
@@ -116,11 +120,32 @@
 #define   PORT_TUNSTAT_PERST_ACK_PEND	BIT(1)
 #define PORT_PREFMEM_ENABLE		0x00994
 
+struct reg_info {
+	u32 phy_lane_ctl;
+	u32 port_refclk;
+	u32 port_perst;
+};
+
+const struct reg_info t8103_hw = {
+	.phy_lane_ctl = PHY_LANE_CTL,
+	.port_refclk = PORT_REFCLK,
+	.port_perst = PORT_PERST,
+};
+
+#define PORT_T602X_PERST		0x082c
+
+const struct reg_info t602x_hw = {
+	.phy_lane_ctl = 0,
+	.port_refclk = 0,
+	.port_perst = PORT_T602X_PERST,
+};
+
 struct apple_pcie_priv {
 	struct udevice		*dev;
 	void __iomem            *base;
 	void __iomem            *cfg_base;
 	struct list_head	ports;
+	const struct reg_info	*hw;
 };
 
 struct apple_pcie_port {
@@ -128,6 +153,7 @@ struct apple_pcie_port {
 	struct gpio_desc	reset;
 	ofnode			np;
 	void __iomem		*base;
+	void __iomem		*phy;
 	struct list_head	entry;
 	int			idx;
 };
@@ -187,33 +213,32 @@ static int apple_pcie_setup_refclk(struct apple_pcie_priv *pcie,
 	u32 stat;
 	int res;
 
-	res = readl_poll_sleep_timeout(pcie->base + CORE_RC_PHYIF_STAT, stat,
-				       stat & CORE_RC_PHYIF_STAT_REFCLK,
-				       100, 50000);
-	if (res < 0)
-		return res;
+	if (pcie->hw->phy_lane_ctl)
+		rmw_set(PHY_LANE_CTL_CFGACC, port->phy + pcie->hw->phy_lane_ctl);
 
-	rmw_set(CORE_LANE_CTL_CFGACC, pcie->base + CORE_LANE_CTL(port->idx));
-	rmw_set(CORE_LANE_CFG_REFCLK0REQ, pcie->base + CORE_LANE_CFG(port->idx));
+	rmw_set(PHY_LANE_CFG_REFCLK0REQ, port->phy + PHY_LANE_CFG);
 
-	res = readl_poll_sleep_timeout(pcie->base + CORE_LANE_CFG(port->idx),
-				       stat, stat & CORE_LANE_CFG_REFCLK0ACK,
+	res = readl_poll_sleep_timeout(port->phy + PHY_LANE_CFG,
+				       stat, stat & PHY_LANE_CFG_REFCLK0ACK,
 				       100, 50000);
 	if (res < 0)
 		return res;
 
-	rmw_set(CORE_LANE_CFG_REFCLK1REQ, pcie->base + CORE_LANE_CFG(port->idx));
-	res = readl_poll_sleep_timeout(pcie->base + CORE_LANE_CFG(port->idx),
-				       stat, stat & CORE_LANE_CFG_REFCLK1ACK,
+	rmw_set(PHY_LANE_CFG_REFCLK1REQ, port->phy + PHY_LANE_CFG);
+	res = readl_poll_sleep_timeout(port->phy + PHY_LANE_CFG,
+				       stat, stat & PHY_LANE_CFG_REFCLK1ACK,
 				       100, 50000);
 
 	if (res < 0)
 		return res;
 
-	rmw_clear(CORE_LANE_CTL_CFGACC, pcie->base + CORE_LANE_CTL(port->idx));
+	if (pcie->hw->phy_lane_ctl)
+		rmw_clear(PHY_LANE_CTL_CFGACC, port->phy + pcie->hw->phy_lane_ctl);
+
+	rmw_set(PHY_LANE_CFG_REFCLKEN, port->phy + PHY_LANE_CFG);
 
-	rmw_set(CORE_LANE_CFG_REFCLKEN, pcie->base + CORE_LANE_CFG(port->idx));
-	rmw_set(PORT_REFCLK_EN, port->base + PORT_REFCLK);
+	if (pcie->hw->port_refclk)
+		rmw_set(PORT_REFCLK_EN, port->base + pcie->hw->port_refclk);
 
 	return 0;
 }
@@ -225,6 +250,7 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np)
 	fdt_addr_t addr;
 	u32 stat, idx;
 	int ret;
+	char name[16];
 
 	ret = gpio_request_by_name_nodev(np, "reset-gpios", 0, &reset, 0);
 	if (ret)
@@ -244,11 +270,21 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np)
 	port->reset = reset;
 	port->np = np;
 
-	addr = dev_read_addr_index(pcie->dev, port->idx + 2);
+	snprintf(name, sizeof(name), "port%d", port->idx);
+	addr = dev_read_addr_name(pcie->dev, name);
+	if (addr == FDT_ADDR_T_NONE)
+		addr = dev_read_addr_index(pcie->dev, port->idx + 2);
 	if (addr == FDT_ADDR_T_NONE)
 		return -EINVAL;
 	port->base = map_sysmem(addr, 0);
 
+	snprintf(name, sizeof(name), "phy%d", port->idx);
+	addr = dev_read_addr_name(pcie->dev, name);
+	if (addr == FDT_ADDR_T_NONE)
+		port->phy = pcie->base + CORE_PHY_DEFAULT_BASE(port->idx);
+	else
+		port->phy = map_sysmem(addr, 0);
+
 	rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK);
 
 	/* Assert PERST# before setting up the clock */
@@ -262,7 +298,7 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np)
 	udelay(100);
 
 	/* Deassert PERST# */
-	rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
+	rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst);
 	dm_gpio_set_value(&reset, 0);
 
 	/* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
@@ -275,9 +311,6 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np)
 		return ret;
 	}
 
-	rmw_clear(PORT_REFCLK_CGDIS, port->base + PORT_REFCLK);
-	rmw_clear(PORT_APPCLK_CGDIS, port->base + PORT_APPCLK);
-
 	list_add_tail(&port->entry, &pcie->ports);
 
 	writel_relaxed(PORT_LTSSMCTL_START, port->base + PORT_LTSSMCTL);
@@ -289,6 +322,12 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np)
 	readl_poll_sleep_timeout(port->base + PORT_LINKSTS, stat,
 				 (stat & PORT_LINKSTS_UP), 100, 100000);
 
+	if (pcie->hw->port_refclk)
+		rmw_clear(PORT_REFCLK_CGDIS, port->base + PORT_REFCLK);
+	else
+		rmw_set(PHY_LANE_CFG_REFCLKCGEN, port->phy + PHY_LANE_CFG);
+	rmw_clear(PORT_APPCLK_CGDIS, port->base + PORT_APPCLK);
+
 	return 0;
 }
 
@@ -299,6 +338,8 @@ static int apple_pcie_probe(struct udevice *dev)
 	ofnode of_port;
 	int i, ret;
 
+	pcie->hw = (struct reg_info *)dev_get_driver_data(dev);
+
 	pcie->dev = dev;
 	addr = dev_read_addr_index(dev, 0);
 	if (addr == FDT_ADDR_T_NONE)
@@ -341,7 +382,8 @@ static int apple_pcie_remove(struct udevice *dev)
 }
 
 static const struct udevice_id apple_pcie_of_match[] = {
-	{ .compatible = "apple,pcie" },
+	{ .compatible = "apple,t6020-pcie", .data = (ulong)&t602x_hw },
+	{ .compatible = "apple,pcie", .data = (ulong)&t8103_hw },
 	{ /* sentinel */ }
 };
 
-- 
2.40.0



More information about the U-Boot mailing list