aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pcie_apple.c100
1 files changed, 71 insertions, 29 deletions
diff --git a/drivers/pci/pcie_apple.c b/drivers/pci/pcie_apple.c
index b934fdbc35c..21bafba3b0e 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 */ }
};