diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/Kconfig | 13 | ||||
-rw-r--r-- | drivers/pci/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/pcie_apple.c | 18 | ||||
-rw-r--r-- | drivers/pci/pcie_dw_common.c | 3 | ||||
-rw-r--r-- | drivers/pci/pcie_dw_imx.c | 413 | ||||
-rw-r--r-- | drivers/pci/pcie_intel_fpga.c | 434 | ||||
-rw-r--r-- | drivers/pci/pcie_iproc.c | 1 | ||||
-rw-r--r-- | drivers/pci/pcie_starfive_jh7110.c | 2 |
8 files changed, 390 insertions, 495 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 8ffd88c722d..ea9868425d0 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -183,6 +183,7 @@ config SYS_FSL_PCI_VER_3_X config PCIE_FSL bool "FSL PowerPC PCIe support" select SYS_FSL_PCI_VER_3_X if ARCH_T2080 || ARCH_T4240 + depends on PPC help Say Y here if you want to enable PCIe controller support on FSL PowerPC MPC85xx, MPC86xx, B series, P series and T series SoCs. @@ -190,6 +191,7 @@ config PCIE_FSL config PCI_MPC85XX bool "MPC85XX PowerPC PCI support" + depends on MPC85xx help Say Y here if you want to enable PCI controller support on FSL PowerPC MPC85xx SoC. @@ -265,6 +267,7 @@ config PCIE_LAYERSCAPE config PCIE_LAYERSCAPE_RC bool "Layerscape PCIe Root Complex mode support" + depends on ARM select PCIE_LAYERSCAPE help Enable Layerscape PCIe Root Complex mode driver support. The Layerscape @@ -286,6 +289,7 @@ config PCI_IOMMU_EXTRA_MAPPINGS config PCIE_LAYERSCAPE_EP bool "Layerscape PCIe Endpoint mode support" + depends on ARM select PCIE_LAYERSCAPE select PCI_ENDPOINT help @@ -296,6 +300,7 @@ config PCIE_LAYERSCAPE_EP config PCIE_LAYERSCAPE_GEN4 bool "Layerscape Gen4 PCIe support" + depends on ARM help Support PCIe Gen4 on NXP Layerscape SoCs, which may have one or several PCIe controllers. The PCIe controller can work in RC or @@ -328,12 +333,6 @@ config PCIE_IMX bool "i.MX PCIe support" depends on ARCH_MX6 -config PCIE_INTEL_FPGA - bool "Intel FPGA PCIe support" - help - Say Y here if you want to enable PCIe controller support on Intel - FPGA, example Stratix 10. - config PCIE_IPROC bool "Iproc PCIe support" help @@ -456,7 +455,7 @@ config PCIE_STARFIVE_JH7110 config PCIE_DW_IMX bool "i.MX DW PCIe controller support" - depends on ARCH_IMX8M + depends on ARCH_IMX8M || ARCH_IMX9 select PCIE_DW_COMMON select DM_REGULATOR select REGMAP diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index a0420e733ed..98f3c226f63 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -40,7 +40,6 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ pcie_layerscape_fixup_common.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o -obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o diff --git a/drivers/pci/pcie_apple.c b/drivers/pci/pcie_apple.c index 6a8e715d4b6..f5fda9835dc 100644 --- a/drivers/pci/pcie_apple.c +++ b/drivers/pci/pcie_apple.c @@ -246,8 +246,9 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np) { struct apple_pcie_port *port; struct gpio_desc reset; + struct fdt_pci_addr pci_addr; fdt_addr_t addr; - u32 stat, idx; + u32 stat; int ret; char name[16]; @@ -259,12 +260,13 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np) if (!port) return -ENOMEM; - ret = ofnode_read_u32_index(np, "reg", 0, &idx); + ret = ofnode_read_pci_addr(np, FDT_PCI_SPACE_CONFIG, "reg", + &pci_addr, NULL); if (ret) return ret; /* Use the first reg entry to work out the port index */ - port->idx = idx >> 11; + port->idx = PCI_DEV(pci_addr.phys_hi); port->pcie = pcie; port->reset = reset; port->np = np; @@ -333,9 +335,10 @@ static int apple_pcie_setup_port(struct apple_pcie_priv *pcie, ofnode np) static int apple_pcie_probe(struct udevice *dev) { struct apple_pcie_priv *pcie = dev_get_priv(dev); + struct fdt_pci_addr pci_addr; fdt_addr_t addr; ofnode of_port; - int i, ret; + int ret; pcie->hw = (struct reg_info *)dev_get_driver_data(dev); @@ -357,9 +360,14 @@ static int apple_pcie_probe(struct udevice *dev) of_port = ofnode_next_subnode(of_port)) { if (!ofnode_is_enabled(of_port)) continue; + ret = ofnode_read_pci_addr(of_port, FDT_PCI_SPACE_CONFIG, + "reg", &pci_addr, NULL); + if (ret) + continue; ret = apple_pcie_setup_port(pcie, of_port); if (ret) { - dev_err(pcie->dev, "Port %d setup fail: %d\n", i, ret); + dev_err(pcie->dev, "Port %d setup fail: %d\n", + PCI_DEV(pci_addr.phys_hi), ret); return ret; } } diff --git a/drivers/pci/pcie_dw_common.c b/drivers/pci/pcie_dw_common.c index c4cad019373..4113a9f03cf 100644 --- a/drivers/pci/pcie_dw_common.c +++ b/drivers/pci/pcie_dw_common.c @@ -7,7 +7,6 @@ * * Copyright (C) 2018 Texas Instruments, Inc */ - #include <dm.h> #include <log.h> #include <pci.h> @@ -385,7 +384,7 @@ void pcie_dw_setup_host(struct pcie_dw *pci) 0xffffff, 0x00ff0100); /* setup command register */ - clrsetbits_le32(pci->dbi_base + PCI_PRIMARY_BUS, + clrsetbits_le32(pci->dbi_base + PCI_COMMAND, 0xffff, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR); diff --git a/drivers/pci/pcie_dw_imx.c b/drivers/pci/pcie_dw_imx.c index fdb463710ba..41d9f3c20b9 100644 --- a/drivers/pci/pcie_dw_imx.c +++ b/drivers/pci/pcie_dw_imx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2024 Linaro Ltd. + * Copyright 2025 NXP * * Author: Sumit Garg <sumit.garg@linaro.org> */ @@ -45,6 +46,47 @@ #define IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10) #define IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11) +#define IMX95_PCIE_PHY_GEN_CTRL 0x0 +#define IMX95_PCIE_REF_USE_PAD BIT(17) + +#define IMX95_PCIE_PHY_MPLLA_CTRL 0x10 +#define IMX95_PCIE_PHY_MPLL_STATE BIT(30) + +#define IMX95_PCIE_SS_RW_REG_0 0xf0 +#define IMX95_PCIE_REF_CLKEN BIT(23) +#define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9) +#define IMX95_PCIE_SS_RW_REG_1 0xf4 +#define IMX95_PCIE_CLKREQ_OVERRIDE_EN BIT(8) +#define IMX95_PCIE_CLKREQ_OVERRIDE_VAL BIT(9) +#define IMX95_PCIE_SYS_AUX_PWR_DET BIT(31) + +#define IMX95_PE0_GEN_CTRL_1 0x1050 +#define IMX95_PCIE_DEVICE_TYPE GENMASK(3, 0) + +#define IMX95_PE0_GEN_CTRL_3 0x1058 +#define IMX95_PCIE_LTSSM_EN BIT(0) + +#define IMX95_PCIE_RST_CTRL 0x3010 +#define IMX95_PCIE_COLD_RST BIT(0) + +#define GEN3_RELATED_OFF 0x890 +#define GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL BIT(0) +#define GEN3_RELATED_OFF_RXEQ_RGRDLESS_RXTS BIT(13) +#define GEN3_RELATED_OFF_GEN3_EQ_DISABLE BIT(16) +#define GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT 24 +#define GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK GENMASK(25, 24) +#define GEN3_RELATED_OFF_RATE_SHADOW_SEL_16_0GT 0x1 + +#define IMX_PCIE_FLAG_HAS_PHYDRV BIT(3) +#define IMX_PCIE_FLAG_HAS_APP_RESET BIT(4) +#define IMX_PCIE_FLAG_HAS_SERDES BIT(6) + +#define IMX_PCIE_MAX_INSTANCES 2 + +/* Parameters for the waiting for PCIe PHY PLL to lock s*/ +#define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200 +#define PHY_PLL_LOCK_WAIT_TIMEOUT (2000 * PHY_PLL_LOCK_WAIT_USLEEP_MAX / 1000) + struct pcie_dw_imx { /* Must be first member of the struct */ struct pcie_dw dw; @@ -54,20 +96,196 @@ struct pcie_dw_imx { struct reset_ctl apps_reset; struct phy phy; struct udevice *vpcie; + void *info; + u32 max_link_speed; + bool enable_ext_refclk; + bool supports_clkreq; }; struct pcie_chip_info { + u32 flags; + const u32 ltssm_off; + const u32 ltssm_mask; + const u32 mode_off[IMX_PCIE_MAX_INSTANCES]; + const u32 mode_mask[IMX_PCIE_MAX_INSTANCES]; const char *gpr; + void (*init_phy)(struct pcie_dw_imx *priv); + int (*enable_ref_clk)(struct pcie_dw_imx *priv, bool enable); + int (*core_reset)(struct pcie_dw_imx *priv, bool assert); + int (*wait_pll_lock)(struct pcie_dw_imx *priv); + void (*post_config)(struct pcie_dw_imx *priv); }; +static void imx95_pcie_init_phy(struct pcie_dw_imx *priv) +{ +/* + * Workaround for ERR051624: The Controller Without Vaux Cannot + * Exit L23 Ready Through Beacon or PERST# De-assertion + * + * When the auxiliary power is not available the controller + * cannot exit from L23 Ready with beacon or PERST# de-assertion + * when main power is not removed. + * + * Workaround: Set SS_RW_REG_1[SYS_AUX_PWR_DET] to 1. + */ + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1, + IMX95_PCIE_SYS_AUX_PWR_DET, + IMX95_PCIE_SYS_AUX_PWR_DET); + + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, + IMX95_PCIE_PHY_CR_PARA_SEL, + IMX95_PCIE_PHY_CR_PARA_SEL); + + if (priv->enable_ext_refclk) { + /* External clock is used as reference clock */ + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_PHY_GEN_CTRL, + IMX95_PCIE_REF_USE_PAD, + IMX95_PCIE_REF_USE_PAD); + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, + IMX95_PCIE_REF_CLKEN, 0); + } else { + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_PHY_GEN_CTRL, + IMX95_PCIE_REF_USE_PAD, 0); + + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, + IMX95_PCIE_REF_CLKEN, IMX95_PCIE_REF_CLKEN); + } + + /* Force CLKREQ# low by override */ + if (!priv->supports_clkreq) + regmap_update_bits(priv->iomuxc_gpr, + IMX95_PCIE_SS_RW_REG_1, + IMX95_PCIE_CLKREQ_OVERRIDE_EN | + IMX95_PCIE_CLKREQ_OVERRIDE_VAL, + IMX95_PCIE_CLKREQ_OVERRIDE_EN | + IMX95_PCIE_CLKREQ_OVERRIDE_VAL); +} + +static int imx95_pcie_wait_for_phy_pll_lock(struct pcie_dw_imx *priv) +{ + u32 val; + + if (regmap_read_poll_timeout(priv->iomuxc_gpr, + IMX95_PCIE_PHY_MPLLA_CTRL, val, + val & IMX95_PCIE_PHY_MPLL_STATE, + PHY_PLL_LOCK_WAIT_USLEEP_MAX, + PHY_PLL_LOCK_WAIT_TIMEOUT)) { + printf("PCIe PLL lock timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int imx95_pcie_core_reset(struct pcie_dw_imx *priv, bool assert) +{ + u32 val; + + if (assert) { + /* + * From i.MX95 PCIe PHY perspective, the COLD reset toggle + * should be complete after power-up by the following sequence. + * > 10us(at power-up) + * > 10ns(warm reset) + * |<------------>| + * ______________ + * phy_reset ____/ \________________ + * ____________ + * ref_clk_en_______________________/ + * Toggle COLD reset aligned with this sequence for i.MX95 PCIe. + */ + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + IMX95_PCIE_COLD_RST, IMX95_PCIE_COLD_RST); + /* + * Make sure the write to IMX95_PCIE_RST_CTRL is flushed to the + * hardware by doing a read. Otherwise, there is no guarantee + * that the write has reached the hardware before udelay(). + */ + regmap_read(priv->iomuxc_gpr, IMX95_PCIE_RST_CTRL, &val); + udelay(15); + regmap_update_bits(priv->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + IMX95_PCIE_COLD_RST, 0); + regmap_read(priv->iomuxc_gpr, IMX95_PCIE_RST_CTRL, &val); + udelay(10); + } + + return 0; +} + +static void imx95_pcie_post_config(struct pcie_dw_imx *priv) +{ + u32 val; + + /* + * Workaround for ERR051586: Compliance with 8GT/s Receiver + * Impedance ECN + * + * The default value of GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] is + * 1 which makes receiver non-compliant with the ZRX-DC + * parameter for 2.5 GT/s when operating at 8 GT/s or higher. It + * causes unnecessary timeout in L1. + * + * Workaround: Program GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] to 0. + */ + dw_pcie_dbi_write_enable(&priv->dw, true); + val = readl(priv->dw.dbi_base + GEN3_RELATED_OFF); + val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; + writel(val, priv->dw.dbi_base + GEN3_RELATED_OFF); + dw_pcie_dbi_write_enable(&priv->dw, false); +} + +static int imx8mm_pcie_enable_ref_clk(struct pcie_dw_imx *priv, bool enable) +{ + regmap_update_bits(priv->iomuxc_gpr, IOMUXC_GPR14_OFFSET, + IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE, + enable ? 0 : IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE); + regmap_update_bits(priv->iomuxc_gpr, IOMUXC_GPR14_OFFSET, + IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN, + enable ? IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN : 0); + return 0; +} + static const struct pcie_chip_info imx8mm_chip_info = { + .flags = IMX_PCIE_FLAG_HAS_APP_RESET | IMX_PCIE_FLAG_HAS_PHYDRV, .gpr = "fsl,imx8mm-iomuxc-gpr", + .enable_ref_clk = imx8mm_pcie_enable_ref_clk, }; static const struct pcie_chip_info imx8mp_chip_info = { + .flags = IMX_PCIE_FLAG_HAS_APP_RESET | IMX_PCIE_FLAG_HAS_PHYDRV, .gpr = "fsl,imx8mp-iomuxc-gpr", + .enable_ref_clk = imx8mm_pcie_enable_ref_clk, +}; + +static const struct pcie_chip_info imx95_chip_info = { + .flags = IMX_PCIE_FLAG_HAS_SERDES, + .ltssm_off = IMX95_PE0_GEN_CTRL_3, + .ltssm_mask = IMX95_PCIE_LTSSM_EN, + .mode_off[0] = IMX95_PE0_GEN_CTRL_1, + .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, + .init_phy = imx95_pcie_init_phy, + .core_reset = imx95_pcie_core_reset, + .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, + .post_config = imx95_pcie_post_config, }; +static void imx_pcie_configure_type(struct pcie_dw_imx *priv) +{ + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); + unsigned int mask, val, mode; + + mode = PCI_EXP_TYPE_ROOT_PORT; + + /* If mode_mask is 0, then generic PHY driver is used to set the mode */ + if (!info->mode_mask[0]) + return; + + mask = info->mode_mask[0]; + val = mode << (ffs(mask) - 1); + + regmap_update_bits(priv->iomuxc_gpr, info->mode_off[0], mask, val); +} + static void pcie_dw_configure(struct pcie_dw_imx *priv, u32 cap_speed) { dw_pcie_dbi_write_enable(&priv->dw, true); @@ -75,17 +293,34 @@ static void pcie_dw_configure(struct pcie_dw_imx *priv, u32 cap_speed) clrsetbits_le32(priv->dw.dbi_base + PCIE_LINK_CAPABILITY, TARGET_LINK_SPEED_MASK, cap_speed); + clrsetbits_le32(priv->dw.dbi_base + PCIE_LINK_CTL_2, + TARGET_LINK_SPEED_MASK, cap_speed); + dw_pcie_dbi_write_enable(&priv->dw, false); } static void imx_pcie_ltssm_enable(struct pcie_dw_imx *priv) { - reset_deassert(&priv->apps_reset); + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); + + if (info->ltssm_mask) + regmap_update_bits(priv->iomuxc_gpr, info->ltssm_off, info->ltssm_mask, + info->ltssm_mask); + + if (info->flags & IMX_PCIE_FLAG_HAS_APP_RESET) + reset_deassert(&priv->apps_reset); } static void imx_pcie_ltssm_disable(struct pcie_dw_imx *priv) { - reset_assert(&priv->apps_reset); + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); + + if (info->ltssm_mask) + regmap_update_bits(priv->iomuxc_gpr, info->ltssm_off, + info->ltssm_mask, 0); + + if (info->flags & IMX_PCIE_FLAG_HAS_APP_RESET) + reset_assert(&priv->apps_reset); } static bool is_link_up(u32 val) @@ -122,6 +357,11 @@ static int pcie_link_up(struct pcie_dw_imx *priv, u32 cap_speed) static int imx_pcie_assert_core_reset(struct pcie_dw_imx *priv) { + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); + + if (info->core_reset) + info->core_reset(priv, true); + if (dm_gpio_is_valid(&priv->reset_gpio)) { dm_gpio_set_value(&priv->reset_gpio, 1); mdelay(20); @@ -133,6 +373,7 @@ static int imx_pcie_assert_core_reset(struct pcie_dw_imx *priv) static int imx_pcie_clk_enable(struct pcie_dw_imx *priv) { int ret; + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); ret = clk_enable_bulk(&priv->clks); if (ret) @@ -142,11 +383,8 @@ static int imx_pcie_clk_enable(struct pcie_dw_imx *priv) * Set the over ride low and enabled make sure that * REF_CLK is turned on. */ - regmap_update_bits(priv->iomuxc_gpr, IOMUXC_GPR14_OFFSET, - IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE, 0); - regmap_update_bits(priv->iomuxc_gpr, IOMUXC_GPR14_OFFSET, - IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN, - IMX8M_GPR_PCIE_CLK_REQ_OVERRIDE_EN); + if (info->enable_ref_clk) + info->enable_ref_clk(priv, true); /* allow the clocks to stabilize */ udelay(500); @@ -156,6 +394,11 @@ static int imx_pcie_clk_enable(struct pcie_dw_imx *priv) static void imx_pcie_deassert_core_reset(struct pcie_dw_imx *priv) { + struct pcie_chip_info *info = (struct pcie_chip_info *)(priv->info); + + if (info->core_reset) + info->core_reset(priv, false); + if (!dm_gpio_is_valid(&priv->reset_gpio)) return; @@ -170,10 +413,11 @@ static int pcie_dw_imx_probe(struct udevice *dev) struct pcie_dw_imx *priv = dev_get_priv(dev); struct udevice *ctlr = pci_get_controller(dev); struct pci_controller *hose = dev_get_uclass_priv(ctlr); + struct pcie_chip_info *info = (void *)dev_get_driver_data(dev); int ret; if (priv->vpcie) { - ret = regulator_set_enable(priv->vpcie, true); + ret = regulator_set_enable_if_allowed(priv->vpcie, true); if (ret) { dev_err(dev, "failed to enable vpcie regulator\n"); return ret; @@ -186,31 +430,49 @@ static int pcie_dw_imx_probe(struct udevice *dev) return ret; } + if (info->init_phy) + info->init_phy(priv); + + imx_pcie_configure_type(priv); + ret = imx_pcie_clk_enable(priv); if (ret) { dev_err(dev, "failed to enable clocks\n"); goto err_clk; } - ret = generic_phy_init(&priv->phy); - if (ret) { - dev_err(dev, "failed to initialize PHY\n"); - goto err_phy_init; - } + if (info->flags & IMX_PCIE_FLAG_HAS_PHYDRV) { + ret = generic_phy_init(&priv->phy); + if (ret) { + dev_err(dev, "failed to initialize PHY\n"); + goto err_phy_init; + } - ret = generic_phy_power_on(&priv->phy); - if (ret) { - dev_err(dev, "failed to power on PHY\n"); - goto err_phy_power; + ret = generic_phy_power_on(&priv->phy); + if (ret) { + dev_err(dev, "failed to power on PHY\n"); + goto err_phy_power; + } } imx_pcie_deassert_core_reset(priv); + if (info->wait_pll_lock) { + ret = info->wait_pll_lock(priv); + if (ret) { + dev_err(dev, "failed to wait pll lock\n"); + goto err_link; + } + } + + if (info->post_config) + info->post_config(priv); + priv->dw.first_busno = dev_seq(dev); priv->dw.dev = dev; pcie_dw_setup_host(&priv->dw); - if (pcie_link_up(priv, LINK_SPEED_GEN_1)) { + if (pcie_link_up(priv, priv->max_link_speed)) { printf("PCIE-%d: Link down\n", dev_seq(dev)); ret = -ENODEV; goto err_link; @@ -229,26 +491,41 @@ static int pcie_dw_imx_probe(struct udevice *dev) return 0; err_link: - generic_shutdown_phy(&priv->phy); + if (info->flags & IMX_PCIE_FLAG_HAS_PHYDRV) + generic_shutdown_phy(&priv->phy); err_phy_power: - generic_phy_exit(&priv->phy); + if (info->flags & IMX_PCIE_FLAG_HAS_PHYDRV) + generic_phy_exit(&priv->phy); err_phy_init: - clk_disable_bulk(&priv->clks); + clk_release_bulk(&priv->clks); err_clk: imx_pcie_deassert_core_reset(priv); + dm_gpio_free(dev, &priv->reset_gpio); + + if (priv->vpcie) + regulator_set_enable_if_allowed(priv->vpcie, false); + return ret; } static int pcie_dw_imx_remove(struct udevice *dev) { struct pcie_dw_imx *priv = dev_get_priv(dev); + struct pcie_chip_info *info = (void *)dev_get_driver_data(dev); + + if (info->flags & IMX_PCIE_FLAG_HAS_PHYDRV) + generic_shutdown_phy(&priv->phy); - generic_shutdown_phy(&priv->phy); dm_gpio_free(dev, &priv->reset_gpio); - reset_free(&priv->apps_reset); + if (info->flags & IMX_PCIE_FLAG_HAS_APP_RESET) + reset_free(&priv->apps_reset); + clk_release_bulk(&priv->clks); + if (priv->vpcie) + regulator_set_enable_if_allowed(priv->vpcie, false); + return 0; } @@ -257,7 +534,9 @@ static int pcie_dw_imx_of_to_plat(struct udevice *dev) struct pcie_chip_info *info = (void *)dev_get_driver_data(dev); struct pcie_dw_imx *priv = dev_get_priv(dev); ofnode gpr; - int ret; + int ret, index; + + priv->info = info; /* Get the controller base address */ priv->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbi"); @@ -274,17 +553,29 @@ static int pcie_dw_imx_of_to_plat(struct udevice *dev) return -EINVAL; } + priv->dw.atu_base = (void *)dev_read_addr_name_ptr(dev, "atu"); + if (!priv->dw.atu_base) + dev_dbg(dev, "failed to get atu address from dtb\n"); + ret = clk_get_bulk(dev, &priv->clks); if (ret) { dev_err(dev, "failed to get PCIe clks\n"); return ret; } - ret = reset_get_by_name(dev, "apps", &priv->apps_reset); - if (ret) { - dev_err(dev, - "Failed to get PCIe apps reset control\n"); - goto err_reset; + index = ofnode_stringlist_search(dev_ofnode(dev), "clock-names", "ext-ref"); + if (index < 0) + priv->enable_ext_refclk = false; + else + priv->enable_ext_refclk = true; + + if (info->flags & IMX_PCIE_FLAG_HAS_APP_RESET) { + ret = reset_get_by_name(dev, "apps", &priv->apps_reset); + if (ret) { + dev_err(dev, + "Failed to get PCIe apps reset control\n"); + goto err_reset; + } } ret = gpio_request_by_name(dev, "reset-gpio", 0, &priv->reset_gpio, @@ -294,26 +585,58 @@ static int pcie_dw_imx_of_to_plat(struct udevice *dev) goto err_gpio; } - ret = generic_phy_get_by_name(dev, "pcie-phy", &priv->phy); - if (ret) { - dev_err(dev, "failed to get pcie phy\n"); - goto err_phy; + if (info->flags & IMX_PCIE_FLAG_HAS_PHYDRV) { + ret = generic_phy_get_by_name(dev, "pcie-phy", &priv->phy); + if (ret) { + dev_err(dev, "failed to get pcie phy\n"); + goto err_phy; + } } - gpr = ofnode_by_compatible(ofnode_null(), info->gpr); - if (ofnode_equal(gpr, ofnode_null())) { - dev_err(dev, "unable to find GPR node\n"); - ret = -ENODEV; - goto err_phy; + if (info->flags & IMX_PCIE_FLAG_HAS_SERDES) { + void __iomem *app_base; + fdt_size_t app_size; + struct regmap_config config; + + app_base = (void *)dev_read_addr_size_name(dev, "app", &app_size); + if ((fdt_addr_t)app_base == FDT_ADDR_T_NONE) { + dev_err(dev, "failed to get app_base address\n"); + return -EINVAL; + } + + config.r_start = (ulong)app_base; + config.r_size = (ulong)app_size; + config.reg_offset_shift = 0; + config.width = REGMAP_SIZE_32; + + priv->iomuxc_gpr = devm_regmap_init(dev, NULL, NULL, &config); + if (IS_ERR(priv->iomuxc_gpr)) { + dev_err(dev, "unable to remap gpr\n"); + ret = PTR_ERR(priv->iomuxc_gpr); + goto err_phy; + } } - priv->iomuxc_gpr = syscon_node_to_regmap(gpr); - if (IS_ERR(priv->iomuxc_gpr)) { - dev_err(dev, "unable to find iomuxc registers\n"); - ret = PTR_ERR(priv->iomuxc_gpr); - goto err_phy; + if (info->gpr) { + gpr = ofnode_by_compatible(ofnode_null(), info->gpr); + if (ofnode_equal(gpr, ofnode_null())) { + dev_err(dev, "unable to find GPR node\n"); + ret = -ENODEV; + goto err_phy; + } + + priv->iomuxc_gpr = syscon_node_to_regmap(gpr); + if (IS_ERR(priv->iomuxc_gpr)) { + dev_err(dev, "unable to find iomuxc registers\n"); + ret = PTR_ERR(priv->iomuxc_gpr); + goto err_phy; + } } + priv->max_link_speed = dev_read_u32_default(dev, "fsl,max-link-speed", LINK_SPEED_GEN_1); + + priv->supports_clkreq = dev_read_bool(dev, "supports-clkreq"); + /* vpcie-supply regulator is optional */ device_get_supply_regulator(dev, "vpcie-supply", &priv->vpcie); @@ -322,7 +645,8 @@ static int pcie_dw_imx_of_to_plat(struct udevice *dev) err_phy: dm_gpio_free(dev, &priv->reset_gpio); err_gpio: - reset_free(&priv->apps_reset); + if (info->flags & IMX_PCIE_FLAG_HAS_APP_RESET) + reset_free(&priv->apps_reset); err_reset: clk_release_bulk(&priv->clks); @@ -337,6 +661,7 @@ static const struct dm_pci_ops pcie_dw_imx_ops = { static const struct udevice_id pcie_dw_imx_ids[] = { { .compatible = "fsl,imx8mm-pcie", .data = (ulong)&imx8mm_chip_info, }, { .compatible = "fsl,imx8mp-pcie", .data = (ulong)&imx8mp_chip_info, }, + { .compatible = "fsl,imx95-pcie", .data = (ulong)&imx95_chip_info, }, { } }; diff --git a/drivers/pci/pcie_intel_fpga.c b/drivers/pci/pcie_intel_fpga.c deleted file mode 100644 index 959fd369086..00000000000 --- a/drivers/pci/pcie_intel_fpga.c +++ /dev/null @@ -1,434 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel FPGA PCIe host controller driver - * - * Copyright (C) 2013-2018 Intel Corporation. All rights reserved - * - */ - -#include <dm.h> -#include <pci.h> -#include <asm/global_data.h> -#include <asm/io.h> -#include <dm/device_compat.h> -#include <linux/bitops.h> -#include <linux/delay.h> - -#define RP_TX_REG0 0x2000 -#define RP_TX_CNTRL 0x2004 -#define RP_TX_SOP BIT(0) -#define RP_TX_EOP BIT(1) -#define RP_RXCPL_STATUS 0x200C -#define RP_RXCPL_SOP BIT(0) -#define RP_RXCPL_EOP BIT(1) -#define RP_RXCPL_REG 0x2008 -#define P2A_INT_STATUS 0x3060 -#define P2A_INT_STS_ALL 0xf -#define P2A_INT_ENABLE 0x3070 -#define RP_CAP_OFFSET 0x70 - -/* TLP configuration type 0 and 1 */ -#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */ -#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */ -#define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */ -#define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */ -#define TLP_PAYLOAD_SIZE 0x01 -#define TLP_READ_TAG 0x1d -#define TLP_WRITE_TAG 0x10 -#define RP_DEVFN 0 - -#define RP_CFG_ADDR(pcie, reg) \ - ((pcie->hip_base) + (reg) + (1 << 20)) -#define RP_SECONDARY(pcie) \ - readb(RP_CFG_ADDR(pcie, PCI_SECONDARY_BUS)) -#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) - -#define TLP_CFGRD_DW0(pcie, bus) \ - ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGRD1 \ - : TLP_FMTTYPE_CFGRD0) << 24) | \ - TLP_PAYLOAD_SIZE) - -#define TLP_CFGWR_DW0(pcie, bus) \ - ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGWR1 \ - : TLP_FMTTYPE_CFGWR0) << 24) | \ - TLP_PAYLOAD_SIZE) - -#define TLP_CFG_DW1(pcie, tag, be) \ - (((TLP_REQ_ID(pcie->first_busno, RP_DEVFN)) << 16) | (tag << 8) | (be)) -#define TLP_CFG_DW2(bus, dev, fn, offset) \ - (((bus) << 24) | ((dev) << 19) | ((fn) << 16) | (offset)) - -#define TLP_COMP_STATUS(s) (((s) >> 13) & 7) -#define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff) -#define TLP_HDR_SIZE 3 -#define TLP_LOOP 20000 -#define DWORD_MASK 3 - -#define IS_ROOT_PORT(pcie, bdf) \ - ((PCI_BUS(bdf) == pcie->first_busno) ? true : false) - -/** - * struct intel_fpga_pcie - Intel FPGA PCIe controller state - * @bus: Pointer to the PCI bus - * @cra_base: The base address of CRA register space - * @hip_base: The base address of Rootport configuration space - * @first_busno: This driver supports multiple PCIe controllers. - * first_busno stores the bus number of the PCIe root-port - * number which may vary depending on the PCIe setup. - */ -struct intel_fpga_pcie { - struct udevice *bus; - void __iomem *cra_base; - void __iomem *hip_base; - int first_busno; -}; - -/** - * Intel FPGA PCIe port uses BAR0 of RC's configuration space as the - * translation from PCI bus to native BUS. Entire DDR region is mapped - * into PCIe space using these registers, so it can be reached by DMA from - * EP devices. - * The BAR0 of bridge should be hidden during enumeration to avoid the - * sizing and resource allocation by PCIe core. - */ -static bool intel_fpga_pcie_hide_rc_bar(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, int offset) -{ - if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) == 0 && - PCI_FUNC(bdf) == 0 && offset == PCI_BASE_ADDRESS_0) - return true; - - return false; -} - -static inline void cra_writel(struct intel_fpga_pcie *pcie, const u32 value, - const u32 reg) -{ - writel(value, pcie->cra_base + reg); -} - -static inline u32 cra_readl(struct intel_fpga_pcie *pcie, const u32 reg) -{ - return readl(pcie->cra_base + reg); -} - -static bool intel_fpga_pcie_link_up(struct intel_fpga_pcie *pcie) -{ - return !!(readw(RP_CFG_ADDR(pcie, RP_CAP_OFFSET + PCI_EXP_LNKSTA)) - & PCI_EXP_LNKSTA_DLLLA); -} - -static bool intel_fpga_pcie_addr_valid(struct intel_fpga_pcie *pcie, - pci_dev_t bdf) -{ - /* If there is no link, then there is no device */ - if (!IS_ROOT_PORT(pcie, bdf) && !intel_fpga_pcie_link_up(pcie)) - return false; - - /* access only one slot on each root port */ - if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) > 0) - return false; - - if ((PCI_BUS(bdf) == pcie->first_busno + 1) && PCI_DEV(bdf) > 0) - return false; - - return true; -} - -static void tlp_write_tx(struct intel_fpga_pcie *pcie, u32 reg0, u32 ctrl) -{ - cra_writel(pcie, reg0, RP_TX_REG0); - cra_writel(pcie, ctrl, RP_TX_CNTRL); -} - -static int tlp_read_packet(struct intel_fpga_pcie *pcie, u32 *value) -{ - int i; - u32 ctrl; - u32 comp_status; - u32 dw[4]; - u32 count = 0; - - for (i = 0; i < TLP_LOOP; i++) { - ctrl = cra_readl(pcie, RP_RXCPL_STATUS); - if (!(ctrl & RP_RXCPL_SOP)) - continue; - - /* read first DW */ - dw[count++] = cra_readl(pcie, RP_RXCPL_REG); - - /* Poll for EOP */ - for (i = 0; i < TLP_LOOP; i++) { - ctrl = cra_readl(pcie, RP_RXCPL_STATUS); - dw[count++] = cra_readl(pcie, RP_RXCPL_REG); - if (ctrl & RP_RXCPL_EOP) { - comp_status = TLP_COMP_STATUS(dw[1]); - if (comp_status) { - *value = pci_get_ff(PCI_SIZE_32); - return 0; - } - - if (value && - TLP_BYTE_COUNT(dw[1]) == sizeof(u32) && - count >= 3) - *value = dw[3]; - - return 0; - } - } - - udelay(5); - } - - dev_err(pcie->dev, "read TLP packet timed out\n"); - return -ENODEV; -} - -static void tlp_write_packet(struct intel_fpga_pcie *pcie, u32 *headers, - u32 data) -{ - tlp_write_tx(pcie, headers[0], RP_TX_SOP); - - tlp_write_tx(pcie, headers[1], 0); - - tlp_write_tx(pcie, headers[2], 0); - - tlp_write_tx(pcie, data, RP_TX_EOP); -} - -static int tlp_cfg_dword_read(struct intel_fpga_pcie *pcie, pci_dev_t bdf, - int offset, u8 byte_en, u32 *value) -{ - u32 headers[TLP_HDR_SIZE]; - u8 busno = PCI_BUS(bdf); - - headers[0] = TLP_CFGRD_DW0(pcie, busno); - headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en); - headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); - - tlp_write_packet(pcie, headers, 0); - - return tlp_read_packet(pcie, value); -} - -static int tlp_cfg_dword_write(struct intel_fpga_pcie *pcie, pci_dev_t bdf, - int offset, u8 byte_en, u32 value) -{ - u32 headers[TLP_HDR_SIZE]; - u8 busno = PCI_BUS(bdf); - - headers[0] = TLP_CFGWR_DW0(pcie, busno); - headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en); - headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); - - tlp_write_packet(pcie, headers, value); - - return tlp_read_packet(pcie, NULL); -} - -int intel_fpga_rp_conf_addr(const struct udevice *bus, pci_dev_t bdf, - uint offset, void **paddress) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - *paddress = RP_CFG_ADDR(pcie, offset); - - return 0; -} - -static int intel_fpga_pcie_rp_rd_conf(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - return pci_generic_mmap_read_config(bus, intel_fpga_rp_conf_addr, - bdf, offset, valuep, size); -} - -static int intel_fpga_pcie_rp_wr_conf(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - int ret; - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - ret = pci_generic_mmap_write_config(bus, intel_fpga_rp_conf_addr, - bdf, offset, value, size); - if (!ret) { - /* Monitor changes to PCI_PRIMARY_BUS register on root port - * and update local copy of root bus number accordingly. - */ - if (offset == PCI_PRIMARY_BUS) - pcie->first_busno = (u8)(value); - } - - return ret; -} - -static u8 pcie_get_byte_en(uint offset, enum pci_size_t size) -{ - switch (size) { - case PCI_SIZE_8: - return 1 << (offset & 3); - case PCI_SIZE_16: - return 3 << (offset & 3); - default: - return 0xf; - } -} - -static int _pcie_intel_fpga_read_config(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, uint offset, - ulong *valuep, enum pci_size_t size) -{ - int ret; - u32 data; - u8 byte_en; - - /* Uses memory mapped method to read rootport config registers */ - if (IS_ROOT_PORT(pcie, bdf)) - return intel_fpga_pcie_rp_rd_conf(pcie->bus, bdf, - offset, valuep, size); - - byte_en = pcie_get_byte_en(offset, size); - ret = tlp_cfg_dword_read(pcie, bdf, offset & ~DWORD_MASK, - byte_en, &data); - if (ret) - return ret; - - dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n", - offset, size, data); - *valuep = pci_conv_32_to_size(data, offset, size); - - return 0; -} - -static int _pcie_intel_fpga_write_config(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, uint offset, - ulong value, enum pci_size_t size) -{ - u32 data; - u8 byte_en; - - dev_dbg(pcie->dev, "PCIE CFG write: (b.d.f)=(%02d.%02d.%02d)\n", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", - offset, size, value); - - /* Uses memory mapped method to read rootport config registers */ - if (IS_ROOT_PORT(pcie, bdf)) - return intel_fpga_pcie_rp_wr_conf(pcie->bus, bdf, offset, - value, size); - - byte_en = pcie_get_byte_en(offset, size); - data = pci_conv_size_to_32(0, value, offset, size); - - return tlp_cfg_dword_write(pcie, bdf, offset & ~DWORD_MASK, - byte_en, data); -} - -static int pcie_intel_fpga_read_config(const struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - dev_dbg(pcie->dev, "PCIE CFG read: (b.d.f)=(%02d.%02d.%02d)\n", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - - if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) { - *valuep = (u32)pci_get_ff(size); - return 0; - } - - if (!intel_fpga_pcie_addr_valid(pcie, bdf)) { - *valuep = (u32)pci_get_ff(size); - return 0; - } - - return _pcie_intel_fpga_read_config(pcie, bdf, offset, valuep, size); -} - -static int pcie_intel_fpga_write_config(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) - return 0; - - if (!intel_fpga_pcie_addr_valid(pcie, bdf)) - return 0; - - return _pcie_intel_fpga_write_config(pcie, bdf, offset, value, - size); -} - -static int pcie_intel_fpga_probe(struct udevice *dev) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(dev); - - pcie->bus = pci_get_controller(dev); - pcie->first_busno = dev_seq(dev); - - /* clear all interrupts */ - cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS); - /* disable all interrupts */ - cra_writel(pcie, 0, P2A_INT_ENABLE); - - return 0; -} - -static int pcie_intel_fpga_of_to_plat(struct udevice *dev) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(dev); - struct fdt_resource reg_res; - int node = dev_of_offset(dev); - int ret; - - DECLARE_GLOBAL_DATA_PTR; - - ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", - "Cra", ®_res); - if (ret) { - dev_err(dev, "resource \"Cra\" not found\n"); - return ret; - } - - pcie->cra_base = map_physmem(reg_res.start, - fdt_resource_size(®_res), - MAP_NOCACHE); - - ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", - "Hip", ®_res); - if (ret) { - dev_err(dev, "resource \"Hip\" not found\n"); - return ret; - } - - pcie->hip_base = map_physmem(reg_res.start, - fdt_resource_size(®_res), - MAP_NOCACHE); - - return 0; -} - -static const struct dm_pci_ops pcie_intel_fpga_ops = { - .read_config = pcie_intel_fpga_read_config, - .write_config = pcie_intel_fpga_write_config, -}; - -static const struct udevice_id pcie_intel_fpga_ids[] = { - { .compatible = "altr,pcie-root-port-2.0" }, - {}, -}; - -U_BOOT_DRIVER(pcie_intel_fpga) = { - .name = "pcie_intel_fpga", - .id = UCLASS_PCI, - .of_match = pcie_intel_fpga_ids, - .ops = &pcie_intel_fpga_ops, - .of_to_plat = pcie_intel_fpga_of_to_plat, - .probe = pcie_intel_fpga_probe, - .priv_auto = sizeof(struct intel_fpga_pcie), -}; diff --git a/drivers/pci/pcie_iproc.c b/drivers/pci/pcie_iproc.c index 360ef1b011f..a6ed0189178 100644 --- a/drivers/pci/pcie_iproc.c +++ b/drivers/pci/pcie_iproc.c @@ -13,6 +13,7 @@ #include <dm/device_compat.h> #include <linux/delay.h> #include <linux/log2.h> +#include <linux/sizes.h> #define EP_PERST_SOURCE_SELECT_SHIFT 2 #define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT) diff --git a/drivers/pci/pcie_starfive_jh7110.c b/drivers/pci/pcie_starfive_jh7110.c index 51aca7359ff..0908ae16b67 100644 --- a/drivers/pci/pcie_starfive_jh7110.c +++ b/drivers/pci/pcie_starfive_jh7110.c @@ -292,8 +292,6 @@ static int starfive_pcie_probe(struct udevice *dev) if (ret) return ret; - dev_err(dev, "Starfive PCIe bus probed.\n"); - return 0; } |